diff --git a/godot/addons/better-terrain/BetterTerrain.cs b/godot/addons/better-terrain/BetterTerrain.cs deleted file mode 100644 index 31f1677..0000000 --- a/godot/addons/better-terrain/BetterTerrain.cs +++ /dev/null @@ -1,258 +0,0 @@ -using Godot; -using Godot.Collections; - -#nullable disable - -/* - -This is a lightweight wrapper for Better Terrain in C#. - -It is not a C# implementation, it merely provides a type safe interface to access -the BetterTerrain autoload from C#. If you are not using Godot in C#, you can ignore -this file. - -The interface is created for a specific tilemap node, which it uses to locate the -autoload, and to fill in as a parameter to simplify all the subsequent calls. -Very simple example: - -``` - BetterTerrain betterTerrain; - - public override void _Ready() - { - TileMapLayer tileMapLayer = GetNode("TileMapLayer"); - betterTerrain = new BetterTerrain(tm); - - var coordinates = new Vector2I(0, 0); - betterTerrain.SetCell(coordinates, 1); - betterTerrain.UpdateTerrainCell(coordinates); - } -``` - -The functions available are the same as BetterTerrain's, though the TileMapLayer or -TileSet parameters are automatically filled in. The help is not duplicated here, -refer to the GDScript version for specifics. - -*/ - -public class BetterTerrain -{ - public enum TerrainType - { - MatchTiles = 0, - MatchVertices = 1, - Category = 2, - Decoration = 3 - } - - public enum SymmetryType - { - None = 0, - Mirror = 1, // Horizontally mirror - Flip = 2, // Vertically flip - Reflect = 3, // All four reflections - RotateClockwise = 4, - RotateCounterClockwise = 5, - Rotate180 = 6, - RotateAll = 7, // All four rotated forms - All = 8 // All rotated and reflected forms - } - - private static readonly NodePath nodePath = new("/root/BetterTerrain"); - private readonly Node betterTerrain; - private readonly TileMapLayer tileMapLayer; - - public BetterTerrain(TileMapLayer tileMapLayer) - { - this.tileMapLayer = tileMapLayer; - betterTerrain = tileMapLayer.GetNode(nodePath); - } - - public Array> GetTerrainCategories() - { - return (Array>)betterTerrain.Call(MethodName.GetTerrainCategories, tileMapLayer.TileSet); - } - - public bool AddTerrain(string name, Color color, TerrainType type, Array categories = null, Godot.Collections.Dictionary icon = null) - { - categories ??= new Array(); - icon ??= new Godot.Collections.Dictionary(); - return (bool)betterTerrain.Call(MethodName.AddTerrain, tileMapLayer.TileSet, name, color, (int)type, categories, icon); - } - - public bool RemoveTerrain(int index) - { - return (bool)betterTerrain.Call(MethodName.RemoveTerrain, tileMapLayer.TileSet, index); - } - - public int TerrainCount() - { - return (int)betterTerrain.Call(MethodName.TerrainCount, tileMapLayer.TileSet); - } - - public Godot.Collections.Dictionary GetTerrain(int index) - { - return (Godot.Collections.Dictionary)betterTerrain.Call(MethodName.GetTerrain, tileMapLayer.TileSet, index); - } - - public bool SetTerrain(int index, string name, Color color, TerrainType type, Array categories = null, Godot.Collections.Dictionary icon = null) - { - categories ??= new Array(); - icon ??= new Godot.Collections.Dictionary(); - return (bool)betterTerrain.Call(MethodName.SetTerrain, tileMapLayer.TileSet, index, name, color, (int)type, categories, icon); - } - - public bool SwapTerrains(int index1, int index2) - { - return (bool)betterTerrain.Call(MethodName.SwapTerrains, tileMapLayer.TileSet, index1, index2); - } - - public bool SetTileTerrainType(TileData tileData, int type) - { - return (bool)betterTerrain.Call(MethodName.SetTileTerrainType, tileMapLayer.TileSet, tileData, type); - } - - public int GetTileTerrainType(TileData tileData) - { - return (int)betterTerrain.Call(MethodName.GetTileTerrainType, tileData); - } - - public bool SetTileSymmetryType(TileData tileData, SymmetryType type) - { - return (bool)betterTerrain.Call(MethodName.SetTileSymmetryType, tileMapLayer.TileSet, tileData, (int)type); - } - - public SymmetryType GetTileSymmetryType(TileData tileData) - { - return (SymmetryType)(int)betterTerrain.Call(MethodName.GetTileSymmetryType, tileData); - } - - public Array GetTilesInTerrain(int type) - { - return (Array)betterTerrain.Call(MethodName.GetTilesInTerrain, tileMapLayer.TileSet, type); - } - - public Array> GetTileSourcesInTerrain(int type) - { - return (Array>)betterTerrain.Call(MethodName.GetTileSourcesInTerrain, tileMapLayer.TileSet, type); - } - - public bool AddTilePeeringType(TileData tileData, TileSet.CellNeighbor peering, int type) - { - return (bool)betterTerrain.Call(MethodName.AddTilePeeringType, tileMapLayer.TileSet, tileData, (int)peering, type); - } - - public bool RemoveTilePeeringType(TileData tileData, TileSet.CellNeighbor peering, int type) - { - return (bool)betterTerrain.Call(MethodName.RemoveTilePeeringType, tileMapLayer.TileSet, tileData, (int)peering, type); - } - - public Array TilePeeringKeys(TileData tileData) - { - return (Array)betterTerrain.Call(MethodName.TilePeeringKeys, tileData); - } - - public Array TilePeeringTypes(TileData tileData, TileSet.CellNeighbor peering) - { - return (Array)betterTerrain.Call(MethodName.TilePeeringTypes, tileData, (int)peering); - } - - public Array TilePeeringForType(TileData tileData, int type) - { - return (Array)betterTerrain.Call(MethodName.TilePeeringForType, tileData, type); - } - - public bool SetCell(Vector2I coordinate, int type) - { - return (bool)betterTerrain.Call(MethodName.SetCell, tileMapLayer, coordinate, type); - } - - public bool SetCells(Array coordinates, int type) - { - return (bool)betterTerrain.Call(MethodName.SetCells, tileMapLayer, coordinates, type); - } - - public bool ReplaceCell(Vector2I coordinate, int type) - { - return (bool)betterTerrain.Call(MethodName.ReplaceCell, tileMapLayer, coordinate, type); - } - - public bool ReplaceCells(Array coordinates, int type) - { - return (bool)betterTerrain.Call(MethodName.ReplaceCells, tileMapLayer, coordinates, type); - } - - public int GetCell(Vector2I coordinate) - { - return (int)betterTerrain.Call(MethodName.GetCell, tileMapLayer, coordinate); - } - - public void UpdateTerrainCells(Array cells, bool updateSurroundingCells = true) - { - betterTerrain.Call(MethodName.UpdateTerrainCells, tileMapLayer, cells, updateSurroundingCells); - } - - public void UpdateTerrainCell(Vector2I cell, bool updateSurroundingCells = true) - { - betterTerrain.Call(MethodName.UpdateTerrainCell, tileMapLayer, cell, updateSurroundingCells); - } - - public void UpdateTerrainArea(Rect2I area, bool updateSurroundingCells = true) - { - betterTerrain.Call(MethodName.UpdateTerrainArea, tileMapLayer, area, updateSurroundingCells); - } - - public Godot.Collections.Dictionary CreateTerrainChangeset(Godot.Collections.Dictionary paint) - { - return (Godot.Collections.Dictionary)betterTerrain.Call(MethodName.CreateTerrainChangeset, tileMapLayer, paint); - } - - public bool IsTerrainChangesetReady(Godot.Collections.Dictionary changeset) - { - return (bool)betterTerrain.Call(MethodName.IsTerrainChangesetReady, changeset); - } - - public void WaitForTerrainChangeset(Godot.Collections.Dictionary changeset) - { - betterTerrain.Call(MethodName.WaitForTerrainChangeset, changeset); - } - - public void ApplyTerrainChangeset(Godot.Collections.Dictionary changeset) - { - betterTerrain.Call(MethodName.ApplyTerrainChangeset, changeset); - } - - private static class MethodName - { - public static readonly StringName GetTerrainCategories = "get_terrain_categories"; - public static readonly StringName AddTerrain = "add_terrain"; - public static readonly StringName RemoveTerrain = "remove_terrain"; - public static readonly StringName TerrainCount = "terrain_count"; - public static readonly StringName GetTerrain = "get_terrain"; - public static readonly StringName SetTerrain = "set_terrain"; - public static readonly StringName SwapTerrains = "swap_terrains"; - public static readonly StringName SetTileTerrainType = "set_tile_terrain_type"; - public static readonly StringName GetTileTerrainType = "get_tile_terrain_type"; - public static readonly StringName SetTileSymmetryType = "set_tile_symmetry_type"; - public static readonly StringName GetTileSymmetryType = "get_tile_symmetry_type"; - public static readonly StringName GetTilesInTerrain = "get_tiles_in_terrain"; - public static readonly StringName GetTileSourcesInTerrain = "get_tile_sources_in_terrain"; - public static readonly StringName AddTilePeeringType = "add_tile_peering_type"; - public static readonly StringName RemoveTilePeeringType = "remove_tile_peering_type"; - public static readonly StringName TilePeeringKeys = "tile_peering_keys"; - public static readonly StringName TilePeeringTypes = "tile_peering_types"; - public static readonly StringName TilePeeringForType = "tile_peering_for_type"; - public static readonly StringName SetCell = "set_cell"; - public static readonly StringName SetCells = "set_cells"; - public static readonly StringName ReplaceCell = "replace_cell"; - public static readonly StringName ReplaceCells = "replace_cells"; - public static readonly StringName GetCell = "get_cell"; - public static readonly StringName UpdateTerrainCells = "update_terrain_cells"; - public static readonly StringName UpdateTerrainCell = "update_terrain_cell"; - public static readonly StringName UpdateTerrainArea = "update_terrain_area"; - public static readonly StringName CreateTerrainChangeset = "create_terrain_changeset"; - public static readonly StringName IsTerrainChangesetReady = "is_terrain_changeset_ready"; - public static readonly StringName WaitForTerrainChangeset = "wait_for_terrain_changeset"; - public static readonly StringName ApplyTerrainChangeset = "apply_terrain_changeset"; - } -} diff --git a/godot/addons/better-terrain/BetterTerrain.gd b/godot/addons/better-terrain/BetterTerrain.gd deleted file mode 100644 index 8c53711..0000000 --- a/godot/addons/better-terrain/BetterTerrain.gd +++ /dev/null @@ -1,1160 +0,0 @@ -@tool -extends Node - -## A [TileMapLayer] terrain / auto-tiling system. -## -## This is a drop-in replacement for Godot 4's tilemap terrain system, offering -## more versatile and straightforward autotiling. It can be used with any -## existing [TileMapLayer] or [TileSet], either through the editor plugin, or -## directly via code. -## [br][br] -## The [b]BetterTerrain[/b] class contains only static functions, each of which -## either takes a [TileMapLayer], a [TileSet], and sometimes a [TileData]. -## Meta-data is embedded inside the [TileSet] and the [TileData] types to store -## the terrain information. See [method Object.get_meta] for information. -## [br][br] -## Once terrain is set up, it can be written to the tilemap using [method set_cells]. -## Similar to Godot 3.x, setting the cells does not run the terrain solver, so once -## the cells have been set, you need to call an update function such as [method update_terrain_cells]. - - -## The meta-data key used to store terrain information. -const TERRAIN_META = &"_better_terrain" - -## The current version. Used to handle future upgrades. -const TERRAIN_SYSTEM_VERSION = "0.2" - -var _tile_cache = {} -var rng = RandomNumberGenerator.new() -var use_seed := true - -## A helper class that provides functions detailing valid peering bits and -## polygons for different tile types. -var data := load("res://addons/better-terrain/BetterTerrainData.gd"): - get: - return data - -enum TerrainType { - MATCH_TILES, ## Selects tiles by matching against adjacent tiles. - MATCH_VERTICES, ## Select tiles by analysing vertices, similar to wang-style tiles. - CATEGORY, ## Declares a matching type for more sophisticated rules. - DECORATION, ## Fills empty tiles by matching adjacent tiles - MAX, -} - -enum TileCategory { - EMPTY = -1, ## An empty cell, or a tile marked as decoration - NON_TERRAIN = -2, ## A non-empty cell that does not contain a terrain tile - ERROR = -3 -} - -enum SymmetryType { - NONE, - MIRROR, ## Horizontally mirror - FLIP, ## Vertically flip - REFLECT, ## All four reflections - ROTATE_CLOCKWISE, - ROTATE_COUNTER_CLOCKWISE, - ROTATE_180, - ROTATE_ALL, ## All four rotated forms - ALL ## All rotated and reflected forms -} - - -func _intersect(first: Array, second: Array) -> bool: - if first.size() > second.size(): - return _intersect(second, first) # Array 'has' is fast compared to gdscript loop - for f in first: - if second.has(f): - return true - return false - - -# Meta-data functions - -func _get_terrain_meta(ts: TileSet) -> Dictionary: - return ts.get_meta(TERRAIN_META) if ts and ts.has_meta(TERRAIN_META) else { - terrains = [], - decoration = ["Decoration", Color.DIM_GRAY, TerrainType.DECORATION, [], {path = "res://addons/better-terrain/icons/Decoration.svg"}], - version = TERRAIN_SYSTEM_VERSION - } - - -func _set_terrain_meta(ts: TileSet, meta : Dictionary) -> void: - ts.set_meta(TERRAIN_META, meta) - ts.emit_changed() - - -func _get_tile_meta(td: TileData) -> Dictionary: - return td.get_meta(TERRAIN_META) if td.has_meta(TERRAIN_META) else { - type = TileCategory.NON_TERRAIN - } - - -func _set_tile_meta(ts: TileSet, td: TileData, meta) -> void: - td.set_meta(TERRAIN_META, meta) - ts.emit_changed() - - -func _get_cache(ts: TileSet) -> Array: - if _tile_cache.has(ts): - return _tile_cache[ts] - - var cache := [] - if !ts: - return cache - _tile_cache[ts] = cache - - var watcher = Node.new() - watcher.set_script(load("res://addons/better-terrain/Watcher.gd")) - watcher.tileset = ts - watcher.trigger.connect(_purge_cache.bind(ts)) - add_child(watcher) - ts.changed.connect(watcher.activate) - - var types = {} - - var ts_meta := _get_terrain_meta(ts) - for t in ts_meta.terrains.size(): - var terrain = ts_meta.terrains[t] - var bits = terrain[3].duplicate() - bits.push_back(t) - types[t] = bits - cache.push_back([]) - - # Decoration - types[-1] = [TileCategory.EMPTY] - cache.push_back([[-1, Vector2.ZERO, -1, {}, 1.0]]) - - for s in ts.get_source_count(): - var source_id := ts.get_source_id(s) - var source := ts.get_source(source_id) as TileSetAtlasSource - if !source: - continue - source.changed.connect(watcher.activate) - for c in source.get_tiles_count(): - var coord := source.get_tile_id(c) - for a in source.get_alternative_tiles_count(coord): - var alternate := source.get_alternative_tile_id(coord, a) - var td := source.get_tile_data(coord, alternate) - var td_meta := _get_tile_meta(td) - if td_meta.type < TileCategory.EMPTY or td_meta.type >= cache.size(): - continue - - td.changed.connect(watcher.activate) - var peering := {} - for key in td_meta.keys(): - if !(key is int): - continue - - var targets := [] - for k in types: - if _intersect(types[k], td_meta[key]): - targets.push_back(k) - - peering[key] = targets - - # Decoration tiles without peering are skipped - if td_meta.type == TileCategory.EMPTY and !peering: - continue - - var symmetry = td_meta.get("symmetry", SymmetryType.NONE) - # Branch out no symmetry tiles early - if symmetry == SymmetryType.NONE: - cache[td_meta.type].push_back([source_id, coord, alternate, peering, td.probability]) - continue - - # calculate the symmetry order for this tile - var symmetry_order := 0 - for flags in data.symmetry_mapping[symmetry]: - var symmetric_peering = data.peering_bits_after_symmetry(peering, flags) - if symmetric_peering == peering: - symmetry_order += 1 - - var adjusted_probability = td.probability / symmetry_order - for flags in data.symmetry_mapping[symmetry]: - var symmetric_peering = data.peering_bits_after_symmetry(peering, flags) - cache[td_meta.type].push_back([source_id, coord, alternate | flags, symmetric_peering, adjusted_probability]) - - return cache - - -func _get_cache_terrain(ts_meta : Dictionary, index: int) -> Array: - # the cache and the terrains in ts_meta don't line up because - # decorations are cached too - if index < 0 or index >= ts_meta.terrains.size(): - return ts_meta.decoration - return ts_meta.terrains[index] - - -func _purge_cache(ts: TileSet) -> void: - _tile_cache.erase(ts) - for c in get_children(): - if c.tileset == ts: - c.tidy() - break - - -func _clear_invalid_peering_types(ts: TileSet) -> void: - var ts_meta := _get_terrain_meta(ts) - - var cache := _get_cache(ts) - for t in cache.size(): - var type = _get_cache_terrain(ts_meta, t)[2] - var valid_peering_types = data.get_terrain_peering_cells(ts, type) - - for c in cache[t]: - if c[0] < 0: - continue - var source := ts.get_source(c[0]) as TileSetAtlasSource - if !source: - continue - var td := source.get_tile_data(c[1], c[2]) - var td_meta := _get_tile_meta(td) - - for peering in c[3].keys(): - if valid_peering_types.has(peering): - continue - td_meta.erase(peering) - - _set_tile_meta(ts, td, td_meta) - - # Not strictly necessary - _purge_cache(ts) - - -func _has_invalid_peering_types(ts: TileSet) -> bool: - var ts_meta := _get_terrain_meta(ts) - - var cache := _get_cache(ts) - for t in cache.size(): - var type = _get_cache_terrain(ts_meta, t)[2] - var valid_peering_types = data.get_terrain_peering_cells(ts, type) - - for c in cache[t]: - for peering in c[3].keys(): - if !valid_peering_types.has(peering): - return true - - return false - - -func _update_terrain_data(ts: TileSet) -> void: - var ts_meta = _get_terrain_meta(ts) - var previous_version = ts_meta.get("version") - - # First release: no version info - if !ts_meta.has("version"): - ts_meta["version"] = "0.0" - - # 0.0 -> 0.1: add categories - if ts_meta.version == "0.0": - for t in ts_meta.terrains: - if t.size() == 3: - t.push_back([]) - ts_meta.version = "0.1" - - # 0.1 -> 0.2: add decoration tiles and terrain icons - if ts_meta.version == "0.1": - # Add terrain icon containers - for t in ts_meta.terrains: - if t.size() == 4: - t.push_back({}) - - # Add default decoration data - ts_meta["decoration"] = ["Decoration", Color.DIM_GRAY, TerrainType.DECORATION, [], {path = "res://addons/better-terrain/icons/Decoration.svg"}] - ts_meta.version = "0.2" - - if previous_version != ts_meta.version: - _set_terrain_meta(ts, ts_meta) - - -func _weighted_selection(choices: Array, apply_empty_probability: bool): - if choices.is_empty(): - return null - - var weight = choices.reduce(func(a, c): return a + c[4], 0.0) - - if apply_empty_probability and weight < 1.0 and rng.randf() > weight: - return [-1, Vector2.ZERO, -1, null, 1.0] - - if choices.size() == 1: - return choices[0] - - if weight == 0.0: - return choices[rng.randi() % choices.size()] - - var pick = rng.randf() * weight - for c in choices: - if pick < c[4]: - return c - pick -= c[4] - return choices.back() - - -func _weighted_selection_seeded(choices: Array, coord: Vector2i, apply_empty_probability: bool): - if use_seed: - rng.seed = hash(coord) - return _weighted_selection(choices, apply_empty_probability) - - -func _update_tile_tiles(tm: TileMapLayer, coord: Vector2i, types: Dictionary, cache: Array, apply_empty_probability: bool): - var type = types[coord] - - const reward := 3 - var penalty := -2000 if apply_empty_probability else -10 - - var best_score := -1000 # Impossibly bad score - var best := [] - for t in cache[type]: - var score := 0 - for peering in t[3]: - score += reward if t[3][peering].has(types[tm.get_neighbor_cell(coord, peering)]) else penalty - - if score > best_score: - best_score = score - best = [t] - elif score == best_score: - best.append(t) - - return _weighted_selection_seeded(best, coord, apply_empty_probability) - - -func _probe(tm: TileMapLayer, coord: Vector2i, peering: int, type: int, types: Dictionary) -> int: - var targets = data.associated_vertex_cells(tm, coord, peering) - targets = targets.map(func(c): return types[c]) - - var first = targets[0] - if targets.all(func(t): return t == first): - return first - - # if different, use the lowest non-same - targets = targets.filter(func(t): return t != type) - return targets.reduce(func(a, t): return min(a, t)) - - -func _update_tile_vertices(tm: TileMapLayer, coord: Vector2i, types: Dictionary, cache: Array): - var type = types[coord] - - const reward := 3 - const penalty := -10 - - var best_score := -1000 # Impossibly bad score - var best := [] - for t in cache[type]: - var score := 0 - for peering in t[3]: - score += reward if _probe(tm, coord, peering, type, types) in t[3][peering] else penalty - - if score > best_score: - best_score = score - best = [t] - elif score == best_score: - best.append(t) - - return _weighted_selection_seeded(best, coord, false) - - -func _update_tile_immediate(tm: TileMapLayer, coord: Vector2i, ts_meta: Dictionary, types: Dictionary, cache: Array) -> void: - var type = types[coord] - if type < TileCategory.EMPTY or type >= ts_meta.terrains.size(): - return - - var placement - var terrain = _get_cache_terrain(ts_meta, type) - if terrain[2] in [TerrainType.MATCH_TILES, TerrainType.DECORATION]: - placement = _update_tile_tiles(tm, coord, types, cache, terrain[2] == TerrainType.DECORATION) - elif terrain[2] == TerrainType.MATCH_VERTICES: - placement = _update_tile_vertices(tm, coord, types, cache) - else: - return - - if placement: - tm.set_cell(coord, placement[0], placement[1], placement[2]) - - -func _update_tile_deferred(tm: TileMapLayer, coord: Vector2i, ts_meta: Dictionary, types: Dictionary, cache: Array): - var type = types[coord] - if type >= TileCategory.EMPTY and type < ts_meta.terrains.size(): - var terrain = _get_cache_terrain(ts_meta, type) - if terrain[2] in [TerrainType.MATCH_TILES, TerrainType.DECORATION]: - return _update_tile_tiles(tm, coord, types, cache, terrain[2] == TerrainType.DECORATION) - elif terrain[2] == TerrainType.MATCH_VERTICES: - return _update_tile_vertices(tm, coord, types, cache) - return null - - -func _widen(tm: TileMapLayer, coords: Array) -> Array: - var result := {} - var peering_neighbors = data.get_terrain_peering_cells(tm.tile_set, TerrainType.MATCH_TILES) - for c in coords: - result[c] = true - var neighbors = data.neighboring_coords(tm, c, peering_neighbors) - for t in neighbors: - result[t] = true - return result.keys() - - -func _widen_with_exclusion(tm: TileMapLayer, coords: Array, exclusion: Rect2i) -> Array: - var result := {} - var peering_neighbors = data.get_terrain_peering_cells(tm.tile_set, TerrainType.MATCH_TILES) - for c in coords: - if !exclusion.has_point(c): - result[c] = true - var neighbors = data.neighboring_coords(tm, c, peering_neighbors) - for t in neighbors: - if !exclusion.has_point(t): - result[t] = true - return result.keys() - -# Terrains - -## Returns an [Array] of categories. These are the terrains in the [TileSet] which -## are marked with [enum TerrainType] of [code]CATEGORY[/code]. Each entry in the -## array is a [Dictionary] with [code]name[/code], [code]color[/code], and [code]id[/code]. -func get_terrain_categories(ts: TileSet) -> Array: - var result := [] - if !ts: - return result - - var ts_meta := _get_terrain_meta(ts) - for id in ts_meta.terrains.size(): - var t = ts_meta.terrains[id] - if t[2] == TerrainType.CATEGORY: - result.push_back({name = t[0], color = t[1], id = id}) - - return result - - -## Adds a new terrain to the [TileSet]. Returns [code]true[/code] if this is successful. -## [br][br] -## [code]type[/code] must be one of [enum TerrainType].[br] -## [code]categories[/code] is an indexed list of terrain categories that this terrain -## can match as. The indexes must be valid terrains of the CATEGORY type. -## [code]icon[/code] is a [Dictionary] with either a [code]path[/code] string pointing -## to a resource, or a [code]source_id[/code] [int] and a [code]coord[/code] [Vector2i]. -## The former takes priority if both are present. -func add_terrain(ts: TileSet, name: String, color: Color, type: int, categories: Array = [], icon: Dictionary = {}) -> bool: - if !ts or name.is_empty() or type < 0 or type == TerrainType.DECORATION or type >= TerrainType.MAX: - return false - - var ts_meta := _get_terrain_meta(ts) - - # check categories - if type == TerrainType.CATEGORY and !categories.is_empty(): - return false - for c in categories: - if c < 0 or c >= ts_meta.terrains.size() or ts_meta.terrains[c][2] != TerrainType.CATEGORY: - return false - - if icon and not (icon.has("path") or (icon.has("source_id") and icon.has("coord"))): - return false - - ts_meta.terrains.push_back([name, color, type, categories, icon]) - _set_terrain_meta(ts, ts_meta) - _purge_cache(ts) - return true - - -## Removes the terrain at [code]index[/code] from the [TileSet]. Returns [code]true[/code] -## if the deletion is successful. -func remove_terrain(ts: TileSet, index: int) -> bool: - if !ts or index < 0: - return false - - var ts_meta := _get_terrain_meta(ts) - if index >= ts_meta.terrains.size(): - return false - - if ts_meta.terrains[index][2] == TerrainType.CATEGORY: - for t in ts_meta.terrains: - t[3].erase(index) - - for s in ts.get_source_count(): - var source := ts.get_source(ts.get_source_id(s)) as TileSetAtlasSource - if !source: - continue - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - for a in source.get_alternative_tiles_count(coord): - var alternate := source.get_alternative_tile_id(coord, a) - var td := source.get_tile_data(coord, alternate) - - var td_meta := _get_tile_meta(td) - if td_meta.type == TileCategory.NON_TERRAIN: - continue - - if td_meta.type == index: - _set_tile_meta(ts, td, null) - continue - - if td_meta.type > index: - td_meta.type -= 1 - - for peering in td_meta.keys(): - if !(peering is int): - continue - - var fixed_peering = [] - for p in td_meta[peering]: - if p < index: - fixed_peering.append(p) - elif p > index: - fixed_peering.append(p - 1) - - if fixed_peering.is_empty(): - td_meta.erase(peering) - else: - td_meta[peering] = fixed_peering - - _set_tile_meta(ts, td, td_meta) - - ts_meta.terrains.remove_at(index) - _set_terrain_meta(ts, ts_meta) - - _purge_cache(ts) - return true - - -## Returns the number of terrains in the [TileSet]. -func terrain_count(ts: TileSet) -> int: - if !ts: - return 0 - - var ts_meta := _get_terrain_meta(ts) - return ts_meta.terrains.size() - - -## Retrieves information about the terrain at [code]index[/code] in the [TileSet]. -## [br][br] -## Returns a [Dictionary] describing the terrain. If it succeeds, the key [code]valid[/code] -## will be set to [code]true[/code]. Other keys are [code]name[/code], [code]color[/code], -## [code]type[/code] (a [enum TerrainType]), [code]categories[/code] which is -## an [Array] of category type terrains that this terrain matches as, and -## [code]icon[/code] which is a [Dictionary] with a [code]path[/code] [String] or -## a [code]source_id[/code] [int] and [code]coord[/code] [Vector2i] -func get_terrain(ts: TileSet, index: int) -> Dictionary: - if !ts or index < TileCategory.EMPTY: - return {valid = false} - - var ts_meta := _get_terrain_meta(ts) - if index >= ts_meta.terrains.size(): - return {valid = false} - - var terrain := _get_cache_terrain(ts_meta, index) - return { - id = index, - name = terrain[0], - color = terrain[1], - type = terrain[2], - categories = terrain[3].duplicate(), - icon = terrain[4].duplicate(), - valid = true - } - - -## Updates the details of the terrain at [code]index[/code] in [TileSet]. Returns -## [code]true[/code] if this succeeds. -## [br][br] -## If supplied, the [code]categories[/code] must be a list of indexes to other [code]CATEGORY[/code] -## type terrains. -## [code]icon[/code] is a [Dictionary] with either a [code]path[/code] string pointing -## to a resource, or a [code]source_id[/code] [int] and a [code]coord[/code] [Vector2i]. -func set_terrain(ts: TileSet, index: int, name: String, color: Color, type: int, categories: Array = [], icon: Dictionary = {valid = false}) -> bool: - if !ts or name.is_empty() or index < 0 or type < 0 or type == TerrainType.DECORATION or type >= TerrainType.MAX: - return false - - var ts_meta := _get_terrain_meta(ts) - if index >= ts_meta.terrains.size(): - return false - - if type == TerrainType.CATEGORY and !categories.is_empty(): - return false - for c in categories: - if c < 0 or c == index or c >= ts_meta.terrains.size() or ts_meta.terrains[c][2] != TerrainType.CATEGORY: - return false - - var icon_valid = icon.get("valid", "true") - if icon_valid: - match icon: - {}, {"path"}, {"source_id", "coord"}: pass - _: return false - - if type != TerrainType.CATEGORY: - for t in ts_meta.terrains: - t[3].erase(index) - - ts_meta.terrains[index] = [name, color, type, categories, icon] - _set_terrain_meta(ts, ts_meta) - - _clear_invalid_peering_types(ts) - _purge_cache(ts) - return true - - -## Swaps the terrains at [code]index1[/code] and [code]index2[/code] in [TileSet]. -func swap_terrains(ts: TileSet, index1: int, index2: int) -> bool: - if !ts or index1 < 0 or index2 < 0 or index1 == index2: - return false - - var ts_meta := _get_terrain_meta(ts) - if index1 >= ts_meta.terrains.size() or index2 >= ts_meta.terrains.size(): - return false - - for t in ts_meta.terrains: - var has1 = t[3].has(index1) - var has2 = t[3].has(index2) - - if has1 and !has2: - t[3].erase(index1) - t[3].push_back(index2) - elif has2 and !has1: - t[3].erase(index2) - t[3].push_back(index1) - - for s in ts.get_source_count(): - var source := ts.get_source(ts.get_source_id(s)) as TileSetAtlasSource - if !source: - continue - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - for a in source.get_alternative_tiles_count(coord): - var alternate := source.get_alternative_tile_id(coord, a) - var td := source.get_tile_data(coord, alternate) - - var td_meta := _get_tile_meta(td) - if td_meta.type == TileCategory.NON_TERRAIN: - continue - - if td_meta.type == index1: - td_meta.type = index2 - elif td_meta.type == index2: - td_meta.type = index1 - - for peering in td_meta.keys(): - if !(peering is int): - continue - - var fixed_peering = [] - for p in td_meta[peering]: - if p == index1: - fixed_peering.append(index2) - elif p == index2: - fixed_peering.append(index1) - else: - fixed_peering.append(p) - td_meta[peering] = fixed_peering - - _set_tile_meta(ts, td, td_meta) - - var temp = ts_meta.terrains[index1] - ts_meta.terrains[index1] = ts_meta.terrains[index2] - ts_meta.terrains[index2] = temp - _set_terrain_meta(ts, ts_meta) - - _purge_cache(ts) - return true - - -# Terrain tile data - -## For a tile in a [TileSet] as specified by [TileData], set the terrain associated -## with that tile to [code]type[/code], which is an index of an existing terrain. -## Returns [code]true[/code] on success. -func set_tile_terrain_type(ts: TileSet, td: TileData, type: int) -> bool: - if !ts or !td or type < TileCategory.NON_TERRAIN: - return false - - var td_meta = _get_tile_meta(td) - td_meta.type = type - if type == TileCategory.NON_TERRAIN: - td_meta = null - _set_tile_meta(ts, td, td_meta) - - _clear_invalid_peering_types(ts) - _purge_cache(ts) - return true - - -## Returns the terrain type associated with tile specified by [TileData]. Returns -## -1 if the tile has no associated terrain. -func get_tile_terrain_type(td: TileData) -> int: - if !td: - return TileCategory.ERROR - var td_meta := _get_tile_meta(td) - return td_meta.type - - -## For a tile represented by [TileData] [code]td[/code] in [TileSet] -## [code]ts[/code], sets [enum SymmetryType] [code]type[/code]. This controls -## how the tile is rotated/mirrored during placement. -func set_tile_symmetry_type(ts: TileSet, td: TileData, type: int) -> bool: - if !ts or !td or type < SymmetryType.NONE or type > SymmetryType.ALL: - return false - - var td_meta := _get_tile_meta(td) - if td_meta.type == TileCategory.NON_TERRAIN: - return false - - td_meta.symmetry = type - _set_tile_meta(ts, td, td_meta) - _purge_cache(ts) - return true - - -## For a tile [code]td[/code], returns the [enum SymmetryType] which that -## tile uses. -func get_tile_symmetry_type(td: TileData) -> int: - if !td: - return SymmetryType.NONE - - var td_meta := _get_tile_meta(td) - return td_meta.get("symmetry", SymmetryType.NONE) - - -## Returns an Array of all [TileData] tiles included in the specified -## terrain [code]type[/code] for the [TileSet] [code]ts[/code] -func get_tiles_in_terrain(ts: TileSet, type: int) -> Array[TileData]: - var result:Array[TileData] = [] - if !ts or type < TileCategory.EMPTY: - return result - - var cache := _get_cache(ts) - if type > cache.size(): - return result - - var tiles = cache[type] - if !tiles: - return result - for c in tiles: - if c[0] < 0: - continue - var source := ts.get_source(c[0]) as TileSetAtlasSource - var td := source.get_tile_data(c[1], c[2]) - result.push_back(td) - - return result - - -## Returns an [Array] of [Dictionary] items including information about each -## tile included in the specified terrain [code]type[/code] for -## the [TileSet] [code]ts[/code]. Each Dictionary item includes -## [TileSetAtlasSource] [code]source[/code], [TileData] [code]td[/code], -## [Vector2i] [code]coord[/code], and [int] [code]alt_id[/code]. -func get_tile_sources_in_terrain(ts: TileSet, type: int) -> Array[Dictionary]: - var result:Array[Dictionary] = [] - - var cache := _get_cache(ts) - var tiles = cache[type] - if !tiles: - return result - for c in tiles: - if c[0] < 0: - continue - var source := ts.get_source(c[0]) as TileSetAtlasSource - if not source: - continue - var td := source.get_tile_data(c[1], c[2]) - result.push_back({ - source = source, - td = td, - coord = c[1], - alt_id = c[2] - }) - - return result - - -## For a [TileSet]'s tile, specified by [TileData], add terrain [code]type[/code] -## (an index of a terrain) to match this tile in direction [code]peering[/code], -## which is of type [enum TileSet.CellNeighbor]. Returns [code]true[/code] on success. -func add_tile_peering_type(ts: TileSet, td: TileData, peering: int, type: int) -> bool: - if !ts or !td or peering < 0 or peering > 15 or type < TileCategory.EMPTY: - return false - - var ts_meta := _get_terrain_meta(ts) - var td_meta := _get_tile_meta(td) - if td_meta.type < TileCategory.EMPTY or td_meta.type >= ts_meta.terrains.size(): - return false - - if !td_meta.has(peering): - td_meta[peering] = [type] - elif !td_meta[peering].has(type): - td_meta[peering].append(type) - else: - return false - _set_tile_meta(ts, td, td_meta) - _purge_cache(ts) - return true - - -## For a [TileSet]'s tile, specified by [TileData], remove terrain [code]type[/code] -## from matching in direction [code]peering[/code], which is of type [enum TileSet.CellNeighbor]. -## Returns [code]true[/code] on success. -func remove_tile_peering_type(ts: TileSet, td: TileData, peering: int, type: int) -> bool: - if !ts or !td or peering < 0 or peering > 15 or type < TileCategory.EMPTY: - return false - - var td_meta := _get_tile_meta(td) - if !td_meta.has(peering): - return false - if !td_meta[peering].has(type): - return false - td_meta[peering].erase(type) - if td_meta[peering].is_empty(): - td_meta.erase(peering) - _set_tile_meta(ts, td, td_meta) - _purge_cache(ts) - return true - - -## For the tile specified by [TileData], return an [Array] of peering directions -## for which terrain matching is set up. These will be of type [enum TileSet.CellNeighbor]. -func tile_peering_keys(td: TileData) -> Array: - if !td: - return [] - - var td_meta := _get_tile_meta(td) - var result := [] - for k in td_meta: - if k is int: - result.append(k) - return result - - -## For the tile specified by [TileData], return the [Array] of terrains that match -## for the direction [code]peering[/code] which should be of type [enum TileSet.CellNeighbor]. -func tile_peering_types(td: TileData, peering: int) -> Array: - if !td or peering < 0 or peering > 15: - return [] - - var td_meta := _get_tile_meta(td) - return td_meta[peering].duplicate() if td_meta.has(peering) else [] - - -## For the tile specified by [TileData], return the [Array] of peering directions -## for the specified terrain type [code]type[/code]. -func tile_peering_for_type(td: TileData, type: int) -> Array: - if !td: - return [] - - var td_meta := _get_tile_meta(td) - var result := [] - var sides := tile_peering_keys(td) - for side in sides: - if td_meta[side].has(type): - result.push_back(side) - - result.sort() - return result - - -# Painting - -## Applies the terrain [code]type[/code] to the [TileMapLayer] for the [Vector2i] -## [code]coord[/code]. Returns [code]true[/code] if it succeeds. Use [method set_cells] -## to change multiple tiles at once. -## [br][br] -## Use terrain type -1 to erase cells. -func set_cell(tm: TileMapLayer, coord: Vector2i, type: int) -> bool: - if !tm or !tm.tile_set or type < TileCategory.EMPTY: - return false - - if type == TileCategory.EMPTY: - tm.erase_cell(coord) - return true - - var cache := _get_cache(tm.tile_set) - if type >= cache.size(): - return false - - if cache[type].is_empty(): - return false - - var tile = cache[type].front() - tm.set_cell(coord, tile[0], tile[1], tile[2]) - return true - - -## Applies the terrain [code]type[/code] to the [TileMapLayer] for the -## [Vector2i] [code]coords[/code]. Returns [code]true[/code] if it succeeds. -## [br][br] -## Note that this does not cause the terrain solver to run, so this will just place -## an arbitrary terrain-associated tile in the given position. To run the solver, -## you must set the require cells, and then call either [method update_terrain_cell], -## [method update_terrain_cels], or [method update_terrain_area]. -## [br][br] -## If you want to prepare changes to the tiles in advance, you can use [method create_terrain_changeset] -## and the associated functions. -## [br][br] -## Use terrain type -1 to erase cells. -func set_cells(tm: TileMapLayer, coords: Array, type: int) -> bool: - if !tm or !tm.tile_set or type < TileCategory.EMPTY: - return false - - if type == TileCategory.EMPTY: - for c in coords: - tm.erase_cell(c) - return true - - var cache := _get_cache(tm.tile_set) - if type >= cache.size(): - return false - - if cache[type].is_empty(): - return false - - var tile = cache[type].front() - for c in coords: - tm.set_cell(c, tile[0], tile[1], tile[2]) - return true - - -## Replaces an existing tile on the [TileMapLayer] for the [Vector2i] -## [code]coord[/code] with a new tile in the provided terrain [code]type[/code] -## *only if* there is a tile with a matching set of peering sides in this terrain. -## Returns [code]true[/code] if any tiles were changed. Use [method replace_cells] -## to replace multiple tiles at once. -func replace_cell(tm: TileMapLayer, coord: Vector2i, type: int) -> bool: - if !tm or !tm.tile_set or type < 0: - return false - - var cache := _get_cache(tm.tile_set) - if type >= cache.size(): - return false - - if cache[type].is_empty(): - return false - - var td = tm.get_cell_tile_data(coord) - if !td: - return false - - var ts_meta := _get_terrain_meta(tm.tile_set) - var categories = ts_meta.terrains[type][3] - var check_types = [type] + categories - - for check_type in check_types: - var placed_peering = tile_peering_for_type(td, check_type) - for pt in get_tiles_in_terrain(tm.tile_set, type): - var check_peering := tile_peering_for_type(pt, check_type) - if placed_peering == check_peering: - var tile = cache[type].front() - tm.set_cell(coord, tile[0], tile[1], tile[2]) - return true - - return false - - -## Replaces existing tiles on the [TileMapLayer] for the [Vector2i] -## [code]coords[/code] with new tiles in the provided terrain [code]type[/code] -## *only if* there is a tile with a matching set of peering sides in this terrain -## for each tile. -## Returns [code]true[/code] if any tiles were changed. -func replace_cells(tm: TileMapLayer, coords: Array, type: int) -> bool: - if !tm or !tm.tile_set or type < 0: - return false - - var cache := _get_cache(tm.tile_set) - if type >= cache.size(): - return false - - if cache[type].is_empty(): - return false - - var ts_meta := _get_terrain_meta(tm.tile_set) - var categories = ts_meta.terrains[type][3] - var check_types = [type] + categories - - var changed = false - var potential_tiles = get_tiles_in_terrain(tm.tile_set, type) - for c in coords: - var found = false - var td = tm.get_cell_tile_data(c) - if !td: - continue - for check_type in check_types: - var placed_peering = tile_peering_for_type(td, check_type) - for pt in potential_tiles: - var check_peering = tile_peering_for_type(pt, check_type) - if placed_peering == check_peering: - var tile = cache[type].front() - tm.set_cell(c, tile[0], tile[1], tile[2]) - changed = true - found = true - break - - if found: - break - - return changed - - -## Returns the terrain type detected in the [TileMapLayer] at specified [Vector2i] -## [code]coord[/code]. Returns -1 if tile is not valid or does not contain a -## tile associated with a terrain. -func get_cell(tm: TileMapLayer, coord: Vector2i) -> int: - if !tm or !tm.tile_set: - return TileCategory.ERROR - - if tm.get_cell_source_id(coord) == -1: - return TileCategory.EMPTY - - var t := tm.get_cell_tile_data(coord) - if !t: - return TileCategory.NON_TERRAIN - - return _get_tile_meta(t).type - - -## Runs the tile solving algorithm on the [TileMapLayer] for the given -## [Vector2i] coordinates in the [code]cells[/code] parameter. By default, -## the surrounding cells are also solved, but this can be adjusted by passing [code]false[/code] -## to the [code]and_surrounding_cells[/code] parameter. -## [br][br] -## See also [method update_terrain_area] and [method update_terrain_cell]. -func update_terrain_cells(tm: TileMapLayer, cells: Array, and_surrounding_cells := true) -> void: - if !tm or !tm.tile_set: - return - - if and_surrounding_cells: - cells = _widen(tm, cells) - var needed_cells := _widen(tm, cells) - - var types := {} - for c in needed_cells: - types[c] = get_cell(tm, c) - - var ts_meta := _get_terrain_meta(tm.tile_set) - var cache := _get_cache(tm.tile_set) - for c in cells: - _update_tile_immediate(tm, c, ts_meta, types, cache) - - -## Runs the tile solving algorithm on the [TileMapLayer] for the given [Vector2i] -## [code]cell[/code]. By default, the surrounding cells are also solved, but -## this can be adjusted by passing [code]false[/code] to the [code]and_surrounding_cells[/code] -## parameter. This calls through to [method update_terrain_cells]. -func update_terrain_cell(tm: TileMapLayer, cell: Vector2i, and_surrounding_cells := true) -> void: - update_terrain_cells(tm, [cell], and_surrounding_cells) - - -## Runs the tile solving algorithm on the [TileMapLayer] for the given [Rect2i] -## [code]area[/code]. By default, the surrounding cells are also solved, but -## this can be adjusted by passing [code]false[/code] to the [code]and_surrounding_cells[/code] -## parameter. -## [br][br] -## See also [method update_terrain_cells]. -func update_terrain_area(tm: TileMapLayer, area: Rect2i, and_surrounding_cells := true) -> void: - if !tm or !tm.tile_set: - return - - # Normalize area and extend so tiles cover inclusive space - area = area.abs() - area.size += Vector2i.ONE - - var edges = [] - for x in range(area.position.x, area.end.x): - edges.append(Vector2i(x, area.position.y)) - edges.append(Vector2i(x, area.end.y - 1)) - for y in range(area.position.y + 1, area.end.y - 1): - edges.append(Vector2i(area.position.x, y)) - edges.append(Vector2i(area.end.x - 1, y)) - - var additional_cells := [] - var needed_cells := _widen_with_exclusion(tm, edges, area) - - if and_surrounding_cells: - additional_cells = needed_cells - needed_cells = _widen_with_exclusion(tm, needed_cells, area) - - var types := {} - for y in range(area.position.y, area.end.y): - for x in range(area.position.x, area.end.x): - var coord = Vector2i(x, y) - types[coord] = get_cell(tm, coord) - for c in needed_cells: - types[c] = get_cell(tm, c) - - var ts_meta := _get_terrain_meta(tm.tile_set) - var cache := _get_cache(tm.tile_set) - for y in range(area.position.y, area.end.y): - for x in range(area.position.x, area.end.x): - var coord := Vector2i(x, y) - _update_tile_immediate(tm, coord, ts_meta, types, cache) - for c in additional_cells: - _update_tile_immediate(tm, c, ts_meta, types, cache) - - -## For a [TileMapLayer], create a changeset that will -## be calculated via a [WorkerThreadPool], so it will not delay processing the current -## frame or affect the framerate. -## [br][br] -## The [code]paint[/code] parameter must be a [Dictionary] with keys of type [Vector2i] -## representing map coordinates, and integer values representing terrain types. -## [br][br] -## Returns a [Dictionary] with internal details. See also [method is_terrain_changeset_ready], -## [method apply_terrain_changeset], and [method wait_for_terrain_changeset]. -func create_terrain_changeset(tm: TileMapLayer, paint: Dictionary) -> Dictionary: - # Force cache rebuild if required - var _cache := _get_cache(tm.tile_set) - - var cells := paint.keys() - var needed_cells := _widen(tm, cells) - - var types := {} - for c in needed_cells: - types[c] = paint[c] if paint.has(c) else get_cell(tm, c) - - var placements := [] - placements.resize(cells.size()) - - var ts_meta := _get_terrain_meta(tm.tile_set) - var work := func(n: int): - placements[n] = _update_tile_deferred(tm, cells[n], ts_meta, types, _cache) - - return { - "valid": true, - "tilemap": tm, - "cells": cells, - "placements": placements, - "group_id": WorkerThreadPool.add_group_task(work, cells.size(), -1, false, "BetterTerrain") - } - - -## Returns [code]true[/code] if a changeset created by [method create_terrain_changeset] -## has finished the threaded calculation and is ready to be applied by [method apply_terrain_changeset]. -## See also [method wait_for_terrain_changeset]. -func is_terrain_changeset_ready(change: Dictionary) -> bool: - if !change.has("group_id"): - return false - - return WorkerThreadPool.is_group_task_completed(change.group_id) - - -## Blocks until a changeset created by [method create_terrain_changeset] finishes. -## This is useful to tidy up threaded work in the event that a node is to be removed -## whilst still waiting on threads. -## [br][br] -## Usage example: -## [codeblock] -## func _exit_tree(): -## if changeset.valid: -## BetterTerrain.wait_for_terrain_changeset(changeset) -## [/codeblock] -func wait_for_terrain_changeset(change: Dictionary) -> void: - if change.has("group_id"): - WorkerThreadPool.wait_for_group_task_completion(change.group_id) - - -## Apply the changes in a changeset created by [method create_terrain_changeset] -## once it is confirmed by [method is_terrain_changeset_ready]. The changes will -## be applied to the [TileMapLayer] that the changeset was initialized with. -## [br][br] -## Completed changesets can be applied multiple times, and stored for as long as -## needed once calculated. -func apply_terrain_changeset(change: Dictionary) -> void: - for n in change.cells.size(): - var placement = change.placements[n] - if placement: - change.tilemap.set_cell(change.cells[n], placement[0], placement[1], placement[2]) diff --git a/godot/addons/better-terrain/BetterTerrain.gd.uid b/godot/addons/better-terrain/BetterTerrain.gd.uid deleted file mode 100644 index 735e021..0000000 --- a/godot/addons/better-terrain/BetterTerrain.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d2so7sid6wvhf diff --git a/godot/addons/better-terrain/BetterTerrainData.gd b/godot/addons/better-terrain/BetterTerrainData.gd deleted file mode 100644 index 5d3bcd5..0000000 --- a/godot/addons/better-terrain/BetterTerrainData.gd +++ /dev/null @@ -1,598 +0,0 @@ -@tool - -## Data functions for [TileSet] properties. -## -## This data class has functions for retrieving data regarding the mathematical -## properties of a tile set. - -const _terrain_peering_square_tiles : Array[int] = [0, 3, 4, 7, 8, 11, 12, 15] -const _terrain_peering_square_vertices : Array[int] = [3, 7, 11, 15] -const _terrain_peering_isometric_tiles : Array[int] = [1, 2, 5, 6, 9, 10, 13, 14] -const _terrain_peering_isometric_vertices : Array[int] = [1, 5, 9, 13] -const _terrain_peering_horiztonal_tiles : Array[int] = [0, 2, 6, 8, 10, 14] -const _terrain_peering_horiztonal_vertices : Array[int] = [3, 5, 7, 11, 13, 15] -const _terrain_peering_vertical_tiles : Array[int] = [2, 4, 6, 10, 12, 14] -const _terrain_peering_vertical_vertices : Array[int] = [1, 3, 7, 9, 11, 15] -const _terrain_peering_non_modifying : Array[int] = [] - -const _terrain_peering_hflip : Array[int] = [8, 9, 6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11] -const _terrain_peering_vflip : Array[int] = [0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3] -const _terrain_peering_transpose : Array[int] = [4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7] - -const symmetry_mapping := { - BetterTerrain.SymmetryType.NONE: [0], - BetterTerrain.SymmetryType.MIRROR: [0, TileSetAtlasSource.TRANSFORM_FLIP_H], - BetterTerrain.SymmetryType.FLIP: [0, TileSetAtlasSource.TRANSFORM_FLIP_V], - BetterTerrain.SymmetryType.REFLECT: [ - 0, - TileSetAtlasSource.TRANSFORM_FLIP_H, - TileSetAtlasSource.TRANSFORM_FLIP_V, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V - ], - BetterTerrain.SymmetryType.ROTATE_CLOCKWISE: [0, TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_TRANSPOSE], - BetterTerrain.SymmetryType.ROTATE_COUNTER_CLOCKWISE: [0, TileSetAtlasSource.TRANSFORM_FLIP_V | TileSetAtlasSource.TRANSFORM_TRANSPOSE], - BetterTerrain.SymmetryType.ROTATE_180: [0, TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V], - BetterTerrain.SymmetryType.ROTATE_ALL: [ - 0, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_TRANSPOSE, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V, - TileSetAtlasSource.TRANSFORM_FLIP_V | TileSetAtlasSource.TRANSFORM_TRANSPOSE - ], - BetterTerrain.SymmetryType.ALL: [ - 0, - TileSetAtlasSource.TRANSFORM_FLIP_H, - TileSetAtlasSource.TRANSFORM_FLIP_V, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V, - TileSetAtlasSource.TRANSFORM_TRANSPOSE, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_TRANSPOSE, - TileSetAtlasSource.TRANSFORM_FLIP_V | TileSetAtlasSource.TRANSFORM_TRANSPOSE, - TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V | TileSetAtlasSource.TRANSFORM_TRANSPOSE - ] -} - - -## Returns an [Array] of ints of type [enum TileSet.CellNeighbor] which represent -## the valid neighboring tiles for a terrain of [code]type[/code] in TileSet -static func get_terrain_peering_cells(ts: TileSet, type: int) -> Array[int]: - if !ts or type < 0 or type >= BetterTerrain.TerrainType.MAX: - return [] - - if type == BetterTerrain.TerrainType.CATEGORY: - return _terrain_peering_non_modifying - if type == BetterTerrain.TerrainType.DECORATION: - type = BetterTerrain.TerrainType.MATCH_TILES - - match [ts.tile_shape, type]: - [TileSet.TILE_SHAPE_SQUARE, BetterTerrain.TerrainType.MATCH_TILES]: - return _terrain_peering_square_tiles - [TileSet.TILE_SHAPE_SQUARE, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _terrain_peering_square_vertices - [TileSet.TILE_SHAPE_ISOMETRIC, BetterTerrain.TerrainType.MATCH_TILES]: - return _terrain_peering_isometric_tiles - [TileSet.TILE_SHAPE_ISOMETRIC, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _terrain_peering_isometric_vertices - - match [ts.tile_offset_axis, type]: - [TileSet.TILE_OFFSET_AXIS_VERTICAL, BetterTerrain.TerrainType.MATCH_TILES]: - return _terrain_peering_vertical_tiles - [TileSet.TILE_OFFSET_AXIS_VERTICAL, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _terrain_peering_vertical_vertices - [TileSet.TILE_OFFSET_AXIS_HORIZONTAL, BetterTerrain.TerrainType.MATCH_TILES]: - return _terrain_peering_horiztonal_tiles - [TileSet.TILE_OFFSET_AXIS_HORIZONTAL, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _terrain_peering_horiztonal_vertices - - return [] - - -## Returns true if [code]peering[/code] is a valid neighboring cell for a terrain of -## [code]type[/code] in [TileSet] -static func is_terrain_peering_cell(ts: TileSet, type: int, peering: int) -> bool: - return peering in get_terrain_peering_cells(ts, type) - - -static func _peering_polygon_square_tiles(peering: int) -> PackedVector2Array: - const t := 1.0 / 3.0 - var result : PackedVector2Array - match peering: - TileSet.CELL_NEIGHBOR_RIGHT_SIDE: result.append(Vector2(2*t, t)) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: result.append(Vector2(2*t, 2*t)) - TileSet.CELL_NEIGHBOR_BOTTOM_SIDE: result.append(Vector2(t, 2*t)) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: result.append(Vector2(0, 2*t)) - TileSet.CELL_NEIGHBOR_LEFT_SIDE: result.append(Vector2(0, t)) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: result.append(Vector2(0, 0)) - TileSet.CELL_NEIGHBOR_TOP_SIDE: result.append(Vector2(t, 0)) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: result.append(Vector2(2*t, 0)) - -1: result.append(Vector2(t, t)) - result.append(result[0] + Vector2(t, 0)) - result.append(result[0] + Vector2(t, t)) - result.append(result[0] + Vector2(0, t)) - return result - - -static func _peering_polygon_square_vertices(peering: int) -> PackedVector2Array: - const t := 1.0 / 2.0 - var result : PackedVector2Array - match peering: - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - result.append(Vector2(1, t)) - result.append(Vector2(1, 1)) - result.append(Vector2(t, 1)) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - result.append(Vector2(0, t)) - result.append(Vector2(t, 1)) - result.append(Vector2(0, 1)) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - result.append(Vector2(0, 0)) - result.append(Vector2(t, 0)) - result.append(Vector2(0, t)) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - result.append(Vector2(t, 0)) - result.append(Vector2(1, 0)) - result.append(Vector2(1, t)) - -1: - result.append(Vector2(t, 0)) - result.append(Vector2(1, t)) - result.append(Vector2(t, 1)) - result.append(Vector2(0, t)) - return result - - -static func _peering_polygon_isometric_tiles(peering: int) -> PackedVector2Array: - const t := 1.0 / 4.0 - match peering: - -1: return PackedVector2Array([Vector2(2 * t, t), Vector2(3 * t, 2 * t), Vector2(2 * t, 3 * t), Vector2(t, 2 * t)]) - TileSet.CELL_NEIGHBOR_RIGHT_CORNER: - return PackedVector2Array([Vector2(3 * t, 2 * t), Vector2(1, t), Vector2(1, 3 * t)]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - return PackedVector2Array([Vector2(3 * t, 2 * t), Vector2(1, 3 * t), Vector2(3 * t, 1), Vector2(2 * t, 3 * t)]) - TileSet.CELL_NEIGHBOR_BOTTOM_CORNER: - return PackedVector2Array([Vector2(2 * t, 3 * t), Vector2(3 * t, 1), Vector2(t, 1)]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - return PackedVector2Array([Vector2(t, 2 * t), Vector2(2 * t, 3 * t), Vector2(t, 1), Vector2(0, 3 * t)]) - TileSet.CELL_NEIGHBOR_LEFT_CORNER: - return PackedVector2Array([Vector2(0, t), Vector2(t, 2 * t), Vector2(0, 3 * t)]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE: - return PackedVector2Array([Vector2(t, 0), Vector2(2 * t, t), Vector2(t, 2 * t), Vector2(0, t)]) - TileSet.CELL_NEIGHBOR_TOP_CORNER: - return PackedVector2Array([Vector2(t, 0), Vector2(3 * t, 0), Vector2(2 * t, t)]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_SIDE: - return PackedVector2Array([Vector2(3 * t, 0), Vector2(1, t), Vector2(3 * t, 2 * t), Vector2(2 * t, t)]) - return PackedVector2Array() - - -static func _peering_polygon_isometric_vertices(peering: int) -> PackedVector2Array: - const t := 1.0 / 4.0 - const ttt := 3.0 * t - match peering: - -1: return PackedVector2Array([Vector2(t, t), Vector2(ttt, t), Vector2(ttt, ttt), Vector2(t, ttt)]) - TileSet.CELL_NEIGHBOR_RIGHT_CORNER: - return PackedVector2Array([Vector2(ttt, t), Vector2(1, 0), Vector2(1, 1), Vector2(ttt, ttt)]) - TileSet.CELL_NEIGHBOR_BOTTOM_CORNER: - return PackedVector2Array([Vector2(t, ttt), Vector2(ttt, ttt), Vector2(1, 1), Vector2(0, 1)]) - TileSet.CELL_NEIGHBOR_LEFT_CORNER: - return PackedVector2Array([Vector2(0, 0), Vector2(t, t), Vector2(t, ttt), Vector2(0, 1)]) - TileSet.CELL_NEIGHBOR_TOP_CORNER: - return PackedVector2Array([Vector2(0, 0), Vector2(1, 0), Vector2(ttt, t), Vector2(t, t)]) - return PackedVector2Array() - - -static func _peering_polygon_horizontal_tiles(peering: int) -> PackedVector2Array: - const e := 1.0 / (2.0 * sqrt(3.0)) - const w := sqrt(3.0) / 8.0 - const t := 1.0 / 2.0 - const s := 1.0 / 8.0 - match peering: - -1: - return PackedVector2Array([ - Vector2(t, 2 * s), - Vector2(t + w, t - s), - Vector2(t + w, t + s), - Vector2(t, 6 * s), - Vector2(t - w, t + s), - Vector2(t - w, t - s) - ]) - TileSet.CELL_NEIGHBOR_RIGHT_SIDE: - return PackedVector2Array([ - Vector2(t + w, t - s), - Vector2(1, t - e), - Vector2(1, t + e), - Vector2(t + w, t + s) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - return PackedVector2Array([ - Vector2(t + w, t + s), - Vector2(1, t + e), - Vector2(t, 1), - Vector2(t, 6 * s) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - return PackedVector2Array([ - Vector2(t, 6 * s), - Vector2(t, 1), - Vector2(0, t + e), - Vector2(t - w, t + s) - ]) - TileSet.CELL_NEIGHBOR_LEFT_SIDE: - return PackedVector2Array([ - Vector2(t - w, t + s), - Vector2(0, t + e), - Vector2(0, t - e), - Vector2(t - w, t - s) - ]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE: - return PackedVector2Array([ - Vector2(t - w, t - s), - Vector2(0, t - e), - Vector2(t, 0), - Vector2(t, 2 * s) - ]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_SIDE: - return PackedVector2Array([ - Vector2(t, 2 * s), - Vector2(t, 0), - Vector2(1, t - e), - Vector2(t + w, t - s) - ]) - return PackedVector2Array() - - -static func _peering_polygon_horizontal_vertices(peering: int) -> PackedVector2Array: - const e := 1.0 / (2.0 * sqrt(3.0)) - const w := sqrt(3.0) / 8.0 - const t := 1.0 / 2.0 - const s := 1.0 / 8.0 - match peering: - -1: - return PackedVector2Array([ - Vector2(t - s, t - w), - Vector2(t + s, t - w), - Vector2(6 * s, t), - Vector2(t + s, t + w), - Vector2(t - s, t + w), - Vector2(2 * s, t) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return PackedVector2Array([ - Vector2(6 * s, t), - Vector2(1, t), - Vector2(1, t + e), - Vector2(t + e, 1 - s), - Vector2(t + s, t + w) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_CORNER: - return PackedVector2Array([ - Vector2(t - s, t + w), - Vector2(t + s, t + w), - Vector2(t + e, 1 - s), - Vector2(t, 1), - Vector2(t - e, 1 - s) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return PackedVector2Array([ - Vector2(0, t), - Vector2(2 * s, t), - Vector2(t - s, t + w), - Vector2(t - e, 1 - s), - Vector2(0, t + e) - ]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - return PackedVector2Array([ - Vector2(t - e, s), - Vector2(t - s, t - w), - Vector2(2 * s, t), - Vector2(0, t), - Vector2(0, t - e) - ]) - TileSet.CELL_NEIGHBOR_TOP_CORNER: - return PackedVector2Array([ - Vector2(t, 0), - Vector2(t + e, s), - Vector2(t + s, t - w), - Vector2(t - s, t - w), - Vector2(t - e, s) - ]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return PackedVector2Array([ - Vector2(t + e, s), - Vector2(1, t - e), - Vector2(1, t), - Vector2(6 * s, t), - Vector2(t + s, t - w) - ]) - return PackedVector2Array() - - -static func _peering_polygon_vertical_tiles(peering: int) -> PackedVector2Array: - const e := 1.0 / (2.0 * sqrt(3.0)) - const w := sqrt(3.0) / 8.0 - const t := 1.0 / 2.0 - const s := 1.0 / 8.0 - match peering: - -1: - return PackedVector2Array([ - Vector2(t - s, t - w), - Vector2(t + s, t - w), - Vector2(6 * s, t), - Vector2(t + s, t + w), - Vector2(t - s, t + w), - Vector2(2 * s, t) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - return PackedVector2Array([ - Vector2(6 * s, t), - Vector2(1, t), - Vector2(t + e, 1), - Vector2(t + s, t + w) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_SIDE: - return PackedVector2Array([ - Vector2(t - s, t + w), - Vector2(t + s, t + w), - Vector2(t + e, 1), - Vector2(t - e, 1) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - return PackedVector2Array([ - Vector2(0, t), - Vector2(2 * s, t), - Vector2(t - s, t + w), - Vector2(t - e, 1) - ]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_SIDE: - return PackedVector2Array([ - Vector2(t - e, 0), - Vector2(t - s, t - w), - Vector2(2 * s, t), - Vector2(0, t) - ]) - TileSet.CELL_NEIGHBOR_TOP_SIDE: - return PackedVector2Array([ - Vector2(t - e, 0), - Vector2(t + e, 0), - Vector2(t + s, t - w), - Vector2(t - s, t - w) - ]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_SIDE: - return PackedVector2Array([ - Vector2(t + e, 0), - Vector2(1, t), - Vector2(6 * s, t), - Vector2(t + s, t - w) - ]) - return PackedVector2Array() - - -static func _peering_polygon_vertical_vertices(peering: int) -> PackedVector2Array: - const e := 1.0 / (2.0 * sqrt(3.0)) - const w := sqrt(3.0) / 8.0 - const t := 1.0 / 2.0 - const s := 1.0 / 8.0 - match peering: - -1: - return PackedVector2Array([ - Vector2(t, 2 * s), - Vector2(t + w, t - s), - Vector2(t + w, t + s), - Vector2(t, 6 * s), - Vector2(t - w, t + s), - Vector2(t - w, t - s) - ]) - TileSet.CELL_NEIGHBOR_RIGHT_CORNER: - return PackedVector2Array([ - Vector2(1 - s, t - e), - Vector2(1, t), - Vector2(1 - s, t + e), - Vector2(t + w, t + s), - Vector2(t + w, t - s) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return PackedVector2Array([ - Vector2(t + w, t + s), - Vector2(1 - s, t + e), - Vector2(t + e, 1), - Vector2(t, 1), - Vector2(t, 6 * s) - ]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return PackedVector2Array([ - Vector2(t - w, t + s), - Vector2(t, 6 * s), - Vector2(t, 1), - Vector2(t - e, 1), - Vector2(s, t + e) - ]) - TileSet.CELL_NEIGHBOR_LEFT_CORNER: - return PackedVector2Array([ - Vector2(s, t - e), - Vector2(t - w, t - s), - Vector2(t - w, t + s), - Vector2(s, t + e), - Vector2(0, t) - ]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - return PackedVector2Array([ - Vector2(t - e, 0), - Vector2(t, 0), - Vector2(t, 2 * s), - Vector2(t - w, t - s), - Vector2(s, t - e) - ]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return PackedVector2Array([ - Vector2(t, 0), - Vector2(t + e, 0), - Vector2(1 - s, t - e), - Vector2(t + w, t - s), - Vector2(t, 2 * s) - ]) - return PackedVector2Array() - - -static func _peering_non_modifying() -> PackedVector2Array: - const t := 1.0 / 3.0 - return PackedVector2Array([ - Vector2(t, 0), - Vector2(2 * t, 0), - Vector2(1, t), - Vector2(1, 2 * t), - Vector2(2 * t, 1), - Vector2(t, 1), - Vector2(0, 2 * t), - Vector2(0, t) - ]) - - -## Returns a parameterized polygon (coordinated are between 0 and 1) for [code]peering[/code] -## direction for a terrain of [code]type[/code] in [TileSet] -static func peering_polygon(ts: TileSet, type: int, peering: int) -> PackedVector2Array: - if type == BetterTerrain.TerrainType.CATEGORY: - return _peering_non_modifying() - if type == BetterTerrain.TerrainType.DECORATION: - type = BetterTerrain.TerrainType.MATCH_TILES - - match [ts.tile_shape, type]: - [TileSet.TILE_SHAPE_SQUARE, BetterTerrain.TerrainType.MATCH_TILES]: - return _peering_polygon_square_tiles(peering) - [TileSet.TILE_SHAPE_SQUARE, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _peering_polygon_square_vertices(peering) - [TileSet.TILE_SHAPE_ISOMETRIC, BetterTerrain.TerrainType.MATCH_TILES]: - return _peering_polygon_isometric_tiles(peering) - [TileSet.TILE_SHAPE_ISOMETRIC, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _peering_polygon_isometric_vertices(peering) - - match [ts.tile_offset_axis, type]: - [TileSet.TILE_OFFSET_AXIS_VERTICAL, BetterTerrain.TerrainType.MATCH_TILES]: - return _peering_polygon_vertical_tiles(peering) - [TileSet.TILE_OFFSET_AXIS_VERTICAL, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _peering_polygon_vertical_vertices(peering) - [TileSet.TILE_OFFSET_AXIS_HORIZONTAL, BetterTerrain.TerrainType.MATCH_TILES]: - return _peering_polygon_horizontal_tiles(peering) - [TileSet.TILE_OFFSET_AXIS_HORIZONTAL, BetterTerrain.TerrainType.MATCH_VERTICES]: - return _peering_polygon_horizontal_vertices(peering) - - return PackedVector2Array() - - -## Returns as polygon centered on 0, 0 which represents the shape of the cell of -## a tile from [TileSet]. -static func cell_polygon(ts: TileSet) -> PackedVector2Array: - const t := 1.0 / 2.0 - if ts.tile_shape in [TileSet.TILE_SHAPE_SQUARE, TileSet.TILE_SHAPE_HALF_OFFSET_SQUARE]: - return PackedVector2Array([Vector2(-t, -t), Vector2(t, -t), Vector2(t, t), Vector2(-t, t)]) - if ts.tile_shape == TileSet.TILE_SHAPE_ISOMETRIC: - return PackedVector2Array([Vector2(0, -t), Vector2(t, 0), Vector2(0, t), Vector2(-t, 0)]) - - const e := t - 1.0 / (2.0 * sqrt(3.0)) - if ts.tile_offset_axis == TileSet.TILE_OFFSET_AXIS_HORIZONTAL: - return PackedVector2Array([ - Vector2(0, -t), - Vector2(t, -e), - Vector2(t, e), - Vector2(0, t), - Vector2(-t, e), - Vector2(-t, -e), - ]) - - return PackedVector2Array([ - Vector2(-t, 0), - Vector2(-e, -t), - Vector2(e, -t), - Vector2(t, 0), - Vector2(e, t), - Vector2(-e, t), - ]) - - -## Returns an [Array] of coordinated that neighbor [code]coord[/code] based on [code]peering[/code] -## [Array] of [enum TileSet.CellNeighbor] for a [TileSet]. -static func neighboring_coords(tm: TileMapLayer, coord: Vector2i, peerings: Array) -> Array: - return peerings.map(func(p): return tm.get_neighbor_cell(coord, p)) - - -## Returns an [Array] of coordinates which neighbor the vertex describe by [code]corner[/code] -## (which is of type [enum TileSet.CellNeighbor]) from [code]coord[/code] in [TileSet]. -static func associated_vertex_cells(tm: TileMapLayer, coord: Vector2i, corner: int) -> Array: - # get array of associated peering bits - if tm.tile_set.tile_shape in [TileSet.TILE_SHAPE_SQUARE, TileSet.TILE_SHAPE_ISOMETRIC]: - match corner: - # Square - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return neighboring_coords(tm, coord, [0, 3, 4]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return neighboring_coords(tm, coord, [4, 7, 8]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - return neighboring_coords(tm, coord, [8, 11, 12]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return neighboring_coords(tm, coord, [12, 15, 0]) - # Isometric - TileSet.CELL_NEIGHBOR_RIGHT_CORNER: - return neighboring_coords(tm, coord, [14, 1, 2]) - TileSet.CELL_NEIGHBOR_BOTTOM_CORNER: - return neighboring_coords(tm, coord, [2, 5, 6]) - TileSet.CELL_NEIGHBOR_LEFT_CORNER: - return neighboring_coords(tm, coord, [6, 9, 10]) - TileSet.CELL_NEIGHBOR_TOP_CORNER: - return neighboring_coords(tm, coord, [10, 13, 14]) - - if tm.tile_set.tile_offset_axis == TileSet.TILE_OFFSET_AXIS_HORIZONTAL: - match corner: - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return neighboring_coords(tm, coord, [0, 2]) - TileSet.CELL_NEIGHBOR_BOTTOM_CORNER: - return neighboring_coords(tm, coord, [2, 6]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return neighboring_coords(tm, coord, [6, 8]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - return neighboring_coords(tm, coord, [8, 10]) - TileSet.CELL_NEIGHBOR_TOP_CORNER: - return neighboring_coords(tm, coord, [10, 14]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return neighboring_coords(tm, coord, [14, 0]) - - # TileSet.TILE_OFFSET_AXIS_VERTICAL - match corner: - TileSet.CELL_NEIGHBOR_RIGHT_CORNER: - return neighboring_coords(tm, coord, [14, 2]) - TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - return neighboring_coords(tm, coord, [2, 4]) - TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - return neighboring_coords(tm, coord, [4, 6]) - TileSet.CELL_NEIGHBOR_LEFT_CORNER: - return neighboring_coords(tm, coord, [6, 10]) - TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER: - return neighboring_coords(tm, coord, [10, 12]) - TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER: - return neighboring_coords(tm, coord, [12, 14]) - - return [] - - -## Returns an [Array] of [enum TileSet.CellNeighbor] suitable for flood filling -## an area in [TileSet]. -static func cells_adjacent_for_fill(ts: TileSet) -> Array[int]: - if ts.tile_shape == TileSet.TILE_SHAPE_SQUARE: - return [0, 4, 8, 12] - if ts.tile_shape == TileSet.TILE_SHAPE_ISOMETRIC: - return [2, 6, 10, 14] - if ts.tile_offset_axis == TileSet.TILE_OFFSET_AXIS_HORIZONTAL: - return _terrain_peering_horiztonal_tiles - return _terrain_peering_vertical_tiles - - -static func peering_bit_after_symmetry(bit: int, altflags: int) -> int: - if altflags & TileSetAtlasSource.TRANSFORM_TRANSPOSE: - bit = _terrain_peering_transpose[bit] - if altflags & TileSetAtlasSource.TRANSFORM_FLIP_H: - bit = _terrain_peering_hflip[bit] - if altflags & TileSetAtlasSource.TRANSFORM_FLIP_V: - bit = _terrain_peering_vflip[bit] - return bit - - -static func peering_bits_after_symmetry(dict: Dictionary, altflags: int) -> Dictionary: - # rearrange dictionary keys based on altflags - var result := {} - for k in dict: - result[peering_bit_after_symmetry(k, altflags)] = dict[k] - return result diff --git a/godot/addons/better-terrain/BetterTerrainData.gd.uid b/godot/addons/better-terrain/BetterTerrainData.gd.uid deleted file mode 100644 index 7525c09..0000000 --- a/godot/addons/better-terrain/BetterTerrainData.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cmeo3arrf2ccv diff --git a/godot/addons/better-terrain/TerrainPlugin.gd b/godot/addons/better-terrain/TerrainPlugin.gd deleted file mode 100644 index eb514ae..0000000 --- a/godot/addons/better-terrain/TerrainPlugin.gd +++ /dev/null @@ -1,73 +0,0 @@ -@tool -extends EditorPlugin - -const AUTOLOAD_NAME = "BetterTerrain" -var dock : Control -var button : Button - -func _enter_tree() -> void: - # Wait for autoloads to register - await get_tree().process_frame - - if !get_tree().root.get_node_or_null(^"BetterTerrain"): - # Autoload wasn't present on plugin init, which means plugin won't have loaded correctly - add_autoload_singleton(AUTOLOAD_NAME, "res://addons/better-terrain/BetterTerrain.gd") - ProjectSettings.save() - - var confirm = ConfirmationDialog.new() - confirm.dialog_text = "The editor needs to be restarted for Better Terrain to load correctly. Restart now? Note: Unsaved changes will be lost." - confirm.confirmed.connect(func(): - OS.set_restart_on_exit(true, ["-e"]) - get_tree().quit() - ) - get_editor_interface().popup_dialog_centered(confirm) - - dock = load("res://addons/better-terrain/editor/Dock.tscn").instantiate() - dock.update_overlay.connect(self.update_overlays) - get_editor_interface().get_editor_main_screen().mouse_exited.connect(dock.canvas_mouse_exit) - dock.undo_manager = get_undo_redo() - button = add_control_to_bottom_panel(dock, "Terrain") - button.toggled.connect(dock.about_to_be_visible) - dock.force_show_terrains.connect(button.toggled.emit.bind(true)) - button.visible = false - - -func _exit_tree() -> void: - remove_control_from_bottom_panel(dock) - dock.queue_free() - - -func _handles(object) -> bool: - return object is TileMapLayer or object is TileSet - - -func _make_visible(visible) -> void: - button.visible = visible - - -func _edit(object) -> void: - var new_tileset : TileSet = null - - if object is TileMapLayer: - dock.tilemap = object - new_tileset = object.tile_set - if object is TileSet: - dock.tilemap = null - new_tileset = object - - if dock.tileset != new_tileset: - dock.tiles_about_to_change() - dock.tileset = new_tileset - dock.tiles_changed() - - -func _forward_canvas_draw_over_viewport(overlay: Control) -> void: - if dock.visible: - dock.canvas_draw(overlay) - - -func _forward_canvas_gui_input(event: InputEvent) -> bool: - if !dock.visible: - return false - - return dock.canvas_input(event) diff --git a/godot/addons/better-terrain/TerrainPlugin.gd.uid b/godot/addons/better-terrain/TerrainPlugin.gd.uid deleted file mode 100644 index daee621..0000000 --- a/godot/addons/better-terrain/TerrainPlugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dar1dq8au8dgv diff --git a/godot/addons/better-terrain/Watcher.gd b/godot/addons/better-terrain/Watcher.gd deleted file mode 100644 index 0c5fa51..0000000 --- a/godot/addons/better-terrain/Watcher.gd +++ /dev/null @@ -1,20 +0,0 @@ -@tool -extends Node - -signal trigger -var complete := false -var tileset : TileSet - -func tidy() -> bool: - if complete: - return false - - complete = true - queue_free() - return true - - -func activate(): - if tidy(): - trigger.emit() - diff --git a/godot/addons/better-terrain/Watcher.gd.uid b/godot/addons/better-terrain/Watcher.gd.uid deleted file mode 100644 index 6ed5b77..0000000 --- a/godot/addons/better-terrain/Watcher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4sdpl0lvpfct diff --git a/godot/addons/better-terrain/editor/Dock.gd b/godot/addons/better-terrain/editor/Dock.gd deleted file mode 100644 index 9d2b6f7..0000000 --- a/godot/addons/better-terrain/editor/Dock.gd +++ /dev/null @@ -1,948 +0,0 @@ -@tool -extends Control - -signal update_overlay -signal force_show_terrains - -# The maximum individual tiles the overlay will draw before shortcutting the display -# To prevent editor lag when drawing large rectangles or filling large areas -const MAX_CANVAS_RENDER_TILES = 1500 -const TERRAIN_PROPERTIES_SCENE := preload("res://addons/better-terrain/editor/TerrainProperties.tscn") -const TERRAIN_ENTRY_SCENE := preload("res://addons/better-terrain/editor/TerrainEntry.tscn") -const MIN_ZOOM_SETTING := "editor/better_terrain/min_zoom_amount" -const MAX_ZOOM_SETTING := "editor/better_terrain/max_zoom_amount" - - -# Buttons -@onready var draw_button: Button = $VBox/Toolbar/Draw -@onready var line_button: Button = $VBox/Toolbar/Line -@onready var rectangle_button: Button = $VBox/Toolbar/Rectangle -@onready var fill_button: Button = $VBox/Toolbar/Fill -@onready var replace_button: Button = $VBox/Toolbar/Replace - -@onready var paint_type: Button = $VBox/Toolbar/PaintType -@onready var paint_terrain: Button = $VBox/Toolbar/PaintTerrain -@onready var select_tiles: Button = $VBox/Toolbar/SelectTiles - -@onready var paint_symmetry: Button = $VBox/Toolbar/PaintSymmetry -@onready var symmetry_options: OptionButton = $VBox/Toolbar/SymmetryOptions - -@onready var shuffle_random: Button = $VBox/Toolbar/ShuffleRandom -@onready var zoom_slider_container: VBoxContainer = $VBox/Toolbar/ZoomContainer - -@onready var source_selector: MenuBar = $VBox/Toolbar/Sources -@onready var source_selector_popup: PopupMenu = $VBox/Toolbar/Sources/Sources - -@onready var clean_button: Button = $VBox/Toolbar/Clean -@onready var layer_up: Button = $VBox/Toolbar/LayerUp -@onready var layer_down: Button = $VBox/Toolbar/LayerDown -@onready var layer_highlight: Button = $VBox/Toolbar/LayerHighlight -@onready var layer_grid: Button = $VBox/Toolbar/LayerGrid - -@onready var grid_mode_button: Button = $VBox/HSplit/Terrains/LowerToolbar/GridMode -@onready var quick_mode_button: Button = $VBox/HSplit/Terrains/LowerToolbar/QuickMode - -@onready var edit_tool_buttons: HBoxContainer = $VBox/HSplit/Terrains/LowerToolbar/EditTools -@onready var add_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/AddTerrain -@onready var edit_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/EditTerrain -@onready var pick_icon_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/PickIcon -@onready var move_up_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveUp -@onready var move_down_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveDown -@onready var remove_terrain_button: Button = $VBox/HSplit/Terrains/LowerToolbar/EditTools/RemoveTerrain - -@onready var scroll_container: ScrollContainer = $VBox/HSplit/Terrains/Panel/ScrollContainer -@onready var terrain_list: HFlowContainer = $VBox/HSplit/Terrains/Panel/ScrollContainer/TerrainList -@onready var tile_view: Control = $VBox/HSplit/Panel/ScrollArea/TileView - - -var selected_entry := -2 - -var tilemap : TileMapLayer -var tileset : TileSet - -var undo_manager : EditorUndoRedoManager -var terrain_undo - -var draw_overlay := false -var initial_click : Vector2i -var prev_position : Vector2i -var current_position : Vector2i -var tileset_dirty := false -var zoom_slider : HSlider - -enum PaintMode { - NO_PAINT, - PAINT, - ERASE -} - -enum PaintAction { - NO_ACTION, - LINE, - RECT -} - -enum SourceSelectors { - ALL = 1000000, - NONE = 1000001, -} - -var paint_mode := PaintMode.NO_PAINT - -var paint_action := PaintAction.NO_ACTION - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - draw_button.icon = get_theme_icon("Edit", "EditorIcons") - line_button.icon = get_theme_icon("Line", "EditorIcons") - rectangle_button.icon = get_theme_icon("Rectangle", "EditorIcons") - fill_button.icon = get_theme_icon("Bucket", "EditorIcons") - select_tiles.icon = get_theme_icon("ToolSelect", "EditorIcons") - add_terrain_button.icon = get_theme_icon("Add", "EditorIcons") - edit_terrain_button.icon = get_theme_icon("Tools", "EditorIcons") - pick_icon_button.icon = get_theme_icon("ColorPick", "EditorIcons") - move_up_button.icon = get_theme_icon("ArrowUp", "EditorIcons") - move_down_button.icon = get_theme_icon("ArrowDown", "EditorIcons") - remove_terrain_button.icon = get_theme_icon("Remove", "EditorIcons") - grid_mode_button.icon = get_theme_icon("FileThumbnail", "EditorIcons") - quick_mode_button.icon = get_theme_icon("GuiVisibilityVisible", "EditorIcons") - layer_up.icon = get_theme_icon("MoveUp", "EditorIcons") - layer_down.icon = get_theme_icon("MoveDown", "EditorIcons") - layer_highlight.icon = get_theme_icon("TileMapHighlightSelected", "EditorIcons") - layer_grid.icon = get_theme_icon("Grid", "EditorIcons") - - select_tiles.button_group.pressed.connect(_on_bit_button_pressed) - - terrain_undo = load("res://addons/better-terrain/editor/TerrainUndo.gd").new() - add_child(terrain_undo) - tile_view.undo_manager = undo_manager - tile_view.terrain_undo = terrain_undo - - tile_view.paste_occurred.connect(_on_paste_occurred) - tile_view.change_zoom_level.connect(_on_change_zoom_level) - tile_view.terrain_updated.connect(_on_terrain_updated) - - # Zoom slider is manipulated by settings, make it at runtime - zoom_slider = HSlider.new() - zoom_slider.custom_minimum_size = Vector2(100, 0) - zoom_slider.value_changed.connect(tile_view._on_zoom_value_changed) - zoom_slider_container.add_child(zoom_slider) - - # Init settings if needed - if !ProjectSettings.has_setting(MIN_ZOOM_SETTING): - ProjectSettings.set(MIN_ZOOM_SETTING, 1.0) - ProjectSettings.add_property_info({ - "name": MIN_ZOOM_SETTING, - "type": TYPE_FLOAT, - "hint": PROPERTY_HINT_RANGE, - "hint_string": "0.1,1.0,0.1" - }) - ProjectSettings.set_initial_value(MIN_ZOOM_SETTING, 1.0) - ProjectSettings.set_as_basic(MIN_ZOOM_SETTING, true) - - if !ProjectSettings.has_setting(MAX_ZOOM_SETTING): - ProjectSettings.set(MAX_ZOOM_SETTING, 8.0) - ProjectSettings.add_property_info({ - "name": MAX_ZOOM_SETTING, - "type": TYPE_FLOAT, - "hint": PROPERTY_HINT_RANGE, - "hint_string": "2.0,32.0,1.0" - }) - ProjectSettings.set_initial_value(MAX_ZOOM_SETTING, 8.0) - ProjectSettings.set_as_basic(MAX_ZOOM_SETTING, true) - ProjectSettings.set_order(MAX_ZOOM_SETTING, ProjectSettings.get_order(MIN_ZOOM_SETTING) + 1) - - ProjectSettings.settings_changed.connect(_on_adjust_settings) - _on_adjust_settings() - zoom_slider.value = 1.0 - - -func _process(delta): - scroll_container.scroll_horizontal = 0 - - -func _on_adjust_settings(): - zoom_slider.min_value = ProjectSettings.get_setting(MIN_ZOOM_SETTING, 1.0) - zoom_slider.max_value = ProjectSettings.get_setting(MAX_ZOOM_SETTING, 8.0) - zoom_slider.step = (zoom_slider.max_value - zoom_slider.min_value) / 100.0 - - -func _get_fill_cells(target: Vector2i) -> Array: - var pick := BetterTerrain.get_cell(tilemap, target) - var bounds := tilemap.get_used_rect() - var neighbors = BetterTerrain.data.cells_adjacent_for_fill(tileset) - - # No sets yet, so use a dictionary - var checked := {} - var pending := [target] - var goal := [] - - while !pending.is_empty(): - var p = pending.pop_front() - if checked.has(p): - continue - checked[p] = true - if !bounds.has_point(p) or BetterTerrain.get_cell(tilemap, p) != pick: - continue - - goal.append(p) - pending.append_array(BetterTerrain.data.neighboring_coords(tilemap, p, neighbors)) - - return goal - - -func tiles_about_to_change() -> void: - if tileset and tileset.changed.is_connected(queue_tiles_changed): - tileset.changed.disconnect(queue_tiles_changed) - - -func tiles_changed() -> void: - # ensure up to date - BetterTerrain._update_terrain_data(tileset) - - # clear terrains - for c in terrain_list.get_children(): - terrain_list.remove_child(c) - c.queue_free() - - # load terrains from tileset - var terrain_count := BetterTerrain.terrain_count(tileset) - var item_count = terrain_count + 1 - for i in terrain_count: - var terrain := BetterTerrain.get_terrain(tileset, i) - if i >= terrain_list.get_child_count(): - add_terrain_entry(terrain, i) - - if item_count > terrain_list.get_child_count(): - var terrain := BetterTerrain.get_terrain(tileset, BetterTerrain.TileCategory.EMPTY) - if terrain.valid: - add_terrain_entry(terrain, item_count - 1) - - while item_count < terrain_list.get_child_count(): - var child = terrain_list.get_child(terrain_list.get_child_count() - 1) - terrain_list.remove_child(child) - child.free() - - source_selector_popup.clear() - source_selector_popup.add_item("All", SourceSelectors.ALL) - source_selector_popup.add_item("None", SourceSelectors.NONE) - var source_count = tileset.get_source_count() if tileset else 0 - for s in source_count: - var source_id = tileset.get_source_id(s) - var source := tileset.get_source(source_id) - if !(source is TileSetAtlasSource): - continue - - var name := source.resource_name - if name.is_empty(): - var texture := (source as TileSetAtlasSource).texture - var texture_name := texture.resource_name if texture else "" - if !texture_name.is_empty(): - name = texture_name - else: - var texture_path := texture.resource_path if texture else "" - if !texture_path.is_empty(): - name = texture_path.get_file() - - if !name.is_empty(): - name += " " - name += " (ID: %d)" % source_id - - source_selector_popup.add_check_item(name, source_id) - - source_selector_popup.set_item_checked( - source_selector_popup.get_item_index(source_id), - not tile_view.disabled_sources.has(source_id) - ) - source_selector.visible = source_selector_popup.item_count > 3 # All, None and more than one source - - update_tile_view_paint() - tile_view.refresh_tileset(tileset) - - if tileset and !tileset.changed.is_connected(queue_tiles_changed): - tileset.changed.connect(queue_tiles_changed) - - clean_button.visible = BetterTerrain._has_invalid_peering_types(tileset) - - tileset_dirty = false - _on_grid_mode_pressed() - _on_quick_mode_pressed() - - -func about_to_be_visible(visible: bool) -> void: - if !visible: - return - - if tilemap and tileset != tilemap.tile_set: - tiles_about_to_change() - tileset = tilemap.tile_set - tiles_changed() - - var settings := EditorInterface.get_editor_settings() - layer_highlight.set_pressed_no_signal(settings.get_setting("editors/tiles_editor/highlight_selected_layer")) - layer_grid.set_pressed_no_signal(settings.get_setting("editors/tiles_editor/display_grid")) - - -func queue_tiles_changed() -> void: - # Bring terrain data up to date with complex tileset changes - if !tileset or tileset_dirty: - return - - tileset_dirty = true - tiles_changed.call_deferred() - - -func _on_entry_select(index:int): - selected_entry = index - if selected_entry >= BetterTerrain.terrain_count(tileset): - selected_entry = BetterTerrain.TileCategory.EMPTY - for i in range(terrain_list.get_child_count()): - if i != index: - terrain_list.get_child(i).set_selected(false) - update_tile_view_paint() - - -func _on_clean_pressed() -> void: - var confirmed := [false] - var popup := ConfirmationDialog.new() - popup.dialog_text = tr("Tile set changes have caused terrain to become invalid. Remove invalid terrain data?") - popup.dialog_hide_on_ok = false - popup.confirmed.connect(func(): - confirmed[0] = true - popup.hide() - ) - EditorInterface.popup_dialog_centered(popup) - await popup.visibility_changed - popup.queue_free() - - if confirmed[0]: - undo_manager.create_action("Clean invalid terrain peering data", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(BetterTerrain, &"_clear_invalid_peering_types", tileset) - undo_manager.add_do_method(self, &"tiles_changed") - terrain_undo.create_peering_restore_point(undo_manager, tileset) - undo_manager.add_undo_method(self, &"tiles_changed") - undo_manager.commit_action() - - -func _on_grid_mode_pressed() -> void: - for c in terrain_list.get_children(): - c.grid_mode = grid_mode_button.button_pressed - c.update_style() - - -func _on_quick_mode_pressed() -> void: - edit_tool_buttons.visible = !quick_mode_button.button_pressed - for c in terrain_list.get_children(): - c.visible = !quick_mode_button.button_pressed or c.terrain.type in [BetterTerrain.TerrainType.MATCH_TILES, BetterTerrain.TerrainType.MATCH_VERTICES] - - -func update_tile_view_paint() -> void: - tile_view.paint = selected_entry - tile_view.queue_redraw() - - var editable = tile_view.paint != BetterTerrain.TileCategory.EMPTY - edit_terrain_button.disabled = !editable - move_up_button.disabled = !editable or tile_view.paint == 0 - move_down_button.disabled = !editable or tile_view.paint == BetterTerrain.terrain_count(tileset) - 1 - remove_terrain_button.disabled = !editable - pick_icon_button.disabled = !editable - - -func _on_add_terrain_pressed() -> void: - if !tileset: - return - - var popup := TERRAIN_PROPERTIES_SCENE.instantiate() - popup.set_category_data(BetterTerrain.get_terrain_categories(tileset)) - popup.terrain_name = "New terrain" - popup.terrain_color = Color.from_hsv(randf(), 0.3 + 0.7 * randf(), 0.6 + 0.4 * randf()) - popup.terrain_icon = "" - popup.terrain_type = 0 - EditorInterface.popup_dialog_centered(popup) - await popup.visibility_changed - if popup.accepted: - undo_manager.create_action("Add terrain type", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(self, &"perform_add_terrain", popup.terrain_name, popup.terrain_color, popup.terrain_type, popup.terrain_categories, {path = popup.terrain_icon}) - undo_manager.add_undo_method(self, &"perform_remove_terrain", terrain_list.get_child_count() - 1) - undo_manager.commit_action() - popup.queue_free() - - -func _on_edit_terrain_pressed() -> void: - if !tileset: - return - - if selected_entry < 0: - return - - var t := BetterTerrain.get_terrain(tileset, selected_entry) - var categories = BetterTerrain.get_terrain_categories(tileset) - categories = categories.filter(func(x): return x.id != selected_entry) - - var popup := TERRAIN_PROPERTIES_SCENE.instantiate() - popup.set_category_data(categories) - - t.icon = t.icon.duplicate() - - popup.terrain_name = t.name - popup.terrain_type = t.type - popup.terrain_color = t.color - if t.has("icon") and t.icon.has("path"): - popup.terrain_icon = t.icon.path - popup.terrain_categories = t.categories - EditorInterface.popup_dialog_centered(popup) - await popup.visibility_changed - if popup.accepted: - undo_manager.create_action("Edit terrain details", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(self, &"perform_edit_terrain", selected_entry, popup.terrain_name, popup.terrain_color, popup.terrain_type, popup.terrain_categories, {path = popup.terrain_icon}) - undo_manager.add_undo_method(self, &"perform_edit_terrain", selected_entry, t.name, t.color, t.type, t.categories, t.icon) - if t.type != popup.terrain_type: - terrain_undo.create_terrain_type_restore_point(undo_manager, tileset) - terrain_undo.create_peering_restore_point_specific(undo_manager, tileset, selected_entry) - undo_manager.commit_action() - popup.queue_free() - - -func _on_pick_icon_pressed(): - if selected_entry < 0: - return - tile_view.pick_icon_terrain = selected_entry - - -func _on_pick_icon_focus_exited(): - tile_view.pick_icon_terrain_cancel = true - pick_icon_button.button_pressed = false - - -func _on_move_pressed(down: bool) -> void: - if !tileset: - return - - if selected_entry < 0: - return - - var index1 = selected_entry - var index2 = index1 + (1 if down else -1) - if index2 < 0 or index2 >= terrain_list.get_child_count(): - return - - undo_manager.create_action("Reorder terrains", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(self, &"perform_swap_terrain", index1, index2) - undo_manager.add_undo_method(self, &"perform_swap_terrain", index1, index2) - undo_manager.commit_action() - - -func _on_remove_terrain_pressed() -> void: - if !tileset: - return - - if selected_entry < 0: - return - - # store confirmation in array to pass by ref - var t := BetterTerrain.get_terrain(tileset, selected_entry) - var confirmed := [false] - var popup := ConfirmationDialog.new() - popup.dialog_text = tr("Are you sure you want to remove {0}?").format([t.name]) - popup.dialog_hide_on_ok = false - popup.confirmed.connect(func(): - confirmed[0] = true - popup.hide() - ) - EditorInterface.popup_dialog_centered(popup) - await popup.visibility_changed - popup.queue_free() - - if confirmed[0]: - undo_manager.create_action("Remove terrain type", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(self, &"perform_remove_terrain", selected_entry) - undo_manager.add_undo_method(self, &"perform_add_terrain", t.name, t.color, t.type, t.categories, t.icon) - for n in range(terrain_list.get_child_count() - 2, selected_entry, -1): - undo_manager.add_undo_method(self, &"perform_swap_terrain", n, n - 1) - if t.type == BetterTerrain.TerrainType.CATEGORY: - terrain_undo.create_terrain_type_restore_point(undo_manager, tileset) - terrain_undo.create_peering_restore_point_specific(undo_manager, tileset, selected_entry) - undo_manager.commit_action() - - -func add_terrain_entry(terrain:Dictionary, index:int = -1): - if index < 0: - index = terrain_list.get_child_count() - - var entry = TERRAIN_ENTRY_SCENE.instantiate() - entry.tileset = tileset - entry.terrain = terrain - entry.grid_mode = grid_mode_button.button_pressed - entry.select.connect(_on_entry_select) - - terrain_list.add_child(entry) - terrain_list.move_child(entry, index) - - -func remove_terrain_entry(index: int): - terrain_list.get_child(index).free() - for i in range(index, terrain_list.get_child_count()): - var child = terrain_list.get_child(i) - child.terrain = BetterTerrain.get_terrain(tileset, i) - child.update() - - -func perform_add_terrain(name: String, color: Color, type: int, categories: Array, icon:Dictionary = {}) -> void: - if BetterTerrain.add_terrain(tileset, name, color, type, categories, icon): - var index = BetterTerrain.terrain_count(tileset) - 1 - var terrain = BetterTerrain.get_terrain(tileset, index) - add_terrain_entry(terrain, index) - - -func perform_remove_terrain(index: int) -> void: - if index >= BetterTerrain.terrain_count(tileset): - return - if BetterTerrain.remove_terrain(tileset, index): - remove_terrain_entry(index) - update_tile_view_paint() - - -func perform_swap_terrain(index1: int, index2: int) -> void: - var lower := min(index1, index2) - var higher := max(index1, index2) - if lower >= terrain_list.get_child_count() or higher >= terrain_list.get_child_count(): - return - var item1 = terrain_list.get_child(lower) - var item2 = terrain_list.get_child(higher) - if BetterTerrain.swap_terrains(tileset, lower, higher): - terrain_list.move_child(item1, higher) - item1.terrain = BetterTerrain.get_terrain(tileset, higher) - item1.update() - item2.terrain = BetterTerrain.get_terrain(tileset, lower) - item2.update() - selected_entry = index2 - terrain_list.get_child(index2).set_selected(true) - update_tile_view_paint() - - -func perform_edit_terrain(index: int, name: String, color: Color, type: int, categories: Array, icon: Dictionary = {}) -> void: - if index >= terrain_list.get_child_count(): - return - var entry = terrain_list.get_child(index) - # don't overwrite empty icon - var valid_icon = icon - if icon.has("path") and icon.path.is_empty(): - var terrain = BetterTerrain.get_terrain(tileset, index) - valid_icon = terrain.icon - if BetterTerrain.set_terrain(tileset, index, name, color, type, categories, valid_icon): - entry.terrain = BetterTerrain.get_terrain(tileset, index) - entry.update() - tile_view.queue_redraw() - - -func _on_shuffle_random_pressed(): - BetterTerrain.use_seed = !shuffle_random.button_pressed - - -func _on_bit_button_pressed(button: BaseButton) -> void: - match select_tiles.button_group.get_pressed_button(): - select_tiles: tile_view.paint_mode = tile_view.PaintMode.SELECT - paint_type: tile_view.paint_mode = tile_view.PaintMode.PAINT_TYPE - paint_terrain: tile_view.paint_mode = tile_view.PaintMode.PAINT_PEERING - paint_symmetry: tile_view.paint_mode = tile_view.PaintMode.PAINT_SYMMETRY - _: tile_view.paint_mode = tile_view.PaintMode.NO_PAINT - tile_view.queue_redraw() - - symmetry_options.visible = paint_symmetry.button_pressed - - -func _on_symmetry_selected(index): - tile_view.paint_symmetry = index - - -func _on_paste_occurred(): - select_tiles.button_pressed = true - - -func _on_change_zoom_level(value): - zoom_slider.value = value - - -func _on_terrain_updated(index): - var entry = terrain_list.get_child(index) - entry.terrain = BetterTerrain.get_terrain(tileset, index) - entry.update() - - -func canvas_tilemap_transform() -> Transform2D: - if not tilemap: - return Transform2D.IDENTITY - - var transform := tilemap.get_viewport_transform() * tilemap.global_transform - - # Handle subviewport - var editor_viewport := EditorInterface.get_editor_viewport_2d() - if tilemap.get_viewport() != editor_viewport: - var container = tilemap.get_viewport().get_parent() as SubViewportContainer - if container: - transform = editor_viewport.global_canvas_transform * container.get_transform() * transform - - return transform - - -func canvas_draw(overlay: Control) -> void: - if not draw_overlay or not tilemap: - return - - if selected_entry < 0: - return - - var type = selected_entry - var terrain := BetterTerrain.get_terrain(tileset, type) - if !terrain.valid: - return - - var tiles := [] - var transform := canvas_tilemap_transform() - - if paint_action == PaintAction.RECT and paint_mode != PaintMode.NO_PAINT: - var area := Rect2i(initial_click, current_position - initial_click).abs() - - # Shortcut fill for large areas - if area.size.x > 1 and area.size.y > 1 and area.size.x * area.size.y > MAX_CANVAS_RENDER_TILES: - var shortcut := PackedVector2Array([ - tilemap.map_to_local(area.position), - tilemap.map_to_local(Vector2i(area.end.x, area.position.y)), - tilemap.map_to_local(area.end), - tilemap.map_to_local(Vector2i(area.position.x, area.end.y)) - ]) - overlay.draw_colored_polygon(transform * shortcut, Color(terrain.color, 0.5)) - return - - for y in range(area.position.y, area.end.y + 1): - for x in range(area.position.x, area.end.x + 1): - tiles.append(Vector2i(x, y)) - elif paint_action == PaintAction.LINE and paint_mode != PaintMode.NO_PAINT: - var cells := _get_tileset_line(initial_click, current_position, tileset) - var shape = BetterTerrain.data.cell_polygon(tileset) - for c in cells: - var tile_transform := Transform2D(0.0, tilemap.tile_set.tile_size, 0.0, tilemap.map_to_local(c)) - overlay.draw_colored_polygon(transform * tile_transform * shape, Color(terrain.color, 0.5)) - elif fill_button.button_pressed: - tiles = _get_fill_cells(current_position) - if tiles.size() > MAX_CANVAS_RENDER_TILES: - tiles.resize(MAX_CANVAS_RENDER_TILES) - else: - tiles.append(current_position) - - var shape = BetterTerrain.data.cell_polygon(tileset) - for t in tiles: - var tile_transform := Transform2D(0.0, tilemap.tile_set.tile_size, 0.0, tilemap.map_to_local(t)) - overlay.draw_colored_polygon(transform * tile_transform * shape, Color(terrain.color, 0.5)) - - -func canvas_input(event: InputEvent) -> bool: - if not tilemap: - return false - if selected_entry < 0: - return false - - draw_overlay = true - if event is InputEventMouseMotion: - var tr := canvas_tilemap_transform() - var pos := tr.affine_inverse() * Vector2(event.position) - var event_position := tilemap.local_to_map(pos) - prev_position = current_position - if event_position == current_position: - return false - current_position = event_position - update_overlay.emit() - - var replace_mode = replace_button.button_pressed - - var released : bool = event is InputEventMouseButton and !event.pressed - if released: - terrain_undo.finish_action() - var type = selected_entry - if paint_action == PaintAction.RECT and paint_mode != PaintMode.NO_PAINT: - var area := Rect2i(initial_click, current_position - initial_click).abs() - # Fill from initial_target to target - undo_manager.create_action(tr("Draw terrain rectangle"), UndoRedo.MERGE_DISABLE, tilemap) - for y in range(area.position.y, area.end.y + 1): - for x in range(area.position.x, area.end.x + 1): - var coord := Vector2i(x, y) - if paint_mode == PaintMode.PAINT: - if replace_mode: - undo_manager.add_do_method(BetterTerrain, &"replace_cell", tilemap, coord, type) - else: - undo_manager.add_do_method(BetterTerrain, &"set_cell", tilemap, coord, type) - else: - undo_manager.add_do_method(tilemap, &"erase_cell", coord) - - undo_manager.add_do_method(BetterTerrain, &"update_terrain_area", tilemap, area) - terrain_undo.create_tile_restore_point_area(undo_manager, tilemap, area) - undo_manager.commit_action() - update_overlay.emit() - elif paint_action == PaintAction.LINE and paint_mode != PaintMode.NO_PAINT: - undo_manager.create_action(tr("Draw terrain line"), UndoRedo.MERGE_DISABLE, tilemap) - var cells := _get_tileset_line(initial_click, current_position, tileset) - if paint_mode == PaintMode.PAINT: - if replace_mode: - undo_manager.add_do_method(BetterTerrain, &"replace_cells", tilemap, cells, type) - else: - undo_manager.add_do_method(BetterTerrain, &"set_cells", tilemap, cells, type) - elif paint_mode == PaintMode.ERASE: - for c in cells: - undo_manager.add_do_method(tilemap, &"erase_cell", c) - undo_manager.add_do_method(BetterTerrain, &"update_terrain_cells", tilemap, cells) - terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells) - undo_manager.commit_action() - update_overlay.emit() - - paint_mode = PaintMode.NO_PAINT - return true - - var clicked : bool = event is InputEventMouseButton and event.pressed - if clicked: - paint_mode = PaintMode.NO_PAINT - - if (event.is_command_or_control_pressed() and !event.shift_pressed): - var pick = BetterTerrain.get_cell(tilemap, current_position) - if pick >= 0: - terrain_list.get_children()[pick]._on_focus_entered() - #_on_entry_select(pick) - return true - - paint_action = PaintAction.NO_ACTION - if rectangle_button.button_pressed: - paint_action = PaintAction.RECT - elif line_button.button_pressed: - paint_action = PaintAction.LINE - elif draw_button.button_pressed: - if event.shift_pressed: - paint_action = PaintAction.LINE - if event.is_command_or_control_pressed(): - paint_action = PaintAction.RECT - - if event.button_index == MOUSE_BUTTON_LEFT: - paint_mode = PaintMode.PAINT - elif event.button_index == MOUSE_BUTTON_RIGHT: - paint_mode = PaintMode.ERASE - else: - return false - - if (clicked or event is InputEventMouseMotion) and paint_mode != PaintMode.NO_PAINT: - if clicked: - initial_click = current_position - terrain_undo.action_index += 1 - terrain_undo.action_count = 0 - var type = selected_entry - - if paint_action == PaintAction.LINE or paint_action == PaintAction.RECT: - # if painting as line, execution happens on release. - # prevent other painting actions from running. - pass - elif draw_button.button_pressed: - undo_manager.create_action(tr("Draw terrain") + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tilemap, true) - var cells := _get_tileset_line(prev_position, current_position, tileset) - if paint_mode == PaintMode.PAINT: - if replace_mode: - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"replace_cells", [tilemap, cells, type]) - else: - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_cells", [tilemap, cells, type]) - elif paint_mode == PaintMode.ERASE: - for c in cells: - terrain_undo.add_do_method(undo_manager, tilemap, &"erase_cell", [c]) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"update_terrain_cells", [tilemap, cells]) - terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells) - undo_manager.commit_action() - terrain_undo.action_count += 1 - elif fill_button.button_pressed: - var cells := _get_fill_cells(current_position) - undo_manager.create_action(tr("Fill terrain"), UndoRedo.MERGE_DISABLE, tilemap) - if paint_mode == PaintMode.PAINT: - if replace_mode: - undo_manager.add_do_method(BetterTerrain, &"replace_cells", tilemap, cells, type) - else: - undo_manager.add_do_method(BetterTerrain, &"set_cells", tilemap, cells, type) - elif paint_mode == PaintMode.ERASE: - for c in cells: - undo_manager.add_do_method(tilemap, &"erase_cell", c) - undo_manager.add_do_method(BetterTerrain, &"update_terrain_cells", tilemap, cells) - terrain_undo.create_tile_restore_point(undo_manager, tilemap, cells) - undo_manager.commit_action() - - update_overlay.emit() - return true - - return false - - -func canvas_mouse_exit() -> void: - draw_overlay = false - update_overlay.emit() - - -func _shortcut_input(event) -> void: - if event is InputEventKey: - if event.keycode == KEY_C and (event.is_command_or_control_pressed() and not event.echo): - get_viewport().set_input_as_handled() - tile_view.copy_selection() - if event.keycode == KEY_V and (event.is_command_or_control_pressed() and not event.echo): - get_viewport().set_input_as_handled() - tile_view.paste_selection() - - -## bresenham alg ported from Geometry2D::bresenham_line() -func _get_line(from:Vector2i, to:Vector2i) -> Array[Vector2i]: - if from == to: - return [to] - - var points:Array[Vector2i] = [] - var delta := (to - from).abs() * 2 - var step := (to - from).sign() - var current := from - - if delta.x > delta.y: - var err:int = delta.x / 2 - while current.x != to.x: - points.push_back(current); - err -= delta.y - if err < 0: - current.y += step.y - err += delta.x - current.x += step.x - else: - var err:int = delta.y / 2 - while current.y != to.y: - points.push_back(current) - err -= delta.x - if err < 0: - current.x += step.x - err += delta.y - current.y += step.y - - points.push_back(current); - return points; - - -## half-offset bresenham alg ported from TileMapEditor::get_line -func _get_tileset_line(from:Vector2i, to:Vector2i, tileset:TileSet) -> Array[Vector2i]: - if tileset.tile_shape == TileSet.TILE_SHAPE_SQUARE: - return _get_line(from, to) - - var points:Array[Vector2i] = [] - - var transposed := tileset.get_tile_offset_axis() == TileSet.TILE_OFFSET_AXIS_VERTICAL - if transposed: - from = Vector2i(from.y, from.x) - to = Vector2i(to.y, to.x) - - var delta:Vector2i = to - from - delta = Vector2i(2 * delta.x + abs(posmod(to.y, 2)) - abs(posmod(from.y, 2)), delta.y) - var sign:Vector2i = delta.sign() - - var current := from; - points.push_back(Vector2i(current.y, current.x) if transposed else current) - - var err := 0 - if abs(delta.y) < abs(delta.x): - var err_step:Vector2i = 3 * delta.abs() - while current != to: - err += err_step.y - if err > abs(delta.x): - if sign.x == 0: - current += Vector2i(sign.y, 0) - else: - current += Vector2i(sign.x if bool(current.y % 2) != (sign.x < 0) else 0, sign.y) - err -= err_step.x - else: - current += Vector2i(sign.x, 0) - err += err_step.y - points.push_back(Vector2i(current.y, current.x) if transposed else current) - else: - var err_step:Vector2i = delta.abs() - while current != to: - err += err_step.x - if err > 0: - if sign.x == 0: - current += Vector2i(0, sign.y) - else: - current += Vector2i(sign.x if bool(current.y % 2) != (sign.x < 0) else 0, sign.y) - err -= err_step.y; - else: - if sign.x == 0: - current += Vector2i(0, sign.y) - else: - current += Vector2i(-sign.x if bool(current.y % 2) != (sign.x > 0) else 0, sign.y) - err += err_step.y - points.push_back(Vector2i(current.y, current.x) if transposed else current) - - return points - - -func _on_terrain_enable_id_pressed(id): - if id in [SourceSelectors.ALL, SourceSelectors.NONE]: - for i in source_selector_popup.item_count: - if source_selector_popup.is_item_checkable(i): - source_selector_popup.set_item_checked(i, id == SourceSelectors.ALL) - else: - var index = source_selector_popup.get_item_index(id) - var checked = source_selector_popup.is_item_checked(index) - source_selector_popup.set_item_checked(index, !checked) - - var disabled_sources : Array[int] - for i in source_selector_popup.item_count: - if source_selector_popup.is_item_checkable(i) and !source_selector_popup.is_item_checked(i): - disabled_sources.append(source_selector_popup.get_item_id(i)) - tile_view.disabled_sources = disabled_sources - - -func corresponding_tilemap_editor_button(similar: Button) -> Button: - var editors = EditorInterface.get_base_control().find_children("*", "TileMapLayerEditor", true, false) - var tile_map_layer_editor = editors[0] - var buttons = tile_map_layer_editor.find_children("*", "Button", true, false) - for button: Button in buttons: - if button.icon == similar.icon: - return button - return null - - -func _on_layer_up_or_down_pressed(button: Button) -> void: - var matching_button = corresponding_tilemap_editor_button(button) - if !matching_button: - return - - # Major hack, to reduce flicker hide the tileset editor briefly - var editors = EditorInterface.get_base_control().find_children("*", "TileSetEditor", true, false) - var tile_set_editor = editors[0] - - matching_button.pressed.emit() - tile_set_editor.modulate = Color.TRANSPARENT - await get_tree().process_frame - await get_tree().process_frame - force_show_terrains.emit() - tile_set_editor.modulate = Color.WHITE - - - -func _on_layer_up_pressed() -> void: - _on_layer_up_or_down_pressed(layer_up) - - -func _on_layer_down_pressed() -> void: - _on_layer_up_or_down_pressed(layer_down) - - -func _on_layer_highlight_toggled(toggled: bool) -> void: - var settings = EditorInterface.get_editor_settings() - settings.set_setting("editors/tiles_editor/highlight_selected_layer", toggled) - - var highlight = corresponding_tilemap_editor_button(layer_highlight) - if highlight: - highlight.toggled.emit(toggled) - - -func _on_layer_grid_toggled(toggled: bool) -> void: - var settings = EditorInterface.get_editor_settings() - settings.set_setting("editors/tiles_editor/display_grid", toggled) - - var grid = corresponding_tilemap_editor_button(layer_grid) - if grid: - grid.toggled.emit(toggled) diff --git a/godot/addons/better-terrain/editor/Dock.gd.uid b/godot/addons/better-terrain/editor/Dock.gd.uid deleted file mode 100644 index daa2961..0000000 --- a/godot/addons/better-terrain/editor/Dock.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dgoa61jt54fpq diff --git a/godot/addons/better-terrain/editor/Dock.tscn b/godot/addons/better-terrain/editor/Dock.tscn deleted file mode 100644 index f659343..0000000 --- a/godot/addons/better-terrain/editor/Dock.tscn +++ /dev/null @@ -1,405 +0,0 @@ -[gd_scene load_steps=33 format=3 uid="uid://de8b6h6ieal7r"] - -[ext_resource type="Script" path="res://addons/better-terrain/editor/Dock.gd" id="1_raoha"] -[ext_resource type="Texture2D" uid="uid://c6lxq2y7mpb18" path="res://addons/better-terrain/icons/EditType.svg" id="2_cpm2t"] -[ext_resource type="Texture2D" uid="uid://y3xy6qdckht6" path="res://addons/better-terrain/icons/Replace.svg" id="2_fvmt6"] -[ext_resource type="Texture2D" uid="uid://bo2cjv08jkvf8" path="res://addons/better-terrain/icons/EditTerrain.svg" id="3_pqb1p"] -[ext_resource type="Texture2D" uid="uid://b0es228gfcykd" path="res://addons/better-terrain/icons/Warning.svg" id="4_6ahwe"] -[ext_resource type="Script" path="res://addons/better-terrain/editor/TileView.gd" id="4_nqppq"] -[ext_resource type="Texture2D" uid="uid://co6gwwmog0pjy" path="res://addons/better-terrain/icons/EditSymmetry.svg" id="5_kfjwu"] -[ext_resource type="Texture2D" uid="uid://cs4mdmluiydj6" path="res://addons/better-terrain/icons/ShuffleRandom.svg" id="5_n3owo"] -[ext_resource type="Texture2D" uid="uid://5hm3bfj3dvej" path="res://addons/better-terrain/icons/SymmetryMirror.svg" id="6_mofuh"] -[ext_resource type="Texture2D" uid="uid://dqmc1jp56or8m" path="res://addons/better-terrain/icons/SymmetryFlip.svg" id="7_ojxs0"] -[ext_resource type="Texture2D" uid="uid://cxoewno1cefua" path="res://addons/better-terrain/icons/SymmetryReflect.svg" id="8_8dhyg"] -[ext_resource type="Texture2D" uid="uid://baxhjy28r1iqj" path="res://addons/better-terrain/icons/SymmetryRotateClockwise.svg" id="9_tq76a"] -[ext_resource type="Texture2D" uid="uid://csbwdkr6bc2db" path="res://addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg" id="10_o5h1f"] -[ext_resource type="Texture2D" uid="uid://8mcycyl3e66r" path="res://addons/better-terrain/icons/SymmetryRotate180.svg" id="11_m6syp"] -[ext_resource type="Texture2D" uid="uid://b7fx4mk18lmls" path="res://addons/better-terrain/icons/SymmetryRotateAll.svg" id="12_11vru"] -[ext_resource type="Texture2D" uid="uid://cyjra4g05dwh" path="res://addons/better-terrain/icons/SymmetryAll.svg" id="13_lp5m2"] - -[sub_resource type="ButtonGroup" id="ButtonGroup_aon7c"] - -[sub_resource type="InputEventKey" id="InputEventKey_saph6"] -device = -1 -keycode = 68 -unicode = 100 - -[sub_resource type="Shortcut" id="Shortcut_3k2al"] -events = [SubResource("InputEventKey_saph6")] - -[sub_resource type="Image" id="Image_3r1gs"] -data = { -"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0), -"format": "RGBA8", -"height": 16, -"mipmaps": false, -"width": 16 -} - -[sub_resource type="ImageTexture" id="ImageTexture_v6msm"] -image = SubResource("Image_3r1gs") - -[sub_resource type="InputEventKey" id="InputEventKey_q1v0d"] -device = -1 -keycode = 76 -unicode = 108 - -[sub_resource type="Shortcut" id="Shortcut_wc6bu"] -events = [SubResource("InputEventKey_q1v0d")] - -[sub_resource type="InputEventKey" id="InputEventKey_68n3h"] -device = -1 -keycode = 82 -unicode = 114 - -[sub_resource type="InputEventKey" id="InputEventKey_qcu1e"] -device = -1 -keycode = 67 -unicode = 99 - -[sub_resource type="Shortcut" id="Shortcut_tcjet"] -events = [SubResource("InputEventKey_68n3h"), SubResource("InputEventKey_qcu1e")] - -[sub_resource type="InputEventKey" id="InputEventKey_grxy4"] -device = -1 -keycode = 66 -unicode = 98 - -[sub_resource type="Shortcut" id="Shortcut_46fac"] -events = [SubResource("InputEventKey_grxy4")] - -[sub_resource type="InputEventKey" id="InputEventKey_xd61m"] -device = -1 -keycode = 80 -unicode = 112 - -[sub_resource type="Shortcut" id="Shortcut_uwwa1"] -events = [SubResource("InputEventKey_xd61m")] - -[sub_resource type="ButtonGroup" id="ButtonGroup_3wrxn"] -allow_unpress = true - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mpeb7"] -bg_color = Color(0, 0, 0, 0.4) - -[node name="Dock" type="Control" node_paths=PackedStringArray("shortcut_context")] -custom_minimum_size = Vector2(0, 100) -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -focus_mode = 2 -shortcut_context = NodePath(".") -script = ExtResource("1_raoha") - -[node name="VBox" type="VBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="Toolbar" type="HBoxContainer" parent="VBox"] -layout_mode = 2 - -[node name="Draw" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Draw terrain -Shift: Draw line. -Ctrl/Cmd+Shift: Draw rectangle." -toggle_mode = true -button_pressed = true -button_group = SubResource("ButtonGroup_aon7c") -shortcut = SubResource("Shortcut_3k2al") -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="Line" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Draw line" -toggle_mode = true -button_group = SubResource("ButtonGroup_aon7c") -shortcut = SubResource("Shortcut_wc6bu") -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="Rectangle" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Fill a rectangle of terrain" -toggle_mode = true -button_group = SubResource("ButtonGroup_aon7c") -shortcut = SubResource("Shortcut_tcjet") -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="Fill" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Bucket fill terrain" -toggle_mode = true -button_group = SubResource("ButtonGroup_aon7c") -shortcut = SubResource("Shortcut_46fac") -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="Replace" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Toggle replace mode" -toggle_mode = true -shortcut = SubResource("Shortcut_uwwa1") -icon = ExtResource("2_fvmt6") - -[node name="VSeparator" type="VSeparator" parent="VBox/Toolbar"] -layout_mode = 2 - -[node name="SelectTiles" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Select" -toggle_mode = true -button_group = SubResource("ButtonGroup_3wrxn") -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="PaintType" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Paint terrain types" -toggle_mode = true -button_group = SubResource("ButtonGroup_3wrxn") -icon = ExtResource("2_cpm2t") -flat = true - -[node name="PaintTerrain" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Paint terrain connecting types" -toggle_mode = true -button_group = SubResource("ButtonGroup_3wrxn") -icon = ExtResource("3_pqb1p") -flat = true - -[node name="PaintSymmetry" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Paint tile symmetry" -toggle_mode = true -button_group = SubResource("ButtonGroup_3wrxn") -icon = ExtResource("5_kfjwu") -flat = true - -[node name="SymmetryOptions" type="OptionButton" parent="VBox/Toolbar"] -visible = false -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -selected = 0 -item_count = 9 -popup/item_0/text = "No symmetry" -popup/item_0/id = 8 -popup/item_1/text = "Mirror" -popup/item_1/icon = ExtResource("6_mofuh") -popup/item_1/id = 1 -popup/item_2/text = "Flip" -popup/item_2/icon = ExtResource("7_ojxs0") -popup/item_2/id = 1 -popup/item_3/text = "Reflect" -popup/item_3/icon = ExtResource("8_8dhyg") -popup/item_3/id = 2 -popup/item_4/text = "Rotate clockwise" -popup/item_4/icon = ExtResource("9_tq76a") -popup/item_4/id = 3 -popup/item_5/text = "Rotate counter-clockwise" -popup/item_5/icon = ExtResource("10_o5h1f") -popup/item_5/id = 4 -popup/item_6/text = "Rotate 180" -popup/item_6/icon = ExtResource("11_m6syp") -popup/item_6/id = 5 -popup/item_7/text = "All rotations" -popup/item_7/icon = ExtResource("12_11vru") -popup/item_7/id = 6 -popup/item_8/text = "All reflections & rotations" -popup/item_8/icon = ExtResource("13_lp5m2") -popup/item_8/id = 7 - -[node name="VSeparator3" type="VSeparator" parent="VBox/Toolbar"] -layout_mode = 2 - -[node name="ZoomContainer" type="VBoxContainer" parent="VBox/Toolbar"] -layout_mode = 2 -alignment = 1 - -[node name="Sources" type="MenuBar" parent="VBox/Toolbar"] -layout_mode = 2 - -[node name="Sources" type="PopupMenu" parent="VBox/Toolbar/Sources"] -hide_on_item_selection = false -hide_on_checkable_item_selection = false - -[node name="Spacer" type="Control" parent="VBox/Toolbar"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="ShuffleRandom" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Shuffle random tiles each update" -toggle_mode = true -icon = ExtResource("5_n3owo") -flat = true - -[node name="Clean" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -text = "Clean tile data" -icon = ExtResource("4_6ahwe") - -[node name="VSeparator2" type="VSeparator" parent="VBox/Toolbar"] -layout_mode = 2 - -[node name="LayerUp" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Select previous layer" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="LayerDown" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Select next layer" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="LayerHighlight" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Highlight selected layer" -toggle_mode = true -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="LayerGrid" type="Button" parent="VBox/Toolbar"] -layout_mode = 2 -tooltip_text = "Toggle grid visibility" -toggle_mode = true -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="HSplit" type="HSplitContainer" parent="VBox"] -layout_mode = 2 -size_flags_vertical = 3 -split_offset = 325 - -[node name="Terrains" type="VBoxContainer" parent="VBox/HSplit"] -layout_mode = 2 - -[node name="Panel" type="PanelContainer" parent="VBox/HSplit/Terrains"] -layout_mode = 2 -size_flags_vertical = 3 -theme_override_styles/panel = SubResource("StyleBoxFlat_mpeb7") - -[node name="ScrollContainer" type="ScrollContainer" parent="VBox/HSplit/Terrains/Panel"] -layout_mode = 2 -horizontal_scroll_mode = 3 - -[node name="TerrainList" type="HFlowContainer" parent="VBox/HSplit/Terrains/Panel/ScrollContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="LowerToolbar" type="HBoxContainer" parent="VBox/HSplit/Terrains"] -layout_mode = 2 - -[node name="GridMode" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar"] -layout_mode = 2 -tooltip_text = "Toggle grid view" -toggle_mode = true -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="QuickMode" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar"] -auto_translate_mode = 1 -layout_mode = 2 -tooltip_text = "Toggle quick mode. Only shows paintable terrain types." -toggle_mode = true -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="VSeparator" type="VSeparator" parent="VBox/HSplit/Terrains/LowerToolbar"] -layout_mode = 2 - -[node name="EditTools" type="HBoxContainer" parent="VBox/HSplit/Terrains/LowerToolbar"] -layout_mode = 2 -size_flags_horizontal = 3 -alignment = 2 - -[node name="AddTerrain" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Add terrain type" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="EditTerrain" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Edit terrain type" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="PickIcon" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Pick terrain icon from tileset" -toggle_mode = true -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="MoveUp" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Move selected terrain up" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="MoveDown" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Move selected terrain down" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="RemoveTerrain" type="Button" parent="VBox/HSplit/Terrains/LowerToolbar/EditTools"] -layout_mode = 2 -tooltip_text = "Remove selected terrain type(s)" -icon = SubResource("ImageTexture_v6msm") -flat = true - -[node name="Panel" type="Panel" parent="VBox/HSplit"] -custom_minimum_size = Vector2(0, 80) -layout_mode = 2 - -[node name="ScrollArea" type="ScrollContainer" parent="VBox/HSplit/Panel"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 - -[node name="TileView" type="Control" parent="VBox/HSplit/Panel/ScrollArea"] -texture_filter = 1 -texture_repeat = 1 -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -focus_mode = 2 -script = ExtResource("4_nqppq") - -[connection signal="item_selected" from="VBox/Toolbar/SymmetryOptions" to="." method="_on_symmetry_selected"] -[connection signal="id_pressed" from="VBox/Toolbar/Sources/Sources" to="." method="_on_terrain_enable_id_pressed"] -[connection signal="pressed" from="VBox/Toolbar/ShuffleRandom" to="." method="_on_shuffle_random_pressed"] -[connection signal="pressed" from="VBox/Toolbar/Clean" to="." method="_on_clean_pressed"] -[connection signal="pressed" from="VBox/Toolbar/LayerUp" to="." method="_on_layer_up_pressed"] -[connection signal="pressed" from="VBox/Toolbar/LayerDown" to="." method="_on_layer_down_pressed"] -[connection signal="toggled" from="VBox/Toolbar/LayerHighlight" to="." method="_on_layer_highlight_toggled"] -[connection signal="toggled" from="VBox/Toolbar/LayerGrid" to="." method="_on_layer_grid_toggled"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/GridMode" to="." method="_on_grid_mode_pressed"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/QuickMode" to="." method="_on_quick_mode_pressed"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/AddTerrain" to="." method="_on_add_terrain_pressed"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/EditTerrain" to="." method="_on_edit_terrain_pressed"] -[connection signal="focus_exited" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/PickIcon" to="." method="_on_pick_icon_focus_exited"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/PickIcon" to="." method="_on_pick_icon_pressed"] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveUp" to="." method="_on_move_pressed" binds= [false]] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/MoveDown" to="." method="_on_move_pressed" binds= [true]] -[connection signal="pressed" from="VBox/HSplit/Terrains/LowerToolbar/EditTools/RemoveTerrain" to="." method="_on_remove_terrain_pressed"] -[connection signal="mouse_exited" from="VBox/HSplit/Panel/ScrollArea/TileView" to="VBox/HSplit/Panel/ScrollArea/TileView" method="clear_highlighted_tile"] diff --git a/godot/addons/better-terrain/editor/TerrainEntry.gd b/godot/addons/better-terrain/editor/TerrainEntry.gd deleted file mode 100644 index a937f95..0000000 --- a/godot/addons/better-terrain/editor/TerrainEntry.gd +++ /dev/null @@ -1,185 +0,0 @@ -@tool -extends PanelContainer - -signal select(index) - -@onready var color_panel := %Color -@onready var terrain_icon_slot := %TerrainIcon -@onready var type_icon_slot := %TypeIcon -@onready var type_icon_panel := %TerrainIconPanel -@onready var name_label := %Name -@onready var layout_container := %Layout -@onready var icon_layout_container := %IconLayout - -var selected := false - -var tileset:TileSet -var terrain:Dictionary - -var grid_mode := false -var color_style_list:StyleBoxFlat -var color_style_grid:StyleBoxFlat -var color_style_decoration:StyleBoxFlat - -var _terrain_texture:Texture2D -var _terrain_texture_rect:Rect2i -var _icon_draw_connected := false - - -func _ready(): - update() - -func update(): - if !terrain or !terrain.valid: - return - if !tileset: - return - - name_label.text = terrain.name - tooltip_text = "%s (%d)" % [terrain.name, terrain.id] - - color_style_list = color_panel.get_theme_stylebox("panel").duplicate() - color_style_grid = color_panel.get_theme_stylebox("panel").duplicate() - color_style_decoration = color_panel.get_theme_stylebox("panel").duplicate() - - color_style_list.bg_color = terrain.color - color_style_list.corner_radius_top_left = 8 - color_style_list.corner_radius_bottom_left = 8 - color_style_list.corner_radius_top_right = 0 - color_style_list.corner_radius_bottom_right = 0 - color_style_list.content_margin_left = -1 - color_style_list.content_margin_right = -1 - color_style_list.border_width_left = 0 - color_style_list.border_width_right = 0 - color_style_list.border_width_top = 0 - color_style_list.border_width_bottom = 0 - - color_style_grid.bg_color = terrain.color - color_style_grid.corner_radius_top_left = 6 - color_style_grid.corner_radius_bottom_left = 6 - color_style_grid.corner_radius_top_right = 6 - color_style_grid.corner_radius_bottom_right = 6 - color_style_grid.content_margin_left = -1 - color_style_grid.content_margin_right = -1 - color_style_grid.border_width_left = 0 - color_style_grid.border_width_right = 0 - color_style_grid.border_width_top = 0 - color_style_grid.border_width_bottom = 0 - - color_style_decoration.bg_color = terrain.color - color_style_decoration.corner_radius_top_left = 8 - color_style_decoration.corner_radius_bottom_left = 8 - color_style_decoration.corner_radius_top_right = 8 - color_style_decoration.corner_radius_bottom_right = 8 - color_style_decoration.content_margin_left = -1 - color_style_decoration.content_margin_right = -1 - color_style_decoration.border_width_left = 4 - color_style_decoration.border_width_right = 4 - color_style_decoration.border_width_top = 4 - color_style_decoration.border_width_bottom = 4 - - match terrain.type: - BetterTerrain.TerrainType.MATCH_TILES: - type_icon_slot.texture = load("res://addons/better-terrain/icons/MatchTiles.svg") - BetterTerrain.TerrainType.MATCH_VERTICES: - type_icon_slot.texture = load("res://addons/better-terrain/icons/MatchVertices.svg") - BetterTerrain.TerrainType.CATEGORY: - type_icon_slot.texture = load("res://addons/better-terrain/icons/NonModifying.svg") - BetterTerrain.TerrainType.DECORATION: - type_icon_slot.texture = load("res://addons/better-terrain/icons/Decoration.svg") - - var has_icon = false - if terrain.has("icon"): - if terrain.icon.has("path") and not terrain.icon.path.is_empty(): - terrain_icon_slot.texture = load(terrain.icon.path) - _terrain_texture = null - terrain_icon_slot.queue_redraw() - has_icon = true - elif terrain.icon.has("source_id") and tileset.has_source(terrain.icon.source_id): - var source := tileset.get_source(terrain.icon.source_id) as TileSetAtlasSource - var coord := terrain.icon.coord as Vector2i - var rect := source.get_tile_texture_region(coord, 0) - _terrain_texture = source.texture - _terrain_texture_rect = rect - terrain_icon_slot.queue_redraw() - has_icon = true - - if not has_icon: - var tiles = BetterTerrain.get_tile_sources_in_terrain(tileset, get_index()) - if tiles.size() > 0: - var source := tiles[0].source as TileSetAtlasSource - var coord := tiles[0].coord as Vector2i - var rect := source.get_tile_texture_region(coord, 0) - _terrain_texture = source.texture - _terrain_texture_rect = rect - terrain_icon_slot.queue_redraw() - - if _terrain_texture: - terrain_icon_slot.texture = null - - if not _icon_draw_connected: - terrain_icon_slot.connect("draw", func(): - if _terrain_texture: - terrain_icon_slot.draw_texture_rect_region(_terrain_texture, Rect2i(0,0, 44, 44), _terrain_texture_rect) - ) - _icon_draw_connected = true - - update_style() - - -func update_style(): - if terrain.type == BetterTerrain.TerrainType.DECORATION: - type_icon_panel.visible = false - color_panel.custom_minimum_size = Vector2i(52,52) - else: - type_icon_panel.visible = true - color_panel.custom_minimum_size = Vector2i(24,24) - - if grid_mode: - if terrain.type == BetterTerrain.TerrainType.DECORATION: - color_panel.add_theme_stylebox_override("panel", color_style_decoration) - color_panel.size_flags_vertical = Control.SIZE_FILL - icon_layout_container.size_flags_vertical = Control.SIZE_EXPAND_FILL - else: - color_panel.add_theme_stylebox_override("panel", color_style_grid) - color_panel.size_flags_vertical = Control.SIZE_SHRINK_BEGIN - icon_layout_container.size_flags_vertical = Control.SIZE_FILL - custom_minimum_size = Vector2(0, 60) - size_flags_horizontal = Control.SIZE_FILL - layout_container.vertical = true - name_label.visible = false - icon_layout_container.add_theme_constant_override("separation", -24) - else: - if terrain.type == BetterTerrain.TerrainType.DECORATION: - color_panel.add_theme_stylebox_override("panel", color_style_decoration) - else: - color_panel.add_theme_stylebox_override("panel", color_style_list) - icon_layout_container.size_flags_vertical = Control.SIZE_FILL - custom_minimum_size = Vector2(2000, 60) - size_flags_horizontal = Control.SIZE_EXPAND_FILL - layout_container.vertical = false - name_label.visible = true - color_panel.size_flags_vertical = Control.SIZE_FILL - icon_layout_container.add_theme_constant_override("separation", 4) - - -func set_selected(value:bool = true): - selected = value - if value: - select.emit(get_index()) - queue_redraw() - - -func _draw(): - if selected: - draw_rect(Rect2(Vector2.ZERO, get_rect().size), Color(0.15, 0.70, 1, 0.3)) - - -func _on_focus_entered(): - queue_redraw() - selected = true - select.emit(get_index()) - - -func _on_focus_exited(): - queue_redraw() diff --git a/godot/addons/better-terrain/editor/TerrainEntry.gd.uid b/godot/addons/better-terrain/editor/TerrainEntry.gd.uid deleted file mode 100644 index aa1f05b..0000000 --- a/godot/addons/better-terrain/editor/TerrainEntry.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://crxmsm22lowxx diff --git a/godot/addons/better-terrain/editor/TerrainEntry.tscn b/godot/addons/better-terrain/editor/TerrainEntry.tscn deleted file mode 100644 index 3973bbf..0000000 --- a/godot/addons/better-terrain/editor/TerrainEntry.tscn +++ /dev/null @@ -1,114 +0,0 @@ -[gd_scene load_steps=8 format=3 uid="uid://u2y444hj182c"] - -[ext_resource type="Script" path="res://addons/better-terrain/editor/TerrainEntry.gd" id="1_o2na3"] -[ext_resource type="Texture2D" uid="uid://kmypxsqhynyv" path="res://addons/better-terrain/icons/Decoration.svg" id="2_ossyj"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3pdcc"] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -draw_center = false - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dqhir"] -bg_color = Color(0.243, 0.816, 0.518, 1) -border_color = Color(0, 0, 0, 0.439216) -corner_radius_top_left = 8 -corner_radius_bottom_left = 8 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rohyw"] -content_margin_left = 2.0 -content_margin_top = 2.0 -content_margin_right = 2.0 -content_margin_bottom = 2.0 -bg_color = Color(0, 0, 0, 0.439216) -corner_radius_top_left = 4 -corner_radius_top_right = 4 -corner_radius_bottom_right = 4 -corner_radius_bottom_left = 4 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xa0fl"] -content_margin_left = 4.0 -content_margin_top = 4.0 -content_margin_right = 4.0 -content_margin_bottom = 4.0 -bg_color = Color(0, 0, 0, 0.439216) - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_b4rkm"] -content_margin_left = 3.0 -bg_color = Color(0, 0, 0, 0.439216) -draw_center = false - -[node name="TerrainEntry" type="PanelContainer"] -custom_minimum_size = Vector2(60, 60) -offset_right = 200.0 -offset_bottom = 60.0 -size_flags_vertical = 3 -focus_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxFlat_3pdcc") -script = ExtResource("1_o2na3") - -[node name="Layout" type="BoxContainer" parent="."] -unique_name_in_owner = true -layout_mode = 2 -theme_override_constants/separation = 4 - -[node name="IconLayout" type="HBoxContainer" parent="Layout"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 4 - -[node name="Color" type="PanelContainer" parent="Layout/IconLayout"] -unique_name_in_owner = true -z_index = 1 -custom_minimum_size = Vector2(24, 24) -layout_mode = 2 -size_flags_horizontal = 0 -mouse_filter = 1 -theme_override_styles/panel = SubResource("StyleBoxFlat_dqhir") - -[node name="PanelContainer" type="PanelContainer" parent="Layout/IconLayout/Color"] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -mouse_filter = 1 -theme_override_styles/panel = SubResource("StyleBoxFlat_rohyw") - -[node name="TypeIcon" type="TextureRect" parent="Layout/IconLayout/Color/PanelContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -texture = ExtResource("2_ossyj") - -[node name="TerrainIconPanel" type="PanelContainer" parent="Layout/IconLayout"] -unique_name_in_owner = true -custom_minimum_size = Vector2(52, 52) -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -mouse_filter = 1 -theme_override_styles/panel = SubResource("StyleBoxFlat_xa0fl") - -[node name="TerrainIcon" type="TextureRect" parent="Layout/IconLayout/TerrainIconPanel"] -unique_name_in_owner = true -texture_filter = 1 -custom_minimum_size = Vector2(40, 40) -layout_mode = 2 -expand_mode = 4 -stretch_mode = 5 - -[node name="Name" type="Label" parent="Layout"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 1 -theme_override_colors/font_outline_color = Color(0, 0, 0, 1) -theme_override_constants/outline_size = 0 -theme_override_styles/normal = SubResource("StyleBoxFlat_b4rkm") -text = "New Terrain" -vertical_alignment = 1 -text_overrun_behavior = 3 - -[connection signal="focus_entered" from="." to="." method="_on_focus_entered"] -[connection signal="focus_exited" from="." to="." method="_on_focus_exited"] diff --git a/godot/addons/better-terrain/editor/TerrainProperties.gd b/godot/addons/better-terrain/editor/TerrainProperties.gd deleted file mode 100644 index 09b3170..0000000 --- a/godot/addons/better-terrain/editor/TerrainProperties.gd +++ /dev/null @@ -1,85 +0,0 @@ -@tool -extends ConfirmationDialog - -var category_icon := load("res://addons/better-terrain/icons/NonModifying.svg") - -const CATEGORY_CHECK_ID = &"category_check_id" - -var accepted := false - -var terrain_name : String: - set(value): %NameEdit.text = value - get: return %NameEdit.text - -var terrain_color : Color: - set(value): %ColorPicker.color = value - get: return %ColorPicker.color - -var terrain_icon : String: - set(value): %IconEdit.text = value - get: return %IconEdit.text - -var terrain_type : int: - set(value): - %TypeOption.selected = value - _on_type_option_item_selected(value) - get: return %TypeOption.selected - -var terrain_categories : Array: set = set_categories, get = get_categories - - -# category is name, color, id -func set_category_data(options: Array) -> void: - if !options.is_empty(): - %CategoryLabel.show() - %CategoryContainer.show() - - for o in options: - var c = CheckBox.new() - c.text = o.name - c.icon = category_icon - c.add_theme_color_override(&"icon_normal_color", o.color) - c.add_theme_color_override(&"icon_disabled_color", Color(o.color, 0.4)) - c.add_theme_color_override(&"icon_focus_color", o.color) - c.add_theme_color_override(&"icon_hover_color", o.color) - c.add_theme_color_override(&"icon_hover_pressed_color", o.color) - c.add_theme_color_override(&"icon_normal_color", o.color) - c.add_theme_color_override(&"icon_pressed_color", o.color) - - c.set_meta(CATEGORY_CHECK_ID, o.id) - %CategoryLayout.add_child(c) - - -func set_categories(ids : Array): - for c in %CategoryLayout.get_children(): - c.button_pressed = c.get_meta(CATEGORY_CHECK_ID) in ids - - -func get_categories() -> Array: - var result := [] - if terrain_type == BetterTerrain.TerrainType.CATEGORY: - return result - for c in %CategoryLayout.get_children(): - if c.button_pressed: - result.push_back(c.get_meta(CATEGORY_CHECK_ID)) - return result - - -func _on_confirmed() -> void: - # confirm valid name - if terrain_name.is_empty(): - var dialog := AcceptDialog.new() - dialog.dialog_text = "Name cannot be empty" - EditorInterface.popup_dialog_centered(dialog) - await dialog.visibility_changed - dialog.queue_free() - return - - accepted = true - hide() - - -func _on_type_option_item_selected(index: int) -> void: - var categories_available = (index != BetterTerrain.TerrainType.CATEGORY) - for c in %CategoryLayout.get_children(): - c.disabled = !categories_available diff --git a/godot/addons/better-terrain/editor/TerrainProperties.gd.uid b/godot/addons/better-terrain/editor/TerrainProperties.gd.uid deleted file mode 100644 index 5603beb..0000000 --- a/godot/addons/better-terrain/editor/TerrainProperties.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4b16t0vx621a diff --git a/godot/addons/better-terrain/editor/TerrainProperties.tscn b/godot/addons/better-terrain/editor/TerrainProperties.tscn deleted file mode 100644 index 43fdd2b..0000000 --- a/godot/addons/better-terrain/editor/TerrainProperties.tscn +++ /dev/null @@ -1,93 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://fdjybw6e7whr"] - -[ext_resource type="Script" path="res://addons/better-terrain/editor/TerrainProperties.gd" id="1_52nx8"] -[ext_resource type="Texture2D" uid="uid://d1h1p7pcwdnjk" path="res://addons/better-terrain/icons/MatchTiles.svg" id="2_ncc5p"] -[ext_resource type="Texture2D" uid="uid://dfemy1g6okwlv" path="res://addons/better-terrain/icons/MatchVertices.svg" id="3_0nvmi"] -[ext_resource type="Texture2D" uid="uid://1yr6yruwl63u" path="res://addons/better-terrain/icons/NonModifying.svg" id="5_awp83"] - -[node name="TerrainProperties" type="ConfirmationDialog"] -title = "Edit terrain properties" -initial_position = 2 -size = Vector2i(317, 257) -visible = true -dialog_hide_on_ok = false -script = ExtResource("1_52nx8") - -[node name="GridContainer" type="GridContainer" parent="."] -offset_left = 8.0 -offset_top = 8.0 -offset_right = 309.0 -offset_bottom = 208.0 -columns = 2 - -[node name="NameLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Name" - -[node name="NameEdit" type="LineEdit" parent="GridContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Terrain name" - -[node name="ColorLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Color" - -[node name="ColorPicker" type="ColorPickerButton" parent="GridContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -color = Color(1, 0.262745, 0.498039, 1) -edit_alpha = false - -[node name="IconLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Icon" - -[node name="IconEdit" type="LineEdit" parent="GridContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -placeholder_text = "Icon path (optional)" - -[node name="TypeLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Mode" - -[node name="TypeOption" type="OptionButton" parent="GridContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -item_count = 3 -popup/item_0/text = "Match tiles" -popup/item_0/icon = ExtResource("2_ncc5p") -popup/item_1/text = "Match vertices" -popup/item_1/icon = ExtResource("3_0nvmi") -popup/item_1/id = 1 -popup/item_2/text = "Category" -popup/item_2/icon = ExtResource("5_awp83") -popup/item_2/id = 2 - -[node name="CategoryLabel" type="Label" parent="GridContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -size_flags_vertical = 1 -text = "Categories" - -[node name="CategoryContainer" type="ScrollContainer" parent="GridContainer"] -unique_name_in_owner = true -visible = false -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 -size_flags_vertical = 3 - -[node name="CategoryLayout" type="VBoxContainer" parent="GridContainer/CategoryContainer"] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 -size_flags_vertical = 3 - -[connection signal="confirmed" from="." to="." method="_on_confirmed"] -[connection signal="item_selected" from="GridContainer/TypeOption" to="." method="_on_type_option_item_selected"] diff --git a/godot/addons/better-terrain/editor/TerrainUndo.gd b/godot/addons/better-terrain/editor/TerrainUndo.gd deleted file mode 100644 index 201d7df..0000000 --- a/godot/addons/better-terrain/editor/TerrainUndo.gd +++ /dev/null @@ -1,190 +0,0 @@ -@tool -extends Node - -var action_index := 0 -var action_count := 0 -var _current_action_index := 0 -var _current_action_count := 0 - -func create_tile_restore_point(undo_manager: EditorUndoRedoManager, tm: TileMapLayer, cells: Array, and_surrounding_cells: bool = true) -> void: - if and_surrounding_cells: - cells = BetterTerrain._widen(tm, cells) - - var restore := [] - for c in cells: - restore.append([ - c, - tm.get_cell_source_id(c), - tm.get_cell_atlas_coords(c), - tm.get_cell_alternative_tile(c) - ]) - - undo_manager.add_undo_method(self, &"restore_tiles", tm, restore) - - -func create_tile_restore_point_area(undo_manager: EditorUndoRedoManager, tm: TileMapLayer, area: Rect2i, and_surrounding_cells: bool = true) -> void: - area.end += Vector2i.ONE - - var restore := [] - for y in range(area.position.y, area.end.y): - for x in range(area.position.x, area.end.x): - var c := Vector2i(x, y) - restore.append([ - c, - tm.get_cell_source_id(c), - tm.get_cell_atlas_coords(c), - tm.get_cell_alternative_tile(c) - ]) - - undo_manager.add_undo_method(self, &"restore_tiles", tm, restore) - - if !and_surrounding_cells: - return - - var edges := [] - for x in range(area.position.x, area.end.x): - edges.append(Vector2i(x, area.position.y)) - edges.append(Vector2i(x, area.end.y)) - for y in range(area.position.y + 1, area.end.y - 1): - edges.append(Vector2i(area.position.x, y)) - edges.append(Vector2i(area.end.x, y)) - - edges = BetterTerrain._widen_with_exclusion(tm, edges, area) - create_tile_restore_point(undo_manager, tm, edges, false) - - -func restore_tiles(tm: TileMapLayer, restore: Array) -> void: - for r in restore: - tm.set_cell(r[0], r[1], r[2], r[3]) - - -func create_peering_restore_point(undo_manager: EditorUndoRedoManager, ts: TileSet) -> void: - var restore := [] - - for s in ts.get_source_count(): - var source_id := ts.get_source_id(s) - var source := ts.get_source(source_id) as TileSetAtlasSource - if !source: - continue - - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - for a in source.get_alternative_tiles_count(coord): - var alternate := source.get_alternative_tile_id(coord, a) - - var td := source.get_tile_data(coord, alternate) - var tile_type := BetterTerrain.get_tile_terrain_type(td) - if tile_type == BetterTerrain.TileCategory.NON_TERRAIN: - continue - - var peering_dict := {} - for c in BetterTerrain.tile_peering_keys(td): - peering_dict[c] = BetterTerrain.tile_peering_types(td, c) - var symmetry = BetterTerrain.get_tile_symmetry_type(td) - restore.append([source_id, coord, alternate, tile_type, peering_dict, symmetry]) - - undo_manager.add_undo_method(self, &"restore_peering", ts, restore) - - -func create_peering_restore_point_specific(undo_manager: EditorUndoRedoManager, ts: TileSet, protect: int) -> void: - var restore := [] - - for s in ts.get_source_count(): - var source_id := ts.get_source_id(s) - var source := ts.get_source(source_id) as TileSetAtlasSource - if !source: - continue - - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - for a in source.get_alternative_tiles_count(coord): - var alternate := source.get_alternative_tile_id(coord, a) - - var td := source.get_tile_data(coord, alternate) - var tile_type := BetterTerrain.get_tile_terrain_type(td) - if tile_type == BetterTerrain.TileCategory.NON_TERRAIN: - continue - - var to_restore : bool = tile_type == protect - - var terrain := BetterTerrain.get_terrain(ts, tile_type) - var cells = BetterTerrain.data.get_terrain_peering_cells(ts, terrain.type) - for c in cells: - if protect in BetterTerrain.tile_peering_types(td, c): - to_restore = true - break - - if !to_restore: - continue - - var peering_dict := {} - for c in cells: - peering_dict[c] = BetterTerrain.tile_peering_types(td, c) - var symmetry = BetterTerrain.get_tile_symmetry_type(td) - restore.append([source_id, coord, alternate, tile_type, peering_dict, symmetry]) - - undo_manager.add_undo_method(self, &"restore_peering", ts, restore) - - -func create_peering_restore_point_tile(undo_manager: EditorUndoRedoManager, ts: TileSet, source_id: int, coord: Vector2i, alternate: int) -> void: - var source := ts.get_source(source_id) as TileSetAtlasSource - var td := source.get_tile_data(coord, alternate) - var tile_type := BetterTerrain.get_tile_terrain_type(td) - - var restore := [] - var peering_dict := {} - for c in BetterTerrain.tile_peering_keys(td): - peering_dict[c] = BetterTerrain.tile_peering_types(td, c) - var symmetry = BetterTerrain.get_tile_symmetry_type(td) - restore.append([source_id, coord, alternate, tile_type, peering_dict, symmetry]) - - undo_manager.add_undo_method(self, &"restore_peering", ts, restore) - - -func restore_peering(ts: TileSet, restore: Array) -> void: - for r in restore: - var source := ts.get_source(r[0]) as TileSetAtlasSource - var td := source.get_tile_data(r[1], r[2]) - BetterTerrain.set_tile_terrain_type(ts, td, r[3]) - var peering_types = r[4] - for peering in peering_types: - var types := BetterTerrain.tile_peering_types(td, peering) - for t in types: - BetterTerrain.remove_tile_peering_type(ts, td, peering, t) - for t in peering_types[peering]: - BetterTerrain.add_tile_peering_type(ts, td, peering, t) - var symmetry = r[5] - BetterTerrain.set_tile_symmetry_type(ts, td, symmetry) - - -func create_terrain_type_restore_point(undo_manager: EditorUndoRedoManager, ts: TileSet) -> void: - var count = BetterTerrain.terrain_count(ts) - var restore = [] - for i in count: - restore.push_back(BetterTerrain.get_terrain(ts, i)) - - undo_manager.add_undo_method(self, &"restore_terrain", ts, restore) - - -func restore_terrain(ts: TileSet, restore: Array) -> void: - for i in restore.size(): - var r = restore[i] - BetterTerrain.set_terrain(ts, i, r.name, r.color, r.type, r.categories, r.icon) - - -func add_do_method(undo_manager: EditorUndoRedoManager, object:Object, method:StringName, args:Array): - if action_index > _current_action_index: - _current_action_index = action_index - _current_action_count = action_count - if action_count > _current_action_count: - _current_action_count = action_count - undo_manager.add_do_method(self, "_do_method", object, method, args, action_count) - - -func _do_method(object:Object, method:StringName, args:Array, this_action_count:int): - if this_action_count >= _current_action_count: - object.callv(method, args) - - -func finish_action(): - _current_action_count = 0 diff --git a/godot/addons/better-terrain/editor/TerrainUndo.gd.uid b/godot/addons/better-terrain/editor/TerrainUndo.gd.uid deleted file mode 100644 index f9a0f5c..0000000 --- a/godot/addons/better-terrain/editor/TerrainUndo.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://di6bxgay3uvku diff --git a/godot/addons/better-terrain/editor/TileView.gd b/godot/addons/better-terrain/editor/TileView.gd deleted file mode 100644 index 4947d83..0000000 --- a/godot/addons/better-terrain/editor/TileView.gd +++ /dev/null @@ -1,899 +0,0 @@ -@tool -extends Control - -signal paste_occurred -signal change_zoom_level(value) -signal terrain_updated(index) - -@onready var checkerboard := get_theme_icon("Checkerboard", "EditorIcons") - -@onready var paint_symmetry_icons := [ - null, - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg"), - preload("res://addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg"), -] - -# Draw checkerboard and tiles with specific materials in -# individual canvas items via rendering server -var _canvas_item_map = {} -var _canvas_item_background : RID - -var tileset: TileSet -var disabled_sources: Array[int] = []: set = set_disabled_sources - -var paint := BetterTerrain.TileCategory.NON_TERRAIN -var paint_symmetry := BetterTerrain.SymmetryType.NONE -var highlighted_tile_part := { valid = false } -var zoom_level := 1.0 - -var tiles_size : Vector2 -var tile_size : Vector2i -var tile_part_size : Vector2 -var alternate_size : Vector2 -var alternate_lookup := [] -var initial_click : Vector2i -var prev_position : Vector2i -var current_position : Vector2i - -var selection_start : Vector2i -var selection_end : Vector2i -var selection_rect : Rect2i -var selected_tile_states : Array[Dictionary] = [] -var copied_tile_states : Array[Dictionary] = [] -var staged_paste_tile_states : Array[Dictionary] = [] - -var pick_icon_terrain : int = -1 -var pick_icon_terrain_cancel := false - -var undo_manager : EditorUndoRedoManager -var terrain_undo - -# Modes for painting -enum PaintMode { - NO_PAINT, - PAINT_TYPE, - PAINT_PEERING, - PAINT_SYMMETRY, - SELECT, - PASTE -} - -var paint_mode := PaintMode.NO_PAINT - -# Actual interactions for painting -enum PaintAction { - NO_ACTION, - DRAW_TYPE, - ERASE_TYPE, - DRAW_PEERING, - ERASE_PEERING, - DRAW_SYMMETRY, - ERASE_SYMMETRY, - SELECT, - PASTE -} - -var paint_action := PaintAction.NO_ACTION - -const ALTERNATE_TILE_MARGIN := 18 - -func _enter_tree() -> void: - _canvas_item_background = RenderingServer.canvas_item_create() - RenderingServer.canvas_item_set_parent(_canvas_item_background, get_canvas_item()) - RenderingServer.canvas_item_set_draw_behind_parent(_canvas_item_background, true) - - -func _exit_tree() -> void: - RenderingServer.free_rid(_canvas_item_background) - for p in _canvas_item_map: - RenderingServer.free_rid(_canvas_item_map[p]) - _canvas_item_map.clear() - - -func refresh_tileset(ts: TileSet) -> void: - tileset = ts - - tiles_size = Vector2.ZERO - alternate_size = Vector2.ZERO - alternate_lookup = [] - disabled_sources = disabled_sources.filter( - func(id): - return ts.has_source(id) - ) - - if !tileset: - return - - for s in tileset.get_source_count(): - var source_id := tileset.get_source_id(s) - var source := tileset.get_source(source_id) as TileSetAtlasSource - if !source or !source.texture: - continue - - tiles_size.x = max(tiles_size.x, source.texture.get_width()) - tiles_size.y += source.texture.get_height() - - tile_size = source.texture_region_size - tile_part_size = Vector2(tile_size) / 3.0 - - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - var alt_count := source.get_alternative_tiles_count(coord) - if alt_count <= 1: - continue - - var rect := source.get_tile_texture_region(coord, 0) - alternate_lookup.append([rect.size, source_id, coord]) - alternate_size.x = max(alternate_size.x, rect.size.x * (alt_count - 1)) - alternate_size.y += rect.size.y - - _on_zoom_value_changed(zoom_level) - - -func is_tile_in_source(source: TileSetAtlasSource, coord: Vector2i) -> bool: - var origin := source.get_tile_at_coords(coord) - if origin == Vector2i(-1, -1): - return false - - # Animation frames are not needed - var size := source.get_tile_size_in_atlas(origin) - return coord.x < origin.x + size.x and coord.y < origin.y + size.y - - -func _build_tile_part_from_position(result: Dictionary, position: Vector2i, rect: Rect2) -> void: - result.rect = rect - var type := BetterTerrain.get_tile_terrain_type(result.data) - if type == BetterTerrain.TileCategory.NON_TERRAIN: - return - result.terrain_type = type - - var normalize_position := (Vector2(position) - rect.position) / rect.size - - var terrain := BetterTerrain.get_terrain(tileset, type) - if !terrain.valid: - return - for p in BetterTerrain.data.get_terrain_peering_cells(tileset, terrain.type): - var side_polygon = BetterTerrain.data.peering_polygon(tileset, terrain.type, p) - if Geometry2D.is_point_in_polygon(normalize_position, side_polygon): - result.peering = p - result.polygon = side_polygon - break - - -func tile_part_from_position(position: Vector2i) -> Dictionary: - if !tileset: - return { valid = false } - - var offset := Vector2.ZERO - var alt_offset := Vector2.RIGHT * (zoom_level * tiles_size.x + ALTERNATE_TILE_MARGIN) - if Rect2(alt_offset, zoom_level * alternate_size).has_point(position): - for a in alternate_lookup: - if a[1] in disabled_sources: - continue - var next_offset_y = alt_offset.y + zoom_level * a[0].y - if position.y > next_offset_y: - alt_offset.y = next_offset_y - continue - - var source := tileset.get_source(a[1]) as TileSetAtlasSource - if !source: - break - - var count := source.get_alternative_tiles_count(a[2]) - var index := int((position.x - alt_offset.x) / (zoom_level * a[0].x)) + 1 - - if index < count: - var alt_id := source.get_alternative_tile_id(a[2], index) - var target_rect := Rect2( - alt_offset + Vector2.RIGHT * (index - 1) * zoom_level * a[0].x, - zoom_level * a[0] - ) - - var result := { - valid = true, - source_id = a[1], - coord = a[2], - alternate = alt_id, - data = source.get_tile_data(a[2], alt_id) - } - _build_tile_part_from_position(result, position, target_rect) - return result - - else: - for s in tileset.get_source_count(): - var source_id := tileset.get_source_id(s) - if source_id in disabled_sources: - continue - var source := tileset.get_source(source_id) as TileSetAtlasSource - if !source || !source.texture: - continue - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - var rect := source.get_tile_texture_region(coord, 0) - var target_rect := Rect2(offset + zoom_level * rect.position, zoom_level * rect.size) - if !target_rect.has_point(position): - continue - - var result := { - valid = true, - source_id = source_id, - coord = coord, - alternate = 0, - data = source.get_tile_data(coord, 0) - } - _build_tile_part_from_position(result, position, target_rect) - return result - - offset.y += zoom_level * source.texture.get_height() - - return { valid = false } - - -func tile_rect_from_position(position: Vector2i) -> Rect2: - if !tileset: - return Rect2(-1,-1,0,0) - - var offset := Vector2.ZERO - var alt_offset := Vector2.RIGHT * (zoom_level * tiles_size.x + ALTERNATE_TILE_MARGIN) - if Rect2(alt_offset, zoom_level * alternate_size).has_point(position): - for a in alternate_lookup: - if a[1] in disabled_sources: - continue - var next_offset_y = alt_offset.y + zoom_level * a[0].y - if position.y > next_offset_y: - alt_offset.y = next_offset_y - continue - - var source := tileset.get_source(a[1]) as TileSetAtlasSource - if !source: - break - - var count := source.get_alternative_tiles_count(a[2]) - var index := int((position.x - alt_offset.x) / (zoom_level * a[0].x)) + 1 - - if index < count: - var target_rect := Rect2( - alt_offset + Vector2.RIGHT * (index - 1) * zoom_level * a[0].x, - zoom_level * a[0] - ) - return target_rect - - else: - for s in tileset.get_source_count(): - var source_id := tileset.get_source_id(s) - if source_id in disabled_sources: - continue - var source := tileset.get_source(source_id) as TileSetAtlasSource - if !source: - continue - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - var rect := source.get_tile_texture_region(coord, 0) - var target_rect := Rect2(offset + zoom_level * rect.position, zoom_level * rect.size) - if target_rect.has_point(position): - return target_rect - - offset.y += zoom_level * source.texture.get_height() - - return Rect2(-1,-1,0,0) - - -func tile_parts_from_rect(rect:Rect2) -> Array[Dictionary]: - if !tileset: - return [] - - var tiles:Array[Dictionary] = [] - - var offset := Vector2.ZERO - var alt_offset := Vector2.RIGHT * (zoom_level * tiles_size.x + ALTERNATE_TILE_MARGIN) - for s in tileset.get_source_count(): - var source_id := tileset.get_source_id(s) - if source_id in disabled_sources: - continue - var source := tileset.get_source(source_id) as TileSetAtlasSource - if !source: - continue - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - var tile_rect := source.get_tile_texture_region(coord, 0) - var target_rect := Rect2(offset + zoom_level * tile_rect.position, zoom_level * tile_rect.size) - if target_rect.intersects(rect): - var result := { - valid = true, - source_id = source_id, - coord = coord, - alternate = 0, - data = source.get_tile_data(coord, 0) - } - var pos = target_rect.position + target_rect.size/2 - _build_tile_part_from_position(result, pos, target_rect) - tiles.push_back(result) - var alt_count := source.get_alternative_tiles_count(coord) - for a in alt_count: - var alt_id := 0 - if a == 0: - continue - - target_rect = Rect2(alt_offset + zoom_level * (a - 1) * tile_rect.size.x * Vector2.RIGHT, zoom_level * tile_rect.size) - alt_id = source.get_alternative_tile_id(coord, a) - if target_rect.intersects(rect): - var td := source.get_tile_data(coord, alt_id) - var result := { - valid = true, - source_id = source_id, - coord = coord, - alternate = alt_id, - data = td - } - var pos = target_rect.position + target_rect.size/2 - _build_tile_part_from_position(result, pos, target_rect) - tiles.push_back(result) - if alt_count > 1: - alt_offset.y += zoom_level * tile_rect.size.y - - offset.y += zoom_level * source.texture.get_height() - - return tiles - - -func _get_canvas_item(td: TileData) -> RID: - if !td.material: - return self.get_canvas_item() - if _canvas_item_map.has(td.material): - return _canvas_item_map[td.material] - - var rid = RenderingServer.canvas_item_create() - RenderingServer.canvas_item_set_material(rid, td.material.get_rid()) - RenderingServer.canvas_item_set_parent(rid, get_canvas_item()) - RenderingServer.canvas_item_set_draw_behind_parent(rid, true) - RenderingServer.canvas_item_set_default_texture_filter(rid, RenderingServer.CANVAS_ITEM_TEXTURE_FILTER_NEAREST) - _canvas_item_map[td.material] = rid - return rid - - -func _draw_tile_data(texture: Texture2D, rect: Rect2, src_rect: Rect2, td: TileData, draw_sides: bool = true) -> void: - var flipped_rect := rect - if td.flip_h: - flipped_rect.size.x = -rect.size.x - if td.flip_v: - flipped_rect.size.y = -rect.size.y - - RenderingServer.canvas_item_add_texture_rect_region( - _get_canvas_item(td), - flipped_rect, - texture.get_rid(), - src_rect, - td.modulate, - td.transpose - ) - - var type := BetterTerrain.get_tile_terrain_type(td) - if type == BetterTerrain.TileCategory.NON_TERRAIN: - draw_rect(rect, Color(0.1, 0.1, 0.1, 0.5), true) - return - - var terrain := BetterTerrain.get_terrain(tileset, type) - if !terrain.valid: - return - - var transform := Transform2D(0.0, rect.size, 0.0, rect.position) - var center_polygon = transform * BetterTerrain.data.peering_polygon(tileset, terrain.type, -1) - draw_colored_polygon(center_polygon, Color(terrain.color, 0.6)) - if terrain.type == BetterTerrain.TerrainType.DECORATION: - center_polygon.append(center_polygon[0]) - draw_polyline(center_polygon, Color.BLACK) - - if paint < BetterTerrain.TileCategory.EMPTY or paint >= BetterTerrain.terrain_count(tileset): - return - - if not draw_sides: - return - - var paint_terrain := BetterTerrain.get_terrain(tileset, paint) - for p in BetterTerrain.data.get_terrain_peering_cells(tileset, terrain.type): - if paint in BetterTerrain.tile_peering_types(td, p): - var side_polygon = transform * BetterTerrain.data.peering_polygon(tileset, terrain.type, p) - draw_colored_polygon(side_polygon, Color(paint_terrain.color, 0.6)) - if paint_terrain.type == BetterTerrain.TerrainType.DECORATION: - side_polygon.append(side_polygon[0]) - draw_polyline(side_polygon, Color.BLACK) - - -func _draw_tile_symmetry(texture: Texture2D, rect: Rect2, src_rect: Rect2, td: TileData, draw_icon: bool = true) -> void: - var flipped_rect := rect - if td.flip_h: - flipped_rect.size.x = -rect.size.x - if td.flip_v: - flipped_rect.size.y = -rect.size.y - - RenderingServer.canvas_item_add_texture_rect_region( - _get_canvas_item(td), - flipped_rect, - texture.get_rid(), - src_rect, - td.modulate, - td.transpose - ) - - if not draw_icon: - return - - var symmetry_type = BetterTerrain.get_tile_symmetry_type(td) - if symmetry_type == 0: - return - var symmetry_icon = paint_symmetry_icons[symmetry_type] - - RenderingServer.canvas_item_add_texture_rect_region( - _get_canvas_item(td), - rect, - symmetry_icon.get_rid(), - Rect2(Vector2.ZERO, symmetry_icon.get_size()), - Color(1,1,1,0.5) - ) - - -func _draw() -> void: - if !tileset: - return - - # Clear material-based render targets - RenderingServer.canvas_item_clear(_canvas_item_background) - for p in _canvas_item_map: - RenderingServer.canvas_item_clear(_canvas_item_map[p]) - - var offset := Vector2.ZERO - var alt_offset := Vector2.RIGHT * (zoom_level * tiles_size.x + ALTERNATE_TILE_MARGIN) - - RenderingServer.canvas_item_add_texture_rect( - _canvas_item_background, - Rect2(alt_offset, zoom_level * alternate_size), - checkerboard.get_rid(), - true - ) - - for s in tileset.get_source_count(): - var source_id := tileset.get_source_id(s) - if source_id in disabled_sources: - continue - var source := tileset.get_source(source_id) as TileSetAtlasSource - if !source or !source.texture: - continue - - RenderingServer.canvas_item_add_texture_rect( - _canvas_item_background, - Rect2(offset, zoom_level * source.texture.get_size()), - checkerboard.get_rid(), - true - ) - for t in source.get_tiles_count(): - var coord := source.get_tile_id(t) - var rect := source.get_tile_texture_region(coord, 0) - var alt_count := source.get_alternative_tiles_count(coord) - var target_rect : Rect2 - for a in alt_count: - var alt_id := 0 - if a == 0: - target_rect = Rect2(offset + zoom_level * rect.position, zoom_level * rect.size) - else: - target_rect = Rect2(alt_offset + zoom_level * (a - 1) * rect.size.x * Vector2.RIGHT, zoom_level * rect.size) - alt_id = source.get_alternative_tile_id(coord, a) - - var td := source.get_tile_data(coord, alt_id) - var drawing_current = BetterTerrain.get_tile_terrain_type(td) == paint - if paint_mode == PaintMode.PAINT_SYMMETRY: - _draw_tile_symmetry(source.texture, target_rect, rect, td, drawing_current) - else: - _draw_tile_data(source.texture, target_rect, rect, td) - - if drawing_current: - draw_rect(target_rect.grow(-1), Color(0,0,0, 0.75), false, 1) - draw_rect(target_rect, Color(1,1,1, 0.75), false, 1) - - if paint_mode == PaintMode.SELECT: - if selected_tile_states.any(func(v): - return v.part.data == td - ): - draw_rect(target_rect.grow(-1), Color.DEEP_SKY_BLUE, false, 2) - - if alt_count > 1: - alt_offset.y += zoom_level * rect.size.y - - # Blank out unused or uninteresting tiles - var size := source.get_atlas_grid_size() - for y in size.y: - for x in size.x: - var pos := Vector2i(x, y) - if !is_tile_in_source(source, pos): - var atlas_pos := source.margins + pos * (source.separation + source.texture_region_size) - draw_rect(Rect2(offset + zoom_level * atlas_pos, zoom_level * source.texture_region_size), Color(0.0, 0.0, 0.0, 0.8), true) - - offset.y += zoom_level * source.texture.get_height() - - # Blank out unused alternate tile sections - alt_offset = Vector2.RIGHT * (zoom_level * tiles_size.x + ALTERNATE_TILE_MARGIN) - for a in alternate_lookup: - if a[1] in disabled_sources: - continue - var source := tileset.get_source(a[1]) as TileSetAtlasSource - if source: - var count := source.get_alternative_tiles_count(a[2]) - 1 - var occupied_width = count * zoom_level * a[0].x - var area := Rect2( - alt_offset.x + occupied_width, - alt_offset.y, - zoom_level * alternate_size.x - occupied_width, - zoom_level * a[0].y - ) - draw_rect(area, Color(0.0, 0.0, 0.0, 0.8), true) - alt_offset.y += zoom_level * a[0].y - - if highlighted_tile_part.valid: - if paint_mode == PaintMode.PAINT_PEERING and highlighted_tile_part.has("polygon"): - var transform := Transform2D(0.0, highlighted_tile_part.rect.size - 2 * Vector2.ONE, 0.0, highlighted_tile_part.rect.position + Vector2.ONE) - draw_colored_polygon(transform * highlighted_tile_part.polygon, Color(Color.WHITE, 0.2)) - if paint_mode != PaintMode.NO_PAINT: - var inner_rect := Rect2(highlighted_tile_part.rect.position + Vector2.ONE, highlighted_tile_part.rect.size - 2 * Vector2.ONE) - draw_rect(inner_rect, Color.WHITE, false) - if paint_mode == PaintMode.PAINT_SYMMETRY: - if paint_symmetry > 0: - var symmetry_icon = paint_symmetry_icons[paint_symmetry] - draw_texture_rect(symmetry_icon, highlighted_tile_part.rect, false, Color(0.5,0.75,1,0.5)) - - if paint_mode == PaintMode.SELECT: - draw_rect(selection_rect, Color.WHITE, false) - - if paint_mode == PaintMode.PASTE: - if staged_paste_tile_states.size() > 0: - var base_rect = staged_paste_tile_states[0].base_rect - var paint_terrain := BetterTerrain.get_terrain(tileset, paint) - var paint_terrain_type = paint_terrain.type - if paint_terrain_type == BetterTerrain.TerrainType.CATEGORY: - paint_terrain_type = 0 - for state in staged_paste_tile_states: - var staged_rect:Rect2 = state.base_rect - staged_rect.position -= base_rect.position + base_rect.size / 2 - - staged_rect.position *= zoom_level - staged_rect.size *= zoom_level - - staged_rect.position += Vector2(current_position) - - var real_rect = tile_rect_from_position(staged_rect.get_center()) - if real_rect.position.x >= 0: - draw_rect(real_rect, Color(0,0,0, 0.3), true) - var transform := Transform2D(0.0, real_rect.size, 0.0, real_rect.position) - var tile_sides = BetterTerrain.data.get_terrain_peering_cells(tileset, paint_terrain_type) - for p in tile_sides: - if state.paint in BetterTerrain.tile_peering_types(state.part.data, p): - var side_polygon = BetterTerrain.data.peering_polygon(tileset, paint_terrain_type, p) - var color = Color(paint_terrain.color, 0.6) - draw_colored_polygon(transform * side_polygon, color) - - draw_rect(staged_rect, Color.DEEP_PINK, false) - - - -func delete_selection(): - undo_manager.create_action("Delete tile terrain peering types", UndoRedo.MERGE_DISABLE, tileset) - for t in selected_tile_states: - for side in range(16): - var old_peering = BetterTerrain.tile_peering_types(t.part.data, side) - if old_peering.has(paint): - undo_manager.add_do_method(BetterTerrain, &"remove_tile_peering_type", tileset, t.part.data, side, paint) - undo_manager.add_undo_method(BetterTerrain, &"add_tile_peering_type", tileset, t.part.data, side, paint) - - undo_manager.add_do_method(self, &"queue_redraw") - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - - -func toggle_selection(): - undo_manager.create_action("Toggle tile terrain", UndoRedo.MERGE_DISABLE, tileset, true) - for t in selected_tile_states: - var type := BetterTerrain.get_tile_terrain_type(t.part.data) - var goal := paint if paint != type else BetterTerrain.TileCategory.NON_TERRAIN - - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_tile_terrain_type", [tileset, t.part.data, goal]) - if goal == BetterTerrain.TileCategory.NON_TERRAIN: - terrain_undo.create_peering_restore_point_tile( - undo_manager, - tileset, - t.part.source_id, - t.part.coord, - t.part.alternate - ) - else: - undo_manager.add_undo_method(BetterTerrain, &"set_tile_terrain_type", tileset, t.part.data, type) - - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - - -func copy_selection(): - copied_tile_states = selected_tile_states - - -func paste_selection(): - staged_paste_tile_states = copied_tile_states - selected_tile_states = [] - paint_mode = PaintMode.PASTE - paint_action = PaintAction.PASTE - paste_occurred.emit() - queue_redraw() - - -func set_disabled_sources(list): - disabled_sources = list - queue_redraw() - - -func emit_terrain_updated(index): - terrain_updated.emit(index) - - -func _gui_input(event) -> void: - if event is InputEventKey and event.is_pressed(): - if event.keycode == KEY_DELETE and not event.echo: - accept_event() - delete_selection() - if event.keycode == KEY_ENTER and not event.echo: - accept_event() - toggle_selection() - if event.keycode == KEY_ESCAPE and not event.echo: - accept_event() - if paint_action == PaintAction.PASTE: - staged_paste_tile_states = [] - paint_mode = PaintMode.SELECT - paint_action = PaintAction.NO_ACTION - selection_start = Vector2i(-1,-1) - if event.keycode == KEY_C and (event.ctrl_pressed or event.meta_pressed) and not event.echo: - accept_event() - copy_selection() - if event.keycode == KEY_X and (event.ctrl_pressed or event.meta_pressed) and not event.echo: - accept_event() - copy_selection() - delete_selection() - if event.keycode == KEY_V and (event.ctrl_pressed or event.meta_pressed) and not event.echo: - accept_event() - paste_selection() - if event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_WHEEL_UP and (event.ctrl_pressed or event.meta_pressed): - accept_event() - change_zoom_level.emit(zoom_level * 1.1) - if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and (event.ctrl_pressed or event.meta_pressed): - accept_event() - change_zoom_level.emit(zoom_level / 1.1) - - var released : bool = event is InputEventMouseButton and (not event.pressed and (event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT)) - if released: - paint_action = PaintAction.NO_ACTION - - if event is InputEventMouseMotion: - prev_position = current_position - current_position = event.position - var tile := tile_part_from_position(event.position) - if tile.valid != highlighted_tile_part.valid or\ - (tile.valid and tile.data != highlighted_tile_part.data) or\ - (tile.valid and tile.get("peering") != highlighted_tile_part.get("peering")) or\ - event.button_mask & MOUSE_BUTTON_LEFT and paint_action == PaintAction.SELECT: - queue_redraw() - highlighted_tile_part = tile - - var clicked : bool = event is InputEventMouseButton and (event.pressed and (event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT)) - if clicked: - initial_click = current_position - selection_start = Vector2i(-1,-1) - terrain_undo.action_index += 1 - terrain_undo.action_count = 0 - if released: - terrain_undo.finish_action() - selection_rect = Rect2i(0,0,0,0) - queue_redraw() - - if paint_action == PaintAction.PASTE: - if event is InputEventMouseMotion: - queue_redraw() - - if clicked: - if event.button_index == MOUSE_BUTTON_LEFT and staged_paste_tile_states.size() > 0: - undo_manager.create_action("Paste tile terrain peering types", UndoRedo.MERGE_DISABLE, tileset) - var base_rect = staged_paste_tile_states[0].base_rect - for p in staged_paste_tile_states: - var staged_rect:Rect2 = p.base_rect - staged_rect.position -= base_rect.position + base_rect.size / 2 - - staged_rect.position *= zoom_level - staged_rect.size *= zoom_level - - staged_rect.position += Vector2(current_position) - - var old_tile_part = tile_part_from_position(staged_rect.get_center()) - var new_tile_state = p - if (not old_tile_part.valid) or (not new_tile_state.part.valid): - continue - - for side in range(16): - var old_peering = BetterTerrain.tile_peering_types(old_tile_part.data, side) - var new_sides = new_tile_state.sides - if new_sides.has(side) and not old_peering.has(paint): - undo_manager.add_do_method(BetterTerrain, &"add_tile_peering_type", tileset, old_tile_part.data, side, paint) - undo_manager.add_undo_method(BetterTerrain, &"remove_tile_peering_type", tileset, old_tile_part.data, side, paint) - elif old_peering.has(paint) and not new_sides.has(side): - undo_manager.add_do_method(BetterTerrain, &"remove_tile_peering_type", tileset, old_tile_part.data, side, paint) - undo_manager.add_undo_method(BetterTerrain, &"add_tile_peering_type", tileset, old_tile_part.data, side, paint) - - var old_symmetry = BetterTerrain.get_tile_symmetry_type(old_tile_part.data) - var new_symmetry = new_tile_state.symmetry - if new_symmetry != old_symmetry: - undo_manager.add_do_method(BetterTerrain, &"set_tile_symmetry_type", tileset, old_tile_part.data, new_symmetry) - undo_manager.add_undo_method(BetterTerrain, &"set_tile_symmetry_type", tileset, old_tile_part.data, old_symmetry) - - undo_manager.add_do_method(self, &"queue_redraw") - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - - staged_paste_tile_states = [] - paint_mode = PaintMode.SELECT - paint_action = PaintAction.SELECT - return - - if clicked and pick_icon_terrain >= 0: - highlighted_tile_part = tile_part_from_position(current_position) - if !highlighted_tile_part.valid: - return - - var t = BetterTerrain.get_terrain(tileset, paint) - var prev_icon = t.icon.duplicate() - var icon = { - source_id = highlighted_tile_part.source_id, - coord = highlighted_tile_part.coord - } - undo_manager.create_action("Edit terrain details", UndoRedo.MERGE_DISABLE, tileset) - undo_manager.add_do_method(BetterTerrain, &"set_terrain", tileset, paint, t.name, t.color, t.type, t.categories, icon) - undo_manager.add_do_method(self, &"emit_terrain_updated", paint) - undo_manager.add_undo_method(BetterTerrain, &"set_terrain", tileset, paint, t.name, t.color, t.type, t.categories, prev_icon) - undo_manager.add_undo_method(self, &"emit_terrain_updated", paint) - undo_manager.commit_action() - pick_icon_terrain = -1 - return - - if pick_icon_terrain_cancel: - pick_icon_terrain = -1 - pick_icon_terrain_cancel = false - - if paint != BetterTerrain.TileCategory.NON_TERRAIN and clicked: - paint_action = PaintAction.NO_ACTION - if highlighted_tile_part.valid: - match [paint_mode, event.button_index]: - [PaintMode.PAINT_TYPE, MOUSE_BUTTON_LEFT]: paint_action = PaintAction.DRAW_TYPE - [PaintMode.PAINT_TYPE, MOUSE_BUTTON_RIGHT]: paint_action = PaintAction.ERASE_TYPE - [PaintMode.PAINT_PEERING, MOUSE_BUTTON_LEFT]: paint_action = PaintAction.DRAW_PEERING - [PaintMode.PAINT_PEERING, MOUSE_BUTTON_RIGHT]: paint_action = PaintAction.ERASE_PEERING - [PaintMode.PAINT_SYMMETRY, MOUSE_BUTTON_LEFT]: paint_action = PaintAction.DRAW_SYMMETRY - [PaintMode.PAINT_SYMMETRY, MOUSE_BUTTON_RIGHT]: paint_action = PaintAction.ERASE_SYMMETRY - [PaintMode.SELECT, MOUSE_BUTTON_LEFT]: paint_action = PaintAction.SELECT - else: - match [paint_mode, event.button_index]: - [PaintMode.SELECT, MOUSE_BUTTON_LEFT]: paint_action = PaintAction.SELECT - - if (clicked or event is InputEventMouseMotion) and paint_action != PaintAction.NO_ACTION: - - if paint_action == PaintAction.SELECT: - if clicked: - selection_start = Vector2i(-1,-1) - queue_redraw() - if selection_start.x < 0: - selection_start = current_position - selection_end = current_position - - selection_rect = Rect2i(selection_start, selection_end - selection_start).abs() - var selected_tile_parts = tile_parts_from_rect(selection_rect) - selected_tile_states = [] - for t in selected_tile_parts: - var state := { - part = t, - base_rect = Rect2(t.rect.position / zoom_level, t.rect.size / zoom_level), - paint = paint, - sides = BetterTerrain.tile_peering_for_type(t.data, paint), - symmetry = BetterTerrain.get_tile_symmetry_type(t.data) - } - selected_tile_states.push_back(state) - else: - if !highlighted_tile_part.valid: - return - #slightly crude and non-optimal but way simpler than the "correct" solution - var current_position_vec2 = Vector2(current_position) - var prev_position_vec2 = Vector2(prev_position) - var mouse_dist = current_position_vec2.distance_to(prev_position_vec2) - var step_size = (tile_part_size.x * zoom_level) - var steps = ceil(mouse_dist / step_size) + 1 - for i in range(steps): - var t = float(i) / steps - var check_position = prev_position_vec2.lerp(current_position_vec2, t) - highlighted_tile_part = tile_part_from_position(check_position) - - if !highlighted_tile_part.valid: - continue - - if paint_action == PaintAction.DRAW_TYPE or paint_action == PaintAction.ERASE_TYPE: - var type := BetterTerrain.get_tile_terrain_type(highlighted_tile_part.data) - var goal := paint if paint_action == PaintAction.DRAW_TYPE else BetterTerrain.TileCategory.NON_TERRAIN - if type != goal: - undo_manager.create_action("Set tile terrain type " + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tileset, true) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_tile_terrain_type", [tileset, highlighted_tile_part.data, goal]) - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - if goal == BetterTerrain.TileCategory.NON_TERRAIN: - terrain_undo.create_peering_restore_point_tile( - undo_manager, - tileset, - highlighted_tile_part.source_id, - highlighted_tile_part.coord, - highlighted_tile_part.alternate - ) - else: - undo_manager.add_undo_method(BetterTerrain, &"set_tile_terrain_type", tileset, highlighted_tile_part.data, type) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - elif paint_action == PaintAction.DRAW_PEERING: - if highlighted_tile_part.has("peering"): - if !(paint in BetterTerrain.tile_peering_types(highlighted_tile_part.data, highlighted_tile_part.peering)): - undo_manager.create_action("Set tile terrain peering type " + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tileset, true) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"add_tile_peering_type", [tileset, highlighted_tile_part.data, highlighted_tile_part.peering, paint]) - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - undo_manager.add_undo_method(BetterTerrain, &"remove_tile_peering_type", tileset, highlighted_tile_part.data, highlighted_tile_part.peering, paint) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - elif paint_action == PaintAction.ERASE_PEERING: - if highlighted_tile_part.has("peering"): - if paint in BetterTerrain.tile_peering_types(highlighted_tile_part.data, highlighted_tile_part.peering): - undo_manager.create_action("Remove tile terrain peering type " + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tileset, true) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"remove_tile_peering_type", [tileset, highlighted_tile_part.data, highlighted_tile_part.peering, paint]) - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - undo_manager.add_undo_method(BetterTerrain, &"add_tile_peering_type", tileset, highlighted_tile_part.data, highlighted_tile_part.peering, paint) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - elif paint_action == PaintAction.DRAW_SYMMETRY: - if paint == BetterTerrain.get_tile_terrain_type(highlighted_tile_part.data): - undo_manager.create_action("Set tile symmetry type " + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tileset, true) - var old_symmetry = BetterTerrain.get_tile_symmetry_type(highlighted_tile_part.data) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_tile_symmetry_type", [tileset, highlighted_tile_part.data, paint_symmetry]) - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - undo_manager.add_undo_method(BetterTerrain, &"set_tile_symmetry_type", tileset, highlighted_tile_part.data, old_symmetry) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - elif paint_action == PaintAction.ERASE_SYMMETRY: - if paint == BetterTerrain.get_tile_terrain_type(highlighted_tile_part.data): - undo_manager.create_action("Remove tile symmetry type " + str(terrain_undo.action_index), UndoRedo.MERGE_ALL, tileset, true) - var old_symmetry = BetterTerrain.get_tile_symmetry_type(highlighted_tile_part.data) - terrain_undo.add_do_method(undo_manager, BetterTerrain, &"set_tile_symmetry_type", [tileset, highlighted_tile_part.data, BetterTerrain.SymmetryType.NONE]) - terrain_undo.add_do_method(undo_manager, self, &"queue_redraw", []) - undo_manager.add_undo_method(BetterTerrain, &"set_tile_symmetry_type", tileset, highlighted_tile_part.data, old_symmetry) - undo_manager.add_undo_method(self, &"queue_redraw") - undo_manager.commit_action() - terrain_undo.action_count += 1 - - -func _on_zoom_value_changed(value) -> void: - zoom_level = value - custom_minimum_size.x = zoom_level * tiles_size.x - if alternate_size.x > 0: - custom_minimum_size.x += ALTERNATE_TILE_MARGIN + zoom_level * alternate_size.x - custom_minimum_size.y = zoom_level * max(tiles_size.y, alternate_size.y) - queue_redraw() - - -func clear_highlighted_tile() -> void: - highlighted_tile_part = { valid = false } - queue_redraw() diff --git a/godot/addons/better-terrain/editor/TileView.gd.uid b/godot/addons/better-terrain/editor/TileView.gd.uid deleted file mode 100644 index bd04da7..0000000 --- a/godot/addons/better-terrain/editor/TileView.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bx2gcykbipbxo diff --git a/godot/addons/better-terrain/icon.svg b/godot/addons/better-terrain/icon.svg deleted file mode 100644 index 377fba9..0000000 --- a/godot/addons/better-terrain/icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icon.svg.import b/godot/addons/better-terrain/icon.svg.import deleted file mode 100644 index 16696c1..0000000 --- a/godot/addons/better-terrain/icon.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c66nal373iwgd" -path="res://.godot/imported/icon.svg-7d4870855c0daec5051feb4adbea0091.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icon.svg" -dest_files=["res://.godot/imported/icon.svg-7d4870855c0daec5051feb4adbea0091.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/Decoration.svg b/godot/addons/better-terrain/icons/Decoration.svg deleted file mode 100644 index 8ec40b5..0000000 --- a/godot/addons/better-terrain/icons/Decoration.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/better-terrain/icons/Decoration.svg.import b/godot/addons/better-terrain/icons/Decoration.svg.import deleted file mode 100644 index 02587bb..0000000 --- a/godot/addons/better-terrain/icons/Decoration.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://kmypxsqhynyv" -path="res://.godot/imported/Decoration.svg-03773e83cc849c7744ecf3d36eee0072.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/Decoration.svg" -dest_files=["res://.godot/imported/Decoration.svg-03773e83cc849c7744ecf3d36eee0072.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/EditSymmetry.svg b/godot/addons/better-terrain/icons/EditSymmetry.svg deleted file mode 100644 index 3565800..0000000 --- a/godot/addons/better-terrain/icons/EditSymmetry.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/godot/addons/better-terrain/icons/EditSymmetry.svg.import b/godot/addons/better-terrain/icons/EditSymmetry.svg.import deleted file mode 100644 index 47ffaf5..0000000 --- a/godot/addons/better-terrain/icons/EditSymmetry.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://co6gwwmog0pjy" -path="res://.godot/imported/EditSymmetry.svg-794172208a8d86bb609531b82199f095.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/EditSymmetry.svg" -dest_files=["res://.godot/imported/EditSymmetry.svg-794172208a8d86bb609531b82199f095.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/EditTerrain.svg b/godot/addons/better-terrain/icons/EditTerrain.svg deleted file mode 100644 index e175385..0000000 --- a/godot/addons/better-terrain/icons/EditTerrain.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/EditTerrain.svg.import b/godot/addons/better-terrain/icons/EditTerrain.svg.import deleted file mode 100644 index 948006f..0000000 --- a/godot/addons/better-terrain/icons/EditTerrain.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bo2cjv08jkvf8" -path="res://.godot/imported/EditTerrain.svg-f7ee950d68a391de33e4e8ddd76bf2ac.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/EditTerrain.svg" -dest_files=["res://.godot/imported/EditTerrain.svg-f7ee950d68a391de33e4e8ddd76bf2ac.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/EditType.svg b/godot/addons/better-terrain/icons/EditType.svg deleted file mode 100644 index 51e7d41..0000000 --- a/godot/addons/better-terrain/icons/EditType.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/EditType.svg.import b/godot/addons/better-terrain/icons/EditType.svg.import deleted file mode 100644 index 0aa98cc..0000000 --- a/godot/addons/better-terrain/icons/EditType.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c6lxq2y7mpb18" -path="res://.godot/imported/EditType.svg-e7b3005c6a8f21d5102295c55b564ad1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/EditType.svg" -dest_files=["res://.godot/imported/EditType.svg-e7b3005c6a8f21d5102295c55b564ad1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/MatchTiles.svg b/godot/addons/better-terrain/icons/MatchTiles.svg deleted file mode 100644 index efc5713..0000000 --- a/godot/addons/better-terrain/icons/MatchTiles.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/MatchTiles.svg.import b/godot/addons/better-terrain/icons/MatchTiles.svg.import deleted file mode 100644 index a137b97..0000000 --- a/godot/addons/better-terrain/icons/MatchTiles.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d1h1p7pcwdnjk" -path="res://.godot/imported/MatchTiles.svg-38111e21a893bd8f161311f0d1968a40.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/MatchTiles.svg" -dest_files=["res://.godot/imported/MatchTiles.svg-38111e21a893bd8f161311f0d1968a40.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/MatchVertices.svg b/godot/addons/better-terrain/icons/MatchVertices.svg deleted file mode 100644 index 339ee2c..0000000 --- a/godot/addons/better-terrain/icons/MatchVertices.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/MatchVertices.svg.import b/godot/addons/better-terrain/icons/MatchVertices.svg.import deleted file mode 100644 index c914385..0000000 --- a/godot/addons/better-terrain/icons/MatchVertices.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dfemy1g6okwlv" -path="res://.godot/imported/MatchVertices.svg-288fe47ee1089920379407d6abf1a06c.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/MatchVertices.svg" -dest_files=["res://.godot/imported/MatchVertices.svg-288fe47ee1089920379407d6abf1a06c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/NonModifying.svg b/godot/addons/better-terrain/icons/NonModifying.svg deleted file mode 100644 index a1a10dd..0000000 --- a/godot/addons/better-terrain/icons/NonModifying.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/NonModifying.svg.import b/godot/addons/better-terrain/icons/NonModifying.svg.import deleted file mode 100644 index 04c0853..0000000 --- a/godot/addons/better-terrain/icons/NonModifying.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://1yr6yruwl63u" -path="res://.godot/imported/NonModifying.svg-4d16d471be4a8f1d3ba0c013ff629ee1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/NonModifying.svg" -dest_files=["res://.godot/imported/NonModifying.svg-4d16d471be4a8f1d3ba0c013ff629ee1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/Replace.svg b/godot/addons/better-terrain/icons/Replace.svg deleted file mode 100644 index bcb940b..0000000 --- a/godot/addons/better-terrain/icons/Replace.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/godot/addons/better-terrain/icons/Replace.svg.import b/godot/addons/better-terrain/icons/Replace.svg.import deleted file mode 100644 index aa40af7..0000000 --- a/godot/addons/better-terrain/icons/Replace.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://y3xy6qdckht6" -path="res://.godot/imported/Replace.svg-7654df79fd42fc27133e4d3f81a4d56b.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/Replace.svg" -dest_files=["res://.godot/imported/Replace.svg-7654df79fd42fc27133e4d3f81a4d56b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/ShuffleRandom.svg b/godot/addons/better-terrain/icons/ShuffleRandom.svg deleted file mode 100644 index a66ba86..0000000 --- a/godot/addons/better-terrain/icons/ShuffleRandom.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/godot/addons/better-terrain/icons/ShuffleRandom.svg.import b/godot/addons/better-terrain/icons/ShuffleRandom.svg.import deleted file mode 100644 index 8aa5e36..0000000 --- a/godot/addons/better-terrain/icons/ShuffleRandom.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cs4mdmluiydj6" -path="res://.godot/imported/ShuffleRandom.svg-15ee49f7a06c55a1e95e1ed056732dc5.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/ShuffleRandom.svg" -dest_files=["res://.godot/imported/ShuffleRandom.svg-15ee49f7a06c55a1e95e1ed056732dc5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryAll.svg b/godot/addons/better-terrain/icons/SymmetryAll.svg deleted file mode 100644 index 4aeca2d..0000000 --- a/godot/addons/better-terrain/icons/SymmetryAll.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryAll.svg.import b/godot/addons/better-terrain/icons/SymmetryAll.svg.import deleted file mode 100644 index aded76e..0000000 --- a/godot/addons/better-terrain/icons/SymmetryAll.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cyjra4g05dwh" -path="res://.godot/imported/SymmetryAll.svg-cd6a02766f60c09344aa97e0325457c1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryAll.svg" -dest_files=["res://.godot/imported/SymmetryAll.svg-cd6a02766f60c09344aa97e0325457c1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryFlip.svg b/godot/addons/better-terrain/icons/SymmetryFlip.svg deleted file mode 100644 index a180318..0000000 --- a/godot/addons/better-terrain/icons/SymmetryFlip.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/SymmetryFlip.svg.import b/godot/addons/better-terrain/icons/SymmetryFlip.svg.import deleted file mode 100644 index 8a954de..0000000 --- a/godot/addons/better-terrain/icons/SymmetryFlip.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqmc1jp56or8m" -path="res://.godot/imported/SymmetryFlip.svg-ea11c1010d0643843f115093c045dc42.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryFlip.svg" -dest_files=["res://.godot/imported/SymmetryFlip.svg-ea11c1010d0643843f115093c045dc42.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryMirror.svg b/godot/addons/better-terrain/icons/SymmetryMirror.svg deleted file mode 100644 index 463e09a..0000000 --- a/godot/addons/better-terrain/icons/SymmetryMirror.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/SymmetryMirror.svg.import b/godot/addons/better-terrain/icons/SymmetryMirror.svg.import deleted file mode 100644 index 83348f9..0000000 --- a/godot/addons/better-terrain/icons/SymmetryMirror.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://5hm3bfj3dvej" -path="res://.godot/imported/SymmetryMirror.svg-0bf9d259572cc33d41c783e35586310a.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryMirror.svg" -dest_files=["res://.godot/imported/SymmetryMirror.svg-0bf9d259572cc33d41c783e35586310a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryReflect.svg b/godot/addons/better-terrain/icons/SymmetryReflect.svg deleted file mode 100644 index c618809..0000000 --- a/godot/addons/better-terrain/icons/SymmetryReflect.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryReflect.svg.import b/godot/addons/better-terrain/icons/SymmetryReflect.svg.import deleted file mode 100644 index 8a0444e..0000000 --- a/godot/addons/better-terrain/icons/SymmetryReflect.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cxoewno1cefua" -path="res://.godot/imported/SymmetryReflect.svg-39f88a51808c88d6cb37005ed1ddd254.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryReflect.svg" -dest_files=["res://.godot/imported/SymmetryReflect.svg-39f88a51808c88d6cb37005ed1ddd254.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryRotate180.svg b/godot/addons/better-terrain/icons/SymmetryRotate180.svg deleted file mode 100644 index 44b65fd..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotate180.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryRotate180.svg.import b/godot/addons/better-terrain/icons/SymmetryRotate180.svg.import deleted file mode 100644 index d7e3503..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotate180.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://8mcycyl3e66r" -path="res://.godot/imported/SymmetryRotate180.svg-805113e1c31c7195ed5fec5febf455b9.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryRotate180.svg" -dest_files=["res://.godot/imported/SymmetryRotate180.svg-805113e1c31c7195ed5fec5febf455b9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryRotateAll.svg b/godot/addons/better-terrain/icons/SymmetryRotateAll.svg deleted file mode 100644 index 1fb8d0e..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateAll.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryRotateAll.svg.import b/godot/addons/better-terrain/icons/SymmetryRotateAll.svg.import deleted file mode 100644 index a244e9e..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateAll.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b7fx4mk18lmls" -path="res://.godot/imported/SymmetryRotateAll.svg-959ef9f7a9c5b12d37b3a1c9ddcf2432.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryRotateAll.svg" -dest_files=["res://.godot/imported/SymmetryRotateAll.svg-959ef9f7a9c5b12d37b3a1c9ddcf2432.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg b/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg deleted file mode 100644 index 1f4823a..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg.import b/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg.import deleted file mode 100644 index 5a53862..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateClockwise.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://baxhjy28r1iqj" -path="res://.godot/imported/SymmetryRotateClockwise.svg-9d1254877c31fcd2b5fd3dd58555e624.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryRotateClockwise.svg" -dest_files=["res://.godot/imported/SymmetryRotateClockwise.svg-9d1254877c31fcd2b5fd3dd58555e624.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg b/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg deleted file mode 100644 index 6ffb93a..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg.import b/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg.import deleted file mode 100644 index b9081b2..0000000 --- a/godot/addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://csbwdkr6bc2db" -path="res://.godot/imported/SymmetryRotateCounterClockwise.svg-ba4f86a741d97c0ebfc0ae19d3460f6f.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/SymmetryRotateCounterClockwise.svg" -dest_files=["res://.godot/imported/SymmetryRotateCounterClockwise.svg-ba4f86a741d97c0ebfc0ae19d3460f6f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/Warning.svg b/godot/addons/better-terrain/icons/Warning.svg deleted file mode 100644 index 199bf7f..0000000 --- a/godot/addons/better-terrain/icons/Warning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/better-terrain/icons/Warning.svg.import b/godot/addons/better-terrain/icons/Warning.svg.import deleted file mode 100644 index 928d015..0000000 --- a/godot/addons/better-terrain/icons/Warning.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b0es228gfcykd" -path="res://.godot/imported/Warning.svg-7bb0ec60ff2da2c7ebdba79b0dcdd006.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/Warning.svg" -dest_files=["res://.godot/imported/Warning.svg-7bb0ec60ff2da2c7ebdba79b0dcdd006.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg deleted file mode 100644 index 559ca91..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg.import deleted file mode 100644 index e3fe894..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://iid5buh1t5j5" -path="res://.godot/imported/SymmetryAll.svg-c2902d14b54ee9a54b7986a2ea5e47a7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryAll.svg" -dest_files=["res://.godot/imported/SymmetryAll.svg-c2902d14b54ee9a54b7986a2ea5e47a7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg deleted file mode 100644 index 0b60a3f..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg.import deleted file mode 100644 index cdc49df..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://brro1lqnf3r5y" -path="res://.godot/imported/SymmetryFlip.svg-0de1b384a4706cad746bcf7b3b7f0c2d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryFlip.svg" -dest_files=["res://.godot/imported/SymmetryFlip.svg-0de1b384a4706cad746bcf7b3b7f0c2d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg deleted file mode 100644 index e0a268f..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg.import deleted file mode 100644 index 01d3290..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dpf5p8xxn52cb" -path="res://.godot/imported/SymmetryMirror.svg-2ba85612b4c15f1a7eab344dc47f9a9a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryMirror.svg" -dest_files=["res://.godot/imported/SymmetryMirror.svg-2ba85612b4c15f1a7eab344dc47f9a9a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg deleted file mode 100644 index 5acc95a..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg.import deleted file mode 100644 index 352a731..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d251v4pxpwsre" -path="res://.godot/imported/SymmetryReflect.svg-de65ca99c884ea9239bb60e11b7c0ca4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryReflect.svg" -dest_files=["res://.godot/imported/SymmetryReflect.svg-de65ca99c884ea9239bb60e11b7c0ca4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg deleted file mode 100644 index 677a62b..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg.import deleted file mode 100644 index 4fe09b4..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c1bmbyb3ig0mx" -path="res://.godot/imported/SymmetryRotate180.svg-ff244f85658bd621d56af3cf4f7c7ebe.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryRotate180.svg" -dest_files=["res://.godot/imported/SymmetryRotate180.svg-ff244f85658bd621d56af3cf4f7c7ebe.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg deleted file mode 100644 index fc81aae..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg.import deleted file mode 100644 index 559613a..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bcky1dfn4umac" -path="res://.godot/imported/SymmetryRotateAll.svg-795a9b37a8f5df7e7376c9f762121b21.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateAll.svg" -dest_files=["res://.godot/imported/SymmetryRotateAll.svg-795a9b37a8f5df7e7376c9f762121b21.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg deleted file mode 100644 index 400e11a..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg.import deleted file mode 100644 index 492d59f..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://def0fcqsn6s6x" -path="res://.godot/imported/SymmetryRotateClockwise.svg-e133d151dd3970411596d18bb133aece.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateClockwise.svg" -dest_files=["res://.godot/imported/SymmetryRotateClockwise.svg-e133d151dd3970411596d18bb133aece.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg deleted file mode 100644 index 39b5242..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg.import b/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg.import deleted file mode 100644 index 1db7d1b..0000000 --- a/godot/addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ngej4qhkypb2" -path="res://.godot/imported/SymmetryRotateCounterClockwise.svg-b603f534dc5383de58f7e26cdf86fe8b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/better-terrain/icons/paint-symmetry/SymmetryRotateCounterClockwise.svg" -dest_files=["res://.godot/imported/SymmetryRotateCounterClockwise.svg-b603f534dc5383de58f7e26cdf86fe8b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/better-terrain/plugin.cfg b/godot/addons/better-terrain/plugin.cfg deleted file mode 100644 index 1bfb36b..0000000 --- a/godot/addons/better-terrain/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="BetterTerrain" -description="This is a drop-in replacement for Godot 4's tilemap terrain system, offering more versatile and straightforward autotiling. It can be used with any existing TileMap or TileSet, either through the editor plugin, or directly via code." -author="Portponky" -version="" -script="TerrainPlugin.gd" diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd deleted file mode 100644 index 50b3db0..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd +++ /dev/null @@ -1,28 +0,0 @@ -@tool -class_name BasicHitBox2D extends HitBox2D -## [BasicHitBox2D] is associated with an object that can collide with a [HurtBox2D]. - - -## The [Health.Affect] to be performed. -@export var affect: Health.Affect = Health.Affect.DAMAGE: - set(a): - affect = a - if actions.size() > 0: - actions[0].affect = a - actions[0].type = _type_from_affect(a) - -## The amount of the action. -@export var amount: int = 1: - set(a): - amount = a - if actions.size() > 0: - actions[0].amount = amount - - -func _ready() -> void: - super() - actions.append(HealthAction.new(affect, _type_from_affect(affect), amount)) - - -func _type_from_affect(affect: Health.Affect) -> HealthActionType.Enum: - return HealthActionType.Enum.KINETIC if affect == Health.Affect.DAMAGE else HealthActionType.Enum.MEDICINE diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd.uid deleted file mode 100644 index 89e4241..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/basic_hit_box_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chrsg1fc53qs3 diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd deleted file mode 100644 index 5d9d956..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd +++ /dev/null @@ -1,59 +0,0 @@ -@tool -class_name HitBox2D extends Area2D -## [HitBox2D] is associated with an object that can collide with a [HurtBox2D]. - -## emitted when collision with [HitBox2D] detected. -signal hit_box_entered(hit_box: HitBox2D) -## emitted when collision with [HurtBox2D] detected. -signal hurt_box_entered(hurt_box: HurtBox2D) -## emitted after the action is applied to a [HurtBox2D]. -signal action_applied(hurt_box: HurtBox2D) -## emitted when collision with [Area2D] that isn't [HitBox2D] or [HurtBox2D]. -## Can be using to detect things like environment. -signal unknown_area_entered(area: Area2D) - - -## Ignore collisions when [color=orange]true[/color].[br] -## Set this to [color=orange]true[/color] after a collision is detected to avoid -## further collisions.[br] -## It is recommended to set this to [color=orange]true[/color] before calling -## [color=orange]queue_free()[/color] to avoid further collisions. -@export var ignore_collisions: bool - -## [Modifer] applied to [HealthActionType.Enum]. -@export var actions: Array[HealthAction] = [] - - -func _ready() -> void: - area_entered.connect(_on_area_entered) - - -## Detect collisions with [HitBox2D] or [HurtBox2D] and apply appropriate action. -func _on_area_entered(area: Area2D) -> void: - if ignore_collisions: - return - - if area is HitBox2D: - hit_box_entered.emit(area) - return - - if area is not HurtBox2D: - unknown_area_entered.emit(area) - return - - var hurt_box: HurtBox2D = area - hurt_box_entered.emit(hurt_box) - var cloned_actions := _clone_actions() - hurt_box.apply_all_actions(cloned_actions) - action_applied.emit(hurt_box) - - -func _clone_actions() -> Array[HealthAction]: - var dup: Array[HealthAction] - dup.assign( - actions.map( - func(action: HealthAction) -> HealthAction: return action.clone() - ) - ) - - return dup diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd.uid deleted file mode 100644 index e22841a..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b1vnxk5bfh6el diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg deleted file mode 100644 index 0ce4575..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg.import b/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg.import deleted file mode 100644 index c3cb4fa..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cpwchp5bmp6sa" -path="res://.godot/imported/hit_box_2d.svg-04c42ff1d0690e4b40b58e7908e7eb80.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg" -dest_files=["res://.godot/imported/hit_box_2d.svg-04c42ff1d0690e4b40b58e7908e7eb80.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd deleted file mode 100644 index c90f797..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd +++ /dev/null @@ -1,27 +0,0 @@ -@tool -class_name BasicHitScan2D extends HitScan2D -## BasicHitScan2D interacts with [HurtBox2D] to affect [Health] components. - - -## The [Health.Affect] to be performed. -@export var affect: Health.Affect = Health.Affect.DAMAGE: - set(a): - affect = a - if actions.size() > 0: - actions[0].affect = a - actions[0].type = _type_from_affect(a) - -## The amount of the action. -@export var amount: int = 1: - set(a): - amount = a - if actions.size() > 0: - actions[0].amount = amount - - -func _ready() -> void: - actions.append(HealthAction.new(affect, _type_from_affect(affect), amount)) - - -func _type_from_affect(affect: Health.Affect) -> HealthActionType.Enum: - return HealthActionType.Enum.KINETIC if affect == Health.Affect.DAMAGE else HealthActionType.Enum.MEDICINE diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd.uid deleted file mode 100644 index c14463d..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/basic_hit_scan_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4prlhibnn6cj diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd deleted file mode 100644 index 1f98f1a..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool -class_name HitScan2D extends RayCast2D -## [HitScan2D] interacts with [HurtBox2D] to affect [Health] components. - -## emitted when collision with [HitBox2D] detected. -signal hit_box_entered(hit_box: HitBox2D) -## emitted when collision with [HurtBox2D] detected. -signal hurt_box_entered(hurt_box: HurtBox2D) -## emitted after the action is applied to a [HurtBox2D]. -signal action_applied(hurt_box: HurtBox2D) -## emitted when collision with [Area2D] that isn't [HitBox2D] or [HurtBox2D]. -## Used to detect things like environment. -signal unknown_area_entered(area: Area2D) - - -## [Modifer] applied to [HealthActionType.Enum]. -@export var actions: Array[HealthAction] = [] - -# Here for testing, can't mock native node functions -var _collider: Node - - -func _enter_tree() -> void: - # override default in editor - if Engine.is_editor_hint(): - collide_with_areas = true - - -func _set(property: StringName, value: Variant) -> bool: - # allow setting anything in game - if not Engine.is_editor_hint(): - return false - - match property: - # force collide_with_area in editor - "collide_with_areas": - collide_with_areas = true - _: - return false - - return true - - -## Detect collisions with [HurtBox2D] and apply appropriate action. -func fire() -> void: - var collider = _collider if _collider else get_collider() - if not collider: - return - - if collider is HitBox2D: - var hit_box: HitBox2D = collider - if hit_box.ignore_collisions: - return - - hit_box_entered.emit(collider) - return - - if collider is not HurtBox2D: - unknown_area_entered.emit(collider) - return - - var hurt_box: HurtBox2D = collider - hurt_box_entered.emit(hurt_box) - hurt_box.apply_all_actions(actions) - action_applied.emit(hurt_box) diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd.uid deleted file mode 100644 index c4c9b7d..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://brdxl7cvlitd6 diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg deleted file mode 100644 index dcaebf3..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg.import b/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg.import deleted file mode 100644 index f8ebb2a..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://53discmcr7gn" -path="res://.godot/imported/hit_scan_2d.svg-76735babe2b0e36ac7e614925b1aeaa5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg" -dest_files=["res://.godot/imported/hit_scan_2d.svg-76735babe2b0e36ac7e614925b1aeaa5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd deleted file mode 100644 index 3522980..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -class_name BasicHurtBox2D extends HurtBox2D -## [BasicHurtBox2D] enables collision detection by [HitBox2D] or [HitScan2D] and applies affects to [Health]. - -## The multiplier to apply to all damage actions. -@export var damage_multiplier: float = 1.0: - set(mult): - damage_multiplier = mult - if modifiers.has(HealthActionType.Enum.KINETIC): - modifiers[HealthActionType.Enum.KINETIC].multiplier = mult - -## The multiplier to apply to all heal actions. -@export var heal_multiplier: float = 1.0: - set(mult): - heal_multiplier = mult - if modifiers.has(HealthActionType.Enum.MEDICINE): - modifiers[HealthActionType.Enum.MEDICINE].multiplier = mult - -@export_group("Advanced") - -## Applies healing to [Health] when [color=orange]damage()[/color] is called. -@export var heal_on_damage: bool = false: - set(enable): - heal_on_damage = enable - if modifiers.has(HealthActionType.Enum.KINETIC): - modifiers[HealthActionType.Enum.KINETIC].convert_affect = _affect_heal_on_damage(enable) - - -## Applies damage to [Health] when [color=orange]heal()[/color] is called. -@export var damage_on_heal: bool = false: - set(enable): - damage_on_heal = enable - if modifiers.has(HealthActionType.Enum.MEDICINE): - modifiers[HealthActionType.Enum.MEDICINE].convert_affect = _affect_damage_on_heal(enable) - - - -func _ready() -> void: - modifiers[HealthActionType.Enum.KINETIC] = HealthModifier.new(0, damage_multiplier, _affect_heal_on_damage(heal_on_damage)) - modifiers[HealthActionType.Enum.MEDICINE] = HealthModifier.new(0, heal_multiplier, _affect_damage_on_heal(damage_on_heal)) - - -func _affect_heal_on_damage(enabled: bool) -> Health.Affect: - return Health.Affect.HEAL if enabled else Health.Affect.NONE - - -func _affect_damage_on_heal(enabled: bool) -> Health.Affect: - return Health.Affect.DAMAGE if enabled else Health.Affect.NONE diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd.uid deleted file mode 100644 index c92ae6f..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/basic_hurt_box_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtfoilkdcfvgv diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd deleted file mode 100644 index e61f550..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd +++ /dev/null @@ -1,45 +0,0 @@ -@tool -class_name HurtBox2D extends Area2D -## [HurtBox2D] enables collision detection by [HitBox2D] or [HitScan2D] and applies affects to [Health]. - - -## The [Health] component to affect. -@export var health: Health = null: - set(new_health): - health = new_health - if Engine.is_editor_hint(): - update_configuration_warnings() - - -## [Modifer] applied to [HealthActionType.Enum]. -@export var modifiers: Dictionary[HealthActionType.Enum, HealthModifier] = {} - - -func apply_all_actions(actions: Array[HealthAction]) -> void: - if not health: - push_error("%s is missing a 'Health' component" % self) - return - - var modified_actions: Array[HealthModifiedAction] - modified_actions.assign( - actions.filter(func(action: HealthAction) -> bool: return action != null) - .map(_map_modified_action) - ) - - health.apply_all_modified_actions(modified_actions) - - -func _map_modified_action(action: HealthAction) -> HealthModifiedAction: - var modifier := modifiers.get(action.type, HealthModifier.new()) - var modified_action := HealthModifiedAction.new(action, modifier.clone()) - return modified_action - - -# Warn users if values haven't been configured. -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - if health is not Health: - warnings.append("This node requires a 'Health' component") - - return warnings diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd.uid b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd.uid deleted file mode 100644 index c28cf69..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ctuf38y050aep diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg deleted file mode 100644 index 283848a..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg.import b/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg.import deleted file mode 100644 index a4b909f..0000000 --- a/godot/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://v78abft1b1ba" -path="res://.godot/imported/hurt_box_2d.svg-635cc32a4a08d276e81d7b9735ef33ab.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg" -dest_files=["res://.godot/imported/hurt_box_2d.svg-635cc32a4a08d276e81d7b9735ef33ab.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd deleted file mode 100644 index dc2dd0d..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd +++ /dev/null @@ -1,26 +0,0 @@ -class_name BasicHitBox3D extends HitBox3D -## [BasicHitBox3D] is associated with an object that can collide with a [HurtBox3D]. - -## The [Health.Affect] to be performed. -@export var affect: Health.Affect = Health.Affect.DAMAGE: - set(a): - affect = a - if actions.size() > 0: - actions[0].affect = a - actions[0].type = _type_from_affect(a) - -## The amount of the action. -@export var amount: int = 1: - set(a): - amount = a - if actions.size() > 0: - actions[0].amount = amount - - -func _ready() -> void: - super() - actions.append(HealthAction.new(affect, _type_from_affect(affect), amount)) - - -func _type_from_affect(affect: Health.Affect) -> HealthActionType.Enum: - return HealthActionType.Enum.KINETIC if affect == Health.Affect.DAMAGE else HealthActionType.Enum.MEDICINE diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd.uid deleted file mode 100644 index 22761cb..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/basic_hit_box_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dl46g2gg100af diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd deleted file mode 100644 index 1e891e1..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd +++ /dev/null @@ -1,59 +0,0 @@ -@tool -class_name HitBox3D extends Area3D -## [HitBox3D] is associated with an object that can collide with a [HurtBox3D]. - -## emitted when collision with [HitBox3D] detected. -signal hit_box_entered(hit_box: HitBox3D) -## emitted when collision with [HurtBox3D] detected. -signal hurt_box_entered(hurt_box: HurtBox3D) -## emitted after the action is applied to a [HurtBox3D]. -signal action_applied(hurt_box: HurtBox3D) -## emitted when collision with [Area3D] that isn't [HitBox3D] or [HurtBox3D]. -## Can be using to detect things like environment. -signal unknown_area_entered(area: Area3D) - - -## Ignore collisions when [color=orange]true[/color].[br] -## Set this to [color=orange]true[/color] after a collision is detected to avoid -## further collisions.[br] -## It is recommended to set this to [color=orange]true[/color] before calling -## [color=orange]queue_free()[/color] to avoid further collisions. -@export var ignore_collisions: bool - -## [Modifer] applied to [HealthActionType.Enum]. -@export var actions: Array[HealthAction] = [] - - -func _ready() -> void: - area_entered.connect(_on_area_entered) - - -## Detect collisions with [HitBox3D] or [HurtBox3D] and apply appropriate action. -func _on_area_entered(area: Area3D) -> void: - if ignore_collisions: - return - - if area is HitBox3D: - hit_box_entered.emit(area) - return - - if area is not HurtBox3D: - unknown_area_entered.emit(area) - return - - var hurt_box: HurtBox3D = area - hurt_box_entered.emit(hurt_box) - var cloned_actions := _clone_actions() - hurt_box.apply_all_actions(cloned_actions) - action_applied.emit(hurt_box) - - -func _clone_actions() -> Array[HealthAction]: - var dup: Array[HealthAction] - dup.assign( - actions.map( - func(action: HealthAction) -> HealthAction: return action.clone() - ) - ) - - return dup diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd.uid deleted file mode 100644 index 92d9b56..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cpfdw8qktypdy diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg deleted file mode 100644 index 3d2e664..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg.import b/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg.import deleted file mode 100644 index 5f471b6..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b5lt2v55qk41m" -path="res://.godot/imported/hit_box_3d.svg-47caa32a8495f1c1c3eb8e87db083a81.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg" -dest_files=["res://.godot/imported/hit_box_3d.svg-47caa32a8495f1c1c3eb8e87db083a81.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd deleted file mode 100644 index 848e718..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd +++ /dev/null @@ -1,27 +0,0 @@ -@tool -class_name BasicHitScan3D extends HitScan3D -## BasicHitScan3D interacts with [HurtBox3D] to affect [Health] components. - - -## The [Health.Affect] to be performed. -@export var affect: Health.Affect = Health.Affect.DAMAGE: - set(a): - affect = a - if actions.size() > 0: - actions[0].affect = a - actions[0].type = _type_from_affect(a) - -## The amount of the action. -@export var amount: int = 1: - set(a): - amount = a - if actions.size() > 0: - actions[0].amount = amount - - -func _ready() -> void: - actions.append(HealthAction.new(affect, _type_from_affect(affect), amount)) - - -func _type_from_affect(affect: Health.Affect) -> HealthActionType.Enum: - return HealthActionType.Enum.KINETIC if affect == Health.Affect.DAMAGE else HealthActionType.Enum.MEDICINE diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd.uid deleted file mode 100644 index 7e73d57..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/basic_hit_scan_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cqqsjswdqi60 diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd deleted file mode 100644 index 20baef2..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool -class_name HitScan3D extends RayCast3D -## [HitScan3D] interacts with [HurtBox3D] to affect [Health] components. - -## emitted when collision with [HitBox3D] detected. -signal hit_box_entered(hit_box: HitBox3D) -## emitted when collision with [HurtBox3D] detected. -signal hurt_box_entered(hurt_box: HurtBox3D) -## emitted after the action is applied to a [HurtBox3D]. -signal action_applied(hurt_box: HurtBox3D) -## emitted when collision with [Area3D] that isn't [HitBox3D] or [HurtBox3D]. -## Used to detect things like environment. -signal unknown_area_entered(area: Area3D) - - -## [Modifer] applied to [HealthActionType.Enum]. -@export var actions: Array[HealthAction] = [] - -# Here for testing, can't mock native node functions -var _collider: Node - - -func _enter_tree() -> void: - # override default in editor - if Engine.is_editor_hint(): - collide_with_areas = true - - -func _set(property: StringName, value: Variant) -> bool: - # allow setting anything in game - if not Engine.is_editor_hint(): - return false - - match property: - # force collide_with_area in editor - "collide_with_areas": - collide_with_areas = true - _: - return false - - return true - - -## Detect collisions with [HurtBox3D] and apply appropriate action. -func fire() -> void: - var collider = _collider if _collider else get_collider() - if not collider: - return - - if collider is HitBox3D: - var hit_box: HitBox3D = collider - if hit_box.ignore_collisions: - return - - hit_box_entered.emit(collider) - return - - if collider is not HurtBox3D: - unknown_area_entered.emit(collider) - return - - var hurt_box: HurtBox3D = collider - hurt_box_entered.emit(hurt_box) - hurt_box.apply_all_actions(actions) - action_applied.emit(hurt_box) diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd.uid deleted file mode 100644 index c24b191..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b2t4n1l4cd5nv diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg deleted file mode 100644 index a97b6b5..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg.import b/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg.import deleted file mode 100644 index 2bdf627..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://rbwlv0smmn85" -path="res://.godot/imported/hit_scan_3d.svg-02bcbfb1fae1be4286e63dea514540bb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg" -dest_files=["res://.godot/imported/hit_scan_3d.svg-02bcbfb1fae1be4286e63dea514540bb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd deleted file mode 100644 index bce921e..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool -class_name BasicHurtBox3D extends HurtBox3D -## [BasicHurtBox3D] enables collision detection by [HitBox3D] or [HitScan3D] and applies affects to [Health]. - -## The multiplier to apply to all damage actions. -@export var damage_multiplier: float = 1.0: - set(mult): - damage_multiplier = mult - if modifiers.has(HealthActionType.Enum.KINETIC): - modifiers[HealthActionType.Enum.KINETIC].multiplier = mult - -## The multiplier to apply to all heal actions. -@export var heal_multiplier: float = 1.0: - set(mult): - heal_multiplier = mult - if modifiers.has(HealthActionType.Enum.MEDICINE): - modifiers[HealthActionType.Enum.MEDICINE].multiplier = mult - -@export_group("Advanced") - -## Applies healing to [Health] when [color=orange]damage()[/color] is called. -@export var heal_on_damage: bool = false: - set(enable): - heal_on_damage = enable - if modifiers.has(HealthActionType.Enum.KINETIC): - modifiers[HealthActionType.Enum.KINETIC].convert_affect = _affect_heal_on_damage(enable) - - -## Applies damage to [Health] when [color=orange]heal()[/color] is called. -@export var damage_on_heal: bool = false: - set(enable): - damage_on_heal = enable - if modifiers.has(HealthActionType.Enum.MEDICINE): - modifiers[HealthActionType.Enum.MEDICINE].convert_affect = _affect_damage_on_heal(enable) - - - -func _ready() -> void: - modifiers[HealthActionType.Enum.KINETIC] = HealthModifier.new(0, damage_multiplier, _affect_heal_on_damage(heal_on_damage)) - modifiers[HealthActionType.Enum.MEDICINE] = HealthModifier.new(0, heal_multiplier, _affect_damage_on_heal(damage_on_heal)) - - -func _affect_heal_on_damage(enabled: bool) -> Health.Affect: - return Health.Affect.HEAL if enabled else Health.Affect.NONE - - -func _affect_damage_on_heal(enabled: bool) -> Health.Affect: - return Health.Affect.DAMAGE if enabled else Health.Affect.NONE diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd.uid deleted file mode 100644 index 0713467..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/basic_hurt_box_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dyxvt8yarxaff diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd deleted file mode 100644 index ceb6d8c..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd +++ /dev/null @@ -1,45 +0,0 @@ -@tool -class_name HurtBox3D extends Area3D -## [HurtBox3D] enables collision detection by [HitBox3D] or [HitScan3D] and applies affects to [Health]. - - -## The [Health] component to affect. -@export var health: Health = null: - set(new_health): - health = new_health - if Engine.is_editor_hint(): - update_configuration_warnings() - - -## [Modifer] applied to [HealthActionType.Enum]. -@export var modifiers: Dictionary[HealthActionType.Enum, HealthModifier] = {} - - -func apply_all_actions(actions: Array[HealthAction]) -> void: - if not health: - push_error("%s is missing a 'Health' component" % self) - return - - var modified_actions: Array[HealthModifiedAction] - modified_actions.assign( - actions.filter(func(action: HealthAction) -> bool: return action != null) - .map(_map_modified_action) - ) - - health.apply_all_modified_actions(modified_actions) - - -func _map_modified_action(action: HealthAction) -> HealthModifiedAction: - var modifier := modifiers.get(action.type, HealthModifier.new()) - var modified_action := HealthModifiedAction.new(action, modifier.clone()) - return modified_action - - -# Warn users if values haven't been configured. -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - if health is not Health: - warnings.append("This node requires a 'Health' component") - - return warnings diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd.uid b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd.uid deleted file mode 100644 index 04225d3..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://df8tt6exgnci5 diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg deleted file mode 100644 index 756ab1e..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg.import b/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg.import deleted file mode 100644 index 1bb61db..0000000 --- a/godot/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cyruf70duruso" -path="res://.godot/imported/hurt_box_3d.svg-1a2f57403b3043a3debd4eaa657e18b5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg" -dest_files=["res://.godot/imported/hurt_box_3d.svg-1a2f57403b3043a3debd4eaa657e18b5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/health_hitbox_hurtbox/LICENSE b/godot/addons/health_hitbox_hurtbox/LICENSE deleted file mode 100644 index c89dfce..0000000 --- a/godot/addons/health_hitbox_hurtbox/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 David Clutter - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/godot/addons/health_hitbox_hurtbox/README.md b/godot/addons/health_hitbox_hurtbox/README.md deleted file mode 100644 index 77adffc..0000000 --- a/godot/addons/health_hitbox_hurtbox/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Godot Health, HitBoxes, HurtBoxes, and HitScans - -[![Godot](https://img.shields.io/badge/Godot-4.4%2b-blue?logo=godot-engine)](https://godotengine.org/download) -[![LICENSE](https://img.shields.io/badge/license-MIT-blue)](https://github.com/cluttered-code/godot-health-components/blob/main/addons/health_components/LICENSE) -[![Current Release](https://img.shields.io/github/release/cluttered-code/godot-health-hitbox-hurtbox.svg "Current Release")](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/releases/latest) -[![actions](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/actions/workflows/ci.yml/badge.svg)](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/actions/workflows/ci.yml) -[![Downloads](https://img.shields.io/github/downloads/cluttered-code/godot-health-hitbox-hurtbox/total.svg "Downloads")](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/releases) - -[![Live Example](https://img.shields.io/badge/Live_Example-itch.io-fa5c5c)](https://cluttered-code.itch.io/godot-health-hitbox-hurtbox-hitscan) -[![ko-fi](https://img.shields.io/badge/Support%20on-ko--fi-ff5e5b?logo=ko-fi)](https://ko-fi.com/clutteredcode) - -> [!CAUTION] -> A lot changed in v5.0.0. It is recommended to update to v4.4.0 before going to v5.0.0 to avoid issues with component name changes. We're working hard to update the documentation. -> The components in the documentation are all now prefixed with "Basic". We added more complex variants to allow for multiple damage types and modifiers. -> Thank for the support! - -## Documentation - -Check out the [Wiki](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/wiki) for Documentation and tutorials! - -## Process and Data Flow -```mermaid -flowchart LR - HitBox - HitScan - HurtBox - Health - - HitBox -- detect collision and send **amount** --> HurtBox - HitScan -- detect collision and send **amount** --> HurtBox - HurtBox -- send **amount** and **multiplier** --> Health -``` - -## ![Health](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/health/health.svg) Health - -`Health` component tracks an entity's health and emits signals for various health realted changes. - -![Health inspector](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/images/health_inspector.png "Health Inspector") - -## ![HurtBox2D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg) Hurtbox ![HurtBox3D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg) - -`HurtBox2D` and `HurtBox3D` components require a `Collision Shape` so it can be detected and is assigned a ![Health](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/health/health.svg) `Health` component to apply damage and healing when hit. - -![HurtBox2D Inspector](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/images/basic_hurt_box_2d_inspector.png "HurtBox2D Inspector") - -## ![HitBox2D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/2d/hit_box_2d/hit_box_2d.svg) Hitbox ![HitBox3D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/3d/hit_box_3d/hit_box_3d.svg) - - `HitBox2D` and `HitBox3D` components require a `Collision Shape` to detect collisions with a ![HurtBox2D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg) `HurtBox2D` or ![HurtBox3D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg) `HurtBox3D` to apply `DAMAGE` or `HEAL`. - -![HitBox2D Inspector](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/images/basic_hit_box_2d_inspector.png "HitBox2D Inspector") - -## ![HitScan2D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/2d/hit_scan_2d/hit_scan_2d.svg) HitScan ![HitScan3D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/3d/hit_scan_3d/hit_scan_3d.svg) - -`HitScan2D` and `HitScan3D` components extend `RayCast2D` and `RayCast3D` to detect collisions with a ![Hurtbox2D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/2d/hurt_box_2d/hurt_box_2d.svg) `HurtBox2D` or ![Hurtbox3D](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/addons/health_hitbox_hurtbox/3d/hurt_box_3d/hurt_box_3d.svg) `HurtBox3D` to apply `DAMAGE` or `HEAL`. - -![HitScan2D Inspector](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/images/basic_hit_scan_2d_inspector.png "HitScan2D Inspector") - -## Live Example Demonstration - -[itch.io - godot-health-hitbox-hurtbox-hitscan](https://cluttered-code.itch.io/godot-health-hitbox-hurtbox-hitscan) - -## Installation - -### Asset Library Installation - -1. Open the `AssetLib` tab in the Godot Editor. -2. Search for `Health`, `HitBox`, or `HurtBox` in the search bar. -3. Click the download button next to the Health, HitBoxes, and HurtBoxes plugin. -4. Once the installation is complete, go to `Project` -> `Project Settings` -> `Plugins`. -5. Find the `Health, HitBoxes, and HurtBoxes` plugin in the list and check the box to enable it. - -## Usage - -![Player Structure](https://raw.githubusercontent.com/cluttered-code/godot-health-hitbox-hurtbox/refs/heads/main/images/character_structure.png "CharacterBody2D Structure") - -1. Add a `Health` node to a Node that needs health (ie. `CharacterBody2D` or `StaticBody3D`) -2. Add a `HurtBox2D` node with a `CollisionShape2D` to the same Node. -3. Set the `HurtBox2D` collision layer. -4. `HitBox2D` or `HitScan2D` - - Create a projectile or melee weapon with a `HitBox2D` and set the collision mask to the same layer as the `HurtBox2D` collision layer. This will automatically apply damage and healing. - - Create a gun with a `HitScan2D` extending from the barrel and set the collision mask to the same layer as the `HurtBox2D` collision layer. `fire()` needs to be called on the `HitScan2D` to apply damage and healing. - -## Issues - -Submit issues to the [Github Issues Page](https://github.com/cluttered-code/godot-health-hitbox-hurtbox/issues) diff --git a/godot/addons/health_hitbox_hurtbox/health/health.gd b/godot/addons/health_hitbox_hurtbox/health/health.gd deleted file mode 100644 index d79e96f..0000000 --- a/godot/addons/health_hitbox_hurtbox/health/health.gd +++ /dev/null @@ -1,250 +0,0 @@ -class_name Health extends Node -## Health is used to track an entity's health, death, and revival. - - -## Affect an action will have on [Health]. -enum Affect { NONE, DAMAGE, HEAL } - -## Emitted after damage is applied. -signal damaged(entity: Node, type: HealthActionType.Enum, amount: int, incrementer: int, multiplier: float, applied: int) -## Emitted after damage is applied when death has occured. -signal died(entity: Node) - -## Emitted after healing is applied. -signal healed(entity: Node, type: HealthActionType.Enum, amount: int, incrementer: int, multiplier: float, applied: int) -## Emitted after healing is applied when dead. -signal revived(entity: Node) - -## Emitted after damage or healing is applied. -signal action_applied(action: HealthModifiedAction, applied: int) - - -## Emitted when damaged and entity had full health. -signal first_hit(entity: Node) -## Emitted when trying to damage an entity that is not damageable. -signal not_damageable(entity: Node) -## Emitted when damaging and current health is already zero. -signal already_dead(entity: Node) -## Emitted when trying to apply enough damage to an enemy to kill them and they cannot be. -signal not_killable(entity: Node) - - -## Emitted when trying to heal and entity is not healable. -signal not_healable(entity: Node) -## Emitted when enity is healed and health is now full. -signal full(entity: Node) -## Emitted when healing and current health is already full. -signal already_full(entity: Node) -## Emitted when trying to heal a dead entity that is not revivable -signal not_revivable(entity: Node) - -const DEFAULT_MAX = 100 - -## The current amount of health.[br] -## Value is clamped [0, max]. -@export var current: int = DEFAULT_MAX: - set(curr): - current = clampi(curr, 0, max) - -## The maximum amount of health.[br] -## Will not allow values < 1. -## Will reduce current if greater than updated max.[br] -@export var max: int = DEFAULT_MAX: - set(new_max): - var old_max = max - max = maxi(new_max, 1) - # after max is set or current will clamp wrong - if Engine.is_editor_hint() and current == old_max: - # keep full health in editor if it was before - current = max - else: - # reduce current in game so it is not greater than max - current = mini(current, max) - -@export_group("Conditions") -## Enable if entity is capable of taking damage. -@export var damageable: bool = true -## Enable if entity is capable of being healed. -@export var healable: bool = true -## Enable if entity is able to be killed. -@export var killable: bool = true -## Enable if entity is able to be revived from death. -@export var revivable: bool = true - - -@export_group("Advanced") -## The entity this component is tracking health for, -## sent in signals for association.[br][br] -## Defaults to [color=orange]owner[/color]. -@export var entity: Node: - get(): - return entity if entity else owner - -## Additional [Modifer] applied to [HealthActionType.Enum]. -@export var modifiers: Dictionary[HealthActionType.Enum, HealthModifier] = {} - - -## Returns [color=orange]true[/color] when not alive. -func is_dead() -> bool: - return current == 0 and killable - - -## Returns [color=orange]true[/color] when current health is greater than 0. -func is_alive() -> bool: - return not is_dead() - - -## Return [color=orange]true[/color] when current health is max. -func is_full() -> bool: - return current == max - - -## Returns the percent of current to maximum health. -func percent() -> float: - return clampf(float(current) / float(max), 0.0, 1.0) - - -## Apply enough damage to kill. Ignores modifiers. -func kill(type: HealthActionType.Enum = HealthActionType.Enum.NONE) -> void: - var mod_ac := HealthModifiedAction.new(HealthAction.new(Affect.DAMAGE, type, current), HealthModifier.new()) - _damage(mod_ac) - - -## Apply enough healing to fill. Ignores modifiers. -func fill(type: HealthActionType.Enum = HealthActionType.Enum.NONE) -> void: - var mod_ac := HealthModifiedAction.new(HealthAction.new(Affect.HEAL, type, max - current), HealthModifier.new()) - _heal(mod_ac) - - -## Apply all the [HealthAction] objects in the arary. -func apply_all_actions(actions: Array[HealthAction]) -> void: - for action in actions: - apply_action(action) - - -## Apply the specified [HealthAction]. -func apply_action(action: HealthAction) -> void: - var modified_action := HealthModifiedAction.new(action, HealthModifier.new()) - apply_modified_action(modified_action) - - -## Apply all the [HealthModifiedAction] objects in the arary. -func apply_all_modified_actions(actions: Array[HealthModifiedAction]) -> void: - for action in actions: - apply_modified_action(action) - - -## Apply the specified [HealthModifiedAction]. -func apply_modified_action(action: HealthModifiedAction) -> void: - if not action: - return - - var modifier := _get_modifier(action.type) - - var affect: Affect = modifier.convert_affect if modifier.convert_affect else action.affect - var type: HealthActionType.Enum = modifier.convert_type if modifier.convert_type else action.type - - var ac := HealthAction.new(affect, type, action.amount) - var mod := HealthModifier.new(action.incrementer + modifier.incrementer, action.multiplier * modifier.multiplier) - var mod_ac := HealthModifiedAction.new(ac, mod) - - match affect: - Affect.DAMAGE: - _damage(mod_ac) - Affect.HEAL: - _heal(mod_ac) - _: - print_debug("%s affect unimplemented" % Health.Affect.find_key(affect)) - - -## Apply the specified amount of damage if damageable and not dead. -func damage(amount: int, incrementer: int = 0, multiplier: float = 1.0, type: HealthActionType.Enum = HealthActionType.Enum.NONE) -> void: - var action := HealthAction.new(Affect.DAMAGE, type, amount) - var modifier := HealthModifier.new(incrementer, multiplier) - var modified_action := HealthModifiedAction.new(action, modifier) - apply_modified_action(modified_action) - - -## apply the specified amount of healing if healable, not full, or dead and revivable. -func heal(amount: int, incrementer: int = 0, multiplier: float = 1.0, type: HealthActionType.Enum = HealthActionType.Enum.NONE) -> void: - var action := HealthAction.new(Affect.HEAL, type, amount) - var modifier := HealthModifier.new(incrementer, multiplier) - var modified_action := HealthModifiedAction.new(action, modifier) - apply_modified_action(modified_action) - - -## Apply the specified amount of damage if damageable and not dead. -func _damage(mod_ac: HealthModifiedAction) -> void: - if not damageable: - print_debug("%s cannot be damaged" % entity) - not_damageable.emit(entity) - return - - if is_dead(): - print_debug("%s is already dead" % entity) - already_dead.emit(entity) - return - - var applied := clampi(roundi((mod_ac.amount + mod_ac.incrementer) * mod_ac.multiplier), 0, current) - if applied == current and not killable: - print_debug("%s is not killable" % entity) - not_killable.emit(entity) - return - - var is_first_hit := is_full() and applied > 0 - current -= applied - print_debug( - "%s affect=%s type=%s amount=%d incrementer=%d multiplier=%0.4f applied=%d current=%d" - % [entity, Affect.find_key(mod_ac.affect), HealthActionType.Enum.find_key(mod_ac.type), mod_ac.amount, mod_ac.incrementer, mod_ac.multiplier, applied, current] - ) - damaged.emit(entity, mod_ac.type, mod_ac.amount, mod_ac.incrementer, mod_ac.multiplier, applied) - action_applied.emit(mod_ac, applied) - - if is_first_hit: - print_debug("%s first hit" % entity) - first_hit.emit(entity) - - if is_dead(): - print_debug("%s died" % entity) - died.emit(entity) - - -## apply the specified amount of healing if healable, not full, or dead and revivable. -func _heal(mod_ac: HealthModifiedAction) -> void: - if not healable: - print_debug("%s is not healable" % entity) - not_healable.emit(entity) - return - - if is_full(): - print_debug("%s already has full health" % entity) - already_full.emit(entity) - return - - if is_dead() and not revivable: - print_debug("%s cannot be revived" % entity) - not_revivable.emit(entity) - return - - var notify_revived := is_dead() and mod_ac.amount > 0 - - var applied := clampi(roundi((mod_ac.amount + mod_ac.incrementer) * mod_ac.multiplier), 0, max - current) - current += applied - print_debug( - "%s affect=%s type=%s amount=%d incrementer=%d multiplier=%0.4f applied=%d current=%d" - % [entity, Affect.find_key(mod_ac.affect), HealthActionType.Enum.find_key(mod_ac.type), mod_ac.amount, mod_ac.incrementer, mod_ac.multiplier, applied, current] - ) - healed.emit(entity, mod_ac.type, mod_ac.amount, mod_ac.incrementer, mod_ac.multiplier, applied) - action_applied.emit(mod_ac, applied) - - if current == max and applied > 0: - print_debug("%s has full health" % entity) - full.emit(entity) - - if notify_revived: - print_debug("%s revived" % entity) - revived.emit(entity) - - -func _get_modifier(type: HealthActionType.Enum) -> HealthModifier: - return modifiers.get(type, HealthModifier.new()) diff --git a/godot/addons/health_hitbox_hurtbox/health/health.gd.uid b/godot/addons/health_hitbox_hurtbox/health/health.gd.uid deleted file mode 100644 index 30c2773..0000000 --- a/godot/addons/health_hitbox_hurtbox/health/health.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dr8bvnfebp76 diff --git a/godot/addons/health_hitbox_hurtbox/health/health.svg b/godot/addons/health_hitbox_hurtbox/health/health.svg deleted file mode 100644 index 08cc94f..0000000 --- a/godot/addons/health_hitbox_hurtbox/health/health.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/health_hitbox_hurtbox/health/health.svg.import b/godot/addons/health_hitbox_hurtbox/health/health.svg.import deleted file mode 100644 index ede708e..0000000 --- a/godot/addons/health_hitbox_hurtbox/health/health.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://diu1fttubkvuv" -path="res://.godot/imported/health.svg-38b8dcaf4b974319ed410dae73e766f5.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/health_hitbox_hurtbox/health/health.svg" -dest_files=["res://.godot/imported/health.svg-38b8dcaf4b974319ed410dae73e766f5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=true diff --git a/godot/addons/health_hitbox_hurtbox/plugin.cfg b/godot/addons/health_hitbox_hurtbox/plugin.cfg deleted file mode 100644 index 47a48c4..0000000 --- a/godot/addons/health_hitbox_hurtbox/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Health, HitBoxes, HurtBoxes, and HitScans" -description="2D and 3D Components to manage health, damage, and healing" -author="ClutteredCode" -version="5.0.3" -script="plugin.gd" diff --git a/godot/addons/health_hitbox_hurtbox/plugin.gd b/godot/addons/health_hitbox_hurtbox/plugin.gd deleted file mode 100644 index 3ba0725..0000000 --- a/godot/addons/health_hitbox_hurtbox/plugin.gd +++ /dev/null @@ -1,137 +0,0 @@ -@tool -extends EditorPlugin - -const addon_path = "res://addons/health_hitbox_hurtbox/%s" - -var hit_box_2d_added: bool -var hit_scan_2d_added: bool -var hurt_box_2d_added: bool -var basic_hit_box_2d_added: bool -var basic_hit_scan_2d_added: bool -var basic_hurt_box_2d_added: bool - -var hit_box_3d_added: bool -var hit_scan_3d_added: bool -var hurt_box_3d_added: bool -var basic_hit_box_3d_added: bool -var basic_hit_scan_3d_added: bool -var basic_hurt_box_3d_added: bool - -func _enter_tree() -> void: - add_custom_type("Health", "Node", - preload("health/health.gd"), - preload("health/health.svg")) - - # ================== - # Load 2D components - # ================== - if FileAccess.file_exists(addon_path % "2d/hit_box_2d/hit_box_2d.gd"): - hit_box_2d_added = true - add_custom_type("HitBox2D", "Area2D", - load(addon_path % "2d/hit_box_2d/hit_box_2d.gd"), - load(addon_path % "2d/hit_box_2d/hit_box_2d.svg")) - - if FileAccess.file_exists(addon_path % "2d/hit_scan_2d/hit_scan_2d.gd"): - hit_scan_2d_added = true - add_custom_type("HitScan2D", "RayCast2D", - load(addon_path % "2d/hit_scan_2d/hit_scan_2d.gd"), - load(addon_path % "2d/hit_scan_2d/hit_scan_2d.svg")) - - if FileAccess.file_exists(addon_path % "2d/hurt_box_2d/hurt_box_2d.gd"): - hurt_box_2d_added = true - add_custom_type("HurtBox2D", "Area2D", - load(addon_path % "2d/hurt_box_2d/hurt_box_2d.gd"), - load(addon_path % "2d/hurt_box_2d/hurt_box_2d.svg")) - - if FileAccess.file_exists(addon_path % "2d/hit_box_2d/basic_hit_box_2d.gd"): - basic_hit_box_2d_added = true - add_custom_type("BasicHitBox2D", "HitBox2D", - load(addon_path % "2d/hit_box_2d/basic_hit_box_2d.gd"), - load(addon_path % "2d/hit_box_2d/hit_box_2d.svg")) - - if FileAccess.file_exists(addon_path % "2d/hit_scan_2d/basic_hit_scan_2d.gd"): - basic_hit_scan_2d_added = true - add_custom_type("BasicHitScan2D", "HitScan2D", - load(addon_path % "2d/hit_scan_2d/basic_hit_scan_2d.gd"), - load(addon_path % "2d/hit_scan_2d/hit_scan_2d.svg")) - - if FileAccess.file_exists(addon_path % "2d/hurt_box_2d/basic_hurt_box_2d.gd"): - basic_hurt_box_2d_added = true - add_custom_type("BasicHurtBox2D", "HurtBox2D", - load(addon_path % "2d/hurt_box_2d/basic_hurt_box_2d.gd"), - load(addon_path % "2d/hurt_box_2d/hurt_box_2d.svg")) - - # ================== - # Load 3D components - # ================== - if FileAccess.file_exists(addon_path % "3d/hit_box_3d/hit_box_3d.gd"): - hit_box_3d_added = true - add_custom_type("HitBox3D", "Area3D", - load(addon_path % "3d/hit_box_3d/hit_box_3d.gd"), - load(addon_path % "3d/hit_box_3d/hit_box_3d.svg")) - - if FileAccess.file_exists(addon_path % "3d/hit_scan_3d/hit_scan_3d.gd"): - hit_scan_3d_added = true - add_custom_type("HitScan3D", "RayCast3D", - load(addon_path % "3d/hit_scan_3d/hit_scan_3d.gd"), - load(addon_path % "3d/hit_scan_3d/hit_scan_3d.svg")) - - if FileAccess.file_exists(addon_path % "3d/hurt_box_3d/hurt_box_3d.gd"): - hurt_box_3d_added = true - add_custom_type("HurtBox3D", "Area3D", - load(addon_path % "3d/hurt_box_3d/hurt_box_3d.gd"), - load(addon_path % "3d/hurt_box_3d/hurt_box_3d.svg")) - - if FileAccess.file_exists(addon_path % "3d/hit_box_3d/basic_hit_box_3d.gd"): - basic_hit_box_3d_added = true - add_custom_type("BasicHitBox3D", "HitBox3D", - load(addon_path % "3d/hit_box_3d/basic_hit_box_3d.gd"), - load(addon_path % "3d/hit_box_3d/hit_box_3d.svg")) - - if FileAccess.file_exists(addon_path % "3d/hit_scan_3d/basic_hit_scan_3d.gd"): - basic_hit_scan_3d_added = true - add_custom_type("BasicHitScan3D", "HitScan3D", - load(addon_path % "3d/hit_scan_3d/basic_hit_scan_3d.gd"), - load(addon_path % "3d/hit_scan_3d/hit_scan_3d.svg")) - - if FileAccess.file_exists(addon_path % "3d/hurt_box_3d/basic_hurt_box_3d.gd"): - basic_hurt_box_3d_added = true - add_custom_type("BasicHurtBox3D", "HurtBox3D", - load(addon_path % "3d/hurt_box_3d/basic_hurt_box_3d.gd"), - load(addon_path % "3d/hurt_box_3d/hurt_box_3d.svg")) - - -func _exit_tree() -> void: - remove_custom_type("Health") - - # ==================== - # Remove 2D components - # ==================== - if hit_box_2d_added: - remove_custom_type("HitBox2D") - if hit_scan_2d_added: - remove_custom_type("HitScan2D") - if hurt_box_2d_added: - remove_custom_type("HurtBox2D") - if basic_hit_box_2d_added: - remove_custom_type("BasicHitBox2D") - if basic_hit_scan_2d_added: - remove_custom_type("BasicHitScan2D") - if basic_hurt_box_2d_added: - remove_custom_type("BasicHurtBox2D") - - # ==================== - # Remove 3D components - # ==================== - if hit_box_3d_added: - remove_custom_type("HitBox3D") - if hit_scan_3d_added: - remove_custom_type("HitScan3D") - if hurt_box_3d_added: - remove_custom_type("HurtBox3D") - if basic_hit_box_3d_added: - remove_custom_type("BasicHitBox3D") - if basic_hit_scan_3d_added: - remove_custom_type("BasicHitScan3D") - if basic_hurt_box_3d_added: - remove_custom_type("BasicHurtBox3D") diff --git a/godot/addons/health_hitbox_hurtbox/plugin.gd.uid b/godot/addons/health_hitbox_hurtbox/plugin.gd.uid deleted file mode 100644 index 17afd06..0000000 --- a/godot/addons/health_hitbox_hurtbox/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dlmekhfo1ga6q diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_action.gd b/godot/addons/health_hitbox_hurtbox/resources/health_action.gd deleted file mode 100644 index 0644eac..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_action.gd +++ /dev/null @@ -1,21 +0,0 @@ -class_name HealthAction extends Resource - - -@export var affect: Health.Affect = Health.Affect.DAMAGE -@export var type: HealthActionType.Enum = HealthActionType.Enum.KINETIC -@export var amount: int = 1 - - -func _init(affect: Health.Affect = Health.Affect.DAMAGE, type: HealthActionType.Enum = HealthActionType.Enum.KINETIC, amount: int = 1) -> void: - self.affect = affect - self.type = type - self.amount = amount - - -## clone because duplicate() doesn't work with _init() parameters -func clone() -> HealthAction: - return HealthAction.new(affect, type, amount) - - -func _to_string() -> String: - return "HealthAction" % [Health.Affect.find_key(affect), HealthActionType.Enum.find_key(type), amount] diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_action.gd.uid b/godot/addons/health_hitbox_hurtbox/resources/health_action.gd.uid deleted file mode 100644 index 10d2b73..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_action.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hrwhd52e5mkq diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd b/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd deleted file mode 100644 index d4bba4e..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd +++ /dev/null @@ -1,10 +0,0 @@ -class_name HealthActionType extends Object - -## These are the keys used to add [HealthModifier] to [Health] and HurtBoxes. -## NOTICE: Developers can add health action types here to enable more modifiers. -## ALERT: It is recommended to move this and it's guid file out of the 'addon' folder -## when adding more customs types so this file isn't replaced when updating the plugin.[br] -## [br] -## examples of other damage types: BLUDGEON, PIERCE, POISON, FIRE, LIGHTNING... -## examples of other heal types: POTION, MED_KIT, INJECTION, FOOD... -enum Enum { NONE, MEDICINE, KINETIC } diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd.uid b/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd.uid deleted file mode 100644 index 1bad5cb..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_action_type.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d3ikqatofvene diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd b/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd deleted file mode 100644 index 7c7eff4..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd +++ /dev/null @@ -1,44 +0,0 @@ -class_name HealthModifiedAction extends Resource - -var action: HealthAction -var modifier: HealthModifier - -## passthrough returns the modifier.convert_affect or action.affect -var affect: Health.Affect: - get(): - return modifier.convert_affect if modifier.convert_affect else action.affect - -## passthought returns the modifier.conver_type or action.type -var type: HealthActionType.Enum: - get(): - return modifier.convert_type if modifier.convert_type else action.type - -## passthrough returns action.amount -var amount: int: - get(): - return action.amount - -## passthrough returns modifier.incrementer -var incrementer: int: - get(): - return modifier.incrementer - -## passthrough returns modifier.multiplier -var multiplier: float: - get(): - return modifier.multiplier - - -func _init(action: HealthAction, modifier: HealthModifier) -> void: - self.action = action - self.modifier = modifier - - - -## clone because duplicate() doesn't work with _init() parameters -func clone() -> HealthModifiedAction: - return HealthModifiedAction.new(action, modifier) - - -func _to_string() -> String: - return "HealthModifiedAction<%s %s>" % [action, modifier] diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd.uid b/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd.uid deleted file mode 100644 index c1048e9..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_modified_action.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dbxcqu35cfi0m diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd b/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd deleted file mode 100644 index 275a589..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd +++ /dev/null @@ -1,30 +0,0 @@ -class_name HealthModifier extends Resource - -@export var incrementer: int = 0 -@export var multiplier: float = 1.0 - -@export var convert_affect: Health.Affect = Health.Affect.NONE -@export var convert_type: HealthActionType.Enum = HealthActionType.Enum.NONE - - -func _init( - incrementer: int = 0, - multiplier: float = 1.0, - convert_affect: Health.Affect = Health.Affect.NONE, - convert_type: HealthActionType.Enum = HealthActionType.Enum.NONE -) -> void: - self.incrementer = incrementer - self.multiplier = multiplier - self.convert_affect = convert_affect - self.convert_type = convert_type - - - -## clone because duplicate() doesn't work with _init() parameters -func clone() -> HealthModifier: - return HealthModifier.new(incrementer, multiplier, convert_affect, convert_type) - - -func _to_string() -> String: - return "HealthModifier"\ - % [incrementer, multiplier, Health.Affect.find_key(convert_affect), HealthActionType.Enum.find_key(convert_type)] diff --git a/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd.uid b/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd.uid deleted file mode 100644 index 8d823d9..0000000 --- a/godot/addons/health_hitbox_hurtbox/resources/health_modifier.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cobp4qehnuq77 diff --git a/godot/addons/proton_scatter/LICENSE b/godot/addons/proton_scatter/LICENSE deleted file mode 100755 index ba6eddb..0000000 --- a/godot/addons/proton_scatter/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2019 HungryProton - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/godot/addons/proton_scatter/demos/assets/brick.tscn b/godot/addons/proton_scatter/demos/assets/brick.tscn deleted file mode 100644 index bd15c8a..0000000 --- a/godot/addons/proton_scatter/demos/assets/brick.tscn +++ /dev/null @@ -1,23 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://b4ted6l27vuyd"] - -[ext_resource type="PackedScene" uid="uid://d1d1fag0m04yc" path="res://addons/proton_scatter/demos/assets/models/brick.glb" id="1_bkmk2"] -[ext_resource type="Texture2D" uid="uid://dqa2jfs1jy0hq" path="res://addons/proton_scatter/demos/assets/textures/t_rock.jpg" id="2_235bd"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_nwvh2"] -albedo_color = Color(0.678431, 0.596078, 0.466667, 1) -albedo_texture = ExtResource("2_235bd") -uv1_scale = Vector3(0.75, 0.75, 0.75) -uv1_triplanar = true - -[sub_resource type="BoxShape3D" id="BoxShape3D_0rrnn"] -size = Vector3(0.4, 0.4, 0.4) - -[node name="brick" instance=ExtResource("1_bkmk2")] - -[node name="Cube" parent="." index="0"] -material_override = SubResource("StandardMaterial3D_nwvh2") - -[node name="StaticBody3D" type="StaticBody3D" parent="." index="1"] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"] -shape = SubResource("BoxShape3D_0rrnn") diff --git a/godot/addons/proton_scatter/demos/assets/bush.tscn b/godot/addons/proton_scatter/demos/assets/bush.tscn deleted file mode 100644 index 7e0d3a8..0000000 --- a/godot/addons/proton_scatter/demos/assets/bush.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://b8abs8me7ckgo"] - -[ext_resource type="PackedScene" uid="uid://dbb4culid55v5" path="res://addons/proton_scatter/demos/assets/models/bush.glb" id="1_kv8tm"] -[ext_resource type="Material" uid="uid://bn3fr3m3glrnp" path="res://addons/proton_scatter/demos/assets/materials/m_bush.tres" id="2_bkwoq"] - -[node name="bush" instance=ExtResource("1_kv8tm")] - -[node name="Bush" parent="." index="0"] -material_override = ExtResource("2_bkwoq") -instance_shader_parameters/camera_bend_strength = 0.0 diff --git a/godot/addons/proton_scatter/demos/assets/dead_branch.tscn b/godot/addons/proton_scatter/demos/assets/dead_branch.tscn deleted file mode 100644 index 956a667..0000000 --- a/godot/addons/proton_scatter/demos/assets/dead_branch.tscn +++ /dev/null @@ -1,9 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://ctkii8aivl17n"] - -[ext_resource type="PackedScene" uid="uid://cmqlv88xp71tw" path="res://addons/proton_scatter/demos/assets/models/dead_branch.glb" id="1_5foyv"] -[ext_resource type="Material" uid="uid://d01d0h08lqqn6" path="res://addons/proton_scatter/demos/assets/materials/m_trunk.tres" id="2_tldro"] - -[node name="dead_branch" instance=ExtResource("1_5foyv")] - -[node name="DeadBranch" parent="." index="0"] -surface_material_override/0 = ExtResource("2_tldro") diff --git a/godot/addons/proton_scatter/demos/assets/fence_planks.tscn b/godot/addons/proton_scatter/demos/assets/fence_planks.tscn deleted file mode 100644 index 7a60b84..0000000 --- a/godot/addons/proton_scatter/demos/assets/fence_planks.tscn +++ /dev/null @@ -1,18 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bfcjigq0vdl4d"] - -[ext_resource type="PackedScene" uid="uid://6gxiul1pw13t" path="res://addons/proton_scatter/demos/assets/models/fence_planks.glb" id="1"] -[ext_resource type="Material" path="res://addons/proton_scatter/demos/assets/materials/m_fence.tres" id="2"] - -[sub_resource type="BoxShape3D" id="BoxShape3D_fesk1"] -size = Vector3(1, 0.5, 0.1) - -[node name="fence_planks" instance=ExtResource("1")] - -[node name="fence_planks2" parent="." index="0"] -surface_material_override/0 = ExtResource("2") - -[node name="StaticBody3D" type="StaticBody3D" parent="." index="1"] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.197684, 0.0236663) -shape = SubResource("BoxShape3D_fesk1") diff --git a/godot/addons/proton_scatter/demos/assets/gobot.tscn b/godot/addons/proton_scatter/demos/assets/gobot.tscn deleted file mode 100644 index 5b005eb..0000000 --- a/godot/addons/proton_scatter/demos/assets/gobot.tscn +++ /dev/null @@ -1,16 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bmglbfn5jaubp"] - -[ext_resource type="PackedScene" uid="uid://d3f4d3m7n8tpr" path="res://addons/proton_scatter/demos/assets/models/gobot.glb" id="1_gfyx7"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_rhuea"] -albedo_color = Color(0.278431, 0.54902, 0.74902, 1) -metallic = 0.4 -metallic_specular = 0.2 -roughness = 0.15 -rim_enabled = true -rim = 0.3 - -[node name="gobot" instance=ExtResource("1_gfyx7")] - -[node name="Sphere001" parent="." index="0"] -surface_material_override/0 = SubResource("StandardMaterial3D_rhuea") diff --git a/godot/addons/proton_scatter/demos/assets/grass.tscn b/godot/addons/proton_scatter/demos/assets/grass.tscn deleted file mode 100644 index 36260f3..0000000 --- a/godot/addons/proton_scatter/demos/assets/grass.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://c3c76je2y6vfj"] - -[ext_resource type="PackedScene" uid="uid://018flajgtx7t" path="res://addons/proton_scatter/demos/assets/models/grass.glb" id="1_203fe"] -[ext_resource type="Material" uid="uid://c4mot1fo3siox" path="res://addons/proton_scatter/demos/assets/materials/m_grass.tres" id="2_sv1ar"] - -[node name="grass" instance=ExtResource("1_203fe")] - -[node name="Plane011" parent="." index="0"] -instance_shader_parameters/camera_bend_strength = 0.35 -surface_material_override/0 = ExtResource("2_sv1ar") diff --git a/godot/addons/proton_scatter/demos/assets/grass_2.tscn b/godot/addons/proton_scatter/demos/assets/grass_2.tscn deleted file mode 100644 index 6810785..0000000 --- a/godot/addons/proton_scatter/demos/assets/grass_2.tscn +++ /dev/null @@ -1,9 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cia3jakp3wj1d"] - -[ext_resource type="PackedScene" uid="uid://dcnm2ijk7hj4j" path="res://addons/proton_scatter/demos/assets/models/grass_2.glb" id="1_xyqky"] -[ext_resource type="Material" uid="uid://c4mot1fo3siox" path="res://addons/proton_scatter/demos/assets/materials/m_grass.tres" id="2_63qe5"] - -[node name="grass_2" instance=ExtResource("1_xyqky")] - -[node name="Grass" parent="." index="0"] -surface_material_override/0 = ExtResource("2_63qe5") diff --git a/godot/addons/proton_scatter/demos/assets/large_rock.tscn b/godot/addons/proton_scatter/demos/assets/large_rock.tscn deleted file mode 100644 index 2234439..0000000 --- a/godot/addons/proton_scatter/demos/assets/large_rock.tscn +++ /dev/null @@ -1,17 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://8ay5rlrutcmx"] - -[ext_resource type="PackedScene" uid="uid://bxqkgplyoipsx" path="res://addons/proton_scatter/demos/assets/models/large_rock.glb" id="1_etns1"] -[ext_resource type="Material" uid="uid://i0jgjmbbl2m5" path="res://addons/proton_scatter/demos/assets/materials/m_rock.tres" id="2_fes1d"] - -[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_6ssqc"] -data = PackedVector3Array(0.0629, 0.1755, -1.8335, -0.0082, 0.0041, -1.6822, 0.2717, -0.1032, -1.6837, 0.6881, 0.5954, 1.4818, 1.1748, -0.0814, 1.7311, 0.3761, 0.3877, 1.5951, 0.8004, 0.2889, -1.6673, 0.453, 0.787, -1.6234, 0.2234, 0.3394, -1.8428, 0.0438, -0.3535, -1.5059, 0.0958, -0.4313, -1.5075, 0.2334, -0.4206, -1.5131, 1.7542, -0.4854, 0.9086, 1.6573, -0.2166, 1.2501, 1.8018, -0.1166, 1.0465, -0.9001, 0.6982, -1.3812, 0.4904, 0.8361, -0.4902, -1.2997, 0.5397, -0.7858, -1.3066, -0.6146, -0.0152, -1.3934, -0.7148, -0.3785, -1.6779, -0.4855, -0.1607, -1.6422, -0.27, -0.3156, -1.3474, 0.367, -0.2501, -1.5688, -0.3115, 0.1105, 0.7765, -0.6276, -1.2561, 0.9699, -0.5671, -1.2091, 0.6074, -0.5308, -1.4001, -0.9001, 0.6982, -1.3812, -0.534, 0.3122, -1.6595, -0.4893, 0.652, -1.605, 1.5141, -0.6082, 1.2539, 1.502, -0.4979, 1.4563, 1.5644, -0.4551, 1.31, 1.6136, 0.2882, 1.3723, 1.2715, 0.1425, 1.7004, 1.307, 0.4153, 1.6132, -0.0974, 0.1771, -1.7741, -0.0692, 0.1191, -1.7434, -0.0832, 0.1572, -1.7751, -0.0258, 0.0213, -1.688, -0.3113, -0.1613, -1.5779, 0.0157, -0.0532, -1.6436, -0.0864, 0.2978, -1.7808, 0.0784, 0.5885, -1.8004, -0.0895, 0.5831, -1.6991, 1.8072, -0.4701, -0.0799, 1.571, 0.5779, 0.2372, 1.7035, -0.1804, -0.405, 0.7935, 0.8229, -1.3081, 0.9762, 0.8279, -1.1273, 0.6719, 0.9108, -1.1199, -1.2328, -0.714, -0.1886, -1.3066, -0.6146, -0.0152, -1.0843, -0.5896, 0.1569, -1.6727, -0.3783, -0.0804, -1.6583, -0.5073, -0.3071, -1.6422, -0.27, -0.3156, 1.7542, -0.4854, 0.9086, 1.4359, -0.8794, 0.8237, 1.5663, -0.6718, 1.1167, 0.6096, -0.219, -1.5025, 0.6415, -0.1642, -1.5814, 0.2717, -0.1032, -1.6837, -0.0258, 0.0213, -1.688, 0.0157, -0.0532, -1.6436, -0.0082, 0.0041, -1.6822, 0.4631, 0.9672, -1.1988, 0.6719, 0.9108, -1.1199, 0.5883, 0.9628, -1.0063, 1.6466, 0.5513, 1.0625, 1.6113, 0.4774, 1.1526, 1.487, 0.6285, 1.1421, 1.259, -0.746, -0.7881, 0.8809, -0.6144, -1.19, -0.8459, -0.6965, -0.1217, 1.2972, 0.6831, -0.5577, 1.3496, 0.6378, -0.4421, 1.3469, 0.6517, -0.3691, 1.0299, -0.8113, 1.3675, 1.1519, -0.8005, 1.3807, 1.0338, -0.9119, 1.2882, 0.1273, -0.231, -1.5631, 0.2717, -0.1032, -1.6837, 0.0157, -0.0532, -1.6436, 0.0157, -0.0532, -1.6436, 0.2717, -0.1032, -1.6837, -0.0082, 0.0041, -1.6822, -0.0082, 0.0041, -1.6822, 0.0629, 0.1755, -1.8335, -0.0258, 0.0213, -1.688, -0.0258, 0.0213, -1.688, 0.0629, 0.1755, -1.8335, -0.0692, 0.1191, -1.7434, -0.0832, 0.1572, -1.7751, -0.0864, 0.2978, -1.7808, -0.0974, 0.1771, -1.7741, -0.0692, 0.1191, -1.7434, 0.0629, 0.1755, -1.8335, -0.0832, 0.1572, -1.7751, -0.0864, 0.2978, -1.7808, -0.0832, 0.1572, -1.7751, 0.0629, 0.1755, -1.8335, 0.1504, 0.3249, 1.5256, 0.2321, -0.5546, 1.2968, -0.1811, 0.3534, 1.33, -0.1811, 0.3534, 1.33, -0.7713, -0.4525, 0.8629, -0.8882, 0.3173, 0.8972, -0.8882, 0.3173, 0.8972, -0.7713, -0.4525, 0.8629, -1.057, 0.126, 0.9512, -1.057, 0.126, 0.9512, -0.7713, -0.4525, 0.8629, -1.1208, -0.2211, 0.8364, -0.7713, -0.4525, 0.8629, -0.1811, 0.3534, 1.33, 0.2321, -0.5546, 1.2968, 0.2321, -0.5546, 1.2968, 0.5577, -0.3719, 1.5982, 0.5902, -0.5067, 1.4887, 0.6927, -0.351, 1.6834, 1.1748, -0.0814, 1.7311, 1.0161, -0.3973, 1.7034, 0.2321, -0.5546, 1.2968, 0.1504, 0.3249, 1.5256, 0.5577, -0.3719, 1.5982, 0.1504, 0.3249, 1.5256, 0.3761, 0.3877, 1.5951, 0.5577, -0.3719, 1.5982, 0.5577, -0.3719, 1.5982, 0.3761, 0.3877, 1.5951, 0.6927, -0.351, 1.6834, 0.6927, -0.351, 1.6834, 0.3761, 0.3877, 1.5951, 1.1748, -0.0814, 1.7311, 1.1748, -0.0814, 1.7311, 0.6881, 0.5954, 1.4818, 1.2715, 0.1425, 1.7004, 1.2715, 0.1425, 1.7004, 0.6881, 0.5954, 1.4818, 1.307, 0.4153, 1.6132, 1.307, 0.4153, 1.6132, 1.0721, 0.6892, 1.1619, 1.3943, 0.5306, 1.4472, 1.0721, 0.6892, 1.1619, 1.307, 0.4153, 1.6132, 0.6881, 0.5954, 1.4818, 0.5536, 0.8275, -1.4892, 0.7935, 0.8229, -1.3081, 0.606, 0.847, -1.3151, 0.5536, 0.8275, -1.4892, 0.8004, 0.2889, -1.6673, 0.7935, 0.8229, -1.3081, 0.7935, 0.8229, -1.3081, 0.8004, 0.2889, -1.6673, 0.9175, 0.7849, -1.3125, 0.0784, 0.5885, -1.8004, 0.2234, 0.3394, -1.8428, 0.2304, 0.721, -1.7333, 0.2304, 0.721, -1.7333, 0.2234, 0.3394, -1.8428, 0.453, 0.787, -1.6234, 0.453, 0.787, -1.6234, 0.8004, 0.2889, -1.6673, 0.5536, 0.8275, -1.4892, 0.9625, 0.7976, -1.2398, 1.1721, 0.7244, -1.0147, 0.9762, 0.8279, -1.1273, 0.8004, 0.2889, -1.6673, 1.0764, 0.3168, -1.4944, 0.9175, 0.7849, -1.3125, 0.9175, 0.7849, -1.3125, 1.0764, 0.3168, -1.4944, 0.9625, 0.7976, -1.2398, 0.9625, 0.7976, -1.2398, 1.1928, 0.2492, -1.3592, 1.1721, 0.7244, -1.0147, 1.0764, 0.3168, -1.4944, 1.1928, 0.2492, -1.3592, 0.9625, 0.7976, -1.2398, 1.1721, 0.7244, -1.0147, 1.1928, 0.2492, -1.3592, 1.3553, 0.3188, -1.0845, 0.0438, -0.3535, -1.5059, 0.2334, -0.4206, -1.5131, 0.1273, -0.231, -1.5631, 1.8018, -0.1166, 1.0465, 1.6936, -0.0517, 1.195, 1.7358, 0.1659, 1.068, 1.7358, 0.1659, 1.068, 1.6944, 0.1451, 1.1403, 1.7079, 0.2069, 1.098, 1.6936, -0.0517, 1.195, 1.6944, 0.1451, 1.1403, 1.7358, 0.1659, 1.068, 1.6936, -0.0517, 1.195, 1.8018, -0.1166, 1.0465, 1.6573, -0.2166, 1.2501, 1.6573, -0.2166, 1.2501, 1.7542, -0.4854, 0.9086, 1.5644, -0.4551, 1.31, 1.7542, -0.4854, 0.9086, 1.5663, -0.6718, 1.1167, 1.5644, -0.4551, 1.31, 1.5644, -0.4551, 1.31, 1.5663, -0.6718, 1.1167, 1.5141, -0.6082, 1.2539, 0.3565, 0.8862, -1.3307, 0.5536, 0.8275, -1.4892, 0.606, 0.847, -1.3151, 0.5536, 0.8275, -1.4892, 0.3565, 0.8862, -1.3307, 0.453, 0.787, -1.6234, 0.453, 0.787, -1.6234, 0.3565, 0.8862, -1.3307, 0.2304, 0.721, -1.7333, 0.2304, 0.721, -1.7333, -0.0895, 0.5831, -1.6991, 0.0784, 0.5885, -1.8004, -0.2181, 0.7012, -1.5976, -0.9001, 0.6982, -1.3812, -0.4893, 0.652, -1.605, 0.2304, 0.721, -1.7333, 0.3565, 0.8862, -1.3307, -0.0895, 0.5831, -1.6991, -0.0895, 0.5831, -1.6991, 0.3565, 0.8862, -1.3307, -0.2181, 0.7012, -1.5976, 0.5883, 0.9628, -1.0063, 0.4904, 0.8361, -0.4902, 0.4631, 0.9672, -1.1988, 0.4631, 0.9672, -1.1988, 0.4904, 0.8361, -0.4902, 0.3565, 0.8862, -1.3307, 0.3127, 0.6878, 0.2041, -1.2997, 0.5397, -0.7858, 0.4904, 0.8361, -0.4902, 1.0721, 0.6892, 1.1619, 0.6881, 0.5954, 1.4818, 0.6961, 0.7351, 0.3218, 0.6961, 0.7351, 0.3218, 0.6881, 0.5954, 1.4818, 0.3127, 0.6878, 0.2041, 0.3761, 0.3877, 1.5951, 0.1504, 0.3249, 1.5256, 0.6881, 0.5954, 1.4818, -0.1811, 0.3534, 1.33, 0.3127, 0.6878, 0.2041, 0.1504, 0.3249, 1.5256, 0.3127, 0.6878, 0.2041, 0.6881, 0.5954, 1.4818, 0.1504, 0.3249, 1.5256, -1.2352, 0.3268, 0.2088, 0.3127, 0.6878, 0.2041, -0.8882, 0.3173, 0.8972, -0.8882, 0.3173, 0.8972, 0.3127, 0.6878, 0.2041, -0.1811, 0.3534, 1.33, -1.2997, 0.5397, -0.7858, 0.3127, 0.6878, 0.2041, -1.3474, 0.367, -0.2501, -1.3474, 0.367, -0.2501, 0.3127, 0.6878, 0.2041, -1.2352, 0.3268, 0.2088, -0.9001, 0.6982, -1.3812, -1.2997, 0.5397, -0.7858, -1.1636, 0.6589, -1.169, -0.2181, 0.7012, -1.5976, 0.4904, 0.8361, -0.4902, -0.9001, 0.6982, -1.3812, 0.3565, 0.8862, -1.3307, 0.4904, 0.8361, -0.4902, -0.2181, 0.7012, -1.5976, -1.1208, -0.2211, 0.8364, -1.0843, -0.5896, 0.1569, -1.4177, -0.2864, 0.367, -1.4177, -0.2864, 0.367, -1.3066, -0.6146, -0.0152, -1.5688, -0.3115, 0.1105, -1.0843, -0.5896, 0.1569, -1.3066, -0.6146, -0.0152, -1.4177, -0.2864, 0.367, -1.5688, -0.3115, 0.1105, -1.3066, -0.6146, -0.0152, -1.6727, -0.3783, -0.0804, -1.6727, -0.3783, -0.0804, -1.3066, -0.6146, -0.0152, -1.6779, -0.4855, -0.1607, -1.6779, -0.4855, -0.1607, -1.3934, -0.7148, -0.3785, -1.6583, -0.5073, -0.3071, -1.6583, -0.5073, -0.3071, -1.3934, -0.7148, -0.3785, -1.5776, -0.5652, -0.4479, -1.5776, -0.5652, -0.4479, -1.3934, -0.7148, -0.3785, -1.4282, -0.6229, -0.5707, -1.3934, -0.7148, -0.3785, -1.3066, -0.6146, -0.0152, -1.2328, -0.714, -0.1886, -1.0843, -0.5896, 0.1569, -1.1208, -0.2211, 0.8364, -0.7713, -0.4525, 0.8629, -1.4177, -0.2864, 0.367, -1.2352, 0.3268, 0.2088, -1.1208, -0.2211, 0.8364, -1.1208, -0.2211, 0.8364, -1.2352, 0.3268, 0.2088, -1.057, 0.126, 0.9512, -1.057, 0.126, 0.9512, -1.2352, 0.3268, 0.2088, -0.8882, 0.3173, 0.8972, -1.2352, 0.3268, 0.2088, -1.5688, -0.3115, 0.1105, -1.3474, 0.367, -0.2501, -1.5688, -0.3115, 0.1105, -1.2352, 0.3268, 0.2088, -1.4177, -0.2864, 0.367, -1.6422, -0.27, -0.3156, -1.5688, -0.3115, 0.1105, -1.6727, -0.3783, -0.0804, -1.387, 0.0341, -0.9932, -1.2997, 0.5397, -0.7858, -1.4997, -0.1393, -0.7307, -1.4997, -0.1393, -0.7307, -1.3474, 0.367, -0.2501, -1.6422, -0.27, -0.3156, -1.2722, 0.4609, -1.2479, -1.387, 0.0341, -0.9932, -1.1493, 0.3036, -1.3146, -1.1636, 0.6589, -1.169, -1.2997, 0.5397, -0.7858, -1.2362, 0.5774, -1.237, -1.2362, 0.5774, -1.237, -1.2997, 0.5397, -0.7858, -1.2722, 0.4609, -1.2479, -1.2722, 0.4609, -1.2479, -1.2997, 0.5397, -0.7858, -1.387, 0.0341, -0.9932, -1.4997, -0.1393, -0.7307, -1.2997, 0.5397, -0.7858, -1.3474, 0.367, -0.2501, 1.1928, 0.2492, -1.3592, 1.0502, -0.6021, -1.1682, 1.3553, 0.3188, -1.0845, 1.3553, 0.3188, -1.0845, 1.259, -0.746, -0.7881, 1.7035, -0.1804, -0.405, 1.3553, 0.3188, -1.0845, 1.1109, -0.6863, -1.0196, 1.259, -0.746, -0.7881, 1.7035, -0.1804, -0.405, 1.5814, -0.7117, -0.4108, 1.8072, -0.4701, -0.0799, 1.8072, -0.4701, -0.0799, 1.6645, -0.7082, -0.1973, 1.7652, -0.6177, 0.216, 1.5814, -0.7117, -0.4108, 1.6645, -0.7082, -0.1973, 1.8072, -0.4701, -0.0799, 1.7652, -0.6177, 0.216, 1.6645, -0.7082, -0.1973, 1.6461, -0.7592, 0.1617, 1.436, -0.7221, -0.624, 1.5814, -0.7117, -0.4108, 1.7035, -0.1804, -0.405, 0.8004, 0.2889, -1.6673, 0.6415, -0.1642, -1.5814, 1.0764, 0.3168, -1.4944, 1.0764, 0.3168, -1.4944, 0.6415, -0.1642, -1.5814, 1.1928, 0.2492, -1.3592, 0.6415, -0.1642, -1.5814, 0.6096, -0.219, -1.5025, 1.1928, 0.2492, -1.3592, 0.0629, 0.1755, -1.8335, 0.2717, -0.1032, -1.6837, 0.2234, 0.3394, -1.8428, 0.2234, 0.3394, -1.8428, 0.2717, -0.1032, -1.6837, 0.8004, 0.2889, -1.6673, 0.6415, -0.1642, -1.5814, 0.8004, 0.2889, -1.6673, 0.2717, -0.1032, -1.6837, 0.2334, -0.4206, -1.5131, 0.6096, -0.219, -1.5025, 0.1273, -0.231, -1.5631, 0.6074, -0.5308, -1.4001, 0.6096, -0.219, -1.5025, 0.2334, -0.4206, -1.5131, 1.7035, -0.1804, -0.405, 1.259, -0.746, -0.7881, 1.436, -0.7221, -0.624, 1.1928, 0.2492, -1.3592, 0.9699, -0.5671, -1.2091, 1.0502, -0.6021, -1.1682, 1.1109, -0.6863, -1.0196, 1.3553, 0.3188, -1.0845, 1.0502, -0.6021, -1.1682, 0.6074, -0.5308, -1.4001, 0.9699, -0.5671, -1.2091, 0.6096, -0.219, -1.5025, 0.9699, -0.5671, -1.2091, 1.1928, 0.2492, -1.3592, 0.6096, -0.219, -1.5025, 0.8809, -0.6144, -1.19, 0.9699, -0.5671, -1.2091, 0.7765, -0.6276, -1.2561, -0.534, 0.3122, -1.6595, -0.9001, 0.6982, -1.3812, -1.1493, 0.3036, -1.3146, -1.1493, 0.3036, -1.3146, -1.2362, 0.5774, -1.237, -1.2722, 0.4609, -1.2479, -0.9001, 0.6982, -1.3812, -1.2362, 0.5774, -1.237, -1.1493, 0.3036, -1.3146, -1.2362, 0.5774, -1.237, -0.9001, 0.6982, -1.3812, -1.1636, 0.6589, -1.169, 1.502, -0.4979, 1.4563, 1.5141, -0.6082, 1.2539, 1.3317, -0.6356, 1.518, 1.3317, -0.6356, 1.518, 1.5141, -0.6082, 1.2539, 1.2689, -0.7439, 1.3995, 1.2689, -0.7439, 1.3995, 1.124, -0.9978, 1.0499, 1.1519, -0.8005, 1.3807, 1.1519, -0.8005, 1.3807, 1.124, -0.9978, 1.0499, 1.0338, -0.9119, 1.2882, 1.0338, -0.9119, 1.2882, 1.124, -0.9978, 1.0499, 1.0169, -0.9992, 1.153, 1.124, -0.9978, 1.0499, 1.5663, -0.6718, 1.1167, 1.2368, -0.9984, 0.9293, 1.2368, -0.9984, 0.9293, 1.5663, -0.6718, 1.1167, 1.4359, -0.8794, 0.8237, 1.5663, -0.6718, 1.1167, 1.2689, -0.7439, 1.3995, 1.5141, -0.6082, 1.2539, 1.124, -0.9978, 1.0499, 1.2689, -0.7439, 1.3995, 1.5663, -0.6718, 1.1167, 1.2715, 0.1425, 1.7004, 1.6307, -0.0932, 1.3908, 1.1748, -0.0814, 1.7311, 1.1748, -0.0814, 1.7311, 1.1624, -0.5844, 1.6321, 1.0161, -0.3973, 1.7034, 1.502, -0.4979, 1.4563, 1.3317, -0.6356, 1.518, 1.1624, -0.5844, 1.6321, 1.1748, -0.0814, 1.7311, 1.502, -0.4979, 1.4563, 1.1624, -0.5844, 1.6321, 1.502, -0.4979, 1.4563, 1.1748, -0.0814, 1.7311, 1.5954, -0.2805, 1.4511, 1.5954, -0.2805, 1.4511, 1.1748, -0.0814, 1.7311, 1.6307, -0.0932, 1.3908, 1.6307, -0.0932, 1.3908, 1.2715, 0.1425, 1.7004, 1.6136, 0.2882, 1.3723, 1.6136, 0.2882, 1.3723, 1.307, 0.4153, 1.6132, 1.3943, 0.5306, 1.4472, -0.534, 0.3122, -1.6595, -0.2181, 0.7012, -1.5976, -0.4893, 0.652, -1.605, -0.2181, 0.7012, -1.5976, -0.534, 0.3122, -1.6595, -0.0895, 0.5831, -1.6991, -0.0895, 0.5831, -1.6991, -0.534, 0.3122, -1.6595, -0.0864, 0.2978, -1.7808, -0.0974, 0.1771, -1.7741, -0.3113, -0.1613, -1.5779, -0.0692, 0.1191, -1.7434, -0.0692, 0.1191, -1.7434, -0.3113, -0.1613, -1.5779, -0.0258, 0.0213, -1.688, -0.0864, 0.2978, -1.7808, -0.534, 0.3122, -1.6595, -0.0974, 0.1771, -1.7741, -0.3113, -0.1613, -1.5779, -0.0974, 0.1771, -1.7741, -0.534, 0.3122, -1.6595, 0.0157, -0.0532, -1.6436, -0.3113, -0.1613, -1.5779, 0.1273, -0.231, -1.5631, 0.0784, 0.5885, -1.8004, -0.0864, 0.2978, -1.7808, 0.2234, 0.3394, -1.8428, 0.2234, 0.3394, -1.8428, -0.0864, 0.2978, -1.7808, 0.0629, 0.1755, -1.8335, 1.7035, -0.1804, -0.405, 1.3496, 0.6378, -0.4421, 1.3553, 0.3188, -1.0845, 1.3553, 0.3188, -1.0845, 1.2972, 0.6831, -0.5577, 1.1721, 0.7244, -1.0147, 1.3496, 0.6378, -0.4421, 1.2972, 0.6831, -0.5577, 1.3553, 0.3188, -1.0845, 1.3496, 0.6378, -0.4421, 1.5036, 0.5972, -0.0994, 1.3469, 0.6517, -0.3691, 1.571, 0.5779, 0.2372, 1.8018, -0.1166, 1.0465, 1.5632, 0.6125, 0.4668, 1.5632, 0.6125, 0.4668, 1.6466, 0.5513, 1.0625, 1.559, 0.6543, 0.9634, 1.5632, 0.6125, 0.4668, 1.7358, 0.1659, 1.068, 1.6466, 0.5513, 1.0625, 1.7358, 0.1659, 1.068, 1.7079, 0.2069, 1.098, 1.6466, 0.5513, 1.0625, 1.6466, 0.5513, 1.0625, 1.7079, 0.2069, 1.098, 1.6113, 0.4774, 1.1526, 1.6113, 0.4774, 1.1526, 1.7079, 0.2069, 1.098, 1.6616, 0.3586, 1.2649, 1.6616, 0.3586, 1.2649, 1.6944, 0.1451, 1.1403, 1.6136, 0.2882, 1.3723, 1.6136, 0.2882, 1.3723, 1.6944, 0.1451, 1.1403, 1.6307, -0.0932, 1.3908, 1.6307, -0.0932, 1.3908, 1.6573, -0.2166, 1.2501, 1.5954, -0.2805, 1.4511, 1.5954, -0.2805, 1.4511, 1.5644, -0.4551, 1.31, 1.502, -0.4979, 1.4563, 1.6573, -0.2166, 1.2501, 1.5644, -0.4551, 1.31, 1.5954, -0.2805, 1.4511, 1.6573, -0.2166, 1.2501, 1.6307, -0.0932, 1.3908, 1.6936, -0.0517, 1.195, 1.6936, -0.0517, 1.195, 1.6307, -0.0932, 1.3908, 1.6944, 0.1451, 1.1403, 1.5036, 0.5972, -0.0994, 1.7035, -0.1804, -0.405, 1.571, 0.5779, 0.2372, 1.6616, 0.3586, 1.2649, 1.7079, 0.2069, 1.098, 1.6944, 0.1451, 1.1403, 1.5632, 0.6125, 0.4668, 1.8018, -0.1166, 1.0465, 1.7358, 0.1659, 1.068, 1.8018, -0.1166, 1.0465, 1.7652, -0.6177, 0.216, 1.7542, -0.4854, 0.9086, 1.7652, -0.6177, 0.216, 1.8018, -0.1166, 1.0465, 1.571, 0.5779, 0.2372, 1.3496, 0.6378, -0.4421, 1.7035, -0.1804, -0.405, 1.5036, 0.5972, -0.0994, 1.571, 0.5779, 0.2372, 1.8072, -0.4701, -0.0799, 1.7652, -0.6177, 0.216, 1.487, 0.6285, 1.1421, 1.0721, 0.6892, 1.1619, 1.559, 0.6543, 0.9634, 1.559, 0.6543, 0.9634, 1.0721, 0.6892, 1.1619, 1.5632, 0.6125, 0.4668, 1.5632, 0.6125, 0.4668, 0.6961, 0.7351, 0.3218, 1.571, 0.5779, 0.2372, 1.571, 0.5779, 0.2372, 0.6961, 0.7351, 0.3218, 1.5036, 0.5972, -0.0994, 1.5036, 0.5972, -0.0994, 0.6961, 0.7351, 0.3218, 1.3469, 0.6517, -0.3691, 1.6616, 0.3586, 1.2649, 1.6136, 0.2882, 1.3723, 1.6113, 0.4774, 1.1526, 1.6113, 0.4774, 1.1526, 1.6136, 0.2882, 1.3723, 1.487, 0.6285, 1.1421, 1.2972, 0.6831, -0.5577, 0.4904, 0.8361, -0.4902, 1.1721, 0.7244, -1.0147, 1.1721, 0.7244, -1.0147, 0.4904, 0.8361, -0.4902, 0.9762, 0.8279, -1.1273, 1.5632, 0.6125, 0.4668, 1.0721, 0.6892, 1.1619, 0.6961, 0.7351, 0.3218, 1.3469, 0.6517, -0.3691, 0.4904, 0.8361, -0.4902, 1.2972, 0.6831, -0.5577, 0.6961, 0.7351, 0.3218, 0.4904, 0.8361, -0.4902, 1.3469, 0.6517, -0.3691, 1.0721, 0.6892, 1.1619, 1.487, 0.6285, 1.1421, 1.3943, 0.5306, 1.4472, 1.3943, 0.5306, 1.4472, 1.487, 0.6285, 1.1421, 1.6136, 0.2882, 1.3723, 0.4904, 0.8361, -0.4902, 0.6961, 0.7351, 0.3218, 0.3127, 0.6878, 0.2041, 0.5883, 0.9628, -1.0063, 0.9762, 0.8279, -1.1273, 0.4904, 0.8361, -0.4902, 0.7935, 0.8229, -1.3081, 0.6719, 0.9108, -1.1199, 0.606, 0.847, -1.3151, 0.6719, 0.9108, -1.1199, 0.9762, 0.8279, -1.1273, 0.5883, 0.9628, -1.0063, 0.9762, 0.8279, -1.1273, 0.7935, 0.8229, -1.3081, 0.9625, 0.7976, -1.2398, 0.9625, 0.7976, -1.2398, 0.7935, 0.8229, -1.3081, 0.9175, 0.7849, -1.3125, -1.2328, -0.714, -0.1886, -1.0843, -0.5896, 0.1569, -0.8459, -0.6965, -0.1217, -1.1493, 0.3036, -1.3146, -0.8122, -0.4144, -1.2617, -0.534, 0.3122, -1.6595, -0.534, 0.3122, -1.6595, -0.8122, -0.4144, -1.2617, -0.3113, -0.1613, -1.5779, -0.8122, -0.4144, -1.2617, -1.387, 0.0341, -0.9932, -1.1401, -0.5073, -0.9935, -1.1493, 0.3036, -1.3146, -1.387, 0.0341, -0.9932, -0.8122, -0.4144, -1.2617, -1.1401, -0.5073, -0.9935, -1.4997, -0.1393, -0.7307, -1.4282, -0.6229, -0.5707, -1.4282, -0.6229, -0.5707, -1.4997, -0.1393, -0.7307, -1.5776, -0.5652, -0.4479, -1.6583, -0.5073, -0.3071, -1.6727, -0.3783, -0.0804, -1.6779, -0.4855, -0.1607, -1.5776, -0.5652, -0.4479, -1.6422, -0.27, -0.3156, -1.6583, -0.5073, -0.3071, -1.4997, -0.1393, -0.7307, -1.6422, -0.27, -0.3156, -1.5776, -0.5652, -0.4479, -1.4997, -0.1393, -0.7307, -1.1401, -0.5073, -0.9935, -1.387, 0.0341, -0.9932, 1.6461, -0.7592, 0.1617, 1.4359, -0.8794, 0.8237, 1.7652, -0.6177, 0.216, 1.7652, -0.6177, 0.216, 1.4359, -0.8794, 0.8237, 1.7542, -0.4854, 0.9086, 0.6096, -0.219, -1.5025, 0.2717, -0.1032, -1.6837, 0.1273, -0.231, -1.5631, 0.6719, 0.9108, -1.1199, 0.4631, 0.9672, -1.1988, 0.606, 0.847, -1.3151, 0.606, 0.847, -1.3151, 0.4631, 0.9672, -1.1988, 0.3565, 0.8862, -1.3307, 1.6466, 0.5513, 1.0625, 1.487, 0.6285, 1.1421, 1.559, 0.6543, 0.9634, 1.1624, -0.5844, 1.6321, 1.0299, -0.8113, 1.3675, 1.0161, -0.3973, 1.7034, 1.0161, -0.3973, 1.7034, 1.0299, -0.8113, 1.3675, 0.6927, -0.351, 1.6834, 0.6927, -0.351, 1.6834, 0.5902, -0.5067, 1.4887, 0.5577, -0.3719, 1.5982, 0.2321, -0.5546, 1.2968, -0.8459, -0.6965, -0.1217, -0.7713, -0.4525, 0.8629, -0.7713, -0.4525, 0.8629, -0.8459, -0.6965, -0.1217, -1.0843, -0.5896, 0.1569, 0.6927, -0.351, 1.6834, 1.0299, -0.8113, 1.3675, 0.5902, -0.5067, 1.4887, 0.5902, -0.5067, 1.4887, 1.0169, -0.9992, 1.153, 0.2321, -0.5546, 1.2968, -0.8459, -0.6965, -0.1217, -1.3934, -0.7148, -0.3785, -1.2328, -0.714, -0.1886, 0.2321, -0.5546, 1.2968, 1.259, -0.746, -0.7881, -0.8459, -0.6965, -0.1217, 1.2368, -0.9984, 0.9293, 1.259, -0.746, -0.7881, 0.2321, -0.5546, 1.2968, 1.3317, -0.6356, 1.518, 1.1519, -0.8005, 1.3807, 1.1624, -0.5844, 1.6321, 1.1519, -0.8005, 1.3807, 1.3317, -0.6356, 1.518, 1.2689, -0.7439, 1.3995, 1.0169, -0.9992, 1.153, 0.5902, -0.5067, 1.4887, 1.0338, -0.9119, 1.2882, 1.0338, -0.9119, 1.2882, 0.5902, -0.5067, 1.4887, 1.0299, -0.8113, 1.3675, 1.0299, -0.8113, 1.3675, 1.1624, -0.5844, 1.6321, 1.1519, -0.8005, 1.3807, -0.8459, -0.6965, -0.1217, -1.4282, -0.6229, -0.5707, -1.3934, -0.7148, -0.3785, -1.4282, -0.6229, -0.5707, -0.8459, -0.6965, -0.1217, -1.1401, -0.5073, -0.9935, -1.1401, -0.5073, -0.9935, -0.8459, -0.6965, -0.1217, -0.8122, -0.4144, -1.2617, -0.8122, -0.4144, -1.2617, 0.0438, -0.3535, -1.5059, -0.3113, -0.1613, -1.5779, -0.3113, -0.1613, -1.5779, 0.0438, -0.3535, -1.5059, 0.1273, -0.231, -1.5631, 1.2368, -0.9984, 0.9293, 0.2321, -0.5546, 1.2968, 1.124, -0.9978, 1.0499, 1.124, -0.9978, 1.0499, 0.2321, -0.5546, 1.2968, 1.0169, -0.9992, 1.153, -0.8459, -0.6965, -0.1217, 0.0438, -0.3535, -1.5059, -0.8122, -0.4144, -1.2617, 0.0958, -0.4313, -1.5075, 0.0438, -0.3535, -1.5059, -0.8459, -0.6965, -0.1217, 0.0958, -0.4313, -1.5075, 0.6074, -0.5308, -1.4001, 0.2334, -0.4206, -1.5131, 0.0958, -0.4313, -1.5075, 0.7765, -0.6276, -1.2561, 0.6074, -0.5308, -1.4001, -0.8459, -0.6965, -0.1217, 0.7765, -0.6276, -1.2561, 0.0958, -0.4313, -1.5075, 1.6461, -0.7592, 0.1617, 1.2368, -0.9984, 0.9293, 1.4359, -0.8794, 0.8237, 1.5814, -0.7117, -0.4108, 1.6461, -0.7592, 0.1617, 1.6645, -0.7082, -0.1973, 1.259, -0.746, -0.7881, 1.6461, -0.7592, 0.1617, 1.436, -0.7221, -0.624, 1.436, -0.7221, -0.624, 1.6461, -0.7592, 0.1617, 1.5814, -0.7117, -0.4108, 0.9699, -0.5671, -1.2091, 0.8809, -0.6144, -1.19, 1.0502, -0.6021, -1.1682, 1.0502, -0.6021, -1.1682, 0.8809, -0.6144, -1.19, 1.1109, -0.6863, -1.0196, 1.1109, -0.6863, -1.0196, 0.8809, -0.6144, -1.19, 1.259, -0.746, -0.7881, 0.7765, -0.6276, -1.2561, -0.8459, -0.6965, -0.1217, 0.8809, -0.6144, -1.19, 1.259, -0.746, -0.7881, 1.2368, -0.9984, 0.9293, 1.6461, -0.7592, 0.1617) - -[node name="large_rock" instance=ExtResource("1_etns1")] - -[node name="LargeRock" parent="." index="0"] -surface_material_override/0 = ExtResource("2_fes1d") - -[node name="StaticBody3D" type="StaticBody3D" parent="LargeRock" index="0"] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="LargeRock/StaticBody3D" index="0"] -shape = SubResource("ConcavePolygonShape3D_6ssqc") diff --git a/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader b/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader deleted file mode 100644 index 9850b66..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader +++ /dev/null @@ -1,62 +0,0 @@ -shader_type spatial; - -render_mode depth_draw_opaque, cull_disabled; - -// Texture settings -uniform sampler2D texture_albedo : hint_default_white, repeat_disable; -uniform sampler2D texture_gradient : hint_default_white, repeat_disable; -uniform sampler2D texture_noise : hint_default_white; -uniform float alpha_scissor_threshold : hint_range(0.0, 1.0); -uniform vec4 transmission : source_color; -uniform vec4 secondary_color : source_color; -uniform float secondary_attenuation = 0.2; -uniform float grass_height = 1.0; - -// Wind settings -uniform vec2 wind_direction = vec2(1, -0.5); -uniform float wind_speed = 1.0; -uniform float wind_strength = 2.0; -uniform float noise_scale = 20.0; - -instance uniform float camera_bend_strength : hint_range(0.0, 3.0) = 0.2; - -varying float color; -varying float height; - -void vertex() { - height = VERTEX.y; - float influence = smoothstep(0, 1, height / 2.0); - vec4 world_pos = MODEL_MATRIX * vec4(VERTEX, 1.0); - vec2 uv = world_pos.xz / (noise_scale + 1e-2); - vec2 panning_uv = uv + fract(TIME * wind_direction * wind_speed); - float wind = texture(texture_noise, panning_uv).r * 2.0 - 0.4; - color = texture(texture_noise, uv).r; - - vec2 wind_offset = -wind_direction * wind_strength * influence * wind; - world_pos.xz += wind_offset; - world_pos.y -= wind * influence * smoothstep(0.0, height, wind_strength); - - //Push the top vertex away from the camera to bend the grass clump - float ndotv = 1.0 - dot(vec3(0.0, 1.0, 0.0), normalize(INV_VIEW_MATRIX[1].xyz)); - world_pos.xz += INV_VIEW_MATRIX[1].xz * camera_bend_strength * height * ndotv; - - vec4 local_pos = inverse(MODEL_MATRIX) * world_pos; - local_pos.x += wind_strength * influence * cos(TIME * 1.0) / 8.0; - local_pos.z += wind_strength * influence * sin(TIME * 1.5) / 8.0; - - VERTEX = local_pos.xyz; - //NORMAL = vec3(0.0, 1.0, 0.0); -} - -void fragment() { - vec4 tex = texture(texture_albedo, UV); - if (tex.a < alpha_scissor_threshold) { - discard; - } - - BACKLIGHT = transmission.rgb; - vec4 gradient = texture(texture_gradient, vec2(height / grass_height, 0.0)); - float secondary_weight = smoothstep(0.0, 1.0, color - secondary_attenuation); - ALBEDO = tex.rbg * gradient.rgb; - //ALBEDO = mix(ALBEDO, secondary_color.rgb, secondary_weight); -} diff --git a/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader.uid b/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader.uid deleted file mode 100644 index 87c430e..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/grass.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c6dnyceunecxm diff --git a/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader b/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader deleted file mode 100644 index ca84300..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader +++ /dev/null @@ -1,51 +0,0 @@ -shader_type spatial; - -render_mode depth_draw_opaque, cull_disabled; - -// Texture settings -uniform sampler2D texture_albedo : hint_default_white, repeat_disable; -uniform sampler2D texture_gradient : hint_default_white; -uniform sampler2D texture_noise : hint_default_white; -uniform float alpha_scissor_threshold : hint_range(0.0, 1.0); -uniform vec4 transmission : source_color; -uniform float total_height = 1.0; - -// Wind settings -uniform vec2 wind_direction = vec2(1, -0.5); -uniform float wind_speed = 1.0; -uniform float wind_strength = 2.0; -uniform float noise_scale = 20.0; - -varying float color; -varying float height; - -void vertex() { - height = VERTEX.y; - - vec4 world_pos = MODEL_MATRIX * vec4(VERTEX, 1.0); - vec2 uv = (world_pos.xz + VERTEX.yy) / (noise_scale + 1e-2) ; - vec2 panning_uv = uv + fract(TIME * wind_direction * wind_speed); - float wind = texture(texture_noise, panning_uv).r * 2.0 - 0.4; - color = texture(texture_noise, uv).r; - - float wind_influence = smoothstep(0, 1, 1.0 - UV.y); - vec2 wind_offset = -wind_direction * wind_strength * wind_influence * wind; - world_pos.xz += wind_offset; - world_pos.y -= wind * wind_influence * wind_strength * 0.45; - - vec4 local_pos = inverse(MODEL_MATRIX) * world_pos; - - VERTEX = local_pos.xyz; - //NORMAL = vec3(0.0, 1.0, 0.0); -} - -void fragment() { - vec4 tex = texture(texture_albedo, UV); - if (tex.a < alpha_scissor_threshold) { - discard; - } - - BACKLIGHT = transmission.rgb; - vec4 gradient = texture(texture_gradient, vec2(height / total_height, 0.0)); - ALBEDO = tex.rbg * gradient.rgb; -} diff --git a/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader.uid b/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader.uid deleted file mode 100644 index cff2869..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/leaves.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://do11ymehrpr2v diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_bush.tres b/godot/addons/proton_scatter/demos/assets/materials/m_bush.tres deleted file mode 100644 index d38f6e1..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_bush.tres +++ /dev/null @@ -1,37 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://bn3fr3m3glrnp"] - -[ext_resource type="Shader" path="res://addons/proton_scatter/demos/assets/materials/grass.gdshader" id="1_peshr"] -[ext_resource type="Texture2D" uid="uid://b2a6ylo2enm4g" path="res://addons/proton_scatter/demos/assets/textures/t_bush.png" id="2_mbhvd"] - -[sub_resource type="Gradient" id="Gradient_122hb"] -offsets = PackedFloat32Array(0, 0.5, 1) -colors = PackedColorArray(0.179688, 0.0759602, 0.0183228, 1, 0.386532, 0.390625, 0.0230687, 1, 1, 0.693237, 0.0687054, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_i0bw2"] -gradient = SubResource("Gradient_122hb") - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_eeqpx"] -seed = 1 -frequency = 0.002 - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_7l0n1"] -in_3d_space = true -seamless = true -seamless_blend_skirt = 0.65 -noise = SubResource("FastNoiseLite_eeqpx") - -[resource] -render_priority = 0 -shader = ExtResource("1_peshr") -shader_parameter/alpha_scissor_threshold = 0.25 -shader_parameter/transmission = Color(0.619608, 0.541176, 0.101961, 1) -shader_parameter/secondary_color = Color(0, 0, 0, 1) -shader_parameter/secondary_attenuation = 0.2 -shader_parameter/grass_height = 0.829 -shader_parameter/wind_direction = Vector2(1, -0.5) -shader_parameter/wind_speed = 0.5 -shader_parameter/wind_strength = 0.15 -shader_parameter/noise_scale = 6.0 -shader_parameter/texture_albedo = ExtResource("2_mbhvd") -shader_parameter/texture_gradient = SubResource("GradientTexture1D_i0bw2") -shader_parameter/texture_noise = SubResource("NoiseTexture2D_7l0n1") diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_fence.tres b/godot/addons/proton_scatter/demos/assets/materials/m_fence.tres deleted file mode 100644 index d2cedf3..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_fence.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="SpatialMaterial" format=2] - -[resource] -resource_name = "wood" -vertex_color_use_as_albedo = true -albedo_color = Color( 0.568627, 0.466667, 0.372549, 1 ) diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_grass.tres b/godot/addons/proton_scatter/demos/assets/materials/m_grass.tres deleted file mode 100644 index e9e922f..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_grass.tres +++ /dev/null @@ -1,37 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://c4mot1fo3siox"] - -[ext_resource type="Shader" path="res://addons/proton_scatter/demos/assets/materials/grass.gdshader" id="1_fntgl"] -[ext_resource type="Texture2D" uid="uid://d23p13yi7asw0" path="res://addons/proton_scatter/demos/assets/textures/t_grass_2.png" id="2_1odx0"] - -[sub_resource type="Gradient" id="Gradient_122hb"] -offsets = PackedFloat32Array(0, 0.473451, 1) -colors = PackedColorArray(0.179688, 0.0855483, 0.00322032, 1, 0.251693, 0.390625, 0.0117187, 1, 1, 0.964706, 0.129412, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_i0bw2"] -gradient = SubResource("Gradient_122hb") - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_eeqpx"] -seed = 1 -frequency = 0.002 - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_7l0n1"] -in_3d_space = true -seamless = true -seamless_blend_skirt = 0.65 -noise = SubResource("FastNoiseLite_eeqpx") - -[resource] -render_priority = 0 -shader = ExtResource("1_fntgl") -shader_parameter/alpha_scissor_threshold = 0.3 -shader_parameter/transmission = Color(0.737255, 0.72549, 0, 1) -shader_parameter/secondary_color = Color(0, 0, 0, 1) -shader_parameter/secondary_attenuation = 0.2 -shader_parameter/grass_height = 0.6 -shader_parameter/wind_direction = Vector2(1, -0.5) -shader_parameter/wind_speed = 0.5 -shader_parameter/wind_strength = 0.15 -shader_parameter/noise_scale = 6.0 -shader_parameter/texture_albedo = ExtResource("2_1odx0") -shader_parameter/texture_gradient = SubResource("GradientTexture1D_i0bw2") -shader_parameter/texture_noise = SubResource("NoiseTexture2D_7l0n1") diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_leaves.tres b/godot/addons/proton_scatter/demos/assets/materials/m_leaves.tres deleted file mode 100644 index a73f1c1..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_leaves.tres +++ /dev/null @@ -1,38 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://djo80ucamk643"] - -[ext_resource type="Shader" path="res://addons/proton_scatter/demos/assets/materials/grass.gdshader" id="1_8py1k"] -[ext_resource type="Texture2D" uid="uid://cgenco43aneod" path="res://addons/proton_scatter/demos/assets/textures/t_leaves_1.png" id="2_l2uea"] - -[sub_resource type="Gradient" id="Gradient_yy7fg"] -offsets = PackedFloat32Array(0, 0.726872, 0.934272) -colors = PackedColorArray(0.333333, 0.486275, 0.556863, 1, 0.496467, 0.55, 0.1485, 1, 0.898039, 0.670588, 0.0196078, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_rwvaq"] -gradient = SubResource("Gradient_yy7fg") - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_wpihy"] -seed = 1 -frequency = 0.002 - -[sub_resource type="NoiseTexture2D" id="NoiseTexture_tgrrr"] -in_3d_space = true -seamless = true -seamless_blend_skirt = 0.65 -noise = SubResource("FastNoiseLite_wpihy") - -[resource] -render_priority = 0 -shader = ExtResource("1_8py1k") -shader_parameter/alpha_scissor_threshold = 0.5 -shader_parameter/camera_bend_strength = 0.0 -shader_parameter/grass_height = 1.0 -shader_parameter/noise_scale = 12.0 -shader_parameter/secondary_attenuation = 0.2 -shader_parameter/secondary_color = Color(0, 0.305882, 0.211765, 1) -shader_parameter/texture_albedo = ExtResource("2_l2uea") -shader_parameter/texture_gradient = SubResource("GradientTexture1D_rwvaq") -shader_parameter/texture_noise = SubResource("NoiseTexture_tgrrr") -shader_parameter/transmission = Color(1, 0.975296, 0.943663, 1) -shader_parameter/wind_direction = Vector2(1, -0.5) -shader_parameter/wind_speed = 0.5 -shader_parameter/wind_strength = 0.05 diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_mushroom.tres b/godot/addons/proton_scatter/demos/assets/materials/m_mushroom.tres deleted file mode 100644 index 080c39c..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_mushroom.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ds2hjlo70hglg"] - -[ext_resource type="Texture2D" uid="uid://bjdgw8o5tr1a3" path="res://addons/proton_scatter/demos/assets/textures/mushroom.png" id="1_y0tuv"] - -[resource] -albedo_texture = ExtResource("1_y0tuv") diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_pine_leaves.tres b/godot/addons/proton_scatter/demos/assets/materials/m_pine_leaves.tres deleted file mode 100644 index 6815dae..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_pine_leaves.tres +++ /dev/null @@ -1,35 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=7 format=3 uid="uid://d28lq2qtgdyie"] - -[ext_resource type="Shader" path="res://addons/proton_scatter/demos/assets/materials/leaves.gdshader" id="1_hlncd"] -[ext_resource type="Texture2D" uid="uid://ctpb1w0cr8tqc" path="res://addons/proton_scatter/demos/assets/textures/t_pine_branch.png" id="2_yef44"] - -[sub_resource type="Gradient" id="Gradient_pookg"] -offsets = PackedFloat32Array(0.38342, 0.694301, 1) -colors = PackedColorArray(0.059375, 0.078125, 0.07, 1, 0.628287, 0.73, 0.1752, 1, 0.897921, 1, 0, 1) - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_n86jv"] -gradient = SubResource("Gradient_pookg") - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_t7o5y"] -seed = 1 -frequency = 0.002 - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_03p8g"] -in_3d_space = true -seamless = true -seamless_blend_skirt = 0.65 -noise = SubResource("FastNoiseLite_t7o5y") - -[resource] -render_priority = 0 -shader = ExtResource("1_hlncd") -shader_parameter/alpha_scissor_threshold = 0.3 -shader_parameter/transmission = Color(0.745098, 0.741176, 0, 1) -shader_parameter/total_height = 4.046 -shader_parameter/wind_direction = Vector2(1, -0.5) -shader_parameter/wind_speed = 0.2 -shader_parameter/wind_strength = 0.05 -shader_parameter/noise_scale = 12.0 -shader_parameter/texture_albedo = ExtResource("2_yef44") -shader_parameter/texture_gradient = SubResource("GradientTexture1D_n86jv") -shader_parameter/texture_noise = SubResource("NoiseTexture2D_03p8g") diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_rock.tres b/godot/addons/proton_scatter/demos/assets/materials/m_rock.tres deleted file mode 100644 index 6275bd2..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_rock.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://i0jgjmbbl2m5"] - -[ext_resource type="Texture2D" uid="uid://drdh36j6mu3ah" path="res://addons/proton_scatter/demos/assets/textures/t_rock_dirty.png" id="1_hx37f"] - -[resource] -albedo_color = Color(0.439216, 0.407843, 0.388235, 1) -albedo_texture = ExtResource("1_hx37f") -metallic_specular = 0.3 -uv1_triplanar = true -uv1_world_triplanar = true diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_trunk.tres b/godot/addons/proton_scatter/demos/assets/materials/m_trunk.tres deleted file mode 100644 index d9ddbde..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_trunk.tres +++ /dev/null @@ -1,7 +0,0 @@ -[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d01d0h08lqqn6"] - -[ext_resource type="Texture2D" uid="uid://c7pop5xgpxtiv" path="res://addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png" id="1_g4son"] - -[resource] -albedo_color = Color(0.470588, 0.376471, 0.309804, 1) -albedo_texture = ExtResource("1_g4son") diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader b/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader deleted file mode 100644 index cff66d1..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader +++ /dev/null @@ -1,90 +0,0 @@ -// Source: https://godotshaders.com/shader/toon-water-shader/ - -shader_type spatial; - -const float SMOOTHSTEP_AA = 0.01; -uniform sampler2D surfaceNoise; -uniform sampler2D distortNoise; -uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap; - -uniform float beer_factor = 0.8; - -uniform float foam_distance = 0.01; -uniform float foam_max_distance = 0.4; -uniform float foam_min_distance = 0.04; -uniform vec4 foam_color: source_color = vec4(1.0); - -uniform vec2 surface_noise_tiling = vec2(1.0, 4.0); -uniform vec3 surface_noise_scroll = vec3(0.03, 0.03, 0.0); -uniform float surface_noise_cutoff: hint_range(0, 1) = 0.777; -uniform float surface_distortion_amount: hint_range(0, 1) = 0.27; - -uniform vec4 _DepthGradientShallow: source_color = vec4(0.325, 0.807, 0.971, 0.725); -uniform vec4 _DepthGradientDeep: source_color = vec4(0.086, 0.407, 1, 0.749); -uniform float _DepthMaxDistance: hint_range(0, 1) = 1.0; -uniform float _DepthFactor = 1.0; - -uniform float roughness = 0.25; -uniform float specular = 0.75; - -varying vec2 noiseUV; -varying vec2 distortUV; -varying vec3 viewNormal; - - -vec4 alphaBlend(vec4 top, vec4 bottom) -{ - vec3 color = (top.rgb * top.a) + (bottom.rgb * (1.0 - top.a)); - float alpha = top.a + bottom.a * (1.0 - top.a); - - return vec4(color, alpha); -} - -void vertex() { - viewNormal = (MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz; - noiseUV = UV * surface_noise_tiling; - distortUV = UV; -} - -void fragment(){ - // https://www.youtube.com/watch?v=Jq3he9Lbj7M - float depthVal = texture(DEPTH_TEXTURE, SCREEN_UV).r; - float depth = PROJECTION_MATRIX[3][2] / (depthVal + PROJECTION_MATRIX[2][2]); - depth = depth + VERTEX.z; - depth = exp(-depth * beer_factor); - depth = 1.0 - depth; - - // Still unsure how to get properly the NORMAL from the camera - // This was generated by ChatGPT xD - vec4 view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depthVal, 1.0); - view_pos /= view_pos.w; - vec3 existingNormal = normalize(cross( dFdx(view_pos.xyz), dFdy(view_pos.xyz))); - - float normalDot = clamp(dot(existingNormal.xyz, viewNormal), 0.0, 1.0); - float foamDistance = mix(foam_max_distance, foam_min_distance, normalDot); - - float foamDepth = clamp(depth / foamDistance, 0.0, 1.0); - float surfaceNoiseCutoff = foamDepth * surface_noise_cutoff; - - vec4 distortNoiseSample = texture(distortNoise, distortUV); - vec2 distortAmount = (distortNoiseSample.xy * 2.0 -1.0) * surface_distortion_amount; - - vec2 noise_uv = vec2( - (noiseUV.x + TIME * surface_noise_scroll.x) + distortAmount.x , - (noiseUV.y + TIME * surface_noise_scroll.y + distortAmount.y) - ); - float surfaceNoiseSample = texture(surfaceNoise, noise_uv).r; - float surfaceNoiseAmount = smoothstep(surfaceNoiseCutoff - SMOOTHSTEP_AA, surfaceNoiseCutoff + SMOOTHSTEP_AA, surfaceNoiseSample); - - float waterDepth = clamp(depth / _DepthMaxDistance, 0.0, 1.0) * _DepthFactor; - vec4 waterColor = mix(_DepthGradientShallow, _DepthGradientDeep, waterDepth); - - vec4 surfaceNoiseColor = foam_color; - surfaceNoiseColor.a *= surfaceNoiseAmount; - vec4 color = alphaBlend(surfaceNoiseColor, waterColor); - - ALBEDO = color.rgb; - ALPHA = color.a; - ROUGHNESS = roughness; - SPECULAR = specular; -} \ No newline at end of file diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader.uid b/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader.uid deleted file mode 100644 index 1a1b630..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_water.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dq5uom8qujhma diff --git a/godot/addons/proton_scatter/demos/assets/materials/m_water.tres b/godot/addons/proton_scatter/demos/assets/materials/m_water.tres deleted file mode 100644 index 9dcd264..0000000 --- a/godot/addons/proton_scatter/demos/assets/materials/m_water.tres +++ /dev/null @@ -1,40 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=6 format=3 uid="uid://c7mw5tryqfggw"] - -[ext_resource type="Shader" path="res://addons/proton_scatter/demos/assets/materials/m_water.gdshader" id="1_j8rl3"] - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_7bjdc"] -noise_type = 2 -fractal_type = 3 - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_wxuht"] -seamless = true -noise = SubResource("FastNoiseLite_7bjdc") - -[sub_resource type="FastNoiseLite" id="FastNoiseLite_dx86n"] -noise_type = 2 -domain_warp_enabled = true - -[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_1j0ob"] -seamless = true -noise = SubResource("FastNoiseLite_dx86n") - -[resource] -render_priority = 0 -shader = ExtResource("1_j8rl3") -shader_parameter/beer_factor = 4.0 -shader_parameter/foam_distance = 0.01 -shader_parameter/foam_max_distance = 0.345 -shader_parameter/foam_min_distance = 0.05 -shader_parameter/foam_color = Color(1, 1, 1, 0.784314) -shader_parameter/surface_noise_tiling = Vector2(1, 4) -shader_parameter/surface_noise_scroll = Vector3(0.03, 0.03, 0) -shader_parameter/surface_noise_cutoff = 0.875 -shader_parameter/surface_distortion_amount = 0.65 -shader_parameter/_DepthGradientShallow = Color(0.435294, 0.647059, 0.972549, 0.72549) -shader_parameter/_DepthGradientDeep = Color(0.0823529, 0.392157, 0.701961, 0.862745) -shader_parameter/_DepthMaxDistance = 1.0 -shader_parameter/_DepthFactor = 1.0 -shader_parameter/roughness = 0.001 -shader_parameter/specular = 0.5 -shader_parameter/surfaceNoise = SubResource("NoiseTexture2D_1j0ob") -shader_parameter/distortNoise = SubResource("NoiseTexture2D_wxuht") diff --git a/godot/addons/proton_scatter/demos/assets/models/brick.glb b/godot/addons/proton_scatter/demos/assets/models/brick.glb deleted file mode 100644 index 0748793..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/brick.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/brick.glb.import b/godot/addons/proton_scatter/demos/assets/models/brick.glb.import deleted file mode 100644 index 4fa0288..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/brick.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://d1d1fag0m04yc" -path="res://.godot/imported/brick.glb-d79404ecf88b29143e6e07e77bacb44c.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/brick.glb" -dest_files=["res://.godot/imported/brick.glb-d79404ecf88b29143e6e07e77bacb44c.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/bush.glb b/godot/addons/proton_scatter/demos/assets/models/bush.glb deleted file mode 100644 index e25bf36..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/bush.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/bush.glb.import b/godot/addons/proton_scatter/demos/assets/models/bush.glb.import deleted file mode 100644 index 28c0637..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/bush.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://dbb4culid55v5" -path="res://.godot/imported/bush.glb-28e0128066fe8d913839a6b96204b1c6.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/bush.glb" -dest_files=["res://.godot/imported/bush.glb-28e0128066fe8d913839a6b96204b1c6.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb b/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb deleted file mode 100644 index de35d32..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb.import b/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb.import deleted file mode 100644 index 1305fdd..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/dead_branch.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://cmqlv88xp71tw" -path="res://.godot/imported/dead_branch.glb-e4e41ce877f1ef0b2d20a7b89af5de7b.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/dead_branch.glb" -dest_files=["res://.godot/imported/dead_branch.glb-e4e41ce877f1ef0b2d20a7b89af5de7b.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb b/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb deleted file mode 100644 index 2ac79fd..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb.import b/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb.import deleted file mode 100644 index b952e5c..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/fence_planks.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://6gxiul1pw13t" -path="res://.godot/imported/fence_planks.glb-4cee642c3e514323763ee9631fb323e9.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/fence_planks.glb" -dest_files=["res://.godot/imported/fence_planks.glb-4cee642c3e514323763ee9631fb323e9.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/gobot.glb b/godot/addons/proton_scatter/demos/assets/models/gobot.glb deleted file mode 100644 index f8a83fe..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/gobot.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/gobot.glb.import b/godot/addons/proton_scatter/demos/assets/models/gobot.glb.import deleted file mode 100644 index 2f10118..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/gobot.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://d3f4d3m7n8tpr" -path="res://.godot/imported/gobot.glb-36505aa16090f2bc2f34fbe5362f44e8.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/gobot.glb" -dest_files=["res://.godot/imported/gobot.glb-36505aa16090f2bc2f34fbe5362f44e8.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/grass.glb b/godot/addons/proton_scatter/demos/assets/models/grass.glb deleted file mode 100644 index f3a2f57..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/grass.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/grass.glb.import b/godot/addons/proton_scatter/demos/assets/models/grass.glb.import deleted file mode 100644 index d210c58..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/grass.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://018flajgtx7t" -path="res://.godot/imported/grass.glb-0ef73576363e4c601b9f45b1787e1487.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/grass.glb" -dest_files=["res://.godot/imported/grass.glb-0ef73576363e4c601b9f45b1787e1487.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/grass_2.glb b/godot/addons/proton_scatter/demos/assets/models/grass_2.glb deleted file mode 100644 index 8c20845..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/grass_2.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/grass_2.glb.import b/godot/addons/proton_scatter/demos/assets/models/grass_2.glb.import deleted file mode 100644 index 1d7082c..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/grass_2.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://dcnm2ijk7hj4j" -path="res://.godot/imported/grass_2.glb-2dc56a32acf64077863c701e8b94ea02.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/grass_2.glb" -dest_files=["res://.godot/imported/grass_2.glb-2dc56a32acf64077863c701e8b94ea02.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/large_rock.glb b/godot/addons/proton_scatter/demos/assets/models/large_rock.glb deleted file mode 100644 index e88cd6c..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/large_rock.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/large_rock.glb.import b/godot/addons/proton_scatter/demos/assets/models/large_rock.glb.import deleted file mode 100644 index 40d7d9a..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/large_rock.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://bxqkgplyoipsx" -path="res://.godot/imported/large_rock.glb-f7a7a73f49167cee4ed84e7342d1f507.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/large_rock.glb" -dest_files=["res://.godot/imported/large_rock.glb-f7a7a73f49167cee4ed84e7342d1f507.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb b/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb deleted file mode 100644 index 6fc402a..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb.import b/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb.import deleted file mode 100644 index fecb7b1..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/mushrooms.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://c38uugpgw7hjm" -path="res://.godot/imported/mushrooms.glb-64c83b02a53711f9983c978d53ab0f12.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/mushrooms.glb" -dest_files=["res://.godot/imported/mushrooms.glb-64c83b02a53711f9983c978d53ab0f12.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb b/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb deleted file mode 100644 index 2081573..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb.import b/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb.import deleted file mode 100644 index 56e5b19..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/pine_tree.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://bhums0j31gm5n" -path="res://.godot/imported/pine_tree.glb-662cc3d34707ccadde24f89b98fadf88.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/pine_tree.glb" -dest_files=["res://.godot/imported/pine_tree.glb-662cc3d34707ccadde24f89b98fadf88.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/small_rock.glb b/godot/addons/proton_scatter/demos/assets/models/small_rock.glb deleted file mode 100644 index f30897f..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/small_rock.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/small_rock.glb.import b/godot/addons/proton_scatter/demos/assets/models/small_rock.glb.import deleted file mode 100644 index 1c985bb..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/small_rock.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://b81l25tbebki4" -path="res://.godot/imported/small_rock.glb-9b9690e480edfa6e23f0243045338de9.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/small_rock.glb" -dest_files=["res://.godot/imported/small_rock.glb-9b9690e480edfa6e23f0243045338de9.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/models/tree.glb b/godot/addons/proton_scatter/demos/assets/models/tree.glb deleted file mode 100644 index 92e9012..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/models/tree.glb and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/models/tree.glb.import b/godot/addons/proton_scatter/demos/assets/models/tree.glb.import deleted file mode 100644 index 01995ce..0000000 --- a/godot/addons/proton_scatter/demos/assets/models/tree.glb.import +++ /dev/null @@ -1,42 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://c3mfolo7c5uvh" -path="res://.godot/imported/tree.glb-86fae6fb2428df7d74097b1a7c75b288.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/models/tree.glb" -dest_files=["res://.godot/imported/tree.glb-86fae6fb2428df7d74097b1a7c75b288.scn"] - -[params] - -nodes/root_type="Node3D" -nodes/root_name="Scene Root" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -gltf/naming_version=0 -gltf/embedded_image_handling=1 diff --git a/godot/addons/proton_scatter/demos/assets/mushroom.tscn b/godot/addons/proton_scatter/demos/assets/mushroom.tscn deleted file mode 100644 index ab23cea..0000000 --- a/godot/addons/proton_scatter/demos/assets/mushroom.tscn +++ /dev/null @@ -1,12 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bodkixm8bubes"] - -[ext_resource type="PackedScene" uid="uid://c38uugpgw7hjm" path="res://addons/proton_scatter/demos/assets/models/mushrooms.glb" id="1_spmys"] -[ext_resource type="Texture2D" uid="uid://bjdgw8o5tr1a3" path="res://addons/proton_scatter/demos/assets/textures/mushroom.png" id="2_ofsik"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_i5aqh"] -albedo_texture = ExtResource("2_ofsik") - -[node name="mushrooms" instance=ExtResource("1_spmys")] - -[node name="Sphere_001" parent="." index="0"] -material_override = SubResource("StandardMaterial3D_i5aqh") diff --git a/godot/addons/proton_scatter/demos/assets/pine_tree.tscn b/godot/addons/proton_scatter/demos/assets/pine_tree.tscn deleted file mode 100644 index 9f1b08c..0000000 --- a/godot/addons/proton_scatter/demos/assets/pine_tree.tscn +++ /dev/null @@ -1,31 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://caqxfqurbp3ku"] - -[ext_resource type="PackedScene" uid="uid://bhums0j31gm5n" path="res://addons/proton_scatter/demos/assets/models/pine_tree.glb" id="1_hw1e5"] -[ext_resource type="Material" uid="uid://d01d0h08lqqn6" path="res://addons/proton_scatter/demos/assets/materials/m_trunk.tres" id="2_cgtpc"] -[ext_resource type="Material" uid="uid://d28lq2qtgdyie" path="res://addons/proton_scatter/demos/assets/materials/m_pine_leaves.tres" id="2_xnytt"] - -[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2xqpo"] -radius = 0.0750397 -height = 1.3553 - -[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uhp33"] -radius = 0.101768 -height = 0.489166 - -[node name="pine_tree" instance=ExtResource("1_hw1e5")] - -[node name="Trunk" parent="." index="0"] -surface_material_override/0 = ExtResource("2_cgtpc") - -[node name="Leaves" parent="." index="1"] -surface_material_override/0 = ExtResource("2_xnytt") - -[node name="StaticBody3D" type="StaticBody3D" parent="." index="2"] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.661681, 0) -shape = SubResource("CapsuleShape3D_2xqpo") - -[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" index="1"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.015189, 0) -shape = SubResource("CapsuleShape3D_uhp33") diff --git a/godot/addons/proton_scatter/demos/assets/small_rock.tscn b/godot/addons/proton_scatter/demos/assets/small_rock.tscn deleted file mode 100644 index 2025b28..0000000 --- a/godot/addons/proton_scatter/demos/assets/small_rock.tscn +++ /dev/null @@ -1,9 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bltmr2xgs8nq1"] - -[ext_resource type="PackedScene" uid="uid://b81l25tbebki4" path="res://addons/proton_scatter/demos/assets/models/small_rock.glb" id="1_e2qk6"] -[ext_resource type="Material" uid="uid://i0jgjmbbl2m5" path="res://addons/proton_scatter/demos/assets/materials/m_rock.tres" id="2_clsfy"] - -[node name="small_rock" instance=ExtResource("1_e2qk6")] - -[node name="SmallRock" parent="." index="0"] -surface_material_override/0 = ExtResource("2_clsfy") diff --git a/godot/addons/proton_scatter/demos/assets/source.blend b/godot/addons/proton_scatter/demos/assets/source.blend deleted file mode 100644 index f973cf9..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/source.blend and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/source.blend.import b/godot/addons/proton_scatter/demos/assets/source.blend.import deleted file mode 100644 index 7ea86ba..0000000 --- a/godot/addons/proton_scatter/demos/assets/source.blend.import +++ /dev/null @@ -1,59 +0,0 @@ -[remap] - -importer="scene" -importer_version=1 -type="PackedScene" -uid="uid://bhnirs2kpt6kc" -path="res://.godot/imported/source.blend-6553bbdea542ba64489fdff7990920e8.scn" - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/source.blend" -dest_files=["res://.godot/imported/source.blend-6553bbdea542ba64489fdff7990920e8.scn"] - -[params] - -nodes/root_type="" -nodes/root_name="" -nodes/root_script=null -nodes/apply_root_scale=true -nodes/root_scale=1.0 -nodes/import_as_skeleton_bones=false -nodes/use_name_suffixes=true -nodes/use_node_type_suffixes=true -meshes/ensure_tangents=true -meshes/generate_lods=true -meshes/create_shadow_meshes=true -meshes/light_baking=1 -meshes/lightmap_texel_size=0.2 -meshes/force_disable_compression=false -skins/use_named_skins=true -animation/import=true -animation/fps=30 -animation/trimming=false -animation/remove_immutable_tracks=true -animation/import_rest_as_RESET=false -import_script/path="" -materials/extract=0 -materials/extract_format=0 -materials/extract_path="" -_subresources={} -blender/nodes/visible=0 -blender/nodes/active_collection_only=false -blender/nodes/punctual_lights=true -blender/nodes/cameras=true -blender/nodes/custom_properties=true -blender/nodes/modifiers=1 -blender/meshes/colors=false -blender/meshes/uvs=true -blender/meshes/normals=true -blender/meshes/export_geometry_nodes_instances=false -blender/meshes/tangents=true -blender/meshes/skins=2 -blender/meshes/export_bones_deforming_mesh_only=false -blender/materials/unpack_enabled=true -blender/materials/export_materials=1 -blender/animation/limit_playback=true -blender/animation/always_sample=true -blender/animation/group_tracks=true -gltf/naming_version=2 diff --git a/godot/addons/proton_scatter/demos/assets/textures/grid.png b/godot/addons/proton_scatter/demos/assets/textures/grid.png deleted file mode 100644 index c5bbc74..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/grid.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/grid.png.import b/godot/addons/proton_scatter/demos/assets/textures/grid.png.import deleted file mode 100644 index 18467eb..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/grid.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6xc5b38d25gf" -path.s3tc="res://.godot/imported/grid.png-491581bd748087c94a4b25c27dcb904c.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/grid.png" -dest_files=["res://.godot/imported/grid.png-491581bd748087c94a4b25c27dcb904c.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/mushroom.png b/godot/addons/proton_scatter/demos/assets/textures/mushroom.png deleted file mode 100644 index f1f960d..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/mushroom.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/mushroom.png.import b/godot/addons/proton_scatter/demos/assets/textures/mushroom.png.import deleted file mode 100644 index aaf966a..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/mushroom.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjdgw8o5tr1a3" -path.s3tc="res://.godot/imported/mushroom.png-36c0c492b0f6a79e2aa68780d9a86c03.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/mushroom.png" -dest_files=["res://.godot/imported/mushroom.png-36c0c492b0f6a79e2aa68780d9a86c03.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/sky_2.png b/godot/addons/proton_scatter/demos/assets/textures/sky_2.png deleted file mode 100644 index 921ae63..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/sky_2.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/sky_2.png.import b/godot/addons/proton_scatter/demos/assets/textures/sky_2.png.import deleted file mode 100644 index cdfb603..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/sky_2.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bgc5rl13dopuj" -path.s3tc="res://.godot/imported/sky_2.png-3246d9ba45b69131effdf515c69428b4.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/sky_2.png" -dest_files=["res://.godot/imported/sky_2.png-3246d9ba45b69131effdf515c69428b4.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_bush.png b/godot/addons/proton_scatter/demos/assets/textures/t_bush.png deleted file mode 100644 index 3afb9f9..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_bush.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_bush.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_bush.png.import deleted file mode 100644 index 30811c0..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_bush.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b2a6ylo2enm4g" -path.s3tc="res://.godot/imported/t_bush.png-644d0e155c07db6d89949c275e110f2a.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_bush.png" -dest_files=["res://.godot/imported/t_bush.png-644d0e155c07db6d89949c275e110f2a.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_grass.png b/godot/addons/proton_scatter/demos/assets/textures/t_grass.png deleted file mode 100644 index 2f712d4..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_grass.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_grass.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_grass.png.import deleted file mode 100644 index 903af27..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_grass.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c08mm3p2ehvr6" -path="res://.godot/imported/t_grass.png-2144df75763a0a189eba3035fc0b94aa.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_grass.png" -dest_files=["res://.godot/imported/t_grass.png-2144df75763a0a189eba3035fc0b94aa.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png b/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png deleted file mode 100644 index 346a5c1..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png.import deleted file mode 100644 index 6ec2d76..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_grass_2.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d23p13yi7asw0" -path.s3tc="res://.godot/imported/t_grass_2.png-e3f17c2ee365553e0f39f2b5865e73de.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_grass_2.png" -dest_files=["res://.godot/imported/t_grass_2.png-e3f17c2ee365553e0f39f2b5865e73de.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png b/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png deleted file mode 100644 index 1913781..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png.import deleted file mode 100644 index 7e90911..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_leaves_1.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://drmmcy11y7mho" -path.s3tc="res://.godot/imported/t_leaves_1.png-1d55b008d9a51575d696e027028d7b90.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_leaves_1.png" -dest_files=["res://.godot/imported/t_leaves_1.png-1d55b008d9a51575d696e027028d7b90.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png b/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png deleted file mode 100644 index 26ea314..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png.import deleted file mode 100644 index df1607d..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_pine_branch.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ctpb1w0cr8tqc" -path.s3tc="res://.godot/imported/t_pine_branch.png-912fabf99bebd2eee6af2f445a54650e.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_pine_branch.png" -dest_files=["res://.godot/imported/t_pine_branch.png-912fabf99bebd2eee6af2f445a54650e.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg b/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg deleted file mode 100644 index d709604..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg.import b/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg.import deleted file mode 100644 index e4ae01e..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_rock.jpg.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqa2jfs1jy0hq" -path.s3tc="res://.godot/imported/t_rock.jpg-ae52c049ee9fab72f1ddf136050fd9ee.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_rock.jpg" -dest_files=["res://.godot/imported/t_rock.jpg-ae52c049ee9fab72f1ddf136050fd9ee.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png b/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png deleted file mode 100644 index 69ef74c..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png.import deleted file mode 100644 index 2ccec6b..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_rock_dirty.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://drdh36j6mu3ah" -path.s3tc="res://.godot/imported/t_rock_dirty.png-da395e5af8ffe9e04730e7e21eb6a86a.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_rock_dirty.png" -dest_files=["res://.godot/imported/t_rock_dirty.png-da395e5af8ffe9e04730e7e21eb6a86a.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/assets/textures/t_sand.png b/godot/addons/proton_scatter/demos/assets/textures/t_sand.png deleted file mode 100644 index 244c60b..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_sand.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_sand.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_sand.png.import deleted file mode 100644 index 69d60c5..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_sand.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://sudhfhsu333v" -path="res://.godot/imported/t_sand.png-1294bc4057daa02a434527a7e90f8d41.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_sand.png" -dest_files=["res://.godot/imported/t_sand.png-1294bc4057daa02a434527a7e90f8d41.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png b/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png deleted file mode 100755 index 73529aa..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png.import deleted file mode 100644 index 6376353..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://uax7x76f73fx" -path="res://.godot/imported/t_tree_bark.png-7732e2f9079e9ae58b8ccd57e5fc6c8a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_tree_bark.png" -dest_files=["res://.godot/imported/t_tree_bark.png-7732e2f9079e9ae58b8ccd57e5fc6c8a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png b/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png deleted file mode 100644 index 80823c2..0000000 Binary files a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png and /dev/null differ diff --git a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png.import b/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png.import deleted file mode 100644 index ad4d708..0000000 --- a/godot/addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c7pop5xgpxtiv" -path.s3tc="res://.godot/imported/t_tree_bark_rough.png-e025145ebb3b5e0dd14e26284dc6cf59.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/demos/assets/textures/t_tree_bark_rough.png" -dest_files=["res://.godot/imported/t_tree_bark_rough.png-e025145ebb3b5e0dd14e26284dc6cf59.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/proton_scatter/demos/loading.gd b/godot/addons/proton_scatter/demos/loading.gd deleted file mode 100644 index 355cd80..0000000 --- a/godot/addons/proton_scatter/demos/loading.gd +++ /dev/null @@ -1,23 +0,0 @@ -@tool -extends Control - -# Hides the loading screen when the scatter nodes are ready. -# -# Every Scatter nodes emit a signal called "build_completed" when they are done -# generating their multimeshes. - -var _scatter_completed := false - - -func _ready() -> void: - # Show the loading screen, unless scatter is already done. - visible = not _scatter_completed - - -# In this example, the Grass is usually the last one to complete, so its -# 'build_completed' signal is connected to this method. -# You could also listen to multiple Scatter nodes and accumulate all the signals -# to be extra safe. How you handle this is up to you. -func _on_scatter_build_completed() -> void: - visible = false - _scatter_completed = true diff --git a/godot/addons/proton_scatter/demos/loading.gd.uid b/godot/addons/proton_scatter/demos/loading.gd.uid deleted file mode 100644 index 3a89aa4..0000000 --- a/godot/addons/proton_scatter/demos/loading.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dksp5ex42udcd diff --git a/godot/addons/proton_scatter/demos/showcase.tscn b/godot/addons/proton_scatter/demos/showcase.tscn deleted file mode 100644 index c134ba1..0000000 --- a/godot/addons/proton_scatter/demos/showcase.tscn +++ /dev/null @@ -1,768 +0,0 @@ -[gd_scene load_steps=79 format=3 uid="uid://dga4klregd82"] - -[ext_resource type="Texture2D" uid="uid://bgc5rl13dopuj" path="res://addons/proton_scatter/demos/assets/textures/sky_2.png" id="1_bp1wy"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter.gd" id="1_odnwj"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/modifier_stack.gd" id="2_wdwa6"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_item.gd" id="3_tn31i"] -[ext_resource type="Material" uid="uid://c7mw5tryqfggw" path="res://addons/proton_scatter/demos/assets/materials/m_water.tres" id="3_yrj3o"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_shape.gd" id="4_5klvy"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_grid.gd" id="4_cnevb"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/randomize_transforms.gd" id="5_h0430"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/path_shape.gd" id="8_vjeqj"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/sphere_shape.gd" id="9_mhcwm"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/box_shape.gd" id="11_lv5tc"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/relax.gd" id="12_04tbd"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/project_on_geometry.gd" id="13_s5uny"] -[ext_resource type="PackedScene" uid="uid://bmglbfn5jaubp" path="res://addons/proton_scatter/demos/assets/gobot.tscn" id="15_mnk3f"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_random.gd" id="15_terd0"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/randomize_rotation.gd" id="16_qmwrn"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/array.gd" id="17_2af2s"] -[ext_resource type="Script" path="res://addons/proton_scatter/demos/loading.gd" id="18_0clps"] - -[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_bxgb5"] -panorama = ExtResource("1_bp1wy") - -[sub_resource type="Sky" id="Sky_ju840"] -sky_material = SubResource("PanoramaSkyMaterial_bxgb5") - -[sub_resource type="Environment" id="Environment_1kod5"] -background_mode = 2 -background_energy_multiplier = 1.25 -sky = SubResource("Sky_ju840") -sky_rotation = Vector3(0, 1.13446, 0) -ambient_light_color = Color(0.352941, 0.215686, 0.529412, 1) -ambient_light_sky_contribution = 0.2 -ambient_light_energy = 0.5 -tonemap_mode = 3 -tonemap_white = 1.2 -glow_enabled = true -fog_enabled = true -fog_light_color = Color(0.243137, 0.411765, 0.607843, 1) -fog_light_energy = 1.8 -fog_density = 0.02 -fog_sky_affect = 0.05 -fog_height = 4.0 -fog_height_density = 0.02 -volumetric_fog_temporal_reprojection_enabled = false -adjustment_enabled = true -adjustment_contrast = 1.15 -adjustment_saturation = 1.1 - -[sub_resource type="PlaneMesh" id="PlaneMesh_84bvf"] -size = Vector2(300, 300) - -[sub_resource type="Resource" id="Resource_slkpd"] -script = ExtResource("4_cnevb") -spacing = Vector3(1.5, 2, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_hc5ta"] -script = ExtResource("5_h0430") -position = Vector3(0.173, 0.222, 0.918) -rotation = Vector3(10, 360, 10) -scale = Vector3(1.201, 0.399, 1.183) -enabled = true -override_global_seed = true -custom_seed = 10 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_4npfm"] -script = ExtResource("16_qmwrn") -rotation = Vector3(360, 0, 360) -snap_angle = Vector3(180, 0, 180) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_nl1d8"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_slkpd"), SubResource("Resource_hc5ta"), SubResource("Resource_4npfm")]) - -[sub_resource type="Curve3D" id="Curve3D_ew6qf"] -_data = { -"points": PackedVector3Array(3.80872, 0, 0.938568, -3.80872, 0, -0.938568, -5.23002, 0, 0.969148, -4.01273, -4.76837e-07, 0.319402, 4.01273, 4.76837e-07, -0.319402, -4.0201, 0, -3.87154, 0.483762, 0, -2.35326, -0.483762, 0, 2.35326, 2.27396, 0, -0.779812), -"tilts": PackedFloat32Array(0, 0, 0) -} -point_count = 3 - -[sub_resource type="Resource" id="Resource_ftiyl"] -script = ExtResource("8_vjeqj") -closed = true -thickness = 0.0 -curve = SubResource("Curve3D_ew6qf") - -[sub_resource type="Resource" id="Resource_egokv"] -script = ExtResource("4_cnevb") -spacing = Vector3(4, 4, 4) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_sfry4"] -script = ExtResource("5_h0430") -position = Vector3(10, 4, 10) -rotation = Vector3(10, 180, 10) -scale = Vector3(5, 5, 5) -enabled = true -override_global_seed = true -custom_seed = 25 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_lq5i4"] -script = ExtResource("16_qmwrn") -rotation = Vector3(360, 0, 360) -snap_angle = Vector3(180, 0, 180) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_56f0d"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_egokv"), SubResource("Resource_sfry4"), SubResource("Resource_lq5i4")]) - -[sub_resource type="Resource" id="Resource_1jvqx"] -script = ExtResource("11_lv5tc") -size = Vector3(29.1644, 1, 11.2962) - -[sub_resource type="Resource" id="Resource_k2idu"] -script = ExtResource("15_terd0") -amount = 14 -enabled = true -override_global_seed = true -custom_seed = 30 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_5juyu"] -script = ExtResource("12_04tbd") -iterations = 5 -offset_step = 0.1 -consecutive_step_multiplier = 0.5 -use_computeshader = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_8rpv2"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 1.0 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_le8k7"] -script = ExtResource("5_h0430") -position = Vector3(0, 0, 0) -rotation = Vector3(0, 0, 0) -scale = Vector3(3, 3, 3) -enabled = true -override_global_seed = true -custom_seed = 30 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_vl457"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_k2idu"), SubResource("Resource_5juyu"), SubResource("Resource_8rpv2"), SubResource("Resource_le8k7")]) - -[sub_resource type="Curve3D" id="Curve3D_p31po"] -_data = { -"points": PackedVector3Array(0, 0, 0, 0, 0, 0, -5.18137, -4.76837e-07, 0.742086, 0, 0, 0, 0, 0, 0, -6.91097, -2.38419e-07, -2.62414, 0, 0, 0, 0, 0, 0, 4.23263, 0, -2.10494, 0, 0, 0, 0, 0, 0, 4.13477, 0, -0.306146, 0, 0, 0, 0, 0, 0, -1.36184, 0, 1.16488), -"tilts": PackedFloat32Array(0, 0, 0, 0, 0) -} -point_count = 5 - -[sub_resource type="Resource" id="Resource_jto6x"] -script = ExtResource("8_vjeqj") -closed = true -thickness = 0.0 -curve = SubResource("Curve3D_p31po") - -[sub_resource type="Resource" id="Resource_5p0cc"] -script = ExtResource("15_terd0") -amount = 500 -enabled = true -override_global_seed = true -custom_seed = 7 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_25te8"] -script = ExtResource("5_h0430") -position = Vector3(0, 0, 0) -rotation = Vector3(360, 360, 360) -scale = Vector3(1.5, 1.5, 1.5) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_v0wvh"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 1.0 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ac5wm"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_5p0cc"), SubResource("Resource_25te8"), SubResource("Resource_v0wvh")]) - -[sub_resource type="Resource" id="Resource_0weea"] -script = ExtResource("11_lv5tc") -size = Vector3(11.3737, 0.642154, 5.57444) - -[sub_resource type="Resource" id="Resource_eq8kb"] -script = ExtResource("15_terd0") -amount = 10000 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_m4caw"] -script = ExtResource("5_h0430") -position = Vector3(0.2, 0, 0.2) -rotation = Vector3(20, 360, 20) -scale = Vector3(6, 5, 6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_i8m6m"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 1.0 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 20.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ywyik"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_eq8kb"), SubResource("Resource_m4caw"), SubResource("Resource_i8m6m")]) - -[sub_resource type="Resource" id="Resource_iou5c"] -script = ExtResource("9_mhcwm") -radius = 3.03782 - -[sub_resource type="Resource" id="Resource_llvm5"] -script = ExtResource("9_mhcwm") -radius = 2.15656 - -[sub_resource type="Resource" id="Resource_maxps"] -script = ExtResource("4_cnevb") -spacing = Vector3(0.2, 0.3, 0.2) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_5ics8"] -script = ExtResource("16_qmwrn") -rotation = Vector3(0, 360, 0) -snap_angle = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_ilaru"] -script = ExtResource("5_h0430") -position = Vector3(0, 0.107, 0) -rotation = Vector3(0, 360, 0) -scale = Vector3(0.75, 0.75, 0.75) -enabled = true -override_global_seed = true -custom_seed = 20 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_elisw"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, 0, 1) -ray_length = 1.0 -ray_offset = 0.5 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_01as6"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_maxps"), SubResource("Resource_5ics8"), SubResource("Resource_ilaru"), SubResource("Resource_elisw")]) - -[sub_resource type="Resource" id="Resource_272xj"] -script = ExtResource("11_lv5tc") -size = Vector3(1.64858, 0.539851, 0.847638) - -[sub_resource type="Resource" id="Resource_p1ngd"] -script = ExtResource("11_lv5tc") -size = Vector3(1.07363, 0.537276, 1.1214) - -[sub_resource type="Resource" id="Resource_is18q"] -script = ExtResource("11_lv5tc") -size = Vector3(2.15312, 0.683458, 0.916096) - -[sub_resource type="Resource" id="Resource_f0xq2"] -script = ExtResource("15_terd0") -amount = 150 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_txtls"] -script = ExtResource("5_h0430") -position = Vector3(0.058, 0, 0.086) -rotation = Vector3(360, 360, 360) -scale = Vector3(4, 4, 4) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_i0o45"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 1.0 -remove_points_on_miss = true -align_with_collision_normal = true -max_slope = 90.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_tmf4u"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_f0xq2"), SubResource("Resource_txtls"), SubResource("Resource_i0o45")]) - -[sub_resource type="Curve3D" id="Curve3D_lorvn"] -_data = { -"points": PackedVector3Array(0, 0, 0, 0, 0, 0, -3.37811, 0, 0.414886, 0, 0, 0, 0, 0, 0, -6.85248, 0, 0.176656, 0, 0, 0, 0, 0, 0, -6.65984, 0, -2.15071, 0, 0, 0, 0, 0, 0, 0.0761006, 0, -2.44185, 0, 0, 0, 0, 0, 0, 0.0166965, 0, -0.474161), -"tilts": PackedFloat32Array(0, 0, 0, 0, 0) -} -point_count = 5 - -[sub_resource type="Resource" id="Resource_ojpr0"] -script = ExtResource("8_vjeqj") -closed = true -thickness = 0.0 -curve = SubResource("Curve3D_lorvn") - -[sub_resource type="Resource" id="Resource_s5vim"] -script = ExtResource("15_terd0") -amount = 13 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_71r1e"] -script = ExtResource("12_04tbd") -iterations = 5 -offset_step = 0.02 -consecutive_step_multiplier = 0.35 -use_computeshader = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_7g71n"] -script = ExtResource("5_h0430") -position = Vector3(1, 1, 1) -rotation = Vector3(0, 360, 0) -scale = Vector3(0.2, 0.2, 0.2) -enabled = true -override_global_seed = true -custom_seed = 9 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_xgx45"] -script = ExtResource("13_s5uny") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 1.0 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -exclude_mask = 0 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_itou7"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_s5vim"), SubResource("Resource_71r1e"), SubResource("Resource_7g71n"), SubResource("Resource_xgx45")]) - -[sub_resource type="Resource" id="Resource_bpfxh"] -script = ExtResource("9_mhcwm") -radius = 1.57673 - -[sub_resource type="Resource" id="Resource_rspgw"] -script = ExtResource("9_mhcwm") -radius = 1.57673 - -[sub_resource type="Resource" id="Resource_rkfbt"] -script = ExtResource("4_cnevb") -spacing = Vector3(0.78, 2, 0.78) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_58g4b"] -script = ExtResource("17_2af2s") -amount = 1 -min_amount = -1 -local_offset = true -offset = Vector3(0.39, 0, 0) -local_rotation = false -rotation = Vector3(0, 0, 0) -individual_rotation_pivots = true -rotation_pivot = Vector3(0, 0, 0) -local_scale = true -scale = Vector3(1, 1, 1) -randomize_indices = false -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_187ca"] -script = ExtResource("17_2af2s") -amount = 1 -min_amount = -1 -local_offset = true -offset = Vector3(0.195, 0, 0.39) -local_rotation = false -rotation = Vector3(0, 0, 0) -individual_rotation_pivots = true -rotation_pivot = Vector3(0, 0, 0) -local_scale = true -scale = Vector3(1, 1, 1) -randomize_indices = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_3s5c4"] -script = ExtResource("5_h0430") -position = Vector3(0, 0.02, 0) -rotation = Vector3(0, 0, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_jft8j"] -script = ExtResource("2_wdwa6") -stack = Array[Resource("res://addons/proton_scatter/src/modifiers/base_modifier.gd")]([SubResource("Resource_rkfbt"), SubResource("Resource_58g4b"), SubResource("Resource_187ca"), SubResource("Resource_3s5c4")]) - -[sub_resource type="Resource" id="Resource_3agf6"] -script = ExtResource("11_lv5tc") -size = Vector3(3.74466, 1, 3.51889) - -[node name="ProtonScatterShowcase" type="Node3D"] -process_mode = 4 - -[node name="Lighting" type="Node3D" parent="."] - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Lighting"] -transform = Transform3D(0.422618, -0.383022, 0.821394, 0, 0.906308, 0.422618, -0.906308, -0.178606, 0.383022, 0, 2.29496, 0) -light_color = Color(1, 0.941176, 0.921569, 1) -light_energy = 2.0 -light_indirect_energy = 0.5 -shadow_enabled = true -shadow_opacity = 0.85 -shadow_blur = 0.2 -directional_shadow_max_distance = 20.0 - -[node name="WorldEnvironment" type="WorldEnvironment" parent="Lighting"] -environment = SubResource("Environment_1kod5") - -[node name="Camera3D" type="Camera3D" parent="Lighting"] -transform = Transform3D(1, 0, 0, 0, 0.98872, 0.149777, 0, -0.149777, 0.98872, -3.319, 2.435, 4.146) - -[node name="gobot" parent="." instance=ExtResource("15_mnk3f")] -transform = Transform3D(0.265388, -0.0494263, 0.420864, 0.0428064, 0.497174, 0.0313953, -0.421589, 0.0193675, 0.26812, -5.95323, 0.542806, 0.830116) - -[node name="Water" type="MeshInstance3D" parent="."] -material_override = ExtResource("3_yrj3o") -cast_shadow = 0 -mesh = SubResource("PlaneMesh_84bvf") -metadata/_edit_lock_ = true -metadata/_edit_group_ = true - -[node name="MainGround" type="Node3D" parent="."] -process_mode = 3 -script = ExtResource("1_odnwj") -render_mode = 1 -modifier_stack = SubResource("Resource_nl1d8") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="MainGround"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.4 -path = "res://addons/proton_scatter/demos/assets/large_rock.tscn" - -[node name="PathShape" type="Node3D" parent="MainGround"] -script = ExtResource("4_5klvy") -shape = SubResource("Resource_ftiyl") - -[node name="BackgroundMountain" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 68.323, 0, -80.067) -script = ExtResource("1_odnwj") -modifier_stack = SubResource("Resource_56f0d") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="BackgroundMountain"] -script = ExtResource("3_tn31i") -path = "res://addons/proton_scatter/demos/assets/large_rock.tscn" - -[node name="BoxShape" type="Node3D" parent="BackgroundMountain"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.41334, -0.086071, -0.341324) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_1jvqx") - -[node name="Trees" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.64893, 0, -0.774464) -script = ExtResource("1_odnwj") -render_mode = 1 -scatter_parent = NodePath("../MainGround") -modifier_stack = SubResource("Resource_vl457") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="Trees"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.4 -path = "res://addons/proton_scatter/demos/assets/pine_tree.tscn" - -[node name="PathShape" type="Node3D" parent="Trees"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0376822, 0, -0.0782702) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_jto6x") - -[node name="SmallRocks" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.58903, 0.624608, -1.05701) -script = ExtResource("1_odnwj") -scatter_parent = NodePath("../MainGround") -modifier_stack = SubResource("Resource_ac5wm") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="SmallRocks"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.2 -path = "res://addons/proton_scatter/demos/assets/small_rock.tscn" - -[node name="BoxShape" type="Node3D" parent="SmallRocks"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.279, -0.69077, 0.16165) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_0weea") - -[node name="Grass" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.53694, 0.590527, -0.866904) -script = ExtResource("1_odnwj") -scatter_parent = NodePath("../MainGround") -modifier_stack = SubResource("Resource_ywyik") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="Grass"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.15 -path = "res://addons/proton_scatter/demos/assets/grass_2.tscn" - -[node name="SphereShape" type="Node3D" parent="Grass"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.66162, 1.19209e-07, -0.977096) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_iou5c") - -[node name="SphereShape2" type="Node3D" parent="Grass"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.21329, 0.0320051, -0.71306) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_llvm5") - -[node name="Mushrooms" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.48012, 0.850601, -0.986201) -script = ExtResource("1_odnwj") -scatter_parent = NodePath("../Trees") -dbg_disable_thread = true -modifier_stack = SubResource("Resource_01as6") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="Mushrooms"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.2 -path = "res://addons/proton_scatter/demos/assets/mushroom.tscn" - -[node name="ScatterShape" type="Node3D" parent="Mushrooms"] -transform = Transform3D(0.992366, 0, 0.123324, -0.00806148, 0.997861, 0.0648693, -0.12306, -0.0653683, 0.990244, -0.545904, 0.200069, -0.0382232) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_272xj") - -[node name="ScatterShape2" type="Node3D" parent="Mushrooms"] -transform = Transform3D(0.702501, 0, 0.711683, 0, 1, 0, -0.711683, 0, 0.702501, -2.18823, 0.0800232, 0.866356) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_p1ngd") - -[node name="ScatterShape3" type="Node3D" parent="Mushrooms"] -transform = Transform3D(0.82657, 0, 0.562834, 0, 1, 0, -0.562834, 0, 0.82657, -2.31684, 0.0552569, -1.67132) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_is18q") - -[node name="DeadBranches" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.572101, 0) -script = ExtResource("1_odnwj") -scatter_parent = NodePath("../MainGround") -modifier_stack = SubResource("Resource_tmf4u") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="DeadBranches"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.6 -path = "res://addons/proton_scatter/demos/assets/dead_branch.tscn" - -[node name="ScatterShape" type="Node3D" parent="DeadBranches"] -script = ExtResource("4_5klvy") -shape = SubResource("Resource_ojpr0") - -[node name="Bushes" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.222831, 0.534039, -1.07373) -script = ExtResource("1_odnwj") -modifier_stack = SubResource("Resource_itou7") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="Bushes"] -script = ExtResource("3_tn31i") -source_scale_multiplier = 0.7 -path = "res://addons/proton_scatter/demos/assets/bush.tscn" - -[node name="ScatterShape" type="Node3D" parent="Bushes"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.300213, 4.76837e-07, -0.398241) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_bpfxh") - -[node name="ScatterShape2" type="Node3D" parent="Bushes"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.9127, 4.76837e-07, -1.13497) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_rspgw") - -[node name="Platform" type="Node3D" parent="."] -process_mode = 3 -transform = Transform3D(0.330514, 0, 0.943801, 0, 1, 0, -0.943801, 0, 0.330514, -12.248, 0, -5.402) -script = ExtResource("1_odnwj") -dbg_disable_thread = true -modifier_stack = SubResource("Resource_jft8j") -Performance/use_chunks = true -Performance/chunk_dimensions = Vector3(15, 15, 15) - -[node name="ScatterItem" type="Node3D" parent="Platform"] -script = ExtResource("3_tn31i") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Platform"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.248102, 0, 0.914603) -script = ExtResource("4_5klvy") -shape = SubResource("Resource_3agf6") - -[node name="LoadingScreen" type="PanelContainer" parent="."] -visible = false -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("18_0clps") - -[node name="Label" type="Label" parent="LoadingScreen"] -layout_mode = 2 -size_flags_horizontal = 4 -text = "Loading" - -[connection signal="build_completed" from="Grass" to="LoadingScreen" method="_on_scatter_build_completed"] diff --git a/godot/addons/proton_scatter/icons/add.svg b/godot/addons/proton_scatter/icons/add.svg deleted file mode 100644 index a241829..0000000 --- a/godot/addons/proton_scatter/icons/add.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/add.svg.import b/godot/addons/proton_scatter/icons/add.svg.import deleted file mode 100644 index b170ab9..0000000 --- a/godot/addons/proton_scatter/icons/add.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cun73k8jdmr4e" -path="res://.godot/imported/add.svg-c8c46053442728f2bca87eb859e046e7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/add.svg" -dest_files=["res://.godot/imported/add.svg-c8c46053442728f2bca87eb859e046e7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/arrow_down.svg b/godot/addons/proton_scatter/icons/arrow_down.svg deleted file mode 100644 index fac4a77..0000000 --- a/godot/addons/proton_scatter/icons/arrow_down.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - diff --git a/godot/addons/proton_scatter/icons/arrow_down.svg.import b/godot/addons/proton_scatter/icons/arrow_down.svg.import deleted file mode 100644 index 524a318..0000000 --- a/godot/addons/proton_scatter/icons/arrow_down.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://t8c6kjbvst0s" -path="res://.godot/imported/arrow_down.svg-94d8c386a02d5ab5968e7f312ec47343.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/arrow_down.svg" -dest_files=["res://.godot/imported/arrow_down.svg-94d8c386a02d5ab5968e7f312ec47343.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/arrow_exp.svg b/godot/addons/proton_scatter/icons/arrow_exp.svg deleted file mode 100644 index 41a4cf0..0000000 --- a/godot/addons/proton_scatter/icons/arrow_exp.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/arrow_exp.svg.import b/godot/addons/proton_scatter/icons/arrow_exp.svg.import deleted file mode 100644 index c28ad1c..0000000 --- a/godot/addons/proton_scatter/icons/arrow_exp.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bmya2s68yulpy" -path="res://.godot/imported/arrow_exp.svg-fd5b1563541a12b14d65e57fc0f36590.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/arrow_exp.svg" -dest_files=["res://.godot/imported/arrow_exp.svg-fd5b1563541a12b14d65e57fc0f36590.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/arrow_linear.svg b/godot/addons/proton_scatter/icons/arrow_linear.svg deleted file mode 100644 index caacb92..0000000 --- a/godot/addons/proton_scatter/icons/arrow_linear.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/arrow_linear.svg.import b/godot/addons/proton_scatter/icons/arrow_linear.svg.import deleted file mode 100644 index 40de8b4..0000000 --- a/godot/addons/proton_scatter/icons/arrow_linear.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bm7lc1p200gub" -path="res://.godot/imported/arrow_linear.svg-70f906a141e572f767722ba1a068dc9c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/arrow_linear.svg" -dest_files=["res://.godot/imported/arrow_linear.svg-70f906a141e572f767722ba1a068dc9c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/arrow_log.svg b/godot/addons/proton_scatter/icons/arrow_log.svg deleted file mode 100644 index 4de912c..0000000 --- a/godot/addons/proton_scatter/icons/arrow_log.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/arrow_log.svg.import b/godot/addons/proton_scatter/icons/arrow_log.svg.import deleted file mode 100644 index fd77c92..0000000 --- a/godot/addons/proton_scatter/icons/arrow_log.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bddikp3dyx8cb" -path="res://.godot/imported/arrow_log.svg-96f79bb83be8195a3bfdf4d6bc1ab504.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/arrow_log.svg" -dest_files=["res://.godot/imported/arrow_log.svg-96f79bb83be8195a3bfdf4d6bc1ab504.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/arrow_right.svg b/godot/addons/proton_scatter/icons/arrow_right.svg deleted file mode 100644 index 3316c55..0000000 --- a/godot/addons/proton_scatter/icons/arrow_right.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - diff --git a/godot/addons/proton_scatter/icons/arrow_right.svg.import b/godot/addons/proton_scatter/icons/arrow_right.svg.import deleted file mode 100644 index 0c87a40..0000000 --- a/godot/addons/proton_scatter/icons/arrow_right.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cu2t8yylseggu" -path="res://.godot/imported/arrow_right.svg-6771a48f7c1fe79d13059447d2bf9f07.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/arrow_right.svg" -dest_files=["res://.godot/imported/arrow_right.svg-6771a48f7c1fe79d13059447d2bf9f07.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/cache.svg b/godot/addons/proton_scatter/icons/cache.svg deleted file mode 100644 index e45ad80..0000000 --- a/godot/addons/proton_scatter/icons/cache.svg +++ /dev/null @@ -1,69 +0,0 @@ - - diff --git a/godot/addons/proton_scatter/icons/cache.svg.import b/godot/addons/proton_scatter/icons/cache.svg.import deleted file mode 100644 index 2931ecf..0000000 --- a/godot/addons/proton_scatter/icons/cache.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b4op5ha8qjlma" -path="res://.godot/imported/cache.svg-cb20e369c40cb12fb2d5b9a87ba41311.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/cache.svg" -dest_files=["res://.godot/imported/cache.svg-cb20e369c40cb12fb2d5b9a87ba41311.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/checker.png b/godot/addons/proton_scatter/icons/checker.png deleted file mode 100644 index 9abdc75..0000000 Binary files a/godot/addons/proton_scatter/icons/checker.png and /dev/null differ diff --git a/godot/addons/proton_scatter/icons/checker.png.import b/godot/addons/proton_scatter/icons/checker.png.import deleted file mode 100644 index 2a4933b..0000000 --- a/godot/addons/proton_scatter/icons/checker.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bftnx7jk6thqp" -path="res://.godot/imported/checker.png-9f555d2536e1ecfbf8f3b94004e5deef.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/checker.png" -dest_files=["res://.godot/imported/checker.png-9f555d2536e1ecfbf8f3b94004e5deef.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/icons/clear.svg b/godot/addons/proton_scatter/icons/clear.svg deleted file mode 100644 index 43c0031..0000000 --- a/godot/addons/proton_scatter/icons/clear.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/clear.svg.import b/godot/addons/proton_scatter/icons/clear.svg.import deleted file mode 100644 index ab1782a..0000000 --- a/godot/addons/proton_scatter/icons/clear.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bosx22dy64f11" -path="res://.godot/imported/clear.svg-46e0566a8856183197fd37d5ccb84c9b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/clear.svg" -dest_files=["res://.godot/imported/clear.svg-46e0566a8856183197fd37d5ccb84c9b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/close.svg b/godot/addons/proton_scatter/icons/close.svg deleted file mode 100644 index 4147c7b..0000000 --- a/godot/addons/proton_scatter/icons/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/close.svg.import b/godot/addons/proton_scatter/icons/close.svg.import deleted file mode 100644 index 8be71a0..0000000 --- a/godot/addons/proton_scatter/icons/close.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dahwdjl2er75o" -path="res://.godot/imported/close.svg-19437f97d2c1854efc880c19f78fe32e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/close.svg" -dest_files=["res://.godot/imported/close.svg-19437f97d2c1854efc880c19f78fe32e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/curve_close.svg b/godot/addons/proton_scatter/icons/curve_close.svg deleted file mode 100644 index 032f1c6..0000000 --- a/godot/addons/proton_scatter/icons/curve_close.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/curve_close.svg.import b/godot/addons/proton_scatter/icons/curve_close.svg.import deleted file mode 100644 index 08bf121..0000000 --- a/godot/addons/proton_scatter/icons/curve_close.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b7dw1ytimyv2h" -path="res://.godot/imported/curve_close.svg-c3f2c4c26453437a3980b5393ad526e4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/curve_close.svg" -dest_files=["res://.godot/imported/curve_close.svg-c3f2c4c26453437a3980b5393ad526e4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/curve_create.svg b/godot/addons/proton_scatter/icons/curve_create.svg deleted file mode 100644 index 1181111..0000000 --- a/godot/addons/proton_scatter/icons/curve_create.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/curve_create.svg.import b/godot/addons/proton_scatter/icons/curve_create.svg.import deleted file mode 100644 index 1a4036e..0000000 --- a/godot/addons/proton_scatter/icons/curve_create.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmykha5ja17vj" -path="res://.godot/imported/curve_create.svg-6aa0ae777579eb233f93eae8cfc9ae81.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/curve_create.svg" -dest_files=["res://.godot/imported/curve_create.svg-6aa0ae777579eb233f93eae8cfc9ae81.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/curve_delete.svg b/godot/addons/proton_scatter/icons/curve_delete.svg deleted file mode 100644 index 901a08e..0000000 --- a/godot/addons/proton_scatter/icons/curve_delete.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/curve_delete.svg.import b/godot/addons/proton_scatter/icons/curve_delete.svg.import deleted file mode 100644 index 15b06dc..0000000 --- a/godot/addons/proton_scatter/icons/curve_delete.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cligdljx1ad5e" -path="res://.godot/imported/curve_delete.svg-8346b842c26eae7708985a1205d56c1f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/curve_delete.svg" -dest_files=["res://.godot/imported/curve_delete.svg-8346b842c26eae7708985a1205d56c1f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/curve_select.svg b/godot/addons/proton_scatter/icons/curve_select.svg deleted file mode 100644 index 8f09ca6..0000000 --- a/godot/addons/proton_scatter/icons/curve_select.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/curve_select.svg.import b/godot/addons/proton_scatter/icons/curve_select.svg.import deleted file mode 100644 index 88521bf..0000000 --- a/godot/addons/proton_scatter/icons/curve_select.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c1t5x34pc4vs5" -path="res://.godot/imported/curve_select.svg-9a34ca2f976ba8714813d2d2842c56d9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/curve_select.svg" -dest_files=["res://.godot/imported/curve_select.svg-9a34ca2f976ba8714813d2d2842c56d9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/dice.svg b/godot/addons/proton_scatter/icons/dice.svg deleted file mode 100644 index 214a745..0000000 --- a/godot/addons/proton_scatter/icons/dice.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/dice.svg.import b/godot/addons/proton_scatter/icons/dice.svg.import deleted file mode 100644 index 8b0f4b2..0000000 --- a/godot/addons/proton_scatter/icons/dice.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dmmefjvrdhf78" -path="res://.godot/imported/dice.svg-a3afbfd7a5e5fcaee218362e12214844.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/dice.svg" -dest_files=["res://.godot/imported/dice.svg-a3afbfd7a5e5fcaee218362e12214844.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/disabled.svg.import b/godot/addons/proton_scatter/icons/disabled.svg.import deleted file mode 100644 index 8097f19..0000000 --- a/godot/addons/proton_scatter/icons/disabled.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bs1fqiny4gnuh" -path="res://.godot/imported/disabled.svg-243ccf1f821ecaaa0c9f25c00a10ad6e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/disabled.svg" -dest_files=["res://.godot/imported/disabled.svg-243ccf1f821ecaaa0c9f25c00a10ad6e.ctex"] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/bptc_ldr=0 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -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/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 diff --git a/godot/addons/proton_scatter/icons/doc.svg b/godot/addons/proton_scatter/icons/doc.svg deleted file mode 100644 index 89c8735..0000000 --- a/godot/addons/proton_scatter/icons/doc.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/doc.svg.import b/godot/addons/proton_scatter/icons/doc.svg.import deleted file mode 100644 index 6806147..0000000 --- a/godot/addons/proton_scatter/icons/doc.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://do8d3urxirjoa" -path="res://.godot/imported/doc.svg-c884c073ce3af0f82fb9ddd41a433df9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/doc.svg" -dest_files=["res://.godot/imported/doc.svg-c884c073ce3af0f82fb9ddd41a433df9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/documentation.svg b/godot/addons/proton_scatter/icons/documentation.svg deleted file mode 100644 index 113612b..0000000 --- a/godot/addons/proton_scatter/icons/documentation.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - diff --git a/godot/addons/proton_scatter/icons/documentation.svg.import b/godot/addons/proton_scatter/icons/documentation.svg.import deleted file mode 100644 index 8c6a857..0000000 --- a/godot/addons/proton_scatter/icons/documentation.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://06vw5f8awtr6" -path="res://.godot/imported/documentation.svg-b993be041793a6dc87d64c5610aff12d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/documentation.svg" -dest_files=["res://.godot/imported/documentation.svg-b993be041793a6dc87d64c5610aff12d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/down.svg.import b/godot/addons/proton_scatter/icons/down.svg.import deleted file mode 100644 index 5303f0e..0000000 --- a/godot/addons/proton_scatter/icons/down.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://pnkkrn8h6eun" -path="res://.godot/imported/down.svg-4ff1b431a92a8a32e3f77e063ceb84e2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/down.svg" -dest_files=["res://.godot/imported/down.svg-4ff1b431a92a8a32e3f77e063ceb84e2.ctex"] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/bptc_ldr=0 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -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/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 diff --git a/godot/addons/proton_scatter/icons/drag_area.svg b/godot/addons/proton_scatter/icons/drag_area.svg deleted file mode 100644 index 43efb22..0000000 --- a/godot/addons/proton_scatter/icons/drag_area.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/drag_area.svg.import b/godot/addons/proton_scatter/icons/drag_area.svg.import deleted file mode 100644 index c87a65e..0000000 --- a/godot/addons/proton_scatter/icons/drag_area.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ba6cx70dyeuhg" -path="res://.godot/imported/drag_area.svg-b54df88063d806fbe992617a87621f6f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/drag_area.svg" -dest_files=["res://.godot/imported/drag_area.svg-b54df88063d806fbe992617a87621f6f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/duplicate.svg b/godot/addons/proton_scatter/icons/duplicate.svg deleted file mode 100644 index d258f5a..0000000 --- a/godot/addons/proton_scatter/icons/duplicate.svg +++ /dev/null @@ -1,44 +0,0 @@ - - diff --git a/godot/addons/proton_scatter/icons/duplicate.svg.import b/godot/addons/proton_scatter/icons/duplicate.svg.import deleted file mode 100644 index 71ba8d4..0000000 --- a/godot/addons/proton_scatter/icons/duplicate.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d2ajwyebaobjt" -path="res://.godot/imported/duplicate.svg-01a6fe9bb8397972ec3661dd5bf196ff.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/duplicate.svg" -dest_files=["res://.godot/imported/duplicate.svg-01a6fe9bb8397972ec3661dd5bf196ff.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/enabled.svg.import b/godot/addons/proton_scatter/icons/enabled.svg.import deleted file mode 100644 index a4ac5a5..0000000 --- a/godot/addons/proton_scatter/icons/enabled.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://pqr6rieoatt2" -path="res://.godot/imported/enabled.svg-3ee60e316a7df006c36d7328b1ff7080.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/enabled.svg" -dest_files=["res://.godot/imported/enabled.svg-3ee60e316a7df006c36d7328b1ff7080.ctex"] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/bptc_ldr=0 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -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/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 diff --git a/godot/addons/proton_scatter/icons/exclude_path.svg b/godot/addons/proton_scatter/icons/exclude_path.svg deleted file mode 100644 index 05866e3..0000000 --- a/godot/addons/proton_scatter/icons/exclude_path.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/exclude_path.svg.import b/godot/addons/proton_scatter/icons/exclude_path.svg.import deleted file mode 100644 index 3d92aab..0000000 --- a/godot/addons/proton_scatter/icons/exclude_path.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bs4q8qewsd62t" -path="res://.godot/imported/exclude_path.svg-37e9f158a2b3b23dcb473984cd7d4d35.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/exclude_path.svg" -dest_files=["res://.godot/imported/exclude_path.svg-37e9f158a2b3b23dcb473984cd7d4d35.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/global.svg b/godot/addons/proton_scatter/icons/global.svg deleted file mode 100644 index d23299e..0000000 --- a/godot/addons/proton_scatter/icons/global.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - diff --git a/godot/addons/proton_scatter/icons/global.svg.import b/godot/addons/proton_scatter/icons/global.svg.import deleted file mode 100644 index 12ac4ab..0000000 --- a/godot/addons/proton_scatter/icons/global.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://71efqwg3d70v" -path="res://.godot/imported/global.svg-e31c6e1d6185e37600fc56d0988ca1ec.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/global.svg" -dest_files=["res://.godot/imported/global.svg-e31c6e1d6185e37600fc56d0988ca1ec.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/group.svg b/godot/addons/proton_scatter/icons/group.svg deleted file mode 100644 index 5ec0350..0000000 --- a/godot/addons/proton_scatter/icons/group.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/group.svg.import b/godot/addons/proton_scatter/icons/group.svg.import deleted file mode 100644 index a7d311a..0000000 --- a/godot/addons/proton_scatter/icons/group.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ve232bobw4m8" -path="res://.godot/imported/group.svg-f9589c135a827f809b97184ab4d53826.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/group.svg" -dest_files=["res://.godot/imported/group.svg-f9589c135a827f809b97184ab4d53826.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/individual_instances.svg b/godot/addons/proton_scatter/icons/individual_instances.svg deleted file mode 100644 index 2d9f63b..0000000 --- a/godot/addons/proton_scatter/icons/individual_instances.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - categories - - - - categories - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/individual_instances.svg.import b/godot/addons/proton_scatter/icons/individual_instances.svg.import deleted file mode 100644 index 8e23de9..0000000 --- a/godot/addons/proton_scatter/icons/individual_instances.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vxd0iun0wq8i" -path="res://.godot/imported/individual_instances.svg-6f2d7e070dd53c64d21912e2f021ebd5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/individual_instances.svg" -dest_files=["res://.godot/imported/individual_instances.svg-6f2d7e070dd53c64d21912e2f021ebd5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/item.svg b/godot/addons/proton_scatter/icons/item.svg deleted file mode 100644 index 8bc141c..0000000 --- a/godot/addons/proton_scatter/icons/item.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/item.svg.import b/godot/addons/proton_scatter/icons/item.svg.import deleted file mode 100644 index 33ec19a..0000000 --- a/godot/addons/proton_scatter/icons/item.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://xcj2f4ik1law" -path="res://.godot/imported/item.svg-6af5bcafcf0e1297ab1d55a0f7c9cd35.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/item.svg" -dest_files=["res://.godot/imported/item.svg-6af5bcafcf0e1297ab1d55a0f7c9cd35.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/link.svg b/godot/addons/proton_scatter/icons/link.svg deleted file mode 100644 index 909c3af..0000000 --- a/godot/addons/proton_scatter/icons/link.svg +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - diff --git a/godot/addons/proton_scatter/icons/link.svg.import b/godot/addons/proton_scatter/icons/link.svg.import deleted file mode 100644 index 42f5b76..0000000 --- a/godot/addons/proton_scatter/icons/link.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://gbrmse47gdxb" -path="res://.godot/imported/link.svg-15b5849f7b24eb1c738ea9cc78c1b9b4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/link.svg" -dest_files=["res://.godot/imported/link.svg-15b5849f7b24eb1c738ea9cc78c1b9b4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/load.svg b/godot/addons/proton_scatter/icons/load.svg deleted file mode 100644 index 7ee6ae2..0000000 --- a/godot/addons/proton_scatter/icons/load.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/load.svg.import b/godot/addons/proton_scatter/icons/load.svg.import deleted file mode 100644 index 9619b17..0000000 --- a/godot/addons/proton_scatter/icons/load.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ddjrq1h4mkn6a" -path="res://.godot/imported/load.svg-0da8e4247aad5735085e117978c315ac.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/load.svg" -dest_files=["res://.godot/imported/load.svg-0da8e4247aad5735085e117978c315ac.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/m_loading.tres b/godot/addons/proton_scatter/icons/loading/m_loading.tres deleted file mode 100644 index 19ce324..0000000 --- a/godot/addons/proton_scatter/icons/loading/m_loading.tres +++ /dev/null @@ -1,20 +0,0 @@ -[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://do5bc6dg6mp4u"] - -[ext_resource type="Texture2D" uid="uid://dev74yqbbxjc6" path="res://addons/proton_scatter/icons/loading/t_loading.tres" id="1_7rsk1"] - -[resource] -render_priority = 120 -transparency = 1 -blend_mode = 1 -depth_draw_mode = 2 -no_depth_test = true -disable_ambient_light = true -albedo_color = Color(1, 0.498039, 0, 1) -albedo_texture = ExtResource("1_7rsk1") -emission_enabled = true -emission = Color(1, 0.411765, 0, 1) -emission_energy_multiplier = 3.5 -disable_receive_shadows = true -billboard_mode = 1 -fixed_size = true -point_size = 24.8 diff --git a/godot/addons/proton_scatter/icons/loading/progress1.svg b/godot/addons/proton_scatter/icons/loading/progress1.svg deleted file mode 100644 index 07505dd..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress1.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress1.svg.import b/godot/addons/proton_scatter/icons/loading/progress1.svg.import deleted file mode 100644 index 6cb3938..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress1.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bxaffg1bqa2jk" -path.s3tc="res://.godot/imported/progress1.svg-be0037fbccf447743f8ef8f47a7c0ee2.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress1.svg" -dest_files=["res://.godot/imported/progress1.svg-be0037fbccf447743f8ef8f47a7c0ee2.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress2.svg b/godot/addons/proton_scatter/icons/loading/progress2.svg deleted file mode 100644 index 0a48f7d..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress2.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress2.svg.import b/godot/addons/proton_scatter/icons/loading/progress2.svg.import deleted file mode 100644 index d0e0fd8..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress2.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dt36cq4i6vxbp" -path.s3tc="res://.godot/imported/progress2.svg-fe953d9d0296f6129c15dc4d732f5036.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress2.svg" -dest_files=["res://.godot/imported/progress2.svg-fe953d9d0296f6129c15dc4d732f5036.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress3.svg b/godot/addons/proton_scatter/icons/loading/progress3.svg deleted file mode 100644 index a7f0f9c..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress3.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress3.svg.import b/godot/addons/proton_scatter/icons/loading/progress3.svg.import deleted file mode 100644 index 8cf5d1b..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress3.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c0xe1mmwhexf3" -path.s3tc="res://.godot/imported/progress3.svg-9b96e4f9ec9592ba4e14d1fca5e2edaf.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress3.svg" -dest_files=["res://.godot/imported/progress3.svg-9b96e4f9ec9592ba4e14d1fca5e2edaf.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress4.svg b/godot/addons/proton_scatter/icons/loading/progress4.svg deleted file mode 100644 index 1719209..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress4.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress4.svg.import b/godot/addons/proton_scatter/icons/loading/progress4.svg.import deleted file mode 100644 index 216fd64..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress4.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b55ls3njsgrix" -path.s3tc="res://.godot/imported/progress4.svg-e2235c67c95e8b1b5d94112afa435dbe.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress4.svg" -dest_files=["res://.godot/imported/progress4.svg-e2235c67c95e8b1b5d94112afa435dbe.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress5.svg b/godot/addons/proton_scatter/icons/loading/progress5.svg deleted file mode 100644 index 7289b7b..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress5.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress5.svg.import b/godot/addons/proton_scatter/icons/loading/progress5.svg.import deleted file mode 100644 index 9c49b61..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress5.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://fq4k4ug1df24" -path.s3tc="res://.godot/imported/progress5.svg-3fde5493af5eae7b285bd2c5003ffa8b.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress5.svg" -dest_files=["res://.godot/imported/progress5.svg-3fde5493af5eae7b285bd2c5003ffa8b.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress6.svg b/godot/addons/proton_scatter/icons/loading/progress6.svg deleted file mode 100644 index 3deba6d..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress6.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress6.svg.import b/godot/addons/proton_scatter/icons/loading/progress6.svg.import deleted file mode 100644 index 7c52b61..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress6.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c2kqooswn03uj" -path.s3tc="res://.godot/imported/progress6.svg-3aa5747c4f878020609e583ec4f95b8d.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress6.svg" -dest_files=["res://.godot/imported/progress6.svg-3aa5747c4f878020609e583ec4f95b8d.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress7.svg b/godot/addons/proton_scatter/icons/loading/progress7.svg deleted file mode 100644 index 546155d..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress7.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress7.svg.import b/godot/addons/proton_scatter/icons/loading/progress7.svg.import deleted file mode 100644 index b1e576f..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress7.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://8wacu74d4d6s" -path.s3tc="res://.godot/imported/progress7.svg-c2021ffd30acd67c6a669d6fc56fe8bf.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress7.svg" -dest_files=["res://.godot/imported/progress7.svg-c2021ffd30acd67c6a669d6fc56fe8bf.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/progress8.svg b/godot/addons/proton_scatter/icons/loading/progress8.svg deleted file mode 100644 index b56ffcb..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress8.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/loading/progress8.svg.import b/godot/addons/proton_scatter/icons/loading/progress8.svg.import deleted file mode 100644 index b730f7c..0000000 --- a/godot/addons/proton_scatter/icons/loading/progress8.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://boeljf8xa2s5d" -path.s3tc="res://.godot/imported/progress8.svg-f4c6912cb79e58fffa4e23976af93b45.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/icons/loading/progress8.svg" -dest_files=["res://.godot/imported/progress8.svg-f4c6912cb79e58fffa4e23976af93b45.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=4.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/loading/t_loading.tres b/godot/addons/proton_scatter/icons/loading/t_loading.tres deleted file mode 100644 index d825571..0000000 --- a/godot/addons/proton_scatter/icons/loading/t_loading.tres +++ /dev/null @@ -1,29 +0,0 @@ -[gd_resource type="AnimatedTexture" load_steps=9 format=3 uid="uid://dev74yqbbxjc6"] - -[ext_resource type="Texture2D" uid="uid://bxaffg1bqa2jk" path="res://addons/proton_scatter/icons/loading/progress1.svg" id="1_n051c"] -[ext_resource type="Texture2D" uid="uid://dt36cq4i6vxbp" path="res://addons/proton_scatter/icons/loading/progress2.svg" id="2_huiva"] -[ext_resource type="Texture2D" uid="uid://c0xe1mmwhexf3" path="res://addons/proton_scatter/icons/loading/progress3.svg" id="3_5gmad"] -[ext_resource type="Texture2D" uid="uid://b55ls3njsgrix" path="res://addons/proton_scatter/icons/loading/progress4.svg" id="4_ypilv"] -[ext_resource type="Texture2D" uid="uid://fq4k4ug1df24" path="res://addons/proton_scatter/icons/loading/progress5.svg" id="5_o3w57"] -[ext_resource type="Texture2D" uid="uid://c2kqooswn03uj" path="res://addons/proton_scatter/icons/loading/progress6.svg" id="6_475ws"] -[ext_resource type="Texture2D" uid="uid://8wacu74d4d6s" path="res://addons/proton_scatter/icons/loading/progress7.svg" id="7_kuufk"] -[ext_resource type="Texture2D" uid="uid://boeljf8xa2s5d" path="res://addons/proton_scatter/icons/loading/progress8.svg" id="8_spub1"] - -[resource] -frames = 8 -speed_scale = 8.0 -frame_0/texture = ExtResource("1_n051c") -frame_1/texture = ExtResource("2_huiva") -frame_1/duration = 1.0 -frame_2/texture = ExtResource("3_5gmad") -frame_2/duration = 1.0 -frame_3/texture = ExtResource("4_ypilv") -frame_3/duration = 1.0 -frame_4/texture = ExtResource("5_o3w57") -frame_4/duration = 1.0 -frame_5/texture = ExtResource("6_475ws") -frame_5/duration = 1.0 -frame_6/texture = ExtResource("7_kuufk") -frame_6/duration = 1.0 -frame_7/texture = ExtResource("8_spub1") -frame_7/duration = 1.0 diff --git a/godot/addons/proton_scatter/icons/local.svg b/godot/addons/proton_scatter/icons/local.svg deleted file mode 100644 index 2d5e554..0000000 --- a/godot/addons/proton_scatter/icons/local.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/local.svg.import b/godot/addons/proton_scatter/icons/local.svg.import deleted file mode 100644 index d15896c..0000000 --- a/godot/addons/proton_scatter/icons/local.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dt0ctlr32stnn" -path="res://.godot/imported/local.svg-fd1cdf9da074228b5ba1b4f8ff96c57f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/local.svg" -dest_files=["res://.godot/imported/local.svg-fd1cdf9da074228b5ba1b4f8ff96c57f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/menu.svg b/godot/addons/proton_scatter/icons/menu.svg deleted file mode 100644 index 20c5300..0000000 --- a/godot/addons/proton_scatter/icons/menu.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/menu.svg.import b/godot/addons/proton_scatter/icons/menu.svg.import deleted file mode 100644 index 4aaefd3..0000000 --- a/godot/addons/proton_scatter/icons/menu.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://n66mufjib4ds" -path="res://.godot/imported/menu.svg-f26f5349a7002ba943a58d37d6a062f2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/menu.svg" -dest_files=["res://.godot/imported/menu.svg-f26f5349a7002ba943a58d37d6a062f2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/point.svg b/godot/addons/proton_scatter/icons/point.svg deleted file mode 100644 index 1447124..0000000 --- a/godot/addons/proton_scatter/icons/point.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/point.svg.import b/godot/addons/proton_scatter/icons/point.svg.import deleted file mode 100644 index cfe8b44..0000000 --- a/godot/addons/proton_scatter/icons/point.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://4v52mh8eu14l" -path="res://.godot/imported/point.svg-5132d8b7a9cb8505d146d1f26f8e5bd1.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/point.svg" -dest_files=["res://.godot/imported/point.svg-5132d8b7a9cb8505d146d1f26f8e5bd1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/rebuild.svg b/godot/addons/proton_scatter/icons/rebuild.svg deleted file mode 100644 index d69e6a7..0000000 --- a/godot/addons/proton_scatter/icons/rebuild.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/rebuild.svg.import b/godot/addons/proton_scatter/icons/rebuild.svg.import deleted file mode 100644 index 194f35c..0000000 --- a/godot/addons/proton_scatter/icons/rebuild.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://yqlpvcmb7mfi" -path="res://.godot/imported/rebuild.svg-fbde9fa19dc213c85b24bc3d3a1fb89d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/rebuild.svg" -dest_files=["res://.godot/imported/rebuild.svg-fbde9fa19dc213c85b24bc3d3a1fb89d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/remove.svg b/godot/addons/proton_scatter/icons/remove.svg deleted file mode 100644 index eb8e244..0000000 --- a/godot/addons/proton_scatter/icons/remove.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/remove.svg.import b/godot/addons/proton_scatter/icons/remove.svg.import deleted file mode 100644 index cbb98f2..0000000 --- a/godot/addons/proton_scatter/icons/remove.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://btb6rqhhi27mx" -path="res://.godot/imported/remove.svg-8b603896066014738ad4a8d4a482bb8e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/remove.svg" -dest_files=["res://.godot/imported/remove.svg-8b603896066014738ad4a8d4a482bb8e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/restrict_volume.svg b/godot/addons/proton_scatter/icons/restrict_volume.svg deleted file mode 100644 index af4ffbf..0000000 --- a/godot/addons/proton_scatter/icons/restrict_volume.svg +++ /dev/null @@ -1,54 +0,0 @@ - - - - - height-arrow - - - - - height-arrow - - - - diff --git a/godot/addons/proton_scatter/icons/restrict_volume.svg.import b/godot/addons/proton_scatter/icons/restrict_volume.svg.import deleted file mode 100644 index 9091c99..0000000 --- a/godot/addons/proton_scatter/icons/restrict_volume.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmvfdl1wnrw4" -path="res://.godot/imported/restrict_volume.svg-9476f4ee23ebb4f320f21a45306967ac.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/restrict_volume.svg" -dest_files=["res://.godot/imported/restrict_volume.svg-9476f4ee23ebb4f320f21a45306967ac.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/restrict_volume_lock.svg b/godot/addons/proton_scatter/icons/restrict_volume_lock.svg deleted file mode 100644 index 88bdfb7..0000000 --- a/godot/addons/proton_scatter/icons/restrict_volume_lock.svg +++ /dev/null @@ -1,59 +0,0 @@ - - - - - height-arrow - - - - - height-arrow - - - - - diff --git a/godot/addons/proton_scatter/icons/restrict_volume_lock.svg.import b/godot/addons/proton_scatter/icons/restrict_volume_lock.svg.import deleted file mode 100644 index e24aef3..0000000 --- a/godot/addons/proton_scatter/icons/restrict_volume_lock.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://p2v2cqm7k60o" -path="res://.godot/imported/restrict_volume_lock.svg-a29ed4343f793eec0d6ceda09d847281.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/restrict_volume_lock.svg" -dest_files=["res://.godot/imported/restrict_volume_lock.svg-a29ed4343f793eec0d6ceda09d847281.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/right.svg.import b/godot/addons/proton_scatter/icons/right.svg.import deleted file mode 100644 index 9a40282..0000000 --- a/godot/addons/proton_scatter/icons/right.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c5x3svtghg355" -path="res://.godot/imported/right.svg-223d435f72cc2f37c84f07b38111fb2a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/right.svg" -dest_files=["res://.godot/imported/right.svg-223d435f72cc2f37c84f07b38111fb2a.ctex"] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/bptc_ldr=0 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -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/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 diff --git a/godot/addons/proton_scatter/icons/save.svg b/godot/addons/proton_scatter/icons/save.svg deleted file mode 100644 index be5d3ef..0000000 --- a/godot/addons/proton_scatter/icons/save.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/save.svg.import b/godot/addons/proton_scatter/icons/save.svg.import deleted file mode 100644 index ec19d8b..0000000 --- a/godot/addons/proton_scatter/icons/save.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b2omj2e03x72e" -path="res://.godot/imported/save.svg-cdd3febbdfafdd18b4e7e1eca8b243ee.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/save.svg" -dest_files=["res://.godot/imported/save.svg-cdd3febbdfafdd18b4e7e1eca8b243ee.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/scatter.svg b/godot/addons/proton_scatter/icons/scatter.svg deleted file mode 100644 index 9092f4a..0000000 --- a/godot/addons/proton_scatter/icons/scatter.svg +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/scatter.svg.import b/godot/addons/proton_scatter/icons/scatter.svg.import deleted file mode 100644 index 62f3385..0000000 --- a/godot/addons/proton_scatter/icons/scatter.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://chwotbfago2uu" -path="res://.godot/imported/scatter.svg-bfff578dc360b745c3834db069a4a315.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/scatter.svg" -dest_files=["res://.godot/imported/scatter.svg-bfff578dc360b745c3834db069a4a315.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/select_all.svg b/godot/addons/proton_scatter/icons/select_all.svg deleted file mode 100644 index 4440149..0000000 --- a/godot/addons/proton_scatter/icons/select_all.svg +++ /dev/null @@ -1,39 +0,0 @@ - - diff --git a/godot/addons/proton_scatter/icons/select_all.svg.import b/godot/addons/proton_scatter/icons/select_all.svg.import deleted file mode 100644 index 083a1ca..0000000 --- a/godot/addons/proton_scatter/icons/select_all.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://uytbptu3a34s" -path="res://.godot/imported/select_all.svg-791a69a69cd2b6a9baadee0215a94edb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/select_all.svg" -dest_files=["res://.godot/imported/select_all.svg-791a69a69cd2b6a9baadee0215a94edb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/shape.svg b/godot/addons/proton_scatter/icons/shape.svg deleted file mode 100644 index 1335f5a..0000000 --- a/godot/addons/proton_scatter/icons/shape.svg +++ /dev/null @@ -1,41 +0,0 @@ - - diff --git a/godot/addons/proton_scatter/icons/shape.svg.import b/godot/addons/proton_scatter/icons/shape.svg.import deleted file mode 100644 index f62ee74..0000000 --- a/godot/addons/proton_scatter/icons/shape.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b51u02uqdpkrj" -path="res://.godot/imported/shape.svg-d62cbd79ae44bc9e71e9bf0357acae87.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/shape.svg" -dest_files=["res://.godot/imported/shape.svg-d62cbd79ae44bc9e71e9bf0357acae87.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/square_handle.svg b/godot/addons/proton_scatter/icons/square_handle.svg deleted file mode 100644 index 4df41e2..0000000 --- a/godot/addons/proton_scatter/icons/square_handle.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/godot/addons/proton_scatter/icons/square_handle.svg.import b/godot/addons/proton_scatter/icons/square_handle.svg.import deleted file mode 100644 index 11394c8..0000000 --- a/godot/addons/proton_scatter/icons/square_handle.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b5ip0ugocre1l" -path="res://.godot/imported/square_handle.svg-3a66112fe1576c8f64a3c4d4e7121ea4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/square_handle.svg" -dest_files=["res://.godot/imported/square_handle.svg-3a66112fe1576c8f64a3c4d4e7121ea4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/bool.svg b/godot/addons/proton_scatter/icons/types/bool.svg deleted file mode 100644 index 674cbc9..0000000 --- a/godot/addons/proton_scatter/icons/types/bool.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/bool.svg.import b/godot/addons/proton_scatter/icons/types/bool.svg.import deleted file mode 100644 index e16b3b3..0000000 --- a/godot/addons/proton_scatter/icons/types/bool.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cnrguyqhdq7qh" -path="res://.godot/imported/bool.svg-52b1fa0447a042bcdc16ea428ddd807d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/bool.svg" -dest_files=["res://.godot/imported/bool.svg-52b1fa0447a042bcdc16ea428ddd807d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/curve.svg b/godot/addons/proton_scatter/icons/types/curve.svg deleted file mode 100644 index 8b330b7..0000000 --- a/godot/addons/proton_scatter/icons/types/curve.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/types/curve.svg.import b/godot/addons/proton_scatter/icons/types/curve.svg.import deleted file mode 100644 index 0dbd8d2..0000000 --- a/godot/addons/proton_scatter/icons/types/curve.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjv6vm1tf8rex" -path="res://.godot/imported/curve.svg-aac852ce2008b2aa544030f27fdb3fb7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/curve.svg" -dest_files=["res://.godot/imported/curve.svg-aac852ce2008b2aa544030f27fdb3fb7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/float.svg b/godot/addons/proton_scatter/icons/types/float.svg deleted file mode 100644 index b941332..0000000 --- a/godot/addons/proton_scatter/icons/types/float.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/float.svg.import b/godot/addons/proton_scatter/icons/types/float.svg.import deleted file mode 100644 index 462fd3e..0000000 --- a/godot/addons/proton_scatter/icons/types/float.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cpt5bs4irj0kc" -path="res://.godot/imported/float.svg-04e5d7ce1dc5bf58d92d7b3e90c1bdb9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/float.svg" -dest_files=["res://.godot/imported/float.svg-04e5d7ce1dc5bf58d92d7b3e90c1bdb9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/int.svg b/godot/addons/proton_scatter/icons/types/int.svg deleted file mode 100644 index b943822..0000000 --- a/godot/addons/proton_scatter/icons/types/int.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/int.svg.import b/godot/addons/proton_scatter/icons/types/int.svg.import deleted file mode 100644 index c2baf2b..0000000 --- a/godot/addons/proton_scatter/icons/types/int.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b76u8wvdxv7xk" -path="res://.godot/imported/int.svg-6257f86dd757be1a7e16525e9e4334a4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/int.svg" -dest_files=["res://.godot/imported/int.svg-6257f86dd757be1a7e16525e9e4334a4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/string.svg b/godot/addons/proton_scatter/icons/types/string.svg deleted file mode 100644 index abcb92d..0000000 --- a/godot/addons/proton_scatter/icons/types/string.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/string.svg.import b/godot/addons/proton_scatter/icons/types/string.svg.import deleted file mode 100644 index 66ceb6e..0000000 --- a/godot/addons/proton_scatter/icons/types/string.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://duc0v0ndpdima" -path="res://.godot/imported/string.svg-47c2a4465e2fc23004707a7f638ee11f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/string.svg" -dest_files=["res://.godot/imported/string.svg-47c2a4465e2fc23004707a7f638ee11f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/texture.svg b/godot/addons/proton_scatter/icons/types/texture.svg deleted file mode 100644 index bb7831e..0000000 --- a/godot/addons/proton_scatter/icons/types/texture.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/proton_scatter/icons/types/texture.svg.import b/godot/addons/proton_scatter/icons/types/texture.svg.import deleted file mode 100644 index 4f9040c..0000000 --- a/godot/addons/proton_scatter/icons/types/texture.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dn2bmd4exvdfh" -path="res://.godot/imported/texture.svg-b3e461acf41426098532cfe288615e66.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/texture.svg" -dest_files=["res://.godot/imported/texture.svg-b3e461acf41426098532cfe288615e66.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/vector2.svg b/godot/addons/proton_scatter/icons/types/vector2.svg deleted file mode 100644 index 2bab922..0000000 --- a/godot/addons/proton_scatter/icons/types/vector2.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/vector2.svg.import b/godot/addons/proton_scatter/icons/types/vector2.svg.import deleted file mode 100644 index 4b24569..0000000 --- a/godot/addons/proton_scatter/icons/types/vector2.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjei816k8tqwm" -path="res://.godot/imported/vector2.svg-4fbd1b82783fdf0be277b45f49bbe354.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/vector2.svg" -dest_files=["res://.godot/imported/vector2.svg-4fbd1b82783fdf0be277b45f49bbe354.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/vector2i.svg b/godot/addons/proton_scatter/icons/types/vector2i.svg deleted file mode 100644 index f292354..0000000 --- a/godot/addons/proton_scatter/icons/types/vector2i.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/vector2i.svg.import b/godot/addons/proton_scatter/icons/types/vector2i.svg.import deleted file mode 100644 index 3b07fbc..0000000 --- a/godot/addons/proton_scatter/icons/types/vector2i.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://5ue6la1myxjv" -path="res://.godot/imported/vector2i.svg-77972f3560d45185f38f11485fade0c2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/vector2i.svg" -dest_files=["res://.godot/imported/vector2i.svg-77972f3560d45185f38f11485fade0c2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/vector3.svg b/godot/addons/proton_scatter/icons/types/vector3.svg deleted file mode 100644 index 85cac57..0000000 --- a/godot/addons/proton_scatter/icons/types/vector3.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/vector3.svg.import b/godot/addons/proton_scatter/icons/types/vector3.svg.import deleted file mode 100644 index c055518..0000000 --- a/godot/addons/proton_scatter/icons/types/vector3.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://rdfs8dixiw02" -path="res://.godot/imported/vector3.svg-e5e507d504b3fec450fe9420cf2ed166.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/vector3.svg" -dest_files=["res://.godot/imported/vector3.svg-e5e507d504b3fec450fe9420cf2ed166.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/types/vector3i.svg b/godot/addons/proton_scatter/icons/types/vector3i.svg deleted file mode 100644 index 26e9c1b..0000000 --- a/godot/addons/proton_scatter/icons/types/vector3i.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/types/vector3i.svg.import b/godot/addons/proton_scatter/icons/types/vector3i.svg.import deleted file mode 100644 index dd89587..0000000 --- a/godot/addons/proton_scatter/icons/types/vector3i.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ccprltc2l2a7x" -path="res://.godot/imported/vector3i.svg-b66d3d08e0e2fa48c2f0d287a8b08f1a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/types/vector3i.svg" -dest_files=["res://.godot/imported/vector3i.svg-b66d3d08e0e2fa48c2f0d287a8b08f1a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/icons/up.svg.import b/godot/addons/proton_scatter/icons/up.svg.import deleted file mode 100644 index b8c738f..0000000 --- a/godot/addons/proton_scatter/icons/up.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bdp3ycc2b7kyg" -path="res://.godot/imported/up.svg-93c9110a5b9e596fc5bc35363093df32.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/up.svg" -dest_files=["res://.godot/imported/up.svg-93c9110a5b9e596fc5bc35363093df32.ctex"] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_compression=1 -compress/bptc_ldr=0 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -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/size_limit=0 -detect_3d/compress_to=1 -svg/scale=1.0 diff --git a/godot/addons/proton_scatter/icons/warning.svg b/godot/addons/proton_scatter/icons/warning.svg deleted file mode 100644 index f40d539..0000000 --- a/godot/addons/proton_scatter/icons/warning.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/icons/warning.svg.import b/godot/addons/proton_scatter/icons/warning.svg.import deleted file mode 100644 index 9eaf772..0000000 --- a/godot/addons/proton_scatter/icons/warning.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dj0y6peid681t" -path="res://.godot/imported/warning.svg-edf1b604537b5af6863f92713f96edb5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/icons/warning.svg" -dest_files=["res://.godot/imported/warning.svg-edf1b604537b5af6863f92713f96edb5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/masks/bars.png b/godot/addons/proton_scatter/masks/bars.png deleted file mode 100644 index 99ce23b..0000000 Binary files a/godot/addons/proton_scatter/masks/bars.png and /dev/null differ diff --git a/godot/addons/proton_scatter/masks/bars.png.import b/godot/addons/proton_scatter/masks/bars.png.import deleted file mode 100644 index 7964ab2..0000000 --- a/godot/addons/proton_scatter/masks/bars.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dfj7p0fwxa1nc" -path="res://.godot/imported/bars.png-61d34dbd5bccdfb29fbe178f6a4791cb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/masks/bars.png" -dest_files=["res://.godot/imported/bars.png-61d34dbd5bccdfb29fbe178f6a4791cb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/masks/blinds.png b/godot/addons/proton_scatter/masks/blinds.png deleted file mode 100644 index a15a038..0000000 Binary files a/godot/addons/proton_scatter/masks/blinds.png and /dev/null differ diff --git a/godot/addons/proton_scatter/masks/blinds.png.import b/godot/addons/proton_scatter/masks/blinds.png.import deleted file mode 100644 index 7a72251..0000000 --- a/godot/addons/proton_scatter/masks/blinds.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bg6881qstlapu" -path="res://.godot/imported/blinds.png-3f857c707ea5be395a4531d6d60eac1e.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/masks/blinds.png" -dest_files=["res://.godot/imported/blinds.png-3f857c707ea5be395a4531d6d60eac1e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/masks/checker.png b/godot/addons/proton_scatter/masks/checker.png deleted file mode 100644 index ca58baf..0000000 Binary files a/godot/addons/proton_scatter/masks/checker.png and /dev/null differ diff --git a/godot/addons/proton_scatter/masks/checker.png.import b/godot/addons/proton_scatter/masks/checker.png.import deleted file mode 100644 index f7c2998..0000000 --- a/godot/addons/proton_scatter/masks/checker.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dsr872vuejrqx" -path="res://.godot/imported/checker.png-ec978f1465e3b09756cb5cb959e11209.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/masks/checker.png" -dest_files=["res://.godot/imported/checker.png-ec978f1465e3b09756cb5cb959e11209.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/masks/wave.png b/godot/addons/proton_scatter/masks/wave.png deleted file mode 100644 index 3e5f218..0000000 Binary files a/godot/addons/proton_scatter/masks/wave.png and /dev/null differ diff --git a/godot/addons/proton_scatter/masks/wave.png.import b/godot/addons/proton_scatter/masks/wave.png.import deleted file mode 100644 index 3b08935..0000000 --- a/godot/addons/proton_scatter/masks/wave.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c4q2bmujmanc6" -path="res://.godot/imported/wave.png-d387544eba14013e763fdb82094dc9c6.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/proton_scatter/masks/wave.png" -dest_files=["res://.godot/imported/wave.png-d387544eba14013e763fdb82094dc9c6.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/proton_scatter/plugin.cfg b/godot/addons/proton_scatter/plugin.cfg deleted file mode 100644 index 29069d3..0000000 --- a/godot/addons/proton_scatter/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="ProtonScatter" -description="Scatter props or entire scenes across any space in a non destructive way" -author="HungryProton" -version="4.0" -script="plugin.gd" diff --git a/godot/addons/proton_scatter/plugin.gd b/godot/addons/proton_scatter/plugin.gd deleted file mode 100644 index 3ec22b6..0000000 --- a/godot/addons/proton_scatter/plugin.gd +++ /dev/null @@ -1,168 +0,0 @@ -@tool -extends EditorPlugin - - -const ModifierStackPlugin := preload("./src/stack/inspector_plugin/modifier_stack_plugin.gd") -const ScatterGizmoPlugin := preload("./src/scatter_gizmo_plugin.gd") -const ShapeGizmoPlugin := preload("./src/shapes/gizmos_plugin/shape_gizmo_plugin.gd") -const PathPanel := preload("./src/shapes/gizmos_plugin/components/path_panel.tscn") -const ScatterCachePlugin := preload("./src/cache/inspector_plugin/scatter_cache_plugin.gd") - -const GIZMO_SETTING := "addons/proton_scatter/always_show_gizmos" -const MAX_PHYSICS_QUERIES_SETTING := "addons/proton_scatter/max_physics_queries_per_frame" - -var _modifier_stack_plugin := ModifierStackPlugin.new() -var _scatter_gizmo_plugin := ScatterGizmoPlugin.new() -var _shape_gizmo_plugin := ShapeGizmoPlugin.new() -var _scatter_cache_plugin := ScatterCachePlugin.new() -var _path_panel -var _selected_scatter_group: Array[Node] = [] - - -func _get_plugin_name(): - return "ProtonScatter" - - -func _enter_tree(): - _ensure_setting_exists(GIZMO_SETTING, true) - _ensure_setting_exists(MAX_PHYSICS_QUERIES_SETTING, 500) - - add_inspector_plugin(_modifier_stack_plugin) - add_inspector_plugin(_scatter_cache_plugin) - - _path_panel = PathPanel.instantiate() - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, _path_panel) - _path_panel.visible = false - - add_node_3d_gizmo_plugin(_scatter_gizmo_plugin) - _scatter_gizmo_plugin.set_editor_plugin(self) - - add_node_3d_gizmo_plugin(_shape_gizmo_plugin) - _shape_gizmo_plugin.set_undo_redo(get_undo_redo()) - _shape_gizmo_plugin.set_path_gizmo_panel(_path_panel) - _shape_gizmo_plugin.set_editor_plugin(self) - - add_custom_type( - "ProtonScatter", - "Node3D", - preload("./src/scatter.gd"), - preload("./icons/scatter.svg") - ) - add_custom_type( - "ScatterItem", - "Node3D", - preload("./src/scatter_item.gd"), - preload("./icons/item.svg") - ) - add_custom_type( - "ScatterShape", - "Node3D", - preload("./src/scatter_shape.gd"), - preload("./icons/shape.svg") - ) - add_custom_type( - "ScatterCache", - "Node3D", - preload("./src/cache/scatter_cache.gd"), - preload("./icons/cache.svg") - ) - - var editor_selection = get_editor_interface().get_selection() - editor_selection.selection_changed.connect(_on_selection_changed) - - scene_changed.connect(_on_scene_changed) - - -func _exit_tree(): - remove_custom_type("ProtonScatter") - remove_custom_type("ScatterItem") - remove_custom_type("ScatterShape") - remove_custom_type("ScatterCache") - remove_inspector_plugin(_modifier_stack_plugin) - remove_inspector_plugin(_scatter_cache_plugin) - remove_node_3d_gizmo_plugin(_shape_gizmo_plugin) - remove_node_3d_gizmo_plugin(_scatter_gizmo_plugin) - if _path_panel: - remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, _path_panel) - _path_panel.queue_free() - _path_panel = null - - -func _handles(node) -> bool: - return node is ProtonScatterShape - - -func _forward_3d_gui_input(viewport_camera: Camera3D, event: InputEvent) -> int: - return _shape_gizmo_plugin.forward_3d_gui_input(viewport_camera, event) - - -func get_custom_selection() -> Array[Node]: - return _selected_scatter_group - - -func _refresh_scatter_gizmos(nodes: Array[Node]) -> void: - for node in nodes: - if not is_instance_valid(node): - continue - - if node is ProtonScatterShape: - _refresh_scatter_gizmos([node.get_parent()]) - continue - - if node is ProtonScatter: - node.update_gizmos() - for c in node.get_children(): - if c is Node3D: - c.update_gizmos() - - -func _ensure_setting_exists(setting: String, default_value) -> void: - if not ProjectSettings.has_setting(setting): - ProjectSettings.set_setting(setting, default_value) - ProjectSettings.set_initial_value(setting, default_value) - - if ProjectSettings.has_method("set_as_basic"): # 4.0 backward compatibility - ProjectSettings.call("set_as_basic", setting, true) - - -func _on_selection_changed() -> void: - # Clean the gizmos on the previous node selection - _refresh_scatter_gizmos(_selected_scatter_group) - _selected_scatter_group.clear() - - # Get the currently selected nodes - var selected = get_editor_interface().get_selection().get_selected_nodes() - _path_panel.selection_changed(selected) - - if selected.is_empty(): - return - - # Update the selected local scatter group. - # If the user selects a shape, the scatter group will contain the ScatterShape, - # all the sibling shapes, and the parent scatter node, even if they are not - # selected. This is required to make their gizmos appear. - for node in selected: - var scatter_node - - if node is ProtonScatter: - scatter_node = node - - elif node is ProtonScatterShape and is_instance_valid(node): - scatter_node = node.get_parent() - - if not is_instance_valid(scatter_node): - continue - - _selected_scatter_group.push_back(scatter_node) - scatter_node.undo_redo = get_undo_redo() - scatter_node.editor_plugin = self - - for c in scatter_node.get_children(): - if c is ProtonScatterShape: - _selected_scatter_group.push_back(c) - - _refresh_scatter_gizmos(_selected_scatter_group) - - -func _on_scene_changed(_scene_root) -> void: - pass diff --git a/godot/addons/proton_scatter/plugin.gd.uid b/godot/addons/proton_scatter/plugin.gd.uid deleted file mode 100644 index c3b1558..0000000 --- a/godot/addons/proton_scatter/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dbqfn7yams35i diff --git a/godot/addons/proton_scatter/presets/grass.tscn b/godot/addons/proton_scatter/presets/grass.tscn deleted file mode 100644 index 1a25665..0000000 --- a/godot/addons/proton_scatter/presets/grass.tscn +++ /dev/null @@ -1,65 +0,0 @@ -[gd_scene load_steps=14 format=3 uid="uid://2e6nvcbuqhao"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter.gd" id="1_hwvsa"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/modifier_stack.gd" id="2_84xri"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_grid.gd" id="3_t5gts"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/randomize_transforms.gd" id="4_v7woi"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/project_on_geometry.gd" id="5_tgf12"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_item.gd" id="6_11eqr"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_shape.gd" id="7_vk3gk"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/sphere_shape.gd" id="9_w0igc"] - -[sub_resource type="Resource" id="Resource_mu1a8"] -script = ExtResource("3_t5gts") -spacing = Vector3(0.2, 1, 0.2) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_8361b"] -script = ExtResource("4_v7woi") -position = Vector3(0, 0, 0) -rotation = Vector3(20, 360, 20) -scale = Vector3(4, 2, 4) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_14cyx"] -script = ExtResource("5_tgf12") -ray_direction = Vector3(0, -1, 0) -ray_length = 10.0 -ray_offset = 10.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_mv17r"] -script = ExtResource("2_84xri") -stack = Array[Resource]([SubResource("Resource_mu1a8"), SubResource("Resource_8361b"), SubResource("Resource_14cyx")]) - -[sub_resource type="Resource" id="Resource_gaw40"] -script = ExtResource("9_w0igc") -radius = 5.0 - -[node name="ProtonScatter" type="Node3D"] -script = ExtResource("1_hwvsa") -modifier_stack = SubResource("Resource_mv17r") - -[node name="Grass" type="Node3D" parent="."] -script = ExtResource("6_11eqr") -path = "res://addons/proton_scatter/demos/assets/grass_2.tscn" - -[node name="ScatterShape" type="Node3D" parent="."] -script = ExtResource("7_vk3gk") -shape = SubResource("Resource_gaw40") diff --git a/godot/addons/proton_scatter/presets/scatter_default.tscn b/godot/addons/proton_scatter/presets/scatter_default.tscn deleted file mode 100644 index 75654b7..0000000 --- a/godot/addons/proton_scatter/presets/scatter_default.tscn +++ /dev/null @@ -1,78 +0,0 @@ -[gd_scene load_steps=16 format=3 uid="uid://yxn1ih6qrc01"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter.gd" id="1_e0kty"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/modifier_stack.gd" id="2_lt5xy"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_random.gd" id="3_0051t"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/randomize_transforms.gd" id="4_5a045"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/project_on_geometry.gd" id="5_gkw57"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/relax.gd" id="5_n2in0"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_item.gd" id="6_3iwkw"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_shape.gd" id="7_jofmq"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/sphere_shape.gd" id="8_gnbkw"] - -[sub_resource type="Resource" id="Resource_jbxru"] -script = ExtResource("3_0051t") -amount = 75 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_0oyil"] -script = ExtResource("4_5a045") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_ogw66"] -script = ExtResource("5_n2in0") -iterations = 3 -offset_step = 0.2 -consecutive_step_multiplier = 0.75 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_awufl"] -script = ExtResource("5_gkw57") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_xqhqc"] -script = ExtResource("2_lt5xy") -stack = Array[Resource]([SubResource("Resource_jbxru"), SubResource("Resource_0oyil"), SubResource("Resource_ogw66"), SubResource("Resource_awufl")]) - -[sub_resource type="Resource" id="Resource_g8bsm"] -script = ExtResource("8_gnbkw") -radius = 2.0 - -[node name="ProtonScatter" type="Node3D"] -script = ExtResource("1_e0kty") -modifier_stack = SubResource("Resource_xqhqc") - -[node name="ScatterItem" type="Node3D" parent="."] -script = ExtResource("6_3iwkw") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="."] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("7_jofmq") -shape = SubResource("Resource_g8bsm") diff --git a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd b/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd deleted file mode 100644 index e407717..0000000 --- a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd +++ /dev/null @@ -1,45 +0,0 @@ -@tool -extends PanelContainer - - -const ScatterCache := preload("res://addons/proton_scatter/src/cache/scatter_cache.gd") - - -@onready var _rebuild_button: Button = %RebuildButton -@onready var _restore_button: Button = %RestoreButton -@onready var _clear_button: Button = %ClearButton -@onready var _enable_for_all_button: Button = %EnableForAllButton - -var _cache: ScatterCache - - -func _ready() -> void: - _rebuild_button.pressed.connect(_on_rebuild_pressed) - _restore_button.pressed.connect(_on_restore_pressed) - _clear_button.pressed.connect(_on_clear_pressed) - _enable_for_all_button.pressed.connect(_on_enable_for_all_pressed) - custom_minimum_size.y = size.y * 1.25 - - -func set_object(cache: ScatterCache) -> void: - _cache = cache - - -func _on_rebuild_pressed() -> void: - if is_instance_valid(_cache): - _cache.update_cache() - - -func _on_restore_pressed() -> void: - if is_instance_valid(_cache): - _cache.restore_cache() - - -func _on_clear_pressed() -> void: - if is_instance_valid(_cache): - _cache.clear_cache() - - -func _on_enable_for_all_pressed() -> void: - if is_instance_valid(_cache): - _cache.enable_for_all_nodes() diff --git a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd.uid b/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd.uid deleted file mode 100644 index 91d1eb8..0000000 --- a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dgiotkssxbcc diff --git a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.tscn b/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.tscn deleted file mode 100644 index e12ad7c..0000000 --- a/godot/addons/proton_scatter/src/cache/inspector_plugin/cache_panel.tscn +++ /dev/null @@ -1,49 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://dilbceex72g24"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/cache/inspector_plugin/cache_panel.gd" id="1_h1g4a"] -[ext_resource type="Texture2D" uid="uid://yqlpvcmb7mfi" path="res://addons/proton_scatter/icons/rebuild.svg" id="2_0ml76"] -[ext_resource type="Texture2D" uid="uid://ddjrq1h4mkn6a" path="res://addons/proton_scatter/icons/load.svg" id="3_i6mdl"] -[ext_resource type="Texture2D" uid="uid://btb6rqhhi27mx" path="res://addons/proton_scatter/icons/remove.svg" id="4_bfbdy"] - -[node name="CachePanel" type="PanelContainer"] -custom_minimum_size = Vector2(0, 82.5) -offset_right = 161.0 -offset_bottom = 66.0 -size_flags_horizontal = 3 -script = ExtResource("1_h1g4a") - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -layout_mode = 2 -alignment = 1 - -[node name="RebuildButton" type="Button" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 3 -text = "Update Cache" -icon = ExtResource("2_0ml76") - -[node name="RestoreButton" type="Button" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 3 -text = "Restore Transforms" -icon = ExtResource("3_i6mdl") - -[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 - -[node name="ClearButton" type="Button" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 3 -text = "Clear Cache" -icon = ExtResource("4_bfbdy") - -[node name="EnableForAllButton" type="Button" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Enable Cache For All" diff --git a/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd b/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd deleted file mode 100644 index 96431e4..0000000 --- a/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd +++ /dev/null @@ -1,17 +0,0 @@ -@tool -extends EditorInspectorPlugin - - -const CachePanel = preload("./cache_panel.tscn") -const ScatterCache = preload("../../cache/scatter_cache.gd") - - -func _can_handle(object): - return is_instance_of(object, ScatterCache) - - -func _parse_category(object, category: String): - if category == "ScatterCache" or category == "scatter_cache.gd": - var ui = CachePanel.instantiate() - ui.set_object(object) - add_custom_control(ui) diff --git a/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd.uid b/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd.uid deleted file mode 100644 index e94b22d..0000000 --- a/godot/addons/proton_scatter/src/cache/inspector_plugin/scatter_cache_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ddw07ivebpbix diff --git a/godot/addons/proton_scatter/src/cache/scatter_cache.gd b/godot/addons/proton_scatter/src/cache/scatter_cache.gd deleted file mode 100644 index 00b3c65..0000000 --- a/godot/addons/proton_scatter/src/cache/scatter_cache.gd +++ /dev/null @@ -1,232 +0,0 @@ -@tool -extends Node - -# ProtonScatterCacheNode -# -# Saves the transforms created by ProtonScatter nodes in an external resource -# and restore them when loading the scene. -# -# Use this node when you don't want to wait for scatter nodes to fully rebuild -# at start. -# You can also enable "Show output in tree" to get the same effect, but the -# cache makes it much more VCS friendly, and doesn't clutter your scene tree. - -const DEFAULT_CACHE_FOLDER := "res://addons/proton_scatter/cache/" - -const ProtonScatterTransformList := preload("../common/transform_list.gd") - - -signal cache_restored - - -@export_file("*.res", "*.tres") var cache_file := "": - set(val): - cache_file = val - if is_inside_tree(): - update_configuration_warnings() - - -## Determines whether the cache should be automatically updated when the scene is saved. -## If this is set to off, you will need to manually use the Update Cache button to ensure the -## cache is up-to-date. -@export var auto_rebuild_cache_when_saving := true - -@export_group("Debug", "dbg_") - -## This parameter is primarily intended for debugging purposes, as loading large cache -## files on the main thread can cause the editor to become unresponsive. -@export var dbg_disable_thread := false - -# The resource where transforms are actually stored -var _local_cache: ProtonScatterCacheResource -var _scene_root: Node -var _scatter_nodes: Dictionary #Key: ProtonScatter, Value: cached version -var _local_cache_changed := false - - -func _ready() -> void: - if not is_inside_tree(): - return - - _scene_root = _get_local_scene_root(self) - - # Check if cache_file is empty, indicating the default case - if cache_file.is_empty(): - if Engine.is_editor_hint(): - # Ensure the cache folder exists - _ensure_cache_folder_exists() - else: - printerr("ProtonScatter error: You load a ScatterCache node with an empty cache file attribute. Outside of the editor, the addon can't set a default value. Please open the scene in the editor and set a default value.") - return - - # Retrieve the scene name to create a unique recognizable name - var scene_path: String = _scene_root.get_scene_file_path() - var scene_name: String - - # If the scene path is not available, set a random name - if scene_path.is_empty(): - scene_name = str(randi()) - else: - # Use the base name of the scene file and append a hash to avoid collisions - scene_name = scene_path.get_file().get_basename() - scene_name += "_" + str(scene_path.hash()) - - # Set the cache path to the cache folder, incorporating the scene name - cache_file = DEFAULT_CACHE_FOLDER.get_basename().path_join(scene_name + "_scatter_cache.res") - return - - restore_cache.call_deferred() - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings = PackedStringArray() - if cache_file.is_empty(): - warnings.push_back("No path set for the cache file. Select where to store the cache in the inspector.") - - return warnings - - -func _notification(what): - if what == NOTIFICATION_EDITOR_PRE_SAVE and auto_rebuild_cache_when_saving: - update_cache() - - -func clear_cache() -> void: - _scatter_nodes.clear() - _local_cache = null - - -func update_cache() -> void: - if cache_file.is_empty(): - printerr("Cache file path is empty.") - return - - _purge_outdated_nodes() - _discover_scatter_nodes(_scene_root) - - if not _local_cache: - _local_cache = ProtonScatterCacheResource.new() - - for s in _scatter_nodes: - # Ignore this node if its cache is already up to date - var cached_version: int = _scatter_nodes[s] - if s.build_version == cached_version: - continue - - # If transforms are not available, try to rebuild once. - if not s.transforms: - s.rebuild.call_deferred() - await s.build_completed - - if not s.transforms: - continue # Move on to the next if still no results. - - # Store the transforms in the cache. - _local_cache.store(_scene_root.get_path_to(s), s.transforms.list) - _scatter_nodes[s] = s.build_version - _local_cache_changed = true - - # Only save the cache on disk if there's something new to save - if not _local_cache_changed: - return - - # TODO: Save large files on a thread - var err = ResourceSaver.save(_local_cache, cache_file) - _local_cache_changed = false - - if err != OK: - printerr("ProtonScatter error: Failed to save the cache file. Code: ", err) - - -func restore_cache() -> void: - # Load the cache file if it exists - if not ResourceLoader.exists(cache_file): - printerr("Could not find cache file ", cache_file) - return - - if is_inside_tree(): - await _load_cache_threaded(cache_file) - else: - _local_cache = load(cache_file) - if not _local_cache: - printerr("Could not load cache: ", cache_file) - return - - _scatter_nodes.clear() - _discover_scatter_nodes(_scene_root) - - for s in _scatter_nodes: - if s.force_rebuild_on_load: - continue # Ignore the cache if the scatter node is about to rebuild anyway. - - # Send the cached transforms to the scatter node. - var transforms = ProtonScatterTransformList.new() - transforms.list = _local_cache.get_transforms(_scene_root.get_path_to(s)) - s._perform_sanity_check() - s._on_transforms_ready(transforms) - s.build_version = 0 - _scatter_nodes[s] = 0 - - cache_restored.emit() - - -func enable_for_all_nodes() -> void: - _purge_outdated_nodes() - _discover_scatter_nodes(_scene_root) - for s in _scatter_nodes: - s.force_rebuild_on_load = false - - -# If the node comes from an instantiated scene, returns the root of that -# instance. Returns the tree root node otherwise. -func _get_local_scene_root(node: Node) -> Node: - if not node.scene_file_path.is_empty(): - return node - - var parent: Node = node.get_parent() - if not parent: - return node - - return _get_local_scene_root(parent) - - -func _discover_scatter_nodes(node: Node) -> void: - if node is ProtonScatter and not _scatter_nodes.has(node): - _scatter_nodes[node] = -1 - - for c in node.get_children(): - _discover_scatter_nodes(c) - - -func _purge_outdated_nodes() -> void: - var nodes_to_remove: Array[ProtonScatter] = [] - for node in _scatter_nodes: - if not is_instance_valid(node): - nodes_to_remove.push_back(node) - _local_cache.erase(_scene_root.get_path_to(node)) - _local_cache_changed = true - - for node in nodes_to_remove: - _scatter_nodes.erase(node) - - -func _ensure_cache_folder_exists() -> void: - if not DirAccess.dir_exists_absolute(DEFAULT_CACHE_FOLDER): - DirAccess.make_dir_recursive_absolute(DEFAULT_CACHE_FOLDER) - - -func _load_cache_threaded(cache_file_path: String) -> void: - # Cache files are large, load on a separate thread when possible - ResourceLoader.load_threaded_request(cache_file) - while true: - match ResourceLoader.load_threaded_get_status(cache_file): - ResourceLoader.ThreadLoadStatus.THREAD_LOAD_INVALID_RESOURCE: - return - ResourceLoader.ThreadLoadStatus.THREAD_LOAD_IN_PROGRESS: - await get_tree().process_frame - ResourceLoader.ThreadLoadStatus.THREAD_LOAD_FAILED: - return - ResourceLoader.ThreadLoadStatus.THREAD_LOAD_LOADED: - break - - _local_cache = ResourceLoader.load_threaded_get(cache_file) diff --git a/godot/addons/proton_scatter/src/cache/scatter_cache.gd.uid b/godot/addons/proton_scatter/src/cache/scatter_cache.gd.uid deleted file mode 100644 index 62210d4..0000000 --- a/godot/addons/proton_scatter/src/cache/scatter_cache.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cmdgshlf5dawf diff --git a/godot/addons/proton_scatter/src/common/bounds.gd b/godot/addons/proton_scatter/src/common/bounds.gd deleted file mode 100644 index a5486b4..0000000 --- a/godot/addons/proton_scatter/src/common/bounds.gd +++ /dev/null @@ -1,50 +0,0 @@ -@tool -extends Resource - -# Used by the Domain class -# TODO: This could be replaced by a built-in AABB - -var size: Vector3 -var center: Vector3 -var min: Vector3 -var max: Vector3 - -var _points := 0 - - -func clear() -> void: - size = Vector3.ZERO - center = Vector3.ZERO - min = Vector3.ZERO - max = Vector3.ZERO - _points = 0 - - -func feed(point: Vector3) -> void: - if _points == 0: - min = point - max = point - - min = _minv(min, point) - max = _maxv(max, point) - _points += 1 - - -# Call this after you've called feed() with all the points in your data set -func compute_bounds() -> void: - if min == null or max == null: - return - - size = max - min - center = min + (size / 2.0) - - -# Returns a vector with the smallest values in each of the 2 input vectors -func _minv(v1: Vector3, v2: Vector3) -> Vector3: - return Vector3(min(v1.x, v2.x), min(v1.y, v2.y), min(v1.z, v2.z)) - - -# Returns a vector with the highest values in each of the 2 input vectors -func _maxv(v1: Vector3, v2: Vector3) -> Vector3: - return Vector3(max(v1.x, v2.x), max(v1.y, v2.y), max(v1.z, v2.z)) - diff --git a/godot/addons/proton_scatter/src/common/bounds.gd.uid b/godot/addons/proton_scatter/src/common/bounds.gd.uid deleted file mode 100644 index 7e7bb98..0000000 --- a/godot/addons/proton_scatter/src/common/bounds.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bqu8by5a5tbtb diff --git a/godot/addons/proton_scatter/src/common/cache_resource.gd b/godot/addons/proton_scatter/src/common/cache_resource.gd deleted file mode 100644 index e499fdc..0000000 --- a/godot/addons/proton_scatter/src/common/cache_resource.gd +++ /dev/null @@ -1,27 +0,0 @@ -@tool -class_name ProtonScatterCacheResource -extends Resource - - -@export var data = {} - - -func clear() -> void: - data.clear() - - -func store(node_path: String, transforms: Array[Transform3D]) -> void: - data[node_path] = transforms - - -func erase(node_path: String) -> void: - data.erase(node_path) - - -func get_transforms(node_path: String) -> Array[Transform3D]: - var res: Array[Transform3D] - - if node_path in data: - res.assign(data[node_path]) - - return res diff --git a/godot/addons/proton_scatter/src/common/cache_resource.gd.uid b/godot/addons/proton_scatter/src/common/cache_resource.gd.uid deleted file mode 100644 index d12c7e4..0000000 --- a/godot/addons/proton_scatter/src/common/cache_resource.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://drokggkxglxws diff --git a/godot/addons/proton_scatter/src/common/domain.gd b/godot/addons/proton_scatter/src/common/domain.gd deleted file mode 100644 index ccb11e4..0000000 --- a/godot/addons/proton_scatter/src/common/domain.gd +++ /dev/null @@ -1,310 +0,0 @@ -@tool -extends RefCounted - -# A domain is the complete area where transforms can (and can't) be placed. -# A Scatter node has one single domain, a domain has one or more shape nodes. -# -# It's the combination of every shape defined under a Scatter node, grouped in -# a single class that exposes utility functions (check if a point is inside, or -# along the surface etc). -# -# An instance of this class is passed to the modifiers during a rebuild. - - -const BaseShape := preload("../shapes/base_shape.gd") -const Bounds := preload("../common/bounds.gd") - - -class DomainShapeInfo: - var node: Node3D - var shape: BaseShape - - func is_point_inside(point: Vector3, local: bool) -> bool: - var t: Transform3D - if is_instance_valid(node): - t = node.get_transform() if local else node.get_global_transform() - return shape.is_point_inside(point, t) - else: - return false - - func get_corners_global() -> Array: - return shape.get_corners_global(node.get_global_transform()) - -# A polygon made of one outer boundary and one or multiple holes (inner polygons) -class ComplexPolygon: - var inner: Array[PackedVector2Array] = [] - var outer: PackedVector2Array - - func add(polygon: PackedVector2Array) -> void: - if polygon.is_empty(): return - if Geometry2D.is_polygon_clockwise(polygon): - inner.push_back(polygon) - else: - if not outer.is_empty(): - print_debug("ProtonScatter error: Replacing polygon's existing outer boundary. This should not happen, please report.") - outer = polygon - - func add_array(array: Array, reverse := false) -> void: - for p in array: - if reverse: - p.reverse() - add(p) - - func get_all() -> Array[PackedVector2Array]: - var res = inner.duplicate() - res.push_back(outer) - return res - - func _to_string() -> String: - var res = "o: " + var_to_str(outer.size()) + ", i: [" - for i in inner: - res += var_to_str(i.size()) + ", " - res += "]" - return res - - -var root: ProtonScatter -var positive_shapes: Array[DomainShapeInfo] -var negative_shapes: Array[DomainShapeInfo] -var bounds_global: Bounds = Bounds.new() -var bounds_local: Bounds = Bounds.new() -var edges: Array[Curve3D] = [] - - -func is_empty() -> bool: - return positive_shapes.is_empty() - - -# If a point is in an exclusion shape, returns false -# If a point is in an inclusion shape (but not in an exclusion one), returns true -# If a point is in neither, returns false -func is_point_inside(point: Vector3, local := true) -> bool: - for s in negative_shapes: - if s.is_point_inside(point, local): - return false - - for s in positive_shapes: - if s.is_point_inside(point, local): - return true - - return false - - -# If a point is inside an exclusion shape, returns true -# Returns false in every other case -func is_point_excluded(point: Vector3, local := true) -> bool: - for s in negative_shapes: - if s.is_point_inside(point, local): - return true - - return false - - -# Recursively find all ScatterShape nodes under the provided root. In case of -# nested Scatter nodes, shapes under these other Scatter nodes will be ignored -func discover_shapes(root_node: Node3D) -> void: - root = root_node - positive_shapes.clear() - negative_shapes.clear() - - if not is_instance_valid(root): - return - - for c in root.get_children(): - _discover_shapes_recursive(c) - compute_bounds() - compute_edges() - - -func compute_bounds() -> void: - bounds_global.clear() - bounds_local.clear() - - if not is_instance_valid(root): - return - - var gt: Transform3D = root.get_global_transform().affine_inverse() - - for info in positive_shapes: - for point in info.get_corners_global(): - bounds_global.feed(point) - bounds_local.feed(gt * point) - - bounds_global.compute_bounds() - bounds_local.compute_bounds() - - -func compute_edges() -> void: - edges.clear() - - if not is_instance_valid(root): - return - - var source_polygons: Array[ComplexPolygon] = [] - - ## Retrieve all polygons - for info in positive_shapes: - # Store all closed polygons in a specific array - var polygon := ComplexPolygon.new() - polygon.add_array(info.shape.get_closed_edges(info.node.transform)) - - # Polygons with holes must be merged together first - if not polygon.inner.is_empty(): - source_polygons.push_back(polygon) - else: - source_polygons.push_front(polygon) - - # Store open edges directly since they are already Curve3D and we - # don't apply boolean operations to them. - var open_edges = info.shape.get_open_edges(info.node.transform) - edges.append_array(open_edges) - - if source_polygons.is_empty(): - return - - ## Merge all closed polygons together - var merged_polygons: Array[ComplexPolygon] = [] - - while not source_polygons.is_empty(): - var merged := false - var p1: ComplexPolygon = source_polygons.pop_back() - var max_steps: int = source_polygons.size() - var i = 0 - - # Test p1 against every other polygon from source_polygon until a - # successful merge. If no merge happened, put it in the final array. - while i < max_steps and not merged: - i += 1 - - # Get the next polygon in the list - var p2: ComplexPolygon = source_polygons.pop_back() - - # If the outer boundary of any of the two polygons is completely - # enclosed in one of the other polygon's hole, we don't try to - # merge them and go the next iteration. - var full_overlap = false - for ip1 in p1.inner: - var res = Geometry2D.clip_polygons(p2.outer, ip1) - if res.is_empty(): - full_overlap = true - break - - for ip2 in p2.inner: - var res = Geometry2D.clip_polygons(p1.outer, ip2) - if res.is_empty(): - full_overlap = true - break - - if full_overlap: - source_polygons.push_front(p2) - continue - - # Try to merge the two polygons p1 and p2 - var res = Geometry2D.merge_polygons(p1.outer, p2.outer) - var outer_polygons := 0 - for p in res: - if not Geometry2D.is_polygon_clockwise(p): - outer_polygons += 1 - - # If the merge generated a new polygon, process the holes data from - # the two original polygons and store in the new_polygon - # P1 and P2 are then discarded and replaced by the new polygon. - if outer_polygons == 1: - var new_polygon = ComplexPolygon.new() - new_polygon.add_array(res) - - # Process the holes data from p1 and p2 - for ip1 in p1.inner: - for ip2 in p2.inner: - new_polygon.add_array(Geometry2D.intersect_polygons(ip1, ip2), true) - new_polygon.add_array(Geometry2D.clip_polygons(ip2, p1.outer), true) - - new_polygon.add_array(Geometry2D.clip_polygons(ip1, p2.outer), true) - - source_polygons.push_back(new_polygon) - merged = true - - # If the polygons don't overlap, return it to the pool to be tested - # against other polygons - else: - source_polygons.push_front(p2) - - # If p1 is not overlapping any other polygon, add it to the final list - if not merged: - merged_polygons.push_back(p1) - - ## For each polygons from the previous step, create a corresponding Curve3D - for cp in merged_polygons: - for polygon in cp.get_all(): - if polygon.size() < 2: # Ignore polygons too small to form a loop - continue - - var curve := Curve3D.new() - for point in polygon: - curve.add_point(Vector3(point.x, 0.0, point.y)) - - # Close the look if the last vertex is missing (Randomly happens) - var first_point := polygon[0] - var last_point := polygon[-1] - if first_point != last_point: - curve.add_point(Vector3(first_point.x, 0.0, first_point.y)) - - edges.push_back(curve) - - -func get_root() -> ProtonScatter: - return root - - -func get_global_transform() -> Transform3D: - return root.get_global_transform() - - -func get_local_transform() -> Transform3D: - return root.get_transform() - - -func get_edges() -> Array[Curve3D]: - if edges.is_empty(): - compute_edges() - return edges - - -func get_copy(): - var copy = get_script().new() - - copy.root = root - copy.bounds_global = bounds_global - copy.bounds_local = bounds_local - - for s in positive_shapes: - var s_copy = DomainShapeInfo.new() - s_copy.node = s.node - s_copy.shape = s.shape.get_copy() - copy.positive_shapes.push_back(s_copy) - - for s in negative_shapes: - var s_copy = DomainShapeInfo.new() - s_copy.node = s.node - s_copy.shape = s.shape.get_copy() - copy.negative_shapes.push_back(s_copy) - - return copy - - -func _discover_shapes_recursive(node: Node) -> void: - if node is ProtonScatter: # Ignore shapes under nested Scatter nodes - return - - if node is ProtonScatterShape and node.shape != null: - var info := DomainShapeInfo.new() - info.node = node - info.shape = node.shape - - if node.negative: - negative_shapes.push_back(info) - else: - positive_shapes.push_back(info) - - for c in node.get_children(): - _discover_shapes_recursive(c) diff --git a/godot/addons/proton_scatter/src/common/domain.gd.uid b/godot/addons/proton_scatter/src/common/domain.gd.uid deleted file mode 100644 index 22d1424..0000000 --- a/godot/addons/proton_scatter/src/common/domain.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c7cr1oew02lo5 diff --git a/godot/addons/proton_scatter/src/common/event_helper.gd b/godot/addons/proton_scatter/src/common/event_helper.gd deleted file mode 100644 index 912d18c..0000000 --- a/godot/addons/proton_scatter/src/common/event_helper.gd +++ /dev/null @@ -1,72 +0,0 @@ -extends RefCounted - -# Utility class that mimics the Input class behavior -# -# This only useful when using actions from the Input class isn't possible, -# like in _unhandled_input or forward_3d_gui_input for example, where you don't -# have a native way to detect if a key was just pressed or released. -# -# How to use: -# Call the feed() method first with the latest event you received, then call -# either of the is_key_* function -# -# If you don't call feed() on the same frame before calling any of these two, -# the behavior is undefined. - - -var _actions := {} - - -func feed(event: InputEvent) -> void: - var key - if event is InputEventMouseButton: - key = event.button_index - elif event is InputEventKey: - key = event.keycode - else: - _cleanup_states() - return - - if not key in _actions: - _actions[key] = { - pressed = event.pressed, - just_released = not event.pressed, - just_pressed = event.pressed, - } - return - - var pressed = _actions[key].pressed - - if pressed and not event.pressed: - _actions[key].just_released = true - _actions[key].just_pressed = false - - if not pressed and event.pressed: - _actions[key].just_pressed = true - _actions[key].just_released = false - - if pressed and event.pressed: - _actions[key].just_pressed = false - _actions[key].just_released = false - - _actions[key].pressed = event.pressed - - -func _cleanup_states() -> void: - for key in _actions: - _actions[key].just_released = false - _actions[key].just_pressed = false - - -func is_key_just_pressed(key) -> bool: - if key in _actions: - return _actions[key].just_pressed - - return false - - -func is_key_just_released(key) -> bool: - if key in _actions: - return _actions[key].just_released - - return false diff --git a/godot/addons/proton_scatter/src/common/event_helper.gd.uid b/godot/addons/proton_scatter/src/common/event_helper.gd.uid deleted file mode 100644 index fc38f68..0000000 --- a/godot/addons/proton_scatter/src/common/event_helper.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dyu156s2mneok diff --git a/godot/addons/proton_scatter/src/common/physics_helper.gd b/godot/addons/proton_scatter/src/common/physics_helper.gd deleted file mode 100644 index 91d9b09..0000000 --- a/godot/addons/proton_scatter/src/common/physics_helper.gd +++ /dev/null @@ -1,103 +0,0 @@ -@tool -extends Node - -# Runs jobs during the physics step. -# Only supports raycast for now, but can easilly be adapted to handle -# the other types of queries. - -signal job_completed - - -const MAX_PHYSICS_QUERIES_SETTING := "addons/proton_scatter/max_physics_queries_per_frame" - - -var _is_ready := false -var _job_in_progress := false -var _max_queries_per_frame := 400 -var _main_thread_id: int -var _queries: Array -var _results: Array[Dictionary] -var _space_state: PhysicsDirectSpaceState3D - - -func _ready() -> void: - set_physics_process(false) - _main_thread_id = OS.get_thread_caller_id() - _is_ready = true - - -func _exit_tree(): - if _job_in_progress: - _job_in_progress = false - job_completed.emit() - - -func execute(queries: Array) -> Array[Dictionary]: - if not _is_ready: - printerr("ProtonScatter error: Calling execute on a PhysicsHelper before it's ready, this should not happen.") - return [] - - # Don't execute physics queries, if the node is not inside the tree. - # This avoids infinite loops, because the _physics_process will never be executed. - # This happens when the Scatter node is removed, while it perform a rebuild with a Thread. - if not is_inside_tree(): - printerr("ProtonScatter error: Calling execute on a PhysicsHelper while the node is not inside the tree.") - return [] - - # Clear previous job if any - _queries.clear() - - if _job_in_progress: - await _until(get_tree().physics_frame, func(): return _job_in_progress) - - _results.clear() - _queries = queries - _max_queries_per_frame = ProjectSettings.get_setting(MAX_PHYSICS_QUERIES_SETTING, 500) - _job_in_progress = true - set_physics_process.bind(true).call_deferred() - - await _until(job_completed, func(): return _job_in_progress, true) - - return _results.duplicate() - - -func _physics_process(_delta: float) -> void: - if _queries.is_empty(): - return - - if not _space_state: - _space_state = get_tree().get_root().get_world_3d().get_direct_space_state() - - var steps = min(_max_queries_per_frame, _queries.size()) - for i in steps: - var q = _queries.pop_back() - var hit := _space_state.intersect_ray(q) # TODO: Add support for other operations - _results.push_back(hit) - - if _queries.is_empty(): - set_physics_process(false) - _results.reverse() - _job_in_progress = false - job_completed.emit() - - -func _in_main_thread() -> bool: - return OS.get_thread_caller_id() == _main_thread_id - - -func _until(s: Signal, callable: Callable, physics := false) -> void: - if _in_main_thread(): - await s - return - - # Called from a sub thread - var delay: int = 0 - if physics: - delay = round(get_physics_process_delta_time() * 100.0) - else: - delay = round(get_process_delta_time() * 100.0) - - while callable.call(): - OS.delay_msec(delay) - if not is_inside_tree(): - return diff --git a/godot/addons/proton_scatter/src/common/physics_helper.gd.uid b/godot/addons/proton_scatter/src/common/physics_helper.gd.uid deleted file mode 100644 index 1013adb..0000000 --- a/godot/addons/proton_scatter/src/common/physics_helper.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c72grqs1osao2 diff --git a/godot/addons/proton_scatter/src/common/scatter_util.gd b/godot/addons/proton_scatter/src/common/scatter_util.gd deleted file mode 100644 index 0ab2e90..0000000 --- a/godot/addons/proton_scatter/src/common/scatter_util.gd +++ /dev/null @@ -1,524 +0,0 @@ -extends Node - -# To prevent the other core scripts from becoming too large, some of their -# utility functions are written here (only the functions that don't disturb -# reading the core code, mostly data validation and other verbose checks). - -### SCATTER UTILITY FUNCTIONS ### - - -# Make sure the output node exists. This is the parent node to -# everything generated by the scatter mesh -static func ensure_output_root_exists(s: ProtonScatter) -> void: - # Check if the node exists in the tree - if not s.output_root: - s.output_root = s.get_node_or_null("ScatterOutput") - - # If the node is valid, end here - if is_instance_valid(s.output_root) and s.has_node(NodePath(s.output_root.name)): - enforce_output_root_owner(s) - return - - # Some conditions are not met, cleanup and recreate the root - if s.output_root: - if s.has_node(NodePath(s.output_root.name)): - s.remove_node(s.output_root.name) - s.output_root.queue_free() - s.output_root = null - - s.output_root = Marker3D.new() - s.output_root.name = "ScatterOutput" - s.add_child(s.output_root, true) - - enforce_output_root_owner(s) - - -static func enforce_output_root_owner(s: ProtonScatter) -> void: - if is_instance_valid(s.output_root) and s.is_inside_tree(): - if s.show_output_in_tree: - set_owner_recursive(s.output_root, s.get_tree().get_edited_scene_root()) - else: - set_owner_recursive(s.output_root, null) - - # TMP: Workaround to force the scene tree to update and take in account - # the owner changes. Otherwise it doesn't show until much later. - s.output_root.update_configuration_warnings() - - -# Item root is a Node3D placed as a child of the ScatterOutput node. -# Each ScatterItem has a corresponding output node, serving as a parent for -# the Multimeshes or duplicates generated by the Scatter node. -static func get_or_create_item_root(item: ProtonScatterItem) -> Node3D: - var s: ProtonScatter = item.get_parent() - ensure_output_root_exists(s) - var item_root: Node3D = s.output_root.get_node_or_null(NodePath(item.name)) - - if not item_root: - item_root = Node3D.new() - item_root.name = item.name - s.output_root.add_child(item_root, true) - - if Engine.is_editor_hint(): - item_root.owner = item.get_tree().get_edited_scene_root() - - return item_root - - -static func get_or_create_multimesh(item: ProtonScatterItem, count: int) -> MultiMeshInstance3D: - var item_root := get_or_create_item_root(item) - var mmi: MultiMeshInstance3D = item_root.get_node_or_null("MultiMeshInstance3D") - - if not mmi: - mmi = MultiMeshInstance3D.new() - mmi.set_name("MultiMeshInstance3D") - item_root.add_child(mmi, true) - - mmi.set_owner(item_root.owner) - if not mmi.multimesh: - mmi.multimesh = MultiMesh.new() - if item.custom_script: - mmi.multimesh.use_colors = true - mmi.multimesh.use_custom_data = true - mmi.set_script(item.custom_script) - elif not item.custom_script: - # We should reset the use_* props of the multimesh, which fails if instance_count > 0. - mmi.multimesh.instance_count = 0 - mmi.multimesh.use_colors = false - mmi.multimesh.use_custom_data = false - - var mesh_instance: MeshInstance3D = get_merged_meshes_from(item) - if not mesh_instance: - return - - mmi.position = Vector3.ZERO - mmi.material_override = get_final_material(item, mesh_instance) - mmi.set_cast_shadows_setting(item.override_cast_shadow) - - mmi.multimesh.instance_count = 0 # Set this to zero or you can't change the other values - mmi.multimesh.mesh = mesh_instance.mesh - mmi.multimesh.transform_format = MultiMesh.TRANSFORM_3D - - mmi.visibility_range_begin = item.visibility_range_begin - mmi.visibility_range_begin_margin = item.visibility_range_begin_margin - mmi.visibility_range_end = item.visibility_range_end - mmi.visibility_range_end_margin = item.visibility_range_end_margin - mmi.visibility_range_fade_mode = item.visibility_range_fade_mode - mmi.layers = item.visibility_layers - - mmi.multimesh.instance_count = count - copy_instance_shader_parameters(mesh_instance, mmi) - - mesh_instance.queue_free() - - return mmi - - -static func get_or_create_multimesh_chunk(item: ProtonScatterItem, - mesh_instance: MeshInstance3D, - index: Vector3i, - count: int)\ - -> MultiMeshInstance3D: - var item_root := get_or_create_item_root(item) - var chunk_name = "MultiMeshInstance3D" + "_%s_%s_%s"%[index.x, index.y, index.z] - var mmi: MultiMeshInstance3D = item_root.get_node_or_null(chunk_name) - if not mesh_instance: - return - - if not mmi: - mmi = MultiMeshInstance3D.new() - mmi.set_name(chunk_name) - # if set_name is used after add_child it is crazy slow - # This doesn't make much sense but it is definitely the case. - # About a 100x slowdown was observed in this case - item_root.add_child.bind(mmi, true).call_deferred() - - if not mmi.multimesh: - mmi.multimesh = MultiMesh.new() - if item.custom_script: - mmi.multimesh.use_colors = true - mmi.multimesh.use_custom_data = true - mmi.set_script(item.custom_script) - elif not item.custom_script: - # We should reset the use_* props of the multimesh, which fails if instance_count > 0. - mmi.multimesh.instance_count = 0 - mmi.multimesh.use_colors = false - mmi.multimesh.use_custom_data = false - - mmi.position = Vector3.ZERO - mmi.material_override = get_final_material(item, mesh_instance) - mmi.set_cast_shadows_setting(item.override_cast_shadow) - - mmi.multimesh.instance_count = 0 # Set this to zero or you can't change the other values - mmi.multimesh.mesh = mesh_instance.mesh - mmi.multimesh.transform_format = MultiMesh.TRANSFORM_3D - - mmi.visibility_range_begin = item.visibility_range_begin - mmi.visibility_range_begin_margin = item.visibility_range_begin_margin - mmi.visibility_range_end = item.visibility_range_end - mmi.visibility_range_end_margin = item.visibility_range_end_margin - mmi.visibility_range_fade_mode = item.visibility_range_fade_mode - mmi.layers = item.visibility_layers - - mmi.multimesh.instance_count = count - copy_instance_shader_parameters(mesh_instance, mmi) - - return mmi - - -static func get_or_create_particles(item: ProtonScatterItem) -> GPUParticles3D: - var item_root := get_or_create_item_root(item) - var particles: GPUParticles3D = item_root.get_node_or_null("GPUParticles3D") - - if not particles: - particles = GPUParticles3D.new() - particles.set_name("GPUParticles3D") - item_root.add_child(particles) - - particles.set_owner(item_root.owner) - - var mesh_instance: MeshInstance3D = get_merged_meshes_from(item) - if not mesh_instance: - return - - particles.material_override = get_final_material(item, mesh_instance) - particles.set_draw_pass_mesh(0, mesh_instance.mesh) - particles.position = Vector3.ZERO - particles.local_coords = true - particles.layers = item.visibility_layers - - # Use the user provided material if it exists. - var process_material: Material = item.override_process_material - - # Or load the default one if there's nothing. - if not process_material: - process_material = ShaderMaterial.new() - process_material.shader = preload("../particles/static.gdshader") - - if process_material is ShaderMaterial: - process_material.set_shader_parameter("global_transform", item_root.get_global_transform()) - - particles.set_process_material(process_material) - - # TMP: Workaround to get infinite life time. - # Should be fine, but extensive testing is required. - # I can't get particles to restart when using emit_particle() from a script, so it's either - # that, or encoding the transform array in a texture an read that data from the particle - # shader, which is significantly harder. - particles.lifetime = 1.79769e308 - - # Kill previous particles or new ones will not spawn. - particles.restart() - - return particles - - -# Called from child nodes who affect the rebuild process (like ScatterShape) -# Usually, it would be the Scatter node responsibility to listen to changes from -# the children nodes, but keeping track of the children is annoying (they can -# be moved around from a Scatter node to another, or put under a wrong node, or -# other edge cases). -# So instead, when a child change, it notifies the parent Scatter node through -# this method. -static func request_parent_to_rebuild(node: Node, deferred := true) -> void: - var parent = node.get_parent() - if not parent or not parent.is_inside_tree(): - return - - if parent and parent is ProtonScatter: - if not parent.is_ready: - return - if not parent.enable_updates_in_game and not Engine.is_editor_hint(): - return - - if deferred: - parent.rebuild.call_deferred(true) - else: - parent.rebuild(true) - - -### MESH UTILITY ### - -# Recursively search for all MeshInstances3D in the node's children and -# returns them all in an array. If node is a MeshInstance, it will also be -# added to the array -static func get_all_mesh_instances_from(node: Node) -> Array[MeshInstance3D]: - var res: Array[MeshInstance3D] = [] - - if node is MeshInstance3D: - res.push_back(node) - - for c in node.get_children(): - res.append_array(get_all_mesh_instances_from(c)) - - return res - - -static func get_final_material(item: ProtonScatterItem, mi: MeshInstance3D) -> Material: - if item.override_material: - return item.override_material - - if mi.material_override: - return mi.material_override - - if mi.get_surface_override_material(0): - return mi.get_surface_override_material(0) - - return null - - -# Merge all the MeshInstances from the local node tree into a single MeshInstance. -# /!\ This is a best effort algorithm and will not work in some specific cases. /!\ -# -# Mesh resources can have a maximum of 8 surfaces: -# + If less than 8 different surfaces are found across all the MeshInstances, -# this returns a single instance with all the surfaces. -# -# + If more than 8 surfaces are found, but some shares the same material, -# these surfaces will be merged together if there's less than 8 unique materials. -# -# + If there's more than 8 unique materials, everything will be merged into -# a single surface. Material and custom data will NOT be preserved on the new mesh. -# -static func get_merged_meshes_from(item: ProtonScatterItem) -> MeshInstance3D: - if not item: - return null - - var source: Node = item.get_item() - if not is_instance_valid(source): - return null - - source.transform = Transform3D() - - # Get all the mesh instances - var mesh_instances: Array[MeshInstance3D] = get_all_mesh_instances_from(source) - source.queue_free() - - if mesh_instances.is_empty(): - return null - - # If there's only one mesh instance we can reuse it directly if the materials allow it. - if mesh_instances.size() == 1: - # Duplicate the meshinstance, not the mesh resource - var mi: MeshInstance3D = mesh_instances[0].duplicate() - copy_instance_shader_parameters(mesh_instances[0], mi) - - # MI uses a material override, all surface materials will be ignored - if mi.material_override: - return mi - - var surface_overrides_count := 0 - for i in mi.get_surface_override_material_count(): - if mi.get_surface_override_material(i): - surface_overrides_count += 1 - - # If there's one material override or less, no duplicate mesh is required. - if surface_overrides_count <= 1: - return mi - - # Helper lambdas - var get_material_for_surface = func (mi: MeshInstance3D, idx: int) -> Material: - if mi.get_material_override(): - return mi.get_material_override() - - if mi.get_surface_override_material(idx): - return mi.get_surface_override_material(idx) - - if mi.mesh is PrimitiveMesh: - return mi.mesh.get_material() - - return mi.mesh.surface_get_material(idx) - - # Count how many surfaces / materials there are in the source instances - var total_surfaces := 0 - var surfaces_map := {} - # Key: Material - # data: Array[Dictionary] - # "surface": surface index - # "mesh_instance": parent mesh instance - - for mi in mesh_instances: - if not mi.mesh: - continue # Should not happen - - # Update the total surface count - var surface_count = mi.mesh.get_surface_count() - total_surfaces += surface_count - - # Store surfaces in the material indexed dictionary - for surface_index in surface_count: - var material: Material = get_material_for_surface.call(mi, surface_index) - if not material in surfaces_map: - surfaces_map[material] = [] - - surfaces_map[material].push_back({ - "surface": surface_index, - "mesh_instance": mi, - }) - - # ------ - # Less than 8 surfaces, merge in a single MeshInstance - # ------ - if total_surfaces <= 8: - var mesh := ImporterMesh.new() - - for mi in mesh_instances: - var inverse_transform := mi.transform.affine_inverse() - - for surface_index in mi.mesh.get_surface_count(): - # Retrieve surface data - var primitive_type = Mesh.PRIMITIVE_TRIANGLES - var format = 0 - var arrays := mi.mesh.surface_get_arrays(surface_index) - if mi.mesh is ArrayMesh: - primitive_type = mi.mesh.surface_get_primitive_type(surface_index) - format = mi.mesh.surface_get_format(surface_index) # Preserve custom data format - - # Update vertex position based on MeshInstance transform - var vertex_count = arrays[ArrayMesh.ARRAY_VERTEX].size() - var vertex: Vector3 - for index in vertex_count: - vertex = arrays[ArrayMesh.ARRAY_VERTEX][index] * inverse_transform - arrays[ArrayMesh.ARRAY_VERTEX][index] = vertex - - # Get the material if any - var material: Material = get_material_for_surface.call(mi, surface_index) - - # Store updated surface data in the new mesh - mesh.add_surface(primitive_type, arrays, [], {}, material, "", format) - - if item.lod_generate: - mesh.generate_lods(item.lod_merge_angle, item.lod_split_angle, []) - - var instance := MeshInstance3D.new() - instance.mesh = mesh.get_mesh() - return instance - - # ------ - # Too many surfaces and materials, merge everything in a single one. - # ------ - var total_unique_materials := surfaces_map.size() - - if total_unique_materials > 8: - var surface_tool := SurfaceTool.new() - surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES) - - for mi in mesh_instances: - var mesh : Mesh = mi.mesh - for surface_i in mesh.get_surface_count(): - surface_tool.append_from(mesh, surface_i, mi.transform) - - var mesh := ImporterMesh.new() - mesh.add_surface(surface_tool.get_primitive_type(), surface_tool.commit_to_arrays()) - - if item.lod_generate: - mesh.generate_lods(item.lod_merge_angle, item.lod_split_angle, []) - - var instance = MeshInstance3D.new() - instance.mesh = mesh.get_mesh() - return instance - - # ------ - # Merge surfaces grouped by their materials - # ------ - var mesh := ImporterMesh.new() - - for material in surfaces_map.keys(): - var surface_tool := SurfaceTool.new() - surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES) - - var surfaces: Array = surfaces_map[material] - for data in surfaces: - var idx: int = data["surface"] - var mi: MeshInstance3D = data["mesh_instance"] - - surface_tool.append_from(mi.mesh, idx, mi.transform) - - mesh.add_surface( - surface_tool.get_primitive_type(), - surface_tool.commit_to_arrays(), - [], {}, - material) - - if item.lod_generate: - mesh.generate_lods(item.lod_merge_angle, item.lod_split_angle, []) - - var instance := MeshInstance3D.new() - instance.mesh = mesh.get_mesh() - return instance - - -static func get_all_static_bodies_from(node: Node) -> Array[StaticBody3D]: - var res: Array[StaticBody3D] = [] - - if node is StaticBody3D: - res.push_back(node) - - for c in node.get_children(): - res.append_array(get_all_static_bodies_from(c)) - - return res - - -# Grab every static bodies from the source item and merge them in a single -# one with multiple collision shapes. -static func get_collision_data(item: ProtonScatterItem) -> StaticBody3D: - var static_body := StaticBody3D.new() - var source: Node3D = item.get_item() - if not is_instance_valid(source): - return static_body - - source.transform = Transform3D() - - for body in get_all_static_bodies_from(source): - for child in body.get_children(): - if child is CollisionShape3D: - # Don't use reparent() here or the child transform gets reset. - body.remove_child(child) - child.owner = null - static_body.add_child(child) - - source.queue_free() - return static_body - - -static func set_owner_recursive(node: Node, new_owner) -> void: - node.set_owner(new_owner) - - if not node.get_scene_file_path().is_empty(): - return # Node is an instantiated scene, don't change its children owner. - - for c in node.get_children(): - set_owner_recursive(c, new_owner) - - -static func get_aabb_from_transforms(transforms : Array) -> AABB: - if transforms.size() < 1: - return AABB(Vector3.ZERO, Vector3.ZERO) - var aabb = AABB(transforms[0].origin, Vector3.ZERO) - for t in transforms: - aabb = aabb.expand(t.origin) - return aabb - - -static func set_visibility_layers(node: Node, layers: int) -> void: - if node is VisualInstance3D: - node.layers = layers - for child in node.get_children(): - set_visibility_layers(child, layers) - - -## This assumes both instances shares the same uniforms, but doesn't actually -## check if the copy is valid or not. -static func copy_instance_shader_parameters(source: GeometryInstance3D, target: GeometryInstance3D) -> void: - const SHADER_PARAMETER_PREFIX := &"instance_shader_parameters/" - for property: Dictionary in source.get_property_list(): - var p_name: String = property["name"] - if not p_name.begins_with(SHADER_PARAMETER_PREFIX): - continue - var uniform_name: String = p_name.trim_prefix(SHADER_PARAMETER_PREFIX) - if uniform_name.is_empty(): - continue - var value: Variant = source.get_instance_shader_parameter(uniform_name) - if value == null: - continue - target.set_instance_shader_parameter(uniform_name, value) diff --git a/godot/addons/proton_scatter/src/common/scatter_util.gd.uid b/godot/addons/proton_scatter/src/common/scatter_util.gd.uid deleted file mode 100644 index 8a8bc1e..0000000 --- a/godot/addons/proton_scatter/src/common/scatter_util.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dr5nhp2ns6oha diff --git a/godot/addons/proton_scatter/src/common/transform_list.gd b/godot/addons/proton_scatter/src/common/transform_list.gd deleted file mode 100644 index a0328eb..0000000 --- a/godot/addons/proton_scatter/src/common/transform_list.gd +++ /dev/null @@ -1,74 +0,0 @@ -@tool -extends RefCounted - - -var list: Array[Transform3D] = [] -var max_count := -1 - - -func add(count: int) -> void: - for i in count: - var t := Transform3D() - list.push_back(t) - - -func append(array: Array[Transform3D]) -> void: - list.append_array(array) - - -func remove(count: int) -> void: - count = int(max(count, 0)) # Prevent using a negative number - var new_size = max(list.size() - count, 0) - list.resize(new_size) - - -func resize(count: int) -> void: - if max_count >= 0: - count = int(min(count, max_count)) - - var current_count = list.size() - if count > current_count: - add(count - current_count) - else: - remove(current_count - count) - - -# TODO: Faster algorithm probably exists for this, research an alternatives -# if this ever becomes a performance bottleneck. -func shuffle(random_seed := 0) -> void: - var n = list.size() - if n < 2: - return - - var rng = RandomNumberGenerator.new() - rng.set_seed(random_seed) - - var i = n - 1 - var j - var tmp - while i >= 1: - j = rng.randi() % (i + 1) - tmp = list[j] - list[j] = list[i] - list[i] = tmp - i -= 1 - - -func clear() -> void: - list = [] - - -func is_empty() -> bool: - return list.is_empty() - - -func size() -> int: - return list.size() - - -func enforce_uniform_scale() -> void: - for i: int in list.size(): - var t: Transform3D = list[i] - var current_scale: Vector3 = t.basis.get_scale() - var scale := Vector3.ONE * (current_scale.x + current_scale.y + current_scale.z) / 3.0 - list[i] = list[i].orthonormalized().scaled_local(scale) diff --git a/godot/addons/proton_scatter/src/common/transform_list.gd.uid b/godot/addons/proton_scatter/src/common/transform_list.gd.uid deleted file mode 100644 index 28a64bd..0000000 --- a/godot/addons/proton_scatter/src/common/transform_list.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cqodw55oksoui diff --git a/godot/addons/proton_scatter/src/common/util.gd b/godot/addons/proton_scatter/src/common/util.gd deleted file mode 100644 index 50242b0..0000000 --- a/godot/addons/proton_scatter/src/common/util.gd +++ /dev/null @@ -1,29 +0,0 @@ -@tool -extends RefCounted - - -static func get_position_and_normal_at(curve: Curve3D, offset: float) -> Array: - if not curve: - return [] - - var pos: Vector3 = curve.sample_baked(offset) - var normal := Vector3.ZERO - - var pos1 - if offset + curve.get_bake_interval() < curve.get_baked_length(): - pos1 = curve.sample_baked(offset + curve.get_bake_interval()) - normal = (pos1 - pos) - else: - pos1 = curve.sample_baked(offset - curve.get_bake_interval()) - normal = (pos - pos1) - - return [pos, normal] - - -static func remove_line_breaks(text: String) -> String: - # Remove tabs - text = text.replace("\t", "") - # Remove line breaks - text = text.replace("\n", " ") - # Remove occasional double space caused by the line above - return text.replace(" ", " ") diff --git a/godot/addons/proton_scatter/src/common/util.gd.uid b/godot/addons/proton_scatter/src/common/util.gd.uid deleted file mode 100644 index 2b27ab4..0000000 --- a/godot/addons/proton_scatter/src/common/util.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d0v1ka4262bwf diff --git a/godot/addons/proton_scatter/src/documentation/documentation.gd b/godot/addons/proton_scatter/src/documentation/documentation.gd deleted file mode 100644 index 46b7df1..0000000 --- a/godot/addons/proton_scatter/src/documentation/documentation.gd +++ /dev/null @@ -1,284 +0,0 @@ -@tool -extends PopupPanel - - -# Formats and displays the DocumentationData provided by other parts of the addon -# TODO: Adjust title font size based on the editor font size / scaling - - -const DocumentationInfo = preload("./documentation_info.gd") -const SpecialPages = preload("./pages/special_pages.gd") - -var _pages := {} -var _items := {} -var _categories_roots := {} - -var _modifiers_root: TreeItem - -var _edited_text: String -var _accent_color := Color.CORNFLOWER_BLUE -var _editor_scale := 1.0 -var _header_size := 20 -var _sub_header_size := 16 - -var _populated := false - - -@onready var tree: Tree = $HSplitContainer/Tree -@onready var label: RichTextLabel = $HSplitContainer/RichTextLabel - - -func _ready() -> void: - tree.create_item() # Create tree root - tree.hide_root = true - tree.item_selected.connect(_on_item_selected) - - add_page(SpecialPages.get_scatter_documentation(), tree.create_item()) - add_page(SpecialPages.get_item_documentation(), tree.create_item()) - add_page(SpecialPages.get_shape_documentation(), tree.create_item()) - add_page(SpecialPages.get_cache_documentation(), tree.create_item()) - - _modifiers_root = tree.create_item() - add_page(SpecialPages.get_modifiers_documentation(), _modifiers_root) - - _populate() - - -# Fed from the StackPanel scene, before the ready function -func set_editor_plugin(editor_plugin: EditorPlugin) -> void: - if not editor_plugin: - return - - var editor_interface := editor_plugin.get_editor_interface() - var editor_settings := editor_interface.get_editor_settings() - - _accent_color = editor_settings.get("interface/theme/accent_color") - _editor_scale = editor_interface.get_editor_scale() - - -func show_page(page_name: String) -> void: - if not page_name in _items: - return - - var item: TreeItem = _items[page_name] - item.select(0) - popup_centered(Vector2i(900, 600)) - - -# Generate a formatted string from the DocumentationInfo input. -# This string will be stored and later displayed in the RichTextLabel so we -# we don't have to regenerate it everytime we look at another page. -func add_page(info: DocumentationInfo, item: TreeItem = null) -> void: - if not item: - var root: TreeItem = _get_or_create_tree_root(info.get_category()) - item = tree.create_item(root) - - item.set_text(0, info.get_title()) - - _begin_formatting() - - # Page title - _format_title(info.get_title()) - - # Paragraphs - for p in info.get_paragraphs(): - _format_paragraph(p) - - # Parameters - if not info.get_parameters().is_empty(): - _format_subtitle("Parameters") - - for p in info.get_parameters(): - _format_parameter(p) - - # Warnings - if not info.get_warnings().is_empty(): - _format_subtitle("Warnings") - - for w in info.get_warnings(): - _format_warning(w) - - _pages[item] = _get_formatted_text() - _items[info.get_title()] = item - - -func _populate(): - if _populated: # Already generated the documentation pages - return - - var path = _get_root_folder() + "/src/modifiers/" - var result := {} - _discover_modifiers_recursive(path, result) - - var names := result.keys() - names.sort() - - for n in names: - var info = result[n] - add_page(info) - - _populated = true - - -func _discover_modifiers_recursive(path, result) -> void: - var dir = DirAccess.open(path) - dir.list_dir_begin() - var path_root = dir.get_current_dir() + "/" - - while true: - var file = dir.get_next() - if file == "": - break - if file == "base_modifier.gd": - continue - if dir.current_is_dir(): - _discover_modifiers_recursive(path_root + file, result) - continue - if not file.ends_with(".gd") and not file.ends_with(".gdc"): - continue - - var full_path = path_root + file - var script = load(full_path) - if not script or not script.can_instantiate(): - print("Error: Failed to load script ", file) - continue - - var modifier = script.new() - - var info: DocumentationInfo = modifier.documentation - info.set_title(modifier.display_name) - info.set_category(modifier.category) - if modifier.use_edge_data: - info.add_warning( - "This modifier uses edge data (represented by the blue lines - on the Scatter node). These edges are usually locked to the - local XZ plane, (except for the Path shape when they are - NOT closed). If you can't see these lines, make sure to have at - least one Shape crossing the ProtonScatter local XZ plane.", - 1) - - if modifier.deprecated: - info.add_warning( - "This modifier has been deprecated. It won't receive any updates - and will be deleted in a future update.", - 2) - - result[modifier.display_name] = info - - dir.list_dir_end() - - -func _get_root_folder() -> String: - var script: Script = get_script() - var path: String = script.get_path().get_base_dir() - var folders = path.right(-6) # Remove the res:// - var tokens = folders.split('/') - return "res://" + tokens[0] + "/" + tokens[1] - - -func _get_or_create_tree_root(root_name: String) -> TreeItem: - if root_name in _categories_roots: - return _categories_roots[root_name] - - var root = tree.create_item(_modifiers_root) - root.set_text(0, root_name) - root.set_selectable(0, false) - _categories_roots[root_name] = root - return root - - -func _begin_formatting() -> void: - _edited_text = "" - - -func _get_formatted_text() -> String: - return _edited_text - - -func _format_title(text: String) -> void: - _edited_text += "[font_size=" + var_to_str(_header_size * _editor_scale) + "]" - _edited_text += "[color=" + _accent_color.to_html() + "]" - _edited_text += "[center][b]" - _edited_text += text - _edited_text += "[/b][/center]" - _edited_text += "[/color]" - _edited_text += "[/font_size]" - _format_line_break(2) - - -func _format_subtitle(text: String) -> void: - _edited_text += "[font_size=" + var_to_str(_header_size * _editor_scale) + "]" - _edited_text += "[color=" + _accent_color.to_html() + "]" - _edited_text += "[b]" + text + "[/b]" - _edited_text += "[/color]" - _edited_text += "[/font_size]" - _format_line_break(2) - - -func _format_line_break(count := 1) -> void: - for i in count: - _edited_text += "\n" - - -func _format_paragraph(text: String) -> void: - _edited_text += "[p]" + text + "[/p]" - _format_line_break(2) - - -func _format_parameter(p) -> void: - var root_folder = _get_root_folder() - - _edited_text += "[indent]" - - if not p.type.is_empty(): - var file_name = p.type.to_lower() + ".svg" - _edited_text += "[img]" + root_folder + "/icons/types/" + file_name + "[/img] " - - _edited_text += "[b]" + p.name + "[/b] " - - match p.cost: - 1: - _edited_text += "[img]" + root_folder + "/icons/arrow_log.svg[/img]" - 2: - _edited_text += "[img]" + root_folder + "/icons/arrow_linear.svg[/img]" - 3: - _edited_text += "[img]" + root_folder + "/icons/arrow_exp.svg[/img]" - - _format_line_break(2) - _edited_text += "[indent]" + p.description + "[/indent]" - _format_line_break(2) - - for warning in p.warnings: - if not warning.text.is_empty(): - _format_warning(warning) - - _edited_text += "[/indent]" - - -func _format_warning(w, indent := true) -> void: - if indent: - _edited_text += "[indent]" - - var color := "Darkgray" - match w.importance: - 1: - color = "yellow" - 2: - color = "red" - - _edited_text += "[color=" + color + "][i]" + w.text + "[/i][/color]\n" - - if indent: - _edited_text += "[/indent]" - - _format_line_break(1) - - -func _on_item_selected() -> void: - var selected: TreeItem = tree.get_selected() - - if _pages.has(selected): - var text: String = _pages[selected] - label.set_text(text) - else: - label.set_text("[center] Under construction [/center]") diff --git a/godot/addons/proton_scatter/src/documentation/documentation.gd.uid b/godot/addons/proton_scatter/src/documentation/documentation.gd.uid deleted file mode 100644 index a828c9c..0000000 --- a/godot/addons/proton_scatter/src/documentation/documentation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0xdxl8smb6eo diff --git a/godot/addons/proton_scatter/src/documentation/documentation.tscn b/godot/addons/proton_scatter/src/documentation/documentation.tscn deleted file mode 100644 index 0bcaa8f..0000000 --- a/godot/addons/proton_scatter/src/documentation/documentation.tscn +++ /dev/null @@ -1,29 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cfg8iqtuion8b"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/documentation/documentation.gd" id="1_5c4lw"] -[ext_resource type="PackedScene" uid="uid://cojoo2c73fpsb" path="res://addons/proton_scatter/src/documentation/panel.tscn" id="2_vpfxu"] - -[node name="Documentation" type="PopupPanel"] -title = "ProtonScatter documentation" -exclusive = true -unresizable = false -borderless = false -script = ExtResource("1_5c4lw") - -[node name="HSplitContainer" parent="." instance=ExtResource("2_vpfxu")] -offset_left = 4.0 -offset_top = 4.0 -offset_right = -1824.0 -offset_bottom = -984.0 - -[node name="Tree" parent="HSplitContainer" index="0"] -offset_right = 80.0 -offset_bottom = 92.0 -hide_root = true - -[node name="RichTextLabel" parent="HSplitContainer" index="1"] -offset_left = 92.0 -offset_right = 92.0 -offset_bottom = 92.0 - -[editable path="HSplitContainer"] diff --git a/godot/addons/proton_scatter/src/documentation/documentation_info.gd b/godot/addons/proton_scatter/src/documentation/documentation_info.gd deleted file mode 100644 index b6eac91..0000000 --- a/godot/addons/proton_scatter/src/documentation/documentation_info.gd +++ /dev/null @@ -1,113 +0,0 @@ -@tool -extends RefCounted - - -# Stores raw documentation data. - -# The data is provided by any class that needs an entry in the documentation -# panel. This was initially designed for all the modifiers, but might be expanded -# to other parts of the addon as well. - -# Formatting is handled by the main Documentation class. - -const Util := preload("../common/util.gd") - - -class Warning: - var text: String - var importance: int - -class Parameter: - var name: String - var cost: int - var type: String - var description: String - var warnings: Array[Warning] = [] - - func set_name(text: String) -> Parameter: - name = Util.remove_line_breaks(text) - return self - - func set_description(text: String) -> Parameter: - description = Util.remove_line_breaks(text) - return self - - func set_cost(val: int) -> Parameter: - cost = val - return self - - func set_type(val: String) -> Parameter: - type = Util.remove_line_breaks(val) - return self - - func add_warning(warning: String, warning_importance := -1) -> Parameter: - var w = Warning.new() - w.text = Util.remove_line_breaks(warning) - w.importance = warning_importance - warnings.push_back(w) - return self - - -var _category: String -var _page_title: String -var _paragraphs: Array[String] = [] -var _warnings: Array[Warning] = [] -var _parameters: Array[Parameter] = [] - - -func set_category(text: String) -> void: - _category = text - - -func set_title(text: String) -> void: - _page_title = text - - -func add_paragraph(text: String) -> void: - _paragraphs.push_back(Util.remove_line_breaks(text)) - - -# Warning importance: -# 0: Default (Grey) -# 1: Mid (Yellow) -# 2: Critical (Red) -func add_warning(text: String, importance: int = 0) -> void: - var w = Warning.new() - w.text = Util.remove_line_breaks(text) - w.importance = importance - - _warnings.push_back(w) - - -# Add documentation for a user exposed parameter. -# Cost: -# 0: None -# 1: Log -# 2: Linear -# 3: Exponential -func add_parameter(name := "") -> Parameter: - var p = Parameter.new() - p.name = name - p.cost = 0 - _parameters.push_back(p) - return p - - -func get_title() -> String: - return _page_title - - -func get_category() -> String: - return _category - - -func get_paragraphs() -> Array[String]: - return _paragraphs - - -func get_warnings() -> Array[Warning]: - return _warnings - - -func get_parameters() -> Array[Parameter]: - return _parameters diff --git a/godot/addons/proton_scatter/src/documentation/documentation_info.gd.uid b/godot/addons/proton_scatter/src/documentation/documentation_info.gd.uid deleted file mode 100644 index 65d5fa6..0000000 --- a/godot/addons/proton_scatter/src/documentation/documentation_info.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ban4ir1q1wmgh diff --git a/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd b/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd deleted file mode 100644 index 1736632..0000000 --- a/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd +++ /dev/null @@ -1,150 +0,0 @@ -@tool -extends RefCounted - -const DocumentationInfo = preload("../documentation_info.gd") - - -static func get_scatter_documentation() -> DocumentationInfo: - var info := DocumentationInfo.new() - - info.set_title("ProtonScatter") - info.add_paragraph( - "ProtonScatter is a content positioning add-on. It is suited to place - a large amount of objects in a procedural way.") - info.add_paragraph( - "This add-on is [color=red][b]IN BETA[/b][/color] which means breaking - changes may happen. It is not recommended to use in production yet." - ) - info.add_paragraph( - "First, define [i]what[/i] you want to place using [b]ScatterItems[/b] - nodes.") - info.add_paragraph( - "Then, define [i]where[/i] to place them using [b]ScatterShapes[/b] - nodes.") - info.add_paragraph( - "Finaly, define [i]how[/i] the content should be placed using the - [b]Modifier stack[/b] that's on the [b]ProtonScatter[/b] node.") - info.add_paragraph( - "Each of these components have their dedicated documenation page, but - first, you should check out the example scenes in the demo folder.") - - var p := info.add_parameter("General / Global seed") - p.set_type("int") - p.set_description( - "The random seed to use on this node. Modifiers using random components - can access this value and use it accordingly. You can also specify - a custom seed for specific modifiers as well.") - - p = info.add_parameter("General / Show output in tree") - p.set_type("bool") - p.set_description( - "Show the generated items in the editor scene tree. By default this - option is disabled as it creates quite a bit of clutter when instancing - is disabled. It also increases the scene file size significantly.") - - p = info.add_parameter("Performance / Use instancing") - p.set_type("bool") - p.set_description( - "When enabled, ProtonScatter will use MultiMeshInstance3D nodes - instead of duplicating the source nodes. This allows the GPU to render - thousands of meshes in a single draw call.") - p.add_warning("Collisions and attached scripts are ignored when this - option is enabled.", 1) - - return info - - -static func get_item_documentation() -> DocumentationInfo: - var info := DocumentationInfo.new() - - info.set_title("ScatterItems") - - info.add_paragraph("TODO: Write this page") - - return info - - -static func get_shape_documentation() -> DocumentationInfo: - var info := DocumentationInfo.new() - - info.set_title("ScatterShapes") - - info.add_paragraph("TODO: Write this page") - - return info - - -static func get_cache_documentation() -> DocumentationInfo: - var info := DocumentationInfo.new() - - info.set_title("ScatterCache") - - info.add_paragraph( - "By default, Scatter nodes will recalculate their output on load, - which can be slow in really complex scenes. The cache allows you to - store these results in a file on your disk, and load these instead.") - info.add_paragraph( - "This can significantly speed up loading times, while also being VCS - friendly since the transforms are stored in their own files, rather - than your scenes files.") - info.add_paragraph("[b]How to use:[/b]") - info.add_paragraph( - "[p]+ Disable the [code]Force rebuild on load[code] on every Scatter item you want to cache.[/p] - [p]+ Add a ScatterCache node anywhere in your scene.[/p] - [p]+ Press the 'Rebuild' button to scan for other ProtonScatter nodes - and store their results in the cache.[/p]") - info.add_paragraph("[i]A single cache per scene is enough.[/i]") - - var p := info.add_parameter("Cache File") - p.set_cost(0) - p.set_description("Path to the cache file. By default they are store in the - add-on folder. Their name has a random component to avoid naming collisions - with scenes sharing the same file name. You are free to place this file - anywhere, using any name you would like.") - - return info - - -static func get_modifiers_documentation() -> DocumentationInfo: - var info := DocumentationInfo.new() - - info.set_title("Modifiers") - info.add_paragraph( - "A modifier takes in a Transform3D list, create, modify or delete - transforms, then pass it down to the next modifier. Remember that - [b] modifiers are processed from top to bottom [/b]. A modifier - down the stack will recieve a list processed by the modifiers above.") - info.add_paragraph( - "The initial transform list is empty, so it's necessary to start the - stack with a [b] Create [/b] modifier.") - info.add_paragraph( - "When clicking the [b] Expand button [/b] (the little arrow on the left) - you get access to this modifier's parameters. This is where you can - adjust its behavior according to your needs.") - info.add_paragraph( - "Three common options might be found on these modifiers. (They may - not appear if they are irrelevant). They are defined as follow:") - - var p := info.add_parameter("Use local seed") - p.set_type("bool") - p.set_description( - "The dice icon on the left allows you to force a specific seed for the - modifier. If this option is not used then the Global seed from the - ProtonScatter node will be used instead.") - - p = info.add_parameter("Restrict height") - p.set_type("bool") - p.set_description( - "When applicable, the modifier will remain within the local XZ plane - instead of using the full volume described by the ScatterShape nodes.") - - p = info.add_parameter("Reference frame") - p.set_type("int") - p.set_description( - "[p]+ [b]Global[/b]: Modifier operates in Global space. [/p] - [p]+ [b]Local[/b]: Modifier operates in local space, relative to the ProtonScatter node.[/p] - [p]+ [b]Individual[/b]: Modifier operates on local space, relative to each - individual transforms.[/p]" - ) - - return info diff --git a/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd.uid b/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd.uid deleted file mode 100644 index 92ffbb8..0000000 --- a/godot/addons/proton_scatter/src/documentation/pages/special_pages.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dbtvul6q3pwl diff --git a/godot/addons/proton_scatter/src/documentation/panel.tscn b/godot/addons/proton_scatter/src/documentation/panel.tscn deleted file mode 100644 index f5687e3..0000000 --- a/godot/addons/proton_scatter/src/documentation/panel.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene format=3 uid="uid://cojoo2c73fpsb"] - -[node name="HSplitContainer" type="HSplitContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -split_offset = 250 - -[node name="Tree" type="Tree" parent="."] -layout_mode = 2 -offset_right = 250.0 -offset_bottom = 648.0 - -[node name="RichTextLabel" type="RichTextLabel" parent="."] -layout_mode = 2 -offset_left = 262.0 -offset_right = 1152.0 -offset_bottom = 648.0 -bbcode_enabled = true -text = "[center] [b] [i] Documentation page [/i] [/b] [/center]" diff --git a/godot/addons/proton_scatter/src/modifiers/array.gd b/godot/addons/proton_scatter/src/modifiers/array.gd deleted file mode 100644 index d9abe1e..0000000 --- a/godot/addons/proton_scatter/src/modifiers/array.gd +++ /dev/null @@ -1,182 +0,0 @@ -@tool -extends "base_modifier.gd" - -# Takes existing objects and duplicates them recursively with given transforms - - -@export var amount := 1 -@export var min_amount := -1 -@export var local_offset := false -@export var offset := Vector3.ZERO -@export var local_rotation := false -@export var rotation := Vector3.ZERO -@export var individual_rotation_pivots := true -@export var rotation_pivot := Vector3.ZERO -@export var local_scale := true -@export var scale := Vector3.ONE -@export var randomize_indices := true - -var _rng: RandomNumberGenerator - - -func _init() -> void: - display_name = "Array" - category = "Create" - can_override_seed = true - can_restrict_height = false - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - - documentation.add_paragraph( - "Recursively creates copies of the existing transforms, with each copy - being offset from the previous one in any of a number of possible ways.") - - var p := documentation.add_parameter("Amount") - p.set_type("int") - p.set_cost(2) - p.set_description( - "The iteration count. If set to 1, each existing transforms are copied - once.") - p.add_warning("If set to 0, no copies are created.") - - p = documentation.add_parameter("Minimum amount") - p.set_type("int") - p.set_description( - "Creates a random amount of copies for each transforms, between this - value and the amount value.") - p.add_warning("Ignored if set to a negative value.") - - p = documentation.add_parameter("Offset") - p.set_type("Vector3") - p.set_description( - "Adds a constant offset between each copies and the previous one.") - - p = documentation.add_parameter("Local offset") - p.set_type("bool") - p.set_description( - "If enabled, offset is relative to the previous copy orientation. - Otherwise, the offset is in global space.") - - p = documentation.add_parameter("Rotation") - p.set_type("Vector3") - p.set_description( - "The rotation offset (on each axes) to add on each copy.") - - p = documentation.add_parameter("Local rotation") - p.set_type("bool") - p.set_description( - "If enabled, the rotation is applied in local space relative to each - individual transforms. Otherwise, the rotation is applied in global - space.") - - p = documentation.add_parameter("Rotation Pivot") - p.set_type("Vector3") - p.set_description( - "The point around which each copies are rotated. By default, each - transforms are rotated around their individual centers.") - - p = documentation.add_parameter("Individual Rotation Pivots") - p.set_type("bool") - p.set_description( - "If enabled, each copies will use their own pivot relative to the - previous copy. Otherwise, a single pivot point (defined in global space) - will be used for the rotation of [b]all[/b] the copies.") - - p = documentation.add_parameter("Scale") - p.set_type("Vector3") - p.set_description( - "Scales the copies relative to the transforms they are from.") - - p = documentation.add_parameter("Local Scale") - p.set_type("bool") - p.set_description( - "If enabled, scaling is applied in local space relative to each - individual transforms. Otherwise, global axes are used, resulting - in skewed transforms in most cases.") - - p = documentation.add_parameter("Randomize Indices") - p.set_type("bool") - p.set_description( - "Randomize the transform list order. This is only useful to break up the - repetitive patterns if you're using multiple ScatterItem nodes.") - - -func _process_transforms(transforms, domain, random_seed: int) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(random_seed) - - var new_transforms: Array[Transform3D] = [] - var rotation_rad := Vector3.ZERO - - rotation_rad.x = deg_to_rad(rotation.x) - rotation_rad.y = deg_to_rad(rotation.y) - rotation_rad.z = deg_to_rad(rotation.z) - - var axis_x := Vector3.RIGHT - var axis_y := Vector3.UP - var axis_z := Vector3.FORWARD - - for t in transforms.size(): - new_transforms.push_back(transforms.list[t]) - - var steps = amount - if min_amount >= 0: - steps = _rng.randi_range(min_amount, amount) - - for a in steps: - a += 1 - - # use original object's transform as base transform - var transform : Transform3D = transforms.list[t] - var basis := transform.basis - - # first move to rotation point defined in rotation offset - var rotation_pivot_offset = rotation_pivot - if individual_rotation_pivots: - rotation_pivot_offset = transform * rotation_pivot - - transform.origin -= rotation_pivot_offset - - # then rotate - if local_rotation: - axis_x = basis.x.normalized() - axis_y = basis.y.normalized() - axis_z = basis.z.normalized() - - transform = transform.rotated(axis_x, rotation_rad.x * a) - transform = transform.rotated(axis_y, rotation_rad.y * a) - transform = transform.rotated(axis_z, rotation_rad.z * a) - - # scale - # If the scale is different than 1, each transform gets bigger or - # smaller for each iteration. - var s = scale - s.x = pow(s.x, a) - s.y = pow(s.y, a) - s.z = pow(s.z, a) - - if local_scale: - transform.basis.x *= s.x - transform.basis.y *= s.y - transform.basis.z *= s.z - else: - transform.basis = transform.basis.scaled(s) - - # apply changes back to the transform and undo the rotation pivot offset - transform.origin += rotation_pivot_offset - - # offset - if local_offset: - transform.origin += offset * a - else: - transform.origin += (basis * offset) * a - - # store the final result if the position is valid - if not domain.is_point_excluded(transform.origin): - new_transforms.push_back(transform) - - transforms.list = new_transforms - - if randomize_indices: - transforms.shuffle(random_seed) diff --git a/godot/addons/proton_scatter/src/modifiers/array.gd.uid b/godot/addons/proton_scatter/src/modifiers/array.gd.uid deleted file mode 100644 index f461139..0000000 --- a/godot/addons/proton_scatter/src/modifiers/array.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://lgqxxvomwi6r diff --git a/godot/addons/proton_scatter/src/modifiers/base_modifier.gd b/godot/addons/proton_scatter/src/modifiers/base_modifier.gd deleted file mode 100644 index c166f6e..0000000 --- a/godot/addons/proton_scatter/src/modifiers/base_modifier.gd +++ /dev/null @@ -1,126 +0,0 @@ -@tool -class_name ScatterBaseModifier -extends Resource - -# Modifiers place transforms. They create, edit or remove transforms in a list, -# before the next Modifier in the stack does the same. -# All Modifiers must inherit from this class. -# Transforms in the provided transforms list must be in global space. - - -signal warning_changed -signal modifier_changed - -const TransformList = preload("../common/transform_list.gd") -const Domain = preload("../common/domain.gd") -const DocumentationInfo = preload("../documentation/documentation_info.gd") - -@export var enabled := true -@export var override_global_seed := false -@export var custom_seed := 0 -@export var restrict_height := false # Tells the modifier whether to constrain transforms to the local XY plane or not -@export var reference_frame := 0 - -var display_name: String = "Base Modifier Name" -var category: String = "None" -var documentation := DocumentationInfo.new() -var warning: String = "" -var warning_ignore_no_transforms := false -var warning_ignore_no_shape := true -var expanded := false -var can_override_seed := false -var can_restrict_height := true -var global_reference_frame_available := true -var local_reference_frame_available := false -var individual_instances_reference_frame_available := false -var use_edge_data := false -var deprecated := false -var deprecation_message: String -var interrupt_update: bool = false - - -func get_warning() -> String: - return warning - - -func process_transforms(transforms: TransformList, domain: Domain, global_seed: int) -> void: - if not domain.get_root().is_inside_tree(): - return - - if Engine.is_editor_hint(): - _clear_warning() - - if deprecated: - warning += "This modifier is deprecated.\n" - warning += deprecation_message + "\n" - - if not enabled: - warning_changed.emit() - return - - if domain.is_empty() and not warning_ignore_no_shape: - warning += """The Scatter node does not have a shape. - Add at least one ScatterShape node as a child.\n""" - - if transforms.is_empty() and not warning_ignore_no_transforms: - warning += """There's no transforms to act on. - Make sure you have a Create modifier before this one.\n - """ - - var random_seed: int = global_seed - if can_override_seed and override_global_seed: - random_seed = custom_seed - interrupt_update = false - - @warning_ignore("redundant_await") # Not redundant as child classes could use the await keyword here. - await _process_transforms(transforms, domain, random_seed) - - warning_changed.emit() - - -func get_copy(): - var script: Script = get_script() - var copy = script.new() - for p in get_property_list(): - var value = get(p.name) - copy.set(p.name, value) - return copy - - -## Notify the modifier it should stop updating as soon as it can. -func interrupt() -> void: - interrupt_update = true - - -func is_using_global_space() -> bool: - return reference_frame == 0 - - -func is_using_local_space() -> bool: - return reference_frame == 1 - - -func is_using_individual_instances_space() -> bool: - return reference_frame == 2 - - -func use_global_space_by_default() -> void: - reference_frame = 0 - - -func use_local_space_by_default() -> void: - reference_frame = 1 - - -func use_individual_instances_space_by_default() -> void: - reference_frame = 2 - - -func _clear_warning() -> void: - warning = "" - warning_changed.emit() - - -# Override in inherited class -func _process_transforms(_transforms: TransformList, _domain: Domain, _seed: int) -> void: - pass diff --git a/godot/addons/proton_scatter/src/modifiers/base_modifier.gd.uid b/godot/addons/proton_scatter/src/modifiers/base_modifier.gd.uid deleted file mode 100644 index 6e9eb3a..0000000 --- a/godot/addons/proton_scatter/src/modifiers/base_modifier.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnujm7r1kc4xr diff --git a/godot/addons/proton_scatter/src/modifiers/clusterize.gd b/godot/addons/proton_scatter/src/modifiers/clusterize.gd deleted file mode 100644 index 5f17358..0000000 --- a/godot/addons/proton_scatter/src/modifiers/clusterize.gd +++ /dev/null @@ -1,131 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_file("Texture") var mask: String -@export var mask_rotation := 0.0 -@export var mask_offset := Vector2.ZERO -@export var mask_scale := Vector2.ONE -@export var pixel_to_unit_ratio := 64.0 -@export_range(0.0, 1.0) var remove_below = 0.1 -@export_range(0.0, 1.0) var remove_above = 1.0 -@export var scale_transforms := true - - -func _init() -> void: - display_name = "Clusterize" - category = "Edit" - global_reference_frame_available = true - local_reference_frame_available = false # TODO, enable this and handle this case - individual_instances_reference_frame_available = false - - documentation.add_paragraph( - "Clump transforms together based on a mask. - Sampling the mask returns values between 0 and 1. The transforms are - scaled against these values which means, bright areas don't affect their - scale while dark area scales them down. Transforms are then removed - below a threshold, leaving clumps behind.") - - var p := documentation.add_parameter("Mask") - p.set_type("Texture") - p.set_description("The texture used as a mask.") - p.add_warning( - "The amount of texture fetch depends on the amount of transforms - generated in the previous modifiers (4 reads for each transform). - In theory, the texture size shouldn't affect performances in a - noticeable way.") - - p = documentation.add_parameter("Mask scale") - p.set_type("Vector2") - p.set_description( - "Depending on the mask resolution, the perceived scale will change. - Use this parameter to increase or decrease the area covered by the mask.") - - p = documentation.add_parameter("Mask offset") - p.set_type("Vector2") - p.set_description("Moves the mask XZ position in 3D space") - - p = documentation.add_parameter("Mask rotation") - p.set_type("Float") - p.set_description("Rotates the mask around the Y axis. (Angle in degrees)") - - p = documentation.add_parameter("Remove below") - p.set_type("Float") - p.set_description("Threshold below which the transforms are removed.") - - p = documentation.add_parameter("Remove above") - p.set_type("Float") - p.set_description("Threshold above which the transforms are removed.") - -func _process_transforms(transforms, domain, _seed) -> void: - if not ResourceLoader.exists(mask): - warning += "The specified file " + mask + " could not be loaded." - return - - var texture: Texture = load(mask) - - if not texture is Texture: - warning += "The specified file is not a valid texture." - return - - var image: Image - - # Wait for a frame or risk the whole editor to freeze because of get_image() - # TODO: Check if more safe guards are required here. - await domain.get_root().get_tree().process_frame - - if texture is Texture2D: - image = texture.get_image() - - elif texture is Texture3D: - image = texture.get_data()[0] # TMP, this should depends on the transforms Y coordinates - - elif texture is TextureLayered: - image = texture.get_layer_data(0) # TMP - - image.decompress() - - var width := image.get_width() - var height := image.get_height() - var i := 0 - var angle := deg_to_rad(mask_rotation) - - while i < transforms.list.size(): - var t: Transform3D = transforms.list[i] - var origin := t.origin.rotated(Vector3.UP, angle) - - var x := origin.x * (pixel_to_unit_ratio / mask_scale.x) + mask_offset.x - x = fposmod(x, width - 1) - var y := origin.z * (pixel_to_unit_ratio / mask_scale.y) + mask_offset.y - y = fposmod(y, height - 1) - - var level := _get_pixel(image, x, y) - if level < remove_below: - transforms.list.remove_at(i) - continue - - if level > remove_above: - transforms.list.remove_at(i) - continue - - if scale_transforms: - t.basis = t.basis.scaled(Vector3(level, level, level)) - - transforms.list[i] = t - i += 1 - - -# x and y don't always match an exact pixel, so we sample the neighboring -# pixels as well and return a weighted value based on the input coords. -func _get_pixel(image: Image, x: float, y: float) -> float: - var ix = int(x) - var iy = int(y) - x -= ix - y -= iy - - var nw = image.get_pixel(ix, iy).v - var ne = image.get_pixel(ix + 1, iy).v - var sw = image.get_pixel(ix, iy + 1).v - var se = image.get_pixel(ix + 1, iy + 1).v - - return nw * (1 - x) * (1 - y) + ne * x * (1 - y) + sw * (1 - x) * y + se * x * y diff --git a/godot/addons/proton_scatter/src/modifiers/clusterize.gd.uid b/godot/addons/proton_scatter/src/modifiers/clusterize.gd.uid deleted file mode 100644 index 2b37fea..0000000 --- a/godot/addons/proton_scatter/src/modifiers/clusterize.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dmiiuuxii6wdk diff --git a/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl b/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl deleted file mode 100644 index 4c9aa11..0000000 --- a/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl +++ /dev/null @@ -1,43 +0,0 @@ -#[compute] -#version 450 - -// Invocations in the (x, y, z) dimension -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -// A binding to the input buffer we create in our script -layout(set = 0, binding = 0, std430) readonly buffer BufferIn { - vec4 data[]; -} -buffer_in; - -// A binding to the output buffer we create in our script -layout(set = 0, binding = 1, std430) restrict buffer BufferOut { - vec4 data[]; -} -buffer_out; - -// The code we want to execute in each invocation -void main() { - int last_element_index = buffer_in.data.length(); - // Unique index for each element - uint workgroupSize = gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z; - uint index = gl_WorkGroupID.x * workgroupSize + gl_LocalInvocationIndex; - - vec3 infvec = vec3(1, 1, 1) * 999999; // vector approaching "infinity" - vec3 closest = infvec; // initialize closest to infinity - vec3 origin = buffer_in.data[index].xyz; - - for(int i = 0; i <= last_element_index; i++){ - vec3 newvec = buffer_in.data[i].xyz; - - if (i == index) continue; // ignore self - - float olddist = length(closest - origin); - float newdist = length(newvec - origin); - if (newdist < olddist) - { - closest = newvec; - } - } - buffer_out.data[index] = vec4(origin - closest, 0); -} diff --git a/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl.import b/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl.import deleted file mode 100644 index 05cbec3..0000000 --- a/godot/addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl.import +++ /dev/null @@ -1,14 +0,0 @@ -[remap] - -importer="glsl" -type="RDShaderFile" -uid="uid://cpg67dxgr360g" -path="res://.godot/imported/compute_relax.glsl-b06f9e60cda7719b78bde9673f2501b7.res" - -[deps] - -source_file="res://addons/proton_scatter/src/modifiers/compute_shaders/compute_relax.glsl" -dest_files=["res://.godot/imported/compute_relax.glsl-b06f9e60cda7719b78bde9673f2501b7.res"] - -[params] - diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd b/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd deleted file mode 100644 index ad455e5..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd +++ /dev/null @@ -1,99 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var item_length := 2.0 -@export var ignore_slopes := false - -var _current_offset = 0.0 - - -func _init() -> void: - display_name = "Create Along Edge (Continuous)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - use_edge_data = true - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - - var p - - documentation.add_paragraph( - "Create new transforms along the edges of the Scatter shapes. These - transforms are placed so they touch each other but don't overlap, even - if the curve has sharp turns.") - - documentation.add_paragraph( - "This is useful to place props suchs as fences, walls or anything that - needs to look organized without leaving gaps.") - - documentation.add_warning( - "The transforms are placed starting from the begining of each curves. - If the curve is closed, there will be a gap at the end if the total - curve length isn't a multiple of the item length.") - - p = documentation.add_parameter("Item length") - p.set_type("float") - p.set_description("How long is the item being placed") - p.set_cost(2) - p.add_warning( - "The smaller this value, the more transforms will be created. - Setting a slightly different length than the actual model length - allow for gaps between each transforms.") - - p = documentation.add_parameter("Ignore slopes") - p.set_type("bool") - p.set_description( - "If enabled, all the curves will be projected to the local XZ plane - before creating the new transforms.") - - -# TODO: Use dichotomic search instead of fixed step length? -func _process_transforms(transforms, domain, seed) -> void: - var new_transforms: Array[Transform3D] = [] - var curves: Array[Curve3D] = domain.get_edges() - - for curve in curves: - if not ignore_slopes: - curve = curve.duplicate() - else: - curve = get_projected_curve(curve, domain.get_global_transform()) - - var length_squared = pow(item_length, 2) - var offset_max = curve.get_baked_length() - var offset = 0.0 - var step = item_length / 20.0 - - while offset < offset_max: - var start := curve.sample_baked(offset) - var end: Vector3 - var dist: float - offset += item_length * 0.9 # Saves a few iterations, the target - # point will never be closer than the item length, only further - - while offset < offset_max: - offset += step - end = curve.sample_baked(offset) - dist = start.distance_squared_to(end) - - if dist >= length_squared: - var t = Transform3D() - t.origin = start + ((end - start) / 2.0) - if not domain.is_point_excluded(t.origin): - new_transforms.push_back(t.looking_at(end, Vector3.UP)) - break - - transforms.append(new_transforms) - transforms.shuffle(seed) - - -func get_projected_curve(curve: Curve3D, t: Transform3D) -> Curve3D: - var points = curve.tessellate() - var new_curve = Curve3D.new() - for p in points: - p.y = t.origin.y - new_curve.add_point(p) - - return new_curve diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd.uid deleted file mode 100644 index 54b0286..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cllghta212y50 diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd b/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd deleted file mode 100644 index 503c8ab..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd +++ /dev/null @@ -1,79 +0,0 @@ -@tool -extends "base_modifier.gd" - - -const Util := preload("../common/util.gd") - - -# TODO : -# + change alignement parameters to something more usable and intuitive -# + Use the curve up vector, default to local Y+ when not available -@export var spacing := 1.0 -@export var offset := 0.0 -@export var align_to_path := false -@export var align_up_axis := Vector3.UP - -var _min_spacing := 0.05 - - -func _init() -> void: - display_name = "Create Along Edge (Even)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = false - use_edge_data = true - - var p - documentation.add_paragraph( - "Evenly create transforms along the edges of the ScatterShapes") - - p = documentation.add_parameter("Spacing") - p.set_type("float") - p.set_description("How much space between the transforms origin") - p.set_cost(3) - p.add_warning("The smaller the value, the denser the resulting transforms list.", 1) - p.add_warning( - "A value of 0 would result in infinite transforms, so it's capped - to 0.05 at least.") - - -func _process_transforms(transforms, domain, seed) -> void: - spacing = max(_min_spacing, spacing) - - var gt_inverse: Transform3D = domain.get_global_transform().affine_inverse() - var new_transforms: Array[Transform3D] = [] - var curves: Array[Curve3D] = domain.get_edges() - - for curve in curves: - var length: float = curve.get_baked_length() - var count := int(round(length / spacing)) - var stepped_length: float = count * spacing - - for i in count: - var curve_offset = i * spacing + abs(offset) - - while curve_offset > stepped_length: # Loop back to the curve start if offset is too large - curve_offset -= stepped_length - - var data : Array = Util.get_position_and_normal_at(curve, curve_offset) - var pos: Vector3 = data[0] - var normal: Vector3 = data[1] - - if domain.is_point_excluded(pos): - continue - - var t := Transform3D() - t.origin = pos - if align_to_path: - t = t.looking_at(normal + pos, align_up_axis) - elif is_using_global_space(): - t.basis = gt_inverse.basis - - new_transforms.push_back(t) - - transforms.append(new_transforms) - transforms.shuffle(seed) diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd.uid deleted file mode 100644 index 8c20665..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_even.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://xlsi3eicrvjl diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd b/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd deleted file mode 100644 index 6542514..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd +++ /dev/null @@ -1,79 +0,0 @@ -@tool -extends "base_modifier.gd" - - -const MAX_TRIES := 100 - -@export var instance_count := 10 -@export var align_to_path := false -@export var align_up_axis := Vector3.UP - -var _rng: RandomNumberGenerator - - -func _init() -> void: - display_name = "Create Along Edge (Random)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - use_edge_data = true - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = false - - -func _process_transforms(transforms, domain, random_seed) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(random_seed) - - var gt_inverse: Transform3D = domain.get_global_transform().affine_inverse() - var new_transforms: Array[Transform3D] = [] - var curves: Array[Curve3D] = domain.get_edges() - var total_curve_length := 0.0 - - for curve in curves: - var length: float = curve.get_baked_length() - total_curve_length += length - - for curve in curves: - var length: float = curve.get_baked_length() - var local_instance_count: int = round((length / total_curve_length) * instance_count) - - for i in local_instance_count: - var data = get_pos_and_normal(domain, curve, _rng.randf() * length) - if data.is_empty(): - break - var pos: Vector3 = data[0] - var normal: Vector3 = data[1] - var t := Transform3D() - - t.origin = pos - if align_to_path: - t = t.looking_at(normal + pos, align_up_axis) - elif is_using_global_space(): - t.basis = gt_inverse.basis - - new_transforms.push_back(t) - - transforms.append(new_transforms) - - -func get_pos_and_normal(domain, curve: Curve3D, offset : float) -> Array: - var i := 0 - while i < MAX_TRIES: - i += 1 - var pos: Vector3 = curve.sample_baked(offset) - if domain.is_point_excluded(pos): - continue - var normal := Vector3.ZERO - - var pos1 - if offset + curve.get_bake_interval() < curve.get_baked_length(): - pos1 = curve.sample_baked(offset + curve.get_bake_interval()) - normal = (pos1 - pos) - else: - pos1 = curve.sample_baked(offset - curve.get_bake_interval()) - normal = (pos - pos1) - - return [pos, normal] - return [] diff --git a/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd.uid deleted file mode 100644 index aa694e1..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_along_edge_random.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bloyww4fadci3 diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd b/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd deleted file mode 100644 index 475a2b3..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd +++ /dev/null @@ -1,97 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var spacing := Vector3(2.0, 2.0, 2.0) - -var _min_spacing := 0.05 - - -func _init() -> void: - display_name = "Create Inside (Grid)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - can_restrict_height = true - restrict_height = true - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = false - - documentation.add_paragraph( - "Place transforms along the edges of the ScatterShapes") - - documentation.add_paragraph( - "When [b]Local Space[/b] is enabled, the grid is aligned with the - Scatter root node. Otherwise, the grid is aligned with the global - axes." - ) - - var p = documentation.add_parameter("Spacing") - p.set_type("vector3") - p.set_description( - "Defines the grid size along the 3 axes. A spacing of 1 means 1 unit - of space between each transform on this axis.") - p.set_cost(3) - p.add_warning( - "The smaller the value, the denser the resulting transforms list. - Use with care as the performance impact will go up quickly.", 1) - p.add_warning( - "A value of 0 would result in infinite transforms, so it's capped to 0.05 - at least.") - - -func _process_transforms(transforms, domain, seed) -> void: - spacing.x = max(_min_spacing, spacing.x) - spacing.y = max(_min_spacing, spacing.y) - spacing.z = max(_min_spacing, spacing.z) - - var gt: Transform3D = domain.get_local_transform() - var center: Vector3 = domain.bounds_local.center - var size: Vector3 = domain.bounds_local.size - - var half_size := size * 0.5 - var start_corner := center - half_size - var baseline: float = 0.0 - - var width := int(ceil(size.x / spacing.x)) - var height := int(ceil(size.y / spacing.y)) - var length := int(ceil(size.z / spacing.z)) - - if restrict_height: - height = 1 - baseline = domain.bounds_local.max.y - else: - height = max(1, height) # Make sure height never gets below 1 or else nothing happens - - var max_count: int = width * length * height - var new_transforms: Array[Transform3D] = [] - new_transforms.resize(max_count) - - var t: Transform3D - var pos: Vector3 - var t_index := 0 - - for i in width * length: - for j in height: - t = Transform3D() - pos = Vector3.ZERO - pos.x = (i % width) * spacing.x - pos.y = (j * spacing.y) + baseline - pos.z = (i / width) * spacing.z - pos += start_corner - - if is_using_global_space(): - t.basis = gt.affine_inverse().basis - pos = t * pos - - if domain.is_point_inside(pos): - t.origin = pos - new_transforms[t_index] = t - t_index += 1 - - if t_index != new_transforms.size(): - new_transforms.resize(t_index) - - transforms.append(new_transforms) - transforms.shuffle(seed) diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd.uid deleted file mode 100644 index 493b81f..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_grid.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://btqenpu1uonhm diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd b/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd deleted file mode 100644 index 1ee9daf..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd +++ /dev/null @@ -1,230 +0,0 @@ -@tool -extends "base_modifier.gd" - - -# Poisson disc sampling based on Sebastian Lague implementation, modified to -# support both 2D and 3D space. -# Reference: https://www.youtube.com/watch?v=7WcmyxyFO7o - -# TODO: This doesn't work if the valid space isn't one solid space -# (fails to fill the full domain if it's made of discrete, separate shapes) - - -const Bounds := preload("../common/bounds.gd") - -@export var radius := 1.0 -@export var samples_before_rejection := 15 - - -var _rng: RandomNumberGenerator -var _squared_radius: float -var _domain -var _bounds: Bounds - -var _gt: Transform3D -var _points: Array[Transform3D] # Stores the generated points -var _grid: Array[int] = [] # Flattened array -var _grid_size := Vector3i.ZERO -var _cell_size: float -var _cell_x: int -var _cell_y: int -var _cell_z: int - - -func _init() -> void: - display_name = "Create Inside (Poisson)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - can_restrict_height = true - can_override_seed = true - restrict_height = true - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = false - use_local_space_by_default() - - documentation.add_paragraph( - "Place transforms without overlaps. Transforms are assumed to have a - spherical shape.") - - var p := documentation.add_parameter("Radius") - p.set_type("float") - p.set_description("Transform size.") - p.add_warning( - "The larger the radius, the harder it will be to place the transform, - resulting in a faster early exit. - On the other hand, smaller radius means more room for more points, - meaning more transforms to generate so it will take longer to complete.") - - p = documentation.add_parameter("Samples before rejection") - p.set_type("int") - p.set_description( - "The algorithm tries a point at random until it finds a valid one. This - parameter controls how many attempts before moving to the next - iteration. Lower values are faster but gives poor coverage. Higher - values generates better coverage but are slower.") - p.set_cost(2) - - documentation.add_warning( - "This modifier uses a poisson disk sampling algorithm which can be - quite slow.") - - -func _process_transforms(transforms, domain, seed) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(seed) - _domain = domain - _bounds = _domain.bounds_local - _gt = domain.get_global_transform() - _points = [] - _init_grid() - - # Stores the possible starting points from where we run the sampling. - # This array will progressively be emptied as the algorithm progresses. - var spawn_points: Array[Transform3D] - spawn_points.push_back(_get_starting_point()) - - # Sampler main loop - while not spawn_points.is_empty(): - - # Pick a starting point at random from the existing list - var spawn_index: int = _rng.randi_range(0, spawn_points.size() - 1) - var spawn_center := spawn_points[spawn_index] - - var tries := 0 - var candidate_accepted := false - - while tries < samples_before_rejection: - tries += 1 - - # Generate a random point in space, outside the radius of the spawn point - var dir: Vector3 = _generate_random_vector() - var candidate: Vector3 = spawn_center.origin + dir * _rng.randf_range(radius, radius * 2.0) - - if _is_valid(candidate): - candidate_accepted = true - - # Add new points to the lists - var t = Transform3D() - t.origin = candidate - - if is_using_global_space(): - t.basis = _gt.affine_inverse().basis - - _points.push_back(t) - spawn_points.push_back(t) - - var index: int - if restrict_height: - index = _cell_x + _cell_z * _grid_size.z - else: - index = _cell_x + (_grid_size.y * _cell_y) + (_grid_size.x * _grid_size.y * _cell_z) - - if index < _grid.size(): - _grid[index] = _points.size() - 1 - - break - - # Failed to find a point after too many tries. The space around this - # spawn point is probably full, discard it. - if not candidate_accepted: - spawn_points.remove_at(spawn_index) - - transforms.append(_points) - transforms.shuffle(seed) - - -func _init_grid() -> void: - _squared_radius = radius * radius - _cell_size = radius / sqrt(2) - _grid_size.x = ceil(_bounds.size.x / _cell_size) - _grid_size.y = ceil(_bounds.size.y / _cell_size) - _grid_size.z = ceil(_bounds.size.z / _cell_size) - - _grid_size = _grid_size.clamp(Vector3.ONE, _grid_size) - - _grid = [] - if restrict_height: - _grid.resize(_grid_size.x * _grid_size.z) - else: - _grid.resize(_grid_size.x * _grid_size.y * _grid_size.z) - - -# Starting point must be inside the domain, or we run the risk to never generate -# any valid point later on -# TODO: Domain may have islands, so we should use multiple starting points -func _get_starting_point() -> Transform3D: - var point: Vector3 = _bounds.center - - var tries := 0 - while not _domain.is_point_inside(point) or tries > 200: - tries += 1 - point.x = _rng.randf_range(_bounds.min.x, _bounds.max.x) - point.y = _rng.randf_range(_bounds.min.y, _bounds.max.y) - point.z = _rng.randf_range(_bounds.min.z, _bounds.max.z) - - if restrict_height: - point.y = _bounds.center.y - - var starting_point := Transform3D() - starting_point.origin = point - return starting_point - - -func _is_valid(candidate: Vector3) -> bool: - if not _domain.is_point_inside(candidate): - return false - - # compute candidate current cell - var t_candidate = candidate - _bounds.min - _cell_x = floor(t_candidate.x / _cell_size) - _cell_y = floor(t_candidate.y / _cell_size) - _cell_z = floor(t_candidate.z / _cell_size) - - # Search the surrounding cells for other points - var search_start_x: int = max(0, _cell_x - 2) - var search_end_x: int = min(_cell_x + 2, _grid_size.x - 1) - var search_start_y: int = max(0, _cell_y - 2) - var search_end_y: int = min(_cell_y + 2, _grid_size.y - 1) - var search_start_z: int = max(0, _cell_z - 2) - var search_end_z: int = min(_cell_z + 2, _grid_size.z - 1) - - if restrict_height: - for x in range(search_start_x, search_end_x + 1): - for z in range(search_start_z, search_end_z + 1): - var point_index = _grid[x + z * _grid_size.z] - if _is_point_too_close(candidate, point_index): - return false - else: - for x in range(search_start_x, search_end_x + 1): - for y in range(search_start_y, search_end_y + 1): - for z in range(search_start_z, search_end_z + 1): - var point_index = _grid[x + (_grid_size.y * y) + (_grid_size.x * _grid_size.y * z)] - if _is_point_too_close(candidate, point_index): - return false - - return true - - -func _is_point_too_close(candidate: Vector3, point_index: int) -> bool: - if point_index >= _points.size(): - return false - - var other_point := _points[point_index] - var squared_dist: float = candidate.distance_squared_to(other_point.origin) - return squared_dist < _squared_radius - - -func _generate_random_vector(): - var angle = _rng.randf_range(0.0, TAU) - if restrict_height: - return Vector3(sin(angle), 0.0, cos(angle)) - - var costheta = _rng.randf_range(-1.0, 1.0) - var theta = acos(costheta) - var vector := Vector3.ZERO - vector.x = sin(theta) * cos(angle) - vector.y = sin(theta) * sin(angle) - vector.z = cos(theta) - return vector diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd.uid deleted file mode 100644 index 6424c71..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_poisson.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cfcyhfjvin173 diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd b/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd deleted file mode 100644 index 8bbc9c3..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd +++ /dev/null @@ -1,84 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var amount := 10 - -var _rng: RandomNumberGenerator - - -func _init() -> void: - display_name = "Create Inside (Random)" - category = "Create" - warning_ignore_no_transforms = true - warning_ignore_no_shape = false - can_override_seed = true - global_reference_frame_available = true - local_reference_frame_available = true - use_local_space_by_default() - - documentation.add_paragraph( - "Randomly place new transforms inside the area defined by - the ScatterShape nodes.") - - var p := documentation.add_parameter("Amount") - p.set_type("int") - p.set_description("How many transforms will be created.") - p.set_cost(2) - - documentation.add_warning( - "In some cases, the amount of transforms created by this modifier - might be lower than the requested amount (but never higher). This may - happen if the provided ScatterShape has a huge bounding box but a tiny - valid space, like a curved and narrow path.") - - -# TODO: -# + Multithreading -# + Spatial partionning to discard areas outside the domain earlier -func _process_transforms(transforms, domain, random_seed) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(random_seed) - - var gt: Transform3D = domain.get_global_transform() - var center: Vector3 = domain.bounds_local.center - var half_size: Vector3 = domain.bounds_local.size / 2.0 - var height: float = domain.bounds_local.center.y - - # Generate a random point in the bounding box. Store if it's inside the - # domain, or discard if invalid. Repeat until enough valid points are found. - var t: Transform3D - var pos: Vector3 - var new_transforms: Array[Transform3D] = [] - var max_retries = amount * 10 # TODO: expose this parameter? - var tries := 0 - - while new_transforms.size() != amount: - t = Transform3D() - pos = _random_vec3() * half_size + center - - if restrict_height: - pos.y = height - - if is_using_global_space(): - t.basis = gt.affine_inverse().basis - - if domain.is_point_inside(pos): - t.origin = pos - new_transforms.push_back(t) - continue - - # Prevents an infinite loop - tries += 1 - if tries > max_retries: - break - - transforms.append(new_transforms) - - -func _random_vec3() -> Vector3: - var vec3 = Vector3.ZERO - vec3.x = _rng.randf_range(-1.0, 1.0) - vec3.y = _rng.randf_range(-1.0, 1.0) - vec3.z = _rng.randf_range(-1.0, 1.0) - return vec3 diff --git a/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd.uid b/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd.uid deleted file mode 100644 index 4c3390d..0000000 --- a/godot/addons/proton_scatter/src/modifiers/create_inside_random.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bkospk3q73ig4 diff --git a/godot/addons/proton_scatter/src/modifiers/look_at.gd b/godot/addons/proton_scatter/src/modifiers/look_at.gd deleted file mode 100644 index 51e2562..0000000 --- a/godot/addons/proton_scatter/src/modifiers/look_at.gd +++ /dev/null @@ -1,39 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var target := Vector3.ZERO -@export var up := Vector3.UP - - -func _init() -> void: - display_name = "Look At" - category = "Edit" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_local_space_by_default() - - documentation.add_paragraph("Rotates every transform such that the forward axis (-Z) points towards the target position.") - - documentation.add_parameter("Target").set_type("Vector3").set_description( - "Target position (X, Y, Z)") - documentation.add_parameter("Up").set_type("Vector3").set_description( - "Up axes (X, Y, Z)") - - -func _process_transforms(transforms, domain, _seed : int) -> void: - var st: Transform3D = domain.get_global_transform() - - for i in transforms.size(): - var transform: Transform3D = transforms.list[i] - var local_target := target - - if is_using_global_space(): - local_target = st.affine_inverse().basis * local_target - - elif is_using_individual_instances_space(): - local_target = transform.basis * local_target - - transforms.list[i] = transform.looking_at(local_target, up) diff --git a/godot/addons/proton_scatter/src/modifiers/look_at.gd.uid b/godot/addons/proton_scatter/src/modifiers/look_at.gd.uid deleted file mode 100644 index 410d44c..0000000 --- a/godot/addons/proton_scatter/src/modifiers/look_at.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bw78q8pr24ypb diff --git a/godot/addons/proton_scatter/src/modifiers/offset_position.gd b/godot/addons/proton_scatter/src/modifiers/offset_position.gd deleted file mode 100644 index deefd84..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_position.gd +++ /dev/null @@ -1,63 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_enum("Offset:0", "Multiply:1", "Override:2") var operation: int -@export var position := Vector3.ZERO - - - -func _init() -> void: - display_name = "Edit Position" - category = "Offset" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - documentation.add_paragraph("Moves every transform the same way.") - - var p := documentation.add_parameter("Position") - p.set_type("vector3") - p.set_description("How far each transforms are moved.") - - -func _process_transforms(transforms, domain, _seed) -> void: - var s_gt: Transform3D = domain.get_global_transform() - var s_gt_inverse: Transform3D = s_gt.affine_inverse() - var t: Transform3D - - for i in transforms.list.size(): - t = transforms.list[i] - - var value: Vector3 - - if is_using_individual_instances_space(): - value = t.basis * position - elif is_using_global_space(): - value = s_gt_inverse.basis * position - else: - value = position - - match operation: - 0: - t.origin += value - 1: - if is_using_local_space(): - t.origin *= value - - if is_using_global_space(): - var global_pos = s_gt * t.origin - global_pos -= s_gt.origin - global_pos *= position - global_pos += s_gt.origin - - t.origin = s_gt_inverse * global_pos - - elif is_using_individual_instances_space(): - pass # Multiply does nothing on this reference frame. - 2: - t.origin = value - - transforms.list[i] = t diff --git a/godot/addons/proton_scatter/src/modifiers/offset_position.gd.uid b/godot/addons/proton_scatter/src/modifiers/offset_position.gd.uid deleted file mode 100644 index 8b9669d..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_position.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://biih62w2g01fl diff --git a/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd b/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd deleted file mode 100644 index ab7b11b..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd +++ /dev/null @@ -1,100 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_enum("Offset:0", "Multiply:1", "Override:2") var operation: int -@export var rotation := Vector3.ZERO - - -func _init() -> void: - display_name = "Edit Rotation" - category = "Offset" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - documentation.add_paragraph("Rotates every transform.") - - documentation.add_parameter("Rotation").set_type("Vector3").set_description( - "Rotation angle (in degrees) along each axes (X, Y, Z)") - - -func _process_transforms(transforms, domain, _seed : int) -> void: - var rotation_rad := Vector3.ZERO - rotation_rad.x = deg_to_rad(rotation.x) - rotation_rad.y = deg_to_rad(rotation.y) - rotation_rad.z = deg_to_rad(rotation.z) - - var s_gt: Transform3D = domain.get_global_transform() - var s_lt: Transform3D = domain.get_local_transform() - var s_gt_inverse := s_gt.affine_inverse() - var t: Transform3D - var basis: Basis - var axis_x: Vector3 - var axis_y: Vector3 - var axis_z: Vector3 - var final_rotation: Vector3 - - if is_using_local_space(): - axis_x = Vector3.RIGHT - axis_y = Vector3.UP - axis_z = Vector3.FORWARD - - elif is_using_global_space(): - axis_x = (s_gt_inverse.basis * Vector3.RIGHT).normalized() - axis_y = (s_gt_inverse.basis * Vector3.UP).normalized() - axis_z = (s_gt_inverse.basis * Vector3.FORWARD).normalized() - - for i in transforms.size(): - t = transforms.list[i] - basis = t.basis - - match operation: - 0: # Offset - final_rotation = rotation_rad - - 1: # Multiply - # TMP: Local and global space calculations are probably wrong - var current_rotation: Vector3 - - if is_using_individual_instances_space(): - current_rotation = basis.get_euler() - - elif is_using_local_space(): - var local_t := t * s_lt - current_rotation = local_t.basis.get_euler() - - else: - var global_t := t * s_gt - current_rotation = global_t.basis.get_euler() - - final_rotation = (current_rotation * rotation) - current_rotation - - 2: # Override - # Creates a new basis with the original scale only - # Applies new rotation on top - - if is_using_individual_instances_space(): - basis = Basis().from_scale(t.basis.get_scale()) - - elif is_using_local_space(): - basis = (s_gt_inverse * s_gt).basis - - else: - var tmp_t = Transform3D(Basis.from_scale(t.basis.get_scale()), Vector3.ZERO) - basis = (s_gt_inverse * tmp_t).basis - - final_rotation = rotation_rad - - if is_using_individual_instances_space(): - axis_x = basis.x.normalized() - axis_y = basis.y.normalized() - axis_z = basis.z.normalized() - - basis = basis.rotated(axis_y, final_rotation.y) - basis = basis.rotated(axis_x, final_rotation.x) - basis = basis.rotated(axis_z, final_rotation.z) - - transforms.list[i].basis = basis diff --git a/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd.uid b/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd.uid deleted file mode 100644 index 7822898..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_rotation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chsqcnfydcuap diff --git a/godot/addons/proton_scatter/src/modifiers/offset_scale.gd b/godot/addons/proton_scatter/src/modifiers/offset_scale.gd deleted file mode 100644 index 7ab8389..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_scale.gd +++ /dev/null @@ -1,94 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_enum("Offset:0", "Multiply:1", "Override:2") var operation: int = 1 -@export var scale := Vector3(1, 1, 1) - - -func _init() -> void: - display_name = "Edit Scale" - category = "Offset" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - documentation.add_paragraph("Scales every transform.") - - var p := documentation.add_parameter("Scale") - p.set_type("Vector3") - p.set_description("How much to scale the transform along each axes (X, Y, Z)") - - -func _process_transforms(transforms, domain, _seed) -> void: - var s_gt: Transform3D = domain.get_global_transform() - var s_lt: Transform3D = domain.get_local_transform() - var s_gt_inverse := s_gt.affine_inverse() - var s_lt_inverse := s_lt.affine_inverse() - var basis: Basis - var t: Transform3D - var tmp_t: Transform3D - - for i in transforms.size(): - t = transforms.list[i] - basis = t.basis - - match operation: - 0: # Offset - if is_using_individual_instances_space(): - var current_scale := basis.get_scale() - var s = (current_scale + scale) / current_scale - basis = t.scaled_local(s).basis - - elif is_using_global_space(): - # Convert to global space, scale, convert back to local space - tmp_t = s_gt * t - var current_scale: Vector3 = tmp_t.basis.get_scale() - tmp_t.basis = tmp_t.basis.scaled((current_scale + scale) / current_scale) - basis = (s_gt_inverse * tmp_t).basis - - else: - var current_scale: Vector3 = basis.get_scale() - basis = basis.scaled((current_scale + scale) / current_scale) - - 1: # Multiply - if is_using_individual_instances_space(): - basis = t.scaled_local(scale).basis - - elif is_using_global_space(): - # Convert to global space, scale, convert back to local space - tmp_t = s_gt * t - tmp_t = tmp_t.scaled(scale) - basis = (s_gt_inverse * tmp_t).basis - - else: - basis = basis.scaled(scale) - - 2: # Override - if is_using_individual_instances_space(): - var t_scale: Vector3 = basis.get_scale() - t_scale.x = (1.0 / t_scale.x) * scale.x - t_scale.y = (1.0 / t_scale.y) * scale.y - t_scale.z = (1.0 / t_scale.z) * scale.z - basis = t.scaled_local(t_scale).basis - - elif is_using_global_space(): - # Convert to global space, scale, convert back to local space - tmp_t = t * s_gt - var t_scale: Vector3 = tmp_t.basis.get_scale() - t_scale.x = (1.0 / t_scale.x) * scale.x - t_scale.y = (1.0 / t_scale.y) * scale.y - t_scale.z = (1.0 / t_scale.z) * scale.z - tmp_t.basis = tmp_t.basis.scaled(t_scale) - basis = (s_gt_inverse * tmp_t).basis - - else: - var t_scale: Vector3 = basis.get_scale() - t_scale.x = (1.0 / t_scale.x) * scale.x - t_scale.y = (1.0 / t_scale.y) * scale.y - t_scale.z = (1.0 / t_scale.z) * scale.z - basis = basis.scaled(t_scale) - - transforms.list[i].basis = basis diff --git a/godot/addons/proton_scatter/src/modifiers/offset_scale.gd.uid b/godot/addons/proton_scatter/src/modifiers/offset_scale.gd.uid deleted file mode 100644 index 64f1a6b..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_scale.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hmxlaa3aa1fr diff --git a/godot/addons/proton_scatter/src/modifiers/offset_transform.gd b/godot/addons/proton_scatter/src/modifiers/offset_transform.gd deleted file mode 100644 index 5caba1b..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_transform.gd +++ /dev/null @@ -1,83 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var position := Vector3.ZERO -@export var rotation := Vector3(0.0, 0.0, 0.0) -@export var scale := Vector3.ONE - - -func _init() -> void: - display_name = "Edit Transform" - category = "Offset" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_local_space_by_default() - deprecated = true - deprecation_message = "Use a combination of 'Edit Position', 'Edit Rotation' and 'Edit Scale' instead." - - documentation.add_paragraph( - "Offsets position, rotation and scale in a single modifier. Every - transforms generated before will see the same transformation applied.") - - var p := documentation.add_parameter("Position") - p.set_type("Vector3") - p.set_description("How far each transforms are moved.") - - p = documentation.add_parameter("Rotation") - p.set_type("Vector3") - p.set_description("Rotation angle (in degrees) along each axes (X, Y, Z)") - - p = documentation.add_parameter("Scale") - p.set_type("Vector3") - p.set_description("How much to scale the transform along each axes (X, Y, Z)") - - -func _process_transforms(transforms, domain, _seed) -> void: - var t: Transform3D - var local_t: Transform3D - var basis: Basis - var axis_x := Vector3.RIGHT - var axis_y := Vector3.UP - var axis_z := Vector3.DOWN - var final_scale := scale - var final_position := position - var st: Transform3D = domain.get_global_transform() - - if is_using_local_space(): - axis_x = st.basis.x - axis_y = st.basis.y - axis_z = st.basis.z - final_scale = scale.rotated(Vector3.RIGHT, st.basis.get_euler().x) - final_position = st.basis * position - - for i in transforms.size(): - t = transforms.list[i] - basis = t.basis - - if is_using_individual_instances_space(): - axis_x = basis.x - axis_y = basis.y - axis_z = basis.z - basis.x *= scale.x - basis.y *= scale.y - basis.z *= scale.z - final_position = t.basis * position - - elif is_using_local_space(): - local_t = t * st - local_t.basis = local_t.basis.scaled(final_scale) - basis = (st * local_t).basis - - else: - basis = basis.scaled(final_scale) - - basis = basis.rotated(axis_x, deg_to_rad(rotation.x)) - basis = basis.rotated(axis_y, deg_to_rad(rotation.y)) - basis = basis.rotated(axis_z, deg_to_rad(rotation.z)) - t.basis = basis - t.origin += final_position - - transforms.list[i] = t diff --git a/godot/addons/proton_scatter/src/modifiers/offset_transform.gd.uid b/godot/addons/proton_scatter/src/modifiers/offset_transform.gd.uid deleted file mode 100644 index eb70de4..0000000 --- a/godot/addons/proton_scatter/src/modifiers/offset_transform.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dom12bkgj7uh5 diff --git a/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd b/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd deleted file mode 100644 index 6df96f3..0000000 --- a/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd +++ /dev/null @@ -1,216 +0,0 @@ -@tool -extends "base_modifier.gd" - - -signal projection_completed - - -const ProtonScatterPhysicsHelper := preload("res://addons/proton_scatter/src/common/physics_helper.gd") - - -@export var ray_direction := Vector3.DOWN -@export var ray_length := 10.0 -@export var ray_offset := 1.0 -@export var remove_points_on_miss := true -@export var align_with_collision_normal := false -@export_range(0.0, 90.0) var max_slope = 90.0 -@export_flags_3d_physics var collision_mask = 1 -@export_flags_3d_physics var exclude_mask = 0 - - -func _init() -> void: - display_name = "Project On Colliders" - category = "Edit" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_global_space_by_default() - - documentation.add_paragraph( - "Moves each transforms along the ray direction until they hit a collider. - This is useful to avoid floating objects on uneven terrain for example.") - - documentation.add_warning( - "This modifier only works when physics bodies are around. It will ignore - simple MeshInstances nodes.") - - var p := documentation.add_parameter("Ray direction") - p.set_type("Vector3") - p.set_description( - "In which direction we look for a collider. This default to the DOWN - direction by default (look at the ground).") - p.add_warning( - "This is relative to the transform is local space is enabled, or aligned - with the global axis if local space is disabled.") - - p = documentation.add_parameter("Ray length") - p.set_type("float") - p.set_description("How far we look for other physics objects.") - p.set_cost(2) - - p = documentation.add_parameter("Ray offset") - p.set_type("Vector3") - p.set_description( - "Moves back the raycast origin point along the ray direction. This is - useful if the initial transform is slightly below the ground, which would - make the raycast miss the collider (since it would start inside).") - - p = documentation.add_parameter("Remove points on miss") - p.set_type("bool") - p.set_description( - "When enabled, if the raycast didn't collide with anything, or collided - with a surface above the max slope setting, the transform is removed - from the list. - This is useful to avoid floating objects that are too far from the rest - of the scene's geometry.") - - p = documentation.add_parameter("Align with collision normal") - p.set_type("bool") - p.set_description( - "Rotate the transform to align it with the collision normal in case - the ray cast hit a collider.") - - p = documentation.add_parameter("Max slope") - p.set_type("float") - p.set_description( - "Angle (in degrees) after which the hit is considered invalid. - When a ray cast hit, the normal of the ray is compared against the - normal of the hit. If you set the slope to 0°, the ray and the hit - normal would have to be perfectly aligned to be valid. On the other - hand, setting the maximum slope to 90° treats every collisions as - valid regardless of their normals.") - - p = documentation.add_parameter("Mask") - p.set_description( - "Only collide with colliders on these layers. Disabled layers will - be ignored. It's useful to ignore players or npcs that might be on the - scene when you're editing it.") - - p = documentation.add_parameter("Exclude Mask") - p.set_description( - "Tests if the snapping would collide with the selected layers. - If it collides, the point will be excluded from the list.") - - -func _process_transforms(transforms, domain, _seed) -> void: - if transforms.is_empty(): - return - - # Create all the physics ray queries - var gt: Transform3D = domain.get_global_transform() - var gt_inverse := gt.affine_inverse() - var queries: Array[PhysicsRayQueryParameters3D] = [] - var exclude_queries: Array[PhysicsRayQueryParameters3D] = [] - - for t in transforms.list: - var start = gt * t.origin - var end = start - var dir = ray_direction.normalized() - - if is_using_individual_instances_space(): - dir = t.basis * dir - - elif is_using_local_space(): - dir = gt.basis * dir - - start -= ray_offset * dir - end += ray_length * dir - - var ray_query := PhysicsRayQueryParameters3D.new() - ray_query.from = start - ray_query.to = end - ray_query.collision_mask = collision_mask - - queries.push_back(ray_query) - - var exclude_query := PhysicsRayQueryParameters3D.new() - exclude_query.from = start - exclude_query.to = end - exclude_query.collision_mask = exclude_mask - exclude_queries.push_back(exclude_query) - - # Run the queries in the physics helper since we can't access the PhysicsServer - # from outside the _physics_process while also being in a separate thread. - var physics_helper: ProtonScatterPhysicsHelper = domain.get_root().get_physics_helper() - - var ray_hits := await physics_helper.execute(queries) - - if ray_hits.is_empty(): - return - - # Create queries from the hit points - var index := -1 - for ray_hit in ray_hits: - index += 1 - var hit : Dictionary = ray_hit - if hit.is_empty(): - exclude_queries[index].collision_mask = 0 # this point is empty anyway, we dont care - continue - exclude_queries[index].to = hit.position # only cast up to hit point for correct ordering - - var exclude_hits : Array[Dictionary] = [] - if exclude_mask != 0: # Only cast the rays if it makes any sense - exclude_hits = await physics_helper.execute(exclude_queries) - - # Apply the results - index = 0 - var d: float - var t: Transform3D - var remapped_max_slope = remap(max_slope, 0.0, 90.0, 0.0, 1.0) - var is_point_valid := false - exclude_hits.reverse() # makes it possible to use pop_back which is much faster - var new_transforms_array : Array[Transform3D] = [] - - for hit in ray_hits: - is_point_valid = true - - if hit.is_empty(): - is_point_valid = false - else: - d = abs(Vector3.UP.dot(hit.normal)) - is_point_valid = d >= (1.0 - remapped_max_slope) - - var exclude_hit = exclude_hits.pop_back() - if exclude_hit != null: - if not exclude_hit.is_empty(): - is_point_valid = false - - t = transforms.list[index] - if is_point_valid: - if align_with_collision_normal: - t = _align_with(t, gt_inverse.basis * hit.normal) - - t.origin = gt_inverse * hit.position - new_transforms_array.push_back(t) - elif not remove_points_on_miss: - new_transforms_array.push_back(t) - - index += 1 - - # All done, store the transforms in the original array - transforms.list.clear() - transforms.list.append_array(new_transforms_array) # this avoids memory leak - - if transforms.is_empty(): - warning += """Every points have been removed. Possible reasons include: \n - + No collider is close enough to the shapes. - + Ray length is too short. - + Ray direction is incorrect. - + Collision mask is not set properly. - + Max slope is too low. - """ - - -func _align_with(t: Transform3D, normal: Vector3) -> Transform3D: - var n1 = t.basis.y.normalized() - var n2 = normal.normalized() - - var cosa = n1.dot(n2) - var alpha = acos(cosa) - var axis = n1.cross(n2) - - if axis == Vector3.ZERO: - return t - - return t.rotated(axis.normalized(), alpha) diff --git a/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd.uid b/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd.uid deleted file mode 100644 index 9774792..0000000 --- a/godot/addons/proton_scatter/src/modifiers/project_on_geometry.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cu7uwg46pfuge diff --git a/godot/addons/proton_scatter/src/modifiers/proxy.gd b/godot/addons/proton_scatter/src/modifiers/proxy.gd deleted file mode 100644 index 06cf804..0000000 --- a/godot/addons/proton_scatter/src/modifiers/proxy.gd +++ /dev/null @@ -1,71 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_node_path var scatter_node: NodePath -@export var auto_rebuild := true: - set(val): - auto_rebuild = val - if not is_instance_valid(_source_node) or not _source_node is ProtonScatter: - return - - if auto_rebuild: # Connect signal if not already connected - if not _source_node.build_completed.is_connected(_on_source_changed): - _source_node.build_completed.connect(_on_source_changed) - - # Auto rebuild disabled, disconnect signal if connected - elif _source_node.build_completed.is_connected(_on_source_changed): - _source_node.build_completed.disconnect(_on_source_changed) - -var _source_node: ProtonScatter: - set(val): - # Disconnect signals from previous scatter node if any - if is_instance_valid(_source_node) and _source_node is ProtonScatter: - if _source_node.build_completed.is_connected(_on_source_changed): - _source_node.build_completed.disconnect(_on_source_changed) - - # Replace reference and retrigger the auto_rebuild setter - _source_node = val - auto_rebuild = auto_rebuild - - -func _init() -> void: - display_name = "Proxy" - category = "Misc" - can_restrict_height = false - can_override_seed = false - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - warning_ignore_no_transforms = true - - documentation.add_paragraph("Copy a modifier stack from another ProtonScatter node in the scene.") - documentation.add_paragraph( - "Useful when you need multiple Scatter nodes sharing the same rules, without having to - replicate their modifiers and settings in each." - ) - documentation.add_paragraph( - "Unlike presets which are full independent copies, this method is more similar to a linked - copy. Changes on the original modifier stack will be accounted for in here." - ) - - var p = documentation.add_parameter("Scatter node") - p.set_type("NodePath") - p.set_description("The Scatter node to use as a reference.") - - -func _process_transforms(transforms, domain, _seed) -> void: - _source_node = domain.get_root().get_node_or_null(scatter_node) - - if not _source_node or not _source_node is ProtonScatter: - warning += "You need to select a valid ProtonScatter node." - return - - if _source_node.modifier_stack: - var stack: ProtonScatterModifierStack = _source_node.modifier_stack.get_copy() - var results = await stack.start_update(domain.get_root(), domain) - transforms.append(results.list) - - -func _on_source_changed() -> void: - modifier_changed.emit() diff --git a/godot/addons/proton_scatter/src/modifiers/proxy.gd.uid b/godot/addons/proton_scatter/src/modifiers/proxy.gd.uid deleted file mode 100644 index 0a97256..0000000 --- a/godot/addons/proton_scatter/src/modifiers/proxy.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dnl3txrfkhnyf diff --git a/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd b/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd deleted file mode 100644 index a60cee8..0000000 --- a/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd +++ /dev/null @@ -1,88 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var rotation := Vector3(360.0, 360.0, 360.0) -@export var snap_angle := Vector3.ZERO - -var _rng: RandomNumberGenerator - - -func _init() -> void: - display_name = "Randomize Rotation" - category = "Edit" - can_override_seed = true - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - documentation.add_paragraph("Randomly rotate every transforms individually.") - - var p := documentation.add_parameter("Rotation") - p.set_type("Vector3") - p.set_description("Rotation angle (in degrees) along each axes (X, Y, Z)") - - p = documentation.add_parameter("Snap angle") - p.set_type("Vector3") - p.set_description( - "When set to any value above 0, the rotation will be done by increments - of the snap angle.") - p.add_warning( - "Example: When Snap Angle is set to 90, the possible random rotation - offsets around an axis will be among [0, 90, 180, 360].") - - -func _process_transforms(transforms, domain, random_seed) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(random_seed) - - var t: Transform3D - var b: Basis - - var gt: Transform3D = domain.get_global_transform() - var gb: Basis = gt.basis - var axis_x: Vector3 = Vector3.RIGHT - var axis_y: Vector3 = Vector3.UP - var axis_z: Vector3 = Vector3.FORWARD - - if is_using_local_space(): - axis_x = (Vector3.RIGHT * gb).normalized() - axis_y = (Vector3.UP * gb).normalized() - axis_z = (Vector3.FORWARD * gb).normalized() - - for i in transforms.list.size(): - t = transforms.list[i] - b = t.basis - - if is_using_individual_instances_space(): - axis_x = t.basis.x.normalized() - axis_y = t.basis.y.normalized() - axis_z = t.basis.z.normalized() - - b = b.rotated(axis_x, _random_angle(rotation.x, snap_angle.x)) - b = b.rotated(axis_y, _random_angle(rotation.y, snap_angle.y)) - b = b.rotated(axis_z, _random_angle(rotation.z, snap_angle.z)) - - t.basis = b - transforms.list[i] = t - - -func _random_vec3() -> Vector3: - var vec3 = Vector3.ZERO - vec3.x = _rng.randf_range(-1.0, 1.0) - vec3.y = _rng.randf_range(-1.0, 1.0) - vec3.z = _rng.randf_range(-1.0, 1.0) - return vec3 - - -func _random_angle(rot: float, snap: float) -> float: - return deg_to_rad(snapped(_rng.randf_range(-1.0, 1.0) * rot, snap)) - - -func _clamp_vector(vec3, vmin, vmax) -> Vector3: - vec3.x = clamp(vec3.x, vmin.x, vmax.x) - vec3.y = clamp(vec3.y, vmin.y, vmax.y) - vec3.z = clamp(vec3.z, vmin.z, vmax.z) - return vec3 diff --git a/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd.uid b/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd.uid deleted file mode 100644 index 250faa0..0000000 --- a/godot/addons/proton_scatter/src/modifiers/randomize_rotation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b8pvo18e2jssa diff --git a/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd b/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd deleted file mode 100644 index ab3e28f..0000000 --- a/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd +++ /dev/null @@ -1,106 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var position := Vector3.ZERO -@export var rotation := Vector3.ZERO -@export var scale := Vector3.ZERO - -var _rng: RandomNumberGenerator - - -func _init() -> void: - display_name = "Randomize Transforms" - category = "Edit" - can_override_seed = true - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - -func _process_transforms(transforms, domain, random_seed) -> void: - _rng = RandomNumberGenerator.new() - _rng.set_seed(random_seed) - - var t: Transform3D - var global_t: Transform3D - var basis: Basis - var random_scale: Vector3 - var random_position: Vector3 - var s_gt: Transform3D = domain.get_global_transform() - var s_gt_inverse := s_gt.affine_inverse() - - # Global rotation axis - var axis_x := Vector3.RIGHT - var axis_y := Vector3.UP - var axis_z := Vector3.DOWN - - if is_using_global_space(): - axis_x = (s_gt_inverse.basis * Vector3.RIGHT).normalized() - axis_y = (s_gt_inverse.basis * Vector3.UP).normalized() - axis_z = (s_gt_inverse.basis * Vector3.FORWARD).normalized() - - for i in transforms.size(): - t = transforms.list[i] - basis = t.basis - - # Apply rotation - if is_using_individual_instances_space(): - axis_x = basis.x.normalized() - axis_y = basis.y.normalized() - axis_z = basis.z.normalized() - - basis = basis.rotated(axis_x, deg_to_rad(_random_float() * rotation.x)) - basis = basis.rotated(axis_y, deg_to_rad(_random_float() * rotation.y)) - basis = basis.rotated(axis_z, deg_to_rad(_random_float() * rotation.z)) - - # Apply scale - random_scale = Vector3.ONE + (_rng.randf() * scale) - - if is_using_individual_instances_space(): - basis.x *= random_scale.x - basis.y *= random_scale.y - basis.z *= random_scale.z - - elif is_using_global_space(): - global_t = s_gt * Transform3D(basis, Vector3.ZERO) - global_t = global_t.scaled(random_scale) - basis = (s_gt_inverse * global_t).basis - - else: - basis = basis.scaled(random_scale) - - # Apply position - random_position = _random_vec3() * position - - if is_using_individual_instances_space(): - random_position = t.basis * random_position - - elif is_using_global_space(): - random_position = s_gt_inverse.basis * random_position - - t.origin += random_position - t.basis = basis - - transforms.list[i] = t - - -func _random_vec3() -> Vector3: - var vec3 = Vector3.ZERO - vec3.x = _rng.randf_range(-1.0, 1.0) - vec3.y = _rng.randf_range(-1.0, 1.0) - vec3.z = _rng.randf_range(-1.0, 1.0) - return vec3 - - -func _random_float() -> float: - return _rng.randf_range(-1.0, 1.0) - - -func _clamp_vector(vec3, vmin, vmax) -> Vector3: - vec3.x = clamp(vec3.x, vmin.x, vmax.x) - vec3.y = clamp(vec3.y, vmin.y, vmax.y) - vec3.z = clamp(vec3.z, vmin.z, vmax.z) - return vec3 diff --git a/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd.uid b/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd.uid deleted file mode 100644 index 89ee084..0000000 --- a/godot/addons/proton_scatter/src/modifiers/randomize_transforms.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://docnfknh5blx2 diff --git a/godot/addons/proton_scatter/src/modifiers/relax.gd b/godot/addons/proton_scatter/src/modifiers/relax.gd deleted file mode 100644 index 84527b7..0000000 --- a/godot/addons/proton_scatter/src/modifiers/relax.gd +++ /dev/null @@ -1,191 +0,0 @@ -@tool -extends "base_modifier.gd" - - -static var shader_file: RDShaderFile - - -@export var iterations : int = 3 -@export var offset_step : float = 0.01 -@export var consecutive_step_multiplier : float = 0.5 -@export var use_computeshader : bool = true - - -func _init() -> void: - display_name = "Relax Position" - category = "Edit" - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - can_restrict_height = true - restrict_height = true - - documentation.add_warning( - "This modifier is has an O(n²) complexity and will be slow with - large amounts of points, unless your device supports compute shaders.", - 1) - - var p := documentation.add_parameter("iterations") - p.set_type("int") - p.set_cost(2) - p.set_description( - "How many times the relax algorithm will run. Increasing this value will - generally improves the result, at the cost of execution speed." - ) - - p = documentation.add_parameter("Offset step") - p.set_type("float") - p.set_cost(0) - p.set_description("How far the transform will be pushed away each iteration.") - - p = documentation.add_parameter("Consecutive step multiplier") - p.set_type("float") - p.set_cost(0) - p.set_description( - "On each iteration, multiply the offset step by this value. This value - is usually set between 0 and 1, to make the effect less pronounced on - successive iterations.") - - p = documentation.add_parameter("Use compute shader") - p.set_cost(0) - p.set_type("bool") - p.set_description( - "Run the calculations on the GPU instead of the CPU. This provides - a significant speed boost and should be enabled when possible.") - p.add_warning( - "This parameter can't be enabled when using the OpenGL backend or running - in headless mode.", 2) - - -func _process_transforms(transforms, _domain, _seed) -> void: - var offset := offset_step - if transforms.size() < 2: - return - - # Disable the use of compute shader, if we cannot create a RenderingDevice - if use_computeshader: - var rd := RenderingServer.create_local_rendering_device() - if rd == null: - use_computeshader = false - else: - rd.free() - rd = null - - if use_computeshader: - for iteration in iterations: - if interrupt_update: - return - var movedir: PackedVector3Array = compute_closest(transforms) - for i in transforms.size(): - var dir = movedir[i] - if restrict_height: - dir.y = 0.0 - # move away from closest point - transforms.list[i].origin += dir.normalized() * offset - - offset *= consecutive_step_multiplier - - else: - # calculate the relax transforms on the cpu - for iteration in iterations: - for i in transforms.size(): - if interrupt_update: - return - var min_vector = Vector3.ONE * 99999.0 - var threshold := 99999.0 - var distance := 0.0 - var diff: Vector3 - - # Find the closest point - for j in transforms.size(): - if i == j: - continue - - diff = transforms.list[i].origin - transforms.list[j].origin - distance = diff.length_squared() - - if distance < threshold: - min_vector = diff - threshold = distance - - if restrict_height: - min_vector.y = 0.0 - - # move away from closest point - transforms.list[i].origin += min_vector.normalized() * offset - - offset *= consecutive_step_multiplier - - -# compute the closest points to each other using a compute shader -# return a vector for each point that points away from the closest neighbour -func compute_closest(transforms) -> PackedVector3Array: - var padded_num_vecs = ceil(float(transforms.size()) / 64.0) * 64 - var padded_num_floats = padded_num_vecs * 4 - var rd := RenderingServer.create_local_rendering_device() - var shader_spirv: RDShaderSPIRV = get_shader_file().get_spirv() - var shader := rd.shader_create_from_spirv(shader_spirv) - # Prepare our data. We use vec4 floats in the shader, so we need 32 bit. - var input := PackedFloat32Array() - for i in transforms.size(): - input.append(transforms.list[i].origin.x) - input.append(transforms.list[i].origin.y) - input.append(transforms.list[i].origin.z) - input.append(0) # needed to use vec4, necessary for byte alignment in the shader code - # buffer size, number of vectors sent to the gpu - input.resize(padded_num_floats) # indexing in the compute shader requires padding - var input_bytes := input.to_byte_array() - var output_bytes := input_bytes.duplicate() - # Create a storage buffer that can hold our float values. - var buffer_in := rd.storage_buffer_create(input_bytes.size(), input_bytes) - var buffer_out := rd.storage_buffer_create(output_bytes.size(), output_bytes) - - # Create a uniform to assign the buffer to the rendering device - var uniform_in := RDUniform.new() - uniform_in.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER - uniform_in.binding = 0 # this needs to match the "binding" in our shader file - uniform_in.add_id(buffer_in) - # Create a uniform to assign the buffer to the rendering device - var uniform_out := RDUniform.new() - uniform_out.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER - uniform_out.binding = 1 # this needs to match the "binding" in our shader file - uniform_out.add_id(buffer_out) - # the last parameter (the 0) needs to match the "set" in our shader file - var uniform_set := rd.uniform_set_create([uniform_in, uniform_out], shader, 0) - - # Create a compute pipeline - var pipeline := rd.compute_pipeline_create(shader) - var compute_list := rd.compute_list_begin() - rd.compute_list_bind_compute_pipeline(compute_list, pipeline) - rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0) - # each workgroup computes 64 vectors -# print("Dispatching workgroups: ", padded_num_vecs/64) - rd.compute_list_dispatch(compute_list, padded_num_vecs/64, 1, 1) - rd.compute_list_end() - # Submit to GPU and wait for sync - rd.submit() - rd.sync() - # Read back the data from the buffer - var result_bytes := rd.buffer_get_data(buffer_out) - var result := result_bytes.to_float32_array() - var retval = PackedVector3Array() - for i in transforms.size(): - retval.append(Vector3(result[i*4], result[i*4+1], result[i*4+2])) - - # Free the allocated objects. - # All resources must be freed after use to avoid memory leaks. - if rd != null: - rd.free_rid(pipeline) - rd.free_rid(uniform_set) - rd.free_rid(shader) - rd.free_rid(buffer_in) - rd.free_rid(buffer_out) - rd.free() - rd = null - return retval - -func get_shader_file() -> RDShaderFile: - if shader_file == null: - shader_file = load(get_script().resource_path.get_base_dir() + "/compute_shaders/compute_relax.glsl") - - return shader_file diff --git a/godot/addons/proton_scatter/src/modifiers/relax.gd.uid b/godot/addons/proton_scatter/src/modifiers/relax.gd.uid deleted file mode 100644 index 7868171..0000000 --- a/godot/addons/proton_scatter/src/modifiers/relax.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://oveewoqgjp2o diff --git a/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd b/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd deleted file mode 100644 index 50f20b9..0000000 --- a/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd +++ /dev/null @@ -1,44 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export var negative_shapes_only := false - - -func _init() -> void: - display_name = "Remove Outside" - category = "Remove" - can_restrict_height = false - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - - documentation.add_paragraph( - "Remove all transforms falling outside a ScatterShape node, or inside - a shape set to 'Negative' mode.") - - var p := documentation.add_parameter("Negative Shapes Only") - p.set_type("bool") - p.set_description( - "Only remove transforms falling inside the negative shapes (shown - in red). Transforms outside any shapes will still remain.") - - -func _process_transforms(transforms, domain, seed) -> void: - var i := 0 - var point: Vector3 - var to_remove := false - - while i < transforms.size(): - point = transforms.list[i].origin - - if negative_shapes_only: - to_remove = domain.is_point_excluded(point) - else: - to_remove = not domain.is_point_inside(point) - - if to_remove: - transforms.list.remove_at(i) - continue - - i += 1 diff --git a/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd.uid b/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd.uid deleted file mode 100644 index 1818ce0..0000000 --- a/godot/addons/proton_scatter/src/modifiers/remove_outside_shapes.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dta6spev63v4n diff --git a/godot/addons/proton_scatter/src/modifiers/remove_random.gd b/godot/addons/proton_scatter/src/modifiers/remove_random.gd deleted file mode 100644 index 539edcb..0000000 --- a/godot/addons/proton_scatter/src/modifiers/remove_random.gd +++ /dev/null @@ -1,37 +0,0 @@ -@tool -extends "base_modifier.gd" - - -@export_range(0.0, 100.0) var probability: float = 50.0 - - -func _init() -> void: - display_name = "Remove Random" - category = "Remove" - can_restrict_height = false - global_reference_frame_available = false - local_reference_frame_available = false - individual_instances_reference_frame_available = false - can_override_seed = true - - documentation.add_paragraph( - "Remove transforms at random.") - - var p := documentation.add_parameter("Probability") - p.set_type("float") - p.set_description( - "The probability to remove a transform, in percent. - At 0, nothing is removed. At 100, everything is removed.") - - -func _process_transforms(transforms: TransformList, _domain: Domain, seed: int) -> void: - var i := 0 - var rng := RandomNumberGenerator.new() - rng.seed = seed - var threshold: float = probability / 100.0 - - while i < transforms.size(): - if rng.randf() < threshold: - transforms.list.remove_at(i) - continue - i += 1 diff --git a/godot/addons/proton_scatter/src/modifiers/remove_random.gd.uid b/godot/addons/proton_scatter/src/modifiers/remove_random.gd.uid deleted file mode 100644 index 9cb2d87..0000000 --- a/godot/addons/proton_scatter/src/modifiers/remove_random.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://prm6r2h4vedk diff --git a/godot/addons/proton_scatter/src/modifiers/single_item.gd b/godot/addons/proton_scatter/src/modifiers/single_item.gd deleted file mode 100644 index 2db6d00..0000000 --- a/godot/addons/proton_scatter/src/modifiers/single_item.gd +++ /dev/null @@ -1,55 +0,0 @@ -@tool -extends "base_modifier.gd" - -# Adds a single object with the given transform - -@export var offset := Vector3.ZERO -@export var rotation := Vector3.ZERO -@export var scale := Vector3.ONE - - -func _init() -> void: - display_name = "Add Single Item" - category = "Create" - warning_ignore_no_shape = true - warning_ignore_no_transforms = true - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = false - use_local_space_by_default() - - -func _process_transforms(transforms, domain, _seed) -> void: - var gt: Transform3D = domain.get_global_transform() - var gt_inverse: Transform3D = gt.affine_inverse() - - var t_origin := offset - var basis := Basis() - var x_axis = Vector3.RIGHT - var y_axis = Vector3.UP - var z_axis = Vector3.FORWARD - - if is_using_global_space(): - t_origin = gt_inverse.basis * t_origin - x_axis = gt_inverse.basis * x_axis - y_axis = gt_inverse.basis * y_axis - z_axis = gt_inverse.basis * z_axis - basis = gt_inverse.basis - - basis = basis.rotated(x_axis, deg_to_rad(rotation.x)) - basis = basis.rotated(y_axis, deg_to_rad(rotation.y)) - basis = basis.rotated(z_axis, deg_to_rad(rotation.z)) - - var transform := Transform3D(basis, Vector3.ZERO) - - if is_using_global_space(): - var global_t: Transform3D = gt * transform - global_t.basis = global_t.basis.scaled(scale) - transform = gt_inverse * global_t - else: - transform = transform.scaled_local(scale) - - transform.origin = t_origin - - transforms.list.push_back(transform) diff --git a/godot/addons/proton_scatter/src/modifiers/single_item.gd.uid b/godot/addons/proton_scatter/src/modifiers/single_item.gd.uid deleted file mode 100644 index bcc28c9..0000000 --- a/godot/addons/proton_scatter/src/modifiers/single_item.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cblfk0fuqep72 diff --git a/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd b/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd deleted file mode 100644 index 308a25b..0000000 --- a/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd +++ /dev/null @@ -1,100 +0,0 @@ -@tool -extends "base_modifier.gd" - -# TODO: This modifier has the same shortcomings as offset_rotation, but in every reference frame. - - -@export var position_step := Vector3.ZERO -@export var rotation_step := Vector3.ZERO -@export var scale_step := Vector3.ZERO - - -func _init() -> void: - display_name = "Snap Transforms" - category = "Edit" - can_restrict_height = false - global_reference_frame_available = true - local_reference_frame_available = true - individual_instances_reference_frame_available = true - use_individual_instances_space_by_default() - - documentation.add_paragraph("Snap the individual transforms components.") - documentation.add_paragraph("Values of 0 do not affect the transforms.") - - var p := documentation.add_parameter("Position") - p.set_type("Vector3") - p.set_description("Defines the grid size used to snap the transform position.") - - p = documentation.add_parameter("Rotation") - p.set_type("Vector3") - p.set_description( - "When set to any value above 0, the rotation will be set to the nearest - multiple of that angle.") - p.add_warning( - "Example: If rotation is set to (0, 90.0, 0), the rotation around the Y - axis will be snapped to the closed value among [0, 90, 180, 360].") - - p = documentation.add_parameter("Scale") - p.set_type("Vector3") - p.set_description("Snap the current scale to the nearest multiple.") - - -func _process_transforms(transforms, domain, _seed) -> void: - var s_gt: Transform3D = domain.get_global_transform() - var s_lt: Transform3D = domain.get_local_transform() - var s_gt_inverse := s_gt.affine_inverse() - - var axis_x := Vector3.RIGHT - var axis_y := Vector3.UP - var axis_z := Vector3.FORWARD - - if is_using_global_space(): - axis_x = (s_gt_inverse.basis * Vector3.RIGHT).normalized() - axis_y = (s_gt_inverse.basis * Vector3.UP).normalized() - axis_z = (s_gt_inverse.basis * Vector3.FORWARD).normalized() - - var rotation_step_rad := Vector3.ZERO - rotation_step_rad.x = deg_to_rad(rotation_step.x) - rotation_step_rad.y = deg_to_rad(rotation_step.y) - rotation_step_rad.z = deg_to_rad(rotation_step.z) - - for i in transforms.size(): - var t: Transform3D = transforms.list[i] - var b := Basis() - var current_rotation: Vector3 - - if is_using_individual_instances_space(): - axis_x = t.basis.x.normalized() - axis_y = t.basis.y.normalized() - axis_z = t.basis.z.normalized() - - current_rotation = t.basis.get_euler() - t.origin = snapped(t.origin, position_step) - - elif is_using_local_space(): - var local_t := s_lt * t - current_rotation = local_t.basis.get_euler() - t.origin = snapped(t.origin, position_step) - - else: - b = (s_gt_inverse * Transform3D()).basis - var global_t := s_gt * t - current_rotation = global_t.basis.get_euler() - t.origin = s_gt_inverse * snapped(global_t.origin, position_step) - - b = b.rotated(axis_x, snapped(current_rotation.x, rotation_step_rad.x)) - b = b.rotated(axis_y, snapped(current_rotation.y, rotation_step_rad.y)) - b = b.rotated(axis_z, snapped(current_rotation.z, rotation_step_rad.z)) - - # Snap scale - var current_scale := t.basis.get_scale() - var snapped_scale: Vector3 = snapped(current_scale, scale_step) - t.basis = b - transforms.list[i] = t.scaled_local(snapped_scale) - - -func _clamp_vector(vec3, vmin, vmax) -> Vector3: - vec3.x = clamp(vec3.x, vmin.x, vmax.x) - vec3.y = clamp(vec3.y, vmin.y, vmax.y) - vec3.z = clamp(vec3.z, vmin.z, vmax.z) - return vec3 diff --git a/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd.uid b/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd.uid deleted file mode 100644 index e02504a..0000000 --- a/godot/addons/proton_scatter/src/modifiers/snap_transforms.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hel230du7dq2 diff --git a/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader b/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader deleted file mode 100644 index a7771c5..0000000 --- a/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader +++ /dev/null @@ -1,37 +0,0 @@ -shader_type particles; - - -uniform mat4 global_transform; - - -float rand_from_seed(in uint seed) { - int k; - int s = int(seed); - if (s == 0) - s = 305420679; - k = s / 127773; - s = 16807 * (s - k * 127773) - 2836 * k; - if (s < 0) - s += 2147483647; - seed = uint(s); - return float(seed % uint(65536)) / 65535.0; -} - -uint hash(uint x) { - x = ((x >> uint(16)) ^ x) * uint(73244475); - x = ((x >> uint(16)) ^ x) * uint(73244475); - x = (x >> uint(16)) ^ x; - return x; -} - -void start() { - CUSTOM.x = 0.0; -} - -void process() { - uint seed = hash(uint(INDEX) + uint(1) + RANDOM_SEED); - float random = rand_from_seed(seed); - float offset = cos(TIME) * random * 0.05; - - TRANSFORM[3].y += offset; -} \ No newline at end of file diff --git a/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader.uid b/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader.uid deleted file mode 100644 index 0beacaf..0000000 --- a/godot/addons/proton_scatter/src/particles/example_random_motion.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bluw3x6eai146 diff --git a/godot/addons/proton_scatter/src/particles/static.gdshader b/godot/addons/proton_scatter/src/particles/static.gdshader deleted file mode 100644 index 357a145..0000000 --- a/godot/addons/proton_scatter/src/particles/static.gdshader +++ /dev/null @@ -1,15 +0,0 @@ -shader_type particles; -render_mode keep_data; - - -uniform mat4 global_transform; - - -void start() { - -} - -void process() { - -} - diff --git a/godot/addons/proton_scatter/src/particles/static.gdshader.uid b/godot/addons/proton_scatter/src/particles/static.gdshader.uid deleted file mode 100644 index 13e3fab..0000000 --- a/godot/addons/proton_scatter/src/particles/static.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c56m51ywgur87 diff --git a/godot/addons/proton_scatter/src/presets/preset_entry.gd b/godot/addons/proton_scatter/src/presets/preset_entry.gd deleted file mode 100644 index c7ca30b..0000000 --- a/godot/addons/proton_scatter/src/presets/preset_entry.gd +++ /dev/null @@ -1,28 +0,0 @@ -@tool -extends MarginContainer - -signal load_full -signal load_stack_only -signal delete - - -func _ready() -> void: - $%LoadStackOnly.pressed.connect(func (): load_stack_only.emit()) - $%LoadFullPreset.pressed.connect(func (): load_full.emit()) - $%DeleteButton.pressed.connect(func (): delete.emit()) - - -func set_preset_name(preset_name: String) -> void: - preset_name = preset_name.trim_suffix(".tres") - $%Label.set_text(preset_name.capitalize()) - - -func show_save_controls() -> void: - $%SaveButtons.visible = true - $%LoadButtons.visible = false - - -func show_load_controls() -> void: - $%SaveButtons.visible = false - $%LoadButtons.visible = true - diff --git a/godot/addons/proton_scatter/src/presets/preset_entry.gd.uid b/godot/addons/proton_scatter/src/presets/preset_entry.gd.uid deleted file mode 100644 index 13b3f57..0000000 --- a/godot/addons/proton_scatter/src/presets/preset_entry.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dfti13vg1ufa diff --git a/godot/addons/proton_scatter/src/presets/preset_entry.tscn b/godot/addons/proton_scatter/src/presets/preset_entry.tscn deleted file mode 100644 index d267d64..0000000 --- a/godot/addons/proton_scatter/src/presets/preset_entry.tscn +++ /dev/null @@ -1,92 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://bosqtuvhckh3g"] - -[ext_resource type="Texture2D" uid="uid://ddjrq1h4mkn6a" path="res://addons/proton_scatter/icons/load.svg" id="1_0auay"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/presets/preset_entry.gd" id="1_bqha3"] -[ext_resource type="Texture2D" uid="uid://btb6rqhhi27mx" path="res://addons/proton_scatter/icons/remove.svg" id="2_p04k2"] - -[sub_resource type="SystemFont" id="SystemFont_kgkwq"] - -[sub_resource type="LabelSettings" id="LabelSettings_poli7"] -font = SubResource("SystemFont_kgkwq") - -[node name="PresetEntry" type="MarginContainer"] -custom_minimum_size = Vector2(450, 0) -anchors_preset = 14 -anchor_top = 0.5 -anchor_right = 1.0 -anchor_bottom = 0.5 -offset_top = -45.0 -offset_bottom = 45.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -script = ExtResource("1_bqha3") - -[node name="Panel" type="Panel" parent="."] -layout_mode = 2 - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "Preset name" -label_settings = SubResource("LabelSettings_poli7") - -[node name="VSeparator" type="VSeparator" parent="MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="LoadButtons" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -alignment = 1 - -[node name="LoadStackOnly" type="Button" parent="MarginContainer/HBoxContainer/LoadButtons"] -unique_name_in_owner = true -layout_mode = 2 -text = "Load modifier stack" -icon = ExtResource("1_0auay") -alignment = 0 - -[node name="LoadFullPreset" type="Button" parent="MarginContainer/HBoxContainer/LoadButtons"] -unique_name_in_owner = true -layout_mode = 2 -text = "Load full preset" -icon = ExtResource("1_0auay") -alignment = 0 - -[node name="SaveButtons" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -size_flags_stretch_ratio = 2.0 -alignment = 1 - -[node name="OverrideButton" type="Button" parent="MarginContainer/HBoxContainer/SaveButtons"] -unique_name_in_owner = true -layout_mode = 2 -text = "Override preset" -icon = ExtResource("1_0auay") -alignment = 0 - -[node name="VSeparator2" type="VSeparator" parent="MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="DeleteButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -theme_override_colors/icon_normal_color = Color(0.917647, 0.0784314, 0, 1) -icon = ExtResource("2_p04k2") diff --git a/godot/addons/proton_scatter/src/presets/presets.gd b/godot/addons/proton_scatter/src/presets/presets.gd deleted file mode 100644 index f9a70ab..0000000 --- a/godot/addons/proton_scatter/src/presets/presets.gd +++ /dev/null @@ -1,196 +0,0 @@ -@tool -extends Popup - - -const PRESETS_PATH = "res://addons/proton_scatter/presets" -const PresetEntry := preload("./preset_entry.tscn") -const ProtonScatterUtil := preload('../common/scatter_util.gd') - -var _scatter_node -var _ideal_popup_size: Vector2i -var _editor_file_system: EditorFileSystem -var _preset_path_to_delete: String -var _preset_control_to_delete: Control - -@onready var _new_preset_button: Button = %NewPresetButton -@onready var _new_preset_dialog: ConfirmationDialog = %NewPresetDialog -@onready var _delete_preset_dialog: ConfirmationDialog = %DeleteDialog -@onready var _delete_warning_label: Label = %DeleteLabel -@onready var _presets_root: Control = %PresetsRoot - - -func _ready(): - _new_preset_button.pressed.connect(_show_preset_dialog) - _new_preset_dialog.confirmed.connect(_on_new_preset_name_confirmed) - _delete_preset_dialog.confirmed.connect(_on_delete_preset_confirmed) - _new_preset_dialog.hide() - _delete_preset_dialog.hide() - hide() - - -func save_preset(scatter_node: Node3D) -> void: - if not scatter_node: - return - - _populate() - _scatter_node = scatter_node - _new_preset_button.visible = true - - for c in _presets_root.get_children(): - c.show_save_controls() - - popup_centered(_ideal_popup_size) - - -func load_preset(scatter_node: Node3D) -> void: - if not scatter_node: - return - - _populate() - _scatter_node = scatter_node - _new_preset_button.visible = false - - for c in _presets_root.get_children(): - c.show_load_controls() - - popup_centered(_ideal_popup_size) - - -func load_default(scatter_node: Node3D) -> void: - _scatter_node = scatter_node - _on_load_full_preset(PRESETS_PATH.path_join("scatter_default.tscn")) - - -func set_editor_plugin(editor_plugin: EditorPlugin) -> void: - if not editor_plugin: - return - - _editor_file_system = editor_plugin.get_editor_interface().get_resource_filesystem() - - -func _clear(): - for c in _presets_root.get_children(): - c.queue_free() - - -func _populate() -> void: - _clear() - var dir = DirAccess.open(PRESETS_PATH) - if not dir: - print_debug("ProtonScatter error: Could not open folder ", PRESETS_PATH) - return - - dir.include_hidden = false - dir.include_navigational = false - dir.list_dir_begin() - - while true: - var file := dir.get_next() - if file == "": - break - - if dir.current_is_dir(): - continue - - if not file.ends_with(".tscn") and not file.ends_with(".scn"): - continue - - # Preset found, create an entry - var full_path = PRESETS_PATH.path_join(file) - var entry := PresetEntry.instantiate() - entry.set_preset_name(file.get_basename()) - entry.load_full.connect(_on_load_full_preset.bind(full_path)) - entry.load_stack_only.connect(_on_load_stack_only.bind(full_path)) - entry.delete.connect(_on_delete_button_pressed.bind(full_path, entry)) - - _presets_root.add_child(entry) - - dir.list_dir_end() - var full_height = _presets_root.get_child_count() * 120 - _ideal_popup_size = Vector2i(450, clamp(full_height, 120, 500)) - - -func _show_preset_dialog() -> void: - $%NewPresetName.set_text("") - _new_preset_dialog.popup_centered() - - -func _on_new_preset_name_confirmed() -> void: - var file_name: String = $%NewPresetName.text.to_lower().strip_edges() + ".tscn" - var full_path := PRESETS_PATH.path_join(file_name) - _on_save_preset(full_path) - hide() - - -func _on_save_preset(path) -> void: - var preset = _scatter_node.duplicate(7) - preset.clear_output() - ProtonScatterUtil.set_owner_recursive(preset, preset) - preset.global_transform.origin = Vector3.ZERO - - var packed_scene = PackedScene.new() - if packed_scene.pack(preset) != OK: - print_debug("ProtonScatter error: Failed to save preset") - return - - var err = ResourceSaver.save(packed_scene, path) - if err: - print_debug("ProtonScatter error: Failed to save preset. Code: ", err) - - -func _on_load_full_preset(path: String) -> void: - var preset_scene: PackedScene = load(path) - if not preset_scene: - print("Could not find preset ", path) - return - - var preset = preset_scene.instantiate() - - if preset: - _scatter_node.modifier_stack = preset.modifier_stack.get_copy() - preset.global_transform = _scatter_node.get_global_transform() - - for c in _scatter_node.get_children(): - if c is ProtonScatterItem or c is ProtonScatterShape: - _scatter_node.remove_child(c) - c.owner = null - c.queue_free() - - for c in preset.get_children(): - if c is Marker3D or c.name == "ScatterOutput": - continue - preset.remove_child(c) - c.owner = null - _scatter_node.add_child(c, true) - - ProtonScatterUtil.set_owner_recursive(_scatter_node, get_tree().get_edited_scene_root()) - preset.queue_free() - - _scatter_node.rebuild.call_deferred() - hide() - - -func _on_load_stack_only(path: String) -> void: - var preset = load(path).instantiate() - if preset: - _scatter_node.modifier_stack = preset.modifier_stack.get_copy() - _scatter_node.rebuild.call_deferred() - preset.queue_free() - - hide() - - -func _on_delete_button_pressed(path: String, entry: Control) -> void: - _preset_path_to_delete = path - _preset_control_to_delete = entry - _delete_warning_label.text = "Are you sure you want to delete the preset [" \ - + path.get_file().get_basename().capitalize() + "] ?\n\n" \ - + "This operation cannot be undone." - _delete_preset_dialog.popup_centered() - - -func _on_delete_preset_confirmed() -> void: - DirAccess.remove_absolute(_preset_path_to_delete) - _presets_root.remove_child(_preset_control_to_delete) - _preset_control_to_delete.queue_free() - _editor_file_system.scan() # Refresh the filesystem view diff --git a/godot/addons/proton_scatter/src/presets/presets.gd.uid b/godot/addons/proton_scatter/src/presets/presets.gd.uid deleted file mode 100644 index ee2b33f..0000000 --- a/godot/addons/proton_scatter/src/presets/presets.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cou6q1fq4p5tg diff --git a/godot/addons/proton_scatter/src/presets/presets.tscn b/godot/addons/proton_scatter/src/presets/presets.tscn deleted file mode 100644 index 559fc3d..0000000 --- a/godot/addons/proton_scatter/src/presets/presets.tscn +++ /dev/null @@ -1,90 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bcsosdvstytoq"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/presets/presets.gd" id="1_ualle"] -[ext_resource type="Texture2D" uid="uid://cun73k8jdmr4e" path="res://addons/proton_scatter/icons/add.svg" id="2_j26xt"] -[ext_resource type="PackedScene" uid="uid://bosqtuvhckh3g" path="res://addons/proton_scatter/src/presets/preset_entry.tscn" id="2_orram"] - -[node name="Presets" type="PopupPanel"] -title = "Manage presets" -initial_position = 2 -size = Vector2i(490, 200) -unresizable = false -borderless = false -extend_to_title = true -min_size = Vector2i(400, 150) -script = ExtResource("1_ualle") - -[node name="MarginContainer" type="MarginContainer" parent="."] -offset_left = 4.0 -offset_top = 4.0 -offset_right = 486.0 -offset_bottom = 196.0 -theme_override_constants/margin_left = 12 -theme_override_constants/margin_top = 12 -theme_override_constants/margin_right = 12 -theme_override_constants/margin_bottom = 12 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -layout_mode = 2 - -[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 -horizontal_scroll_mode = 0 - -[node name="PresetsRoot" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -alignment = 1 - -[node name="PresetEntry" parent="MarginContainer/VBoxContainer/ScrollContainer/PresetsRoot" instance=ExtResource("2_orram")] -layout_mode = 2 - -[node name="NewPresetButton" type="Button" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -custom_minimum_size = Vector2(200, 0) -layout_mode = 2 -size_flags_horizontal = 4 -text = "Create new preset" -icon = ExtResource("2_j26xt") - -[node name="NewPresetDialog" type="ConfirmationDialog" parent="."] -unique_name_in_owner = true -title = "Create new preset" - -[node name="MarginContainer" type="MarginContainer" parent="NewPresetDialog"] -offset_left = 8.0 -offset_top = 8.0 -offset_right = 192.0 -offset_bottom = 51.0 - -[node name="NewPresetName" type="LineEdit" parent="NewPresetDialog/MarginContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 4 -placeholder_text = "New preset name" - -[node name="DeleteDialog" type="ConfirmationDialog" parent="."] -unique_name_in_owner = true -title = "Delete preset" -size = Vector2i(250, 184) -ok_button_text = "Delete" -dialog_autowrap = true - -[node name="MarginContainer" type="MarginContainer" parent="DeleteDialog"] -offset_left = 8.0 -offset_top = 8.0 -offset_right = 242.0 -offset_bottom = 395.0 - -[node name="DeleteLabel" type="Label" parent="DeleteDialog/MarginContainer"] -unique_name_in_owner = true -custom_minimum_size = Vector2(250, 0) -layout_mode = 2 -text = "Are you sure you want to delete preset [Preset]? - -This operation cannot be undone." -horizontal_alignment = 1 -autowrap_mode = 2 diff --git a/godot/addons/proton_scatter/src/scatter.gd b/godot/addons/proton_scatter/src/scatter.gd deleted file mode 100644 index 881cfca..0000000 --- a/godot/addons/proton_scatter/src/scatter.gd +++ /dev/null @@ -1,784 +0,0 @@ -@tool -class_name ProtonScatter -extends Node3D - - -signal shape_changed -signal thread_completed -signal build_completed - - -# Includes -const ProtonScatterDomain := preload("./common/domain.gd") -const ProtonScatterPhysicsHelper := preload("./common/physics_helper.gd") -const ProtonScatterTransformList := preload("./common/transform_list.gd") -const ProtonScatterUtil := preload('./common/scatter_util.gd') - - -@export_category("ProtonScatter") - -@export_group("General") - -## Controls whether the scatter system is active. When disabled, all scattered objects -## are removed from the scene. When enabled, the system rebuilds according to current settings. -@export var enabled := true: - set(val): - enabled = val - if is_ready: - rebuild() - -## Used for random number generation across all modifiers. -## Using the same seed with the same settings will produce identical results. -@export var global_seed := 0: - set(val): - global_seed = val - rebuild() - -## scattered objects will be visible in the scene tree. -## Useful for debugging but may impact editor performance with large numbers of objects. -@export var show_output_in_tree := false: - set(val): - show_output_in_tree = val - if output_root: - ProtonScatterUtil.enforce_output_root_owner(self) - -@export_group("Performance") - - -## Determines how scattered objects are rendered in the scene: -## Use Instancing (0): Uses MultiMesh instances for efficient rendering of identical objects. -## Create Copies (1): Creates individual node copies for each scattered object. -## Use Particles (2): Uses GPU particles system for very large numbers of objects. -@export_enum("Use Instancing:0", - "Create Copies:1", - "Use Particles:2")\ - var render_mode := 0: - set(val): - render_mode = val - if is_ready: - notify_property_list_changed() - full_rebuild.call_deferred() - -var use_chunks : bool = true: - set(val): - use_chunks = val - if is_ready: - notify_property_list_changed() - full_rebuild.call_deferred() - -var chunk_dimensions := Vector3.ONE * 15.0: - set(val): - chunk_dimensions.x = max(val.x, 1.0) - chunk_dimensions.y = max(val.y, 1.0) - chunk_dimensions.z = max(val.z, 1.0) - if is_ready: - rebuild.call_deferred() - -## If enabled, creates static collision shapes for scattered objects. -## Uses the Physics server directly instead of creating actual collision nodes -@export var keep_static_colliders := false - -## If enabled, forces a complete rebuild of the scattered objects when the scene loads. -## Disable this if you want to restore the previously cached transforms instead of -## regenerating them, which can be useful for faster scene loading times. -@export var force_rebuild_on_load := true - -## If enabled, allows the scatter node to rebuild its output during gameplay. -## Disable this in production to prevent unnecessary updates and improve performance, -## since scattered objects typically don't need to change after the scene is loaded. -@export var enable_updates_in_game := false - -@export_group("Compatibility") - -@export var force_uniform_scale: bool = false: - set(val): - force_uniform_scale = val - if is_ready: - rebuild.call_deferred() - -@export_group("Dependency") - -## References another ProtonScatter node whose build completion should trigger this node to rebuild. -## Used to create dependency chains where scattered objects are generated in a specific order. -@export var scatter_parent: NodePath: - set(val): - if not is_inside_tree(): - scatter_parent = val - return - - scatter_parent = NodePath() - if is_instance_valid(_dependency_parent): - _dependency_parent.build_completed.disconnect(rebuild) - _dependency_parent = null - - var node = get_node_or_null(val) - if not node: - return - - var type = node.get_script() - var scatter_type = get_script() - if type != scatter_type: - push_warning("ProtonScatter warning: Please select a ProtonScatter node as a parent dependency.") - return - - # TODO: Check for cyclic dependency - - scatter_parent = val - _dependency_parent = node - _dependency_parent.build_completed.connect(rebuild, CONNECT_DEFERRED) - - -@export_group("Debug", "dbg_") - -## Debug option to disable multithreading during scatter operations. -## When enabled, all scatter calculations run on the main thread, which is slower -## but easier to debug. Only use this during development. -@export var dbg_disable_thread := false - -var undo_redo # EditorUndoRedoManager - Can't type this, class not available outside the editor -var modifier_stack: ProtonScatterModifierStack: - set(val): - if modifier_stack: - if modifier_stack.value_changed.is_connected(rebuild): - modifier_stack.value_changed.disconnect(rebuild) - if modifier_stack.stack_changed.is_connected(rebuild): - modifier_stack.stack_changed.disconnect(rebuild) - if modifier_stack.transforms_ready.is_connected(_on_transforms_ready): - modifier_stack.transforms_ready.disconnect(_on_transforms_ready) - if not val: - modifier_stack = null - return - # Enforce uniqueness if the stack is in used by another Scatter node - if val.parent and val.parent != self: - modifier_stack = val.get_copy() - else: - modifier_stack = val - modifier_stack.parent = self - modifier_stack.value_changed.connect(rebuild, CONNECT_DEFERRED) - modifier_stack.stack_changed.connect(rebuild, CONNECT_DEFERRED) - modifier_stack.transforms_ready.connect(_on_transforms_ready, CONNECT_DEFERRED) - -var domain: ProtonScatterDomain: - set(_val): - domain = ProtonScatterDomain.new() # Enforce uniqueness - -var items: Array = [] -var total_item_proportion: int -var output_root: Marker3D -var transforms: ProtonScatterTransformList -var editor_plugin # Holds a reference to the EditorPlugin. Used by other parts. -var is_ready := false -var build_version := 0 - -# Internal variables -var _thread: Thread -var _rebuild_queued := false -var _dependency_parent -var _physics_helper: ProtonScatterPhysicsHelper -var _body_rid: RID -var _collision_shapes: Array[RID] -var _ignore_transform_notification = false -var _is_using_jolt: bool = false - - -func _ready() -> void: - if Engine.is_editor_hint() or enable_updates_in_game: - set_notify_transform(true) - child_exiting_tree.connect(_on_child_exiting_tree) - - _is_using_jolt = ProjectSettings.get_setting("physics/3d/physics_engine") == "Jolt Physics" - _perform_sanity_check() - _discover_items() - update_configuration_warnings.call_deferred() - is_ready = true - - if force_rebuild_on_load and not is_instance_valid(_dependency_parent): - full_rebuild.call_deferred() - - -func _exit_tree(): - if is_thread_running(): - modifier_stack.stop_update() - _thread.wait_to_finish() - _thread = null - - _clear_collision_data() - - -func _get_property_list() -> Array: - var list := [] - list.push_back({ - name = "modifier_stack", - type = TYPE_OBJECT, - hint_string = "ScatterModifierStack", - }) - - var chunk_usage := PROPERTY_USAGE_NO_EDITOR - var dimensions_usage := PROPERTY_USAGE_NO_EDITOR - if render_mode == 0 or render_mode == 2: - chunk_usage = PROPERTY_USAGE_DEFAULT - if use_chunks: - dimensions_usage = PROPERTY_USAGE_DEFAULT - - list.push_back({ - name = "Performance/use_chunks", - type = TYPE_BOOL, - usage = chunk_usage - }) - - list.push_back({ - name = "Performance/chunk_dimensions", - type = TYPE_VECTOR3, - usage = dimensions_usage - }) - return list - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - if items.is_empty(): - warnings.push_back("At least one ScatterItem node is required.") - - if modifier_stack and not modifier_stack.does_not_require_shapes(): - if domain and domain.is_empty(): - warnings.push_back("At least one ScatterShape node is required.") - - return warnings - - -func _notification(what): - if not is_ready: - return - match what: - NOTIFICATION_TRANSFORM_CHANGED: - if _ignore_transform_notification: - _ignore_transform_notification = false - return - _perform_sanity_check() - domain.compute_bounds() - rebuild.call_deferred() - NOTIFICATION_ENTER_WORLD: - _ignore_transform_notification = true - - -func _set(property, value): - if not Engine.is_editor_hint(): - return false - - # Workaround to detect when the node was duplicated from the editor. - if property == "transform": - _on_node_duplicated.call_deferred() - - elif property == "Performance/use_chunks": - use_chunks = value - - elif property == "Performance/chunk_dimensions": - chunk_dimensions = value - - # Backward compatibility. - # Convert the value of previous property "use_instancing" into the proper render_mode. - elif property == "use_instancing": - render_mode = 0 if value else 1 - return true - - return false - - -func _get(property): - if property == "Performance/use_chunks": - return use_chunks - - elif property == "Performance/chunk_dimensions": - return chunk_dimensions - - -func is_thread_running() -> bool: - return _thread != null and _thread.is_started() - - -# Used by some modifiers to retrieve a physics helper node -func get_physics_helper() -> ProtonScatterPhysicsHelper: - return _physics_helper - - -# Deletes what the Scatter node generated. -func clear_output() -> void: - if not output_root: - output_root = get_node_or_null("ScatterOutput") - - if output_root: - remove_child(output_root) - output_root.queue_free() - output_root = null - - ProtonScatterUtil.ensure_output_root_exists(self) - _clear_collision_data() - - -func _clear_collision_data() -> void: - if _body_rid.is_valid(): - PhysicsServer3D.free_rid(_body_rid) - _body_rid = RID() - - for rid in _collision_shapes: - if rid.is_valid(): - PhysicsServer3D.free_rid(rid) - - _collision_shapes.clear() - - -# Wrapper around the _rebuild function. Clears previous output and force -# a clean rebuild. -func full_rebuild(): - update_gizmos() - - if not is_inside_tree(): - return - - _rebuild_queued = false - - if is_thread_running(): - await _thread.wait_to_finish() - _thread = null - - clear_output() - _rebuild(true) - - -# A wrapper around the _rebuild function. Ensure it's not called more than once -# per frame. (Happens when the Scatter node is moved, which triggers the -# TRANSFORM_CHANGED notification in every children, which in turn notify the -# parent Scatter node back about the changes). -func rebuild(force_discover := false) -> void: - update_gizmos() - - if not is_inside_tree() or not is_ready: - return - - if is_thread_running(): - _rebuild_queued = true - return - - force_discover = true # TMP while we fix the other issues - _rebuild(force_discover) - - -# Re compute the desired output. -# This is the main function, scattering the objects in the scene. -# Scattered objects are stored under a Marker3D node called "ScatterOutput" -# DON'T call this function directly outside of the 'rebuild()' function above. -func _rebuild(force_discover) -> void: - if not enabled: - _clear_collision_data() - clear_output() - build_completed.emit() - return - - _perform_sanity_check() - - if force_discover: - _discover_items() - domain.discover_shapes(self) - - if items.is_empty() or (domain.is_empty() and not modifier_stack.does_not_require_shapes()): - clear_output() - push_warning("ProtonScatter warning: No items or shapes, abort") - return - - if render_mode == 1: - clear_output() # TMP, prevents raycasts in modifier to self intersect with previous output - - if keep_static_colliders: - _clear_collision_data() - - if dbg_disable_thread: - modifier_stack.start_update(self, domain) - return - - if is_thread_running(): - await _thread.wait_to_finish() - - _thread = Thread.new() - _thread.start(_rebuild_threaded, Thread.PRIORITY_NORMAL) - - -func _rebuild_threaded() -> void: - # Disable thread safety, but only after 4.1 beta 3 - if _thread.has_method("set_thread_safety_checks_enabled"): - # Calls static method on instance, otherwise it crashes in 4.0.x - @warning_ignore("static_called_on_instance") - _thread.set_thread_safety_checks_enabled(false) - - modifier_stack.start_update(self, domain.get_copy()) - - -func _discover_items() -> void: - items.clear() - total_item_proportion = 0 - - for c in get_children(): - if is_instance_of(c, ProtonScatterItem): - items.push_back(c) - total_item_proportion += c.proportion - - update_configuration_warnings() - - -# Creates one MultimeshInstance3D for each ScatterItem node. -func _update_multimeshes() -> void: - if items.is_empty(): - _discover_items() - - var offset := 0 - var transforms_count: int = transforms.size() - - for item in items: - var count = int(round(float(item.proportion) / total_item_proportion * transforms_count)) - var mmi = ProtonScatterUtil.get_or_create_multimesh(item, count) - if not mmi: - continue - var static_body := ProtonScatterUtil.get_collision_data(item) - - var t: Transform3D - for i in count: - # Extra check because of how 'count' is calculated - if (offset + i) >= transforms_count: - mmi.multimesh.instance_count = i - 1 - continue - - t = item.process_transform(transforms.list[offset + i]) - mmi.multimesh.set_instance_transform(i, t) - _create_collision(static_body, t) - - static_body.queue_free() - offset += count - - -func _update_split_multimeshes() -> void: - var size = domain.bounds_local.size - - var splits := Vector3i.ONE - splits.x = max(1, ceil(size.x / chunk_dimensions.x)) - splits.y = max(1, ceil(size.y / chunk_dimensions.y)) - splits.z = max(1, ceil(size.z / chunk_dimensions.z)) - - if items.is_empty(): - _discover_items() - - var offset := 0 # this many transforms have been used up - var transforms_count: int = transforms.size() - clear_output() - - for item in items: - var root: Node3D = ProtonScatterUtil.get_or_create_item_root(item) - if not is_instance_valid(root): - continue - - # use count number of transforms for this item - var count = int(round(float(item.proportion) / total_item_proportion * transforms_count)) - - # create 3d array with dimensions of split_size to store the chunks' transforms - var transform_chunks : Array = [] - for xi in splits.x: - transform_chunks.append([]) - for yi in splits.y: - transform_chunks[xi].append([]) - for zi in splits.z: - transform_chunks[xi][yi].append([]) - - var t_list = transforms.list.slice(offset) - var aabb = ProtonScatterUtil.get_aabb_from_transforms(t_list) - aabb = aabb.grow(0.1) # avoid degenerate cases - var static_body := ProtonScatterUtil.get_collision_data(item) - - for i in count: - if (offset + i) >= transforms_count: - continue - # both aabb and t are in mmi's local coordinates - var t = item.process_transform(transforms.list[offset + i]) - var p_rel = (t.origin - aabb.position) / aabb.size - # Chunk index - var ci = (p_rel * Vector3(splits)).floor() - # Store the transform to the appropriate array - transform_chunks[ci.x][ci.y][ci.z].append(t) - _create_collision(static_body, t) - - static_body.queue_free() - - # Cache the mesh instance to be used for the chunks - var mesh_instance: MeshInstance3D = ProtonScatterUtil.get_merged_meshes_from(item) - # The relevant transforms are now ordered in chunks - for xi in splits.x: - for yi in splits.y: - for zi in splits.z: - var chunk_elements = transform_chunks[xi][yi][zi].size() - if chunk_elements == 0: - continue - var mmi = ProtonScatterUtil.get_or_create_multimesh_chunk( - item, - mesh_instance, - Vector3i(xi, yi, zi), - chunk_elements) - if not mmi: - continue - - # Use the eventual aabb as origin - # The multimeshinstance needs to be centered where the transforms are - # This matters because otherwise the visibility range fading is messed up - var center = ProtonScatterUtil.get_aabb_from_transforms(transform_chunks[xi][yi][zi]).get_center() - mmi.transform.origin = center - - var t: Transform3D - for i in chunk_elements: - t = transform_chunks[xi][yi][zi][i] - t.origin -= center - mmi.multimesh.set_instance_transform(i, t) - mesh_instance.queue_free() - offset += count - - -func _update_duplicates() -> void: - var offset := 0 - var transforms_count: int = transforms.size() - - for item in items: - var count := int(round(float(item.proportion) / total_item_proportion * transforms_count)) - var root: Node3D = ProtonScatterUtil.get_or_create_item_root(item) - var child_count := root.get_child_count() - - for i in count: - if (offset + i) >= transforms_count: - return - - var instance - if i < child_count: # Grab an instance from the pool if there's one available - instance = root.get_child(i) - else: - instance = _create_instance(item, root) - - if not instance: - break - - var t: Transform3D = item.process_transform(transforms.list[offset + i]) - instance.transform = t - ProtonScatterUtil.set_visibility_layers(instance, item.visibility_layers) - - # Delete the unused instances left in the pool if any - if count < child_count: - for i in (child_count - count): - root.get_child(-1).queue_free() - - offset += count - - -func _update_particles_system() -> void: - var offset := 0 - var transforms_count: int = transforms.size() - - for item in items: - var count := int(round(float(item.proportion) / total_item_proportion * transforms_count)) - var particles = ProtonScatterUtil.get_or_create_particles(item) - if not particles: - continue - - particles.visibility_aabb = AABB(domain.bounds_local.min, domain.bounds_local.size) - particles.amount = count - - var static_body := ProtonScatterUtil.get_collision_data(item) - var t: Transform3D - - for i in count: - if (offset + i) >= transforms_count: - particles.amount = i - 1 - return - - t = item.process_transform(transforms.list[offset + i]) - particles.emit_particle( - t, - Vector3.ZERO, - Color.WHITE, - Color.BLACK, - GPUParticles3D.EMIT_FLAG_POSITION | GPUParticles3D.EMIT_FLAG_ROTATION_SCALE) - _create_collision(static_body, t) - - offset += count - - -# Creates collision data with the Physics server directly. -# This does not create new nodes in the scene tree. This also means you can't -# see these colliders, even when enabling "Debug > Visible collision shapes". -func _create_collision(body: StaticBody3D, t: Transform3D) -> void: - if not keep_static_colliders or render_mode == 1: - return - - # Create a static body - if not _body_rid.is_valid(): - _body_rid = PhysicsServer3D.body_create() - PhysicsServer3D.body_set_mode(_body_rid, PhysicsServer3D.BODY_MODE_STATIC) - PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, global_transform) - PhysicsServer3D.body_set_space(_body_rid, get_world_3d().space) - - for c in body.get_children(): - if c is CollisionShape3D: - var shape_rid: RID - var data: Variant - - if c.shape is SphereShape3D: - shape_rid = PhysicsServer3D.sphere_shape_create() - data = c.shape.radius - - elif c.shape is BoxShape3D: - shape_rid = PhysicsServer3D.box_shape_create() - data = c.shape.size / 2.0 - - elif c.shape is CapsuleShape3D: - shape_rid = PhysicsServer3D.capsule_shape_create() - data = { - "radius": c.shape.radius, - "height": c.shape.height, - } - - elif c.shape is CylinderShape3D: - shape_rid = PhysicsServer3D.cylinder_shape_create() - data = { - "radius": c.shape.radius, - "height": c.shape.height, - } - - elif c.shape is ConcavePolygonShape3D: - shape_rid = PhysicsServer3D.concave_polygon_shape_create() - data = { - "faces": c.shape.get_faces(), - "backface_collision": c.shape.backface_collision, - } - - elif c.shape is ConvexPolygonShape3D: - shape_rid = PhysicsServer3D.convex_polygon_shape_create() - data = c.shape.points - - elif c.shape is HeightMapShape3D: - shape_rid = PhysicsServer3D.heightmap_shape_create() - var min_height := 9999999.0 - var max_height := -9999999.0 - for v in c.shape.map_data: - min_height = v if v < min_height else min_height - max_height = v if v > max_height else max_height - data = { - "width": c.shape.map_width, - "depth": c.shape.map_depth, - "heights": c.shape.map_data, - "min_height": min_height, - "max_height": max_height, - } - - elif c.shape is SeparationRayShape3D: - shape_rid = PhysicsServer3D.separation_ray_shape_create() - data = { - "length": c.shape.length, - "slide_on_slope": c.shape.slide_on_slope, - } - - else: - print_debug("Scatter - Unsupported collision shape: ", c.shape) - continue - - PhysicsServer3D.shape_set_data(shape_rid, data) - PhysicsServer3D.body_add_shape(_body_rid, shape_rid, t * c.transform) - _collision_shapes.push_back(shape_rid) - - -func _create_instance(item: ProtonScatterItem, root: Node3D): - if not item: - return null - - var instance = item.get_item() - if not instance: - return null - - instance.visible = true - root.add_child.bind(instance, true).call_deferred() - - if show_output_in_tree: - # We have to use a lambda here because ProtonScatterUtil isn't an - # actual class_name, it's a const, which makes it impossible to reference - # the callable, (but we can still call it) - var defer_ownership := func(i, o): - ProtonScatterUtil.set_owner_recursive(i, o) - defer_ownership.bind(instance, get_tree().get_edited_scene_root()).call_deferred() - - return instance - - -# Enforce the Scatter node has its required variables set. -func _perform_sanity_check() -> void: - if not modifier_stack: - modifier_stack = ProtonScatterModifierStack.new() - modifier_stack.just_created = true - - if not domain: - domain = ProtonScatterDomain.new() - - domain.discover_shapes(self) - - if not is_instance_valid(_physics_helper): - _physics_helper = ProtonScatterPhysicsHelper.new() - _physics_helper.name = "PhysicsHelper" - add_child(_physics_helper, true, INTERNAL_MODE_BACK) - - # Retrigger the parent setter, in case the parent node no longer exists or changed type. - scatter_parent = scatter_parent - - -# Remove output coming from the source node to avoid linked multimeshes or -# other unwanted side effects -func _on_node_duplicated() -> void: - clear_output() - - -func _on_child_exiting_tree(node: Node) -> void: - if node is ProtonScatterShape or node is ProtonScatterItem: - rebuild.bind(true).call_deferred() - - -# Called when the modifier stack is done generating the full transform list -func _on_transforms_ready(new_transforms: ProtonScatterTransformList) -> void: - if is_thread_running(): - await _thread.wait_to_finish() - _thread = null - - _clear_collision_data() - - if _rebuild_queued: - _rebuild_queued = false - rebuild.call_deferred() - return - - transforms = new_transforms - - if force_uniform_scale or _is_using_jolt: - transforms.enforce_uniform_scale() - - if not transforms or transforms.is_empty(): - clear_output() - update_gizmos() - return - - match render_mode: - 0: - if use_chunks: - _update_split_multimeshes() - else: - _update_multimeshes() - 1: - _update_duplicates() - 2: - _update_particles_system() - - update_gizmos() - build_version += 1 - - if is_inside_tree(): - await get_tree().process_frame - - build_completed.emit() diff --git a/godot/addons/proton_scatter/src/scatter.gd.uid b/godot/addons/proton_scatter/src/scatter.gd.uid deleted file mode 100644 index 45960dc..0000000 --- a/godot/addons/proton_scatter/src/scatter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://kgoinj28hy1g diff --git a/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd b/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd deleted file mode 100644 index e980376..0000000 --- a/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd +++ /dev/null @@ -1,81 +0,0 @@ -@tool -extends EditorNode3DGizmoPlugin - - -# Gizmo plugin for the ProtonScatter nodes. -# -# Displays a loading animation when the node is rebuilding its output -# Also displays the domain edges if one of its modifiers is using this data. - - -const LoadingAnimation := preload("../icons/loading/m_loading.tres") - -var _loading_mesh: Mesh -var _editor_plugin: EditorPlugin - - -func _init(): - # TODO: Replace hardcoded colors by a setting fetch - create_custom_material("line", Color(0.2, 0.4, 0.8)) - add_material("loading", LoadingAnimation) - - _loading_mesh = QuadMesh.new() - _loading_mesh.set_size(Vector2.ONE * 0.15) - - -func _get_gizmo_name() -> String: - return "ProtonScatter" - - -func _has_gizmo(node) -> bool: - return node is ProtonScatter - - -func _redraw(gizmo: EditorNode3DGizmo): - gizmo.clear() - var node = gizmo.get_node_3d() - - if not node.modifier_stack: - return - - if node.is_thread_running(): - gizmo.add_mesh(_loading_mesh, get_material("loading")) - - if node.modifier_stack.is_using_edge_data() and _is_selected(node): - var curves: Array[Curve3D] = node.domain.get_edges() - - for curve in curves: - var lines := PackedVector3Array() - var points: PackedVector3Array = curve.tessellate(4, 8) - var lines_count := points.size() - 1 - - for i in lines_count: - lines.append(points[i]) - lines.append(points[i + 1]) - - gizmo.add_lines(lines, get_material("line")) - - -func set_editor_plugin(plugin: EditorPlugin) -> void: - _editor_plugin = plugin - - -# WORKAROUND -# Creates a standard material displayed on top of everything. -# Only exists because 'create_material() on_top' parameter doesn't seem to work. -func create_custom_material(name, color := Color.WHITE): - var material := StandardMaterial3D.new() - material.set_blend_mode(StandardMaterial3D.BLEND_MODE_ADD) - material.set_shading_mode(StandardMaterial3D.SHADING_MODE_UNSHADED) - material.set_flag(StandardMaterial3D.FLAG_DISABLE_DEPTH_TEST, true) - material.set_albedo(color) - material.render_priority = 100 - - add_material(name, material) - - -func _is_selected(node: Node) -> bool: - if ProjectSettings.get_setting(_editor_plugin.GIZMO_SETTING): - return true - - return node in _editor_plugin.get_custom_selection() diff --git a/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd.uid b/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd.uid deleted file mode 100644 index 1a824e8..0000000 --- a/godot/addons/proton_scatter/src/scatter_gizmo_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dpjmxts5yvq8o diff --git a/godot/addons/proton_scatter/src/scatter_item.gd b/godot/addons/proton_scatter/src/scatter_item.gd deleted file mode 100644 index d425310..0000000 --- a/godot/addons/proton_scatter/src/scatter_item.gd +++ /dev/null @@ -1,241 +0,0 @@ -@tool -class_name ProtonScatterItem -extends Node3D - - -const ScatterUtil := preload('./common/scatter_util.gd') - - -@export_category("ScatterItem") - -## Defines the relative frequency of this item in the scatter distribution. -## For example, if item A has proportion 100 and item B has proportion 50, -## item A will appear twice as often as item B in the final scattered result. -## Higher values mean more instances of this item relative to other items. -@export var proportion := 100: - set(val): - proportion = val - ScatterUtil.request_parent_to_rebuild(self) - - -## Controls where the item to be scattered comes from. -## From current scene (0): Uses a node from the current scene as the source -## From disk (1): Loads the source item from a saved scene file -## This affects how the 'path' property is interpreted - either as a NodePath -## or as a filesystem path to a scene file. -@export_enum("From current scene:0", "From disk:1") var source = 1: - set(val): - source = val - property_list_changed.emit() - -@export var custom_script: Script: - set(val): - custom_script = val - ScatterUtil.request_parent_to_rebuild(self) - -@export_group("Source options", "source_") - -## Global scale multiplier applied to the source item before scattering. -## A value of 1.0 keeps the original scale, 2.0 doubles the size, and 0.5 halves it. -## This affects all instances of this scattered item uniformly, unlike random scale -## modifiers which vary per instance. -@export var source_scale_multiplier := 1.0: - set(val): - source_scale_multiplier = val - ScatterUtil.request_parent_to_rebuild(self) - - -## If enabled, ignores the original position of the source item when scattering. -## When true, each scattered instance uses only the position determined by the scatter -## modifiers. When false, adds the source item's original position as an offset to -## each scattered instance. -@export var source_ignore_position := true: - set(val): - source_ignore_position = val - ScatterUtil.request_parent_to_rebuild(self) - - -## If enabled, ignores the original rotation of the source item when scattering. -## When true, each scattered instance uses only the rotation determined by the scatter -## modifiers. When false, adds the source item's original rotation to each scattered -## instance's rotation. -@export var source_ignore_rotation := true: - set(val): - source_ignore_rotation = val - ScatterUtil.request_parent_to_rebuild(self) - - -## If enabled, ignores the original scale of the source item when scattering. -## When true, each scattered instance uses only the scale determined by the scatter -## modifiers and scale_multiplier. When false, multiplies the source item's original -## scale with the other scale modifications. -@export var source_ignore_scale := true: - set(val): - source_ignore_scale = val - ScatterUtil.request_parent_to_rebuild(self) - - -@export_group("Override options", "override_") - -## Override the source item's original material. -## When assigned, all scattered instances will use this material instead -## of the source item's materials. -@export var override_material: Material: - set(val): - override_material = val - ScatterUtil.request_parent_to_rebuild(self) - - -## Only used when the ProtonScatter's render mode is set to "Use Particles". -## When assigned, overrides the default static particle process material. -@export var override_process_material: Material: - set(val): - override_process_material = val - ScatterUtil.request_parent_to_rebuild(self) # TODO - No need for a full rebuild here - - -## Controls the shadow casting behavior of all scattered instances. -## Overrides the original shadow casting settings from the source item. -## Uses standard Godot shadow casting options -@export var override_cast_shadow: GeometryInstance3D.ShadowCastingSetting = GeometryInstance3D.SHADOW_CASTING_SETTING_ON: - set(val): - override_cast_shadow = val - ScatterUtil.request_parent_to_rebuild(self) # TODO - Only change the multimesh flag instead - -@export_group("Visibility", "visibility") - -## Specifies which 3D render layers the scattered instances will be visible on. -## Uses the standard Godot layer system where each bit represents a layer. -## Useful for controlling which instances are visible to different cameras. -@export_flags_3d_render var visibility_layers: int = 1 - -@export var visibility_range_begin : float = 0 -@export var visibility_range_begin_margin : float = 0 -@export var visibility_range_end : float = 0 -@export var visibility_range_end_margin : float = 0 -#TODO what is a nicer way to expose this? -@export_enum("Disabled:0", "Self:1") var visibility_range_fade_mode = 0 - -@export_group("Level Of Detail", "lod_") - -## Controls whether Level of Detail (LOD) variants are generated for scattered meshes. -## When enabled, creates simplified versions of the source mesh for better performance -## at a distance. LOD generation takes more processing time during scatter operations -## but can significantly improve runtime performance with complex meshes. -@export var lod_generate := true: - set(val): - lod_generate = val - ScatterUtil.request_parent_to_rebuild(self) - - -## Determines the angle threshold at which the mesh for a single ProtonScatterItem -## will be merged with other instances to create a lower polygon count version of the mesh. -## Setting a lower lod_merge_angle value will result in more aggressive merging, reducing -## the overall number of mesh instances -@export_range(0.0, 180.0) var lod_merge_angle := 25.0: - set(val): - lod_merge_angle = val - ScatterUtil.request_parent_to_rebuild(self) - - -## determines the angle threshold at which the mesh for a single ProtonScatterItem -## will be split into a higher polygon count version of the mesh. -## generally more useful for higher polygon count models. -@export_range(0.0, 180.0) var lod_split_angle := 60.0: - set(val): - lod_split_angle = val - ScatterUtil.request_parent_to_rebuild(self) - -var path: String: - set(val): - path = val - source_data_ready = false - _target_scene = load(path) if source != 0 else null - ScatterUtil.request_parent_to_rebuild(self) - -var source_position: Vector3 -var source_rotation: Vector3 -var source_scale: Vector3 -var source_data_ready := false - -var _target_scene: PackedScene - - -func _get_property_list() -> Array: - var list := [] - - if source == 0: - list.push_back({ - name = "path", - type = TYPE_NODE_PATH, - }) - else: - list.push_back({ - name = "path", - type = TYPE_STRING, - hint = PROPERTY_HINT_FILE, - }) - - return list - - -func get_item() -> Node3D: - if path.is_empty(): - return null - - var node: Node3D - - if source == 0 and has_node(path): - node = get_node(path).duplicate() # Never expose the original node - elif source == 1: - node = _target_scene.instantiate() - - if node: - _save_source_data(node) - return node - - return null - - -# Takes a transform in input, scale it based on the local scale multiplier -# If the source transform is not ignored, also copy the source position, rotation and scale. -# Returns the processed transform -func process_transform(t: Transform3D) -> Transform3D: - if not source_data_ready: - _update_source_data() - - var origin = t.origin - t.origin = Vector3.ZERO - - t = t.scaled(Vector3.ONE * source_scale_multiplier) - - if not source_ignore_scale: - t = t.scaled(source_scale) - - if not source_ignore_rotation: - t = t.rotated(t.basis.x.normalized(), source_rotation.x) - t = t.rotated(t.basis.y.normalized(), source_rotation.y) - t = t.rotated(t.basis.z.normalized(), source_rotation.z) - - t.origin = origin - - if not source_ignore_position: - t.origin += source_position - - return t - - -func _save_source_data(node: Node3D) -> void: - if not node: - return - - source_position = node.position - source_rotation = node.rotation - source_scale = node.scale - source_data_ready = true - - -func _update_source_data() -> void: - var node = get_item() - if node: - node.queue_free() diff --git a/godot/addons/proton_scatter/src/scatter_item.gd.uid b/godot/addons/proton_scatter/src/scatter_item.gd.uid deleted file mode 100644 index f858a01..0000000 --- a/godot/addons/proton_scatter/src/scatter_item.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ckdm33s6l3m64 diff --git a/godot/addons/proton_scatter/src/scatter_shape.gd b/godot/addons/proton_scatter/src/scatter_shape.gd deleted file mode 100644 index a09d03d..0000000 --- a/godot/addons/proton_scatter/src/scatter_shape.gd +++ /dev/null @@ -1,74 +0,0 @@ -@tool -class_name ProtonScatterShape -extends Node3D - - -const ScatterUtil := preload('./common/scatter_util.gd') - - -@export_category("ScatterShape") - -## Determines whether the ScatterShape is used as an exclusion or inclusion zone. -## This can be useful for creating holes, gaps, or non-uniform distributions within -## the overall scatter area. -@export var negative = false: - set(val): - negative = val - update_gizmos() - ScatterUtil.request_parent_to_rebuild(self) - - -## The shape determines the boundaries and geometry that will be used to place -## the transforms generated by the ProtonScatter node. -## When the shape is changed, the `changed` signal is emitted, which triggers -## a rebuild of the scatter output. -@export var shape: ProtonScatterBaseShape: - set(val): - # Disconnect the previous shape if any - if shape and shape.changed.is_connected(_on_shape_changed): - shape.changed.disconnect(_on_shape_changed) - - shape = val - if shape: - shape.changed.connect(_on_shape_changed) - - update_gizmos() - ScatterUtil.request_parent_to_rebuild(self) - -var _ignore_transform_notification = false - - -func _ready() -> void: - set_notify_transform(true) - - -func _notification(what): - match what: - NOTIFICATION_TRANSFORM_CHANGED: - if _ignore_transform_notification: - _ignore_transform_notification = false - return - ScatterUtil.request_parent_to_rebuild(self) - - NOTIFICATION_ENTER_WORLD: - _ignore_transform_notification = true - - -func _set(property, _value): - if not Engine.is_editor_hint(): - return false - - # Workaround to detect when the node was duplicated from the editor. - if property == "transform": - _on_node_duplicated.call_deferred() - - return false - - -func _on_shape_changed() -> void: - update_gizmos() - ScatterUtil.request_parent_to_rebuild(self) - - -func _on_node_duplicated() -> void: - shape = shape.get_copy() # Enfore uniqueness on duplicate, could be an option diff --git a/godot/addons/proton_scatter/src/scatter_shape.gd.uid b/godot/addons/proton_scatter/src/scatter_shape.gd.uid deleted file mode 100644 index f53fc28..0000000 --- a/godot/addons/proton_scatter/src/scatter_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c6e8kc1f5s4qp diff --git a/godot/addons/proton_scatter/src/shapes/base_shape.gd b/godot/addons/proton_scatter/src/shapes/base_shape.gd deleted file mode 100644 index 0682e6e..0000000 --- a/godot/addons/proton_scatter/src/shapes/base_shape.gd +++ /dev/null @@ -1,36 +0,0 @@ -@tool -class_name ProtonScatterBaseShape -extends Resource - - -func is_point_inside_global(_point_global: Vector3, _global_transform: Transform3D) -> bool: - return false - - -func is_point_inside_local(_point_local: Vector3) -> bool: - return false - - -# Returns an array of Vector3. This should contain enough points to compute -# a bounding box for the given shape. -func get_corners_global(_shape_global_transform: Transform3D) -> Array[Vector3]: - return [] - - -# Returns the closed contour of the shape (closed, inner and outer if -# applicable) as a 2D polygon, in local space relative to the scatter node. -func get_closed_edges(_shape_t: Transform3D) -> Array[PackedVector2Array]: - return [] - - -# Returns the open edges (in the case of a regular path, not closed) -# in local space relative to the scatter node. -func get_open_edges(_shape_t: Transform3D) -> Array[Curve3D]: - return [] - - -# Returns a copy of this shape. -# TODO: check later when Godot4 enters beta if we can get rid of this and use -# the built-in duplicate() method properly. -func get_copy() -> Resource: - return null diff --git a/godot/addons/proton_scatter/src/shapes/base_shape.gd.uid b/godot/addons/proton_scatter/src/shapes/base_shape.gd.uid deleted file mode 100644 index 51365ee..0000000 --- a/godot/addons/proton_scatter/src/shapes/base_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://t6lxtl5i52hn diff --git a/godot/addons/proton_scatter/src/shapes/box_shape.gd b/godot/addons/proton_scatter/src/shapes/box_shape.gd deleted file mode 100644 index d1cc531..0000000 --- a/godot/addons/proton_scatter/src/shapes/box_shape.gd +++ /dev/null @@ -1,95 +0,0 @@ -@tool -class_name ProtonScatterBoxShape -extends ProtonScatterBaseShape - - -@export var size := Vector3.ONE: - set(val): - size = val - _half_size = size * 0.5 - emit_changed() - -var _half_size := Vector3.ONE - - -func get_copy(): - var copy = get_script().new() - copy.size = size - return copy - - -func is_point_inside(point: Vector3, global_transform: Transform3D) -> bool: - var local_point = global_transform.affine_inverse() * point - return AABB(-_half_size, size).has_point(local_point) - - -func get_corners_global(gt: Transform3D) -> Array: - var res := [] - var corners := [ - Vector3(-1, -1, -1), - Vector3(-1, -1, 1), - Vector3(1, -1, 1), - Vector3(1, -1, -1), - Vector3(-1, 1, -1), - Vector3(-1, 1, 1), - Vector3(1, 1, 1), - Vector3(1, 1, -1), - ] - - for c in corners: - c *= size * 0.5 - res.push_back(gt * c) - - return res - - -# Intersection between and box and a plane results in a polygon between 3 and 6 -# vertices. -# Compute the intersection of each of the 12 edges to the plane, then recompute -# the polygon from the positions found. -func get_closed_edges(shape_t: Transform3D) -> Array[PackedVector2Array]: - var polygon := PackedVector2Array() - - var plane := Plane(Vector3.UP, 0.0) - - var box_edges := [ - # Bottom square - [Vector3(-1, -1, -1), Vector3(-1, -1, 1)], - [Vector3(-1, -1, 1), Vector3(1, -1, 1)], - [Vector3(1, -1, 1), Vector3(1, -1, -1)], - [Vector3(1, -1, -1), Vector3(-1, -1, -1)], - - # Top square - [Vector3(-1, 1, -1), Vector3(-1, 1, 1)], - [Vector3(-1, 1, 1), Vector3(1, 1, 1)], - [Vector3(1, 1, 1), Vector3(1, 1, -1)], - [Vector3(1, 1, -1), Vector3(-1, 1, -1)], - - # Vertical lines - [Vector3(-1, -1, -1), Vector3(-1, 1, -1)], - [Vector3(-1, -1, 1), Vector3(-1, 1, 1)], - [Vector3(1, -1, 1), Vector3(1, 1, 1)], - [Vector3(1, -1, -1), Vector3(1, 1, -1)], - ] - - var intersection_points := PackedVector3Array() - var point - var shape_t_inverse := shape_t.affine_inverse() - - for edge in box_edges: - var p1 = (edge[0] * _half_size) * shape_t_inverse - var p2 = (edge[1] * _half_size) * shape_t_inverse - point = plane.intersects_segment(p1, p2) - if point: - intersection_points.push_back(point) - - if intersection_points.size() < 3: - return [] - - var points_unordered := PackedVector2Array() - for p in intersection_points: - points_unordered.push_back(Vector2(p.x, p.z)) - - polygon = Geometry2D.convex_hull(points_unordered) - - return [polygon] diff --git a/godot/addons/proton_scatter/src/shapes/box_shape.gd.uid b/godot/addons/proton_scatter/src/shapes/box_shape.gd.uid deleted file mode 100644 index 2fcdea7..0000000 --- a/godot/addons/proton_scatter/src/shapes/box_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dpg0l2ao6xptu diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd deleted file mode 100644 index 504894f..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd +++ /dev/null @@ -1,135 +0,0 @@ -@tool -extends "gizmo_handler.gd" - -# 3D Gizmo for the Box shape. - - -func get_handle_name(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> String: - return "Box Size" - - -func get_handle_value(gizmo: EditorNode3DGizmo, handle_id: int, _secondary: bool) -> Variant: - return gizmo.get_node_3d().shape.size - - -func set_handle(gizmo: EditorNode3DGizmo, handle_id: int, _secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void: - if handle_id < 0 or handle_id > 2: - return - - var axis := Vector3.ZERO - axis[handle_id] = 1.0 # handle 0:x, 1:y, 2:z - - var shape_node = gizmo.get_node_3d() - var gt := shape_node.get_global_transform() - var gt_inverse := gt.affine_inverse() - - var origin := gt.origin - var drag_axis := (axis * 4096) * gt_inverse - var ray_from = camera.project_ray_origin(screen_pos) - var ray_to = ray_from + camera.project_ray_normal(screen_pos) * 4096 - - var points = Geometry3D.get_closest_points_between_segments(origin, drag_axis, ray_from, ray_to) - - var size = shape_node.shape.size - size -= axis * size - var dist = origin.distance_to(points[0]) * 2.0 - size += axis * dist - - shape_node.shape.size = size - - -func commit_handle(gizmo: EditorNode3DGizmo, handle_id: int, _secondary: bool, restore: Variant, cancel: bool) -> void: - var shape: ProtonScatterBoxShape = gizmo.get_node_3d().shape - if cancel: - shape.size = restore - return - - _undo_redo.create_action("Set ScatterShape size") - _undo_redo.add_undo_method(self, "_set_size", shape, restore) - _undo_redo.add_do_method(self, "_set_size", shape, shape.size) - _undo_redo.commit_action() - - -func redraw(plugin: EditorNode3DGizmoPlugin, gizmo: EditorNode3DGizmo): - gizmo.clear() - var scatter_shape = gizmo.get_node_3d() - var shape: ProtonScatterBoxShape = scatter_shape.shape - - ### Draw the Box lines - var lines = PackedVector3Array() - var lines_material := plugin.get_material("primary_top", gizmo) - var half_size = shape.size * 0.5 - - var corners := [ - [ # Bottom square - Vector3(-1, -1, -1), - Vector3(-1, -1, 1), - Vector3(1, -1, 1), - Vector3(1, -1, -1), - Vector3(-1, -1, -1), - ], - [ # Top square - Vector3(-1, 1, -1), - Vector3(-1, 1, 1), - Vector3(1, 1, 1), - Vector3(1, 1, -1), - Vector3(-1, 1, -1), - ], - [ # Vertical lines - Vector3(-1, -1, -1), - Vector3(-1, 1, -1), - ], - [ - Vector3(-1, -1, 1), - Vector3(-1, 1, 1), - ], - [ - Vector3(1, -1, 1), - Vector3(1, 1, 1), - ], - [ - Vector3(1, -1, -1), - Vector3(1, 1, -1), - ] - ] - - var block_count = corners.size() - if not is_selected(gizmo): - block_count = 1 - - for i in block_count: - var block = corners[i] - for j in block.size() - 1: - lines.push_back(block[j] * half_size) - lines.push_back(block[j + 1] * half_size) - - gizmo.add_lines(lines, lines_material) - gizmo.add_collision_segments(lines) - - ### Fills the box inside - var mesh = BoxMesh.new() - mesh.size = shape.size - - var mesh_material: StandardMaterial3D - if scatter_shape.negative: - mesh_material = plugin.get_material("exclusive", gizmo) - else: - mesh_material = plugin.get_material("inclusive", gizmo) - - gizmo.add_mesh(mesh, mesh_material) - - ### Draw the handles, one for each axis - var handles := PackedVector3Array() - var handles_ids := PackedInt32Array() - var handles_material := plugin.get_material("default_handle", gizmo) - - handles.push_back(Vector3.RIGHT * shape.size.x * 0.5) - handles.push_back(Vector3.UP * shape.size.y * 0.5) - handles.push_back(Vector3.BACK * shape.size.z * 0.5) - - gizmo.add_handles(handles, handles_material, handles_ids) - - -func _set_size(box: ProtonScatterBoxShape, size: Vector3) -> void: - if box: - box.size = size diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd.uid deleted file mode 100644 index bb37e61..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/box_gizmo.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cu5hqy8b2a4k3 diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/curve_mode_button_group.tres b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/curve_mode_button_group.tres deleted file mode 100644 index f8a67d2..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/curve_mode_button_group.tres +++ /dev/null @@ -1,3 +0,0 @@ -[gd_resource type="ButtonGroup" format=3 uid="uid://1xy55037k3k5"] - -[resource] diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_advanced_options_panel.tscn b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_advanced_options_panel.tscn deleted file mode 100644 index c5a44f0..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_advanced_options_panel.tscn +++ /dev/null @@ -1,55 +0,0 @@ -[gd_scene format=3 uid="uid://qb8j7oasuqbc"] - -[node name="AdvancedOptionsPanel" type="MarginContainer"] -offset_right = 221.0 -offset_bottom = 136.0 -grow_horizontal = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -metadata/_edit_use_custom_anchors = true - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -offset_right = 221.0 -offset_bottom = 136.0 - -[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] -offset_right = 217.0 -offset_bottom = 136.0 - -[node name="MirrorLength" type="CheckButton" parent="HBoxContainer/VBoxContainer"] -offset_right = 217.0 -offset_bottom = 31.0 -focus_mode = 0 -text = "Mirror handles length" - -[node name="MirrorAngle" type="CheckButton" parent="HBoxContainer/VBoxContainer"] -offset_top = 35.0 -offset_right = 217.0 -offset_bottom = 66.0 -focus_mode = 0 -text = "Mirror handles angle" - -[node name="LockToPlane" type="CheckButton" parent="HBoxContainer/VBoxContainer"] -offset_top = 70.0 -offset_right = 217.0 -offset_bottom = 101.0 -focus_mode = 0 -text = "Lock to plane" - -[node name="MirrorAngle3" type="CheckButton" parent="HBoxContainer/VBoxContainer"] -offset_top = 105.0 -offset_right = 217.0 -offset_bottom = 136.0 -focus_mode = 0 -text = "Snap to colliders" - -[node name="VSeparator" type="VSeparator" parent="HBoxContainer"] -visible = false -offset_left = 221.0 -offset_right = 225.0 -offset_bottom = 136.0 - -[node name="VBoxContainer2" type="VBoxContainer" parent="HBoxContainer"] -offset_left = 221.0 -offset_right = 221.0 -offset_bottom = 136.0 diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd deleted file mode 100644 index 9d0b735..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd +++ /dev/null @@ -1,96 +0,0 @@ -@tool -extends Control - - -const ScatterShape = preload("../../../scatter_shape.gd") -const PathShape = preload("../../path_shape.gd") - -var shape_node: ScatterShape - -@onready var _options_button: Button = $%Options -@onready var _options_panel: Popup = $%OptionsPanel - - -func _ready() -> void: - _options_button.toggled.connect(_on_options_button_toggled) - _options_panel.popup_hide.connect(_on_options_panel_hide) - $%SnapToColliders.toggled.connect(_on_snap_to_colliders_toggled) - $%ClosedPath.toggled.connect(_on_closed_path_toggled) - $%MirrorAngle.toggled.connect(_on_mirror_angle_toggled) - - for button in [$%LockToPlane, $%SnapToColliders, $%ClosedPath]: - button.pressed.connect(_on_button_pressed) - - -# Called by the editor plugin when the node selection changes. -# Hides the panel when the selected node is not a path shape. -func selection_changed(selected: Array) -> void: - if selected.is_empty(): - visible = false - shape_node = null - return - - var node = selected[0] - visible = node is ScatterShape and node.shape is PathShape - if visible: - shape_node = node - $%ClosedPath.button_pressed = node.shape.closed - - -func is_select_mode_enabled() -> bool: - return $%Select.button_pressed - - -func is_create_mode_enabled() -> bool: - return $%Create.button_pressed - - -func is_delete_mode_enabled() -> bool: - return $%Delete.button_pressed - - -func is_lock_to_plane_enabled() -> bool: - return $%LockToPlane.button_pressed and not is_snap_to_colliders_enabled() - - -func is_snap_to_colliders_enabled() -> bool: - return $%SnapToColliders.button_pressed - - -func is_mirror_length_enabled() -> bool: - return $%MirrorLength.button_pressed - - -func is_mirror_angle_enabled() -> bool: - return $%MirrorAngle.button_pressed - - -func _on_options_button_toggled(enabled: bool) -> void: - if enabled: - var popup_position := Vector2i(get_global_transform().origin) - popup_position.y += size.y + 12 - _options_panel.popup(Rect2i(popup_position, Vector2i.ZERO)) - else: - _options_panel.hide() - - -func _on_options_panel_hide() -> void: - _options_button.button_pressed = false - - -func _on_mirror_angle_toggled(enabled: bool) -> void: - $%MirrorLength.disabled = not enabled - - -func _on_snap_to_colliders_toggled(enabled: bool) -> void: - $%LockToPlane.disabled = enabled - - -func _on_closed_path_toggled(enabled: bool) -> void: - if shape_node and shape_node.shape is PathShape: - shape_node.shape.closed = enabled - - -func _on_button_pressed() -> void: - if shape_node: - shape_node.update_gizmos() diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd.uid deleted file mode 100644 index c42b197..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cu0v5p26eowkw diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.tscn b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.tscn deleted file mode 100644 index 98f4cc8..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.tscn +++ /dev/null @@ -1,124 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://vijpujrvtyin"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/gizmos_plugin/components/path_panel.gd" id="1_o7kkg"] -[ext_resource type="Texture2D" uid="uid://c1t5x34pc4vs5" path="res://addons/proton_scatter/icons/curve_select.svg" id="2_d7o1n"] -[ext_resource type="ButtonGroup" uid="uid://1xy55037k3k5" path="res://addons/proton_scatter/src/shapes/gizmos_plugin/components/curve_mode_button_group.tres" id="2_sl6yo"] -[ext_resource type="Texture2D" uid="uid://cmykha5ja17vj" path="res://addons/proton_scatter/icons/curve_create.svg" id="3_l70sn"] -[ext_resource type="Texture2D" uid="uid://cligdljx1ad5e" path="res://addons/proton_scatter/icons/curve_delete.svg" id="4_b5yum"] -[ext_resource type="Texture2D" uid="uid://n66mufjib4ds" path="res://addons/proton_scatter/icons/menu.svg" id="6_xiaj2"] - -[node name="PathPanel" type="MarginContainer"] -offset_right = 108.0 -offset_bottom = 24.0 -size_flags_horizontal = 0 -size_flags_vertical = 4 -script = ExtResource("1_o7kkg") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 - -[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 - -[node name="Select" type="Button" parent="HBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -toggle_mode = true -button_pressed = true -button_group = ExtResource("2_sl6yo") -icon = ExtResource("2_d7o1n") -flat = true -icon_alignment = 1 - -[node name="Create" type="Button" parent="HBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -toggle_mode = true -button_group = ExtResource("2_sl6yo") -icon = ExtResource("3_l70sn") -flat = true -icon_alignment = 1 - -[node name="Delete" type="Button" parent="HBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -toggle_mode = true -button_group = ExtResource("2_sl6yo") -icon = ExtResource("4_b5yum") -flat = true -icon_alignment = 1 - -[node name="Options" type="Button" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -toggle_mode = true -action_mode = 0 -icon = ExtResource("6_xiaj2") -flat = true -icon_alignment = 1 - -[node name="OptionsPanel" type="PopupPanel" parent="."] -unique_name_in_owner = true -size = Vector2i(229, 179) - -[node name="AdvancedOptionsPanel" type="MarginContainer" parent="OptionsPanel"] -offset_left = 4.0 -offset_top = 4.0 -offset_right = 225.0 -offset_bottom = 175.0 -grow_horizontal = 2 -size_flags_horizontal = 4 -size_flags_vertical = 4 -metadata/_edit_use_custom_anchors = true - -[node name="HBoxContainer" type="HBoxContainer" parent="OptionsPanel/AdvancedOptionsPanel"] -layout_mode = 2 - -[node name="VBoxContainer" type="VBoxContainer" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer"] -layout_mode = 2 - -[node name="MirrorAngle" type="CheckButton" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -button_pressed = true -text = "Mirror handles angle" - -[node name="MirrorLength" type="CheckButton" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -button_pressed = true -text = "Mirror handles length" - -[node name="ClosedPath" type="CheckButton" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -text = "Closed path" - -[node name="LockToPlane" type="CheckButton" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -button_pressed = true -text = "Lock to plane" - -[node name="SnapToColliders" type="CheckButton" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -focus_mode = 0 -text = "Snap to colliders" - -[node name="VSeparator" type="VSeparator" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer"] -visible = false -layout_mode = 2 - -[node name="VBoxContainer2" type="VBoxContainer" parent="OptionsPanel/AdvancedOptionsPanel/HBoxContainer"] -layout_mode = 2 diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd deleted file mode 100644 index 26e0baf..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd +++ /dev/null @@ -1,50 +0,0 @@ -@tool -extends RefCounted - -# Abstract class. - - -var _undo_redo: EditorUndoRedoManager -var _plugin: EditorPlugin - - -func set_undo_redo(ur: EditorUndoRedoManager) -> void: - _undo_redo = ur - - -func set_editor_plugin(plugin: EditorPlugin) -> void: - _plugin = plugin - - -func get_handle_name(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> String: - return "" - - -func get_handle_value(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> Variant: - return null - - -func set_handle(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool, _camera: Camera3D, _screen_pos: Vector2) -> void: - pass - - -func commit_handle(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool, _restore: Variant, _cancel: bool) -> void: - pass - - -func redraw(_gizmo_plugin: EditorNode3DGizmoPlugin, _gizmo: EditorNode3DGizmo): - pass - - -func forward_3d_gui_input(_viewport_camera: Camera3D, _event: InputEvent) -> bool: - return false - - -func is_selected(gizmo: EditorNode3DGizmo) -> bool: - if not _plugin: - return true - - var current_node = gizmo.get_node_3d() - var selected_nodes := _plugin.get_editor_interface().get_selection().get_selected_nodes() - - return current_node in selected_nodes diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd.uid deleted file mode 100644 index c5612e1..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/gizmo_handler.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cxxw8cj4yq4j1 diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg deleted file mode 100644 index d4bd434..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg.import b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg.import deleted file mode 100644 index 2c079f2..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dmjp2vpqp4qjy" -path.s3tc="res://.godot/imported/main_handle.svg-e76638c615070e68035d2b711214a1fc.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/src/shapes/gizmos_plugin/icons/main_handle.svg" -dest_files=["res://.godot/imported/main_handle.svg-e76638c615070e68035d2b711214a1fc.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg deleted file mode 100644 index 1bdf32d..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg.import b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg.import deleted file mode 100644 index c7e81c0..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://kygbxbbnqkdh" -path.s3tc="res://.godot/imported/secondary_handle.svg-d46e6e295afbc9a7509025fe11144dfd.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/proton_scatter/src/shapes/gizmos_plugin/icons/secondary_handle.svg" -dest_files=["res://.godot/imported/secondary_handle.svg-d46e6e295afbc9a7509025fe11144dfd.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd deleted file mode 100644 index 0b5a6ae..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd +++ /dev/null @@ -1,354 +0,0 @@ -@tool -extends "gizmo_handler.gd" - - -const ProtonScatterEventHelper := preload("res://addons/proton_scatter/src/common/event_helper.gd") -const PathPanel := preload("./components/path_panel.gd") - -var _gizmo_panel: PathPanel -var _event_helper: ProtonScatterEventHelper - - -func get_handle_name(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> String: - return "Path point" - - -func get_handle_value(gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> Variant: - var shape: ProtonScatterPathShape = gizmo.get_node_3d().shape - return shape.get_copy() - - -func set_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void: - if not _gizmo_panel.is_select_mode_enabled(): - return - - var shape_node: ProtonScatterShape = gizmo.get_node_3d() - var curve: Curve3D = shape_node.shape.curve - var point_count: int = curve.get_point_count() - var curve_index := handle_id - var previous_handle_position: Vector3 - - if not secondary: - previous_handle_position = curve.get_point_position(curve_index) - else: - curve_index = int(handle_id / 2) - previous_handle_position = curve.get_point_position(curve_index) - if handle_id % 2 == 0: - previous_handle_position += curve.get_point_in(curve_index) - else: - previous_handle_position += curve.get_point_out(curve_index) - - var click_world_position := _intersect_with(shape_node, camera, screen_pos, previous_handle_position) - var point_local_position: Vector3 = shape_node.get_global_transform().affine_inverse() * click_world_position - - if not secondary: - # Main curve point moved - curve.set_point_position(handle_id, point_local_position) - else: - # In out handle moved - var mirror_angle := _gizmo_panel.is_mirror_angle_enabled() - var mirror_length := _gizmo_panel.is_mirror_length_enabled() - - var point_origin = curve.get_point_position(curve_index) - var in_out_position = point_local_position - point_origin - var mirror_position = -in_out_position - - if handle_id % 2 == 0: - curve.set_point_in(curve_index, in_out_position) - if mirror_angle: - if not mirror_length: - mirror_position = curve.get_point_out(curve_index).length() * -in_out_position.normalized() - curve.set_point_out(curve_index, mirror_position) - else: - curve.set_point_out(curve_index, in_out_position) - if mirror_angle: - if not mirror_length: - mirror_position = curve.get_point_in(curve_index).length() * -in_out_position.normalized() - curve.set_point_in(curve_index, mirror_position) - - shape_node.update_gizmos() - - -func commit_handle(gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool, restore: Variant, cancel: bool) -> void: - var shape_node: ProtonScatterShape = gizmo.get_node_3d() - - if cancel: - _edit_path(shape_node, restore) - else: - _undo_redo.create_action("Edit ScatterShape Path") - _undo_redo.add_undo_method(self, "_edit_path", shape_node, restore) - _undo_redo.add_do_method(self, "_edit_path", shape_node, shape_node.shape.get_copy()) - _undo_redo.commit_action() - - shape_node.update_gizmos() - - -func redraw(plugin: EditorNode3DGizmoPlugin, gizmo: EditorNode3DGizmo): - gizmo.clear() - - # Force the path panel to appear when the scatter shape type is changed - # from the inspector. - if is_selected(gizmo): - _gizmo_panel.selection_changed([gizmo.get_node_3d()]) - - var shape_node: ProtonScatterShape = gizmo.get_node_3d() - var shape: ProtonScatterPathShape = shape_node.shape - - if not shape: - return - - var curve: Curve3D = shape.curve - if not curve or curve.get_point_count() == 0: - return - - # ------ Common stuff ------ - var points := curve.tessellate(4, 8) - var points_2d := PackedVector2Array() - for p in points: - points_2d.push_back(Vector2(p.x, p.z)) - - var line_material: StandardMaterial3D = plugin.get_material("primary_top", gizmo) - var mesh_material: StandardMaterial3D = plugin.get_material("inclusive", gizmo) - if shape_node.negative: - mesh_material = plugin.get_material("exclusive", gizmo) - - # ------ Main line along the path curve ------ - var lines := PackedVector3Array() - var lines_count := points.size() - 1 - - for i in lines_count: - lines.append(points[i]) - lines.append(points[i + 1]) - - gizmo.add_lines(lines, line_material) - gizmo.add_collision_segments(lines) - - # ------ Draw handles ------ - var main_handles := PackedVector3Array() - var in_out_handles := PackedVector3Array() - var handle_lines := PackedVector3Array() - var ids := PackedInt32Array() # Stays empty on purpose - - for i in curve.get_point_count(): - var point_pos = curve.get_point_position(i) - var point_in = curve.get_point_in(i) + point_pos - var point_out = curve.get_point_out(i) + point_pos - - handle_lines.push_back(point_pos) - handle_lines.push_back(point_in) - handle_lines.push_back(point_pos) - handle_lines.push_back(point_out) - - in_out_handles.push_back(point_in) - in_out_handles.push_back(point_out) - main_handles.push_back(point_pos) - - gizmo.add_handles(main_handles, plugin.get_material("primary_handle", gizmo), ids) - gizmo.add_handles(in_out_handles, plugin.get_material("secondary_handle", gizmo), ids, false, true) - - if is_selected(gizmo): - gizmo.add_lines(handle_lines, plugin.get_material("secondary_top", gizmo)) - - # -------- Visual when lock to plane is enabled -------- - if _gizmo_panel.is_lock_to_plane_enabled() and is_selected(gizmo): - var bounds = shape.get_bounds() - var aabb = AABB(bounds.min, bounds.size).grow(shape.thickness / 2.0) - - var width: float = aabb.size.x - var length: float = aabb.size.z - var plane_center: Vector3 = bounds.center - plane_center.y = 0.0 - - var plane_mesh := PlaneMesh.new() - plane_mesh.set_size(Vector2(width, length)) - plane_mesh.set_center_offset(plane_center) - - gizmo.add_mesh(plane_mesh, plugin.get_material("tertiary", gizmo)) - - var plane_lines := PackedVector3Array() - var corners = [ - Vector3(-width, 0, -length), - Vector3(-width, 0, length), - Vector3(width, 0, length), - Vector3(width, 0, -length), - Vector3(-width, 0, -length), - ] - for i in corners.size() - 1: - plane_lines.push_back(corners[i] * 0.5 + plane_center) - plane_lines.push_back(corners[i + 1] * 0.5 + plane_center) - - gizmo.add_lines(plane_lines, plugin.get_material("secondary_top", gizmo)) - - # ----- Mesh representing the inside part of the path ----- - if shape.closed: - var indices = Geometry2D.triangulate_polygon(points_2d) - if indices.is_empty(): - indices = Geometry2D.triangulate_delaunay(points_2d) - - var st = SurfaceTool.new() - st.begin(Mesh.PRIMITIVE_TRIANGLES) - for index in indices: - var p = points_2d[index] - st.add_vertex(Vector3(p.x, 0.0, p.y)) - - var mesh = st.commit() - gizmo.add_mesh(mesh, mesh_material) - - # ------ Mesh representing path thickness ------ - if shape.thickness > 0 and points.size() > 1: - - # ____ TODO ____ : check if this whole section could be replaced by - # Geometry2D.expand_polyline, or an extruded capsule along the path - - ## Main path mesh - var st = SurfaceTool.new() - st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) - - for i in points.size() - 1: - var p1: Vector3 = points[i] - var p2: Vector3 = points[i + 1] - - var normal = (p2 - p1).cross(Vector3.UP).normalized() - var offset = normal * shape.thickness * 0.5 - - st.add_vertex(p1 - offset) - st.add_vertex(p1 + offset) - - ## Add the last missing two triangles from the loop above - var p1: Vector3 = points[-1] - var p2: Vector3 = points[-2] - var normal = (p1 - p2).cross(Vector3.UP).normalized() - var offset = normal * shape.thickness * 0.5 - - st.add_vertex(p1 - offset) - st.add_vertex(p1 + offset) - - var mesh := st.commit() - gizmo.add_mesh(mesh, mesh_material) - - ## Rounded cap (start) - st.begin(Mesh.PRIMITIVE_TRIANGLES) - var center = points[0] - var next = points[1] - normal = (center - next).cross(Vector3.UP).normalized() - - for i in 12: - st.add_vertex(center) - st.add_vertex(center + normal * shape.thickness * 0.5) - normal = normal.rotated(Vector3.UP, PI / 12) - st.add_vertex(center + normal * shape.thickness * 0.5) - - mesh = st.commit() - gizmo.add_mesh(mesh, mesh_material) - - ## Rounded cap (end) - st.begin(Mesh.PRIMITIVE_TRIANGLES) - center = points[-1] - next = points[-2] - normal = (next - center).cross(Vector3.UP).normalized() - - for i in 12: - st.add_vertex(center) - st.add_vertex(center + normal * shape.thickness * 0.5) - normal = normal.rotated(Vector3.UP, -PI / 12) - st.add_vertex(center + normal * shape.thickness * 0.5) - - mesh = st.commit() - gizmo.add_mesh(mesh, mesh_material) - - -func forward_3d_gui_input(viewport_camera: Camera3D, event: InputEvent) -> bool: - if not _event_helper: - _event_helper = ProtonScatterEventHelper.new() - - _event_helper.feed(event) - - if not event is InputEventMouseButton: - return false - - if not _event_helper.is_key_just_pressed(MOUSE_BUTTON_LEFT): # Can't use just_released here - return false - - var shape_node: ProtonScatterShape = _gizmo_panel.shape_node - if not shape_node: - return false - - if not shape_node.shape or not shape_node.shape is ProtonScatterPathShape: - return false - - var shape: ProtonScatterPathShape = shape_node.shape - - # In select mode, the set_handle and commit_handle functions take over. - if _gizmo_panel.is_select_mode_enabled(): - return false - - var click_world_position := _intersect_with(shape_node, viewport_camera, event.position) - var point_local_position: Vector3 = shape_node.get_global_transform().affine_inverse() * click_world_position - - if _gizmo_panel.is_create_mode_enabled(): - shape.create_point(point_local_position) # TODO: add undo redo - shape_node.update_gizmos() - return true - - elif _gizmo_panel.is_delete_mode_enabled(): - var index = shape.get_closest_to(point_local_position) - if index != -1: - shape.remove_point(index) # TODO: add undo redo - shape_node.update_gizmos() - return true - - return false - - -func set_gizmo_panel(panel: PathPanel) -> void: - _gizmo_panel = panel - - -func _edit_path(shape_node: ProtonScatterShape, restore: ProtonScatterPathShape) -> void: - shape_node.shape.curve = restore.curve.duplicate() - shape_node.shape.thickness = restore.thickness - shape_node.update_gizmos() - - -func _intersect_with(path: ProtonScatterShape, camera: Camera3D, screen_point: Vector2, handle_position_local = null) -> Vector3: - # Get the ray data - var from = camera.project_ray_origin(screen_point) - var dir = camera.project_ray_normal(screen_point) - var gt = path.get_global_transform() - - # Snap to collider enabled - if _gizmo_panel.is_snap_to_colliders_enabled(): - var space_state: PhysicsDirectSpaceState3D = path.get_world_3d().get_direct_space_state() - var parameters := PhysicsRayQueryParameters3D.new() - parameters.from = from - parameters.to = from + (dir * 2048) - var hit := space_state.intersect_ray(parameters) - if not hit.is_empty(): - return hit.position - - # Lock to plane enabled - if _gizmo_panel.is_lock_to_plane_enabled(): - var t = Transform3D(gt) - var a = t.basis.x - var b = t.basis.z - var c = a + b - var o = t.origin - var plane = Plane(a + o, b + o, c + o) - var result = plane.intersects_ray(from, dir) - if result != null: - return result - - # Default case (similar to the built in Path3D node) - var origin: Vector3 - if handle_position_local: - origin = gt * handle_position_local - else: - origin = path.get_global_transform().origin - - var plane = Plane(dir, origin) - var res = plane.intersects_ray(from, dir) - if res != null: - return res - - return origin - diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd.uid deleted file mode 100644 index dccb320..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/path_gizmo.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b5h3ifua5wk72 diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd deleted file mode 100644 index d8aa306..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd +++ /dev/null @@ -1,136 +0,0 @@ -@tool -extends EditorNode3DGizmoPlugin - - -# Actual logic split in the handler class to avoid cluttering this script as -# we add extra shapes. -# -# Although we could make an actual gizmo per shape type and add the extra type -# check in the 'has_gizmo' function, it causes more issues to the editor -# than it's worth (2 fewer files), so it's done like this instead. - - -const ScatterShape = preload("../../scatter_shape.gd") -const GizmoHandler = preload("./gizmo_handler.gd") - - -var _editor_plugin: EditorPlugin -var _handlers: Dictionary - - -func _init(): - var handle_icon = preload("./icons/main_handle.svg") - var secondary_handle_icon = preload("./icons/secondary_handle.svg") - - # TODO: Replace hardcoded colors by a setting fetch - create_material("primary", Color(1, 0.4, 0)) - create_material("secondary", Color(0.4, 0.7, 1.0)) - create_material("tertiary", Color(Color.STEEL_BLUE, 0.2)) - create_custom_material("primary_top", Color(1, 0.4, 0)) - create_custom_material("secondary_top", Color(0.4, 0.7, 1.0)) - create_custom_material("tertiary_top", Color(Color.STEEL_BLUE, 0.1)) - - create_material("inclusive", Color(0.9, 0.7, 0.2, 0.15)) - create_material("exclusive", Color(0.9, 0.1, 0.2, 0.15)) - - create_handle_material("default_handle") - create_handle_material("primary_handle", false, handle_icon) - create_handle_material("secondary_handle", false, secondary_handle_icon) - - _handlers[ProtonScatterSphereShape] = preload("./sphere_gizmo.gd").new() - _handlers[ProtonScatterPathShape] = preload("./path_gizmo.gd").new() - _handlers[ProtonScatterBoxShape] = preload("./box_gizmo.gd").new() - - -func _get_gizmo_name() -> String: - return "ScatterShape" - - -func _has_gizmo(node) -> bool: - return node is ScatterShape - - -func _get_handle_name(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool) -> String: - return _get_handler(gizmo).get_handle_name(gizmo, handle_id, secondary) - - -func _get_handle_value(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool) -> Variant: - return _get_handler(gizmo).get_handle_value(gizmo, handle_id, secondary) - - -func _set_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void: - _get_handler(gizmo).set_handle(gizmo, handle_id, secondary, camera, screen_pos) - - -func _commit_handle(gizmo: EditorNode3DGizmo, handle_id: int, secondary: bool, restore: Variant, cancel: bool) -> void: - _get_handler(gizmo).commit_handle(gizmo, handle_id, secondary, restore, cancel) - - -func _redraw(gizmo: EditorNode3DGizmo): - if _is_node_selected(gizmo): - _get_handler(gizmo).redraw(self, gizmo) - else: - gizmo.clear() - - -func forward_3d_gui_input(viewport_camera: Camera3D, event: InputEvent) -> int: - for handler in _handlers.values(): - if handler.forward_3d_gui_input(viewport_camera, event): - return EditorPlugin.AFTER_GUI_INPUT_STOP - - return EditorPlugin.AFTER_GUI_INPUT_PASS - - -func set_undo_redo(ur: EditorUndoRedoManager) -> void: - for handler_type in _handlers: - _handlers[handler_type].set_undo_redo(ur) - - -func set_path_gizmo_panel(panel: Control) -> void: - if ProtonScatterPathShape in _handlers: - _handlers[ProtonScatterPathShape].set_gizmo_panel(panel) - - -func set_editor_plugin(plugin: EditorPlugin) -> void: - _editor_plugin = plugin - for handler_type in _handlers: - _handlers[handler_type].set_editor_plugin(plugin) - - -# Creates a standard material displayed on top of everything. -# Only exists because 'create_material() on_top' parameter doesn't seem to work. -func create_custom_material(name: String, color := Color.WHITE): - var material := StandardMaterial3D.new() - material.set_blend_mode(StandardMaterial3D.BLEND_MODE_ADD) - material.set_shading_mode(StandardMaterial3D.SHADING_MODE_UNSHADED) - material.set_flag(StandardMaterial3D.FLAG_DISABLE_DEPTH_TEST, true) - material.set_albedo(color) - material.render_priority = 100 - - add_material(name, material) - - -func _get_handler(gizmo: EditorNode3DGizmo) -> GizmoHandler: - var null_handler = GizmoHandler.new() # Only so we don't have to check existence later - - var shape_node = gizmo.get_node_3d() - if not shape_node or not shape_node is ScatterShape: - return null_handler - - var shape_resource = shape_node.shape - if not shape_resource: - return null_handler - - var shape_type = shape_resource.get_script() - if not shape_type in _handlers: - return null_handler - - return _handlers[shape_type] - - -func _is_node_selected(gizmo: EditorNode3DGizmo) -> bool: - if ProjectSettings.get_setting(_editor_plugin.GIZMO_SETTING): - return true - - var selected_nodes: Array[Node] = _editor_plugin.get_custom_selection() - return gizmo.get_node_3d() in selected_nodes diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd.uid deleted file mode 100644 index 5817ee0..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/shape_gizmo_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://o0txv7g6rixk diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd deleted file mode 100644 index 12319e7..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd +++ /dev/null @@ -1,97 +0,0 @@ -@tool -extends "gizmo_handler.gd" - -# 3D Gizmo for the Sphere shape. Draws three circle on each axis to represent -# a sphere, displays one handle on the size to control the radius. -# -# (handle_id is ignored in every function since there's a single handle) - -const SphereShape = preload("../sphere_shape.gd") - - -func get_handle_name(_gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> String: - return "Radius" - - -func get_handle_value(gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool) -> Variant: - return gizmo.get_node_3d().shape.radius - - -func set_handle(gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool, camera: Camera3D, screen_pos: Vector2) -> void: - var shape_node = gizmo.get_node_3d() - var gt := shape_node.get_global_transform() - var gt_inverse := gt.affine_inverse() - var origin := gt.origin - - var ray_from = camera.project_ray_origin(screen_pos) - var ray_to = ray_from + camera.project_ray_normal(screen_pos) * 4096 - var points = Geometry3D.get_closest_points_between_segments(origin, (Vector3.LEFT * 4096) * gt_inverse, ray_from, ray_to) - shape_node.shape.radius = origin.distance_to(points[0]) - - -func commit_handle(gizmo: EditorNode3DGizmo, _handle_id: int, _secondary: bool, restore: Variant, cancel: bool) -> void: - var shape: SphereShape = gizmo.get_node_3d().shape - if cancel: - shape.radius = restore - return - - _undo_redo.create_action("Set ScatterShape Radius") - _undo_redo.add_undo_method(self, "_set_radius", shape, restore) - _undo_redo.add_do_method(self, "_set_radius", shape, shape.radius) - _undo_redo.commit_action() - - -func redraw(plugin: EditorNode3DGizmoPlugin, gizmo: EditorNode3DGizmo): - gizmo.clear() - - var scatter_shape = gizmo.get_node_3d() - var shape: SphereShape = scatter_shape.shape - - ### Draw the 3 circles on each axis to represent the sphere - var lines = PackedVector3Array() - var lines_material := plugin.get_material("primary_top", gizmo) - var steps = 32 # TODO: Update based on sphere radius maybe ? - var step_angle = 2 * PI / steps - var radius = shape.radius - - for i in steps: - lines.append(Vector3(cos(i * step_angle), 0.0, sin(i * step_angle)) * radius) - lines.append(Vector3(cos((i + 1) * step_angle), 0.0, sin((i + 1) * step_angle)) * radius) - - if is_selected(gizmo): - for i in steps: - lines.append(Vector3(cos(i * step_angle), sin(i * step_angle), 0.0) * radius) - lines.append(Vector3(cos((i + 1) * step_angle), sin((i + 1) * step_angle), 0.0) * radius) - - for i in steps: - lines.append(Vector3(0.0, cos(i * step_angle), sin(i * step_angle)) * radius) - lines.append(Vector3(0.0, cos((i + 1) * step_angle), sin((i + 1) * step_angle)) * radius) - - gizmo.add_lines(lines, lines_material) - gizmo.add_collision_segments(lines) - - ### Draw the handle - var handles := PackedVector3Array() - var handles_ids := PackedInt32Array() - var handles_material := plugin.get_material("default_handle", gizmo) - - var handle_position: Vector3 = Vector3.LEFT * radius - handles.push_back(handle_position) - - gizmo.add_handles(handles, handles_material, handles_ids) - - ### Fills the sphere inside - var mesh = SphereMesh.new() - mesh.height = shape.radius * 2.0 - mesh.radius = shape.radius - var mesh_material: StandardMaterial3D - if scatter_shape.negative: - mesh_material = plugin.get_material("exclusive", gizmo) - else: - mesh_material = plugin.get_material("inclusive", gizmo) - gizmo.add_mesh(mesh, mesh_material) - - -func _set_radius(sphere: SphereShape, radius: float) -> void: - if sphere: - sphere.radius = radius diff --git a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd.uid b/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd.uid deleted file mode 100644 index 3495332..0000000 --- a/godot/addons/proton_scatter/src/shapes/gizmos_plugin/sphere_gizmo.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dxfmtmjc5qxi1 diff --git a/godot/addons/proton_scatter/src/shapes/path_shape.gd b/godot/addons/proton_scatter/src/shapes/path_shape.gd deleted file mode 100644 index 7d6c92c..0000000 --- a/godot/addons/proton_scatter/src/shapes/path_shape.gd +++ /dev/null @@ -1,249 +0,0 @@ -@tool -class_name ProtonScatterPathShape -extends ProtonScatterBaseShape - - -const Bounds := preload("../common/bounds.gd") - - -@export var closed := true: - set(val): - closed = val - emit_changed() - -@export var thickness := 0.0: - set(val): - thickness = max(0, val) # Width cannot be negative - _half_thickness_squared = pow(thickness * 0.5, 2) - emit_changed() - -@export var curve: Curve3D: - set(val): - # Disconnect previous signal - if curve and curve.changed.is_connected(_on_curve_changed): - curve.changed.disconnect(_on_curve_changed) - - curve = val - curve.changed.connect(_on_curve_changed) - emit_changed() - - -var _polygon: PolygonPathFinder -var _half_thickness_squared: float -var _bounds: Bounds - - -func is_point_inside(point: Vector3, global_transform: Transform3D) -> bool: - if not _polygon: - _update_polygon_from_curve() - - if not _polygon: - return false - - point = global_transform.affine_inverse() * point - - if thickness > 0: - var closest_point_on_curve: Vector3 = curve.get_closest_point(point) - var dist2 = closest_point_on_curve.distance_squared_to(point) - if dist2 < _half_thickness_squared: - return true - - if closed: - return _polygon.is_point_inside(Vector2(point.x, point.z)) - - return false - - -func get_corners_global(gt: Transform3D) -> Array: - var res := [] - - if not curve: - return res - - var half_thickness = thickness * 0.5 - var corners = [ - Vector3(-1, -1, -1), - Vector3(1, -1, -1), - Vector3(1, -1, 1), - Vector3(-1, -1, 1), - Vector3(-1, 1, -1), - Vector3(1, 1, -1), - Vector3(1, 1, 1), - Vector3(-1, 1, 1), - ] - - var points = curve.tessellate(3, 10) - for p in points: - res.push_back(gt * p) - - if thickness > 0: - for offset in corners: - res.push_back(gt * (p + offset * half_thickness)) - - return res - - -func get_bounds() -> Bounds: - if not _bounds: - _update_polygon_from_curve() - return _bounds - - -func get_copy(): - var copy = get_script().new() - - copy.thickness = thickness - copy.closed = closed - if curve: - copy.curve = curve.duplicate() - - return copy - - -func copy_from(source) -> void: - thickness = source.thickness - if source.curve: - curve = source.curve.duplicate() # TODO, update signals - - -# TODO: create points in the middle of the path -func create_point(position: Vector3) -> void: - if not curve: - curve = Curve3D.new() - - curve.add_point(position) - - -func remove_point(index): - if index > curve.get_point_count() - 1: - return - curve.remove_point(index) - - -func get_closest_to(position): - if curve.get_point_count() == 0: - return -1 - - var closest = -1 - var dist_squared = -1 - - for i in curve.get_point_count(): - var point_pos: Vector3 = curve.get_point_position(i) - var point_dist: float = point_pos.distance_squared_to(position) - - if (closest == -1) or (dist_squared > point_dist): - closest = i - dist_squared = point_dist - - var threshold = 16 # Ignore if the closest point is farther than this - if dist_squared >= threshold: - return -1 - - return closest - - -func get_closed_edges(shape_t: Transform3D) -> Array[PackedVector2Array]: - if not closed and thickness <= 0: - return [] - - if not curve: - return [] - - var edges: Array[PackedVector2Array] = [] - var polyline := PackedVector2Array() - var shape_t_inverse := shape_t.affine_inverse() - var points := curve.tessellate(5, 5) # TODO: find optimal values - - for p in points: - p *= shape_t_inverse # Apply the shape node transform - polyline.push_back(Vector2(p.x, p.z)) - - if closed: - # Ensure the polygon is closed - var first_point: Vector3 = points[0] - var last_point: Vector3 = points[-1] - - if first_point != last_point: - first_point *= shape_t_inverse - polyline.push_back(Vector2(first_point.x, first_point.z)) - - # Prevents the polyline to be considered as a hole later. - if Geometry2D.is_polygon_clockwise(polyline): - polyline.reverse() - - # Expand the polyline to get the outer edge of the path. - if thickness > 0: - # WORKAROUND. We cant specify the round end caps resolution, but it's tied to the polyline - # size. So we scale everything up before calling offset_polyline(), then scale the result - # down so we get rounder caps. - var scale = 5.0 * thickness - var delta = (thickness / 2.0) * scale - - var t2 = Transform2D().scaled(Vector2.ONE * scale) - var result := Geometry2D.offset_polyline(polyline * t2, delta, Geometry2D.JOIN_ROUND, Geometry2D.END_ROUND) - - t2 = Transform2D().scaled(Vector2.ONE * (1.0 / scale)) - for polygon in result: - edges.push_back(polygon * t2) - - if closed and thickness == 0.0: - edges.push_back(polyline) - - return edges - - -func get_open_edges(shape_t: Transform3D) -> Array[Curve3D]: - if not curve or closed or thickness > 0: - return [] - - var res := Curve3D.new() - var shape_t_inverse := shape_t.affine_inverse() - - for i in curve.get_point_count(): - var pos = curve.get_point_position(i) - var pos_t = pos * shape_t_inverse - var p_in = (curve.get_point_in(i) + pos) * shape_t_inverse - pos_t - var p_out = (curve.get_point_out(i) + pos) * shape_t_inverse - pos_t - res.add_point(pos_t, p_in, p_out) - - return [res] - - -func _update_polygon_from_curve() -> void: - var connections = PackedInt32Array() - var polygon_points = PackedVector2Array() - - if not _bounds: - _bounds = Bounds.new() - - _bounds.clear() - _polygon = PolygonPathFinder.new() - - if not curve: - curve = Curve3D.new() - - if curve.get_point_count() == 0: - return - - var baked_points = curve.tessellate(4, 6) - var steps := baked_points.size() - - for i in baked_points.size(): - var point = baked_points[i] - var projected_point = Vector2(point.x, point.z) - _bounds.feed(point) - - polygon_points.push_back(projected_point) - connections.append(i) - if i == steps - 1: - connections.append(0) - else: - connections.append(i + 1) - - _bounds.compute_bounds() - _polygon.setup(polygon_points, connections) - - -func _on_curve_changed() -> void: - _update_polygon_from_curve() - emit_changed() diff --git a/godot/addons/proton_scatter/src/shapes/path_shape.gd.uid b/godot/addons/proton_scatter/src/shapes/path_shape.gd.uid deleted file mode 100644 index 30e6926..0000000 --- a/godot/addons/proton_scatter/src/shapes/path_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c35kb0nppp3g4 diff --git a/godot/addons/proton_scatter/src/shapes/sphere_shape.gd b/godot/addons/proton_scatter/src/shapes/sphere_shape.gd deleted file mode 100644 index 3816ea7..0000000 --- a/godot/addons/proton_scatter/src/shapes/sphere_shape.gd +++ /dev/null @@ -1,71 +0,0 @@ -@tool -class_name ProtonScatterSphereShape -extends ProtonScatterBaseShape - - -@export var radius := 1.0: - set(val): - radius = val - _radius_squared = val * val - emit_changed() - -var _radius_squared := 0.0 - - -func get_copy(): - var copy = ProtonScatterSphereShape.new() - copy.radius = radius - return copy - - -func is_point_inside(point: Vector3, global_transform: Transform3D) -> bool: - var shape_center = global_transform * Vector3.ZERO - return shape_center.distance_squared_to(point) < _radius_squared - - -func get_corners_global(gt: Transform3D) -> Array: - var res := [] - - var corners := [ - Vector3(-1, -1, -1), - Vector3(-1, -1, 1), - Vector3(1, -1, 1), - Vector3(1, -1, -1), - Vector3(-1, 1, -1), - Vector3(-1, 1, 1), - Vector3(1, 1, 1), - Vector3(1, 1, -1), - ] - - for c in corners: - c *= radius - res.push_back(gt * c) - - return res - - - -# Returns the circle matching the intersection between the scatter node XZ plane -# and the sphere. Returns an empty array if there's no intersection. -func get_closed_edges(shape_t: Transform3D) -> Array[PackedVector2Array]: - var edge := PackedVector2Array() - var plane := Plane(Vector3.UP, 0.0) - - var sphere_center := shape_t.origin - var dist2plane = plane.distance_to(sphere_center) - var radius_at_ground_level := sqrt(pow(radius, 2) - pow(dist2plane, 2)) - - # No intersection with plane - if radius_at_ground_level <= 0.0 or radius_at_ground_level > radius: - return [] - - var origin := Vector2(sphere_center.x, sphere_center.z) - var steps: int = max(16, int(radius_at_ground_level * 12)) - var angle: float = TAU / steps - - for i in steps + 1: - var theta = angle * i - var point := origin + Vector2(cos(theta), sin(theta)) * radius_at_ground_level - edge.push_back(point) - - return [edge] diff --git a/godot/addons/proton_scatter/src/shapes/sphere_shape.gd.uid b/godot/addons/proton_scatter/src/shapes/sphere_shape.gd.uid deleted file mode 100644 index a214156..0000000 --- a/godot/addons/proton_scatter/src/shapes/sphere_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://2c1ho43kmi62 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd deleted file mode 100644 index 76c8cc3..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd +++ /dev/null @@ -1,15 +0,0 @@ -@tool -extends EditorProperty - - -var _ui: Control - - -func _init(): - _ui = preload("./ui/stack_panel.tscn").instantiate() - add_child(_ui) - set_bottom_editor(_ui) - - -func set_node(object) -> void: - _ui.set_node(object) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd.uid deleted file mode 100644 index 0938b38..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/editor_property.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b8jvgom08f0vf diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd deleted file mode 100644 index 55290ef..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool -extends EditorInspectorPlugin - - -const Editor = preload("./editor_property.gd") -const Scatter = preload("../../scatter.gd") - - -func _can_handle(object): - return is_instance_of(object, Scatter) - - -func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide): - if name == "modifier_stack": - var editor_property = Editor.new() - editor_property.set_node(object) - add_property_editor("modifier_stack", editor_property) - return true - return false diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd.uid deleted file mode 100644 index a00b25f..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/modifier_stack_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c6yrh0lb4iu74 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd deleted file mode 100644 index 2d2ecb0..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool -extends Button - - -@onready var _popup: PopupPanel = $ModifiersPopup - - -func _ready() -> void: - _popup.popup_hide.connect(_on_popup_closed) - - -func _toggled(button_pressed): - if button_pressed: - _popup.position = global_position + Vector2(0.0, size.y) - _popup.popup() - - -func _on_popup_closed() -> void: - button_pressed = false diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd.uid deleted file mode 100644 index b3a5ef6..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b2ijyxcbk7lgj diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd deleted file mode 100644 index 1026ed8..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd +++ /dev/null @@ -1,59 +0,0 @@ -@tool -extends Control - - -signal value_changed - - -var _scatter -var _previous -var _locked := false - - -func set_scatter(scatter_node) -> void: - _scatter = scatter_node - - -func set_parameter_name(_text: String) -> void: - pass - - -func set_hint_string(_hint: String) -> void: - pass - - -func set_value(val) -> void: - _locked = true - _set_value(val) - _previous = get_value() - _locked = false - - -func get_value(): - pass - - -func get_editor_theme() -> Theme: - if not _scatter: - return ThemeDB.get_default_theme() - - var editor_interface: Variant - - if Engine.get_version_info().minor >= 2: - editor_interface = EditorInterface - return editor_interface.get_editor_theme() - else: - editor_interface = _scatter.editor_plugin.get_editor_interface() - return editor_interface.get_base_control().get_theme() - - -func _set_value(_val): - pass - - -func _on_value_changed(_val) -> void: - if not _locked: - var value = get_value() - if value != _previous: - value_changed.emit(value, _previous) - _previous = value diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd.uid deleted file mode 100644 index 721467e..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/base_parameter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dgqutkvn5a7yo diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/bitmask_button.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/bitmask_button.tscn deleted file mode 100644 index 978b123..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/bitmask_button.tscn +++ /dev/null @@ -1,51 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cf4lrr5tnlwnw"] - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lylt6"] -content_margin_left = 0.0 -content_margin_top = 0.0 -content_margin_right = 0.0 -content_margin_bottom = 0.0 -bg_color = Color(1, 1, 1, 0.54902) -corner_radius_top_left = 2 -corner_radius_top_right = 2 -corner_radius_bottom_right = 2 -corner_radius_bottom_left = 2 -corner_detail = 6 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8hejw"] -content_margin_left = 0.0 -content_margin_top = 0.0 -content_margin_right = 0.0 -content_margin_bottom = 0.0 -bg_color = Color(1, 1, 1, 0.784314) -corner_radius_top_left = 2 -corner_radius_top_right = 2 -corner_radius_bottom_right = 2 -corner_radius_bottom_left = 2 -corner_detail = 6 - -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dmtgy"] -content_margin_left = 0.0 -content_margin_top = 0.0 -content_margin_right = 0.0 -content_margin_bottom = 0.0 -bg_color = Color(1, 1, 1, 1) -corner_radius_top_left = 2 -corner_radius_top_right = 2 -corner_radius_bottom_right = 2 -corner_radius_bottom_left = 2 -corner_detail = 6 - -[node name="Button" type="Button"] -custom_minimum_size = Vector2(20, 20) -size_flags_horizontal = 3 -focus_mode = 0 -theme_override_colors/font_color = Color(0, 0, 0, 1) -theme_override_colors/font_pressed_color = Color(0, 0, 0, 1) -theme_override_colors/font_hover_color = Color(0, 0, 0, 1) -theme_override_font_sizes/font_size = 12 -theme_override_styles/normal = SubResource("StyleBoxFlat_lylt6") -theme_override_styles/hover = SubResource("StyleBoxFlat_8hejw") -theme_override_styles/pressed = SubResource("StyleBoxFlat_dmtgy") -toggle_mode = true -text = "00" diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd deleted file mode 100644 index a002e49..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd +++ /dev/null @@ -1,347 +0,0 @@ -# warning-ignore-all:return_value_discarded - -@tool -extends Control - - -signal curve_updated - - -@export var grid_color := Color(1, 1, 1, 0.2) -@export var grid_color_sub := Color(1, 1, 1, 0.1) -@export var curve_color := Color(1, 1, 1, 0.9) -@export var point_color := Color.WHITE -@export var selected_point_color := Color.ORANGE -@export var point_radius := 4.0 -@export var text_color := Color(0.9, 0.9, 0.9) -@export var columns := 4 -@export var rows := 2 -@export var dynamic_row_count := true - -var curve: Curve -var gt: Transform2D - -var _hover_point := -1: - set(val): - if val != _hover_point: - _hover_point = val - queue_redraw() - -var _selected_point := -1: - set(val): - if val != _selected_point: - _selected_point = val - queue_redraw() - -var _selected_tangent := -1: - set(val): - if val != _selected_tangent: - _selected_tangent = val - queue_redraw() - -var _dragging := false -var _hover_radius := 50.0 # Squared -var _tangents_length := 30.0 -var _font: Font - - -func _ready() -> void: - #rect_min_size.y *= EditorUtil.get_editor_scale() - var plugin := EditorPlugin.new() - var editor_theme := plugin.get_editor_interface().get_base_control().get_theme() - if editor_theme: - _font = editor_theme.get_font("Main", "EditorFonts") - else: - _font = ThemeDB.fallback_font - plugin.queue_free() - - queue_redraw() - connect("resized", _on_resized) - - -func set_curve(c: Curve) -> void: - curve = c - queue_redraw() - - -func get_curve() -> Curve: - return curve - - -func _gui_input(event) -> void: - if event is InputEventKey: - if _selected_point != -1 and event.scancode == KEY_DELETE: - remove_point(_selected_point) - - elif event is InputEventMouseButton: - if event.double_click: - add_point(_to_curve_space(event.position)) - - elif event.pressed and event.button_index == MOUSE_BUTTON_MIDDLE: - var i = get_point_at(event.position) - if i != -1: - remove_point(i) - - elif event.pressed and event.button_index == MOUSE_BUTTON_LEFT: - set_selected_tangent(get_tangent_at(event.position)) - - if _selected_tangent == -1: - set_selected_point(get_point_at(event.position)) - if _selected_point != -1: - _dragging = true - - elif _dragging and not event.pressed: - _dragging = false - emit_signal("curve_updated") - - elif event is InputEventMouseMotion: - if _dragging: - var curve_amplitude: float = curve.get_max_value() - curve.get_min_value() - - # Snap to "round" coordinates when holding Ctrl. - # Be more precise when holding Shift as well. - var snap_threshold: float - if event.ctrl_pressed: - snap_threshold = 0.025 if event.shift else 0.1 - else: - snap_threshold = 0.0 - - if _selected_tangent == -1: # Drag point - var point_pos: Vector2 = _to_curve_space(event.position).snapped(Vector2(snap_threshold, snap_threshold * curve_amplitude)) - - # The index may change if the point is dragged across another one - var i: int = curve.set_point_offset(_selected_point, point_pos.x) - set_hover(i) - set_selected_point(i) - - # This is to prevent the user from losing a point out of view. - if point_pos.y < curve.get_min_value(): - point_pos.y = curve.get_min_value() - elif point_pos.y > curve.get_max_value(): - point_pos.y = curve.get_max_value() - - curve.set_point_value(_selected_point, point_pos.y) - - else: # Drag tangent - var point_pos: Vector2 = curve.get_point_position(_selected_point) - var control_pos: Vector2 = _to_curve_space(event.position).snapped(Vector2(snap_threshold, snap_threshold * curve_amplitude)) - - var dir: Vector2 = (control_pos - point_pos).normalized() - - var tangent: float - if not is_zero_approx(dir.x): - tangent = dir.y / dir.x - else: - tangent = 1 if dir.y >= 0 else -1 - tangent *= 9999 - - var link: bool = not Input.is_key_pressed(KEY_SHIFT) - - if _selected_tangent == 0: - curve.set_point_left_tangent(_selected_point, tangent) - - # Note: if a tangent is set to linear, it shouldn't be linked to the other - if link and _selected_point != (curve.get_point_count() - 1) and curve.get_point_right_mode(_selected_point) != Curve.TANGENT_LINEAR: - curve.set_point_right_tangent(_selected_point, tangent) - - else: - curve.set_point_right_tangent(_selected_point, tangent) - - if link and _selected_point != 0 and curve.get_point_left_mode(_selected_point) != Curve.TANGENT_LINEAR: - curve.set_point_left_tangent(_selected_point, tangent) - queue_redraw() - else: - set_hover(get_point_at(event.position)) - - -func add_point(pos: Vector2) -> void: - if not curve: - return - - pos.y = clamp(pos.y, 0.0, 1.0) - curve.add_point(pos) - queue_redraw() - emit_signal("curve_updated") - - -func remove_point(idx: int) -> void: - if not curve: - return - - if idx == _selected_point: - set_selected_point(-1) - - if idx == _hover_point: - set_hover(-1) - - curve.remove_point(idx) - queue_redraw() - emit_signal("curve_updated") - - -func get_point_at(pos: Vector2) -> int: - if not curve: - return -1 - - for i in curve.get_point_count(): - var p := _to_view_space(curve.get_point_position(i)) - if p.distance_squared_to(pos) <= _hover_radius: - return i - - return -1 - - -func get_tangent_at(pos: Vector2) -> int: - if not curve or _selected_point < 0: - return -1 - - if _selected_point != 0: - var control_pos: Vector2 = _get_tangent_view_pos(_selected_point, 0) - if control_pos.distance_squared_to(pos) < _hover_radius: - return 0 - - if _selected_point != curve.get_point_count() - 1: - var control_pos = _get_tangent_view_pos(_selected_point, 1) - if control_pos.distance_squared_to(pos) < _hover_radius: - return 1 - - return -1 - - -func _draw() -> void: - if not curve: - return - - var text_height = _font.get_height() - var min_outer := Vector2(0, size.y) - var max_outer := Vector2(size.x, 0) - var min_inner := Vector2(text_height, size.y - text_height) - var max_inner := Vector2(size.x - text_height, text_height) - - var width: float = max_inner.x - min_inner.x - var height: float = max_inner.y - min_inner.y - - var curve_min: float = curve.get_min_value() - var curve_max: float = curve.get_max_value() - - - # Main area - draw_line(Vector2(0, max_inner.y), Vector2(max_outer.x, max_inner.y), grid_color) - draw_line(Vector2(0, min_inner.y), Vector2(max_outer.x, min_inner.y), grid_color) - draw_line(Vector2(min_inner.x, max_outer.y), Vector2(min_inner.x, min_outer.y), grid_color) - draw_line(Vector2(max_inner.x, max_outer.y), Vector2(max_inner.x, min_outer.y), grid_color) - - # Grid and scale - ## Vertical lines - var x_offset = 1.0 / columns - var margin = 4 - - for i in columns + 1: - var x = width * (i * x_offset) + min_inner.x - draw_line(Vector2(x, max_outer.y), Vector2(x, min_outer.y), grid_color_sub) - draw_string(_font, Vector2(x + margin, min_outer.y - margin), str(snapped(i * x_offset, 0.01)), 0, -1, -1, text_color) - - ## Horizontal lines - var y_offset = 1.0 / rows - - for i in rows + 1: - var y = height * (i * y_offset) + min_inner.y - draw_line(Vector2(min_outer.x, y), Vector2(max_outer.x, y), grid_color_sub) - var y_value = i * ((curve_max - curve_min) / rows) + curve_min - draw_string(_font, Vector2(min_inner.x + margin, y - margin), str(snapped(y_value, 0.01)), 0, -1, -1, text_color) - - # Plot curve - var steps = 100 - var offset = 1.0 / steps - x_offset = width / steps - - var a: float - var a_y: float - var b: float - var b_y: float - - a = curve.sample_baked(0.0) - a_y = remap(a, curve_min, curve_max, min_inner.y, max_inner.y) - - for i in steps - 1: - b = curve.sample_baked((i + 1) * offset) - b_y = remap(b, curve_min, curve_max, min_inner.y, max_inner.y) - draw_line(Vector2(min_inner.x + x_offset * i, a_y), Vector2(min_inner.x + x_offset * (i + 1), b_y), curve_color) - a_y = b_y - - # Draw points - for i in curve.get_point_count(): - var pos: Vector2 = _to_view_space(curve.get_point_position(i)) - if _selected_point == i: - draw_circle(pos, point_radius, selected_point_color) - else: - draw_circle(pos, point_radius, point_color); - - if _hover_point == i: - draw_arc(pos, point_radius + 4.0, 0.0, 2 * PI, 12, point_color, 1.0, true) - - # Draw tangents - if _selected_point >= 0: - var i: int = _selected_point - var pos: Vector2 = _to_view_space(curve.get_point_position(i)) - - if i != 0: - var control_pos: Vector2 = _get_tangent_view_pos(i, 0) - draw_line(pos, control_pos, selected_point_color) - draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), selected_point_color) - - if i != curve.get_point_count() - 1: - var control_pos: Vector2 = _get_tangent_view_pos(i, 1) - draw_line(pos, control_pos, selected_point_color) - draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), selected_point_color) - - -func _to_view_space(pos: Vector2) -> Vector2: - var h = _font.get_height() - pos.x = remap(pos.x, 0.0, 1.0, h, size.x - h) - pos.y = remap(pos.y, curve.get_min_value(), curve.get_max_value(), size.y - h, h) - return pos - - -func _to_curve_space(pos: Vector2) -> Vector2: - var h = _font.get_height() - pos.x = remap(pos.x, h, size.x - h, 0.0, 1.0) - pos.y = remap(pos.y, size.y - h, h, curve.get_min_value(), curve.get_max_value()) - return pos - - -func _get_tangent_view_pos(i: int, tangent: int) -> Vector2: - var dir: Vector2 - - if tangent == 0: - dir = -Vector2(1.0, curve.get_point_left_tangent(i)) - else: - dir = Vector2(1.0, curve.get_point_right_tangent(i)) - - var point_pos = _to_view_space(curve.get_point_position(i)) - var control_pos = _to_view_space(curve.get_point_position(i) + dir) - - return point_pos + _tangents_length * (control_pos - point_pos).normalized() - - -func set_hover(val: int) -> void: - if val != _hover_point: - _hover_point = val - queue_redraw() - - -func set_selected_point(val: int) -> void: - if val != _selected_point: - _selected_point = val - queue_redraw() - - -func set_selected_tangent(val: int) -> void: - if val != _selected_tangent: - _selected_tangent = val - queue_redraw() - - -func _on_resized() -> void: - if dynamic_row_count: - rows = (int(size.y / custom_minimum_size.y) + 1) * 2 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd.uid deleted file mode 100644 index 3b41170..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtgdcadnx51m1 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd deleted file mode 100644 index fda5f0c..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd +++ /dev/null @@ -1,23 +0,0 @@ -@tool -extends "../base_parameter.gd" - - -var _button - - -func _ready() -> void: - _button = get_node("Button") - _button.toggled.connect(_on_value_changed) - - -func enable(enabled: bool) -> void: - _button.disabled = not enabled - _button.flat = not enabled - - -func get_value() -> bool: - return _button.button_pressed - - -func _set_value(val: bool) -> void: - _button.button_pressed = val diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd.uid deleted file mode 100644 index f2de5d9..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://372yib37e0ag diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.tscn deleted file mode 100644 index 12dab18..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.tscn +++ /dev/null @@ -1,19 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://w6ycb4oveqhd"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.gd" id="1_f6puy"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd" id="2_167vc"] - -[node name="MarginContainer" type="MarginContainer"] -offset_right = 40.0 -offset_bottom = 40.0 -size_flags_horizontal = 4 -size_flags_vertical = 4 -script = ExtResource( "1_f6puy" ) - -[node name="Button" type="Button" parent="."] -offset_right = 40.0 -offset_bottom = 40.0 -focus_mode = 0 -toggle_mode = true -icon_alignment = 1 -script = ExtResource( "2_167vc" ) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd deleted file mode 100644 index 688f19a..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd +++ /dev/null @@ -1,17 +0,0 @@ -@tool -extends "../base_parameter.gd" - - -@onready var _spinbox = $SpinBox - - -func _ready() -> void: - _spinbox.value_changed.connect(_on_value_changed) - - -func get_value() -> int: - return int(_spinbox.get_value()) - - -func _set_value(val: int) -> void: - _spinbox.set_value(val) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd.uid deleted file mode 100644 index f7aa935..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://djwbsf1jc2pe6 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.tscn deleted file mode 100644 index 76175e5..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.tscn +++ /dev/null @@ -1,17 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://c36gqn03pvlnr"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.gd" id="1_f0oq6"] - -[node name="ParameterSpinbox" type="MarginContainer"] -offset_right = 83.0625 -offset_bottom = 31.0 -size_flags_horizontal = 4 -size_flags_vertical = 4 -script = ExtResource( "1_f0oq6" ) - -[node name="SpinBox" type="SpinBox" parent="."] -offset_right = 83.0 -offset_bottom = 31.0 -min_value = -100.0 -allow_greater = true -allow_lesser = true diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd deleted file mode 100644 index c32279a..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd +++ /dev/null @@ -1,131 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $Label -@onready var _grid_1: Control = $%GridContainer1 -@onready var _grid_2: Control = $%GridContainer2 -@onready var _grid_3: Control = $%GridContainer3 -@onready var _grid_4: Control = $%GridContainer4 -@onready var _menu_button: MenuButton = $%MenuButton - -var _buttons: Array[Button] -var _popup: PopupMenu -var _layer_count := 32 - - -func _ready() -> void: - _buttons = [] - var grids = [_grid_1, _grid_2, _grid_3, _grid_4] - - for g in grids: - for c in g.get_children(): - if c is Button: - var layer_number = c.text.to_int() - if layer_number > _layer_count: - c.visible = false - continue - _buttons.push_front(c) - c.focus_mode = Control.FOCUS_NONE - c.pressed.connect(_on_button_pressed) - - _popup = _menu_button.get_popup() - _popup.clear() - - var layer_name := "" - for i in _layer_count: - if i != 0 and i % 4 == 0: - _popup.add_separator("", 100 + i) - - layer_name = ProjectSettings.get_setting("layer_names/3d_physics/layer_" + str(i + 1)) - if layer_name.is_empty(): - layer_name = "Layer " + str(i + 1) - _popup.add_check_item(layer_name, _layer_count - 1 - i) - - _sync_popup_state() - _popup.id_pressed.connect(_on_id_pressed) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func _set_value(val: int) -> void: - var binary_string: String = _dec2bin(val) - var length = binary_string.length() - - if length < _layer_count: - binary_string = binary_string.pad_zeros(_layer_count) - elif length > _layer_count: - binary_string = binary_string.substr(length - _layer_count, length) - - for i in _layer_count: - _buttons[i].button_pressed = binary_string[i] == "1" - - _sync_popup_state() - - -func get_value() -> int: - var binary_string = "" - for b in _buttons: - binary_string += "1" if b.button_pressed else "0" - - var val = _bin2dec(binary_string) - return val - - -func _dec2bin(value: int) -> String: - if value == 0: - return "0" - - var binary_string = "" - while value != 0: - var m = value % 2 - binary_string = str(m) + binary_string - # warning-ignore:integer_division - value = value / 2 - - return binary_string - - -func _bin2dec(binary_string: String) -> int: - var decimal_value = 0 - var count = binary_string.length() - 1 - - for i in binary_string.length(): - decimal_value += pow(2, count) * binary_string[i].to_int() - count -= 1 - - return decimal_value - - -func _sync_popup_state() -> void: - if not _popup: - return - - for i in _layer_count: - var idx = _popup.get_item_index(i) - _popup.set_item_checked(idx, _buttons[i].button_pressed) - - -func _on_button_pressed() -> void: - _on_value_changed(null) - _sync_popup_state() - - -func _on_id_pressed(id: int) -> void: - var idx = _popup.get_item_index(id) - var checked = not _popup.is_item_checked(idx) - _buttons[id].button_pressed = checked - _popup.set_item_checked(idx, checked) - _on_button_pressed() - - -func _on_enable_all_pressed() -> void: - _set_value(4294967295) - _on_value_changed(null) - - -func _on_clear_pressed() -> void: - _set_value(0) - _on_value_changed(null) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd.uid deleted file mode 100644 index 8310764..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bsule72ph4oww diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.tscn deleted file mode 100644 index afff086..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.tscn +++ /dev/null @@ -1,335 +0,0 @@ -[gd_scene load_steps=6 format=3 uid="uid://chondv2lhs4pl"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bitmask.gd" id="1"] -[ext_resource type="PackedScene" uid="uid://cf4lrr5tnlwnw" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/bitmask_button.tscn" id="2"] -[ext_resource type="Texture2D" uid="uid://n66mufjib4ds" path="res://addons/proton_scatter/icons/menu.svg" id="3"] -[ext_resource type="Texture2D" uid="uid://bosx22dy64f11" path="res://addons/proton_scatter/icons/clear.svg" id="4"] -[ext_resource type="Texture2D" uid="uid://uytbptu3a34s" path="res://addons/proton_scatter/icons/select_all.svg" id="4_h30jm"] - -[node name="parameter_bitmask" type="VBoxContainer"] -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 178.0 -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -text = "Parameter name" - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] -layout_mode = 2 -alignment = 2 - -[node name="MenuButton" type="MenuButton" parent="MarginContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -icon = ExtResource("3") -item_count = 39 -popup/item_0/text = "Layer 1" -popup/item_0/checkable = 1 -popup/item_0/id = 31 -popup/item_1/text = "Layer 2" -popup/item_1/checkable = 1 -popup/item_1/id = 30 -popup/item_2/text = "Layer 3" -popup/item_2/checkable = 1 -popup/item_2/id = 29 -popup/item_3/text = "Layer 4" -popup/item_3/checkable = 1 -popup/item_3/id = 28 -popup/item_4/text = "" -popup/item_4/id = 104 -popup/item_4/separator = true -popup/item_5/text = "Layer 5" -popup/item_5/checkable = 1 -popup/item_5/id = 27 -popup/item_6/text = "Layer 6" -popup/item_6/checkable = 1 -popup/item_6/id = 26 -popup/item_7/text = "Layer 7" -popup/item_7/checkable = 1 -popup/item_7/id = 25 -popup/item_8/text = "Layer 8" -popup/item_8/checkable = 1 -popup/item_8/id = 24 -popup/item_9/text = "" -popup/item_9/id = 108 -popup/item_9/separator = true -popup/item_10/text = "Layer 9" -popup/item_10/checkable = 1 -popup/item_10/id = 23 -popup/item_11/text = "Layer 10" -popup/item_11/checkable = 1 -popup/item_11/id = 22 -popup/item_12/text = "Layer 11" -popup/item_12/checkable = 1 -popup/item_12/id = 21 -popup/item_13/text = "Layer 12" -popup/item_13/checkable = 1 -popup/item_13/id = 20 -popup/item_14/text = "" -popup/item_14/id = 112 -popup/item_14/separator = true -popup/item_15/text = "Layer 13" -popup/item_15/checkable = 1 -popup/item_15/id = 19 -popup/item_16/text = "Layer 14" -popup/item_16/checkable = 1 -popup/item_16/id = 18 -popup/item_17/text = "Layer 15" -popup/item_17/checkable = 1 -popup/item_17/id = 17 -popup/item_18/text = "Layer 16" -popup/item_18/checkable = 1 -popup/item_18/id = 16 -popup/item_19/text = "" -popup/item_19/id = 116 -popup/item_19/separator = true -popup/item_20/text = "Layer 17" -popup/item_20/checkable = 1 -popup/item_20/id = 15 -popup/item_21/text = "Layer 18" -popup/item_21/checkable = 1 -popup/item_21/id = 14 -popup/item_22/text = "Layer 19" -popup/item_22/checkable = 1 -popup/item_22/id = 13 -popup/item_23/text = "Layer 20" -popup/item_23/checkable = 1 -popup/item_23/id = 12 -popup/item_24/text = "" -popup/item_24/id = 120 -popup/item_24/separator = true -popup/item_25/text = "Layer 21" -popup/item_25/checkable = 1 -popup/item_25/id = 11 -popup/item_26/text = "Layer 22" -popup/item_26/checkable = 1 -popup/item_26/id = 10 -popup/item_27/text = "Layer 23" -popup/item_27/checkable = 1 -popup/item_27/id = 9 -popup/item_28/text = "Layer 24" -popup/item_28/checkable = 1 -popup/item_28/id = 8 -popup/item_29/text = "" -popup/item_29/id = 124 -popup/item_29/separator = true -popup/item_30/text = "Layer 25" -popup/item_30/checkable = 1 -popup/item_30/id = 7 -popup/item_31/text = "Layer 26" -popup/item_31/checkable = 1 -popup/item_31/id = 6 -popup/item_32/text = "Layer 27" -popup/item_32/checkable = 1 -popup/item_32/id = 5 -popup/item_33/text = "Layer 28" -popup/item_33/checkable = 1 -popup/item_33/id = 4 -popup/item_34/text = "" -popup/item_34/id = 128 -popup/item_34/separator = true -popup/item_35/text = "Layer 29" -popup/item_35/checkable = 1 -popup/item_35/id = 3 -popup/item_36/text = "Layer 30" -popup/item_36/checkable = 1 -popup/item_36/id = 2 -popup/item_37/text = "Layer 31" -popup/item_37/checkable = 1 -popup/item_37/id = 1 -popup/item_38/text = "Layer 32" -popup/item_38/checkable = 1 -popup/item_38/id = 0 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 - -[node name="GridContainer1" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -columns = 4 - -[node name="Button1" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "1" - -[node name="Button2" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "2" - -[node name="Button3" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "3" - -[node name="Button4" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "4" - -[node name="Button5" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "5" - -[node name="Button6" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "6" - -[node name="Button7" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "7" - -[node name="Button8" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer1" instance=ExtResource("2")] -layout_mode = 2 -text = "8" - -[node name="VSeparator" type="VSeparator" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 - -[node name="GridContainer2" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -columns = 4 - -[node name="Button9" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "9" - -[node name="Button10" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "10" - -[node name="Button11" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "11" - -[node name="Button12" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "12" - -[node name="Button13" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "13" - -[node name="Button14" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "14" - -[node name="Button15" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "15" - -[node name="Button16" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/GridContainer2" instance=ExtResource("2")] -layout_mode = 2 -text = "16" - -[node name="HSeparator" type="HSeparator" parent="MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 - -[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 - -[node name="GridContainer3" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2"] -unique_name_in_owner = true -layout_mode = 2 -columns = 4 - -[node name="Button17" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "17" - -[node name="Button18" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "18" - -[node name="Button19" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "19" - -[node name="Button20" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "20" - -[node name="Button21" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "21" - -[node name="Button22" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "22" - -[node name="Button23" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "23" - -[node name="Button24" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer3" instance=ExtResource("2")] -layout_mode = 2 -text = "24" - -[node name="VSeparator2" type="VSeparator" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2"] -layout_mode = 2 - -[node name="GridContainer4" type="GridContainer" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2"] -unique_name_in_owner = true -layout_mode = 2 -columns = 4 - -[node name="Button25" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "25" - -[node name="Button26" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "26" - -[node name="Button27" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "27" - -[node name="Button28" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "28" - -[node name="Button29" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "29" - -[node name="Button30" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "30" - -[node name="Button31" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "31" - -[node name="Button32" parent="MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer2/GridContainer4" instance=ExtResource("2")] -layout_mode = 2 -text = "32" - -[node name="VBoxContainer2" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="EnableAll" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer2"] -layout_mode = 2 -size_flags_vertical = 3 -focus_mode = 0 -icon = ExtResource("4_h30jm") -flat = true -expand_icon = true - -[node name="ClearButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer2"] -layout_mode = 2 -size_flags_vertical = 3 -focus_mode = 0 -icon = ExtResource("4") -flat = true - -[connection signal="pressed" from="MarginContainer/HBoxContainer/VBoxContainer2/EnableAll" to="." method="_on_enable_all_pressed"] -[connection signal="pressed" from="MarginContainer/HBoxContainer/VBoxContainer2/ClearButton" to="." method="_on_clear_pressed"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd deleted file mode 100644 index cdd2f2f..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd +++ /dev/null @@ -1,23 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $Label -@onready var _check_box: CheckBox = $CheckBox - - -func _ready() -> void: - # warning-ignore:return_value_discarded - _check_box.connect("toggled", _on_value_changed) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func get_value() -> bool: - return _check_box.button_pressed - - -func _set_value(val: bool) -> void: - _check_box.button_pressed = val diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd.uid deleted file mode 100644 index 9aab447..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c38tq68wbqelx diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.tscn deleted file mode 100644 index 49aa944..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.tscn +++ /dev/null @@ -1,21 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://10wqs13p5i3d"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_bool.gd" id="1"] - -[node name="ParameterScalar" type="HBoxContainer"] -anchor_right = 1.0 -script = ExtResource( "1" ) - -[node name="Label" type="Label" parent="."] -offset_top = 2.0 -offset_right = 996.0 -offset_bottom = 28.0 -size_flags_horizontal = 3 -text = "Parameter name" - -[node name="CheckBox" type="CheckBox" parent="."] -offset_left = 1000.0 -offset_right = 1024.0 -offset_bottom = 31.0 -focus_mode = 0 -mouse_filter = 1 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd deleted file mode 100644 index 9159699..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd +++ /dev/null @@ -1,25 +0,0 @@ -@tool -extends "base_parameter.gd" - - -const Util = preload("../../../../../common/util.gd") - - -@onready var _label: Label = $Label -@onready var _panel: Control = $MarginContainer/CurvePanel - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func get_value() -> Curve: - return _panel.get_curve() - - -func _set_value(val: Curve) -> void: - _panel.set_curve(val) - - -func _on_curve_updated() -> void: - _on_value_changed(get_value()) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd.uid deleted file mode 100644 index a624399..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b8uq8oy2efuk4 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.tscn deleted file mode 100644 index 9917586..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.tscn +++ /dev/null @@ -1,26 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://dqjwibwhdmgsb"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_curve.gd" id="1"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/curve_panel.gd" id="2"] - -[node name="ParameterCurve" type="VBoxContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -text = "Curve name" - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 - -[node name="CurvePanel" type="PanelContainer" parent="MarginContainer"] -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 -script = ExtResource("2") -selected_point_color = Color(0.878431, 0.47451, 0, 1) -rows = 4 - -[connection signal="curve_updated" from="MarginContainer/CurvePanel" to="." method="_on_curve_updated"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd deleted file mode 100644 index 7f5b9e3..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd +++ /dev/null @@ -1,54 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $%Label -@onready var _select_button: Button = $%FileButton -@onready var _dialog: FileDialog = $%FileDialog -@onready var _texture: Button = $%TextureButton -@onready var _preview_root: Control = $%PreviewRoot - -var _path := "" -var _is_texture := false - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func set_hint_string(hint: String) -> void: - _is_texture = hint == "Texture" - _set_value(get_value()) - - -func _set_value(val: String) -> void: - _path = val - _select_button.text = val.get_file() - _preview_root.visible = false - - if val.is_empty(): - _select_button.text = "Select a file" - - if _is_texture: - var texture = load(get_value()) - if texture is Texture: - _texture.icon = texture - _preview_root.visible = true - - -func get_value() -> String: - return _path - - -func _on_clear_button_pressed() -> void: - _set_value("") - _on_value_changed("") - - -func _on_select_button_pressed() -> void: - _dialog.popup_centered() - - -func _on_file_selected(file: String) -> void: - _set_value(file) - _on_value_changed(file) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd.uid deleted file mode 100644 index 800ca73..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cck5bhimet1pb diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.tscn deleted file mode 100644 index 109b6dc..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.tscn +++ /dev/null @@ -1,67 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cvgj4rdc0mxxq"] - -[ext_resource type="Texture2D" uid="uid://bosx22dy64f11" path="res://addons/proton_scatter/icons/clear.svg" id="1"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_file.gd" id="2"] - -[node name="ParameterFile" type="VBoxContainer"] -anchors_preset = 10 -anchor_right = 1.0 -offset_bottom = 31.0 -size_flags_vertical = 0 -theme_override_constants/separation = 0 -script = ExtResource("2") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 - -[node name="Label" type="Label" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "Parameter name" - -[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="FileButton" type="Button" parent="HBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "Select a file" - -[node name="ClearButton" type="Button" parent="HBoxContainer/HBoxContainer"] -layout_mode = 2 -icon = ExtResource("1") - -[node name="PreviewRoot" type="HBoxContainer" parent="."] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Control" type="Control" parent="PreviewRoot"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="TextureButton" type="Button" parent="PreviewRoot"] -unique_name_in_owner = true -custom_minimum_size = Vector2(100, 100) -layout_mode = 2 -flat = true -expand_icon = true - -[node name="Control" type="Control" parent="."] -layout_mode = 2 - -[node name="FileDialog" type="FileDialog" parent="Control"] -unique_name_in_owner = true -title = "Open a File" -size = Vector2i(400, 600) -ok_button_text = "Open" -file_mode = 0 -filters = PackedStringArray("*.bmp", "*.dds", "*.exr", "*.hdr", "*.jpg", "*.jpeg", "*.png", "*.tga", "*.svg", "*.svgz", "*.webp") - -[connection signal="pressed" from="HBoxContainer/HBoxContainer/FileButton" to="." method="_on_select_button_pressed"] -[connection signal="pressed" from="HBoxContainer/HBoxContainer/ClearButton" to="." method="_on_clear_button_pressed"] -[connection signal="pressed" from="PreviewRoot/TextureButton" to="." method="_on_select_button_pressed"] -[connection signal="file_selected" from="Control/FileDialog" to="." method="_on_file_selected"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd deleted file mode 100644 index 842367f..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd +++ /dev/null @@ -1,88 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $%Label -@onready var _select_button: Button = $%SelectButton -@onready var _popup: ConfirmationDialog = $%ConfirmationDialog -@onready var _tree: Tree = $%Tree - -var _full_path: NodePath -var _root: Node -var _selected: Node - - -func set_root(root) -> void: - _root = root - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func _set_value(val) -> void: - if val == null: - return - - _full_path = val - - if val.is_empty(): - return - - _select_button.text = val.get_name(val.get_name_count() - 1) - - if _root and _root.has_node(val): - _selected = _root.get_node(val) - - if val.is_empty(): - _select_button.text = "Select a node" - - -func get_value() -> NodePath: - #if _root and _selected: - # _full_path = String(_root.get_path_to(_selected)) - return _full_path - - -func _populate_tree() -> void: - _tree.clear() - var scene_root: Node = get_tree().get_edited_scene_root() - var editor_theme: Theme = get_editor_theme() - _create_items_recursive(scene_root, null, editor_theme) - - -func _create_items_recursive(node: Node, parent: TreeItem, editor_theme: Theme) -> void: - if parent and not node.owner: - return # Hidden node. - - var node_item = _tree.create_item(parent) - node_item.set_text(0, node.get_name()) - node_item.set_meta("node", node) - - var node_icon: Texture2D - var node_class := node.get_class() - if is_instance_valid(editor_theme): - if editor_theme.has_icon(node_class, "EditorIcons"): - node_icon = editor_theme.get_icon(node_class, "EditorIcons") - else: - node_icon = editor_theme.get_icon("Node", "EditorIcons") - node_item.set_icon(0, node_icon) - - for child in node.get_children(): - _create_items_recursive(child, node_item, editor_theme) - - -func _on_select_button_pressed() -> void: - _populate_tree() - _popup.popup_centered(Vector2i(400, 600)) - - -func _on_clear_button_pressed() -> void: - _select_button.text = "Select a node" - _full_path = NodePath() - - -func _on_node_selected(): - var node = _tree.get_selected().get_meta("node") - _set_value(_root.get_path_to(node)) - _on_value_changed(get_value()) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd.uid deleted file mode 100644 index c21301d..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ctxt1g763rfbf diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.tscn deleted file mode 100644 index baaff4b..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.tscn +++ /dev/null @@ -1,66 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bku7i3ct7ftui"] - -[ext_resource type="Texture2D" uid="uid://bosx22dy64f11" path="res://addons/proton_scatter/icons/clear.svg" id="1"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_node_selector.gd" id="2"] - -[node name="NodeSelector" type="MarginContainer"] -anchors_preset = 10 -anchor_right = 1.0 -script = ExtResource("2") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 2 -offset_right = 1152.0 -offset_bottom = 31.0 - -[node name="Label" type="Label" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -offset_top = 2.0 -offset_right = 560.0 -offset_bottom = 28.0 -size_flags_horizontal = 3 -text = "Parameter name" - -[node name="SelectButton" type="Button" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -offset_left = 564.0 -offset_right = 1124.0 -offset_bottom = 31.0 -size_flags_horizontal = 3 -text = "Select Node" -flat = true - -[node name="ClearButton" type="Button" parent="HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -offset_left = 1128.0 -offset_right = 1152.0 -offset_bottom = 31.0 -icon = ExtResource("1") - -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] -unique_name_in_owner = true -size = Vector2i(400, 500) - -[node name="ScrollContainer" type="ScrollContainer" parent="ConfirmationDialog"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -960.0 -offset_bottom = -597.0 - -[node name="Tree" type="Tree" parent="ConfirmationDialog/ScrollContainer"] -unique_name_in_owner = true -layout_mode = 2 -offset_right = 184.0 -offset_bottom = 43.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[connection signal="pressed" from="HBoxContainer/SelectButton" to="." method="_on_select_button_pressed"] -[connection signal="pressed" from="HBoxContainer/ClearButton" to="." method="_on_clear_button_pressed"] -[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_node_selected"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd deleted file mode 100644 index 43bef14..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd +++ /dev/null @@ -1,119 +0,0 @@ -# warning-ignore-all:return_value_discarded - -@tool -extends "base_parameter.gd" - - -var _is_int := false -var _is_enum := false - -@onready var _label: Label = $Label -@onready var _spinbox: SpinBox = $%SpinBox -@onready var _option: OptionButton = $%OptionButton - - -func _ready() -> void: - _spinbox.value_changed.connect(_on_value_changed) - _option.item_selected.connect(_on_value_changed) - mark_as_int(_is_int) - - -func mark_as_int(val: bool) -> void: - _is_int = val - if _is_int and _spinbox: - _spinbox.step = 1 - - -func mark_as_enum(val: bool) -> void: - _is_enum = val - - -func toggle_option_item(idx: int, value := false) -> void: - _option.set_item_disabled(idx, not value) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func set_hint_string(hint: String) -> void: - # No hint provided, ignore. - if hint.is_empty(): - return - - if hint == "float": - _spinbox.step = 0.01 - return - - if hint == "int": - _spinbox.step = 1 - return - - # One integer provided - if hint.is_valid_int(): - _set_range(0, hint.to_int()) - return - - # Multiple items provided, check their types - var tokens = hint.split(",") - var all_int = true - var all_float = true - - for t in tokens: - if not t.is_valid_int(): - all_int = false - if not t.is_valid_float(): - all_float = false - - # All items are integer - if all_int and tokens.size() >= 2: - _set_range(tokens[0].to_int(), tokens[1].to_int()) - return - - # All items are float - if all_float: - if tokens.size() >= 2: - _set_range(tokens[0].to_float(), tokens[1].to_float()) - if tokens.size() >= 3: - _spinbox.step = tokens[2].to_float() - return - - # All items are strings, make it a dropdown - _spinbox.visible = false - _option.visible = true - _is_enum = true - _is_int = true - - for i in tokens.size(): - _option.add_item(_sanitize_option_name(tokens[i]), i) - - set_value(int(_spinbox.get_value())) - - -func get_value(): - if _is_enum: - return _option.get_selected_id() - if _is_int: - return int(_spinbox.get_value()) - return _spinbox.get_value() - - -func _set_value(val) -> void: - if _is_int: - val = int(val) - if _is_enum: - _option.select(val) - else: - _spinbox.set_value(val) - - -func _set_range(start, end) -> void: - if start < end: - _spinbox.min_value = start - _spinbox.max_value = end - _spinbox.allow_greater = false - _spinbox.allow_lesser = false - - -func _sanitize_option_name(token: String) -> String: - return token.left(token.find(":")) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd.uid deleted file mode 100644 index fe18760..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d4ilkjlibcrsh diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.tscn deleted file mode 100644 index dce7fe4..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.tscn +++ /dev/null @@ -1,55 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://bspbhkrpgak0e"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.gd" id="1"] - -[node name="ParameterScalar" type="HBoxContainer"] -anchors_preset = 10 -anchor_right = 1.0 -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -offset_top = 2.0 -offset_right = 1833.0 -offset_bottom = 28.0 -size_flags_horizontal = 3 -text = "Parameter name" - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 -offset_left = 1837.0 -offset_right = 1920.0 -offset_bottom = 31.0 -mouse_filter = 2 - -[node name="Panel" type="Panel" parent="MarginContainer"] -visible = false -layout_mode = 2 -offset_right = 83.0 -offset_bottom = 31.0 -mouse_filter = 2 - -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] -layout_mode = 2 -offset_right = 83.0 -offset_bottom = 31.0 -mouse_filter = 2 - -[node name="SpinBox" type="SpinBox" parent="MarginContainer/MarginContainer"] -unique_name_in_owner = true -layout_mode = 2 -offset_right = 83.0 -offset_bottom = 31.0 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="OptionButton" type="OptionButton" parent="MarginContainer/MarginContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -offset_right = 83.0 -offset_bottom = 31.0 -focus_mode = 0 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd deleted file mode 100644 index 390d07d..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd +++ /dev/null @@ -1,27 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $Label -@onready var _line_edit: LineEdit = $MarginContainer/MarginContainer/LineEdit - - -func _ready() -> void: - _line_edit.connect("text_entered", _on_value_changed) - _line_edit.connect("focus_exited", _on_focus_exited) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func _set_value(val: String) -> void: - _line_edit.text = val - - -func get_value() -> String: - return _line_edit.get_text() - - -func _on_focus_exited() -> void: - _on_value_changed(get_value()) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd.uid deleted file mode 100644 index 8297d9b..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chtujjcb1hwqi diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.tscn deleted file mode 100644 index 00fbce5..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.tscn +++ /dev/null @@ -1,56 +0,0 @@ -[gd_scene load_steps=4 format=3] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_string.gd" id="1"] - -[sub_resource type="StyleBoxFlat" id=1] -bg_color = Color( 0, 0, 0, 0.392157 ) - -[sub_resource type="StyleBoxFlat" id=2] -bg_color = Color( 0.6, 0.6, 0.6, 0 ) - -[node name="ParameterString" type="HBoxContainer"] -anchor_right = 1.0 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Label" type="Label" parent="."] -margin_top = 2.0 -margin_right = 638.0 -margin_bottom = 16.0 -size_flags_horizontal = 3 -text = "Parameter name" -valign = 1 - -[node name="MarginContainer" type="MarginContainer" parent="."] -margin_left = 642.0 -margin_right = 1280.0 -margin_bottom = 18.0 -mouse_filter = 2 -size_flags_horizontal = 3 - -[node name="Panel" type="Panel" parent="MarginContainer"] -margin_right = 638.0 -margin_bottom = 18.0 -mouse_filter = 2 -custom_styles/panel = SubResource( 1 ) - -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] -margin_right = 638.0 -margin_bottom = 18.0 -mouse_filter = 2 -custom_constants/margin_right = 4 -custom_constants/margin_top = 2 -custom_constants/margin_left = 4 -custom_constants/margin_bottom = 2 - -[node name="LineEdit" type="LineEdit" parent="MarginContainer/MarginContainer"] -margin_left = 4.0 -margin_top = 2.0 -margin_right = 634.0 -margin_bottom = 16.0 -mouse_filter = 1 -custom_styles/focus = SubResource( 2 ) -custom_styles/normal = SubResource( 2 ) -clear_button_enabled = true diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd deleted file mode 100644 index 7a90a73..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd +++ /dev/null @@ -1,47 +0,0 @@ -# warning-ignore-all:return_value_discarded - -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $Label -@onready var _x: SpinBox = $%X -@onready var _y: SpinBox = $%Y -@onready var _link: Button = $%LinkButton - - -func _ready() -> void: - _x.value_changed.connect(_on_spinbox_value_changed) - _y.value_changed.connect(_on_spinbox_value_changed) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func get_value() -> Vector2: - var vec2 = Vector2.ZERO - vec2.x = _x.get_value() - vec2.y = _y.get_value() - return vec2 - - -func _set_value(val: Vector2) -> void: - _x.set_value(val.x) - _y.set_value(val.y) - - -func _on_clear_pressed(): - var old = get_value() - set_value(Vector2.ZERO) - _previous = old - _on_value_changed(Vector2.ZERO) - - -func _on_spinbox_value_changed(value: float) -> void: - if _link.button_pressed: - var old = get_value() - set_value(Vector2(value, value)) - _previous = old - - _on_value_changed(get_value()) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd.uid deleted file mode 100644 index 85e6159..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cdsgn8ov4arue diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.tscn deleted file mode 100644 index e3872b7..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.tscn +++ /dev/null @@ -1,108 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bjn8ydwp80y7q"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector2.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://bosx22dy64f11" path="res://addons/proton_scatter/icons/clear.svg" id="2"] -[ext_resource type="Texture2D" uid="uid://gbrmse47gdxb" path="res://addons/proton_scatter/icons/link.svg" id="3_u2lry"] - -[node name="ParameterVector2" type="HBoxContainer"] -anchors_preset = 10 -anchor_right = 1.0 -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 5 -text = "Parameter name" - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 0 -mouse_filter = 2 - -[node name="Panel" type="Panel" parent="MarginContainer"] -layout_mode = 2 -mouse_filter = 2 - -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 0 -size_flags_vertical = 4 -mouse_filter = 2 -theme_override_constants/margin_left = 6 -theme_override_constants/margin_right = 6 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer"] -layout_mode = 2 - -[node name="GridContainer" type="GridContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer"] -modulate = Color(1, 0.447059, 0.368627, 1) -layout_mode = 2 -text = "x" - -[node name="X" type="SpinBox" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer2"] -modulate = Color(0.564706, 0.992157, 0.298039, 1) -layout_mode = 2 -text = "y" - -[node name="Y" type="SpinBox" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer2"] -unique_name_in_owner = true -layout_mode = 2 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="Control" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="ClearButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 4 -focus_mode = 0 -mouse_filter = 1 -icon = ExtResource("2") -flat = true - -[node name="Control2" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="LinkButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 4 -focus_mode = 0 -mouse_filter = 1 -toggle_mode = true -icon = ExtResource("3_u2lry") -flat = true - -[node name="Control3" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer/ClearButton" to="." method="_on_clear_pressed"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd deleted file mode 100644 index 55678c9..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd +++ /dev/null @@ -1,49 +0,0 @@ -@tool -extends "base_parameter.gd" - - -@onready var _label: Label = $Label -@onready var _x: SpinBox = $%X -@onready var _y: SpinBox = $%Y -@onready var _z: SpinBox = $%Z -@onready var _link: Button = $%LinkButton - - -func _ready() -> void: - _x.value_changed.connect(_on_spinbox_value_changed) - _y.value_changed.connect(_on_spinbox_value_changed) - _z.value_changed.connect(_on_spinbox_value_changed) - - -func set_parameter_name(text: String) -> void: - _label.text = text - - -func get_value() -> Vector3: - var vec3 = Vector3.ZERO - vec3.x = _x.get_value() - vec3.y = _y.get_value() - vec3.z = _z.get_value() - return vec3 - - -func _set_value(val: Vector3) -> void: - _x.set_value(val.x) - _y.set_value(val.y) - _z.set_value(val.z) - - -func _on_clear_pressed(): - var old = get_value() - set_value(Vector3.ZERO) - _previous = old - _on_value_changed(Vector3.ZERO) - - -func _on_spinbox_value_changed(value: float) -> void: - if _link.button_pressed: - var old = get_value() - set_value(Vector3(value, value, value)) - _previous = old - - _on_value_changed(get_value()) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd.uid deleted file mode 100644 index 82cc3c3..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcdforyxshl7s diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.tscn deleted file mode 100644 index a5c922c..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.tscn +++ /dev/null @@ -1,127 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cdpfgf0447ph4"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_vector3.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://bosx22dy64f11" path="res://addons/proton_scatter/icons/clear.svg" id="2"] -[ext_resource type="Texture2D" uid="uid://gbrmse47gdxb" path="res://addons/proton_scatter/icons/link.svg" id="3_gq2ti"] - -[node name="ParameterVector3" type="HBoxContainer"] -anchors_preset = 10 -anchor_right = 1.0 -script = ExtResource("1") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 5 -text = "Parameter name" - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 0 -mouse_filter = 2 - -[node name="Panel" type="Panel" parent="MarginContainer"] -layout_mode = 2 -mouse_filter = 2 - -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer"] -layout_mode = 2 -size_flags_horizontal = 0 -size_flags_vertical = 4 -mouse_filter = 2 -theme_override_constants/margin_left = 6 -theme_override_constants/margin_right = 6 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer"] -layout_mode = 2 - -[node name="GridContainer" type="GridContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer"] -modulate = Color(1, 0.447059, 0.368627, 1) -layout_mode = 2 -text = "x" - -[node name="X" type="SpinBox" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer2"] -modulate = Color(0.564706, 0.992157, 0.298039, 1) -layout_mode = 2 -text = "y" - -[node name="Y" type="SpinBox" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer2"] -unique_name_in_owner = true -layout_mode = 2 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="HBoxContainer3" type="HBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer3"] -modulate = Color(0.14902, 0.8, 1, 1) -layout_mode = 2 -text = "z" - -[node name="Z" type="SpinBox" parent="MarginContainer/MarginContainer/HBoxContainer/GridContainer/HBoxContainer3"] -unique_name_in_owner = true -layout_mode = 2 -mouse_filter = 1 -min_value = -100.0 -step = 0.001 -allow_greater = true -allow_lesser = true - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/MarginContainer/HBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 -alignment = 1 - -[node name="Control3" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="ClearButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 4 -focus_mode = 0 -mouse_filter = 1 -icon = ExtResource("2") -flat = true - -[node name="Control" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="LinkButton" type="Button" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 4 -focus_mode = 0 -mouse_filter = 1 -toggle_mode = true -icon = ExtResource("3_gq2ti") -flat = true - -[node name="Control2" type="Control" parent="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[connection signal="pressed" from="MarginContainer/MarginContainer/HBoxContainer/VBoxContainer/ClearButton" to="." method="_on_clear_pressed"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd deleted file mode 100644 index 1b46434..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd +++ /dev/null @@ -1,96 +0,0 @@ -@tool -extends Container - -# DragContainer -# Custom containner similar to a VBoxContainer, but the user can rearrange the -# children order via drag and drop. This is only used in the inspector plugin -# for the modifier stack and won't work with arbitrary control nodes. - - -signal child_moved(last_index: int, new_index: int) - - -var _separation: int = 0 -var _drag_offset = null -var _dragged_child = null -var _old_index: int -var _new_index: int -var _map := [] # Stores the y top position of each child in the stack - - -func _ready() -> void: - _separation = get_theme_constant("separation", "VBoxContainer") - - -func _notification(what): - if what == NOTIFICATION_SORT_CHILDREN or what == NOTIFICATION_RESIZED: - _update_layout() - - -func _can_drop_data(at_position, data) -> bool: - if data.get_parent() != self: - return false - - # Drag just started - if not _dragged_child: - _dragged_child = data - _drag_offset = at_position - data.position - _old_index = data.get_index() - _new_index = _old_index - - # Dragged control only follow the y mouse position - data.position.y = at_position.y - _drag_offset.y - - # Check if the children order should be changed - var computed_index = 0 - for pos_y in _map: - if pos_y > data.position.y - 16: - break - computed_index += 1 - - # Prevents edge case when dragging the last item below its current position - computed_index = clamp(computed_index, 0, get_child_count() - 1) - - if computed_index != data.get_index(): - move_child(data, computed_index) - _new_index = computed_index - - return true - - -# Called once at the end of the drag -func _drop_data(at_position, data) -> void: - _drag_offset = null - _dragged_child = null - _update_layout() - - if _old_index != _new_index: - child_moved.emit(_old_index, _new_index) - - -# Detects if the user drops the children outside the container and treats it -# as if the drop happened the moment the mouse left the container. -func _unhandled_input(event): - if not _dragged_child: - return - - if event is InputEventMouseButton and not event.pressed: - _drop_data(_dragged_child.position, _dragged_child) - - -func _update_layout() -> void: - _map.clear() - var offset := Vector2.ZERO - - for c in get_children(): - if c is Control: - _map.push_back(offset.y) - var child_min_size = c.get_combined_minimum_size() - var possible_space = Rect2(offset, Vector2(size.x, child_min_size.y)) - - if c != _dragged_child: - fit_child_in_rect(c, possible_space) - - offset.y += c.size.y + _separation - - custom_minimum_size.y = offset.y - _separation diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd.uid deleted file mode 100644 index e74e361..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b5tfpfqoylvm8 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd deleted file mode 100644 index 3a5cd3d..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd +++ /dev/null @@ -1,203 +0,0 @@ -@tool -extends Control - - -signal value_changed -signal removed -signal documentation_requested -signal duplication_requested - - -const ParameterBool := preload("./components/parameter_bool.tscn") -const ParameterScalar := preload("./components/parameter_scalar.tscn") -const ParameterNodeSelector = preload("./components/parameter_node_selector.tscn") -const ParameterFile = preload("./components/parameter_file.tscn") -const ParameterCurve = preload("./components/parameter_curve.tscn") -const ParameterBitmask = preload("./components/parameter_bitmask.tscn") -const ParameterString = preload("./components/parameter_string.tscn") -const ParameterVector3 = preload("./components/parameter_vector3.tscn") -const ParameterVector2 = preload("./components/parameter_vector2.tscn") -const PARAMETER_IGNORE_LIST := [ - "enabled", - "override_global_seed", - "custom_seed", - "restrict_height", - "reference_frame", - ] - -var _scatter -var _modifier - -@onready var _parameters: Control = $%ParametersRoot -@onready var _name: Label = $%ModifierName -@onready var _expand: Button = $%Expand -@onready var _enabled: Button = $%Enabled -@onready var _remove: Button = $%Remove -@onready var _warning: Button = $%Warning -@onready var _warning_dialog: AcceptDialog = $WarningDialog -@onready var _drag_control: Control = $%DragControl -@onready var _override_ui = $%OverrideGlobalSeed -@onready var _custom_seed_ui = $%CustomSeed -@onready var _restrict_height_ui = $%RestrictHeight -@onready var _transform_space_ui = $%TransformSpace - - -func _ready() -> void: - _name.text = name - _enabled.toggled.connect(_on_enable_toggled) - _remove.pressed.connect(_on_remove_pressed) - _warning.pressed.connect(_on_warning_icon_pressed) - _expand.toggled.connect(_on_expand_toggled) - $%MenuButton.get_popup().id_pressed.connect(_on_menu_item_pressed) - - -func _get_drag_data(at_position: Vector2): - var drag_control_position = _drag_control.global_position - global_position - var drag_rect := Rect2(drag_control_position, _drag_control.size) - if drag_rect.has_point(at_position): - return self - - return null - - -func set_root(val) -> void: - _scatter = val - - -# Loops through all exposed parameters and create an UI component for each of -# them. For special properties (listed in PARAMATER_IGNORE_LIST), a special -# UI is created. -func create_ui_for(modifier) -> void: - _modifier = modifier - _modifier.warning_changed.connect(_on_warning_changed) - _on_warning_changed() - - _name.text = modifier.display_name - _enabled.button_pressed = modifier.enabled - - # Enable or disable irrelevant controls for this modifier - _override_ui.enable(modifier.can_override_seed) - _restrict_height_ui.enable(modifier.can_restrict_height) - _transform_space_ui.mark_as_enum(true) - _transform_space_ui.toggle_option_item(0, modifier.global_reference_frame_available) - _transform_space_ui.toggle_option_item(1, modifier.local_reference_frame_available) - _transform_space_ui.toggle_option_item(2, modifier.individual_instances_reference_frame_available) - if not modifier.global_reference_frame_available and \ - not modifier.local_reference_frame_available and \ - not modifier.individual_instances_reference_frame_available: - _transform_space_ui.visible = false - - # Setup header connections - _override_ui.value_changed.connect(_on_parameter_value_changed.bind("override_global_seed", _override_ui)) - _custom_seed_ui.value_changed.connect(_on_parameter_value_changed.bind("custom_seed", _custom_seed_ui)) - _restrict_height_ui.value_changed.connect(_on_parameter_value_changed.bind("restrict_height", _restrict_height_ui)) - _transform_space_ui.value_changed.connect(_on_parameter_value_changed.bind("reference_frame", _transform_space_ui)) - - # Restore header values - _override_ui.set_value(modifier.override_global_seed) - _custom_seed_ui.set_value(modifier.custom_seed) - _restrict_height_ui.set_value(modifier.restrict_height) - _transform_space_ui.set_value(modifier.reference_frame) - - # Loop over the other properties and create a ui component for each of them - for property in modifier.get_property_list(): - if property.usage != PROPERTY_USAGE_DEFAULT + PROPERTY_USAGE_SCRIPT_VARIABLE: - continue - - if property.name in PARAMETER_IGNORE_LIST: - continue - - var parameter_ui - match property.type: - TYPE_BOOL: - parameter_ui = ParameterBool.instantiate() - TYPE_FLOAT: - parameter_ui = ParameterScalar.instantiate() - TYPE_INT: - if property.hint == PROPERTY_HINT_LAYERS_3D_PHYSICS: - parameter_ui = ParameterBitmask.instantiate() - else: - parameter_ui = ParameterScalar.instantiate() - parameter_ui.mark_as_int(true) - TYPE_STRING: - if property.hint_string == "File" or property.hint_string == "Texture": - parameter_ui = ParameterFile.instantiate() - else: - parameter_ui = ParameterString.instantiate() - TYPE_VECTOR3: - parameter_ui = ParameterVector3.instantiate() - TYPE_VECTOR2: - parameter_ui = ParameterVector2.instantiate() - TYPE_NODE_PATH: - parameter_ui = ParameterNodeSelector.instantiate() - parameter_ui.set_root(_scatter) - TYPE_OBJECT: - if property.class_name == &"Curve": - parameter_ui = ParameterCurve.instantiate() - - if parameter_ui: - _parameters.add_child(parameter_ui) - parameter_ui.set_parameter_name(property.name.capitalize()) - parameter_ui.set_value(modifier.get(property.name)) - parameter_ui.set_hint_string(property.hint_string) - parameter_ui.set_scatter(_scatter) - parameter_ui.value_changed.connect(_on_parameter_value_changed.bind(property.name, parameter_ui)) - - _expand.button_pressed = _modifier.expanded - - -func _restore_value(name, val, ui) -> void: - _modifier.set(name, val) - ui.set_value(val) - value_changed.emit() - - -func _on_expand_toggled(toggled: bool) -> void: - $%ParametersContainer.visible = toggled - _modifier.expanded = toggled - - -func _on_remove_pressed() -> void: - removed.emit() - - -func _on_parameter_value_changed(value, previous, parameter_name, ui) -> void: - if _scatter.undo_redo: - _scatter.undo_redo.create_action("Change value " + parameter_name.capitalize()) - _scatter.undo_redo.add_undo_method(self, "_restore_value", parameter_name, previous, ui) - _scatter.undo_redo.add_do_method(self, "_restore_value", parameter_name, value, ui) - _scatter.undo_redo.commit_action() - else: - _modifier.set(parameter_name, value) - value_changed.emit() - - -func _on_enable_toggled(pressed: bool): - _modifier.enabled = pressed - value_changed.emit() - - -func _on_removed_pressed() -> void: - removed.emit() - - -func _on_warning_changed() -> void: - var warning = _modifier.get_warning() - _warning.visible = (warning != "") - _warning_dialog.dialog_text = warning - - -func _on_warning_icon_pressed() -> void: - _warning_dialog.popup_centered() - - -func _on_menu_item_pressed(id) -> void: - match id: - 0: - documentation_requested.emit() - 2: - duplication_requested.emit() - 3: - _on_remove_pressed() - _: - pass diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd.uid deleted file mode 100644 index 58ee9bb..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cb3i5yx4klhre diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.tscn deleted file mode 100644 index 48206e0..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.tscn +++ /dev/null @@ -1,255 +0,0 @@ -[gd_scene load_steps=21 format=3 uid="uid://blpobpd0eweog"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/modifier_panel.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://cu2t8yylseggu" path="res://addons/proton_scatter/icons/arrow_right.svg" id="2_2djuo"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd" id="4"] -[ext_resource type="Texture2D" uid="uid://t8c6kjbvst0s" path="res://addons/proton_scatter/icons/arrow_down.svg" id="4_7nlfc"] -[ext_resource type="Texture2D" uid="uid://dahwdjl2er75o" path="res://addons/proton_scatter/icons/close.svg" id="5"] -[ext_resource type="Texture2D" uid="uid://n66mufjib4ds" path="res://addons/proton_scatter/icons/menu.svg" id="6_lmo8k"] -[ext_resource type="Texture2D" uid="uid://d2ajwyebaobjt" path="res://addons/proton_scatter/icons/duplicate.svg" id="7_f6nan"] -[ext_resource type="Texture2D" uid="uid://do8d3urxirjoa" path="res://addons/proton_scatter/icons/doc.svg" id="7_owhij"] -[ext_resource type="Texture2D" uid="uid://dj0y6peid681t" path="res://addons/proton_scatter/icons/warning.svg" id="9"] -[ext_resource type="Texture2D" uid="uid://ba6cx70dyeuhg" path="res://addons/proton_scatter/icons/drag_area.svg" id="9_t6pse"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd" id="10_ptukr"] -[ext_resource type="Texture2D" uid="uid://dmmefjvrdhf78" path="res://addons/proton_scatter/icons/dice.svg" id="11_qwhro"] -[ext_resource type="PackedScene" uid="uid://w6ycb4oveqhd" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_button.tscn" id="11_y7srw"] -[ext_resource type="Texture2D" uid="uid://cmvfdl1wnrw4" path="res://addons/proton_scatter/icons/restrict_volume.svg" id="12_lx60d"] -[ext_resource type="Texture2D" uid="uid://dt0ctlr32stnn" path="res://addons/proton_scatter/icons/local.svg" id="13_txjs8"] -[ext_resource type="PackedScene" uid="uid://c36gqn03pvlnr" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/header/parameter_spinbox.tscn" id="13_vhfch"] -[ext_resource type="Texture2D" uid="uid://p2v2cqm7k60o" path="res://addons/proton_scatter/icons/restrict_volume_lock.svg" id="15_0w0as"] -[ext_resource type="Texture2D" uid="uid://71efqwg3d70v" path="res://addons/proton_scatter/icons/global.svg" id="16_ocvvf"] -[ext_resource type="PackedScene" uid="uid://bspbhkrpgak0e" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/components/parameter_scalar.tscn" id="17_aoulv"] -[ext_resource type="Texture2D" uid="uid://vxd0iun0wq8i" path="res://addons/proton_scatter/icons/individual_instances.svg" id="19_ln8a3"] - -[node name="ModifierPanel" type="MarginContainer"] -anchors_preset = 10 -anchor_right = 1.0 -grow_horizontal = 2 -theme_type_variation = &"fg" -script = ExtResource("1") - -[node name="Panel" type="Panel" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="MarginContainer" type="MarginContainer" parent="."] -layout_mode = 2 -mouse_filter = 2 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 -metadata/_edit_layout_mode = 1 -metadata/_edit_use_custom_anchors = false - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -layout_mode = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 0 - -[node name="Expand" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Toggle the parameters view" -focus_mode = 0 -mouse_filter = 1 -toggle_mode = true -icon = ExtResource("2_2djuo") -flat = true -icon_alignment = 1 -script = ExtResource("4") -default_icon = ExtResource("2_2djuo") -pressed_icon = ExtResource("4_7nlfc") - -[node name="ModifierName" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -text = "ModifierPanel" -vertical_alignment = 1 -clip_text = true - -[node name="Buttons" type="HBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer"] -layout_mode = 2 -theme_override_constants/separation = 2 -alignment = 1 - -[node name="Warning" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -size_flags_horizontal = 0 -focus_mode = 0 -mouse_filter = 1 -icon = ExtResource("9") -flat = true - -[node name="MenuButton" type="MenuButton" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Show options" -icon = ExtResource("6_lmo8k") -item_count = 4 -popup/item_0/text = "Show documentation" -popup/item_0/icon = ExtResource("7_owhij") -popup/item_0/id = 0 -popup/item_1/text = "" -popup/item_1/id = 1 -popup/item_1/separator = true -popup/item_2/text = "Duplicate" -popup/item_2/icon = ExtResource("7_f6nan") -popup/item_2/id = 2 -popup/item_3/text = "Delete" -popup/item_3/icon = ExtResource("5") -popup/item_3/id = 3 - -[node name="Enabled" type="CheckBox" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Toggle the modifier. - -If the modifier is disabled, it will not contribute to the final result but will still remain in the stack. - -Use this feature to quickly see how the modifier affects the overall stack." -focus_mode = 0 -mouse_filter = 1 - -[node name="Remove" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_vertical = 4 -tooltip_text = "Delete the modifier. -This will remove it from the stack." -focus_mode = 0 -mouse_filter = 1 -icon = ExtResource("5") -flat = true -icon_alignment = 1 - -[node name="VSeparator" type="VSeparator" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -modulate = Color(1, 1, 1, 0.54902) -layout_mode = 2 - -[node name="DragControl" type="TextureRect" parent="MarginContainer/VBoxContainer/HBoxContainer/Buttons"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Drag and move this button to change the stack order. - -Modifiers are processed from top to bottom." -mouse_default_cursor_shape = 6 -texture = ExtResource("9_t6pse") -stretch_mode = 3 - -[node name="ParametersContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -theme_override_constants/margin_left = 3 -theme_override_constants/margin_top = 3 -theme_override_constants/margin_right = 3 -theme_override_constants/margin_bottom = 3 - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ParametersContainer"] -layout_mode = 2 - -[node name="ParametersRoot" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer"] -layout_mode = 2 - -[node name="CommonHeader" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 4 -alignment = 1 - -[node name="ExpandButton" type="MarginContainer" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader"] -layout_mode = 2 -script = ExtResource("10_ptukr") - -[node name="OverrideGlobalSeed" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton" instance=ExtResource("11_y7srw")] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="Button" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton/OverrideGlobalSeed" index="0"] -layout_mode = 2 -tooltip_text = "Random seed. - -Enable to force a custom seed on this modifier only. If this option is disabled, the Global Seed from the ProtonScatter node will be used instead." -icon = ExtResource("11_qwhro") -icon_alignment = 0 -default_icon = ExtResource("11_qwhro") -pressed_icon = ExtResource("11_qwhro") - -[node name="SpinBoxRoot" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton"] -visible = false -layout_mode = 2 -mouse_filter = 2 - -[node name="VSeparator" type="VSeparator" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton/SpinBoxRoot"] -modulate = Color(1, 1, 1, 0) -layout_mode = 2 -mouse_filter = 2 -theme_override_constants/separation = 28 - -[node name="CustomSeed" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton/SpinBoxRoot" instance=ExtResource("13_vhfch")] -unique_name_in_owner = true -layout_mode = 2 - -[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="RestrictHeight" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader" instance=ExtResource("11_y7srw")] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 1 -size_flags_vertical = 3 - -[node name="Button" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/RestrictHeight" index="0"] -layout_mode = 2 -tooltip_text = "Restrict height. - -If enabled, the modifier will try to remain in the local XZ plane instead of using the full volume defined by the ScatterShapes." -icon = ExtResource("12_lx60d") -default_icon = ExtResource("12_lx60d") -pressed_icon = ExtResource("15_0w0as") - -[node name="TransformSpace" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader" instance=ExtResource("17_aoulv")] -unique_name_in_owner = true -layout_mode = 2 - -[node name="Label" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/TransformSpace" index="0"] -visible = false -text = "" - -[node name="SpinBox" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/TransformSpace/MarginContainer/MarginContainer" index="0"] -visible = false - -[node name="OptionButton" parent="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/TransformSpace/MarginContainer/MarginContainer" index="1"] -visible = true -item_count = 3 -fit_to_longest_item = false -popup/item_0/text = "Global" -popup/item_0/icon = ExtResource("16_ocvvf") -popup/item_0/id = 0 -popup/item_1/text = "Local" -popup/item_1/icon = ExtResource("13_txjs8") -popup/item_1/id = 1 -popup/item_2/text = "Individual" -popup/item_2/icon = ExtResource("19_ln8a3") -popup/item_2/id = 2 - -[node name="WarningDialog" type="AcceptDialog" parent="."] -title = "Warning" -unresizable = true -popup_window = true - -[editable path="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/ExpandButton/OverrideGlobalSeed"] -[editable path="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/RestrictHeight"] -[editable path="MarginContainer/VBoxContainer/ParametersContainer/VBoxContainer/CommonHeader/TransformSpace"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd deleted file mode 100644 index 1d89240..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd +++ /dev/null @@ -1,14 +0,0 @@ -@tool -extends Control - - -@onready var _button: Button = $OverrideGlobalSeed/Button -@onready var _spinbox_root: Control = $SpinBoxRoot - - -func _ready(): - _button.toggled.connect(_on_toggled) - - -func _on_toggled(enabled: bool) -> void: - _spinbox_root.visible = enabled diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd.uid deleted file mode 100644 index f0b822b..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/override_seed_button.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bbv8h1l1l0v7d diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd deleted file mode 100644 index d02da8e..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd +++ /dev/null @@ -1,18 +0,0 @@ -@tool -extends Button - - -@export var default_icon: Texture -@export var pressed_icon: Texture - - -func _ready() -> void: - toggled.connect(_on_toggled) - _on_toggled(button_pressed) - - -func _on_toggled(pressed: bool) -> void: - if pressed: - icon = pressed_icon - else: - icon = default_icon diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd.uid deleted file mode 100644 index 3ab67e6..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/toggle_button.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://3vbt4fd5ayn4 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd deleted file mode 100644 index 2c73397..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd +++ /dev/null @@ -1,9 +0,0 @@ -@tool -extends VBoxContainer - - -@onready var label: Label = $Header/Label - - -func set_category_name(text) -> void: - label.text = text diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd.uid deleted file mode 100644 index 151d700..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://co05xraatr8vh diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.tscn deleted file mode 100644 index 690edec..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.tscn +++ /dev/null @@ -1,26 +0,0 @@ -[gd_scene load_steps=2 format=3] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/category.gd" id="1"] - -[node name="VBoxContainer" type="VBoxContainer"] -margin_right = 40.0 -margin_bottom = 40.0 -rect_pivot_offset = Vector2( -591.851, -77.5574 ) -size_flags_horizontal = 3 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Header" type="VBoxContainer" parent="."] -margin_right = 40.0 -margin_bottom = 22.0 - -[node name="Label" type="Label" parent="Header"] -margin_right = 40.0 -margin_bottom = 14.0 - -[node name="HSeparator" type="HSeparator" parent="Header"] -margin_top = 18.0 -margin_right = 40.0 -margin_bottom = 22.0 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd deleted file mode 100644 index 360c925..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd +++ /dev/null @@ -1,113 +0,0 @@ -@tool -extends PopupPanel - - -signal add_modifier - -var _modifiers := [] - -@onready var _category_root: Control = $MarginContainer/CategoryRoot - - -func _ready() -> void: - _rebuild_ui() - - -func _rebuild_ui(): - for c in _category_root.get_children(): - c.queue_free() - - _discover_modifiers() - for modifier in _modifiers: - var instance = modifier.new() - if instance.enabled: - var category = _get_or_create_category(instance.category) - var button = _create_button(instance.display_name) - category.add_child(button, true) - button.pressed.connect(_on_pressed.bind(modifier)) - - for category in _category_root.get_children(): - var header = category.get_child(0) - _sort_children_by_name(category) - category.move_child(header, 0) - - -func _create_button(display_name) -> Button: - var button = Button.new() - button.name = display_name - button.text = display_name - button.alignment = HORIZONTAL_ALIGNMENT_LEFT - return button - - -func _sort_children_by_name(node: Node) -> void: - var dict := {} - var names := [] - - for child in node.get_children(): - names.push_back(child.name) - dict[child.name] = child - - names.sort_custom(func(a, b): return String(a) < String(b)) - - for i in names.size(): - var n = names[i] - node.move_child(dict[n], i) - - -func _get_or_create_category(text: String) -> Control: - if _category_root.has_node(text): - return _category_root.get_node(text) as Control - - var c = preload("category.tscn").instantiate() - c.name = text - _category_root.add_child(c, true) - c.set_category_name(text) - return c - - -func _discover_modifiers() -> void: - if _modifiers.is_empty(): - var path = _get_root_folder() + "/src/modifiers/" - _discover_modifiers_recursive(path) - - -func _discover_modifiers_recursive(path) -> void: - var dir = DirAccess.open(path) - dir.list_dir_begin() - var path_root = dir.get_current_dir() + "/" - - while true: - var file = dir.get_next() - if file == "": - break - if file == "base_modifier.gd": - continue - if dir.current_is_dir(): - _discover_modifiers_recursive(path_root + file) - continue - if not file.ends_with(".gd") and not file.ends_with(".gdc"): - continue - - var full_path = path_root + file - var script = load(full_path) - if not script or not script.can_instantiate(): - print("Error: Failed to load script ", file) - continue - - _modifiers.push_back(script) - - dir.list_dir_end() - - -func _get_root_folder() -> String: - var script: Script = get_script() - var path: String = script.get_path().get_base_dir() - var folders = path.right(-6) # Remove the res:// - var tokens = folders.split('/') - return "res://" + tokens[0] + "/" + tokens[1] - - -func _on_pressed(modifier) -> void: - add_modifier.emit(modifier.new()) - visible = false diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd.uid deleted file mode 100644 index 008a430..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dr5nhbideb30j diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.tscn deleted file mode 100644 index 644d361..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.tscn +++ /dev/null @@ -1,20 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://belutr5odecw2"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.gd" id="1"] - -[node name="ModifiersPopup" type="PopupPanel"] -size = Vector2i(597, 322) -visible = true -script = ExtResource("1") - -[node name="MarginContainer" type="MarginContainer" parent="."] -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -offset_top = 4.0 -offset_right = -431.0 -offset_bottom = -282.0 - -[node name="CategoryRoot" type="HBoxContainer" parent="MarginContainer"] -offset_right = 589.0 -offset_bottom = 314.0 diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd deleted file mode 100644 index 0c8306c..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd +++ /dev/null @@ -1,87 +0,0 @@ -@tool -extends Window - - -signal load_preset -signal delete_preset - - -@onready var _no_presets: Label = $MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/NoPresets -@onready var _root: VBoxContainer = $MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot -@onready var _confirmation_dialog: ConfirmationDialog = $ConfirmationDialog - -var _selected: String -var _selected_ui: Node - - -func _ready(): - _rebuild_ui() - about_to_popup.connect(_rebuild_ui) - - -func _rebuild_ui(): - for c in _root.get_children(): - c.queue_free() - _root.visible = false - - var presets = _find_all_presets() - if presets.empty(): - _no_presets.visible = true - return - - _no_presets.visible = false - _root.visible = true - for p in presets: - var ui = preload("./preset.tscn").instantiate() - _root.add_child(ui) - ui.set_preset_name(p) - ui.load_preset.connect(_on_load_preset.bind(p)) - ui.delete_preset.connect(_on_delete_preset.bind(p, ui)) - - -func _find_all_presets() -> Array: - var root := _get_root_folder() + "/presets/" - var res := [] - var dir = DirAccess.open(root) - if not dir: - return res - - dir.list_dir_begin() - while true: - var file = dir.get_next() - if file == "": - break - - if file.ends_with(".tscn"): - res.push_back(file.get_basename()) - - dir.list_dir_end() - res.sort() - return res - - -func _get_root_folder() -> String: - var path: String = get_script().get_path().get_base_dir() - var folders = path.right(6) # Remove the res:// - var tokens = folders.split('/') - return "res://" + tokens[0] + "/" + tokens[1] - - -func _on_load_preset(preset_name) -> void: - emit_signal("load_preset", preset_name) - visible = false - - -func _on_delete_preset(preset_name, ui) -> void: - _selected = preset_name - _selected_ui = ui - _confirmation_dialog.popup_centered() - - -func _on_delete_preset_confirmed(): - DirAccess.remove_absolute(_get_root_folder() + "/presets/" + _selected + ".tscn") - _selected_ui.queue_free() - - -func _on_cancel_pressed(): - visible = false diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd.uid deleted file mode 100644 index 934d7d9..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cck2e6jvpjqcp diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.tscn deleted file mode 100644 index 7016386..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.tscn +++ /dev/null @@ -1,101 +0,0 @@ -[gd_scene load_steps=2 format=3] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/presets/load_preset.gd" id="1"] - -[node name="LoadPresetPopup" type="WindowDialog"] -visible = true -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -147.5 -margin_top = -156.5 -margin_right = 147.5 -margin_bottom = 156.5 -size_flags_horizontal = 5 -size_flags_vertical = 5 -window_title = "Load Presets" -resizable = true -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="MarginContainer" type="MarginContainer" parent="."] -anchor_right = 1.0 -anchor_bottom = 1.0 -custom_constants/margin_right = 8 -custom_constants/margin_top = 8 -custom_constants/margin_left = 8 -custom_constants/margin_bottom = 8 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -margin_left = 8.0 -margin_top = 8.0 -margin_right = 287.0 -margin_bottom = 305.0 -custom_constants/separation = 6 - -[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"] -margin_right = 279.0 -margin_bottom = 271.0 -size_flags_vertical = 3 -scroll_horizontal_enabled = false - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"] -margin_right = 279.0 -margin_bottom = 271.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="NoPresets" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer"] -visible = false -margin_right = 247.0 -margin_bottom = 118.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 -text = "No presets found. - -Create new presets by pressing the \"Save Preset\" button first." -valign = 1 -autowrap = true - -[node name="PresetsRoot" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer"] -margin_right = 279.0 -margin_bottom = 271.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] -margin_left = 112.0 -margin_top = 277.0 -margin_right = 166.0 -margin_bottom = 297.0 -size_flags_horizontal = 4 - -[node name="CancelButton" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] -margin_right = 54.0 -margin_bottom = 20.0 -text = "Cancel" - -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] -visible = true -margin_left = -320.0 -margin_top = 37.0 -margin_right = -120.0 -margin_bottom = 112.0 -dialog_text = "Delete preset? -(This action can't be undone)" -__meta__ = { -"_edit_use_anchors_": false -} - -[connection signal="pressed" from="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset" to="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset" method="_on_pressed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset2" to="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset2" method="_on_pressed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset3" to="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset3" method="_on_pressed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset4" to="MarginContainer/VBoxContainer/ScrollContainer/VBoxContainer/PresetsRoot/Preset4" method="_on_pressed"] -[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/CancelButton" to="." method="_on_cancel_pressed"] -[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_delete_preset_confirmed"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd deleted file mode 100644 index 26cc06a..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd +++ /dev/null @@ -1,21 +0,0 @@ -@tool -extends Button - - -signal load_preset -signal delete_preset - - -@onready var _label: Label = $MarginContainer/HBoxContainer/Label - - -func set_preset_name(text) -> void: - _label.text = text - - -func _on_pressed() -> void: - load_preset.emit() - - -func _on_delete() -> void: - delete_preset.emit() diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd.uid deleted file mode 100644 index 055f099..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dv08hctybt01f diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.tscn deleted file mode 100644 index 967db9a..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.tscn +++ /dev/null @@ -1,54 +0,0 @@ -[gd_scene load_steps=3 format=3] - -[ext_resource type="Texture" uid="uid://dahwdjl2er75o" path="res://addons/proton_scatter/icons/close.svg" id="1"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/presets/preset.gd" id="2"] - -[node name="Preset" type="Button"] -anchor_top = 0.5 -anchor_right = 1.0 -anchor_bottom = 0.5 -margin_top = -10.0 -margin_bottom = 29.0 -rect_min_size = Vector2( 0, 40 ) -focus_mode = 0 -script = ExtResource( 2 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="MarginContainer" type="MarginContainer" parent="."] -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 -custom_constants/margin_right = 6 -custom_constants/margin_top = 6 -custom_constants/margin_left = 6 -custom_constants/margin_bottom = 6 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] -margin_left = 6.0 -margin_top = 6.0 -margin_right = 1274.0 -margin_bottom = 34.0 - -[node name="Label" type="Label" parent="MarginContainer/HBoxContainer"] -margin_top = 7.0 -margin_right = 1236.0 -margin_bottom = 21.0 -size_flags_horizontal = 3 -text = "Preset name" -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Delete" type="Button" parent="MarginContainer/HBoxContainer"] -margin_left = 1240.0 -margin_right = 1268.0 -margin_bottom = 28.0 -icon = ExtResource( 1 ) - -[connection signal="pressed" from="." to="." method="_on_pressed"] -[connection signal="pressed" from="MarginContainer/HBoxContainer/Delete" to="." method="_on_delete"] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd deleted file mode 100644 index 91cfed0..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd +++ /dev/null @@ -1,78 +0,0 @@ -@tool -extends Window - - -signal save_preset - - -@onready var _line_edit: LineEdit = $MarginContainer/VBoxContainer/LineEdit -@onready var _cancel: Button = $MarginContainer/VBoxContainer/HBoxContainer/Cancel -@onready var _save: Button = $MarginContainer/VBoxContainer/HBoxContainer/Save -@onready var _warning: Label = $MarginContainer/VBoxContainer/Warning -@onready var _confirm_overwrite = $ConfirmationDialog - - -func _ready(): - _cancel.pressed.connect(_on_cancel_pressed) - _save.pressed.connect(_on_save_pressed) - _warning.text = "" - _confirm_overwrite.confirmed.connect(_save_preset) - - -func _on_cancel_pressed() -> void: - visible = false - _line_edit.text = "" - - -func _on_save_pressed() -> void: - var preset_name: String = _line_edit.text - if preset_name.is_empty(): - _warning.text = "Preset name can't be empty" - return - - if not preset_name.is_valid_filename(): - _warning.text = """Preset name must be a valid file name. - It cannot contain the following characters: - : / \\ ? * " | % < >""" - return - - _warning.text = "" - if _exists(preset_name): - _confirm_overwrite.dialog_text = "Preset \"" + preset_name + "\" already exists. Overwrite?" - _confirm_overwrite.popup_centered() - else: - _save_preset() - - -func _save_preset() -> void: - emit_signal("save_preset", _line_edit.text) - visible = false - _line_edit.text = "" - - -func _exists(preset: String) -> bool: - var dir = DirAccess.open(_get_root_folder() + "/presets/") - if not dir: - return false - - dir.list_dir_begin() - - while true: - var file = dir.get_next() - if file == "": - break - - if file == preset + ".tscn": - dir.list_dir_end() - return true - - dir.list_dir_end() - return false - - -func _get_root_folder() -> String: - var script: Script = get_script() - var path: String = script.get_path().get_base_dir() - var folders = path.right(6) # Remove the res:// - var tokens = folders.split('/') - return "res://" + tokens[0] + "/" + tokens[1] diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd.uid deleted file mode 100644 index e77ca80..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://sfqwxxoe6dlm diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.tscn deleted file mode 100644 index 65e7922..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.tscn +++ /dev/null @@ -1,96 +0,0 @@ -[gd_scene load_steps=2 format=3] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/presets/save_preset.gd" id="1"] - -[node name="SavePresetPopup" type="WindowDialog"] -visible = true -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -180.0 -margin_top = -81.0 -margin_right = 180.0 -margin_bottom = 81.0 -size_flags_horizontal = 5 -size_flags_vertical = 5 -window_title = "Save Preset" -resizable = true -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="MarginContainer" type="MarginContainer" parent="."] -anchor_right = 1.0 -anchor_bottom = 1.0 -custom_constants/margin_right = 24 -custom_constants/margin_top = 4 -custom_constants/margin_left = 24 -custom_constants/margin_bottom = 24 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] -margin_left = 24.0 -margin_top = 4.0 -margin_right = 336.0 -margin_bottom = 120.0 -size_flags_vertical = 0 -custom_constants/separation = 12 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Warning" type="Label" parent="MarginContainer/VBoxContainer"] -modulate = Color( 1, 0.513726, 0.278431, 1 ) -margin_right = 312.0 -margin_bottom = 48.0 -text = "Preset name must be a valid file name. -It cannot contain the following characters: -: / \\\\ ? * \" | % < >" -valign = 2 -autowrap = true - -[node name="LineEdit" type="LineEdit" parent="MarginContainer/VBoxContainer"] -margin_top = 60.0 -margin_right = 312.0 -margin_bottom = 84.0 -placeholder_text = "Preset Name" -caret_blink = true - -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"] -margin_top = 96.0 -margin_right = 312.0 -margin_bottom = 116.0 -custom_constants/separation = 24 -alignment = 1 - -[node name="Cancel" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] -margin_left = 96.0 -margin_right = 150.0 -margin_bottom = 20.0 -text = "Cancel" - -[node name="Save" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"] -margin_left = 174.0 -margin_right = 215.0 -margin_bottom = 20.0 -text = "Save" - -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] -visible = true -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -135.0 -margin_top = -44.0 -margin_right = 135.0 -margin_bottom = 44.0 -window_title = "Overwrite existing preset?" -dialog_autowrap = true -__meta__ = { -"_edit_use_anchors_": false -} diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd deleted file mode 100644 index 80b03fa..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd +++ /dev/null @@ -1,159 +0,0 @@ -@tool -extends Control - - -const ModifierPanel := preload("./modifier/modifier_panel.tscn") - - -@onready var _modifiers_container: Control = $%ModifiersContainer -@onready var _modifiers_popup: PopupPanel = $%ModifiersPopup - -var _scatter -var _modifier_stack -var _undo_redo -var _is_ready := false - - -func _ready(): - _modifiers_popup.add_modifier.connect(_on_modifier_added) - _modifiers_container.child_moved.connect(_on_modifier_moved) - %Rebuild.pressed.connect(_on_rebuild_pressed) - %DocumentationButton.pressed.connect(_on_documentation_requested.bind("ProtonScatter")) - %LoadPreset.pressed.connect(_on_load_preset_pressed) - %SavePreset.pressed.connect(_on_save_preset_pressed) - - _is_ready = true - rebuild_ui() - - -func set_node(node) -> void: - if not node: - return - - _scatter = node - _undo_redo = _scatter.undo_redo - %Documentation.set_editor_plugin(_scatter.editor_plugin) - %Presets.set_editor_plugin(_scatter.editor_plugin) - rebuild_ui() - - -func rebuild_ui() -> void: - if not _is_ready: - return - - _validate_stack_connections() - _clear() - for m in _modifier_stack.stack: - var ui = ModifierPanel.instantiate() - _modifiers_container.add_child(ui) - ui.set_root(_scatter) - ui.create_ui_for(m) - ui.removed.connect(_on_modifier_removed.bind(m)) - ui.value_changed.connect(_on_value_changed) - ui.documentation_requested.connect(_on_documentation_requested.bind(m.display_name)) - ui.duplication_requested.connect(_on_modifier_duplicated.bind(m)) - - -func _clear() -> void: - for c in _modifiers_container.get_children(): - _modifiers_container.remove_child(c) - c.queue_free() - - -func _validate_stack_connections() -> void: - if not _scatter: - return - - if _modifier_stack: - _modifier_stack.stack_changed.disconnect(_on_stack_changed) - - _modifier_stack = _scatter.modifier_stack - _modifier_stack.stack_changed.connect(_on_stack_changed) - - if _modifier_stack.just_created: - %Presets.load_default(_scatter) - _modifier_stack.just_created = false - rebuild_ui() - - -func _set_children_owner(new_owner: Node, node: Node): - for child in node.get_children(): - child.set_owner(new_owner) - if child.get_children().size() > 0: - _set_children_owner(new_owner, child) - - -func _get_root_folder() -> String: - var path: String = get_script().get_path().get_base_dir() - var folders = path.right(6) # Remove the res:// - var tokens = folders.split('/') - return "res://" + tokens[0] + "/" + tokens[1] - - -func _on_modifier_added(modifier) -> void: - if _undo_redo: - _undo_redo.create_action("Create modifier " + modifier.display_name) - _undo_redo.add_undo_method(_modifier_stack, "remove", modifier) - _undo_redo.add_do_method(_modifier_stack, "add", modifier) - _undo_redo.commit_action() - else: - _modifier_stack.add(modifier) - - -func _on_modifier_moved(old_index: int, new_index: int) -> void: - if _undo_redo: - _undo_redo.create_action("Move modifier") - _undo_redo.add_undo_method(_modifier_stack, "move", new_index, old_index) - _undo_redo.add_do_method(_modifier_stack, "move", old_index, new_index) - _undo_redo.commit_action() - else: - _modifier_stack.move(old_index, new_index) - - -func _on_modifier_removed(modifier) -> void: - if _undo_redo: - _undo_redo.create_action("Remove modifier " + modifier.display_name) - _undo_redo.add_undo_method(_modifier_stack, "add", modifier) - _undo_redo.add_do_method(_modifier_stack, "remove", modifier) - _undo_redo.commit_action() - else: - _modifier_stack.remove(modifier) - - -func _on_modifier_duplicated(modifier) -> void: - var index = _modifier_stack.get_index(modifier) - if index == -1: - return - - if _undo_redo: - _undo_redo.create_action("Duplicate modifier " + modifier.display_name) - _undo_redo.add_undo_method(_modifier_stack, "remove_at", index + 1) - _undo_redo.add_do_method(_modifier_stack, "duplicate_modifier", modifier) - _undo_redo.commit_action() - else: - _modifier_stack.duplicate_modifier(modifier) - - -func _on_stack_changed() -> void: - rebuild_ui() - - -func _on_value_changed() -> void: - _modifier_stack.value_changed.emit() - - -func _on_rebuild_pressed() -> void: - if _scatter: - _scatter.full_rebuild() - - -func _on_save_preset_pressed() -> void: - %Presets.save_preset(_scatter) - - -func _on_load_preset_pressed() -> void: - %Presets.load_preset(_scatter) - - -func _on_documentation_requested(page_name) -> void: - %Documentation.show_page(page_name) diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd.uid b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd.uid deleted file mode 100644 index 0244dec..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cgu045kxxq2hy diff --git a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.tscn b/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.tscn deleted file mode 100644 index 5d7578c..0000000 --- a/godot/addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.tscn +++ /dev/null @@ -1,111 +0,0 @@ -[gd_scene load_steps=12 format=3 uid="uid://dllpt2dven8vw"] - -[ext_resource type="Texture2D" uid="uid://cun73k8jdmr4e" path="res://addons/proton_scatter/icons/add.svg" id="1_4vwtj"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/stack_panel.gd" id="1_ga4or"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier/drag_container.gd" id="1_hg5ys"] -[ext_resource type="Texture2D" uid="uid://yqlpvcmb7mfi" path="res://addons/proton_scatter/icons/rebuild.svg" id="2_svid4"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/add_modifier_button.gd" id="3_01ldn"] -[ext_resource type="PackedScene" uid="uid://belutr5odecw2" path="res://addons/proton_scatter/src/stack/inspector_plugin/ui/modifier_list_popup/popup.tscn" id="3_pkswu"] -[ext_resource type="Texture2D" uid="uid://ddjrq1h4mkn6a" path="res://addons/proton_scatter/icons/load.svg" id="3_w72lv"] -[ext_resource type="Texture2D" uid="uid://b2omj2e03x72e" path="res://addons/proton_scatter/icons/save.svg" id="4_5l2cx"] -[ext_resource type="Texture2D" uid="uid://do8d3urxirjoa" path="res://addons/proton_scatter/icons/doc.svg" id="8_fgqhd"] -[ext_resource type="PackedScene" uid="uid://cfg8iqtuion8b" path="res://addons/proton_scatter/src/documentation/documentation.tscn" id="9_y57kc"] -[ext_resource type="PackedScene" uid="uid://bcsosdvstytoq" path="res://addons/proton_scatter/src/presets/presets.tscn" id="11_2ut8s"] - -[node name="StackPanel" type="MarginContainer"] -clip_children = 1 -clip_contents = true -offset_right = 456.0 -offset_bottom = 144.0 -theme_override_constants/margin_left = 4 -theme_override_constants/margin_top = 4 -theme_override_constants/margin_right = 4 -theme_override_constants/margin_bottom = 4 -script = ExtResource("1_ga4or") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -layout_mode = 2 -theme_override_constants/separation = 16 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="Add" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 2 -focus_mode = 0 -toggle_mode = true -text = " Add modifier" -icon = ExtResource("1_4vwtj") -script = ExtResource("3_01ldn") - -[node name="ModifiersPopup" parent="VBoxContainer/HBoxContainer/Add" instance=ExtResource("3_pkswu")] -unique_name_in_owner = true -size = Vector2i(755, 322) -visible = false - -[node name="Rebuild" type="Button" parent="VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -size_flags_horizontal = 4 -tooltip_text = "Force rebuild. - -If the placed items does not look as expected, you can press this button to force it to regenerate the result. - -Usually, you shouldn't have to use it so please report it on Github if you found a case where it's necessary to click this. " -focus_mode = 0 -icon = ExtResource("2_svid4") -icon_alignment = 1 - -[node name="VSeparator" type="VSeparator" parent="VBoxContainer/HBoxContainer"] -modulate = Color(1, 1, 1, 0.54902) -layout_mode = 2 - -[node name="LoadPreset" type="Button" parent="VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Load a preset." -focus_mode = 0 -text = " -" -icon = ExtResource("3_w72lv") -icon_alignment = 1 - -[node name="SavePreset" type="Button" parent="VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Save a preset." -focus_mode = 0 -text = " -" -icon = ExtResource("4_5l2cx") -icon_alignment = 1 - -[node name="VSeparator2" type="VSeparator" parent="VBoxContainer/HBoxContainer"] -modulate = Color(1, 1, 1, 0.54902) -layout_mode = 2 - -[node name="DocumentationButton" type="Button" parent="VBoxContainer/HBoxContainer"] -unique_name_in_owner = true -layout_mode = 2 -tooltip_text = "Open documentation" -focus_mode = 0 -text = " -" -icon = ExtResource("8_fgqhd") -icon_alignment = 1 - -[node name="ModifiersContainer" type="Container" parent="VBoxContainer"] -unique_name_in_owner = true -clip_children = 1 -custom_minimum_size = Vector2(0, -4) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 0 -script = ExtResource("1_hg5ys") - -[node name="Documentation" parent="." instance=ExtResource("9_y57kc")] -unique_name_in_owner = true - -[node name="Presets" parent="." instance=ExtResource("11_2ut8s")] -unique_name_in_owner = true diff --git a/godot/addons/proton_scatter/src/stack/modifier_stack.gd b/godot/addons/proton_scatter/src/stack/modifier_stack.gd deleted file mode 100644 index 21f7f31..0000000 --- a/godot/addons/proton_scatter/src/stack/modifier_stack.gd +++ /dev/null @@ -1,97 +0,0 @@ -@tool -class_name ProtonScatterModifierStack -extends Resource - - -signal stack_changed -signal value_changed -signal transforms_ready - - -const TransformList := preload("../common/transform_list.gd") - - -@export var stack: Array[ScatterBaseModifier] = [] - -var just_created := false -var parent: ProtonScatter - - -func start_update(scatter_node: ProtonScatter, domain): - var transforms = TransformList.new() - - for modifier in stack: - await modifier.process_transforms(transforms, domain, scatter_node.global_seed) - - transforms_ready.emit(transforms) - return transforms - - -func stop_update() -> void: - for modifier in stack: - modifier.interrupt() - - -func add(modifier: ScatterBaseModifier) -> void: - stack.push_back(modifier) - modifier.modifier_changed.connect(_on_modifier_changed) - stack_changed.emit() - - -func move(old_index: int, new_index: int) -> void: - var modifier = stack.pop_at(old_index) - stack.insert(new_index, modifier) - stack_changed.emit() - - -func remove(modifier: ScatterBaseModifier) -> void: - if stack.has(modifier): - stack.erase(modifier) - stack_changed.emit() - - -func remove_at(index: int) -> void: - if stack.size() > index: - stack.remove_at(index) - stack_changed.emit() - - -func duplicate_modifier(modifier: ScatterBaseModifier) -> void: - var index: int = stack.find(modifier) - if index != -1: - var copy = modifier.get_copy() - add(copy) - move(stack.size() - 1, index + 1) - - -func get_copy(): - var copy = get_script().new() - for modifier in stack: - copy.add(modifier.duplicate()) - return copy - - -func get_index(modifier: ScatterBaseModifier) -> int: - return stack.find(modifier) - - -func is_using_edge_data() -> bool: - for modifier in stack: - if modifier.use_edge_data: - return true - - return false - - -# Returns true if at least one modifier does not require shapes in order to work. -# (This is the case for the "Add single item" modifier for example) -func does_not_require_shapes() -> bool: - for modifier in stack: - if modifier.warning_ignore_no_shape: - return true - - return false - - -func _on_modifier_changed() -> void: - stack_changed.emit() diff --git a/godot/addons/proton_scatter/src/stack/modifier_stack.gd.uid b/godot/addons/proton_scatter/src/stack/modifier_stack.gd.uid deleted file mode 100644 index 40bdd7b..0000000 --- a/godot/addons/proton_scatter/src/stack/modifier_stack.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://70icfoyxghmi diff --git a/godot/addons/proton_scatter/tests/unit_testing.tscn b/godot/addons/proton_scatter/tests/unit_testing.tscn deleted file mode 100644 index bb677ef..0000000 --- a/godot/addons/proton_scatter/tests/unit_testing.tscn +++ /dev/null @@ -1,2003 +0,0 @@ -[gd_scene load_steps=205 format=3 uid="uid://chgskywnqfgv"] - -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter.gd" id="1_hld6g"] -[ext_resource type="Texture2D" uid="uid://6xc5b38d25gf" path="res://addons/proton_scatter/demos/assets/textures/grid.png" id="1_xpx1h"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/stack/modifier_stack.gd" id="2_y5xi5"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_random.gd" id="3_6h2s3"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_item.gd" id="4_w0gix"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/scatter_shape.gd" id="5_y7d7p"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/sphere_shape.gd" id="6_ma1h0"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_grid.gd" id="7_h0gb3"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_inside_poisson.gd" id="8_w8gx7"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_along_edge_random.gd" id="9_cbx3g"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_along_edge_even.gd" id="10_isy7v"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/box_shape.gd" id="11_36l2y"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/shapes/path_shape.gd" id="11_iwfud"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/create_along_edge_continuous.gd" id="13_x67hv"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/offset_scale.gd" id="14_tn7vn"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/single_item.gd" id="16_mv3jg"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/array.gd" id="16_u8nl4"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/randomize_transforms.gd" id="17_lon52"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/offset_position.gd" id="17_wnpjh"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/look_at.gd" id="19_ecgtl"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/offset_rotation.gd" id="19_iqrrv"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/clusterize.gd" id="19_kqhj3"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/project_on_geometry.gd" id="20_7q4m2"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/proxy.gd" id="21_5pgs0"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/relax.gd" id="21_h4uuj"] -[ext_resource type="Script" path="res://addons/proton_scatter/src/modifiers/remove_outside_shapes.gd" id="21_x4n8q"] -[ext_resource type="Shader" path="res://addons/proton_scatter/src/particles/example_random_motion.gdshader" id="27_vj2yt"] - -[sub_resource type="BoxMesh" id="BoxMesh_8ubhl"] -size = Vector3(50, 1, 50) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_sj82k"] -albedo_texture = ExtResource("1_xpx1h") -uv1_scale = Vector3(0.5, 0.5, 0.5) -uv1_triplanar = true - -[sub_resource type="BoxShape3D" id="BoxShape3D_bii4q"] -size = Vector3(50, 1, 50) - -[sub_resource type="Resource" id="Resource_a0khl"] -script = ExtResource("3_6h2s3") -amount = 15 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_8vei7"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_a0khl")]) - -[sub_resource type="Resource" id="Resource_g8bsm"] -script = ExtResource("6_ma1h0") -radius = 1.08202 - -[sub_resource type="Resource" id="Resource_mdhrf"] -script = ExtResource("3_6h2s3") -amount = 15 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_wajph"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_mdhrf")]) - -[sub_resource type="Resource" id="Resource_nwd3r"] -script = ExtResource("6_ma1h0") -radius = 1.08202 - -[sub_resource type="Resource" id="Resource_rityo"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.5, 0.5, 0.5) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_axkfo"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_rityo")]) - -[sub_resource type="Resource" id="Resource_y8aw6"] -script = ExtResource("6_ma1h0") -radius = 1.11573 - -[sub_resource type="Resource" id="Resource_gfasn"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.5, 0.5, 0.5) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_4lehm"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_gfasn")]) - -[sub_resource type="Resource" id="Resource_fr8ni"] -script = ExtResource("6_ma1h0") -radius = 1.11573 - -[sub_resource type="Resource" id="Resource_dvb4u"] -script = ExtResource("8_w8gx7") -radius = 0.5 -samples_before_rejection = 15 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_rfrgg"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_dvb4u")]) - -[sub_resource type="Resource" id="Resource_ve5u2"] -script = ExtResource("6_ma1h0") -radius = 1.3139 - -[sub_resource type="Resource" id="Resource_f2e4b"] -script = ExtResource("8_w8gx7") -radius = 0.5 -samples_before_rejection = 15 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_j4x61"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_f2e4b")]) - -[sub_resource type="Resource" id="Resource_gywyd"] -script = ExtResource("6_ma1h0") -radius = 1.3139 - -[sub_resource type="Resource" id="Resource_1knwg"] -script = ExtResource("9_cbx3g") -instance_count = 10 -align_to_path = false -align_up_axis = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_syjiv"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_1knwg")]) - -[sub_resource type="Resource" id="Resource_eofyd"] -script = ExtResource("6_ma1h0") -radius = 0.943292 - -[sub_resource type="Resource" id="Resource_f8pmu"] -script = ExtResource("9_cbx3g") -instance_count = 10 -align_to_path = true -align_up_axis = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_rrmii"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_f8pmu")]) - -[sub_resource type="Resource" id="Resource_yleso"] -script = ExtResource("6_ma1h0") -radius = 0.943292 - -[sub_resource type="Resource" id="Resource_hrm74"] -script = ExtResource("10_isy7v") -spacing = 1.0 -offset = 0.0 -align_to_path = false -align_up_axis = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_b1fel"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_hrm74")]) - -[sub_resource type="Resource" id="Resource_1vjos"] -script = ExtResource("6_ma1h0") -radius = 1.16056 - -[sub_resource type="Resource" id="Resource_18q2p"] -script = ExtResource("10_isy7v") -spacing = 1.0 -offset = 0.01 -align_to_path = true -align_up_axis = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_i6uqa"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_18q2p")]) - -[sub_resource type="Curve3D" id="Curve3D_5o4l7"] -_data = { -"points": PackedVector3Array(0, 0, 0, 0, 0, 0, -1.72569, 1.90735e-06, 1.38458, -1.14569, -0.489434, 0.0747547, 1.68253, 0.29301, 0.132956, 0.129681, 1.16573, -0.751579, 0, 0, 0, 0, 0, 0, 1.86491, -0.92083, 0.889172), -"tilts": PackedFloat32Array(0, 0, 0) -} -point_count = 3 - -[sub_resource type="Resource" id="Resource_jrwst"] -script = ExtResource("11_iwfud") -closed = false -thickness = 0.0 -curve = SubResource("Curve3D_5o4l7") - -[sub_resource type="Resource" id="Resource_42dco"] -script = ExtResource("13_x67hv") -item_length = 1.0 -ignore_slopes = false -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_877np"] -script = ExtResource("14_tn7vn") -operation = 1 -scale = Vector3(1, 1, 2.6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_uox5l"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_42dco"), SubResource("Resource_877np")]) - -[sub_resource type="Resource" id="Resource_1fk1d"] -script = ExtResource("6_ma1h0") -radius = 1.11462 - -[sub_resource type="Resource" id="Resource_07emv"] -script = ExtResource("11_36l2y") -size = Vector3(1, 1, 3.75316) - -[sub_resource type="Resource" id="Resource_nqb4l"] -script = ExtResource("16_mv3jg") -offset = Vector3(0, 0, 0) -rotation = Vector3(0, 0, 40) -scale = Vector3(1, 1, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_bw4o3"] -script = ExtResource("14_tn7vn") -operation = 1 -scale = Vector3(1, 2, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_3bvlc"] -script = ExtResource("16_u8nl4") -amount = 3 -min_amount = -1 -local_offset = true -offset = Vector3(0, 1, 0) -local_rotation = false -rotation = Vector3(0, 0, 0) -individual_rotation_pivots = true -rotation_pivot = Vector3(0, 0, 0) -local_scale = false -scale = Vector3(1, 1, 1) -randomize_indices = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_f6tel"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_nqb4l"), SubResource("Resource_bw4o3"), SubResource("Resource_3bvlc")]) - -[sub_resource type="Resource" id="Resource_02pho"] -script = ExtResource("16_mv3jg") -offset = Vector3(0, 1.187, 0) -rotation = Vector3(0, -31.942, 0) -scale = Vector3(1, 1, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_ec8t1"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_02pho")]) - -[sub_resource type="Resource" id="Resource_qtf2k"] -script = ExtResource("16_mv3jg") -offset = Vector3(0, 0, 0) -rotation = Vector3(45, 0, 0) -scale = Vector3(1, 2, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_mmyxv"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_qtf2k")]) - -[sub_resource type="Resource" id="Resource_73pjb"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.3, 0.4, 0.3) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_blv75"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_j0n8o"] -script = ExtResource("19_kqhj3") -mask = "res://addons/proton_scatter/masks/blinds.png" -mask_rotation = 0.0 -mask_offset = Vector2(0, 8.56) -mask_scale = Vector2(1, 1) -pixel_to_unit_ratio = 32.0 -remove_below = 0.1 -scale_transforms = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_1qaw8"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_73pjb"), SubResource("Resource_blv75"), SubResource("Resource_j0n8o")]) - -[sub_resource type="Resource" id="Resource_a5k4o"] -script = ExtResource("6_ma1h0") -radius = 2.02235 - -[sub_resource type="Resource" id="Resource_t8qwo"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.3, 0.4, 0.3) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_bbajx"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_mysoe"] -script = ExtResource("19_kqhj3") -mask = "res://addons/proton_scatter/masks/blinds.png" -mask_rotation = 0.0 -mask_offset = Vector2(0, 8.56) -mask_scale = Vector2(1, 1) -pixel_to_unit_ratio = 32.0 -remove_below = 0.4 -scale_transforms = false -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_lgfwt"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_t8qwo"), SubResource("Resource_bbajx"), SubResource("Resource_mysoe")]) - -[sub_resource type="Resource" id="Resource_y5kok"] -script = ExtResource("6_ma1h0") -radius = 2.02235 - -[sub_resource type="Resource" id="Resource_rvnu4"] -script = ExtResource("3_6h2s3") -amount = 20 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_1pc4a"] -script = ExtResource("17_lon52") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(0, 360, 0) -scale = Vector3(0, 0, 2) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_iv1l5"] -script = ExtResource("19_ecgtl") -target = Vector3(0, 1, 0) -up = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_1jtvd"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_rvnu4"), SubResource("Resource_1pc4a"), SubResource("Resource_iv1l5")]) - -[sub_resource type="Resource" id="Resource_cf36a"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[sub_resource type="Resource" id="Resource_lqllm"] -script = ExtResource("3_6h2s3") -amount = 20 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_utrbb"] -script = ExtResource("17_lon52") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(0, 360, 0) -scale = Vector3(0, 0, 2) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_lg2ny"] -script = ExtResource("19_ecgtl") -target = Vector3(0, 3, 0) -up = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_osg78"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_lqllm"), SubResource("Resource_utrbb"), SubResource("Resource_lg2ny")]) - -[sub_resource type="Resource" id="Resource_m5v8r"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[sub_resource type="Resource" id="Resource_lnjcs"] -script = ExtResource("3_6h2s3") -amount = 10 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_7rgdv"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(45, 30, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_2yqfv"] -script = ExtResource("17_wnpjh") -operation = 2 -position = Vector3(0, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ggowg"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_lnjcs"), SubResource("Resource_7rgdv"), SubResource("Resource_2yqfv")]) - -[sub_resource type="Resource" id="Resource_b0fis"] -script = ExtResource("6_ma1h0") -radius = 1.35585 - -[sub_resource type="Resource" id="Resource_kr5cl"] -script = ExtResource("3_6h2s3") -amount = 10 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_xhov2"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(45, 30, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_dpvhh"] -script = ExtResource("17_wnpjh") -operation = 0 -position = Vector3(-1, 1, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_4d70d"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_kr5cl"), SubResource("Resource_xhov2"), SubResource("Resource_dpvhh")]) - -[sub_resource type="Resource" id="Resource_kebi0"] -script = ExtResource("6_ma1h0") -radius = 0.948492 - -[sub_resource type="Resource" id="Resource_tj3qn"] -script = ExtResource("3_6h2s3") -amount = 10 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_culo7"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(45, 30, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_dcn1b"] -script = ExtResource("17_wnpjh") -operation = 1 -position = Vector3(1.158, 0.517, 1.055) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_j0g8b"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_tj3qn"), SubResource("Resource_culo7"), SubResource("Resource_dcn1b")]) - -[sub_resource type="Resource" id="Resource_f2qcq"] -script = ExtResource("6_ma1h0") -radius = 0.948492 - -[sub_resource type="Resource" id="Resource_5e2iu"] -script = ExtResource("3_6h2s3") -amount = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_5x3va"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(0, 360, 0) -scale = Vector3(0, 0, 0) -enabled = false -override_global_seed = true -custom_seed = 10 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_wxvdn"] -script = ExtResource("19_iqrrv") -operation = 1 -rotation = Vector3(0, 3.027, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ojwb1"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_5e2iu"), SubResource("Resource_5x3va"), SubResource("Resource_wxvdn")]) - -[sub_resource type="Resource" id="Resource_hp05y"] -script = ExtResource("6_ma1h0") -radius = 1.33379 - -[sub_resource type="Resource" id="Resource_eobi8"] -script = ExtResource("3_6h2s3") -amount = 10 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_drprl"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(40, 0, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_8bivh"] -script = ExtResource("14_tn7vn") -operation = 2 -scale = Vector3(1, 2.65, 1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ndd04"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_eobi8"), SubResource("Resource_drprl"), SubResource("Resource_8bivh")]) - -[sub_resource type="Resource" id="Resource_n0ty0"] -script = ExtResource("6_ma1h0") -radius = 1.44433 - -[sub_resource type="Resource" id="Resource_ufee4"] -script = ExtResource("3_6h2s3") -amount = 15 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_ghxnv"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = true -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_tml5i"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_ufee4"), SubResource("Resource_ghxnv")]) - -[sub_resource type="Resource" id="Resource_vq7kx"] -script = ExtResource("6_ma1h0") -radius = 1.42501 - -[sub_resource type="Resource" id="Resource_74wa8"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.6, 0.6, 0.6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_t2kop"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(0, 0, 0) -scale = Vector3(0, 2, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_gn4jn"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_5wv3k"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_74wa8"), SubResource("Resource_t2kop"), SubResource("Resource_gn4jn")]) - -[sub_resource type="Resource" id="Resource_nwkwt"] -script = ExtResource("6_ma1h0") -radius = 1.42501 - -[sub_resource type="Resource" id="Resource_itdfg"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.6, 1, 0.6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_3mnoc"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(0, 0, 0) -scale = Vector3(0, 3, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_sud0j"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = true -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_wcnr2"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_itdfg"), SubResource("Resource_3mnoc"), SubResource("Resource_sud0j")]) - -[sub_resource type="Resource" id="Resource_h12gh"] -script = ExtResource("6_ma1h0") -radius = 1.59874 - -[sub_resource type="Resource" id="Resource_sc6yw"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.6, 0.6, 0.6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_yfh80"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_p6kkt"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_sc6yw"), SubResource("Resource_yfh80")]) - -[sub_resource type="Resource" id="Resource_5ddch"] -script = ExtResource("6_ma1h0") -radius = 1.42501 - -[sub_resource type="Resource" id="Resource_mn02k"] -script = ExtResource("7_h0gb3") -spacing = Vector3(0.6, 0.6, 0.6) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_up1et"] -script = ExtResource("17_lon52") -position = Vector3(0, 0, 0) -rotation = Vector3(60, 360, 0) -scale = Vector3(0, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_eeqjr"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_66aqb"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_mn02k"), SubResource("Resource_up1et"), SubResource("Resource_eeqjr")]) - -[sub_resource type="Resource" id="Resource_phfha"] -script = ExtResource("6_ma1h0") -radius = 1.42501 - -[sub_resource type="Resource" id="Resource_0ovty"] -script = ExtResource("3_6h2s3") -amount = 20 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_hvbao"] -script = ExtResource("17_lon52") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_w1c4k"] -script = ExtResource("20_7q4m2") -ray_direction = Vector3(0, -1, 0) -ray_length = 5.0 -ray_offset = 5.0 -remove_points_on_miss = false -align_with_collision_normal = false -max_slope = 90.0 -collision_mask = 1 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_xxh5g"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_0ovty"), SubResource("Resource_hvbao"), SubResource("Resource_w1c4k")]) - -[sub_resource type="Resource" id="Resource_eifot"] -script = ExtResource("6_ma1h0") -radius = 1.6059 - -[sub_resource type="Resource" id="Resource_ycnav"] -script = ExtResource("21_5pgs0") -scatter_node = NodePath("../Source") -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_u7eis"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_ycnav")]) - -[sub_resource type="Resource" id="Resource_wowj4"] -script = ExtResource("6_ma1h0") -radius = 1.6059 - -[sub_resource type="Resource" id="Resource_se8q6"] -script = ExtResource("21_5pgs0") -scatter_node = NodePath("../Source") -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_18oia"] -script = ExtResource("21_h4uuj") -iterations = 3 -offset_step = 0.3 -consecutive_step_multiplier = 0.5 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_d7vu4"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_se8q6"), SubResource("Resource_18oia")]) - -[sub_resource type="Resource" id="Resource_82ud0"] -script = ExtResource("6_ma1h0") -radius = 1.6059 - -[sub_resource type="Resource" id="Resource_x2nmf"] -script = ExtResource("3_6h2s3") -amount = 30 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_4e7pm"] -script = ExtResource("17_lon52") -position = Vector3(0, 1, 0) -rotation = Vector3(0, 0, 40) -scale = Vector3(3, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_7up6y"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_x2nmf"), SubResource("Resource_4e7pm")]) - -[sub_resource type="Resource" id="Resource_7kw48"] -script = ExtResource("6_ma1h0") -radius = 1.62434 - -[sub_resource type="Resource" id="Resource_4grs6"] -script = ExtResource("3_6h2s3") -amount = 30 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_so4tv"] -script = ExtResource("17_lon52") -position = Vector3(0, 1.005, 0) -rotation = Vector3(0, 40, 0) -scale = Vector3(3, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_c2lcy"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_4grs6"), SubResource("Resource_so4tv")]) - -[sub_resource type="Resource" id="Resource_8al8a"] -script = ExtResource("6_ma1h0") -radius = 1.63711 - -[sub_resource type="Resource" id="Resource_2vim7"] -script = ExtResource("3_6h2s3") -amount = 30 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_jx3rx"] -script = ExtResource("17_lon52") -position = Vector3(0, 1.005, 0) -rotation = Vector3(0, 40, 100) -scale = Vector3(3, 0, 0) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_t34ex"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_2vim7"), SubResource("Resource_jx3rx")]) - -[sub_resource type="Resource" id="Resource_c5k2f"] -script = ExtResource("6_ma1h0") -radius = 1.74481 - -[sub_resource type="Resource" id="Resource_tlhxg"] -script = ExtResource("3_6h2s3") -amount = 30 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_cbe88"] -script = ExtResource("21_h4uuj") -iterations = 5 -offset_step = 0.3 -consecutive_step_multiplier = 0.6 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ncnfw"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_tlhxg"), SubResource("Resource_cbe88")]) - -[sub_resource type="Resource" id="Resource_pnh7s"] -script = ExtResource("6_ma1h0") -radius = 1.51674 - -[sub_resource type="Resource" id="Resource_68u82"] -script = ExtResource("3_6h2s3") -amount = 40 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_2fbms"] -script = ExtResource("21_h4uuj") -iterations = 5 -offset_step = 0.3 -consecutive_step_multiplier = 0.6 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_1wqmj"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_68u82"), SubResource("Resource_2fbms")]) - -[sub_resource type="Resource" id="Resource_lsc8o"] -script = ExtResource("6_ma1h0") -radius = 1.19268 - -[sub_resource type="Resource" id="Resource_cvv4j"] -script = ExtResource("3_6h2s3") -amount = 75 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_bcg1s"] -script = ExtResource("17_lon52") -position = Vector3(3, 1, 3) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_ditx6"] -script = ExtResource("21_x4n8q") -negative_shapes_only = false -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_rh222"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_cvv4j"), SubResource("Resource_bcg1s"), SubResource("Resource_ditx6")]) - -[sub_resource type="Resource" id="Resource_nnf16"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[sub_resource type="Resource" id="Resource_rq4m2"] -script = ExtResource("3_6h2s3") -amount = 50 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_hjmp1"] -script = ExtResource("17_lon52") -position = Vector3(2, 1, 2) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_14l50"] -script = ExtResource("21_x4n8q") -negative_shapes_only = true -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_thdr8"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_rq4m2"), SubResource("Resource_hjmp1"), SubResource("Resource_14l50")]) - -[sub_resource type="Resource" id="Resource_t87ux"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[sub_resource type="Resource" id="Resource_hu6l0"] -script = ExtResource("11_36l2y") -size = Vector3(8.28605, 3.84222, 3.07433) - -[sub_resource type="Resource" id="Resource_hcorr"] -script = ExtResource("3_6h2s3") -amount = 20 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_nvyeo"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_hcorr")]) - -[sub_resource type="Resource" id="Resource_t1kde"] -script = ExtResource("6_ma1h0") -radius = 1.38138 - -[sub_resource type="Resource" id="Resource_behou"] -script = ExtResource("3_6h2s3") -amount = 40 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_cidgu"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_behou")]) - -[sub_resource type="Resource" id="Resource_4qlye"] -script = ExtResource("11_36l2y") -size = Vector3(2.92705, 1, 2.59448) - -[sub_resource type="Resource" id="Resource_qsibf"] -script = ExtResource("3_6h2s3") -amount = 40 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 0 - -[sub_resource type="Resource" id="Resource_ywyj6"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_qsibf")]) - -[sub_resource type="Curve3D" id="Curve3D_mco2w"] -_data = { -"points": PackedVector3Array(0, 0, 0, 0, 0, 0, -1.0424, -7.15256e-07, 1.36102, 0, 0, 0, 0, 0, 0, -1.10198, -5.36442e-07, -1.0533, 0, 0, 0, 0, 0, 0, 1.9308, -4.17233e-07, -1.00552, 0, 0, 0, 0, 0, 0, 1.95377, -5.96046e-07, 1.38943, 0, 0, 0, 0, 0, 0, 0.818293, -0.042784, 1.50129, 0, 0, 0, 0, 0, 0, 0.752959, -1.19209e-07, -0.200405, 0, 0, 0, 0, 0, 0, -0.140599, -6.55651e-07, -0.126677, 0, 0, 0, 0, 0, 0, -0.0283718, -5.36442e-07, 1.38879), -"tilts": PackedFloat32Array(0, 0, 0, 0, 0, 0, 0, 0) -} -point_count = 8 - -[sub_resource type="Resource" id="Resource_acfig"] -script = ExtResource("11_iwfud") -closed = true -thickness = 0.0 -curve = SubResource("Curve3D_mco2w") - -[sub_resource type="Resource" id="Resource_e8esq"] -script = ExtResource("3_6h2s3") -amount = 75 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_p3662"] -script = ExtResource("17_lon52") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_yl5xk"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_e8esq"), SubResource("Resource_p3662")]) - -[sub_resource type="Resource" id="Resource_x5d01"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[sub_resource type="Resource" id="Resource_g6tkw"] -script = ExtResource("3_6h2s3") -amount = 75 -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = true -reference_frame = 1 - -[sub_resource type="Resource" id="Resource_4jaem"] -script = ExtResource("17_lon52") -position = Vector3(0.15, 0.15, 0.15) -rotation = Vector3(20, 360, 20) -scale = Vector3(0.1, 0.1, 0.1) -enabled = true -override_global_seed = false -custom_seed = 0 -restrict_height = false -reference_frame = 2 - -[sub_resource type="Resource" id="Resource_gavpu"] -script = ExtResource("2_y5xi5") -stack = Array[Resource]([SubResource("Resource_g6tkw"), SubResource("Resource_4jaem")]) - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_7sbin"] -shader = ExtResource("27_vj2yt") - -[sub_resource type="Resource" id="Resource_o7cnt"] -script = ExtResource("6_ma1h0") -radius = 2.0 - -[node name="UnitTesting" type="Node3D"] -editor_description = "This scene checks for regressions. - -Every modifier are used in different Scatter nodes in different configuration. The generated transforms are then compared to the expected results, and throw an error if they don't match." - -[node name="Label3D" type="Label3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.64562, -24.3968) -pixel_size = 0.1 -modulate = Color(0, 0, 0, 1) -outline_modulate = Color(1, 1, 1, 1) -text = "Unit testing scene" -font_size = 46 -outline_size = 6 -uppercase = true - -[node name="Floor" type="StaticBody3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) -metadata/_edit_lock_ = true -metadata/_edit_group_ = true - -[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor"] -mesh = SubResource("BoxMesh_8ubhl") -skeleton = NodePath("../..") -surface_material_override/0 = SubResource("StandardMaterial3D_sj82k") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor"] -shape = SubResource("BoxShape3D_bii4q") - -[node name="CreateInside" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 0, -20) - -[node name="Random" type="Marker3D" parent="CreateInside"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) - -[node name="RandomFullHeight" type="Node3D" parent="CreateInside/Random"] -transform = Transform3D(0.933968, 0.297336, -0.198231, -0.357358, 0.7771, -0.518085, 0, 0.554714, 0.832041, 0, 1, -3) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_8vei7") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Random/RandomFullHeight"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Random/RandomFullHeight"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_g8bsm") - -[node name="RandomFlat" type="Node3D" parent="CreateInside/Random"] -transform = Transform3D(0.963584, 0.267407, 0, -0.267407, 0.963584, 0, 0, 0, 1, 0, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_wajph") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Random/RandomFlat"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Random/RandomFlat"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_nwd3r") - -[node name="Grid" type="Marker3D" parent="CreateInside"] - -[node name="GridFullHeight" type="Node3D" parent="CreateInside/Grid"] -transform = Transform3D(0.840179, 0.54231, 0, -0.54231, 0.840179, 0, 0, 0, 1, -0.169834, 1.0354, -3) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_axkfo") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Grid/GridFullHeight"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Grid/GridFullHeight"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_y8aw6") - -[node name="GridFlat" type="Node3D" parent="CreateInside/Grid"] -transform = Transform3D(0.660834, 0.16392, -0.732412, -0.240753, 0.970586, 7.45058e-09, 0.710869, 0.176331, 0.680861, -0.0824013, -0.118199, -0.518734) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_4lehm") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Grid/GridFlat"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Grid/GridFlat"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_fr8ni") - -[node name="Poisson" type="Marker3D" parent="CreateInside"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0) - -[node name="PoissonFullHeight" type="Node3D" parent="CreateInside/Poisson"] -transform = Transform3D(0.886341, 0.433591, 0.162475, -0.463033, 0.829983, 0.311012, 0, -0.350894, 0.936415, 0, 1, -3) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_rfrgg") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Poisson/PoissonFullHeight"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Poisson/PoissonFullHeight"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_ve5u2") - -[node name="PoissonFlat" type="Node3D" parent="CreateInside/Poisson"] -transform = Transform3D(0.763511, 0.223726, -0.605803, -0.17526, 0.974652, 0.139059, 0.621558, 0, 0.783368, 0, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_j4x61") - -[node name="ScatterItem" type="Node3D" parent="CreateInside/Poisson/PoissonFlat"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateInside/Poisson/PoissonFlat"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_gywyd") - -[node name="CreateAlongEdge" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, 0, -20) - -[node name="Random" type="Marker3D" parent="CreateAlongEdge"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) - -[node name="EdgeRandom" type="Node3D" parent="CreateAlongEdge/Random"] -transform = Transform3D(0.980584, 0.1961, 0, -0.193582, 0.967992, -0.159743, -0.0313257, 0.156642, 0.987159, 0, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_syjiv") - -[node name="ScatterItem" type="Node3D" parent="CreateAlongEdge/Random/EdgeRandom"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape4" type="Node3D" parent="CreateAlongEdge/Random/EdgeRandom"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_eofyd") - -[node name="EdgeRandomAligned" type="Node3D" parent="CreateAlongEdge/Random"] -transform = Transform3D(0.980584, 0.1961, -4.76072e-09, -0.109104, 0.545565, -0.830936, -0.162947, 0.814802, 0.556368, 0, 0.876154, -3.21482) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_rrmii") - -[node name="ScatterItem" type="Node3D" parent="CreateAlongEdge/Random/EdgeRandomAligned"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape4" type="Node3D" parent="CreateAlongEdge/Random/EdgeRandomAligned"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_yleso") - -[node name="Even" type="Marker3D" parent="CreateAlongEdge"] - -[node name="EdgeEvenGlobal" type="Node3D" parent="CreateAlongEdge/Even"] -transform = Transform3D(0.813345, -0.581783, 0, 0.572633, 0.800553, -0.176655, 0.102775, 0.143682, 0.984273, 0, 0.434273, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_b1fel") - -[node name="ScatterItem" type="Node3D" parent="CreateAlongEdge/Even/EdgeEvenGlobal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateAlongEdge/Even/EdgeEvenGlobal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_1vjos") - -[node name="EdgeEvenAligned" type="Node3D" parent="CreateAlongEdge/Even"] -transform = Transform3D(0.9507, -0.310112, 0, 0.310112, 0.950699, 0, 0, 0, 0.999999, 0.72711, 0.89757, -3.66937) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_i6uqa") - -[node name="ScatterItem" type="Node3D" parent="CreateAlongEdge/Even/EdgeEvenAligned"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateAlongEdge/Even/EdgeEvenAligned"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_jrwst") - -[node name="Continuous" type="Marker3D" parent="CreateAlongEdge"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0) - -[node name="EdgeContinuous" type="Node3D" parent="CreateAlongEdge/Continuous"] -transform = Transform3D(0.983496, 0.180931, 0, -0.180931, 0.983496, 0, 0, 0, 1, 0.864534, 0.35345, -0.100313) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_uox5l") - -[node name="ScatterItem" type="Node3D" parent="CreateAlongEdge/Continuous/EdgeContinuous"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="CreateAlongEdge/Continuous/EdgeContinuous"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_1fk1d") - -[node name="ScatterShape2" type="Node3D" parent="CreateAlongEdge/Continuous/EdgeContinuous"] -transform = Transform3D(0.154969, 0, 0.987919, 0, 1, 0, -0.987919, 0, 0.154969, -0.0216227, -7.15256e-07, -1.22508) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_07emv") - -[node name="Array" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0, -6) - -[node name="ProtonScatter" type="Node3D" parent="Array"] -transform = Transform3D(0.86654, 0.499108, 0, -0.499108, 0.86654, 0, 0, 0, 1, -0.499108, 0.32282, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_f6tel") - -[node name="ScatterItem" type="Node3D" parent="Array/ProtonScatter"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="SingleItem" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, -20) - -[node name="SingleLocal" type="Node3D" parent="SingleItem"] -transform = Transform3D(0.379283, -0.0572998, -0.923505, 0.892876, 0.284492, 0.349051, 0.24273, -0.956965, 0.159065, 0, 0, -2) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ec8t1") - -[node name="ScatterItem" type="Node3D" parent="SingleItem/SingleLocal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="SingleGlobal" type="Node3D" parent="SingleItem"] -transform = Transform3D(0.837785, -0.49706, 0.225938, 0.429222, 0.855328, 0.290142, -0.337469, -0.146099, 0.92993, 0, 1.46238, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_mmyxv") - -[node name="ScatterItem" type="Node3D" parent="SingleItem/SingleGlobal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="Clusterize" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, -4) - -[node name="ClustertizeScale" type="Node3D" parent="Clusterize"] -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_1qaw8") - -[node name="ScatterItem" type="Node3D" parent="Clusterize/ClustertizeScale"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Clusterize/ClustertizeScale"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_a5k4o") - -[node name="ClustertizeFilterOnly" type="Node3D" parent="Clusterize"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_lgfwt") - -[node name="ScatterItem" type="Node3D" parent="Clusterize/ClustertizeFilterOnly"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Clusterize/ClustertizeFilterOnly"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_y5kok") - -[node name="LookAt" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 19, 0, -3) - -[node name="LookAtGlobal" type="Node3D" parent="LookAt"] -transform = Transform3D(0.633165, 0.774017, 0, -0.774017, 0.633165, 0, 0, 0, 1, 0, 1, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_1jtvd") - -[node name="ScatterItem" type="Node3D" parent="LookAt/LookAtGlobal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="LookAt/LookAtGlobal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_cf36a") - -[node name="LookAtLocal" type="Node3D" parent="LookAt"] -transform = Transform3D(0.633165, 0.774017, 0, -0.774017, 0.633165, 0, 0, 0, 1, 3, 1, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_osg78") - -[node name="ScatterItem" type="Node3D" parent="LookAt/LookAtLocal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="LookAt/LookAtLocal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_m5v8r") - -[node name="Edit" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18, 0, -14) - -[node name="Position" type="Marker3D" parent="Edit"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) - -[node name="PositionOverride" type="Node3D" parent="Edit/Position"] -transform = Transform3D(0.991119, 0.132978, -0.000208908, -0.129832, 0.967331, -0.217751, -0.0287538, 0.215845, 0.976004, 0, 0.776395, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ggowg") - -[node name="ScatterItem" type="Node3D" parent="Edit/Position/PositionOverride"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Edit/Position/PositionOverride"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_b0fis") - -[node name="PositionOffset" type="Node3D" parent="Edit/Position"] -transform = Transform3D(0.600074, 0.784618, -0.15584, -0.799427, 0.581195, -0.152084, -0.0287538, 0.215845, 0.976004, 0, 0.776395, 2) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_4d70d") - -[node name="ScatterItem" type="Node3D" parent="Edit/Position/PositionOffset"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Edit/Position/PositionOffset"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_kebi0") - -[node name="PositionMultiply" type="Node3D" parent="Edit/Position"] -transform = Transform3D(0.0734645, 0.937927, -0.338966, 0.698269, 0.194297, 0.688962, 0.712055, -0.287305, -0.64065, 0, 0.776395, -2.26686) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_j0g8b") - -[node name="ScatterItem" type="Node3D" parent="Edit/Position/PositionMultiply"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Edit/Position/PositionMultiply"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_f2qcq") - -[node name="Rotation" type="Marker3D" parent="Edit"] - -[node name="ProtonScatter" type="Node3D" parent="Edit/Rotation"] -transform = Transform3D(0.914149, 0.234926, 0.330366, -0.15162, 0.953952, -0.258819, -0.375957, 0.186509, 0.907673, 0, 1.44124, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ojwb1") - -[node name="ScatterItem" type="Node3D" parent="Edit/Rotation/ProtonScatter"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Edit/Rotation/ProtonScatter"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_hp05y") - -[node name="Scale" type="Marker3D" parent="Edit"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0) - -[node name="EditScale" type="Node3D" parent="Edit/Scale"] -transform = Transform3D(-0.542174, -0.339362, 0.768688, 0.430169, -0.897943, -0.093017, 0.721805, 0.280235, 0.632824, 0, 1.60134, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ndd04") - -[node name="ScatterItem" type="Node3D" parent="Edit/Scale/EditScale"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Edit/Scale/EditScale"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_n0ty0") - -[node name="ProjectOnCollider" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 0, -11) - -[node name="CSGSphere3D" type="CSGSphere3D" parent="ProjectOnCollider"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.990063, 0) -use_collision = true -radius = 1.85822 -radial_segments = 20 -rings = 12 - -[node name="ProjectAlign" type="Node3D" parent="ProjectOnCollider"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.07597, 0.67288, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_tml5i") - -[node name="ScatterItem" type="Node3D" parent="ProjectOnCollider/ProjectAlign"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="ProjectOnCollider/ProjectAlign"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_vq7kx") - -[node name="ProjectKeepOnMiss" type="Node3D" parent="ProjectOnCollider"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.70408, 0.67288, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_5wv3k") - -[node name="ScatterItem" type="Node3D" parent="ProjectOnCollider/ProjectKeepOnMiss"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="ProjectOnCollider/ProjectKeepOnMiss"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_nwkwt") - -[node name="ProjectRemoveOnMiss" type="Node3D" parent="ProjectOnCollider"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.01292, 0.67288, 3.00432) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_wcnr2") - -[node name="ScatterItem" type="Node3D" parent="ProjectOnCollider/ProjectRemoveOnMiss"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="ProjectOnCollider/ProjectRemoveOnMiss"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_h12gh") - -[node name="ProjectLocal" type="Node3D" parent="ProjectOnCollider"] -transform = Transform3D(0.959531, 0.281605, 0, -0.139156, 0.474156, -0.869374, -0.24482, 0.834191, 0.494154, -0.592215, 0.580088, 3.27421) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_p6kkt") - -[node name="ScatterItem" type="Node3D" parent="ProjectOnCollider/ProjectLocal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="ProjectOnCollider/ProjectLocal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_5ddch") - -[node name="ProjectIndividual" type="Node3D" parent="ProjectOnCollider"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.58267, 0.580088, 4.82817) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_66aqb") - -[node name="ScatterItem" type="Node3D" parent="ProjectOnCollider/ProjectIndividual"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="ProjectOnCollider/ProjectIndividual"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_phfha") - -[node name="Proxy" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, -9) - -[node name="Source" type="Node3D" parent="Proxy"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_xxh5g") - -[node name="ScatterItem" type="Node3D" parent="Proxy/Source"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Proxy/Source"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_eifot") - -[node name="Proxy" type="Node3D" parent="Proxy"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_u7eis") - -[node name="ScatterItem" type="Node3D" parent="Proxy/Proxy"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Proxy/Proxy"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_wowj4") - -[node name="ProxyWithExtras" type="Node3D" parent="Proxy"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_d7vu4") - -[node name="ScatterItem" type="Node3D" parent="Proxy/ProxyWithExtras"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Proxy/ProxyWithExtras"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_82ud0") - -[node name="RandomizeTransforms" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18, 0, -8) - -[node name="RandomizeGlobal" type="Node3D" parent="RandomizeTransforms"] -transform = Transform3D(0.966007, 0.230774, 0.116509, -0.204648, 0.958019, -0.200794, -0.157955, 0.170125, 0.972681, -4, 1.33719, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_7up6y") - -[node name="ScatterItem" type="Node3D" parent="RandomizeTransforms/RandomizeGlobal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="RandomizeTransforms/RandomizeGlobal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_7kw48") - -[node name="RandomizeLocal" type="Node3D" parent="RandomizeTransforms"] -transform = Transform3D(0.834487, -0.503621, 0.223599, 0.527903, 0.847008, -0.0624175, -0.157955, 0.170125, 0.972681, 1, 1.97163, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_c2lcy") - -[node name="ScatterItem" type="Node3D" parent="RandomizeTransforms/RandomizeLocal"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="RandomizeTransforms/RandomizeLocal"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_8al8a") - -[node name="RandomizeIndividual" type="Node3D" parent="RandomizeTransforms"] -transform = Transform3D(0.706801, 0.707356, -0.00893999, -0.689552, 0.68608, -0.231976, -0.157955, 0.170125, 0.972681, 5, 0.945867, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_t34ex") - -[node name="ScatterItem" type="Node3D" parent="RandomizeTransforms/RandomizeIndividual"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="RandomizeTransforms/RandomizeIndividual"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_c5k2f") - -[node name="Snap" type="Marker3D" parent="."] - -[node name="Relax" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9, 0, -14) - -[node name="RelaxRestrict" type="Node3D" parent="Relax"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.374658, 1.02338, 0.424611) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ncnfw") - -[node name="ScatterItem" type="Node3D" parent="Relax/RelaxRestrict"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Relax/RelaxRestrict"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_pnh7s") - -[node name="RelaxFull" type="Node3D" parent="Relax"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 1.02338, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_1wqmj") - -[node name="ScatterItem" type="Node3D" parent="Relax/RelaxFull"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Relax/RelaxFull"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_lsc8o") - -[node name="RemoveOutside" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 11, 0, -20) - -[node name="RemoveOutside" type="Node3D" parent="RemoveOutside"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.58539, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_rh222") - -[node name="ScatterItem" type="Node3D" parent="RemoveOutside/RemoveOutside"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="RemoveOutside/RemoveOutside"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_nnf16") - -[node name="RemoveNegativeOnly" type="Node3D" parent="RemoveOutside"] -transform = Transform3D(0.906404, 0, 0.422413, 0, 1, 0, -0.422413, 0, 0.906404, -6, 1.58539, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_thdr8") - -[node name="ScatterItem" type="Node3D" parent="RemoveOutside/RemoveNegativeOnly"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="RemoveOutside/RemoveNegativeOnly"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_t87ux") - -[node name="NegativeShape" type="Node3D" parent="RemoveOutside/RemoveNegativeOnly"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, -0.328114, 0, -1.96997) -script = ExtResource("5_y7d7p") -negative = true -shape = SubResource("Resource_hu6l0") - -[node name="Shapes" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 19, 0, -22) - -[node name="Sphere" type="Node3D" parent="Shapes"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0.996649, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_nvyeo") - -[node name="ScatterItem" type="Node3D" parent="Shapes/Sphere"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Shapes/Sphere"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_t1kde") - -[node name="Box" type="Node3D" parent="Shapes"] -transform = Transform3D(1, 0, 0, 0, 0.849488, -0.527608, 0, 0.527608, 0.849488, 0, 0.946816, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_cidgu") - -[node name="ScatterItem" type="Node3D" parent="Shapes/Box"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Shapes/Box"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_4qlye") - -[node name="Path" type="Node3D" parent="Shapes"] -transform = Transform3D(1, 0, 0, 0, 0.849488, -0.527608, 0, 0.527608, 0.849488, 3.41702, 0.946816, 0) -script = ExtResource("1_hld6g") -modifier_stack = SubResource("Resource_ywyj6") - -[node name="ScatterItem" type="Node3D" parent="Shapes/Path"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Shapes/Path"] -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_acfig") - -[node name="Particles" type="Marker3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 2) - -[node name="Standard" type="Node3D" parent="Particles"] -script = ExtResource("1_hld6g") -render_mode = 2 -modifier_stack = SubResource("Resource_yl5xk") - -[node name="ScatterItem" type="Node3D" parent="Particles/Standard"] -script = ExtResource("4_w0gix") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Particles/Standard"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_x5d01") - -[node name="OverrideProcess" type="Node3D" parent="Particles"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, 0) -script = ExtResource("1_hld6g") -render_mode = 2 -modifier_stack = SubResource("Resource_gavpu") - -[node name="ScatterItem" type="Node3D" parent="Particles/OverrideProcess"] -script = ExtResource("4_w0gix") -override_process_material = SubResource("ShaderMaterial_7sbin") -path = "res://addons/proton_scatter/demos/assets/brick.tscn" - -[node name="ScatterShape" type="Node3D" parent="Particles/OverrideProcess"] -transform = Transform3D(1, 0, -2.98023e-08, 0, 1, 0, 2.98023e-08, 0, 1, 0, 0, 0) -script = ExtResource("5_y7d7p") -shape = SubResource("Resource_o7cnt") diff --git a/godot/addons/rmsmartshape/actions/action.gd b/godot/addons/rmsmartshape/actions/action.gd deleted file mode 100644 index 5125edc..0000000 --- a/godot/addons/rmsmartshape/actions/action.gd +++ /dev/null @@ -1,23 +0,0 @@ -class_name SS2D_Action -extends RefCounted - -## Base class for all plugin actions. -## -## UndoRedo system will call [method do] and [method undo]. - -# @virtual -## Returns string to be used as a name in editor History tab. -func get_name() -> String: - return "UntitledAction" - - -# @virtual -## Do action here. -func do() -> void: - pass - - -# @virtual -## Undo action here. -func undo() -> void: - pass diff --git a/godot/addons/rmsmartshape/actions/action.gd.uid b/godot/addons/rmsmartshape/actions/action.gd.uid deleted file mode 100644 index e09589e..0000000 --- a/godot/addons/rmsmartshape/actions/action.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cfqgcckdwr7dc diff --git a/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd b/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd deleted file mode 100644 index b7ae7c7..0000000 --- a/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd +++ /dev/null @@ -1,38 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionAddCollisionNodes - -var _shape: SS2D_Shape -var _container: Node -var _poly: CollisionPolygon2D -var _old_polygon_path: NodePath - - -func _init(shape: SS2D_Shape, container: Node) -> void: - _shape = shape - _container = container - - -func get_name() -> String: - return "Add Collision Nodes" - - -func do() -> void: - _old_polygon_path = _shape.collision_polygon_node_path - - _poly = CollisionPolygon2D.new() - - if _container: - _container.add_child(_poly, true) - else: - _shape.add_sibling(_poly, true) - - _poly.owner = _shape.owner - _shape.collision_polygon_node_path = _shape.get_path_to(_poly) - - -func undo() -> void: - _shape.collision_polygon_node_path = _old_polygon_path - - if is_instance_valid(_poly): - _poly.queue_free() - _poly = null diff --git a/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd.uid b/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd.uid deleted file mode 100644 index fe0ed73..0000000 --- a/godot/addons/rmsmartshape/actions/action_add_collision_nodes.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://djda0uuvxic32 diff --git a/godot/addons/rmsmartshape/actions/action_add_point.gd b/godot/addons/rmsmartshape/actions/action_add_point.gd deleted file mode 100644 index e947ce7..0000000 --- a/godot/addons/rmsmartshape/actions/action_add_point.gd +++ /dev/null @@ -1,44 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionAddPoint - -var _invert_orientation: SS2D_ActionInvertOrientation - -var _commit_update: bool -var _shape: SS2D_Shape -var _key: int -var _position: Vector2 -var _idx: int - - -func _init(shape: SS2D_Shape, position: Vector2, idx: int = -1, commit_update: bool = true) -> void: - _shape = shape - _position = position - _commit_update = commit_update - _idx = idx - _key = _shape.get_point_array().reserve_key() - _invert_orientation = SS2D_ActionInvertOrientation.new(shape) - - -func get_name() -> String: - return "Add Point at (%d, %d)" % [_position.x, _position.y] - - -func do() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _key = pa.add_point(_position, _idx, _key) - _invert_orientation.do() - if _commit_update: - pa.end_update() - - -func undo() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _invert_orientation.undo() - pa.remove_point(_key) - pa.end_update() - - -func get_key() -> int: - return _key diff --git a/godot/addons/rmsmartshape/actions/action_add_point.gd.uid b/godot/addons/rmsmartshape/actions/action_add_point.gd.uid deleted file mode 100644 index 06ad6b3..0000000 --- a/godot/addons/rmsmartshape/actions/action_add_point.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b7ki3odwh0omr diff --git a/godot/addons/rmsmartshape/actions/action_close_shape.gd b/godot/addons/rmsmartshape/actions/action_close_shape.gd deleted file mode 100644 index ba41215..0000000 --- a/godot/addons/rmsmartshape/actions/action_close_shape.gd +++ /dev/null @@ -1,40 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionCloseShape - -var _invert_orientation: SS2D_ActionInvertOrientation - -var _shape: SS2D_Shape -var _key: int -var _performed: bool - - -func _init(shape: SS2D_Shape) -> void: - _shape = shape - _invert_orientation = SS2D_ActionInvertOrientation.new(shape) - - -func get_name() -> String: - return "Close Shape" - - -func do() -> void: - var pa := _shape.get_point_array() - _performed = pa.can_close() - if _performed: - pa.begin_update() - _key = pa.close_shape(_key) - _invert_orientation.do() - pa.end_update() - - -func undo() -> void: - if _performed: - var pa := _shape.get_point_array() - pa.begin_update() - _invert_orientation.undo() - pa.remove_point(_key) - pa.end_update() - - -func get_key() -> int: - return _key diff --git a/godot/addons/rmsmartshape/actions/action_close_shape.gd.uid b/godot/addons/rmsmartshape/actions/action_close_shape.gd.uid deleted file mode 100644 index 6752798..0000000 --- a/godot/addons/rmsmartshape/actions/action_close_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d1xrf4iewfn8w diff --git a/godot/addons/rmsmartshape/actions/action_cut_edge.gd b/godot/addons/rmsmartshape/actions/action_cut_edge.gd deleted file mode 100644 index 437171d..0000000 --- a/godot/addons/rmsmartshape/actions/action_cut_edge.gd +++ /dev/null @@ -1,38 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionCutEdge - - -## A delegate action that selects an action to perform based on the edge -## location and shape state. - -var _shape: SS2D_Shape -var _action: SS2D_Action - - -func _init(shape: SS2D_Shape, key_edge_start: int, key_edge_end: int) -> void: - _shape = shape - var pa := _shape.get_point_array() - - var key_first: int = pa.get_point_key_at_index(0) - var key_last: int = pa.get_point_key_at_index(pa.get_point_count()-1) - if pa.is_shape_closed(): - _action = SS2D_ActionOpenShape.new(shape, key_edge_start) - elif key_edge_start == key_first: - _action = SS2D_ActionDeletePoint.new(shape, key_edge_start) - elif key_edge_end == key_last: - _action = SS2D_ActionDeletePoint.new(shape, key_edge_end) - else: - _action = SS2D_ActionSplitShape.new(shape, key_edge_start) - - -func get_name() -> String: - return _action.get_name() - - -func do() -> void: - _action.do() - - -func undo() -> void: - _action.undo() - diff --git a/godot/addons/rmsmartshape/actions/action_cut_edge.gd.uid b/godot/addons/rmsmartshape/actions/action_cut_edge.gd.uid deleted file mode 100644 index 9a3dbd2..0000000 --- a/godot/addons/rmsmartshape/actions/action_cut_edge.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cetvsyxn1huci diff --git a/godot/addons/rmsmartshape/actions/action_delete_control_point.gd b/godot/addons/rmsmartshape/actions/action_delete_control_point.gd deleted file mode 100644 index 82ab517..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_control_point.gd +++ /dev/null @@ -1,46 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionDeleteControlPoint - -enum PointType {POINT_IN, POINT_OUT} - -var _invert_orientation: SS2D_ActionInvertOrientation - -var _shape: SS2D_Shape -var _key: int -var _point_type: PointType -var _old_value: Vector2 - - -func _init(shape: SS2D_Shape, key: int, point_type: PointType) -> void: - _shape = shape - _key = key - _point_type = point_type - var pa := _shape.get_point_array() - _old_value = pa.get_point_in(key) if _point_type == PointType.POINT_IN else pa.get_point_out(key) - _invert_orientation = SS2D_ActionInvertOrientation.new(shape) - - -func get_name() -> String: - return "Delete Control Point " + ("In" if _point_type == PointType.POINT_IN else "Out") - - -func do() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - if _point_type == PointType.POINT_IN: - pa.set_point_in(_key, Vector2.ZERO) - else: - pa.set_point_out(_key, Vector2.ZERO) - _invert_orientation.do() - pa.end_update() - - -func undo() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _invert_orientation.undo() - if _point_type == PointType.POINT_IN: - pa.set_point_in(_key, _old_value) - else: - pa.set_point_out(_key, _old_value) - pa.end_update() diff --git a/godot/addons/rmsmartshape/actions/action_delete_control_point.gd.uid b/godot/addons/rmsmartshape/actions/action_delete_control_point.gd.uid deleted file mode 100644 index 04c2f1d..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_control_point.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bs64tm81nim7l diff --git a/godot/addons/rmsmartshape/actions/action_delete_point.gd b/godot/addons/rmsmartshape/actions/action_delete_point.gd deleted file mode 100644 index f89449d..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_point.gd +++ /dev/null @@ -1,12 +0,0 @@ -extends SS2D_ActionDeletePoints -class_name SS2D_ActionDeletePoint - - -func _init(shape: SS2D_Shape, key: int, commit_update: bool = true) -> void: - var keys: PackedInt32Array = [key] - super(shape, keys, commit_update) - - -func get_name() -> String: - var pos := _shape.get_point_array().get_point_position(_keys[0]) - return "Delete Point at (%d, %d)" % [pos.x, pos.y] diff --git a/godot/addons/rmsmartshape/actions/action_delete_point.gd.uid b/godot/addons/rmsmartshape/actions/action_delete_point.gd.uid deleted file mode 100644 index 1f179d6..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_point.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://clwvxir8xsa2n diff --git a/godot/addons/rmsmartshape/actions/action_delete_points.gd b/godot/addons/rmsmartshape/actions/action_delete_points.gd deleted file mode 100644 index 5d3d3bb..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_points.gd +++ /dev/null @@ -1,76 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionDeletePoints - -var _invert_orientation: SS2D_ActionInvertOrientation -var _close_shape: SS2D_ActionCloseShape - -var _shape: SS2D_Shape -var _keys: PackedInt32Array -var _indicies: PackedInt32Array -var _points: Array[SS2D_Point] = [] -var _constraints: Array[Dictionary] -var _was_closed: bool -var _commit_update: bool - - -func _init(shape: SS2D_Shape, keys: PackedInt32Array, commit_update: bool = true) -> void: - _shape = shape - _invert_orientation = SS2D_ActionInvertOrientation.new(shape) - _close_shape = SS2D_ActionCloseShape.new(shape) - _commit_update = commit_update - - # FIXME?: Why save constraints here but points in do()? - for k in keys: - add_point_to_delete(k) - - -func get_name() -> String: - return "Delete Points %s" % [_keys] - - -func do() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _was_closed = pa.is_shape_closed() - var first_run := _points.size() == 0 - for k in _keys: - if first_run: - _indicies.append(pa.get_point_index(k)) - _points.append(pa.get_point(k)) - pa.remove_point(k) - if _was_closed: - _close_shape.do() - _invert_orientation.do() - if _commit_update: - pa.end_update() - - -func undo() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _invert_orientation.undo() - if _was_closed: - _close_shape.undo() - for i in range(_keys.size()-1, -1, -1): - pa.add_point_object(_points[i], _indicies[i], _keys[i]) - # Restore point constraints. - for i in range(_keys.size()-1, -1, -1): - for tuple: Vector2i in _constraints[i]: - pa.set_constraint(tuple[0], tuple[1], _constraints[i][tuple]) - pa.end_update() - - -func add_point_to_delete(key: int) -> void: - _keys.push_back(key) - var constraints := _shape.get_point_array().get_point_constraints(key) - # Save point constraints. - _constraints.append(constraints) - - for tuple: Vector2i in constraints: - var constraint: SS2D_Point_Array.CONSTRAINT = constraints[tuple] - if constraint == SS2D_Point_Array.CONSTRAINT.NONE: - continue - var key_other := SS2D_IndexTuple.get_other_value(tuple, key) - if constraint & SS2D_Point_Array.CONSTRAINT.ALL: - if not _keys.has(key_other): - add_point_to_delete(key_other) diff --git a/godot/addons/rmsmartshape/actions/action_delete_points.gd.uid b/godot/addons/rmsmartshape/actions/action_delete_points.gd.uid deleted file mode 100644 index dfef530..0000000 --- a/godot/addons/rmsmartshape/actions/action_delete_points.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://krf08w1t5smo diff --git a/godot/addons/rmsmartshape/actions/action_invert_orientation.gd b/godot/addons/rmsmartshape/actions/action_invert_orientation.gd deleted file mode 100644 index 2c5df7e..0000000 --- a/godot/addons/rmsmartshape/actions/action_invert_orientation.gd +++ /dev/null @@ -1,34 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionInvertOrientation - -var _shape: SS2D_Shape -var _performed: bool - - -func _init(shape: SS2D_Shape) -> void: - _shape = shape - - -func get_name() -> String: - return "Invert Orientation" - - -func do() -> void: - _performed = should_invert_orientation(_shape) - if _performed: - _shape.get_point_array().invert_point_order() - - -func undo() -> void: - if _performed: - _shape.get_point_array().invert_point_order() - - -func should_invert_orientation(s: SS2D_Shape) -> bool: - if s == null: - return false - - var pa := s.get_point_array() - if not pa.is_shape_closed(): - return false - return not pa.are_points_clockwise() and pa.get_point_count() >= 3 diff --git a/godot/addons/rmsmartshape/actions/action_invert_orientation.gd.uid b/godot/addons/rmsmartshape/actions/action_invert_orientation.gd.uid deleted file mode 100644 index dcf4847..0000000 --- a/godot/addons/rmsmartshape/actions/action_invert_orientation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://6c4qkqrauwm diff --git a/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd b/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd deleted file mode 100644 index 8bb9479..0000000 --- a/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd +++ /dev/null @@ -1,25 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionMakeShapeUnique - -var _shape: SS2D_Shape -var _old_array: SS2D_Point_Array -var _new_array: SS2D_Point_Array - - -func _init(shape: SS2D_Shape) -> void: - _shape = shape - _old_array = shape.get_point_array() - _new_array = _shape.get_point_array().clone(true) - - -func get_name() -> String: - return "Make Shape Unique" - - -func do() -> void: - _shape.set_point_array(_new_array) - - -func undo() -> void: - _shape.set_point_array(_old_array) - diff --git a/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd.uid b/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd.uid deleted file mode 100644 index f396a6c..0000000 --- a/godot/addons/rmsmartshape/actions/action_make_shape_unique.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dcryhx248ctcg diff --git a/godot/addons/rmsmartshape/actions/action_move_control_points.gd b/godot/addons/rmsmartshape/actions/action_move_control_points.gd deleted file mode 100644 index 21bacd5..0000000 --- a/godot/addons/rmsmartshape/actions/action_move_control_points.gd +++ /dev/null @@ -1,44 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionMoveControlPoints - -var _shape: SS2D_Shape -var _keys: PackedInt32Array -var _old_points_in: PackedVector2Array -var _old_points_out: PackedVector2Array -var _new_points_in: PackedVector2Array -var _new_points_out: PackedVector2Array - - -func _init(s: SS2D_Shape, keys: PackedInt32Array, - old_points_in: PackedVector2Array, old_points_out: PackedVector2Array) -> void: - _shape = s - _keys = keys - _old_points_in = old_points_in - _old_points_out = old_points_out - var pa := _shape.get_point_array() - for key in _keys: - _new_points_in.append(pa.get_point_in(key)) - _new_points_out.append(pa.get_point_out(key)) - - -func get_name() -> String: - return "Move Control Point" - - -func do() -> void: - _assign_points_in_out(_keys, _new_points_in, _new_points_out) - - -func undo() -> void: - _assign_points_in_out(_keys, _old_points_in, _old_points_out) - - -func _assign_points_in_out(keys: PackedInt32Array, in_positions: PackedVector2Array, out_positions: PackedVector2Array) -> void: - var pa := _shape.get_point_array() - pa.begin_update() - for i in keys.size(): - if pa.get_point_in(keys[i]) != in_positions[i]: - pa.set_point_in(keys[i], in_positions[i]) - if pa.get_point_out(keys[i]) != out_positions[i]: - pa.set_point_out(keys[i], out_positions[i]) - pa.end_update() diff --git a/godot/addons/rmsmartshape/actions/action_move_control_points.gd.uid b/godot/addons/rmsmartshape/actions/action_move_control_points.gd.uid deleted file mode 100644 index ba32a8c..0000000 --- a/godot/addons/rmsmartshape/actions/action_move_control_points.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtgmbqjmi5n6 diff --git a/godot/addons/rmsmartshape/actions/action_move_verticies.gd b/godot/addons/rmsmartshape/actions/action_move_verticies.gd deleted file mode 100644 index 0ff3bd3..0000000 --- a/godot/addons/rmsmartshape/actions/action_move_verticies.gd +++ /dev/null @@ -1,43 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionMoveVerticies - -var _invert_orientation: SS2D_ActionInvertOrientation -var _shape: SS2D_Shape -var _keys: PackedInt32Array -var _old_positions: PackedVector2Array -var _new_positions: PackedVector2Array - - -func _init(s: SS2D_Shape, keys: PackedInt32Array, old_positions: PackedVector2Array) -> void: - _shape = s - _keys = keys.duplicate() - _old_positions = old_positions.duplicate() - _new_positions = PackedVector2Array() - for k in _keys: - _new_positions.append(_shape.get_point_array().get_point_position(k)) - _invert_orientation = SS2D_ActionInvertOrientation.new(_shape) - - -func get_name() -> String: - if _keys.size() == 1: - return "Move Vertex to (%d, %d)" % [_new_positions[0].x, _new_positions[0].y] - else: - return "Move Verticies" - - -func do() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - for i in _keys.size(): - pa.set_point_position(_keys[i], _new_positions[i]) - _invert_orientation.do() - pa.end_update() - - -func undo() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - _invert_orientation.undo() - for i in range(_keys.size() - 1, -1, -1): - pa.set_point_position(_keys[i], _old_positions[i]) - pa.end_update() diff --git a/godot/addons/rmsmartshape/actions/action_move_verticies.gd.uid b/godot/addons/rmsmartshape/actions/action_move_verticies.gd.uid deleted file mode 100644 index dff5693..0000000 --- a/godot/addons/rmsmartshape/actions/action_move_verticies.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://1sx33upy2c8d diff --git a/godot/addons/rmsmartshape/actions/action_open_shape.gd b/godot/addons/rmsmartshape/actions/action_open_shape.gd deleted file mode 100644 index 3c7c389..0000000 --- a/godot/addons/rmsmartshape/actions/action_open_shape.gd +++ /dev/null @@ -1,32 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionOpenShape - -var _shape: SS2D_Shape -var _cut_idx: int -var _closing_key: int - - -func _init(shape: SS2D_Shape, edge_start_key: int) -> void: - _shape = shape - _cut_idx = shape.get_point_array().get_point_index(edge_start_key) - - -func get_name() -> String: - return "Open Shape" - - -func do() -> void: - var pa := _shape.get_point_array() - var last_idx: int = pa.get_point_count() - 1 - _closing_key = pa.get_point_key_at_index(last_idx) - pa.begin_update() - pa.open_shape_at_edge(_cut_idx) - pa.end_update() - - -func undo() -> void: - var pa := _shape.get_point_array() - pa.begin_update() - pa.undo_open_shape_at_edge(_cut_idx, _closing_key) - pa.end_update() - diff --git a/godot/addons/rmsmartshape/actions/action_open_shape.gd.uid b/godot/addons/rmsmartshape/actions/action_open_shape.gd.uid deleted file mode 100644 index 7544d32..0000000 --- a/godot/addons/rmsmartshape/actions/action_open_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dmvu0elurqotc diff --git a/godot/addons/rmsmartshape/actions/action_set_pivot.gd b/godot/addons/rmsmartshape/actions/action_set_pivot.gd deleted file mode 100644 index 1290573..0000000 --- a/godot/addons/rmsmartshape/actions/action_set_pivot.gd +++ /dev/null @@ -1,44 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionSetPivot - -var _shape: SS2D_Shape - -var _new_pos: Vector2 -var _old_pos: Vector2 - - -func _init(s: SS2D_Shape, pos: Vector2) -> void: - _shape = s - _new_pos = pos - _old_pos = _shape.global_position - - -func get_name() -> String: - return "Set Pivot" - - -func do() -> void: - _set_pivot(_new_pos) - - -func undo() -> void: - _set_pivot(_old_pos) - - -func _set_pivot(shape_position: Vector2) -> void: - var shape_gt: Transform2D = _shape.get_global_transform() - var pa := _shape.get_point_array() - - _shape.global_position = shape_position - - pa.begin_update() - pa.disable_constraints() - - for i in pa.get_point_count(): - var key: int = pa.get_point_key_at_index(i) - var point: Vector2 = pa.get_point_position(key) - pa.set_point_position(key, _shape.to_local(shape_gt * point)) - - pa.enable_constraints() - pa.end_update() - diff --git a/godot/addons/rmsmartshape/actions/action_set_pivot.gd.uid b/godot/addons/rmsmartshape/actions/action_set_pivot.gd.uid deleted file mode 100644 index 97088ea..0000000 --- a/godot/addons/rmsmartshape/actions/action_set_pivot.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c18y0hljp5gym diff --git a/godot/addons/rmsmartshape/actions/action_split_curve.gd b/godot/addons/rmsmartshape/actions/action_split_curve.gd deleted file mode 100644 index 543d08a..0000000 --- a/godot/addons/rmsmartshape/actions/action_split_curve.gd +++ /dev/null @@ -1,9 +0,0 @@ -extends SS2D_ActionAddPoint -class_name SS2D_ActionSplitCurve - -func _init(shape: SS2D_Shape, idx: int, gpoint: Vector2, xform: Transform2D, commit_update: bool = true) -> void: - super._init(shape, xform.affine_inverse() * gpoint, idx, commit_update) - - -func get_name() -> String: - return "Split Curve at (%d, %d)" % [_position.x, _position.y] diff --git a/godot/addons/rmsmartshape/actions/action_split_curve.gd.uid b/godot/addons/rmsmartshape/actions/action_split_curve.gd.uid deleted file mode 100644 index 5795984..0000000 --- a/godot/addons/rmsmartshape/actions/action_split_curve.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://k8heyjcjsjk diff --git a/godot/addons/rmsmartshape/actions/action_split_shape.gd b/godot/addons/rmsmartshape/actions/action_split_shape.gd deleted file mode 100644 index 043ba8a..0000000 --- a/godot/addons/rmsmartshape/actions/action_split_shape.gd +++ /dev/null @@ -1,75 +0,0 @@ -extends SS2D_Action -class_name SS2D_ActionSplitShape - -## How it's done: -## 1. First, the shape is copied and added to the scene tree. -## 2. Then, points of the splitted shape are deleted from first point to split point. -## 3. Finally, points of the original shape are deleted from the point after split point to last point. - -var _delete_points_from_original: SS2D_ActionDeletePoints - -var _shape: SS2D_Shape -var _splitted: SS2D_Shape -var _splitted_collision: CollisionPolygon2D -var _split_idx: int - - -func _init(shape: SS2D_Shape, split_point_key: int) -> void: - var pa := shape.get_point_array() - assert(pa.is_shape_closed() == false) - _shape = shape - _split_idx = pa.get_point_index(split_point_key) - _splitted = null - _splitted_collision = null - _delete_points_from_original = null - - -func get_name() -> String: - return "Split Shape" - - -func do() -> void: - if not is_instance_valid(_splitted): - _splitted = _shape.clone() - var splitted_pa := _splitted.get_point_array() - splitted_pa.begin_update() - for i in range(0, _split_idx + 1): - splitted_pa.remove_point_at_index(0) - splitted_pa.end_update() - _shape.get_parent().add_child(_splitted, true) - _splitted.set_owner(_shape.get_tree().get_edited_scene_root()) - # Add a collision shape node if the original shape has one. - if (not _shape.collision_polygon_node_path.is_empty() and _shape.has_node(_shape.collision_polygon_node_path)): - var collision_polygon_original := _shape.get_node(_shape.collision_polygon_node_path) as CollisionPolygon2D - if not is_instance_valid(_splitted_collision): - _splitted_collision = CollisionPolygon2D.new() - _splitted_collision.visible = collision_polygon_original.visible - _splitted_collision.modulate = collision_polygon_original.modulate - collision_polygon_original.get_parent().add_child(_splitted_collision, true) - _splitted_collision.set_owner(collision_polygon_original.get_tree().get_edited_scene_root()) - _splitted.collision_polygon_node_path = _splitted.get_path_to(_splitted_collision) - - if _delete_points_from_original == null: - var pa := _shape.get_point_array() - var delete_keys := PackedInt32Array() - for i in range(pa.get_point_count() - 1, _split_idx, -1): - delete_keys.append(pa.get_point_key_at_index(i)) - _delete_points_from_original = SS2D_ActionDeletePoints.new(_shape, delete_keys) - _delete_points_from_original.do() - - -func undo() -> void: - _splitted.set_owner(null) - _splitted.get_parent().remove_child(_splitted) - if is_instance_valid(_splitted_collision): - _splitted_collision.set_owner(null) - _splitted_collision.get_parent().remove_child(_splitted_collision) - _delete_points_from_original.undo() - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - if is_instance_valid(_splitted) and _splitted.get_parent() == null: - _splitted.queue_free() - if is_instance_valid(_splitted_collision) and _splitted_collision.get_parent() == null: - _splitted_collision.queue_free() diff --git a/godot/addons/rmsmartshape/actions/action_split_shape.gd.uid b/godot/addons/rmsmartshape/actions/action_split_shape.gd.uid deleted file mode 100644 index 5e42929..0000000 --- a/godot/addons/rmsmartshape/actions/action_split_shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c1epbsifds5rp diff --git a/godot/addons/rmsmartshape/asset_library_icon-new.png b/godot/addons/rmsmartshape/asset_library_icon-new.png deleted file mode 100644 index 44db166..0000000 Binary files a/godot/addons/rmsmartshape/asset_library_icon-new.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/asset_library_icon-new.png.import b/godot/addons/rmsmartshape/asset_library_icon-new.png.import deleted file mode 100644 index f59a001..0000000 --- a/godot/addons/rmsmartshape/asset_library_icon-new.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://5wllxq74p8kq" -path="res://.godot/imported/asset_library_icon-new.png-60877ecd9837f02c48423d4ec08e9284.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/asset_library_icon-new.png" -dest_files=["res://.godot/imported/asset_library_icon-new.png-60877ecd9837f02c48423d4ec08e9284.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/asset_library_icon.png b/godot/addons/rmsmartshape/asset_library_icon.png deleted file mode 100644 index 1ff18e6..0000000 Binary files a/godot/addons/rmsmartshape/asset_library_icon.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/asset_library_icon.png.import b/godot/addons/rmsmartshape/asset_library_icon.png.import deleted file mode 100644 index 879aa97..0000000 --- a/godot/addons/rmsmartshape/asset_library_icon.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cbde02owb6iuu" -path="res://.godot/imported/asset_library_icon.png-57d4f9e357cb3293fe7f718c0ef3633c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/asset_library_icon.png" -dest_files=["res://.godot/imported/asset_library_icon.png-57d4f9e357cb3293fe7f718c0ef3633c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/Anchor.svg b/godot/addons/rmsmartshape/assets/Anchor.svg deleted file mode 100644 index a9caae0..0000000 --- a/godot/addons/rmsmartshape/assets/Anchor.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - image/svg+xml - - - - - - - diff --git a/godot/addons/rmsmartshape/assets/Anchor.svg.import b/godot/addons/rmsmartshape/assets/Anchor.svg.import deleted file mode 100644 index be28498..0000000 --- a/godot/addons/rmsmartshape/assets/Anchor.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b2h8c634u1120" -path="res://.godot/imported/Anchor.svg-1c23ca67e353b480fc5d8186bb0064b9.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/Anchor.svg" -dest_files=["res://.godot/imported/Anchor.svg-1c23ca67e353b480fc5d8186bb0064b9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/CenterView.svg b/godot/addons/rmsmartshape/assets/CenterView.svg deleted file mode 100644 index dc4052f..0000000 --- a/godot/addons/rmsmartshape/assets/CenterView.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/rmsmartshape/assets/CenterView.svg.import b/godot/addons/rmsmartshape/assets/CenterView.svg.import deleted file mode 100644 index bd2b33a..0000000 --- a/godot/addons/rmsmartshape/assets/CenterView.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://byx10wt6pl1vo" -path="res://.godot/imported/CenterView.svg-f5e9c7178a59ab586ba9d8fac61799bc.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/CenterView.svg" -dest_files=["res://.godot/imported/CenterView.svg-f5e9c7178a59ab586ba9d8fac61799bc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/InterpLinear.svg b/godot/addons/rmsmartshape/assets/InterpLinear.svg deleted file mode 100644 index 241a82f..0000000 --- a/godot/addons/rmsmartshape/assets/InterpLinear.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/rmsmartshape/assets/InterpLinear.svg.import b/godot/addons/rmsmartshape/assets/InterpLinear.svg.import deleted file mode 100644 index 89ec00b..0000000 --- a/godot/addons/rmsmartshape/assets/InterpLinear.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://umo7sgb6w70s" -path="res://.godot/imported/InterpLinear.svg-c9d61ab817f2809471482a31f06cda10.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/InterpLinear.svg" -dest_files=["res://.godot/imported/InterpLinear.svg-c9d61ab817f2809471482a31f06cda10.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf b/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf deleted file mode 100644 index 42e619f..0000000 Binary files a/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf.import b/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf.import deleted file mode 100644 index 24bc20e..0000000 --- a/godot/addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf.import +++ /dev/null @@ -1,36 +0,0 @@ -[remap] - -importer="font_data_dynamic" -type="FontFile" -uid="uid://cjgo8gf0cp441" -path="res://.godot/imported/SourceCodeVariable-Roman.ttf-cb1e4f55679e973e90075716efcdf601.fontdata" - -[deps] - -source_file="res://addons/rmsmartshape/assets/SourceCodeVariable-Roman.ttf" -dest_files=["res://.godot/imported/SourceCodeVariable-Roman.ttf-cb1e4f55679e973e90075716efcdf601.fontdata"] - -[params] - -Rendering=null -antialiasing=1 -generate_mipmaps=false -disable_embedded_bitmaps=true -multichannel_signed_distance_field=false -msdf_pixel_range=8 -msdf_size=48 -allow_system_fallback=true -force_autohinter=false -modulate_color_glyphs=false -hinting=1 -subpixel_positioning=1 -keep_rounding_remainders=true -oversampling=0.0 -Fallbacks=null -fallbacks=[] -Compress=null -compress=true -preload=[] -language_support={} -script_support={} -opentype_features={} diff --git a/godot/addons/rmsmartshape/assets/closed_shape.png b/godot/addons/rmsmartshape/assets/closed_shape.png deleted file mode 100644 index e2834e3..0000000 Binary files a/godot/addons/rmsmartshape/assets/closed_shape.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/closed_shape.png.import b/godot/addons/rmsmartshape/assets/closed_shape.png.import deleted file mode 100644 index 05ed14a..0000000 --- a/godot/addons/rmsmartshape/assets/closed_shape.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://8r4xp6j0ro3y" -path="res://.godot/imported/closed_shape.png-c1d349f5c2caecc40ec65e52f86a8145.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/closed_shape.png" -dest_files=["res://.godot/imported/closed_shape.png-c1d349f5c2caecc40ec65e52f86a8145.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/freehand.png b/godot/addons/rmsmartshape/assets/freehand.png deleted file mode 100644 index ee1125a..0000000 Binary files a/godot/addons/rmsmartshape/assets/freehand.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/freehand.png.import b/godot/addons/rmsmartshape/assets/freehand.png.import deleted file mode 100644 index a007dcb..0000000 --- a/godot/addons/rmsmartshape/assets/freehand.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bjbq000i2n7qd" -path="res://.godot/imported/freehand.png-de4c7fa877a42fa4776ee9cd166cdabd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/freehand.png" -dest_files=["res://.godot/imported/freehand.png-de4c7fa877a42fa4776ee9cd166cdabd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/gui_theme.res b/godot/addons/rmsmartshape/assets/gui_theme.res deleted file mode 100644 index 55d0270..0000000 Binary files a/godot/addons/rmsmartshape/assets/gui_theme.res and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/icon.png b/godot/addons/rmsmartshape/assets/icon.png deleted file mode 100644 index a9d3337..0000000 Binary files a/godot/addons/rmsmartshape/assets/icon.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/icon.png.import b/godot/addons/rmsmartshape/assets/icon.png.import deleted file mode 100644 index 0b19022..0000000 --- a/godot/addons/rmsmartshape/assets/icon.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://h0jpajdrldwm" -path="res://.godot/imported/icon.png-cf4ff9c0f4595c1f390bb463008250b4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon.png" -dest_files=["res://.godot/imported/icon.png-cf4ff9c0f4595c1f390bb463008250b4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg b/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg deleted file mode 100644 index 9d90a66..0000000 --- a/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg.import b/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg.import deleted file mode 100644 index 4eccd57..0000000 --- a/godot/addons/rmsmartshape/assets/icon_collision_polygon_2d.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c3n1j5ybtgjit" -path="res://.godot/imported/icon_collision_polygon_2d.svg-d52c533e615c0baed724848cec175fe6.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_collision_polygon_2d.svg" -dest_files=["res://.godot/imported/icon_collision_polygon_2d.svg-d52c533e615c0baed724848cec175fe6.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_curve_create.svg b/godot/addons/rmsmartshape/assets/icon_curve_create.svg deleted file mode 100644 index 1181111..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_create.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_curve_create.svg.import b/godot/addons/rmsmartshape/assets/icon_curve_create.svg.import deleted file mode 100644 index 7da3549..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_create.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://qf0hmmvirgbn" -path="res://.godot/imported/icon_curve_create.svg-24c8317cfb8ced81d4c832ca7b3310d5.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_curve_create.svg" -dest_files=["res://.godot/imported/icon_curve_create.svg-24c8317cfb8ced81d4c832ca7b3310d5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_curve_delete.svg b/godot/addons/rmsmartshape/assets/icon_curve_delete.svg deleted file mode 100644 index 901a08e..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_delete.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_curve_delete.svg.import b/godot/addons/rmsmartshape/assets/icon_curve_delete.svg.import deleted file mode 100644 index 6358152..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_delete.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ce2cbowctirhc" -path="res://.godot/imported/icon_curve_delete.svg-9121c11be9a22040b2d567743d44ead0.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_curve_delete.svg" -dest_files=["res://.godot/imported/icon_curve_delete.svg-9121c11be9a22040b2d567743d44ead0.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_curve_edit.svg b/godot/addons/rmsmartshape/assets/icon_curve_edit.svg deleted file mode 100644 index 8f09ca6..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_edit.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_curve_edit.svg.import b/godot/addons/rmsmartshape/assets/icon_curve_edit.svg.import deleted file mode 100644 index d4c6814..0000000 --- a/godot/addons/rmsmartshape/assets/icon_curve_edit.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://crjuwuq4vp15w" -path="res://.godot/imported/icon_curve_edit.svg-bd7d5e1af7c72f4525dff1d79ad0af94.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_curve_edit.svg" -dest_files=["res://.godot/imported/icon_curve_edit.svg-bd7d5e1af7c72f4525dff1d79ad0af94.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg b/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg deleted file mode 100644 index d354946..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg.import deleted file mode 100644 index 5cf7538..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_freehand.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://da64iqyjipw4f" -path="res://.godot/imported/icon_editor_freehand.svg-4eb5cac550480a5ffb50b9c62fba3af1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_freehand.svg" -dest_files=["res://.godot/imported/icon_editor_freehand.svg-4eb5cac550480a5ffb50b9c62fba3af1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle.svg b/godot/addons/rmsmartshape/assets/icon_editor_handle.svg deleted file mode 100644 index 328dc04..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_handle.svg.import deleted file mode 100644 index 1e7d83b..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ccnyogs0qbq8b" -path="res://.godot/imported/icon_editor_handle.svg-ace1b9f89612a442855e8ad0888fdf3e.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_handle.svg" -dest_files=["res://.godot/imported/icon_editor_handle.svg-ace1b9f89612a442855e8ad0888fdf3e.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.5 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg b/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg deleted file mode 100644 index a8bc1fd..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg.import deleted file mode 100644 index 010b75c..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_add.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ci73r1ncmyrrw" -path="res://.godot/imported/icon_editor_handle_add.svg-7258971e5edcfe4396b7b9c27c0ba1cc.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_handle_add.svg" -dest_files=["res://.godot/imported/icon_editor_handle_add.svg-7258971e5edcfe4396b7b9c27c0ba1cc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.5 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg b/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg deleted file mode 100644 index b498345..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg.import deleted file mode 100644 index 11f05ee..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_bezier.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cycko7tpd5xk5" -path="res://.godot/imported/icon_editor_handle_bezier.svg-b0150f05772e8974a66bc735765e0aeb.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_handle_bezier.svg" -dest_files=["res://.godot/imported/icon_editor_handle_bezier.svg-b0150f05772e8974a66bc735765e0aeb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.5 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg b/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg deleted file mode 100644 index ea69f4e..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg.import deleted file mode 100644 index a786d9d..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_control.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dgcshah05p0bm" -path="res://.godot/imported/icon_editor_handle_control.svg-8383942d01a7ee5e839992ed99e53aaf.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_handle_control.svg" -dest_files=["res://.godot/imported/icon_editor_handle_control.svg-8383942d01a7ee5e839992ed99e53aaf.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.5 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg b/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg deleted file mode 100644 index ac96ca6..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg.import deleted file mode 100644 index 64102cf..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_handle_selected.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dh3vdfbsl5o65" -path="res://.godot/imported/icon_editor_handle_selected.svg-356ef806610ee2a60b5838a989f58598.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_handle_selected.svg" -dest_files=["res://.godot/imported/icon_editor_handle_selected.svg-356ef806610ee2a60b5838a989f58598.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.25 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_position.svg b/godot/addons/rmsmartshape/assets/icon_editor_position.svg deleted file mode 100644 index 7657eb5..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_position.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/godot/addons/rmsmartshape/assets/icon_editor_position.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_position.svg.import deleted file mode 100644 index 6a0b15c..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_position.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c18veogqnx5ht" -path="res://.godot/imported/icon_editor_position.svg-1f6e1977293add549ed436510f8834c1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_position.svg" -dest_files=["res://.godot/imported/icon_editor_position.svg-1f6e1977293add549ed436510f8834c1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_editor_snap.svg b/godot/addons/rmsmartshape/assets/icon_editor_snap.svg deleted file mode 100644 index a4a1f33..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_snap.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/godot/addons/rmsmartshape/assets/icon_editor_snap.svg.import b/godot/addons/rmsmartshape/assets/icon_editor_snap.svg.import deleted file mode 100644 index 71b61b6..0000000 --- a/godot/addons/rmsmartshape/assets/icon_editor_snap.svg.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bojrgd0r131xh" -path="res://.godot/imported/icon_editor_snap.svg-f0374ecd8cb313d78a2acb46b093a7f1.ctex" -metadata={ -"has_editor_variant": true, -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_editor_snap.svg" -dest_files=["res://.godot/imported/icon_editor_snap.svg-f0374ecd8cb313d78a2acb46b093a7f1.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=true -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle.svg.import deleted file mode 100644 index a1e995e..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle.svg-55d6fdc3b3c08e53dc0bed806d2f0a8f.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle.svg" -dest_files=[ "res://.import/icon_width_handle.svg-55d6fdc3b3c08e53dc0bed806d2f0a8f.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=true -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle0.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle0.svg.import deleted file mode 100644 index 3d70ef9..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle0.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle0.svg-9a486a252970ecb72608cabecc20a9f6.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle0.svg" -dest_files=[ "res://.import/icon_width_handle0.svg-9a486a252970ecb72608cabecc20a9f6.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=false -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle1.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle1.svg.import deleted file mode 100644 index c4edbdc..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle1.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle1.svg-a1da7c369cb74b89d2283c3679312805.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle1.svg" -dest_files=[ "res://.import/icon_width_handle1.svg-a1da7c369cb74b89d2283c3679312805.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=false -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle2.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle2.svg.import deleted file mode 100644 index fd84d56..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle2.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle2.svg-b02ee2da69342d687c1fd9680123e834.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle2.svg" -dest_files=[ "res://.import/icon_width_handle2.svg-b02ee2da69342d687c1fd9680123e834.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=false -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle3.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle3.svg.import deleted file mode 100644 index 751beb8..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle3.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle3.svg-3dcf9d2b715a3978009539d7a6640342.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle3.svg" -dest_files=[ "res://.import/icon_width_handle3.svg-3dcf9d2b715a3978009539d7a6640342.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=false -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/icon_width_handle4.svg.import b/godot/addons/rmsmartshape/assets/icon_width_handle4.svg.import deleted file mode 100644 index 957a8ee..0000000 --- a/godot/addons/rmsmartshape/assets/icon_width_handle4.svg.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/icon_width_handle4.svg-47fd86c3a89419c03da7bc2def15fbfa.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/icon_width_handle4.svg" -dest_files=[ "res://.import/icon_width_handle4.svg-47fd86c3a89419c03da7bc2def15fbfa.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=true -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/light1-1.png b/godot/addons/rmsmartshape/assets/light1-1.png deleted file mode 100644 index 4523497..0000000 Binary files a/godot/addons/rmsmartshape/assets/light1-1.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/light1-1.png.import b/godot/addons/rmsmartshape/assets/light1-1.png.import deleted file mode 100644 index f5dc6b3..0000000 --- a/godot/addons/rmsmartshape/assets/light1-1.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b350jwt2tgchl" -path="res://.godot/imported/light1-1.png-433fe7882cc83fa28e02c4948a40f886.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/light1-1.png" -dest_files=["res://.godot/imported/light1-1.png-433fe7882cc83fa28e02c4948a40f886.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/meta_shape.png b/godot/addons/rmsmartshape/assets/meta_shape.png deleted file mode 100644 index 2e8259d..0000000 Binary files a/godot/addons/rmsmartshape/assets/meta_shape.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/meta_shape.png.import b/godot/addons/rmsmartshape/assets/meta_shape.png.import deleted file mode 100644 index 249c398..0000000 --- a/godot/addons/rmsmartshape/assets/meta_shape.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://olmio6gxe5d6" -path="res://.godot/imported/meta_shape.png-462cb0c943fa311edd3a47aeb27824d9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/meta_shape.png" -dest_files=["res://.godot/imported/meta_shape.png-462cb0c943fa311edd3a47aeb27824d9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/open_shape.png b/godot/addons/rmsmartshape/assets/open_shape.png deleted file mode 100644 index 8e1978d..0000000 Binary files a/godot/addons/rmsmartshape/assets/open_shape.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/assets/open_shape.png.import b/godot/addons/rmsmartshape/assets/open_shape.png.import deleted file mode 100644 index e6b84aa..0000000 --- a/godot/addons/rmsmartshape/assets/open_shape.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cpg65u2v4mthq" -path="res://.godot/imported/open_shape.png-f18727d78226e221aef881edda953bbd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/assets/open_shape.png" -dest_files=["res://.godot/imported/open_shape.png-f18727d78226e221aef881edda953bbd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/assets/shape.png.import b/godot/addons/rmsmartshape/assets/shape.png.import deleted file mode 100644 index 7af62f8..0000000 --- a/godot/addons/rmsmartshape/assets/shape.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/shape.png-00d53041e0aeffe00cc49849dfbcc65f.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/shape.png" -dest_files=[ "res://.import/shape.png-00d53041e0aeffe00cc49849dfbcc65f.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=false -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=false -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=true -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/assets/shape_anchor.png.import b/godot/addons/rmsmartshape/assets/shape_anchor.png.import deleted file mode 100644 index 86c89d7..0000000 --- a/godot/addons/rmsmartshape/assets/shape_anchor.png.import +++ /dev/null @@ -1,34 +0,0 @@ -[remap] - -importer="texture" -type="StreamTexture" -path="res://.import/shape_anchor.png-c4527dad8f7093abc2088dd0157f0c72.stex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/shape_anchor.png" -dest_files=[ "res://.import/shape_anchor.png-c4527dad8f7093abc2088dd0157f0c72.stex" ] - -[params] - -compress/mode=0 -compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 -compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 -process/fix_alpha_border=true -process/premult_alpha=false -process/HDR_as_SRGB=false -process/invert_color=false -stream=false -size_limit=0 -detect_3d=true -svg/scale=1.0 diff --git a/godot/addons/rmsmartshape/collision_gen.gd b/godot/addons/rmsmartshape/collision_gen.gd deleted file mode 100644 index f8b3540..0000000 --- a/godot/addons/rmsmartshape/collision_gen.gd +++ /dev/null @@ -1,253 +0,0 @@ -extends RefCounted -class_name SS2D_CollisionGen - -# NOTE: Use JOIN_MITER for all transformations because it keeps the corners as they are, which is fast and accurate. - - -## Controls width of generated polygon -@export var collision_size: float = 32 - -## Controls offset of generated polygon -@export var collision_offset: float = 0.0 - - -## Generates a collision polygon intended for open polygons. -## May return the input point array unmodified or a new array. -func generate_open(points: PackedVector2Array) -> PackedVector2Array: - if points.size() <= 2: - return PackedVector2Array() - - var offset := collision_offset - collision_size / 2 - - if is_equal_approx(offset, 0): - return points - - # Geometry2D.offset_polygon() cannot be used to apply collision_offset because it - # interprets the given points as closed polygon and may also change the start/end points, which - # leads to various issues and is difficult to resolve. - points = SS2D_CollisionGen.simple_offset_open_polygon_miter(points, offset) - - return Geometry2D.offset_polyline(points, collision_size / 2, Geometry2D.JOIN_MITER, Geometry2D.END_BUTT).front() - - -## Generates a collision polygon intended for closed polygons. -## May return the input point array unmodified or a new array. -func generate_filled(points: PackedVector2Array) -> PackedVector2Array: - if points.size() <= 2: - return PackedVector2Array() - - if is_equal_approx(collision_offset, 0): - return points - return Geometry2D.offset_polygon(points, collision_offset, Geometry2D.JOIN_MITER).front() - - -## Generates a hollow collision polygon intended for closed shapes. -## Use [method generate_collision_points_fast_open] for open shapes. -func generate_hollow(points: PackedVector2Array) -> PackedVector2Array: - # 1) Generate an outer and an inner offset using offset_polygon(). - # 2) Reverse one array (in this case `outer`) to go along one array, then transition to the other - # and return in the opposite direction back to the starting point. - # 3) offset_polygon() may change start and end points from the original input, so search for the - # closest point in `inner` to the first `outer` point and use that as transition point. - # - # 0__________1 0/6__________5 - # / ________ \ outer /\________ \ - # / /2 3\ \ / /0/6 1\ \ - # 5/ /1 inner 4\ \2 -> 1/ /5 2\ \4 - # \ \ / / \ \ / / - # \ \0______5/ / \ \4______3/ / - # \__________/ \__________/ - # 4 3 2 3 - - if points.size() <= 2: - return PackedVector2Array() - - var outer_offset := collision_offset + collision_size / 2 - var inner_offset := collision_offset - collision_size / 2 - var outer: PackedVector2Array - var inner: PackedVector2Array = points - - if not is_equal_approx(inner_offset, 0): - inner = Geometry2D.offset_polygon(points, inner_offset, Geometry2D.JOIN_MITER).front() - - if not is_equal_approx(outer_offset, 0): - outer = Geometry2D.offset_polygon(points, outer_offset, Geometry2D.JOIN_MITER).front() - else: - # Make a copy so we don't modify the input array which may lead to unexpected behavior, e.g. - # when the input is get_point_array().get_tesselated_points(). - outer = PackedVector2Array(points) - - outer.reverse() - - var closest_idx := 0 - var closest_dist: float = inner[0].distance_squared_to(outer[0]) - - for i in range(1, inner.size()): - var dist := inner[i].distance_squared_to(outer[0]) - if dist < closest_dist: - closest_dist = dist - closest_idx = i - - outer.push_back(outer[0]) - - if closest_idx == 0: - outer.append_array(inner) - else: - outer.append_array(inner.slice(closest_idx)) - outer.append_array(inner.slice(0, closest_idx)) - outer.push_back(inner[closest_idx]) - - return outer - - -## Legacy method for generating collision polygons. -## Uses the edge generation algorithm for retrieving the shape outlines. -## Much slower than other functions (~0.3ms vs ~0.05ms in the collisions.tscn example). -func generate_legacy(shape: SS2D_Shape) -> PackedVector2Array: - var points := PackedVector2Array() - var num_points: int = shape._points.get_point_count() - - if num_points < 2: - return points - - var is_closed := shape._points.is_shape_closed() - var csize: float = 1.0 if is_closed else collision_size - var indices := PackedInt32Array(range(num_points)) - var edge_data := SS2D_IndexMap.new(indices, null) - var edge: SS2D_Edge = shape._build_edge_with_material(edge_data, collision_offset - 1.0, csize) - shape._weld_quad_array(edge.quads, false) - - if is_closed: - var first_quad: SS2D_Quad = edge.quads[0] - var last_quad: SS2D_Quad = edge.quads.back() - SS2D_Shape.weld_quads(last_quad, first_quad) - - if not edge.quads.is_empty(): - # Top edge (typically point A unless corner quad) - for quad in edge.quads: - if quad.corner == SS2D_Quad.CORNER.NONE: - points.push_back(quad.pt_a) - elif quad.corner == SS2D_Quad.CORNER.OUTER: - points.push_back(quad.pt_d) - elif quad.corner == SS2D_Quad.CORNER.INNER: - pass - - if not is_closed: - # Right Edge (point d, the first or final quad will never be a corner) - points.push_back(edge.quads[edge.quads.size() - 1].pt_d) - - # Bottom Edge (typically point c) - for quad_index in edge.quads.size(): - var quad: SS2D_Quad = edge.quads[edge.quads.size() - 1 - quad_index] - if quad.corner == SS2D_Quad.CORNER.NONE: - points.push_back(quad.pt_c) - elif quad.corner == SS2D_Quad.CORNER.OUTER: - pass - elif quad.corner == SS2D_Quad.CORNER.INNER: - points.push_back(quad.pt_b) - - # Left Edge (point b) - points.push_back(edge.quads[0].pt_b) - return points - - -## This is a simple implementation for offseting (inflate/deflate) open polylines but without -## intersection resolution. -## Geometry2D.offset_polygon() always interprets the input as closed polygon, which leads to various -## issues with open shapes, which is the reason why this function exists. -static func simple_offset_open_polygon_miter(points: PackedVector2Array, offset: float) -> PackedVector2Array: - if points.size() < 2 or is_zero_approx(offset): - return PackedVector2Array() - - # top - # P o_____o_____ - # / | \ - # / | \ - # b2 o |d \ - # / . | . \ - # / . | . \ - # / . o . \ - # / /b\ \ - # / / \ \ - # / \ / \ \ - # / ab_orth\ / \ \ - # / / \ \ - # / /ab bc\ \ - # / / \ \ - # . / \ . - # . / \ . - # . / \ . - # o o - # a c - - var new_points := PackedVector2Array() - new_points.resize(points.size() * 2) # Allocate maximum and reduce later. - - var a := points[0] - var b := points[1] - var ab := b - a - var ab_orth := ab.orthogonal().normalized() - new_points[0] = points[0] + ab_orth * offset - var out_i := 1 - const miter_threshold := 0.5 - - for i in range(1, points.size() - 1): - var c := points[i + 1] - var bc := c - b - var bc_orth := bc.orthogonal().normalized() - var dnorm := (ab_orth + bc_orth).normalized() - var d := dnorm * offset - var miter_denom := maxf(dnorm.dot(ab_orth), 1e-6) - var clockwise: bool = (sign(offset) * ab_orth.dot(bc)) < 0 - - if clockwise and miter_denom < miter_threshold: - # Miter length exceeds threshold -> cap it manually or it will create large peaks. - # The cap will be placed `offset` pixels away from b. - # - # 1) We consider the triangle `b2`, `top` and `P`. - # `b2` and `top` are known as well as their directions towards `P` (`ab`, `d_orth`). - # `P` is the point where `b2 + t * ab` and `top + u * d_orth` intersect. - # - # b2 + t * ab = top + u * d_orth = P - # - # We get a linear system with two variables `t` and `u` but we only need to know one. - # - # 2) Transform equation into matrix form - # t * ab - u * d_orth = top - b2 - # - # A X = B - # ⎛ab.x -d_orth.x⎞ ⎛t⎞ = ⎛rhs.x⎞ - # ⎝ab.y -d_orth.y⎠ ⎝u⎠ ⎝rhs.y⎠ - var top := b + d - var d_orth := dnorm.orthogonal() - var b2 := b + ab_orth * offset - var rhs := top - b2 - - # 3) Resolve for `u` using Cramer's rule - # - # det A_2 ab.x * rhs.y - ab.y * rhs.x - # u = --------- = ------------------------------------ - # det A ab.x * -d_orth.y + d_orth.x * ab.y - var det_a2 := ab.x * rhs.y - ab.y * rhs.x - var det := ab.x * -d_orth.y - -d_orth.x * ab.y - var u := det_a2 / det - - # 4) Construct corner points - var cap_half_length := u * d_orth # = P - top - new_points[out_i] = top + cap_half_length - new_points[out_i + 1] = top - cap_half_length - out_i += 2 - else: - new_points[out_i] = b + d / miter_denom - out_i += 1 - - ab = bc - ab_orth = bc_orth - a = b - b = c - - new_points[out_i] = points[-1] + (points[-1] - points[-2]).orthogonal().normalized() * offset - out_i += 1 - new_points.resize(out_i) - - return new_points diff --git a/godot/addons/rmsmartshape/collision_gen.gd.uid b/godot/addons/rmsmartshape/collision_gen.gd.uid deleted file mode 100644 index 0a14ade..0000000 --- a/godot/addons/rmsmartshape/collision_gen.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bw6tjof8l1ebn diff --git a/godot/addons/rmsmartshape/common_functions.gd b/godot/addons/rmsmartshape/common_functions.gd deleted file mode 100644 index d08c537..0000000 --- a/godot/addons/rmsmartshape/common_functions.gd +++ /dev/null @@ -1,50 +0,0 @@ -@tool -extends Node -class_name SS2D_Common_Functions - - -static func sort_z(a, b) -> bool: - if a.z_index < b.z_index: - return true - return false - - -static func sort_int_ascending(a: int, b: int) -> bool: - if a < b: - return true - return false - - -static func sort_int_descending(a: int, b: int) -> bool: - if a < b: - return false - return true - - -static func to_vector3(vector: Vector2) -> Vector3: - return Vector3(vector.x, vector.y, 0) - - -static func merge_arrays(arrays: Array) -> Array: - var new_array := [] - for array: Array in arrays: - for v: Variant in array: - new_array.push_back(v) - return new_array - - -## Returns a cleared mesh object in the given buffer at the given index. -## If the index is out of bounds, creates and appends a new object. -## Used for caching and reusing SS2D_Mesh objects to prevent changing resource IDs even if there was -## no change which in turn causes VCS noise. -static func mesh_buffer_get_or_create(mesh_buffer: Array[SS2D_Mesh], idx: int) -> SS2D_Mesh: - var mesh: SS2D_Mesh - - if idx < mesh_buffer.size(): - mesh = mesh_buffer[idx] - mesh.clear() # Absolutely ensure working on a clean object - else: - mesh = SS2D_Mesh.new() - mesh_buffer.push_back(mesh) - - return mesh diff --git a/godot/addons/rmsmartshape/common_functions.gd.uid b/godot/addons/rmsmartshape/common_functions.gd.uid deleted file mode 100644 index 67fbf55..0000000 --- a/godot/addons/rmsmartshape/common_functions.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://fenpoi32dmlo diff --git a/godot/addons/rmsmartshape/documentation/.gdignore b/godot/addons/rmsmartshape/documentation/.gdignore deleted file mode 100644 index e69de29..0000000 diff --git a/godot/addons/rmsmartshape/documentation/Controls.md b/godot/addons/rmsmartshape/documentation/Controls.md deleted file mode 100644 index 424b2d8..0000000 --- a/godot/addons/rmsmartshape/documentation/Controls.md +++ /dev/null @@ -1,47 +0,0 @@ -# SmartShape2D - Controls and Hotkeys - - - -## Controls - Point Create - -- Add Point - - Left Click Anywhere in the viewport - -- Leave Point Create Mode - - ESCAPE - -## Controls - Point Edit - -- Add Point - - Either: - - Hold ALT and Left Click Anywhere in the viewport - - Click on an edge between two points - -- Grab closest point - - Hold CTRL - -- Cycle through texture indices of a point - - Mouseover a point and MOUSEWHEEL up or down to increment / decrement the texture index - -- Flip texture - - Mouseover a point and press SPACE - -- Change texture width property - - Mouseover a point, hold SHIFT, then MOUSEWHEEL up or down to increment / decrement the texture width - -- Add Bezier curve - - Mouseover a point, hold SHIFT, then click and drag to create control points on the point - -- Create New Shape - - Hold SHFT + ALT and click - - The location of the click will be the the first point of a newly created Shape Node - -### Overlap - -When multiple points and edges overlap, it can be ambiguous what clicking will do. -SmartShape adheres the following rules: -- If a control point overlaps a vertex, the control point takes priority -- If a control point or vertex overlaps an edge: - - Clicking will move the control point or vert - - Clicking while holding ALT will create new point on the edge - diff --git a/godot/addons/rmsmartshape/documentation/FAQ.md b/godot/addons/rmsmartshape/documentation/FAQ.md deleted file mode 100644 index 7fb4e2b..0000000 --- a/godot/addons/rmsmartshape/documentation/FAQ.md +++ /dev/null @@ -1,48 +0,0 @@ -# SmartShape2D - FAQ - - - -## Why aren't my textures repeating? - -> [!NOTE] -> Starting with SS2D v3.3, edge textures will always be tiled regardless of the `repeat` setting. - -If your textures aren't repeating and look something like this: - -![Non-Repeating-Texture-IMG](./imgs/faq-texture-repeat.png) - -The issue is most likely that you forgot to enable texture `repeat`. - -![Creating CanvasTexture](imgs/canvas-item-repeat.png) - -## Why isn't my shape updating when I change the Light Mask? - -There is no accessible signal when changing the Light Mask setting in editor, hence no update is triggered. -The light mask will be correctly set on the next shape update. - -If you need to tell the shape to update its rendering by code, call the `set_as_dirty()` or `force_update` method. - -## Why does changing the width look so ugly? - -Changing the width of the quads generally looks best with welding turned off. - -If welding is on, you can still change the width of the quads, but you may need to play with it a bit. -It's best that you change the width gradually in small increments instead of sharply. -Sharply changing the width will result in odd looking shapes. - -[Non-perspective rendering to a non-parallelogram is kinda tough](http://reedbeta.com/blog/quadrilateral-interpolation-part-1/) - -If anyone has any insights on this issue, please feel free to open an issue on this subject -and let us know how we might be able to fix it - - -## The shape is not rendered - -Usually appears in combination with the following error message. - -> canvas_item_add_polygon: Invalid polygon data, triangulation failed - -This error indicates there are inside-out parts, i.e. edges intersecting other edges. -It is often caused by having two consecutive points at the same position. - -When generating closed SmartShapes programmatically, make sure to call `get_point_array().close_shape()` and do not manually add the closing point. diff --git a/godot/addons/rmsmartshape/documentation/Godot4.md b/godot/addons/rmsmartshape/documentation/Godot4.md deleted file mode 100644 index 964a356..0000000 --- a/godot/addons/rmsmartshape/documentation/Godot4.md +++ /dev/null @@ -1,42 +0,0 @@ -# Using SmartShape2D with Godot 4 - -Godot 4 moved `repeat` for textures as an import option to a per-node option. On how to make textures repeat and -set normal maps see [section below.](#repeating-textures-and-normal-textures-with-canvastexture) - -By default, **shape resources are shared** when the shape is copy-pasted. Editing points will edit every copy of that shape. -To make point geometry unique, press **"Make Unique"** property button in Geometry property group in the inspector: - -![Making Shape Geometry Unique](imgs/godot4-make-points-unique.png) - -## Repeating Textures and Normal Textures with CanvasTexture - -> [!NOTE] -> Starting with SS2D v3.3, edge textures will always be tiled regardless of the `repeat` setting. - -`CanvasItem`, the base class of `Node2D` has a `Texture` section with `repeat`. If you aren't using a normal, you can set it here. -By default, this setting is inherited by children nodes so you could set it on a parent node (assuming all the children need repeating textures or it's easier to disable for a few specific nodes than turn it on for most). - -![Creating CanvasTexture](imgs/canvas-item-repeat.png) - -Normal textures are no longer set in a material resource. - -To set normal textures, you can create a `CanvasTexture` resource in the inspector on any property, that allows setting a `Texture2D`. - -![Creating CanvasTexture](imgs/godot4-create-texture-res.png) - -`CanvasTexture` allows you to assign diffuse texture and normal map texture, as well as set textures to `repeat`: - -![Assigning Texture, Normal Map and Setting Repeat flag](img/../imgs/godot4-assign-normal-tex.png) - -## Converting Projects from Godot 3.x - -Scene files with shapes saved in Godot 3.x should load in Godot 4 project. However, you may encounter some issues. Here is a list of expected problems: -1. Textures are looking weird, not repeated. -2. Normal textures are not used. - -Please read the section on [how to set repeat and use normal textures in Godot 4](#repeating-textures-and-normal-textures-with-canvastexture). - -## Removed Features - -- The Godot 4 version of this addon does not support 1.x RMSmartShape2D nodes anymore. -- SS2D_Shape_Meta node was removed, since its functionality is available copy-pasted shapes by default. diff --git a/godot/addons/rmsmartshape/documentation/Install.md b/godot/addons/rmsmartshape/documentation/Install.md deleted file mode 100644 index 27491b0..0000000 --- a/godot/addons/rmsmartshape/documentation/Install.md +++ /dev/null @@ -1,20 +0,0 @@ -# SmartShape2D - Install - -## Asset Library - -- After installing the plugin, you may encounter an error, this is normal. -- You need to restart Godot before using the plugin. - -## Manual Install - -- Clone the repository at . -- Move the `addons/rmsmartshape` folder to your project's `addons` folder. -- Open your project in Godot to have the addon install. -- After installing the plugin, you may encounter an error, this is normal. -- Restart Godot. - -## Activate Plugin - -- After Installing the plugin, activate the plugin by navigating to `Project -> Project Settings... -> Plugins` - -![Activate Plugin](./imgs/PluginActivate.png) diff --git a/godot/addons/rmsmartshape/documentation/Normals.md b/godot/addons/rmsmartshape/documentation/Normals.md deleted file mode 100644 index 91c3e7b..0000000 --- a/godot/addons/rmsmartshape/documentation/Normals.md +++ /dev/null @@ -1,60 +0,0 @@ -# Normals - -## Default Normals - -Even if you assign normal textures to your Edge Material, the normals will look wrong. - -For example, consider the following image: - -![Normals Wrong](./imgs/NormalWrong.png) - -The normals in the image clearly don't line up with where the light is actually coming from. - -## Encoding Normal data in the canvas_item Vertex Shader Color Parameter - -As SmartShape renders the edges, the textures and their normal textures are also rotated. -This will result in incorrect normals. -To solve this, we can use a shader to correctly calculate the normals. - -The tricky part lies in how few ways there are to pass data to a canvasItem shader on a per-vertex basis. -See here for the full list: -https://docs.godotengine.org/en/stable/tutorials/shading/shading_reference/canvas_item_shader.html#doc-canvas-item-shader - -Fortunately, the COLOR parameter can be used for this purpose. -The COLOR ENCODING paramter of an Edge Material can be used to choose what data is encoded in the -Vertex Shader's Color Parameter. - -If we set the COLOR ENCODING value to "Normals", we get this: - -![Normals wrong with weird diffuse colors](./imgs/NormalColors.png) - -Ok, so now the normals still look wrong, but the colors look wrong too. Great. - -There is one final step before our normals will be correct. We need to decode the normal data in a shader. - - -## Writing a Shader - -You'll want to assign a new shader to the Edge Material's material property. -This shader will determine how each edge is rendered. - -Here's a sample shader to decode our normal data and set our actual color to that of our diffuse texture: - -```glsl -shader_type canvas_item; - -varying mat2 NORMAL_MATRIX; - -void vertex() { - NORMAL_MATRIX = mat2(COLOR.rg, COLOR.ba)*2.0 - mat2(vec2(1.0), vec2(1.0)); -} - -void fragment() { - NORMAL.xy = NORMAL_MATRIX*NORMAL.xy; - COLOR = texture(TEXTURE, UV); -} -``` - -After assigning this shader the the Edge Material's material property, our normals finally look right: - -![Normals Correct](./imgs/NormalCorrect.png) diff --git a/godot/addons/rmsmartshape/documentation/Quickstart.md b/godot/addons/rmsmartshape/documentation/Quickstart.md deleted file mode 100644 index 38166e4..0000000 --- a/godot/addons/rmsmartshape/documentation/Quickstart.md +++ /dev/null @@ -1,130 +0,0 @@ -# SmartShape2D - QuickStart ---- -![Finished Image](./imgs/Inpsector-EdgeMaterialsNormalRange.png) - -If you feel like your workflow with SmartShape2D is a little bit slow, try reading [Controls and Hotkeys](./Controls.md). The hotkeys may help you work with the tool more effectively. - -## Basic understanding -SmartShapes work similarly to [tilesets](https://docs.godotengine.org/en/latest/tutorials/2d/using_tilesets.html) but are not bound to a grid. They can be used to create polygons and even organic shapes. This allows for level design akin to [Rayman Legends](https://youtu.be/WFu1utKAZ18?si=_33TaErpHSh-r732&t=916) (based on the UbiArt Framework). - -Each SmartShape is made up of multiple textures that are responsible for rendering different aspects like corners or edges: - -![Texture Breakdown](./imgs/smartshape_textures_breakdown.png) - -## Creating a Shape - - - -- First, instance a `SS2D_Shape` node - - `SS2D_Shape_Closed` and `SS2D_Shape_Open` are exactly the same and only exist for backwards compatibility -- SS2D_Shape_Anchor is a node that attaches to a shape - -![Nodes](./imgs/NewNode-SS2D_Nodes.png) - -## Editing the Shape - -- After creating the shape node, make sure it's selected and the toolbar appears and is in Point Edit mode - - ![Toolbar Default State](./imgs/Toolbar-PointEdit.png) -- Hold ALT and Left Click on the viewport to add points - - If this is a closed shape, the polygon will close after adding the 3rd point -- You should now have a shape consisting of a few points and lines: - -![Toolbar Default State](./imgs/ShapeClosed-Untextured.png) - -## Setting the Fill Texture of the Shape (Closed Shape only) - -- To give it some life, we'll want to edit the "Shape Material" in the Inspector -- Under "Shape Material" Expand "Fill Textures" and you'll see an empty array -- Set the Array's size to '1' -- Assign a texture to the newly created slot in the array -- After assigning the shape should now have a valid texture - - If nothing happens after setting the texture, try to force the shape to update by adjusting one of the points -- **Note that "Fill Textures" does not affect open shapes at all** -- If you want to add a normal_texture, you would add it using the "Fill Texture Normals" property - -![Fill Texture Set](./imgs/ShapeClosed-FillTextured.png) - -## Texturing the Edges - -- This where the rubber hits the road, the real meat of the tool -- Under "Shape Material" add an element to the "Edge Meta Materials" property - - Shape Material -> Edge Meta Materials -- Set the resource of the newly created element to "SS2D_Material_Edge_Metadata" - - Unfortunately, due to Godot limitations, every avaiable resource will offered to you instead of the one you want - - The options are alphabetized though, which helps in finding the resource you want -- Expand the first element of the "Edge Meta Materials" that you just set - - Shape Material -> Edge Meta Materials -> element 1 -- Set the value of the "Edge Material" property to a new resource of type "SS2D_Material_Edge" - - Shape Material -> Edge Meta Materials -> element 1 -> Edge Material -- Expand "Edge Material" that you just set -- Add an element to "Textures" and assign the texture to one that you want to use as an edge -- The shape's edges should now update using the texture you set - - If nothing happens after setting the texture, try to force the shape to update by adjusting one of the points -- If you want to add a normal_texture, you would add it using the "Texture Normals" property -- Godot should now look something like this: - -![Inspector](./imgs/Inpsector-EdgeMaterial.png) - -### Corners - -- If your shape has sharp 90-degree corners, the texture can look a bit warped in those places -- You can specify a unique texture to use for inner and outer corners for each Edge Material -- The following Edge Material properties are used for corners - - Textures Corner Inner - - Texture Normals Corner Inner - - Textures Corner Outer - - Texture Normals Corner Outer -- See how the addition of outer corner textures improves the square created earlier - -![Inspector](./imgs/Inpsector-EdgeMaterialCornerOuter.png) - -### Multiple Edge Materials in One Edge - -- You can add as many Edge Meta Materials as you want to a Shape Material, each with their own Edge Material -- For instance, you can add an additional egde with a rock texture (and its own set of corner textures) and have it render behind the grass - - To have it render behind the grass, Set the Z index of the meta material - -![Inspector](./imgs/Inpsector-EdgeMaterials2.png) - -### Normal Range - -- Each Meta material has a Normal Range -- The Normal Range indicates when a texture should be rendered - - If the normal range is 0 - 360 or 0 - 0, then any angle is considered in range and the edge will always render - - Angle "0" is Facing directly Right - - Angle "90" is Facing directly Up - - Angle "180" is Facing directly Left - - Angle "270" is Facing directly Down - -- If you wanted to, for example: - - Have rocks display on the bottom part of the shape only - - Have grass display on the sides and top of the shape only -- You could: - - Set the grass Normal Range to 0 - 180 - - Set the rock Normal Range to 181 - 359 - -![Inspector](./imgs/Inpsector-EdgeMaterialsNormalRange.png) - -### Material Overrides - -- Using Material Overrides will allow you to change how specific edges are rendered -- For Example, to prevent the left edge from rendering, we'll do the following: - - Select the edge edit button from the toolbar ![](./imgs/icon_edge.png) - - Right Click the left edge of the shape - - Press the "Material Override" Button - - Uncheck the "Render" Checkbox - -![Edge NoRender](./imgs/EdgeEdit-NoRender.png) - -- You can use material overrides to also specify a specific material for a single edge -- For example, Checking Render and choosing the "Rock" Edge Material will cause the edge to render as rocks, even though the NormalRange configuration would otherwise have it render as grass - -### Multiple Textures - -- If more than one texture is specified for an Edge Material, you can specify which texture should be used -- Enter Point Edit mode, mouseover a point, and scroll up or down to change the texture index - -## Anchoring Nodes to the Shape - -- To anchor nodes directly to the SmartShape2D node, use `SS2D_Shape_Anchor` -- You can then make nodes children to the anchor diff --git a/godot/addons/rmsmartshape/documentation/Resources.md b/godot/addons/rmsmartshape/documentation/Resources.md deleted file mode 100644 index 08a3bcd..0000000 --- a/godot/addons/rmsmartshape/documentation/Resources.md +++ /dev/null @@ -1,115 +0,0 @@ -# SmartShape2D - Resources - - - -## Shape Materials - -Shape materials provide all the texture and collision information needed by the SmartShape nodes. -Once a shape material is defined, it can be easily reused by any number of SmartShape2D nodes. - -- Edge Meta Materials - - An array of resources of type SS2D_Material_Edge_Metadata -- Fill Textures - - Used as the texture for the inside of the polygon for Closed Shapes - - Currently, only the first texture can be used, multiple textures may be supported at a later date -- Normal Textures - - In Godot 4, you can set normal textures with `CanvasTexture` resource. -- Fill Texture Z Index - - Each Edge Meta Material has a ZIndex indicating which edges are drawn first - - This sets the ZIndex for the fill texture - - This allows the user to draw the fill texture in front of some edges or behind others -- Fill Mesh Offset - - The Offset of the Fill Mesh - - Can be used to grow / shrink the fill mesh -- Render Offset - - Every edge in the shape will be offset by this amount -- Weld - - Whether to weld the last quad of an edge with the first quad of the next edge - -## Edge Meta Material - -An Edge Meta Material doesn't contain the actual textures used to render an edge like **Edge Material** does. -Instead, this resource contains a single **Edge Material** and describes how and when to render the edge. - -- Normal Range - - The angles at which an edge is allowed to be rendered -- Weld - - Whether to weld the quads in this edge -- Taper Sharp Corners - - Edge vertices sharper than 90° that aren't rendered as corners, will be tapered and not welded - - Will not work properly on shapes with curves -- Render - - Whether this edge is visible -- Z Index - - Dictates the order in which edges are drawn -- Offset - - Offset of the edge - - Can use a positive or negative value to draw the edges closer or further from the shape - -## Normal Range - -The Normal Range indicates when a texture should be rendered. -Each shape will compare the Surface Normal of an edge to the Normal Range in each Edge Meta Material. -If the edge's Normal is inside a Meta Material's Normal Range, the Meta Material's Edge Material is rendered. - -![NormalRangeVisual](./imgs/AngleExplaination.png) - -- A Normal Range is specified in Degrees - - If the normal range is 0 - 360 or 0 - 0, any angle is considered in range and the edge will always render - - Angle "0" is Facing directly Right - - Angle "90" is Facing directly Up - - Angle "180" is Facing directly Left - - Angle "270" is Facing directly Down - -## Edge Material - -The actual textures used to define an edge - -### Textures - -- The primary textures used for the edge -- At least one texture must be defined -- Example: ![Grass](./imgs/grass.png) - -### Taper Textures - -These textures will be used as the first or last quad in an edge. -They're named "Taper Textures" because the purpose is to show the edge "tapering off" -- Textures_Taper_Left is the first quad in an edge - - Example: ![Grass Taper Left](./imgs/grass-taper-left.png) -- Textures_Taper_Right is the final quad in an edge - - Example: ![Grass Taper Right](./imgs/grass-taper-right.png) - -### Corner Textures - -These textures will be used when the edge forms a sharp corner (80 degrees - 100 degrees) -These are used because corners can look warped when using only regular textures -- Texture_Corner_Inner is used when the corner forms an inner corner - - Example: ![Grass Corner Inner](./imgs/grass-corner-inner.png) -- Texture_Corner_Outer is used when the corner forms an outer angle - - Example: ![Grass Corner Outer](./imgs/grass-corner-outer.png) - -### Normal Texture and Repeat - -To use normal textures, you can create a `CanvasTexture` resource in the inspector on any property, -that allows to set a texture. There you can assign your texture and your normal texture, as well as set -those to `repeat`. - -### Repeat Textures - -See previous section. - -### Fit Mode - -Most likely, the textures you use will not *perfectly* fit the polygon. -This setting allows you to determine how SmartShape will rectify this. - -Different options may look better or worse depending on the art-style. - -- Squish and Stretch - - Texture will be mutated - - Either slightly squished or stretched to fit the polygon -- Crop - - Texture will not be mutated - - Texture will simply be cropped when changing from one texture to the next - diff --git a/godot/addons/rmsmartshape/documentation/Shapes.md b/godot/addons/rmsmartshape/documentation/Shapes.md deleted file mode 100644 index 14c0f41..0000000 --- a/godot/addons/rmsmartshape/documentation/Shapes.md +++ /dev/null @@ -1,90 +0,0 @@ -# SmartShape2D - Shapes - -Each shape consists of a set of points. You can directly edit either the points or the edges between the points in the viewport. - -Shapes are configured to use a [Shape Material](./Resources.md#ShapeMaterial) which determines how the shape is rendered. - -A shape can be open or closed. Each new shape starts open. To close a shape, simply add a point on top of the first one. - - -## Properties - -> [!NOTE] -> Most properties now have documentation comments. - - - -### Editor Debug - -- Will show the bounding box for each quad in the mesh of edges. -- Can be helpful to illustrate why a shape doesn't look the way you expect. - -### Flip Edges - -Will flip the edges of the shape (invert y). - -### Render Edges - -Whether the edges of the shape should be rendered. - -### Collision Size - -Width of the collision polygon. -Only relevant for open shapes or `Hollow` collisions. - -### Collision Offset - -- Offset where the collision polygon begins -- A **positive** value offsets the collision polygon **outwards**. -- A **negative** value offsets the collision polygon **inwards**. - -### Tessellation Stages - -- Number of stages in the curve tessellation process (Uses Curve2D Internally). -- First Param in Curve2D.tessellate. -- See [Curve2D Documentation](https://docs.godotengine.org/en/3.2/classes/class_curve2d.html#class-curve2d-method-tessellate). - -### Tessellation Tolerance - -- Tolerance Degrees in the curve tessellation process (Uses Curve2D Internally). -- Second Param in Curve2D.tessellate. -- See [Curve2D Documentation](https://docs.godotengine.org/en/3.2/classes/class_curve2d.html#class-curve2d-method-tessellate). - -### Collision Generation Method - -- Controls which method should be used to generate the collision shape. -- See also in-engine documentation. - -### Collision Update Mode - -- Controls when to update collisions. -- See also in-engine documentation. - -### Curve Bake Interval - -- Bake interval value for Curve2D. -- See [Curve2D Documentation](https://docs.godotengine.org/en/3.2/classes/class_curve2d.html#class-curve2d-property-bake-interval). - -### Collision Polygon Node Path - -- The path to the `CollisionPolygon2D` that the SmartShape will use for collision. -- Is auto-assigned when pressing the generate collision button. - -### Shape Material - -- The material that this shape will use to render itself. -- For backwards compatibility `fill_texture_z_index` defaults to `-10`. Set this to `0` and enable `fill_texture_show_behind_parent` in order to preserve Godot's normal z-sorting when layering with other nodes. - -### Points - -- **There is no need to edit this property by hand, but you can if you'd like.** -- Contains points and meta-data for the points contained in this shape. -- This data structure is updated as you manipulate the shape. - -### Material Overrides - -- **There is no need to edit this property by hand, but you can if you'd like.** -- When an edge is given a "Material Override" the data for that edge is stored here. -- This data structure is updated as you manipulate the shape. -![Edge Data Popup](./imgs/EdgeEdit-MaterialOverride.png) - diff --git a/godot/addons/rmsmartshape/documentation/Toolbar.md b/godot/addons/rmsmartshape/documentation/Toolbar.md deleted file mode 100644 index 3cbb340..0000000 --- a/godot/addons/rmsmartshape/documentation/Toolbar.md +++ /dev/null @@ -1,79 +0,0 @@ -# SmartShape2D - Toolbar - -![Toolbar Default State](./imgs/Toolbar-PointEdit.png) - - - -## Create Mode - -- In this mode you can start creating a new shape. -- Left-Click anywhere to add a new point. -- Press ESCAPE to exit create mode. -- Hold down ALT and Left-Click to create a point between the two points closest to your mouse. - -## Point Mode - -- In this mode you can add, delete, and move the points that make up a shape -- To **Add** a new point to the shape: - - Hold down ALT and Left-Click anywhere on the viewport to add a point between the two points closest to your mouse. - - Left-Click on an edge between two points. -- To **Move** a point, Left-Click on any point and drag -- To **Delete** a point, Right-Click on any point -- To set the **Control Points** of a point (for curves), hold **Shift**, Left Click on any point and drag - - After the Control Points have been set, you can edit them individually by Left-Clicking and dragging - - You can delete control points by right-clicking them -- To make an empty clone SmartShape2D, hold down ALT + SHIFT and Left-Click anywhere in the viewport. - -## Edge Mode - -- In this mode you can Move Edges and choose how specific edges are rendered -- To **Move** an Edge, Left Click and Drag the Edge -- To **Change an Edges Rendering**, right-click the edge and press "**Material Override**" -![Edge Data Popup](./imgs/EdgeEdit-MaterialOverride.png) - -- This popup allows you to **change how edges are rendered** - - **Render** will toggle whether this edge will be drawn with Edge Materials - - **Set Material** allows you to choose a specific Edge Material to use to render this edge - -## Origin Set - -- This tool allows you to set the origin of any SmartShape -- To **Set the Origin** Left Click anywhere on the viewport - -## Collision Tool - -- Creates a `CollisionPolygon2D` and assigns it to the shape -- It will automatically update when the shape changes -- It can be moved where desired - -## Snapping - -When Moving / Adding points, snapping will cause the positions of the points to snap to the grid. This works the same as Godot's built-in snapping. -You can have snapping either use Global Space, or space relative to the shape's origin. - -## More Options - -More options are listed in the 3-dots-menu. - -### Defer Mesh Updates - -If enabled, does not update shapes immediately when moving points in the editor. -Instead, it will only update after the left mouse button has been released. - -Useful if shape generation becomes too slow with complex shapes. - -### Perform Version Check - -Compares the project's SS2D version and installed SS2D version to determine if there have been breaking changes that require project conversion. - -Usually this is not necessary to run manually, as this check is performed automatically on editor startup. - - -### Collision Generation Options - -Related to [Collision Tool](#collision-tool). - -Allows selecting a parent node where newly generated `CollisionPolygon2D` nodes will be placed. -Accepts arbitrary node paths, group names and [scene unique names](https://docs.godotengine.org/en/latest/tutorials/scripting/scene_unique_nodes.html). - -If the node does not exist, it will be ignored. diff --git a/godot/addons/rmsmartshape/documentation/VersionHistory.md b/godot/addons/rmsmartshape/documentation/VersionHistory.md deleted file mode 100644 index e924a95..0000000 --- a/godot/addons/rmsmartshape/documentation/VersionHistory.md +++ /dev/null @@ -1,117 +0,0 @@ -# Version History - -## 2.x -### 2.2 -January 4th 2021 -### Fix -- Fix for crash that would occur when points were aligned *just* right -- See issue 66 - + https://github.com/SirRamEsq/SmartShape2D/issues/66 -### Features -- Each Edge Material can now have a Material (Shader) -- Each Edge Material Meta can have a z-index and z-as-relative set -- See issue 64 - + https://github.com/SirRamEsq/SmartShape2D/issues/64 - -### 2.1 -December 14th 2020 -#### Significant Changes from 2.0 -- Improved Width handling -- Improved Welding -- Rendering is now achieved by having multiple child-nodes each render a piece of the shape - + Previously, all the rendering was done by the shape node - + Improves performance - + Fixes lighting bugs -- Point Creation mode reimplemented - + Mode active by default - + Can be exited by pressing ESC -- Several usability additions - + Hotkey for grabbing closest point - + Hotkey for creating new shape at point - + Width Grabber for closest point - + Preview for adding points -- Several Bug fixes and issues closed -#### New Features -- Meta Shapes Introduced -- "Fit mode" added to edge material - + Can either squash and stretch the texture or crop it -#### Minor Changes -- Changes to GUI Theme - + More in line with standard Godot -- Add windows scripts for running unit tests -- Changed default snap settings to 8x8 pixels - -### 2.0 -September 7th 2020 -#### Significant Changes from 1.0 -- Edge Textures are no longer determined by a cardinal direction (UP, DOWN, LEFT, RIGHT) - - Instead, a starting and ending normal angle is specified for each edge -- Textures are now defined per-edge instead of per-shape -#### New Features -- Taper textures - - Instead of simply ending, the user can have an edge "taper-off" -- Editing by Edges -- Material Overrides -#### Internal Changes -- Completely overhauled everything -- A rudimentary constraint system is in place - - Closed shapes will add a point when closing, then constrain the added point's position to the first point -- Points are no longer refered to by index, they are refered to by keys - - This enables points to have relationships that aren't affected when: - - Adding/Removing a point - - Changing orientation of the poly -- Many Unit and Integration tests - - Refactored original working code to better support testing -- Kept original scripts and classes from version 1.0 to ease importing - -## 1.x -### Changes in 1.3 -This update primarily fixes bugs and improves existing features to be more usable. -#### Changes -- Merged top/left/right/bottom offset into one variable. render offset -#### Fixes -- Input bugs -- Edge Flipping -- Polygon orientation bugs -- Quad Welding -- Corer quad generation and welding -- Collision variables in the RMSmartShapeMaterial working as intended - -### Changes in 1.2 -#### Tweaks -- Refactoring -- Toolbar takes less space -- Minor bug fixes - -#### New Features -- Bezier Curves! - - Hold shift on a control point to create a curve -- Corner Quads! - - Both inner and outer corner quads are now generated - - Textures can be speciied for each direction of both inner and outer quads -- Edge Moving! - - Can move an edge (two points) by pressing SHIFT in move mode and dragging the edge - -### Changes in 1.1 -- Refactoring -- Fixed Errors Occuring when Texture Arrays are size '0' but not null -- Fixed sync between texture, flip, and width indicies - - Would sometimes share a single array between the 3 vars - - Are all unique now - -- Snapping -- More informative toolbar - -### Changes in 1.0 -- Fixed many debug errors reported related to indexing beyond array sizes -- Fixed control point wrapping of RMSmartShapeAnchor2D nodes anchored to RMSmartShape2D nodes. -- Tested on newly released 3.2 Godot. - -### Changes in 0.91 -- Edges are calculated in relationship to object space instead of screen space -- Added option to allow user to let the object recalculate edges based on screen space. -- Fixed uv calculations for flipped textures. -- Fixed uv bug for edge sections less than half the size of texture width -- Added option to allow for a RMSmartShapeAnchor to mimic scale of monitored node -- Removed sections of code related to clockwise versus clockwise checks, very specifically regarding the direction of texture edges. -- Corrected normal texture bug for fill and edge rendering diff --git a/godot/addons/rmsmartshape/documentation/imgs/AngleExplaination.png b/godot/addons/rmsmartshape/documentation/imgs/AngleExplaination.png deleted file mode 100644 index 5b74564..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/AngleExplaination.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-MaterialOverride.png b/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-MaterialOverride.png deleted file mode 100644 index 56c0070..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-MaterialOverride.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-NoRender.png b/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-NoRender.png deleted file mode 100644 index 789ac59..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/EdgeEdit-NoRender.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterial.png b/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterial.png deleted file mode 100644 index e031a52..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterial.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialCornerOuter.png b/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialCornerOuter.png deleted file mode 100644 index 42bb12b..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialCornerOuter.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterials2.png b/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterials2.png deleted file mode 100644 index f03a474..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterials2.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialsNormalRange.png b/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialsNormalRange.png deleted file mode 100644 index cfc3a68..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/Inpsector-EdgeMaterialsNormalRange.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/NewNode-SS2D_Nodes.png b/godot/addons/rmsmartshape/documentation/imgs/NewNode-SS2D_Nodes.png deleted file mode 100644 index df063e4..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/NewNode-SS2D_Nodes.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/NormalColors.png b/godot/addons/rmsmartshape/documentation/imgs/NormalColors.png deleted file mode 100644 index 904f83a..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/NormalColors.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/NormalCorrect.png b/godot/addons/rmsmartshape/documentation/imgs/NormalCorrect.png deleted file mode 100644 index 2c899e2..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/NormalCorrect.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/NormalWrong.png b/godot/addons/rmsmartshape/documentation/imgs/NormalWrong.png deleted file mode 100644 index 79c188e..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/NormalWrong.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/PluginActivate.png b/godot/addons/rmsmartshape/documentation/imgs/PluginActivate.png deleted file mode 100644 index 1a96705..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/PluginActivate.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-FillTextured.png b/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-FillTextured.png deleted file mode 100644 index d768f8e..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-FillTextured.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-Untextured.png b/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-Untextured.png deleted file mode 100644 index 275b25c..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/ShapeClosed-Untextured.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/Toolbar-PointEdit.png b/godot/addons/rmsmartshape/documentation/imgs/Toolbar-PointEdit.png deleted file mode 100644 index 8bc8b56..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/Toolbar-PointEdit.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/canvas-item-repeat.png b/godot/addons/rmsmartshape/documentation/imgs/canvas-item-repeat.png deleted file mode 100644 index 1045c52..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/canvas-item-repeat.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat-import.png b/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat-import.png deleted file mode 100644 index f5963d7..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat-import.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat.png b/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat.png deleted file mode 100644 index 1ceedbf..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/faq-texture-repeat.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/godot4-assign-normal-tex.png b/godot/addons/rmsmartshape/documentation/imgs/godot4-assign-normal-tex.png deleted file mode 100644 index cc64e74..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/godot4-assign-normal-tex.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/godot4-create-texture-res.png b/godot/addons/rmsmartshape/documentation/imgs/godot4-create-texture-res.png deleted file mode 100644 index 4a0e417..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/godot4-create-texture-res.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/godot4-make-points-unique.png b/godot/addons/rmsmartshape/documentation/imgs/godot4-make-points-unique.png deleted file mode 100644 index 9b1e49d..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/godot4-make-points-unique.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/grass-corner-inner.png b/godot/addons/rmsmartshape/documentation/imgs/grass-corner-inner.png deleted file mode 100644 index 59c4705..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/grass-corner-inner.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/grass-corner-outer.png b/godot/addons/rmsmartshape/documentation/imgs/grass-corner-outer.png deleted file mode 100644 index 5aa5b59..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/grass-corner-outer.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/grass-taper-left.png b/godot/addons/rmsmartshape/documentation/imgs/grass-taper-left.png deleted file mode 100644 index c28f026..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/grass-taper-left.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/grass-taper-right.png b/godot/addons/rmsmartshape/documentation/imgs/grass-taper-right.png deleted file mode 100644 index c3803fc..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/grass-taper-right.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/grass.png b/godot/addons/rmsmartshape/documentation/imgs/grass.png deleted file mode 100644 index caa0420..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/grass.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/icon_edge.png b/godot/addons/rmsmartshape/documentation/imgs/icon_edge.png deleted file mode 100644 index e2e08d6..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/icon_edge.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/sample.gif b/godot/addons/rmsmartshape/documentation/imgs/sample.gif deleted file mode 100644 index 0e9064e..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/sample.gif and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/sample.png b/godot/addons/rmsmartshape/documentation/imgs/sample.png deleted file mode 100644 index bf47a3e..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/sample.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/documentation/imgs/smartshape_textures_breakdown.png b/godot/addons/rmsmartshape/documentation/imgs/smartshape_textures_breakdown.png deleted file mode 100644 index 36a7886..0000000 Binary files a/godot/addons/rmsmartshape/documentation/imgs/smartshape_textures_breakdown.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd b/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd deleted file mode 100644 index 89ef973..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd +++ /dev/null @@ -1,64 +0,0 @@ -@tool -extends VBoxContainer -class_name SS2D_NormalRangeEditor - -signal value_changed - -var start: float: get = _get_start, set = _set_start -var end: float: get = _get_end, set = _set_end -var zero_equals_full_circle := true - -var _progress_bar: TextureProgressBar: - get: - if _progress_bar == null: - _progress_bar = get_node_or_null("%TextureProgressBar") - return _progress_bar - - -func _ready() -> void: - _set_initial_angles() - - -func _enter_tree() -> void: - _set_initial_angles() - - -func _set_initial_angles() -> void: - _set_start(_progress_bar.radial_initial_angle) - _set_end(_progress_bar.radial_fill_degrees) - - -func _on_startSlider_value_changed(value: float) -> void: - _set_start(value) - - -func _on_endSlider_value_changed(value: float) -> void: - _set_end(value) - - -func _set_start(value: float) -> void: - var fill: float = _progress_bar.radial_fill_degrees - var init_angle: float = 360.0 - fill - value + 90.0 - _progress_bar.radial_initial_angle = _mutate_angle_deg(init_angle) - - -func _get_start() -> float: - return _progress_bar.radial_initial_angle - - -func _set_end(value: float) -> void: - _progress_bar.radial_fill_degrees = _mutate_angle_deg(value) - - -func _get_end() -> float: - return _progress_bar.radial_fill_degrees - - -func _on_SS2D_StartEditorSpinSlider_value_changed(value: float) -> void: - _set_start(value) - - -func _mutate_angle_deg(v: float) -> float: - if zero_equals_full_circle and v == 0.0: - return 360.0 - return v diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd.uid b/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd.uid deleted file mode 100644 index 77a39a7..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://r4rt5qimdlyf diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.tscn b/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.tscn deleted file mode 100644 index 27cd99f..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.tscn +++ /dev/null @@ -1,32 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://cg1vy768oxwxr"] - -[ext_resource type="Texture2D" uid="uid://dajqljvjm2d2q" path="res://addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png" id="1"] -[ext_resource type="Script" uid="uid://r4rt5qimdlyf" path="res://addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.gd" id="2"] -[ext_resource type="Texture2D" uid="uid://dgd4sbhsw1no3" path="res://addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png" id="3"] -[ext_resource type="Texture2D" uid="uid://cax163h05b60j" path="res://addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png" id="4"] - -[node name="NormalRangeEditor" type="VBoxContainer"] -anchors_preset = -1 -anchor_right = 0.087 -anchor_bottom = 0.027 -offset_right = 38.912 -offset_bottom = 203.8 -size_flags_horizontal = 3 -size_flags_vertical = 9 -script = ExtResource("2") - -[node name="CenterContainer" type="CenterContainer" parent="."] -layout_mode = 2 - -[node name="TextureProgressBar" type="TextureProgressBar" parent="CenterContainer"] -unique_name_in_owner = true -layout_mode = 2 -max_value = 1.0 -step = 0.0 -value = 1.0 -fill_mode = 4 -texture_under = ExtResource("4") -texture_over = ExtResource("3") -texture_progress = ExtResource("1") -radial_initial_angle = 79.3 -radial_fill_degrees = 93.8 diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd b/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd deleted file mode 100644 index 6e28eac..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd +++ /dev/null @@ -1,26 +0,0 @@ -extends EditorProperty -class_name SS2D_NormalRangeEditorProperty - -var control: SS2D_NormalRangeEditor = preload( - "res://addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditor.tscn" - ).instantiate() - - -func _init() -> void: - add_child(control) - add_focusable(control) - - -func _enter_tree() -> void: - control.connect("value_changed", self._value_changed) - _value_changed() - - -func _exit_tree() -> void: - control.disconnect("value_changed", self._value_changed) - - -func _value_changed() -> void: - var obj: SS2D_NormalRange = get_edited_object() - control.end = obj.distance - control.start = obj.begin diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd.uid b/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd.uid deleted file mode 100644 index 9d7e386..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/NormalRangeEditorProperty.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://6aecavq8vdrv diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png b/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png deleted file mode 100644 index 7b47da6..0000000 Binary files a/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png.import b/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png.import deleted file mode 100644 index a345e7a..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dgd4sbhsw1no3" -path="res://.godot/imported/over_texture.png-8aa46a605c51c9642f0609a4a8bbd43d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/editors/NormalRangeEditor/over_texture.png" -dest_files=["res://.godot/imported/over_texture.png-8aa46a605c51c9642f0609a4a8bbd43d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png b/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png deleted file mode 100644 index 1911c99..0000000 Binary files a/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png.import b/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png.import deleted file mode 100644 index 0e0edb6..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dajqljvjm2d2q" -path="res://.godot/imported/progress_texture.png-5c3ce00c522dd3c8b7a6f676bd7a3382.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/editors/NormalRangeEditor/progress_texture.png" -dest_files=["res://.godot/imported/progress_texture.png-5c3ce00c522dd3c8b7a6f676bd7a3382.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png b/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png deleted file mode 100644 index b838714..0000000 Binary files a/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png and /dev/null differ diff --git a/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png.import b/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png.import deleted file mode 100644 index ad04684..0000000 --- a/godot/addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cax163h05b60j" -path="res://.godot/imported/under_texture.png-87a243e17179ba2b162ef41ea65a8e51.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/rmsmartshape/editors/NormalRangeEditor/under_texture.png" -dest_files=["res://.godot/imported/under_texture.png-87a243e17179ba2b162ef41ea65a8e51.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd b/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd deleted file mode 100644 index cbb97b3..0000000 --- a/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd +++ /dev/null @@ -1,60 +0,0 @@ -extends EditorInspectorPlugin - -## This inspector plugin will show an Execute button for action properties in -## SS2D_Shape. -## -## To add an action property export it with: -## -## @export_placeholder("ActionProperty") var ... -## -## Then, when an action is executed by user (by pressing an Execute button in inspector), -## setter will be called with non-empty string: -## -## func _action_property_setter(value: String) -> void: -## if value.size() > 0: -## ## Action is executed -## - -class ActionPropertyEditor: - extends EditorProperty - - signal action_pressed - - var button: Button - - func _init() -> void: - button = Button.new() - button.text = "Execute" - add_child(button) - button.connect("pressed", func() -> void: emit_signal("action_pressed")) - - func _ready() -> void: - button.icon = get_theme_icon("TextEditorPlay", "EditorIcons") - - -func _can_handle(object: Object) -> bool: - if object is SS2D_Shape: - return true - return false - - -func _parse_property( - object: Object, - _type: Variant.Type, - name: String, - _hint_type: PropertyHint, - hint_string: String, - _usage_flags, - _wide: bool -) -> bool: - if hint_string == "ActionProperty": - var prop_editor := ActionPropertyEditor.new() - add_property_editor(name, prop_editor) - prop_editor.connect("action_pressed", self._on_action_pressed.bind(object, name)) - return true - return false - - -func _on_action_pressed(object: Object, prop_name: String) -> void: - prints("Action executed:", prop_name.capitalize()) - object.set(prop_name, "executed") diff --git a/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd.uid b/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd.uid deleted file mode 100644 index 0bfcd29..0000000 --- a/godot/addons/rmsmartshape/editors/action_property_inspector_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b1isdj0xyeje2 diff --git a/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd b/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd deleted file mode 100644 index b9b4157..0000000 --- a/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd +++ /dev/null @@ -1,44 +0,0 @@ -extends EditorInspectorPlugin - -var control: SS2D_NormalRangeEditorProperty = null - - -func _can_handle(object: Object) -> bool: - #if object is SS2D_NormalRange: - # return true - if object is SS2D_NormalRange: - #Connect - if not object.is_connected("changed", self._changed): - object.connect("changed", self._changed.bind(object)) - return true - else: - #Disconnect - if control != null: - control = null - - if object.has_signal("changed"): - if object.is_connected("changed", self._changed): - object.disconnect("changed", self._changed) - pass - - return false - - -func _changed(_object: Object) -> void: - control._value_changed() - - -func _parse_property( - _object: Object, - _type: Variant.Type, - name: String, - _hint_type: PropertyHint, - _hint_string: String, - _usage_flags: int, - _wide: bool -) -> bool: - if name == "edgeRendering": - control = SS2D_NormalRangeEditorProperty.new() - add_property_editor(" ", control) - return true - return false diff --git a/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd.uid b/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd.uid deleted file mode 100644 index 7af8885..0000000 --- a/godot/addons/rmsmartshape/editors/normal_range_inspector_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0ovs7rrvogvr diff --git a/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd b/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd deleted file mode 100644 index 8336b02..0000000 --- a/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd +++ /dev/null @@ -1,35 +0,0 @@ -extends RefCounted -class_name SS2D_TesselationVertexMapping - -## Provides mappings from tesselated point indices to their corresponding vertex indices and vice-versa. - -var _t_point_idx_to_point_idx := PackedInt32Array() -var _point_idx_to_t_points_idx: Array[PackedInt32Array] = [] - - -## Rebuild the mapping using the given tesselated points and vertices. -func build(tesselated_points: PackedVector2Array, vertices: PackedVector2Array) -> void: - _t_point_idx_to_point_idx.clear() - _point_idx_to_t_points_idx.clear() - - var point_idx := -1 - - for t_point_idx in tesselated_points.size(): - var next_point_idx := SS2D_PluginFunctionality.get_next_point_index_wrap_around(point_idx, vertices) - - if tesselated_points[t_point_idx] == vertices[next_point_idx]: - point_idx = next_point_idx - _point_idx_to_t_points_idx.push_back(PackedInt32Array()) - - _t_point_idx_to_point_idx.push_back(point_idx) - _point_idx_to_t_points_idx[point_idx].push_back(t_point_idx) - - -## Returns the vertex index corresponding to the given tesselated point index -func tess_to_vertex_index(tesselated_idx: int) -> int: - return _t_point_idx_to_point_idx[tesselated_idx] - - -## Returns a list of tesselated point indices corresponding to the given vertex index -func vertex_to_tess_indices(vertex_idx: int) -> PackedInt32Array: - return _point_idx_to_t_points_idx[vertex_idx] diff --git a/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd.uid b/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd.uid deleted file mode 100644 index d11fc73..0000000 --- a/godot/addons/rmsmartshape/lib/tesselation_vertex_mapping.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c36dx2gssfe30 diff --git a/godot/addons/rmsmartshape/lib/tuple.gd b/godot/addons/rmsmartshape/lib/tuple.gd deleted file mode 100644 index aea5e3c..0000000 --- a/godot/addons/rmsmartshape/lib/tuple.gd +++ /dev/null @@ -1,142 +0,0 @@ -@tool -extends RefCounted -class_name SS2D_IndexTuple - -## Provides utility functions for handling and storing indices of two related points using Vector2i. -## -## Index tuples are considered equal if their elements are equal, regardless of their order: -## T(X, Y) <=> T(Y, X). -## -## For effectively working with containers, helper functions for arrays and dictionaries are -## provided that implement the above behavior. - -## Returns the second tuple element that does not equal the given value. -## Returns -1 if neither element matches. -static func get_other_value(t: Vector2i, value: int) -> int: - if t.x == value: - return t.y - elif t.y == value: - return t.x - return -1 - - -## Returns whether two tuples are equal. Two tuples are considered equal when both contain the same values regardless of order. -static func are_equal(t1: Vector2i, t2: Vector2i) -> bool: - return t1 == t2 or t1 == flip_elements(t2) - - -## Returns true when the tuple contains the given value. -static func has(t: Vector2i, value: int) -> bool: - return t.x == value or t.y == value - - -## Searches for an equal tuple in the given array and returns the index or -1 if not found. -## Incorporates the equality behavior. -static func array_find(tuple_array: Array[Vector2i], t: Vector2i) -> int: - for i in tuple_array.size(): - if are_equal(tuple_array[i], t): - return i - return -1 - - -## Returns whether the given tuple exists in the given array. -## Incorporates the equality behavior. -static func array_has(tuple_array: Array[Vector2i], t: Vector2i) -> bool: - return array_find(tuple_array, t) != -1 - - -## Returns a list indices to tuples that contain the given value. -static func array_find_partial(tuple_array: Array[Vector2i], value: int) -> PackedInt32Array: - var out := PackedInt32Array() - - for i in tuple_array.size(): - if tuple_array[i].x == value or tuple_array[i].y == value: - out.push_back(i) - - return out - - -## Transform the tuple into a normalized representation (elements in ascending order). -## Same as sort_ascending() at the moment. -## Useful in more optimized use-cases where certain assumptions can be made if all tuples share a -## normalized representation. -static func normalize_tuple(tuple: Vector2i) -> Vector2i: - return sort_ascending(tuple) - - -## Returns a tuple with elements in ascending order. -static func sort_ascending(tuple: Vector2i) -> Vector2i: - if tuple.x <= tuple.y: - return tuple - return flip_elements(tuple) - - - -## Returns a tuple with x and y components switched. -static func flip_elements(tuple: Vector2i) -> Vector2i: - return Vector2i(tuple.y, tuple.x) - - -## Validates the keys of a dictionary to be correct tuple values and converts all Arrays to -## corresponding Vector2i values. -## Optionally also validates that values are of the given type. -## Exists mostly for backwards compatibility to allow a seamless transition from Array to Vector2i tuples. -static func dict_validate(dict: Dictionary, value_type: Variant = null) -> void: - # TODO: Maybe don't use asserts but push_warning and return true if successful - for key: Variant in dict.keys(): - var value: Variant = dict[key] - - if value_type != null: - assert(is_instance_of(value, value_type), "Incorrect value type in dictionary: " + var_to_str(value)) - - if key is Array or key is PackedInt32Array or key is PackedInt64Array: - var converted := Vector2i(int(key[0]), int(key[1])) - dict.erase(key) - dict[converted] = value - else: - assert(key is Vector2i, "Invalid tuple representation: %s. Should be Vector2i." % var_to_str(key)) - - -## Get the value in a dictionary with the given tuple as key or a default value if it does not exist. -## Incorporates the equality behavior. -static func dict_get(dict: Dictionary, tuple: Vector2i, default: Variant = null) -> Variant: - if dict.has(tuple): - return dict[tuple] - return dict.get(flip_elements(tuple), default) - - -static func dict_has(dict: Dictionary, tuple: Vector2i) -> bool: - return dict.has(tuple) or dict.has(flip_elements(tuple)) - - -static func dict_set(dict: Dictionary, tuple: Vector2i, value: Variant) -> void: - dict[dict_get_key(dict, tuple)] = value - - -## Removes the given entry from the dictionary. Returns true if a corresponding key existed, otherwise false. -static func dict_erase(dict: Dictionary, tuple: Vector2i) -> bool: - return dict.erase(dict_get_key(dict, tuple)) - - -## Checks if there is an existing key for the given tuple or its flipped variant and returns it. -## If a key does not exist, returns the tuple as it is. -## Usually this function does not need to be invoked manually, as helpers for dictionary and array access exist. -static func dict_get_key(dict: Dictionary, tuple: Vector2i) -> Vector2i: - if not dict.has(tuple): - var flipped := flip_elements(tuple) - - if dict.has(flipped): - return flipped - - return tuple - - -## Returns a list of all dictionary keys (tuples) that contain the given value. -static func dict_find_partial(dict: Dictionary, value: int) -> Array[Vector2i]: - var out: Array[Vector2i] = [] - - for t: Vector2i in dict.keys(): - if t.x == value or t.y == value: - out.push_back(t) - - return out diff --git a/godot/addons/rmsmartshape/lib/tuple.gd.uid b/godot/addons/rmsmartshape/lib/tuple.gd.uid deleted file mode 100644 index 532b9e5..0000000 --- a/godot/addons/rmsmartshape/lib/tuple.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bt1u84porvgj5 diff --git a/godot/addons/rmsmartshape/materials/edge_material.gd b/godot/addons/rmsmartshape/materials/edge_material.gd deleted file mode 100644 index 81f5fc7..0000000 --- a/godot/addons/rmsmartshape/materials/edge_material.gd +++ /dev/null @@ -1,156 +0,0 @@ -@tool -extends Resource -class_name SS2D_Material_Edge - -## This material represents the set of textures used for a single edge. -## -## This consists of: [br] -## - textures [br] -## - corner_textures [br] -## - taper_textures [br] - -## All variations of the main edge texture.[br] -## _textures[0] is considered the "main" texture for the EdgeMaterial.[br][br] -## [b]Note:[/b] Will be used to generate an icon representing an edge texture.[br] -@export var textures: Array[Texture2D] = [] : set = _set_textures - -# Textures for the final left and right quad of the edge when the angle is steep -@export var textures_corner_outer: Array[Texture2D] = [] : set = _set_textures_corner_outer -@export var textures_corner_inner: Array[Texture2D] = [] : set = _set_textures_corner_inner - -# Textures for the final left and right quad of the edge when the angle is shallow -# Named as such because the desired look is that the texture "tapers-off" -@export var textures_taper_left: Array[Texture2D] = [] : set = _set_textures_taper_left -@export var textures_taper_right: Array[Texture2D] = [] : set = _set_textures_taper_right - -## Textures that will be used for the sharp_corner_tapering feature -@export var textures_taper_corner_left: Array[Texture2D] = [] : set = _set_textures_taper_corner_left -@export var textures_taper_corner_right: Array[Texture2D] = [] : set = _set_textures_taper_corner_right - -## If the texture choice should be randomized instead of the choice by point setup -@export var randomize_texture: bool = false : set = _set_randomize_texture -## If corner textures should be used -@export var use_corner_texture: bool = true : set = _set_use_corner -## If taper textures should be used -@export var use_taper_texture: bool = true : set = _set_use_taper - -## Whether squishing can occur when texture doesn't fit nicely into total length. -enum FITMODE {SQUISH_AND_STRETCH, CROP} -@export var fit_mode: FITMODE = FITMODE.SQUISH_AND_STRETCH : set = _set_fit_texture - -@export var material: Material = null : set = _set_material - - -########### -# SETTERS # -########### -func _set_textures(ta: Array[Texture2D]) -> void: - textures = ta - emit_changed() - - -func _set_textures_corner_outer(a: Array[Texture2D]) -> void: - textures_corner_outer = a - emit_changed() - - -func _set_textures_corner_inner(a: Array[Texture2D]) -> void: - textures_corner_inner = a - emit_changed() - - -func _set_textures_taper_left(a: Array[Texture2D]) -> void: - textures_taper_left = a - emit_changed() - - -func _set_textures_taper_right(a: Array[Texture2D]) -> void: - textures_taper_right = a - emit_changed() - -func _set_textures_taper_corner_left(a: Array[Texture2D]) -> void: - textures_taper_corner_left = a - emit_changed() - -func _set_textures_taper_corner_right(a: Array[Texture2D]) -> void: - textures_taper_corner_right = a - emit_changed() - -func _set_randomize_texture(b: bool) -> void: - randomize_texture = b - emit_changed() - - -func _set_use_corner(b: bool) -> void: - use_corner_texture = b - emit_changed() - - -func _set_use_taper(b: bool) -> void: - use_taper_texture = b - emit_changed() - - -func _set_fit_texture(fitmode: FITMODE) -> void: - fit_mode = fitmode - emit_changed() - - -func _set_material(m: Material) -> void: - material = m - emit_changed() - - -########### -# GETTERS # -########### -func get_texture(idx: int) -> Texture2D: - return _get_element(idx, textures) - - -func get_texture_corner_inner(idx: int) -> Texture2D: - return _get_element(idx, textures_corner_inner) - - -func get_texture_corner_outer(idx: int) -> Texture2D: - return _get_element(idx, textures_corner_outer) - - -func get_texture_taper_left(idx: int) -> Texture2D: - return _get_element(idx, textures_taper_left) - - -func get_texture_taper_right(idx: int) -> Texture2D: - return _get_element(idx, textures_taper_right) - - -func get_texture_taper_corner_left(idx: int) -> Texture2D: - return _get_element(idx, textures_taper_corner_left) - - -func get_texture_taper_corner_right(idx: int) -> Texture2D: - return _get_element(idx, textures_taper_corner_right) - - -######### -# USAGE # -######### - -## Returns main texture used to visually identify this edge material -func get_icon_texture() -> Texture2D: - if not textures.is_empty(): - return textures[0] - return null - - -############ -# INTERNAL # -############ -func _get_element(idx: int, a: Array) -> Variant: - if a.is_empty(): - return null - return a[_adjust_idx(idx, a)] - - -func _adjust_idx(idx: int, a: Array) -> int: - return idx % a.size() diff --git a/godot/addons/rmsmartshape/materials/edge_material.gd.uid b/godot/addons/rmsmartshape/materials/edge_material.gd.uid deleted file mode 100644 index 52cf9ee..0000000 --- a/godot/addons/rmsmartshape/materials/edge_material.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d0xjijisx1woh diff --git a/godot/addons/rmsmartshape/materials/edge_material_metadata.gd b/godot/addons/rmsmartshape/materials/edge_material_metadata.gd deleted file mode 100644 index 2573188..0000000 --- a/godot/addons/rmsmartshape/materials/edge_material_metadata.gd +++ /dev/null @@ -1,81 +0,0 @@ -@tool -extends Resource -class_name SS2D_Material_Edge_Metadata - -## Represents the metadata for an edge material. -## -## Used by Shape Material. - -@export var edge_material: SS2D_Material_Edge = null : set = set_edge_material -## What range of normals can this edge be used on. -@export var normal_range := SS2D_NormalRange.new(0, 360) : set = set_normal_range -## If edge should be welded to the edges surrounding it. -@export var weld: bool = true : set = set_weld -## Whether or not the edges should use the taper corner textures and not be welded, if they are -## too sharp to be welded without significant distortion. NOTE this will not work properly -## in curved shapes -@export var taper_sharp_corners: bool = false : set = set_taper_sharp_corners -## If this edge should be visible. -@export var render: bool = true : set = set_render -## z index for an edge. -@export var z_index: int = 0 : set = set_z_index -## z index for an edge. -@export var z_as_relative: bool = true : set = set_z_as_relative -## Distance from center. -@export_range (-1.5, 1.5, 0.1) var offset: float = 0.0 : set = set_offset - - -func _to_string() -> String: - return "%s | %s" % [str(edge_material), normal_range] - - -func set_render(b: bool) -> void: - render = b - emit_changed() - - -func set_edge_material(m: SS2D_Material_Edge) -> void: - if edge_material != null: - if edge_material.is_connected("changed", self._on_edge_changed): - edge_material.disconnect("changed", self._on_edge_changed) - edge_material = m - if edge_material != null: - edge_material.connect("changed", self._on_edge_changed) - emit_changed() - - -func set_normal_range(nr: SS2D_NormalRange) -> void: - if nr == null: - return - if normal_range.is_connected("changed", self._on_edge_changed): - normal_range.disconnect("changed", self._on_edge_changed) - normal_range = nr - normal_range.connect("changed", self._on_edge_changed) - emit_changed() - - -func set_weld(b: bool) -> void: - weld = b - emit_changed() - -func set_taper_sharp_corners(val: bool) -> void: - taper_sharp_corners = val - emit_changed() - -func set_z_index(z: int) -> void: - z_index = z - emit_changed() - - -func set_z_as_relative(b: bool) -> void: - z_as_relative = b - emit_changed() - - -func set_offset(f: float) -> void: - offset = f - emit_changed() - - -func _on_edge_changed() -> void: - emit_changed() diff --git a/godot/addons/rmsmartshape/materials/edge_material_metadata.gd.uid b/godot/addons/rmsmartshape/materials/edge_material_metadata.gd.uid deleted file mode 100644 index 533e27d..0000000 --- a/godot/addons/rmsmartshape/materials/edge_material_metadata.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://0lhxan4cqrc1 diff --git a/godot/addons/rmsmartshape/materials/shape_material.gd b/godot/addons/rmsmartshape/materials/shape_material.gd deleted file mode 100644 index e77955c..0000000 --- a/godot/addons/rmsmartshape/materials/shape_material.gd +++ /dev/null @@ -1,139 +0,0 @@ -@tool -extends Resource -class_name SS2D_Material_Shape - -## This material represents the set of edge materials used for a smart shape. -## -## Each edge represents a set of textures used to render an edge. - -## List of materials this shape can use. -@export var _edge_meta_materials: Array[SS2D_Material_Edge_Metadata] = [] : set = set_edge_meta_materials -@export var fill_textures: Array[Texture2D] = [] : set = set_fill_textures -@export var fill_texture_z_index: int = -10 : set = set_fill_texture_z_index -@export var fill_texture_show_behind_parent: bool = false : set = set_fill_texture_show_behind_parent - -## Scale the fill texture -@export_range(0.1, 4, 0.01, "or_greater") var fill_texture_scale: float = 1.0 : set = set_fill_texture_scale - -## Whether the fill texture should start at the global 0/0 instead of the node's 0/0 -@export var fill_texture_absolute_position: bool = false : set = set_fill_texture_absolute_position - -## Whether the fill texture should ignore the node's rotation -@export var fill_texture_absolute_rotation: bool = false : set = set_fill_texture_absolute_rotation - -## How many pixels the fill texture should be shifted in x and y direction -@export var fill_texture_offset: Vector2 = Vector2.ZERO : set = set_fill_texture_offset - -## Added rotation of the texture in degrees -@export_range(-180, 180, 0.1) var fill_texture_angle_offset: float = 0.0 : set = set_fill_texture_angle_offset - -@export var fill_mesh_offset: float = 0.0 : set = set_fill_mesh_offset -@export var fill_mesh_material: Material = null : set = set_fill_mesh_material - -## How much to offset all edges -@export_range (-1.5, 1.5, 0.1) var render_offset: float = 0.0 : set = set_render_offset - - -func set_fill_mesh_material(m: Material) -> void: - fill_mesh_material = m - emit_changed() - - -func set_fill_mesh_offset(f: float) -> void: - fill_mesh_offset = f - emit_changed() - - -func set_render_offset(f: float) -> void: - render_offset = f - emit_changed() - - -## Get all valid edge materials for this normal. -func get_edge_meta_materials(normal: Vector2) -> Array[SS2D_Material_Edge_Metadata]: - var materials: Array[SS2D_Material_Edge_Metadata] = [] - for e in _edge_meta_materials: - if e == null: - continue - if e.normal_range.is_in_range(normal): - materials.push_back(e) - return materials - - -func get_all_edge_meta_materials() -> Array[SS2D_Material_Edge_Metadata]: - return _edge_meta_materials - - -func get_all_edge_materials() -> Array[SS2D_Material_Edge]: - var materials: Array[SS2D_Material_Edge] = [] - for meta in _edge_meta_materials: - if meta.edge_material != null: - materials.push_back(meta.edge_material) - return materials - - -func add_edge_material(e: SS2D_Material_Edge_Metadata) -> void: - var new_array := _edge_meta_materials.duplicate() - new_array.push_back(e) - set_edge_meta_materials(new_array) - - -func _on_edge_material_changed() -> void: - emit_changed() - - -func set_fill_textures(a: Array[Texture2D]) -> void: - fill_textures = a - emit_changed() - - -func set_fill_texture_z_index(i: int) -> void: - fill_texture_z_index = i - emit_changed() - - -func set_fill_texture_show_behind_parent(value: bool) -> void: - fill_texture_show_behind_parent = value - emit_changed() - - -func set_edge_meta_materials(a: Array[SS2D_Material_Edge_Metadata]) -> void: - for e in _edge_meta_materials: - if e == null: - continue - if not a.has(e): - e.disconnect("changed", self._on_edge_material_changed) - - for e in a: - if e == null: - continue - if not e.is_connected("changed", self._on_edge_material_changed): - e.connect("changed", self._on_edge_material_changed) - - _edge_meta_materials = a - emit_changed() - - -func set_fill_texture_offset(value: Vector2) -> void: - fill_texture_offset = value - emit_changed() - - -func set_fill_texture_scale(value:float) -> void: - fill_texture_scale = value - emit_changed() - - -func set_fill_texture_absolute_rotation(value: bool) -> void: - fill_texture_absolute_rotation = value - emit_changed() - - -func set_fill_texture_angle_offset(value: float) -> void: - fill_texture_angle_offset = value - emit_changed() - - -func set_fill_texture_absolute_position(value: bool) -> void: - fill_texture_absolute_position = value - emit_changed() \ No newline at end of file diff --git a/godot/addons/rmsmartshape/materials/shape_material.gd.uid b/godot/addons/rmsmartshape/materials/shape_material.gd.uid deleted file mode 100644 index b1c90d6..0000000 --- a/godot/addons/rmsmartshape/materials/shape_material.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://nc5bfedvnpgm diff --git a/godot/addons/rmsmartshape/normal_range.gd b/godot/addons/rmsmartshape/normal_range.gd deleted file mode 100644 index 195d2f3..0000000 --- a/godot/addons/rmsmartshape/normal_range.gd +++ /dev/null @@ -1,99 +0,0 @@ -@tool -extends Resource -class_name SS2D_NormalRange - -## This class will determine if the normal of a vector falls within the specifed angle ranges. -## -## - if begin and end are equal, any angle is considered to be within range [br] -## - 360.0 and 0.0 degrees are considered equivilent [br] - -@export_range (0, 360, 1) var begin: float = 0.0 : set = set_begin -@export_range (0, 360, 1) var distance: float = 0.0 : set = set_distance - -# This is a hack to support the custom editor, needed a property -# to exist to lock the TextureProgressBar to. Makes it flow better -# in the Inspector. -@export var edgeRendering: Vector2 - - -func set_distance(f: float) -> void: - distance = f - emit_changed() - - -func set_begin(f: float) -> void: - begin = f - emit_changed() - - -func _to_string() -> String: - return "NormalRange: %s - %s" % [begin, begin + distance] - - -static func get_angle_from_vector(vec: Vector2) -> float: - var normal: Vector2 = vec.normalized() - # With respect to the X-axis - # This is how Vector2.angle() is calculated, best to keep it consistent - var comparison_vector := Vector2(1, 0) - - var ab: Vector2 = normal - var bc: Vector2 = comparison_vector - var dot_prod: float = ab.dot(bc) - var determinant: float = (ab.x * bc.y) - (ab.y * bc.x) - var angle: float = atan2(determinant, dot_prod) - - # This angle has a range of 360 degrees - # Is between 180 and - 180 - var deg: float = rad_to_deg(angle) - - # Get range between 0.0 and 360.0 - if deg < 0: - deg = 360.0 + deg - return deg - - -# Get in range between 0.0 and 360.0. -static func _get_positive_angle_deg(degrees: float) -> float: - while degrees < 0: - degrees += 360 - return fmod(degrees, 360.0) - -# Get in range between -360.0 and 360.0 -static func _get_signed_angle_deg(degrees: float) -> float: - var new_degrees: float = degrees - while absf(new_degrees) > 360.0: - new_degrees += (360.0 * signf(degrees) * -1.0) - return new_degrees - - -# Saving a scene with this resource requires a parameter-less init method -func _init(_begin: float = 0.0, _distance: float = 0.0) -> void: - _begin = SS2D_NormalRange._get_signed_angle_deg(_begin) - _distance = SS2D_NormalRange._get_signed_angle_deg(_distance) - - begin = _begin - distance = _distance - - -func is_in_range(vec: Vector2) -> bool: - # A Distance of 0 or 360 is the entire circle - if distance == 0 or SS2D_NormalRange._get_positive_angle_deg(distance) == 360.0: - return true - - var begin_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin) - var end_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin + distance) - # If positive, counter clockwise direction - # If negative, clockwise direction - var direction: float = signf(distance) - var angle: float = SS2D_NormalRange.get_angle_from_vector(vec) - - # Swap begin and end if direction is negative - if direction == -1: - var t: float = begin_positive - begin_positive = end_positive - end_positive = t - - if begin_positive < end_positive: - return ((angle >= begin_positive) and (angle <= end_positive)) - else: - return ((angle >= begin_positive) or (angle <= end_positive)) diff --git a/godot/addons/rmsmartshape/normal_range.gd.uid b/godot/addons/rmsmartshape/normal_range.gd.uid deleted file mode 100644 index a471f60..0000000 --- a/godot/addons/rmsmartshape/normal_range.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d218yx0d1ilsn diff --git a/godot/addons/rmsmartshape/plugin.cfg b/godot/addons/rmsmartshape/plugin.cfg deleted file mode 100644 index 3d925f7..0000000 --- a/godot/addons/rmsmartshape/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="SmartShape2D" -description="Tool to design nicely textured 2D polygons" -author="Ryan Lloyd, Robert Morse, Guy Unger, Serhii Snitsaruk, Marvin Ewald" -version="3.3.0" -script="plugin.gd" diff --git a/godot/addons/rmsmartshape/plugin.gd b/godot/addons/rmsmartshape/plugin.gd deleted file mode 100644 index 3f8ea87..0000000 --- a/godot/addons/rmsmartshape/plugin.gd +++ /dev/null @@ -1,1763 +0,0 @@ -@tool -extends EditorPlugin -class_name SS2D_Plugin - - -## Common Abbreviations -## et = editor transform (viewport's canvas transform) -## -## - Snapping using the build in functionality isn't going to happen -## - https://github.com/godotengine/godot/issues/11180 -## - https://godotengine.org/qa/18051/tool-script-in-3-0 - -const PROJECT_SETTING_INTERNAL_VERSION := "addons/ss2d/version" - -# Icons -# TODO: Change to const and preload when this is resolved: -# https://github.com/godotengine/godot/issues/17483 -var ICON_HANDLE: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_handle.svg") -var ICON_HANDLE_SELECTED: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_handle_selected.svg") -var ICON_HANDLE_BEZIER: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_handle_bezier.svg") -var ICON_HANDLE_CONTROL: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_handle_control.svg") -var ICON_FREEHAND_MODE: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_freehand.svg") -var ICON_CIRCLE_ERASE: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_snap.svg") -var ICON_ADD_HANDLE: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_handle_add.svg") -var ICON_CURVE_EDIT: Texture2D = load("res://addons/rmsmartshape/assets/icon_curve_edit.svg") -var ICON_CURVE_CREATE: Texture2D = load("res://addons/rmsmartshape/assets/icon_curve_create.svg") -var ICON_CURVE_DELETE: Texture2D = load("res://addons/rmsmartshape/assets/icon_curve_delete.svg") -var ICON_PIVOT_POINT: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_position.svg") -var ICON_CENTER_PIVOT: Texture2D = load("res://addons/rmsmartshape/assets/CenterView.svg") -var ICON_INTERP_LINEAR: Texture2D = load("res://addons/rmsmartshape/assets/InterpLinear.svg") -var ICON_SNAP: Texture2D = load("res://addons/rmsmartshape/assets/icon_editor_snap.svg") -var ICON_IMPORT_CLOSED: Texture2D = load("res://addons/rmsmartshape/assets/closed_shape.png") -var ICON_IMPORT_OPEN: Texture2D = load("res://addons/rmsmartshape/assets/open_shape.png") - -enum MODE { EDIT_VERT, EDIT_EDGE, CUT_EDGE, SET_PIVOT, CREATE_VERT, FREEHAND } - -enum SNAP_MENU { ID_USE_GRID_SNAP, ID_SNAP_RELATIVE, ID_CONFIGURE_SNAP } -enum OPTIONS_MENU { ID_DEFER_MESH_UPDATES, ID_CHECK_VERSION } - -enum ACTION_VERT { - NONE = 0, - MOVE_VERT = 1, - MOVE_CONTROL = 2, - MOVE_CONTROL_IN = 3, - MOVE_CONTROL_OUT = 4, - MOVE_WIDTH_HANDLE = 5 -} - - -# Data related to an action being taken on points -class ActionDataVert: - #Type of Action from the ACTION_VERT enum - var type: ACTION_VERT = ACTION_VERT.NONE - # The affected Verticies and their initial positions - var keys: PackedInt32Array - var starting_width: PackedFloat32Array - var starting_positions: PackedVector2Array = [] - var starting_positions_control_in: PackedVector2Array = [] - var starting_positions_control_out: PackedVector2Array = [] - - func _init( - _keys: PackedInt32Array, - positions: PackedVector2Array, - positions_in: PackedVector2Array, - positions_out: PackedVector2Array, - width: PackedFloat32Array, - t: ACTION_VERT - ) -> void: - type = t - keys = _keys - starting_positions = positions - starting_positions_control_in = positions_in - starting_positions_control_out = positions_out - starting_width = width - - func are_verts_selected() -> bool: - return keys.size() > 0 - - func _to_string() -> String: - return "%s: %s = %s" % [type, keys, starting_positions] - - func is_single_vert_selected() -> bool: - return keys.size() == 1 - - func current_point_key() -> int: - if not is_single_vert_selected(): - return -1 - return keys[0] - - func current_point_index(s: SS2D_Shape) -> int: - if not is_single_vert_selected(): - return -1 - return s.get_point_array().get_point_index(keys[0]) - - -# PRELOADS -var GUI_SNAP_POPUP := preload("scenes/SnapPopup.tscn") -var GUI_POINT_INFO_PANEL := preload("scenes/GUI_InfoPanel.tscn") -var GUI_EDGE_INFO_PANEL := preload("scenes/GUI_Edge_InfoPanel.tscn") -var gui_point_info_panel: SS2D_PointInfoPanel = GUI_POINT_INFO_PANEL.instantiate() -var gui_edge_info_panel: SS2D_EdgeInfoPanel = GUI_EDGE_INFO_PANEL.instantiate() -var gui_snap_settings: SS2D_SnapPopup = GUI_SNAP_POPUP.instantiate() - -const GUI_POINT_INFO_PANEL_OFFSET := Vector2(256, 130) - -# This is the shape node being edited -var shape: SS2D_Shape = null - -# Tools -var _tools: Array[SS2D_EditorTool] = [ - SS2D_CollisionEditorTool.new(), -] - -# Toolbar Stuff -var tb_hb: HBoxContainer = null -var tb_vert_create: Button = null -var tb_vert_edit: Button = null -var tb_edge_edit: Button = null -var tb_edge_cut: Button = null -var tb_pivot: Button = null -var tb_center_pivot: Button = null -var tb_freehand: Button = null -var tb_button_group: ButtonGroup = null - -var tb_snap: MenuButton = null -# The PopupMenu that belongs to tb_snap -var tb_snap_popup: PopupMenu = null - -var tb_options: MenuButton = null -var tb_options_popup: PopupMenu = null - -var make_unique_dialog: AcceptDialog - -# Edge Stuff -var on_edge: bool = false -var edge_point: Vector2 -var edge_data: SS2D_Edge = null - -# Width Handle Stuff -var on_width_handle: bool = false -const WIDTH_HANDLE_OFFSET: float = 60.0 -var closest_key: int -var closest_edge_keys := Vector2i(-1, -1) -var width_scaling: float - -# Vertex paint mode stuff -var last_point_position: Vector2 -var _mouse_lmb_pressed := false -var _mouse_rmb_pressed := false -var freehand_paint_size := 20.0 -var freehand_erase_size := 40.0 - -# Track our mode of operation -var current_mode: int = MODE.CREATE_VERT -var previous_mode: int = MODE.CREATE_VERT - -var current_action := ActionDataVert.new([], [], [], [], [], ACTION_VERT.NONE) -var cached_shape_global_transform: Transform2D - -# Action Move Variables -var _mouse_motion_delta_starting_pos := Vector2(0, 0) - -# Defining the viewport to get the current zoom/scale -var target_viewport: Viewport -var current_zoom_level : float = 1.0 - -# Track the property plugin -var plugin: EditorInspectorPlugin - -var is_2d_screen_active := false - -var _defer_mesh_updates := false - -####### -# GUI # -####### - - -func gui_display_snap_settings() -> void: - var pos := tb_snap.get_screen_position() + tb_snap.size - pos.x -= (gui_snap_settings.size.x + tb_snap.size.x) / 2.0 - gui_snap_settings.position = pos - gui_snap_settings.popup() - - -func _snapping_item_selected(id: int) -> void: - if id == SNAP_MENU.ID_USE_GRID_SNAP: - tb_snap_popup.set_item_checked(id, not tb_snap_popup.is_item_checked(id)) - if id == SNAP_MENU.ID_SNAP_RELATIVE: - tb_snap_popup.set_item_checked(id, not tb_snap_popup.is_item_checked(id)) - elif id == SNAP_MENU.ID_CONFIGURE_SNAP: - gui_display_snap_settings() - - -func _options_item_selected(id: int) -> void: - if id == OPTIONS_MENU.ID_DEFER_MESH_UPDATES: - tb_options_popup.set_item_checked(id, not tb_options_popup.is_item_checked(id)) - _defer_mesh_updates = tb_options_popup.is_item_checked(id) - elif id == OPTIONS_MENU.ID_CHECK_VERSION: - perform_version_check_and_conversion(true, true) - - -func _gui_build_toolbar() -> void: - tb_hb = HBoxContainer.new() - add_control_to_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_MENU, tb_hb) - - var sep := VSeparator.new() - tb_hb.add_child(sep) - - tb_button_group = ButtonGroup.new() - - tb_options = MenuButton.new() - tb_options.tooltip_text = SS2D_Strings.EN_TOOLTIP_MORE_OPTIONS - tb_options.icon = EditorInterface.get_base_control().get_theme_icon("GuiTabMenuHl", "EditorIcons") - tb_options_popup = tb_options.get_popup() - tb_options_popup.add_check_item(SS2D_Strings.EN_OPTIONS_DEFER_MESH_UPDATES, OPTIONS_MENU.ID_DEFER_MESH_UPDATES) - tb_options_popup.add_item(SS2D_Strings.EN_OPTIONS_CHECK_VERSION, OPTIONS_MENU.ID_CHECK_VERSION) - tb_options_popup.hide_on_checkable_item_selection = false - tb_options_popup.connect("id_pressed", self._options_item_selected) - - tb_vert_create = create_tool_button(ICON_CURVE_CREATE, SS2D_Strings.EN_TOOLTIP_CREATE_VERT) - tb_vert_create.connect(&"pressed", self._enter_mode.bind(MODE.CREATE_VERT)) - tb_vert_create.button_pressed = true - - tb_vert_edit = create_tool_button(ICON_CURVE_EDIT, SS2D_Strings.EN_TOOLTIP_EDIT_VERT) - tb_vert_edit.connect(&"pressed", self._enter_mode.bind(MODE.EDIT_VERT)) - - tb_edge_edit = create_tool_button(ICON_INTERP_LINEAR, SS2D_Strings.EN_TOOLTIP_EDIT_EDGE) - tb_edge_edit.connect(&"pressed", self._enter_mode.bind(MODE.EDIT_EDGE)) - - var edge_cut_icon: Texture2D = EditorInterface.get_base_control().get_theme_icon(&"ActionCut", &"EditorIcons") - tb_edge_cut = create_tool_button(edge_cut_icon, SS2D_Strings.EN_TOOLTIP_CUT_EDGE) - tb_edge_cut.connect(&"pressed", _enter_mode.bind(MODE.CUT_EDGE)) - - tb_pivot = create_tool_button(ICON_PIVOT_POINT, SS2D_Strings.EN_TOOLTIP_PIVOT) - tb_pivot.connect(&"pressed", self._enter_mode.bind(MODE.SET_PIVOT)) - - tb_center_pivot = create_tool_button(ICON_CENTER_PIVOT, SS2D_Strings.EN_TOOLTIP_CENTER_PIVOT, false) - tb_center_pivot.connect(&"pressed", self._center_pivot) - - tb_freehand = create_tool_button(ICON_FREEHAND_MODE, SS2D_Strings.EN_TOOLTIP_FREEHAND) - tb_freehand.connect(&"pressed", self._enter_mode.bind(MODE.FREEHAND)) - - for i in _tools: - i.register(self) - - tb_snap = MenuButton.new() - tb_snap.tooltip_text = SS2D_Strings.EN_TOOLTIP_SNAP - tb_snap_popup = tb_snap.get_popup() - tb_snap.icon = ICON_SNAP - tb_snap_popup.add_check_item("Use Grid Snap", SNAP_MENU.ID_USE_GRID_SNAP) - tb_snap_popup.add_check_item("Snap Relative", SNAP_MENU.ID_SNAP_RELATIVE) - tb_snap_popup.add_separator() - tb_snap_popup.add_item("Configure Snap...", SNAP_MENU.ID_CONFIGURE_SNAP) - tb_snap_popup.hide_on_checkable_item_selection = false - tb_hb.add_child(tb_snap) - tb_snap_popup.connect("id_pressed", self._snapping_item_selected) - - tb_hb.add_child(tb_options) - -# TODO: Move into SS2D_EditorTool eventually -func create_tool_button(icon: Texture2D, tooltip: String, toggle: bool = true) -> Button: - var tb := Button.new() - tb.toggle_mode = toggle - tb.button_group = tb_button_group - tb.theme_type_variation = "FlatButton" - tb.focus_mode = Control.FocusMode.FOCUS_NONE - tb.icon = icon - tb.tooltip_text = tooltip - tb_hb.add_child(tb) - return tb - - -func _gui_update_vert_info_panel() -> void: - var idx: int = current_action.current_point_index(shape) - var key: int = current_action.current_point_key() - if not is_key_valid(key): - gui_point_info_panel.visible = false - return - gui_point_info_panel.visible = true - # Shrink panel - gui_point_info_panel.size = Vector2(1, 1) - - var point := shape.get_point_array().get_point(key) - gui_point_info_panel.set_idx(idx) - gui_point_info_panel.set_texture_idx(point.texture_idx) - gui_point_info_panel.set_width(point.width) - gui_point_info_panel.set_flip(point.flip) - - -func _load_config() -> void: - var conf := ConfigFile.new() - conf.load(EditorInterface.get_editor_paths().get_project_settings_dir().path_join("ss2d.cfg")) - _defer_mesh_updates = conf.get_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "defer_mesh_updates", false) - tb_options_popup.set_item_checked(OPTIONS_MENU.ID_DEFER_MESH_UPDATES, _defer_mesh_updates) - tb_snap_popup.set_item_checked(SNAP_MENU.ID_USE_GRID_SNAP, conf.get_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "use_grid_snap", false)) - tb_snap_popup.set_item_checked(SNAP_MENU.ID_SNAP_RELATIVE, conf.get_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "snap_relative", false)) - - for i in _tools: - i.load_config(conf) - - -func _save_config() -> void: - var conf := ConfigFile.new() - conf.set_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "defer_mesh_updates", _defer_mesh_updates) - conf.set_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "use_grid_snap", tb_snap_popup.is_item_checked(SNAP_MENU.ID_USE_GRID_SNAP)) - conf.set_value(SS2D_EditorTool.CONFIG_OPTIONS_SECTION, "snap_relative", tb_snap_popup.is_item_checked(SNAP_MENU.ID_SNAP_RELATIVE)) - - for i in _tools: - i.save_config(conf) - - conf.save(EditorInterface.get_editor_paths().get_project_settings_dir().path_join("ss2d.cfg")) - - -func _process(_delta: float) -> void: - if current_mode == MODE.FREEHAND: - current_zoom_level = get_canvas_scale() - - -func get_canvas_scale() -> float: - get_current_viewport() - if target_viewport: - return target_viewport.global_canvas_transform.x.x - else: - return 1.0 - - -func get_current_viewport() -> void: - if !get_tree().get_edited_scene_root(): - return - var editor_viewport: Node = get_tree().get_edited_scene_root().get_parent() - - if editor_viewport is SubViewport: - target_viewport = editor_viewport - elif editor_viewport is SubViewportContainer: - target_viewport = get_tree().get_edited_scene_root() - else: - target_viewport = editor_viewport.get_parent() - - -func _gui_update_edge_info_panel() -> void: - # Don't update if already visible - if gui_edge_info_panel.visible: - return - var indicies := Vector2i(-1, -1) - var override: SS2D_Material_Edge_Metadata = null - var pa := shape.get_point_array() - if on_edge: - var t: Transform2D = get_et() * shape.get_global_transform() - var offset: float = pa.get_closest_offset_straight_edge(t.affine_inverse() * edge_point) - var keys: Vector2i = _get_edge_point_keys_from_offset(offset, true) - indicies = Vector2i(pa.get_point_index(keys.x), pa.get_point_index(keys.y)) - if pa.has_material_override(keys): - override = pa.get_material_override(keys) - gui_edge_info_panel.set_indicies(indicies) - if override != null: - gui_edge_info_panel.set_material_override(true) - gui_edge_info_panel.load_values_from_meta_material(override) - else: - gui_edge_info_panel.set_material_override(false) - - # Shrink panel to minimum size - gui_edge_info_panel.size = Vector2(1, 1) - - -func _gui_update_info_panels() -> void: - if not is_2d_screen_active: - _gui_hide_info_panels() - return - match current_mode: - MODE.EDIT_VERT: - _gui_update_vert_info_panel() - gui_edge_info_panel.visible = false - MODE.EDIT_EDGE: - _gui_update_edge_info_panel() - gui_point_info_panel.visible = false - _: - gui_point_info_panel.visible = false - gui_edge_info_panel.visible = false - - -func _gui_hide_info_panels() -> void: - gui_edge_info_panel.visible = false - gui_point_info_panel.visible = false - -######### -# GODOT # -######### - - -# Called when saving -# https://docs.godotengine.org/en/3.2/classes/class_editorplugin.html?highlight=switch%20scene%20tab -func _apply_changes() -> void: - gui_point_info_panel.visible = false - gui_edge_info_panel.visible = false - - -func _init() -> void: - pass - - -func _ready() -> void: - # Support the undo-redo actions - _gui_build_toolbar() - _load_config() - add_child(gui_point_info_panel) - gui_point_info_panel.visible = false - add_child(gui_edge_info_panel) - gui_edge_info_panel.visible = false - gui_edge_info_panel.connect("material_override_toggled", self._on_edge_material_override_toggled) - gui_edge_info_panel.connect("render_toggled", self._on_edge_material_override_render_toggled) - gui_edge_info_panel.connect("weld_toggled", self._on_edge_material_override_weld_toggled) - gui_edge_info_panel.connect("z_index_changed", self._on_edge_material_override_z_index_changed) - gui_edge_info_panel.connect("edge_material_changed", self._on_edge_material_changed) - add_child(gui_snap_settings) - gui_snap_settings.hide() - - make_unique_dialog = AcceptDialog.new() - make_unique_dialog.title = "Make Shape Unique" - make_unique_dialog.get_label().text = "Make shape point geometry unique (not materials). Proceed?" - make_unique_dialog.get_ok_button().text = "Proceed" - make_unique_dialog.add_cancel_button("Cancel") - make_unique_dialog.theme = EditorInterface.get_base_control().theme - make_unique_dialog.connect("confirmed", self._shape_make_unique) - add_child(make_unique_dialog) - - connect("main_screen_changed", self._on_main_screen_changed) - - perform_version_check_and_conversion() - - -func _enter_tree() -> void: - @warning_ignore("unsafe_method_access") - plugin = load("res://addons/rmsmartshape/editors/normal_range_inspector_plugin.gd").new() - if plugin != null: - add_inspector_plugin(plugin) - - @warning_ignore("unsafe_method_access") - var action_plugin: EditorInspectorPlugin = load("res://addons/rmsmartshape/editors/action_property_inspector_plugin.gd").new() - if action_plugin != null: - add_inspector_plugin(action_plugin) - - -func _exit_tree() -> void: - if (plugin != null): - remove_inspector_plugin(plugin) - - _save_config() - - gui_point_info_panel.visible = false - gui_edge_info_panel.visible = false - remove_control_from_container(EditorPlugin.CONTAINER_CANVAS_EDITOR_MENU, tb_hb) - tb_hb.queue_free() - - -func _forward_canvas_gui_input(event: InputEvent) -> bool: - if not is_shape_valid(): - return false - - # Force update if global transforma has been changed - if cached_shape_global_transform != shape.get_global_transform(): - shape.set_as_dirty() - cached_shape_global_transform = shape.get_global_transform() - - var et: Transform2D = get_et() - var grab_threshold: float = EditorInterface.get_editor_settings().get( - "editors/polygon_editor/point_grab_radius" - ) - - var key_return_value := false - if event is InputEventKey: - key_return_value = _input_handle_keyboard_event(event) - - var mb_return_value := false - if event is InputEventMouseButton: - mb_return_value = _input_handle_mouse_button_event(event, et, grab_threshold) - - var mm_return_value := false - if event is InputEventMouseMotion: - mb_return_value = _input_handle_mouse_motion_event(event, et, grab_threshold) - - var return_value := key_return_value == true or mb_return_value == true or mm_return_value == true - _gui_update_info_panels() - return return_value - - -func _handles(object: Object) -> bool: - var hideToolbar: bool = true - - update_overlays() - gui_point_info_panel.visible = false - gui_edge_info_panel.visible = false - - var selection: EditorSelection = EditorInterface.get_selection() - if selection != null: - if selection.get_selected_nodes().size() == 1: - if selection.get_selected_nodes()[0] is SS2D_Shape: - hideToolbar = false - - if hideToolbar == true: - tb_hb.hide() - - if object is Resource: - return false - - return object is SS2D_Shape - - -func _edit(object: Object) -> void: - on_edge = false - deselect_verts() - if is_shape_valid(): - disconnect_shape(shape) - - shape = object - - if not is_shape_valid(): - gui_point_info_panel.visible = false - gui_edge_info_panel.visible = false - shape = null - else: - connect_shape(shape) - - if shape.get_point_array().get_point_count() == 0: - _enter_mode(MODE.CREATE_VERT) - elif current_mode == MODE.CREATE_VERT: - _enter_mode(MODE.EDIT_VERT) - - update_overlays() - - -func _make_visible(visible: bool) -> void: - if visible: - tb_hb.show() - else: - tb_hb.hide() - - - -func _on_main_screen_changed(screen_name: String) -> void: - is_2d_screen_active = screen_name == "2D" - if not is_2d_screen_active: - _gui_hide_info_panels() - - -############ -# SNAPPING # -############ -func use_global_snap() -> bool: - return not tb_snap_popup.is_item_checked(SNAP_MENU.ID_SNAP_RELATIVE) - - -func use_snap() -> bool: - return tb_snap_popup.is_item_checked(SNAP_MENU.ID_USE_GRID_SNAP) - - -func get_snap_offset() -> Vector2: - return gui_snap_settings.get_snap_offset() - - -func get_snap_step() -> Vector2: - return gui_snap_settings.get_snap_step() - - -func snap(v: Vector2, force: bool = false) -> Vector2: - if not use_snap() and not force: - return v - var step: Vector2 = get_snap_step() - var offset: Vector2 = get_snap_offset() - var t := Transform2D.IDENTITY - if use_global_snap(): - t = shape.get_global_transform() - return SS2D_PluginFunctionality.snap_position(v, offset, step, t) - - -########## -# PLUGIN # -########## - -func disconnect_shape(s: SS2D_Shape) -> void: - if s.is_connected("make_unique_pressed", self._on_shape_make_unique): - s.disconnect("make_unique_pressed", self._on_shape_make_unique) - - -func connect_shape(s: SS2D_Shape) -> void: - if not s.is_connected("make_unique_pressed", self._on_shape_make_unique): - s.connect("make_unique_pressed", self._on_shape_make_unique) - - -func get_material_override_from_indicies() -> SS2D_Material_Edge_Metadata: - var keys := shape.get_point_array().get_edge_keys_for_indices(gui_edge_info_panel.indicies) - return shape.get_point_array().get_material_override(keys) - - -func _on_edge_material_override_render_toggled(enabled: bool) -> void: - var override := get_material_override_from_indicies() - if override != null: - override.render = enabled - - -func _on_edge_material_override_weld_toggled(enabled: bool) -> void: - var override := get_material_override_from_indicies() - if override != null: - override.weld = enabled - - -func _on_edge_material_override_z_index_changed(z: int) -> void: - var override := get_material_override_from_indicies() - if override != null: - override.z_index = z - - -func _on_edge_material_changed(m: SS2D_Material_Edge) -> void: - var override := get_material_override_from_indicies() - if override != null: - override.edge_material = m - - -func _on_edge_material_override_toggled(enabled: bool) -> void: - var indices := gui_edge_info_panel.indicies - - if SS2D_IndexTuple.has(indices, -1): - return - - var keys := shape.get_point_array().get_edge_keys_for_indices(indices) - - # Get the relevant Override data if any exists - var override: SS2D_Material_Edge_Metadata = shape.get_point_array().get_material_override(keys) - - if enabled: - if override == null: - override = SS2D_Material_Edge_Metadata.new() - override.edge_material = null - shape.get_point_array().set_material_override(keys, override) - - # Load override data into the info panel - gui_edge_info_panel.load_values_from_meta_material(override) - else: - if override != null: - shape.get_point_array().remove_material_override(keys) - - -func is_shape_valid() -> bool: - if shape == null: - return false - if not is_instance_valid(shape): - return false - if not shape.is_inside_tree(): - return false - return true - - -func _on_shape_make_unique(_shape: SS2D_Shape) -> void: - make_unique_dialog.popup_centered() - - -func _shape_make_unique() -> void: - perform_action(SS2D_ActionMakeShapeUnique.new(shape)) - - -func get_et() -> Transform2D: - return EditorInterface.get_edited_scene_root().get_viewport().global_canvas_transform - - -func is_key_valid(key: int) -> bool: - if not is_shape_valid(): - return false - return shape.get_point_array().has_point(key) - - -func _enter_mode(mode: int) -> void: - if current_mode == mode: - return - - for tb: Button in [tb_vert_edit, tb_edge_edit, tb_pivot, tb_center_pivot, tb_vert_create, tb_freehand]: - tb.button_pressed = false - - previous_mode = current_mode - current_mode = mode - match mode: - MODE.CREATE_VERT: - tb_vert_create.button_pressed = true - MODE.EDIT_VERT: - tb_vert_edit.button_pressed = true - MODE.EDIT_EDGE: - tb_edge_edit.button_pressed = true - MODE.CUT_EDGE: - tb_edge_cut.button_pressed = true - MODE.SET_PIVOT: - tb_pivot.button_pressed = true - MODE.FREEHAND: - tb_freehand.button_pressed = true - _: - tb_vert_edit.button_pressed = true - - update_overlays() - - -func _center_pivot() -> void: - if shape and shape.get_point_array().is_shape_closed(): - # Calculate centroid - var points: PackedVector2Array = shape.get_point_array().get_tessellated_points() - var point_count: int = points.size() - var total_area: float = 0.0 - var center: Vector2 = Vector2.ZERO - for i in range(point_count): - var pt1: Vector2 = points[i] - var pt2: Vector2 - if i == point_count - 1: - pt2 = points[0] - else: - pt2 = points[i + 1] - - var triangle_area: float = pt1.cross(pt2) - total_area += triangle_area - center += (pt1 + pt2) * triangle_area - - if total_area != 0.0: - center /= 3 * total_area - - perform_action(SS2D_ActionSetPivot.new(shape, shape.to_global(center))) - -############# -# RENDERING # -############# - -func _forward_canvas_draw_over_viewport(overlay: Control) -> void: - # Something might force a draw which we had no control over, - # in this case do some updating to be sure - if not is_shape_valid() or not is_inside_tree(): - return - - match current_mode: - MODE.CREATE_VERT: - draw_mode_edit_vert(overlay) - if Input.is_key_pressed(KEY_ALT) and Input.is_key_pressed(KEY_SHIFT): - draw_new_shape_preview(overlay) - elif Input.is_key_pressed(KEY_ALT): - draw_new_point_close_preview(overlay) - else: - draw_new_point_preview(overlay) - MODE.EDIT_VERT: - draw_mode_edit_vert(overlay) - if Input.is_key_pressed(KEY_ALT): - if Input.is_key_pressed(KEY_SHIFT): - draw_new_shape_preview(overlay) - elif not on_edge: - draw_new_point_close_preview(overlay) - MODE.EDIT_EDGE: - draw_mode_edit_edge(overlay, Color.WHITE, Color.YELLOW) - MODE.CUT_EDGE: - draw_mode_cut_edge(overlay) - MODE.FREEHAND: - if not _mouse_lmb_pressed: - draw_new_point_close_preview(overlay) - draw_freehand_circle(overlay) - draw_mode_edit_vert(overlay, false) - - -func draw_freehand_circle(overlay: Control) -> void: - var mouse: Vector2 = overlay.get_local_mouse_position() - var size: float = freehand_paint_size - var color := Color.WHITE - if Input.is_key_pressed(KEY_CTRL): - color = Color.RED - size = freehand_erase_size - color.a = 0.5 - overlay.draw_arc(mouse, size * 2 * current_zoom_level, 0, TAU, 64, color, 1, true) - color.a = 0.05 - overlay.draw_circle(mouse, size * 2 * current_zoom_level, color) - - -func draw_mode_edit_edge(overlay: Control, color_normal: Color, color_highlight: Color) -> void: - var t: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - var verts: PackedVector2Array = pa.get_vertices() - - draw_shape_outline(overlay, t, verts, color_normal) - draw_vert_handles(overlay, t, verts, false) - - if current_action.type == ACTION_VERT.MOVE_VERT: - var edge_point_keys := current_action.keys - var p1: Vector2 = pa.get_point_position(edge_point_keys[0]) - var p2: Vector2 = pa.get_point_position(edge_point_keys[1]) - overlay.draw_line(t * p1, t * p2, Color.BLACK, 8.0, true) - overlay.draw_line(t * p1, t * p2, color_highlight, 4.0, true) - elif on_edge: - var offset: float = pa.get_closest_offset_straight_edge(t.affine_inverse() * edge_point) - var edge_point_keys := _get_edge_point_keys_from_offset(offset, true) - var p1: Vector2 = pa.get_point_position(edge_point_keys.x) - var p2: Vector2 = pa.get_point_position(edge_point_keys.y) - overlay.draw_line(t * p1, t * p2, Color.BLACK, 8.0, true) - overlay.draw_line(t * p1, t * p2, color_highlight, 4.0, true) - - -func draw_mode_cut_edge(overlay: Control) -> void: - draw_mode_edit_edge(overlay, Color(1.0, 0.25, 0.25, 0.8), Color(1.0, 0.75, 0.75, 1.0)) - - if on_edge: - # Draw "X" marks along the edge that is selected - var t: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - var offset: float = pa.get_closest_offset_straight_edge(t.affine_inverse() * edge_point) - var edge_point_keys := _get_edge_point_keys_from_offset(offset, true) - var from: Vector2 = t * pa.get_point_position(edge_point_keys.x) - var to: Vector2 = t * pa.get_point_position(edge_point_keys.y) - var dir: Vector2 = (to - from).normalized() - var angle: float = dir.angle() - var length: float = (to - from).length() - var num_crosses := remap(length, 0.0, 2000.0, 0.0, 10.0) - @warning_ignore("narrowing_conversion") - num_crosses = snappedi(num_crosses, 2.0) + 1 - var fraction := 1.0 / (num_crosses + 1) - for i in num_crosses: - var pos: Vector2 = from + dir * length * fraction * (i + 1) - overlay.draw_line(Vector2(8.0, 8.0).rotated(angle) + pos, - Vector2(-8.0, -8.0).rotated(angle) + pos, Color.RED, 3.0, true) - overlay.draw_line(Vector2(-8.0, 8.0).rotated(angle) + pos, - Vector2(8.0, -8.0).rotated(angle) + pos, Color.RED, 3.0, true) - - -func draw_mode_edit_vert(overlay: Control, show_vert_handles: bool = true) -> void: - var t: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - var verts: PackedVector2Array = pa.get_vertices() - var points: PackedVector2Array = pa.get_tessellated_points() - draw_shape_outline(overlay, t, points, shape.modulate) - if show_vert_handles: - draw_vert_handles(overlay, t, verts, true) - if on_edge: - overlay.draw_texture(ICON_ADD_HANDLE, edge_point - ICON_ADD_HANDLE.get_size() * 0.5) - - # Draw Highlighted Handle - if current_action.is_single_vert_selected(): - var tex: Texture2D = ICON_HANDLE_SELECTED - overlay.draw_texture( - tex, t * verts[current_action.current_point_index(shape)] - tex.get_size() * 0.5 - ) - - -func draw_shape_outline( - overlay: Control, t: Transform2D, points: PackedVector2Array, color: Color, width: float = 2.0 -) -> void: - if points.size() >= 2: - overlay.draw_polyline(t * points, Color.BLACK, width * 1.5, true) - overlay.draw_polyline(t * points, color, width, true) - - -func draw_vert_handles( - overlay: Control, t: Transform2D, verts: PackedVector2Array, control_points: bool -) -> void: - var transformed_verts := t * verts - var pa := shape.get_point_array() - for i in verts.size(): - # Draw Vert handles - var hp: Vector2 = transformed_verts[i] - var icon: Texture2D = ICON_HANDLE_BEZIER if (Input.is_key_pressed(KEY_SHIFT) and not current_mode == MODE.FREEHAND) else ICON_HANDLE - overlay.draw_texture(icon, hp - icon.get_size() * 0.5) - - # Draw Width handle - var offset: float = WIDTH_HANDLE_OFFSET - var width_handle_key: int = closest_key - if ( - Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) - and current_action.type == ACTION_VERT.MOVE_WIDTH_HANDLE - ): - offset *= width_scaling - width_handle_key = current_action.keys[0] - - var point_index: int = pa.get_point_index(width_handle_key) - if point_index == -1: - return - - var width_handle_normal: Vector2 = _get_vert_normal(t, verts, point_index) - var vertex_position: Vector2 = t * pa.get_point_position(width_handle_key) - var icon_position: Vector2 = vertex_position + width_handle_normal * offset - var size: Vector2 = Vector2.ONE * 10.0 - var width_handle_color := Color("f53351") - overlay.draw_line(vertex_position, icon_position, width_handle_color, 1.0) - overlay.draw_set_transform(icon_position, width_handle_normal.angle(), Vector2.ONE) - overlay.draw_rect(Rect2(-size / 2.0, size), width_handle_color, true) - overlay.draw_set_transform(Vector2.ZERO, 0, Vector2.ONE) - - # Draw Control point handles - if control_points: - for i in verts.size(): - var key: int = pa.get_point_key_at_index(i) - var hp: Vector2 = transformed_verts[i] - - # Drawing the point-out for the last point makes no sense, as there's no point ahead of it - if i < verts.size() - 1: - var pointout: Vector2 = t * (verts[i] + pa.get_point_out(key)) - if hp != pointout: - _draw_control_point_line(overlay, hp, pointout, ICON_HANDLE_CONTROL) - # Drawing the point-in for point 0 makes no sense, as there's no point behind it - if i > 0: - var pointin: Vector2 = t * (verts[i] + pa.get_point_in(key)) - if hp != pointin: - _draw_control_point_line(overlay, hp, pointin, ICON_HANDLE_CONTROL) - - -func _draw_control_point_line(c: Control, vert: Vector2, cp: Vector2, tex: Texture2D) -> void: - # Draw the line with a dark and light color to be visible on all backgrounds - var color_dark := Color(0, 0, 0, 0.3) - var color_light := Color(1, 1, 1, .5) - var width := 2.0 - var normal := (cp - vert).normalized() - c.draw_line(vert + normal * 4 + Vector2.DOWN, cp + Vector2.DOWN, color_dark, width) - c.draw_line(vert + normal * 4, cp, color_light, width) - c.draw_texture(tex, cp - tex.get_size() * 0.5) - - -func draw_new_point_preview(overlay: Control) -> void: - # Draw lines to where a new point will be added - var pa := shape.get_point_array() - var verts: PackedVector2Array = pa.get_vertices() - var t: Transform2D = get_et() * shape.get_global_transform() - var color := Color(1, 1, 1, .5) - var width := 2.0 - var mouse: Vector2 = overlay.get_local_mouse_position() - - if verts.size() > 0: - var a: Vector2 - if pa.is_shape_closed() and verts.size() > 1: - a = t * verts[verts.size() - 2] - overlay.draw_line(mouse, t * verts[0], color,width * .5) - else: - a = t * verts[verts.size() - 1] - overlay.draw_line(mouse, a, color, width) - - overlay.draw_texture(ICON_ADD_HANDLE, mouse - ICON_ADD_HANDLE.get_size() * 0.5) - - -func draw_new_point_close_preview(overlay: Control) -> void: - # Draw lines to where a new point will be added - var t: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - var color := Color(1, 1, 1, .5) - var width := 2.0 - - var mouse: Vector2 = overlay.get_local_mouse_position() - var a: Vector2 = t * pa.get_point_position(closest_edge_keys[0]) - var b: Vector2 = t * pa.get_point_position(closest_edge_keys[1]) - overlay.draw_line(mouse, a, color, width) - color.a = 0.1 - overlay.draw_line(mouse, b, color, width) - overlay.draw_texture(ICON_ADD_HANDLE, mouse - ICON_ADD_HANDLE.get_size() * 0.5) - - -func draw_new_shape_preview(overlay: Control) -> void: - # Draw a plus where a new shape will be added - var mouse: Vector2 = overlay.get_local_mouse_position() - overlay.draw_texture(ICON_ADD_HANDLE, mouse - ICON_ADD_HANDLE.get_size() * 0.5) - - -########## -# PLUGIN # -########## -func deselect_verts() -> void: - current_action = ActionDataVert.new([], [], [], [], [], ACTION_VERT.NONE) - - -func select_verticies(keys: PackedInt32Array, action: ACTION_VERT) -> ActionDataVert: - # FIXME: This is likely buggy, not all point properties are stored - var pa := shape.get_point_array() - var from_positions := PackedVector2Array() - var from_positions_c_in := PackedVector2Array() - var from_positions_c_out := PackedVector2Array() - var from_widths := PackedFloat32Array() - for key in keys: - from_positions.push_back(pa.get_point_position(key)) - from_positions_c_in.push_back(pa.get_point_in(key)) - from_positions_c_out.push_back(pa.get_point_out(key)) - from_widths.push_back(pa.get_point(key).width) - return ActionDataVert.new( - keys, from_positions, from_positions_c_in, from_positions_c_out, from_widths, action - ) - - -func select_vertices_to_move(keys: PackedInt32Array, _mouse_starting_pos_viewport: Vector2) -> void: - _mouse_motion_delta_starting_pos = _mouse_starting_pos_viewport - current_action = select_verticies(keys, ACTION_VERT.MOVE_VERT) - - -func select_control_points_to_move( - keys: PackedInt32Array, _mouse_starting_pos_viewport: Vector2, action: ACTION_VERT = ACTION_VERT.MOVE_CONTROL -) -> void: - current_action = select_verticies(keys, action) - _mouse_motion_delta_starting_pos = _mouse_starting_pos_viewport - - -func select_width_handle_to_move(keys: PackedInt32Array, _mouse_starting_pos_viewport: Vector2) -> void: - _mouse_motion_delta_starting_pos = _mouse_starting_pos_viewport - current_action = select_verticies(keys, ACTION_VERT.MOVE_WIDTH_HANDLE) - - -# TODO: Move into SS2D_EditorTool eventually -func perform_action(action: SS2D_Action) -> void: - var undo := get_undo_redo() - undo.create_action(action.get_name(), UndoRedo.MERGE_DISABLE, shape.get_point_array()) - undo.add_do_method(action, "do") - undo.add_do_method(self, "update_overlays") - undo.add_undo_method(action, "undo") - undo.add_undo_method(self, "update_overlays") - undo.commit_action() - - -######### -# INPUT # -######### -func _input_handle_right_click_press(mb_position: Vector2, grab_threshold: float) -> bool: - if not shape.can_edit: - return false - if current_mode == MODE.EDIT_VERT or current_mode == MODE.CREATE_VERT: - # Mouse over a single vertex? - if current_action.is_single_vert_selected(): - perform_action(SS2D_ActionDeletePoint.new(shape, current_action.keys[0])) - deselect_verts() - return true - else: - # Mouse over a control point? - var et: Transform2D = get_et() - var points_in: Array = SS2D_PluginFunctionality.get_intersecting_control_point_in( - shape, et, mb_position, grab_threshold - ) - var points_out: Array = SS2D_PluginFunctionality.get_intersecting_control_point_out( - shape, et, mb_position, grab_threshold - ) - if not points_in.is_empty(): - perform_action(SS2D_ActionDeleteControlPoint.new(shape, points_in[0], SS2D_ActionDeleteControlPoint.PointType.POINT_IN)) - return true - elif not points_out.is_empty(): - perform_action(SS2D_ActionDeleteControlPoint.new(shape, points_out[0], SS2D_ActionDeleteControlPoint.PointType.POINT_OUT)) - return true - elif current_mode == MODE.EDIT_EDGE: - if on_edge: - gui_edge_info_panel.visible = not gui_edge_info_panel.visible - gui_edge_info_panel.position = get_window().get_mouse_position() - return true - return false - - -func _input_handle_left_click( - mb: InputEventMouseButton, - vp_m_pos: Vector2, - t: Transform2D, - et: Transform2D, - grab_threshold: float -) -> bool: - # Set Pivot? - if current_mode == MODE.SET_PIVOT: - var local_position: Vector2 = et.affine_inverse() * mb.position - if use_snap(): - local_position = snap(local_position) - perform_action(SS2D_ActionSetPivot.new(shape, local_position)) - return true - - var pa := shape.get_point_array() - - if current_mode == MODE.EDIT_VERT or current_mode == MODE.CREATE_VERT: - gui_edge_info_panel.visible = false - var can_add_point: bool = Input.is_key_pressed(KEY_ALT) or current_mode == MODE.CREATE_VERT - var is_first_selected: bool = current_action.is_single_vert_selected() and current_action.current_point_key() == pa.get_point_key_at_index(0) - - if _defer_mesh_updates: - pa.begin_update() - - # Close the shape if the first point is clicked - if can_add_point and is_first_selected and pa.can_close(): - var close_action := SS2D_ActionCloseShape.new(shape) - perform_action(close_action) - if Input.is_key_pressed(KEY_SHIFT): - select_control_points_to_move([close_action.get_key()], vp_m_pos) - else: - select_vertices_to_move([close_action.get_key()], vp_m_pos) - return true - - # Any nearby control points to move? - if not Input.is_key_pressed(KEY_ALT): - if _input_move_control_points(mb, vp_m_pos, grab_threshold): - return true - - # Highlighting a vert to move or add control points to - if current_action.is_single_vert_selected(): - if on_width_handle: - select_width_handle_to_move([current_action.current_point_key()], vp_m_pos) - elif Input.is_key_pressed(KEY_SHIFT): - select_control_points_to_move([current_action.current_point_key()], vp_m_pos) - return true - else: - select_vertices_to_move([current_action.current_point_key()], vp_m_pos) - return true - - # Split the Edge? - if _input_split_edge(mb, vp_m_pos, t): - return true - - if not on_edge and can_add_point: - # Create new point - var local_position: Vector2 = t.affine_inverse() * mb.position - if use_snap(): - local_position = snap(local_position) - - var idx: int = -1 - if Input.is_key_pressed(KEY_SHIFT) and Input.is_key_pressed(KEY_ALT): - # Copy shape with a new single point - var copy: SS2D_Shape = copy_shape(shape) - copy.set_point_array(SS2D_Point_Array.new()) - _enter_mode(MODE.CREATE_VERT) - var selection := EditorInterface.get_selection() - selection.clear() - selection.add_node(copy) - shape = copy - elif Input.is_key_pressed(KEY_ALT): - # Add point between start and end points of the closest edge - idx = pa.get_point_index(closest_edge_keys[1]) - var add_point := SS2D_ActionAddPoint.new(shape, local_position, idx, not _defer_mesh_updates) - perform_action(add_point) - if Input.is_key_pressed(KEY_SHIFT) and not Input.is_key_pressed(KEY_ALT): - select_control_points_to_move([add_point.get_key()], vp_m_pos) - else: - select_vertices_to_move([add_point.get_key()], vp_m_pos) - return true - elif current_mode == MODE.EDIT_EDGE: - if gui_edge_info_panel.visible: - gui_edge_info_panel.visible = false - return true - if on_edge: - # Grab Edge (2 points) - var offset: float = pa.get_closest_offset_straight_edge( - t.affine_inverse() * edge_point - ) - var edge_point_keys := _get_edge_point_keys_from_offset(offset, true) - select_vertices_to_move([edge_point_keys.x, edge_point_keys.y], vp_m_pos) - if _defer_mesh_updates: - pa.begin_update() - return true - elif current_mode == MODE.CUT_EDGE: - if not on_edge: - return true - var offset: float = pa.get_closest_offset_straight_edge(t.affine_inverse() * edge_point) - var edge_keys := _get_edge_point_keys_from_offset(offset, true) - perform_action(SS2D_ActionCutEdge.new(shape, edge_keys.x, edge_keys.y)) - on_edge = false - return true - elif current_mode == MODE.FREEHAND: - return true - return false - - -func _input_handle_mouse_wheel(btn: int) -> bool: - if current_mode == MODE.FREEHAND: - if Input.is_key_pressed(KEY_CTRL) and Input.is_key_pressed(KEY_SHIFT): - var step_multiplier := 1.2 if btn == MOUSE_BUTTON_WHEEL_UP else 0.8 - freehand_erase_size = roundf(clampf(freehand_erase_size * step_multiplier, 5, 400)) - update_overlays() - return true - elif Input.is_key_pressed(KEY_SHIFT): - var step_multiplier := 1.2 if btn == MOUSE_BUTTON_WHEEL_UP else 0.8 - freehand_paint_size = roundf(clampf(freehand_paint_size * step_multiplier, 5, 400)) - update_overlays() - return true - elif current_action.is_single_vert_selected(): - if not shape.can_edit: - return false - var key: int = current_action.current_point_key() - var point := shape.get_point_array().get_point(key) - if Input.is_key_pressed(KEY_SHIFT): - var width_step := 0.1 - if btn == MOUSE_BUTTON_WHEEL_DOWN: - width_step *= -1 - point.width = point.width + width_step - - else: - var texture_idx_step := 1 - if btn == MOUSE_BUTTON_WHEEL_DOWN: - texture_idx_step *= -1 - point.texture_idx = point.texture_idx + texture_idx_step - - update_overlays() - _gui_update_info_panels() - return true - - return false - - -func _input_handle_keyboard_event(event: InputEventKey) -> bool: - if not shape.can_edit: - return false - var kb: InputEventKey = event - if _is_valid_keyboard_scancode(kb): - if current_action.is_single_vert_selected(): - if kb.pressed and kb.keycode == KEY_SPACE: - var key: int = current_action.current_point_key() - var point := shape.get_point_array().get_point(key) - point.flip = not point.flip - _gui_update_info_panels() - - if kb.pressed and kb.keycode == KEY_ESCAPE: - # Hide edge_info_panel - if gui_edge_info_panel.visible: - gui_edge_info_panel.visible = false - - if current_mode == MODE.CREATE_VERT: - _enter_mode(MODE.EDIT_VERT) - - if kb.keycode == KEY_CTRL: - if kb.pressed and not kb.echo: - on_edge = false - if closest_key != -1: - current_action = select_verticies([closest_key], ACTION_VERT.NONE) - else: - deselect_verts() - update_overlays() - - if kb.keycode == KEY_ALT: - update_overlays() - - return true - return false - - -func _is_valid_keyboard_scancode(kb: InputEventKey) -> bool: - match kb.keycode: - KEY_ESCAPE: - return true - KEY_ENTER: - return true - KEY_SPACE: - return true - KEY_SHIFT: - return true - KEY_ALT: - return true - KEY_CTRL: - return true - return false - - -func _input_handle_mouse_button_event( - event: InputEventMouseButton, et: Transform2D, grab_threshold: float -) -> bool: - if not shape.can_edit: - return false - var t: Transform2D = et * shape.get_global_transform() - var mb: InputEventMouseButton = event - var viewport_mouse_position: Vector2 = et.affine_inverse() * mb.position - var mouse_wheel_spun: bool = ( - mb.pressed - and (mb.button_index == MOUSE_BUTTON_WHEEL_DOWN or mb.button_index == MOUSE_BUTTON_WHEEL_UP) - ) - - ####################################### - # Left Mouse Button released - if not mb.pressed and mb.button_index == MOUSE_BUTTON_LEFT: - _mouse_lmb_pressed = false - var rslt: bool = false - var type: ACTION_VERT = current_action.type - var _in := type == ACTION_VERT.MOVE_CONTROL or type == ACTION_VERT.MOVE_CONTROL_IN - var _out := type == ACTION_VERT.MOVE_CONTROL or type == ACTION_VERT.MOVE_CONTROL_OUT - if type == ACTION_VERT.MOVE_VERT: - perform_action(SS2D_ActionMoveVerticies.new(shape, current_action.keys, - current_action.starting_positions)) - rslt = true - elif _in or _out: - perform_action(SS2D_ActionMoveControlPoints.new( - shape, - current_action.keys, - current_action.starting_positions_control_in, - current_action.starting_positions_control_out - )) - rslt = true - elif current_mode == MODE.FREEHAND: - if _defer_mesh_updates: - shape.get_point_array().end_update() - deselect_verts() - return rslt - - ####################################### - # Right Mouse Button released - if not mb.pressed and mb.button_index == MOUSE_BUTTON_RIGHT: - _mouse_rmb_pressed = false - - ######################################### - # Mouse Wheel on valid point - elif mouse_wheel_spun: - return _input_handle_mouse_wheel(mb.button_index) - - ######################################### - # Mouse left click - elif mb.pressed and mb.button_index == MOUSE_BUTTON_LEFT: - _mouse_lmb_pressed = true - return _input_handle_left_click(mb, viewport_mouse_position, t, et, grab_threshold) - - ######################################### - # Mouse right click - elif mb.pressed and mb.button_index == MOUSE_BUTTON_RIGHT: - _mouse_rmb_pressed = true - return _input_handle_right_click_press(mb.position, grab_threshold) - - return false - - -func _input_split_edge(mb: InputEventMouseButton, vp_m_pos: Vector2, t: Transform2D) -> bool: - if not on_edge: - return false - var gpoint: Vector2 = mb.position - var insertion_point: int = -1 - var pa := shape.get_point_array() - var mb_offset: float = pa.get_closest_offset(t.affine_inverse() * gpoint) - - insertion_point = pa.get_point_index(_get_edge_point_keys_from_offset(mb_offset)[1]) - - if insertion_point == -1: - insertion_point = pa.get_point_count() - 1 - - var split_curve := SS2D_ActionSplitCurve.new(shape, insertion_point, gpoint, t, not _defer_mesh_updates) - perform_action(split_curve) - select_vertices_to_move([split_curve.get_key()], vp_m_pos) - on_edge = false - - if _defer_mesh_updates: - pa.begin_update() - - return true - - -func _input_move_control_points(mb: InputEventMouseButton, vp_m_pos: Vector2, grab_threshold: float) -> bool: - var points_in := SS2D_PluginFunctionality.get_intersecting_control_point_in( - shape, get_et(), mb.position, grab_threshold - ) - var points_out := SS2D_PluginFunctionality.get_intersecting_control_point_out( - shape, get_et(), mb.position, grab_threshold - ) - if not points_in.is_empty(): - select_control_points_to_move([points_in[0]], vp_m_pos, ACTION_VERT.MOVE_CONTROL_IN) - return true - elif not points_out.is_empty(): - select_control_points_to_move([points_out[0]], vp_m_pos, ACTION_VERT.MOVE_CONTROL_OUT) - return true - return false - - -func _get_edge_point_keys_from_offset( - offset: float, straight: bool = false, _position := Vector2(0, 0) -) -> Vector2i: - var pa := shape.get_point_array() - for i in range(0, pa.get_point_count() - 1, 1): - var key: int = pa.get_point_key_at_index(i) - var key_next: int = pa.get_point_key_at_index(i + 1) - var this_offset := 0.0 - var next_offset := 0.0 - if straight: - this_offset = pa.get_closest_offset_straight_edge(pa.get_point_position(key)) - next_offset = pa.get_closest_offset_straight_edge(pa.get_point_position(key_next)) - else: - this_offset = pa.get_closest_offset(pa.get_point_position(key)) - next_offset = pa.get_closest_offset(pa.get_point_position(key_next)) - - if offset >= this_offset and offset <= next_offset: - return Vector2i(key, key_next) - # for when the shape is closed and the final point has an offset of 0 - if next_offset == 0 and offset >= this_offset: - return Vector2i(key, key_next) - return Vector2i(-1, -1) - - -func _input_motion_is_on_edge(mm: InputEventMouseMotion, grab_threshold: float) -> bool: - var xform: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - - if pa.get_point_count() < 2: - return false - - # Find edge - var closest_point: Vector2 - if current_mode == MODE.EDIT_EDGE or current_mode == MODE.CUT_EDGE: - closest_point = pa.get_closest_point_straight_edge( - xform.affine_inverse() * mm.position - ) - else: - closest_point = pa.get_closest_point(xform.affine_inverse() * mm.position) - edge_point = xform * closest_point - if edge_point.distance_to(mm.position) <= grab_threshold: - return true - return false - - -func _input_find_closest_edge_keys(mm: InputEventMouseMotion) -> void: - var pa := shape.get_point_array() - - if pa.get_point_count() < 2: - return - - # Find edge - var xform: Transform2D = get_et() * shape.get_global_transform() - var closest_point: Vector2 = pa.get_closest_point_straight_edge(xform.affine_inverse() * mm.position) - var edge_p: Vector2 = xform * closest_point - var offset: float = pa.get_closest_offset_straight_edge(xform.affine_inverse() * edge_p) - closest_edge_keys = _get_edge_point_keys_from_offset(offset, true, xform.affine_inverse() * mm.position) - - -func get_mouse_over_vert_key(mm: InputEventMouseMotion, grab_threshold: float) -> int: - var xform: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - # However, if near a control point or one of its handles then we are not on the edge - for k in pa.get_all_point_keys(): - var pp: Vector2 = pa.get_point_position(k) - var p: Vector2 = xform * pp - if p.distance_to(mm.position) <= grab_threshold: - return k - return -1 - - -func get_mouse_over_width_handle(mm: InputEventMouseMotion, grab_threshold: float) -> int: - var xform: Transform2D = get_et() * shape.get_global_transform() - var pa := shape.get_point_array() - for k in pa.get_all_point_keys(): - var pp: Vector2 = pa.get_point_position(k) - var normal: Vector2 = _get_vert_normal( - xform, pa.get_vertices(), pa.get_point_index(k) - ) - var p: Vector2 = xform * pp + normal * WIDTH_HANDLE_OFFSET - if p.distance_to(mm.position) <= grab_threshold: - return k - return -1 - - -func _input_motion_move_control_points(delta: Vector2, _in: bool, _out: bool) -> bool: - var rslt := false - var pa := shape.get_point_array() - for i in range(0, current_action.keys.size(), 1): - var key: int = current_action.keys[i] - var out_multiplier := 1 - # Invert the delta for position_out if moving both at once - if _out and _in: - out_multiplier = -1 - - var from_in: Vector2 = shape.to_global(current_action.starting_positions_control_in[i]) - var new_position_in: Vector2 = shape.global_transform.affine_inverse() * ( - delta + from_in - ) - - var from_out: Vector2 = shape.to_global(current_action.starting_positions_control_out[i]) - var new_position_out: Vector2 = shape.global_transform.affine_inverse() * ( - (delta * out_multiplier) - + from_out - ) - - if use_snap(): - new_position_in = snap(new_position_in) - new_position_out = snap(new_position_out) - if _in: - pa.set_point_in(key, new_position_in) - rslt = true - if _out: - pa.set_point_out(key, new_position_out) - rslt = true - update_overlays() - - return rslt - - -func _input_motion_move_verts(delta: Vector2) -> bool: - for i in range(0, current_action.keys.size(), 1): - var key: int = current_action.keys[i] - var from: Vector2 = shape.to_global(current_action.starting_positions[i]) - var new_position: Vector2 = shape.global_transform.affine_inverse() * (from + delta) - if use_snap(): - new_position = snap(new_position) - shape.get_point_array().set_point_position(key, new_position) - update_overlays() - return true - - -func _input_motion_move_width_handle(mouse_position: Vector2, scale: Vector2) -> bool: - for i in range(0, current_action.keys.size(), 1): - var key: int = current_action.keys[i] - var from_width: float = current_action.starting_width[i] - var from_position: Vector2 = current_action.starting_positions[i] - width_scaling = from_position.distance_to(mouse_position) / WIDTH_HANDLE_OFFSET * scale.x - shape.get_point_array().get_point(key).width = roundf(from_width * width_scaling * 10.0) / 10.0 - update_overlays() - return true - - -## Will return index of closest vert to point. -func get_closest_vert_to_point(pa: SS2D_Point_Array, p: Vector2) -> int: - var gt: Transform2D = shape.get_global_transform() - var verts: PackedVector2Array = pa.get_vertices() - var transformed_point: Vector2 = gt.affine_inverse() * p - var idx: int = -1 - var closest_distance: float = -1.0 - for i in verts.size(): - var distance: float = verts[i].distance_to(transformed_point) - if distance < closest_distance or closest_distance == -1.0: - idx = pa.get_point_key_at_index(i) - closest_distance = distance - return idx - - -func _input_handle_mouse_motion_event( - event: InputEventMouseMotion, et: Transform2D, grab_threshold: float -) -> bool: - var pa := shape.get_point_array() - var t: Transform2D = et * shape.get_global_transform() - var mm: InputEventMouseMotion = event - var delta_current_pos: Vector2 = et.affine_inverse() * mm.position - gui_point_info_panel.position = mm.position + GUI_POINT_INFO_PANEL_OFFSET - var delta: Vector2 = delta_current_pos - _mouse_motion_delta_starting_pos - - closest_key = get_closest_vert_to_point(pa, delta_current_pos) - - if current_mode == MODE.EDIT_VERT or current_mode == MODE.CREATE_VERT: - var type: ACTION_VERT = current_action.type - var _in := type == ACTION_VERT.MOVE_CONTROL or type == ACTION_VERT.MOVE_CONTROL_IN - var _out := type == ACTION_VERT.MOVE_CONTROL or type == ACTION_VERT.MOVE_CONTROL_OUT - - if type == ACTION_VERT.MOVE_VERT: - return _input_motion_move_verts(delta) - elif _in or _out: - return _input_motion_move_control_points(delta, _in, _out) - elif type == ACTION_VERT.MOVE_WIDTH_HANDLE: - return _input_motion_move_width_handle( - et.affine_inverse() * mm.position, et.get_scale() - ) - var mouse_over_key: int = get_mouse_over_vert_key(event, grab_threshold) - var mouse_over_width_handle: int = get_mouse_over_width_handle(event, grab_threshold) - - # Make the closest key grabable while holding down Control - if ( - Input.is_key_pressed(KEY_CTRL) - and not Input.is_key_pressed(KEY_ALT) - and mouse_over_width_handle == -1 - and mouse_over_key == -1 - ): - mouse_over_key = closest_key - - on_width_handle = false - if mouse_over_key != -1: - on_edge = false - current_action = select_verticies([mouse_over_key], ACTION_VERT.NONE) - elif mouse_over_width_handle != -1: - on_edge = false - on_width_handle = true - current_action = select_verticies([mouse_over_width_handle], ACTION_VERT.NONE) - elif Input.is_key_pressed(KEY_ALT): - _input_find_closest_edge_keys(mm) - else: - deselect_verts() - on_edge = _input_motion_is_on_edge(mm, grab_threshold) - - elif current_mode == MODE.EDIT_EDGE or current_mode == MODE.CUT_EDGE: - # Don't update if edge panel is visible - if gui_edge_info_panel.visible: - return false - var type: ACTION_VERT = current_action.type - if type == ACTION_VERT.MOVE_VERT: - return _input_motion_move_verts(delta) - else: - deselect_verts() - on_edge = _input_motion_is_on_edge(mm, grab_threshold) - - elif current_mode == MODE.FREEHAND: - if _mouse_lmb_pressed: - if not Input.is_key_pressed(KEY_CTRL): - var local_position: Vector2 = t.affine_inverse() * mm.position - if last_point_position.distance_to(local_position) >= freehand_paint_size * 2: - last_point_position = local_position - if use_snap(): - local_position = snap(local_position) - var idx: int = pa.get_point_index(closest_edge_keys[1]) if pa.is_shape_closed() else -1 - perform_action(SS2D_ActionAddPoint.new(shape, local_position, idx, not _defer_mesh_updates)) - update_overlays() - return true - else: - var xform: Transform2D = get_et() * shape.get_global_transform() - var closest_ss2d_point: SS2D_Point = pa.get_point(closest_key) - if closest_ss2d_point != null: - var closest_point: Vector2 = closest_ss2d_point.position - closest_point = xform * closest_point - if closest_point.distance_to(mm.position) / current_zoom_level <= freehand_erase_size * 2: - var delete_point: int = get_mouse_over_vert_key(event, grab_threshold) - delete_point = closest_key - on_width_handle = false - if delete_point != -1: - perform_action(SS2D_ActionDeletePoint.new(shape, delete_point, not _defer_mesh_updates)) - last_point_position = Vector2.ZERO - update_overlays() - return true - else: - _input_find_closest_edge_keys(mm) - - update_overlays() - return false - - -func _get_vert_normal(t: Transform2D, verts: PackedVector2Array, i: int) -> Vector2: - var point: Vector2 = t * verts[i] - var prev_point: Vector2 = t * (verts[(i - 1) % verts.size()]) - var next_point: Vector2 = t * (verts[(i + 1) % verts.size()]) - return ((prev_point - point).normalized().rotated(PI / 2) + (point - next_point).normalized().rotated(PI / 2)).normalized() - - -func copy_shape(s: SS2D_Shape) -> SS2D_Shape: - var copy: SS2D_Shape = s.clone(false) - - var undo := get_undo_redo() - undo.create_action("Add Shape Node") - - undo.add_do_method(s.get_parent(), "add_child", copy, true) - undo.add_do_method(copy, "set_owner", get_tree().get_edited_scene_root()) - undo.add_do_reference(copy) - undo.add_undo_method(copy, "set_owner", null) - undo.add_undo_method(s.get_parent(), "remove_child", copy) - - var collision_polygon_original := s.get_collision_polygon_node() - - if collision_polygon_original: - var collision_polygon_new := CollisionPolygon2D.new() - collision_polygon_new.visible = collision_polygon_original.visible - - undo.add_do_method(collision_polygon_original.get_parent(), "add_child", collision_polygon_new, true) - undo.add_do_method(collision_polygon_new, "set_owner", get_tree().get_edited_scene_root()) - undo.add_do_reference(collision_polygon_new) - - undo.add_undo_method(collision_polygon_original.get_parent(), "remove_child", collision_polygon_new) - - undo.commit_action() - - copy.collision_polygon_node_path = copy.get_path_to(collision_polygon_new) - else: - undo.commit_action() - - return copy - - -######### -# DEBUG # -######### -func _debug_mouse_positions(mm: InputEventMouseMotion, t: Transform2D) -> void: - print("========================================") - print("MouseDelta:%s" % str(_mouse_motion_delta_starting_pos)) - print("= MousePositions =") - print("Position: %s" % str(mm.position)) - print("Relative: %s" % str(mm.relative)) - print("= Transforms =") - print("Transform3D: %s" % str(t)) - print("Inverse: %s" % str(t.affine_inverse())) - print("= Transformed Mouse positions =") - print("Position: %s" % str(t.affine_inverse() * mm.position)) - print("Relative: %s" % str(t.affine_inverse() * mm.relative)) - print("MouseDelta:%s" % str(t.affine_inverse() * _mouse_motion_delta_starting_pos)) - - -#################### -# Version Checking # -#################### -func perform_version_check_and_conversion(force: bool = false, show_dialog_when_no_conversion_needed: bool = false) -> void: - # Only perform check if version changed or after initial install to reduce project startup time. - if not force: - var last_version: String = ProjectSettings.get_setting(PROJECT_SETTING_INTERNAL_VERSION, "") - - # This should suffice for most cases. - # TODO: Consider more sophisticated version checking, e.g. opening a newer project with an older version. - if last_version == get_plugin_version(): - return - - print("SS2D: Version change detected: ", last_version, " != ", get_plugin_version()) - - print("SS2D: Performing version check...") - - var converters: Array[SS2D_VersionTransition.IVersionConverter] = [ - # SS2D_VersionTransition.ShapeNodeTypeConverter.new("Node2D", "MeshInstance2D"), - # Insert more converters for future changes here - ] - - for i in converters: - i.init() - - for i in converters: - if not i.needs_conversion(): - continue - - print("SS2D: Version conversion required") - var dialog: ConfirmationDialog = ConfirmationDialog.new() - add_child(dialog) - var original_ok_button_text := dialog.ok_button_text - dialog.ok_button_text += " (3s)" - dialog.dialog_close_on_escape = false - dialog.title = "SmartShape2D - Version Check" - dialog.dialog_text = """ - SmartShape2D detected scenes that were saved with an older version of SmartShape2D. - These scenes need to be converted to work as before. - - We highly recommend making a backup of your project before proceeding. - - Do you want to proceed?""".dedent().strip_edges() - dialog.get_ok_button().disabled = true - dialog.confirmed.connect(_on_dialog_confirm_conversion.bind(converters)) - dialog.confirmed.connect(_free_dialog.bind(dialog)) - dialog.get_cancel_button().pressed.connect(_free_dialog.bind(dialog)) - dialog.popup_centered() - - await get_tree().create_timer(3).timeout - - # Dialog could be closed already - if is_instance_valid(dialog): - dialog.get_ok_button().disabled = false - dialog.ok_button_text = original_ok_button_text - - return - - # No conversion needed - print("SS2D: No conversion needed") - _write_version_info_to_project() - - if show_dialog_when_no_conversion_needed: - var dialog := AcceptDialog.new() - add_child(dialog) - dialog.title = "Info" - dialog.dialog_text = "No conversion needed." - dialog.confirmed.connect(_free_dialog.bind(dialog)) - dialog.popup_centered() - - -func _on_dialog_confirm_conversion(converters: Array[SS2D_VersionTransition.IVersionConverter]) -> void: - var success := true - - for i in converters.size(): - if not converters[i].needs_conversion(): - continue - - if converters[i].convert(): - print("SS2D: Conversion step ", i + 1, " successful") - else: - push_error("SS2D: Conversion step ", i + 1, " failed -> Aborting") - success = false - break - - var summary := AcceptDialog.new() - add_child(summary) - - if success: - summary.title = "Conversion Successful" - summary.dialog_text = "Conversion successful!" - _write_version_info_to_project() - else: - summary.title = "Conversion Failed" - summary.dialog_text = "An unexpected error occurred.\nSee log output for further information." - - summary.confirmed.connect(_free_dialog.bind(summary)) - summary.popup_centered() - - -func _free_dialog(dialog: Node) -> void: - dialog.queue_free() - - -func _write_version_info_to_project() -> void: - ProjectSettings.set_setting(PROJECT_SETTING_INTERNAL_VERSION, get_plugin_version()) - ProjectSettings.set_as_internal(PROJECT_SETTING_INTERNAL_VERSION, true) - ProjectSettings.save() diff --git a/godot/addons/rmsmartshape/plugin.gd.uid b/godot/addons/rmsmartshape/plugin.gd.uid deleted file mode 100644 index d1da268..0000000 --- a/godot/addons/rmsmartshape/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://diag176hltm6v diff --git a/godot/addons/rmsmartshape/plugin_functionality.gd b/godot/addons/rmsmartshape/plugin_functionality.gd deleted file mode 100644 index a2d4904..0000000 --- a/godot/addons/rmsmartshape/plugin_functionality.gd +++ /dev/null @@ -1,143 +0,0 @@ -@tool -class_name SS2D_PluginFunctionality -extends RefCounted - -## - Everything in this script should be static -## - There is one reason to have code in this script -## 1. To separate out code from the main plugin script to ease testing -## -## Common Abbreviations -## et = editor transform (viewport's canvas transform) - -# --- VERTS - -static func get_intersecting_control_point_in( - s: SS2D_Shape, et: Transform2D, mouse_pos: Vector2, grab_threshold: float -) -> PackedInt32Array: - return _get_intersecting_control_point(s, et, mouse_pos, grab_threshold, true) - - -static func get_intersecting_control_point_out( - s: SS2D_Shape, et: Transform2D, mouse_pos: Vector2, grab_threshold: float -) -> PackedInt32Array: - return _get_intersecting_control_point(s, et, mouse_pos, grab_threshold, false) - - -static func _get_intersecting_control_point( - s: SS2D_Shape, et: Transform2D, mouse_pos: Vector2, grab_threshold: float, _in: bool -) -> PackedInt32Array: - var points := PackedInt32Array() - var xform: Transform2D = et * s.get_global_transform() - var pa := s.get_point_array() - for i in pa.get_point_count(): - var key: int = pa.get_point_key_at_index(i) - var vec_pos: Vector2 = pa.get_point_position(key) - var c_pos := Vector2.ZERO - if _in: - c_pos = pa.get_point_in(key) - else: - c_pos = pa.get_point_out(key) - if c_pos == Vector2.ZERO: - continue - var final_pos := vec_pos + c_pos - final_pos = xform * final_pos - if final_pos.distance_to(mouse_pos) <= grab_threshold: - points.push_back(key) - - return points - - -static func get_next_point_index(idx: int, points: PackedVector2Array, wrap_around: bool = false) -> int: - if wrap_around: - return get_next_point_index_wrap_around(idx, points) - return get_next_point_index_no_wrap_around(idx, points) - - -static func get_previous_point_index(idx: int, points: PackedVector2Array, wrap_around: bool = false) -> int: - if wrap_around: - return get_previous_point_index_wrap_around(idx, points) - return get_previous_point_index_no_wrap_around(idx, points) - - -static func get_next_point_index_no_wrap_around(idx: int, points: PackedVector2Array) -> int: - return mini(idx + 1, points.size() - 1) - - -static func get_previous_point_index_no_wrap_around(idx: int, _points_: PackedVector2Array) -> int: - return maxi(idx - 1, 0) - - -static func get_next_point_index_wrap_around(idx: int, points: PackedVector2Array) -> int: - return (idx + 1) % points.size() - - -static func get_previous_point_index_wrap_around(idx: int, points: PackedVector2Array) -> int: - return posmod(idx - 1, points.size()) - - -## Get the next point that doesn't share the same position with the current point.[br] -## In other words, get the next point in the array with a unique position.[br] -static func get_next_unique_point_idx(idx: int, pts: PackedVector2Array, wrap_around: bool) -> int: - var next_idx: int = get_next_point_index(idx, pts, wrap_around) - if next_idx == idx: - return idx - var pt1: Vector2 = pts[idx] - var pt2: Vector2 = pts[next_idx] - if pt1 == pt2: - return get_next_unique_point_idx(next_idx, pts, wrap_around) - return next_idx - - -static func get_previous_unique_point_idx(idx: int, pts: PackedVector2Array, wrap_around: bool) -> int: - var previous_idx: int = get_previous_point_index(idx, pts, wrap_around) - if previous_idx == idx: - return idx - var pt1: Vector2 = pts[idx] - var pt2: Vector2 = pts[previous_idx] - if pt1 == pt2: - return get_previous_unique_point_idx(previous_idx, pts, wrap_around) - return previous_idx - - -static func snap_position( - pos_global: Vector2, snap_offset: Vector2, snap_step: Vector2, local_t: Transform2D -) -> Vector2: - # Move global position to local position to snap in local space - var pos_local: Vector2 = local_t * pos_global - - # Snap in local space - var x: float = pos_local.x - if snap_step.x != 0: - var delta: float = fmod(pos_local.x, snap_step.x) - # Round up - if delta >= (snap_step.x / 2.0): - x = pos_local.x + (snap_step.x - delta) - # Round down - else: - x = pos_local.x - delta - var y: float = pos_local.y - if snap_step.y != 0: - var delta: float = fmod(pos_local.y, snap_step.y) - # Round up - if delta >= (snap_step.y / 2.0): - y = pos_local.y + (snap_step.y - delta) - # Round down - else: - y = pos_local.y - delta - - # Transform3D local position to global position - var pos_global_snapped := (local_t.affine_inverse() * Vector2(x, y)) + snap_offset - #print ("%s | %s | %s | %s" % [pos_global, pos_local, Vector2(x,y), pos_global_snapped]) - return pos_global_snapped - - -static func show_deprecation_warning(what: String, new_location: String, hint: String = "") -> void: - if new_location: - push_warning(what, " is deprecated. Use ", new_location, " instead. ", hint) - else: - push_warning(what, " is deprecated and will be removed in a future version. ", hint) - - -static func show_point_array_deprecation_warning(what: String) -> void: - show_deprecation_warning(what, "shape.get_point_array()." + what) - diff --git a/godot/addons/rmsmartshape/plugin_functionality.gd.uid b/godot/addons/rmsmartshape/plugin_functionality.gd.uid deleted file mode 100644 index 5154fa3..0000000 --- a/godot/addons/rmsmartshape/plugin_functionality.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d3lpnl7bx6v5q diff --git a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd b/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd deleted file mode 100644 index f748341..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd +++ /dev/null @@ -1,146 +0,0 @@ -@tool -extends PanelContainer -class_name SS2D_EdgeInfoPanel - -signal material_override_toggled(enabled: bool) -signal render_toggled(enabled: bool) -signal weld_toggled(enabled: bool) -signal z_index_changed(value: int) -signal edge_material_changed(value: SS2D_Material_Edge) - -var indicies := Vector2i(-1, -1) : set = set_indicies -var edge_material: SS2D_Material_Edge = null -var edge_material_selector := FileDialog.new() - -@onready var idx_label: Label = %IDX -@onready var material_override_button: Button = %MaterialOverride -@onready var override_container: Container = %OverrideContainer -@onready var render_checkbox: CheckBox = %Render -@onready var weld_checkbox: CheckBox = %Weld -@onready var z_index_spinbox: SpinBox = %ZIndex -@onready var set_material_button: Button = %SetMaterial -@onready var clear_material_button: Button = %ClearMaterial -@onready var material_status: Label = %MaterialStatus - - -func _ready() -> void: - material_override_button.connect("toggled", self._on_toggle_material_override) - render_checkbox.connect("toggled", self._on_toggle_render) - weld_checkbox.connect("toggled", self._on_toggle_weld) - z_index_spinbox.connect("value_changed", self._on_set_z_index) - set_material_button.connect("pressed", self._on_set_edge_material_pressed) - clear_material_button.connect("pressed", self._on_set_edge_material_clear_pressed) - - override_container.hide() - clear_material_button.hide() - - edge_material_selector.file_mode = FileDialog.FILE_MODE_OPEN_FILE - edge_material_selector.dialog_hide_on_ok = true - edge_material_selector.show_hidden_files = true - edge_material_selector.mode_overrides_title = false - edge_material_selector.title = "Select Edge Material" - edge_material_selector.filters = PackedStringArray(["*.tres"]) - edge_material_selector.connect("file_selected", self._on_set_edge_material_file_selected) - add_child(edge_material_selector) - - -func _on_set_edge_material_clear_pressed() -> void: - set_edge_material(null) - - -func _on_set_edge_material_pressed() -> void: - # Update file list - edge_material_selector.invalidate() - edge_material_selector.popup_centered_ratio(0.8) - - -func _on_set_edge_material_file_selected(f: String) -> void: - var rsc := load(f) - if not rsc is SS2D_Material_Edge: - push_error("Selected resource is not an Edge Material! (SS2D_Material_Edge)") - return - set_edge_material(rsc) - - -func set_indicies(t: Vector2i) -> void: - indicies = t - idx_label.text = "IDX: %s" % indicies - - -func set_material_override(enabled: bool) -> void: - material_override_button.button_pressed = enabled - _on_toggle_material_override(enabled) - - -func set_render(enabled: bool, emit: bool = true) -> void: - render_checkbox.button_pressed = enabled - if emit: - _on_toggle_render(enabled) - - -func set_weld(enabled: bool, emit: bool = true) -> void: - weld_checkbox.button_pressed = enabled - if emit: - _on_toggle_weld(enabled) - - -func set_edge_material(v: SS2D_Material_Edge, emit: bool = true) -> void: - edge_material = v - if v == null: - material_status.text = "[No Material]" - clear_material_button.visible = false - else: - # Call string function 'get_file()' to get the filepath - material_status.text = "[%s]" % (v.resource_path).get_file() - clear_material_button.visible = true - if emit: - emit_signal("edge_material_changed", v) - - -func set_edge_z_index(v: int, emit: bool = true) -> void: - z_index_spinbox.value = float(v) - if emit: - _on_set_z_index(float(v)) - - -func get_render() -> bool: - return render_checkbox.button_pressed - - -func get_weld() -> bool: - return weld_checkbox.button_pressed - - -func get_edge_z_index() -> int: - return int(z_index_spinbox.value) - - -func _on_toggle_material_override(pressed: bool) -> void: - override_container.visible = pressed - emit_signal("material_override_toggled", pressed) - - -func _on_toggle_render(pressed: bool) -> void: - emit_signal("render_toggled", pressed) - - -func _on_toggle_weld(pressed: bool) -> void: - emit_signal("weld_toggled", pressed) - - -func _on_set_z_index(v: float) -> void: - emit_signal("z_index_changed", int(v)) - - -func load_values_from_meta_material(meta_mat: SS2D_Material_Edge_Metadata) -> void: - set_render(meta_mat.render) - set_weld(meta_mat.weld) - set_z_index(meta_mat.z_index) - set_edge_material(meta_mat.edge_material) - - -func save_values_to_meta_material(meta_mat: SS2D_Material_Edge_Metadata) -> void: - meta_mat.render = get_render() - meta_mat.weld = get_weld() - meta_mat.z_index = get_z_index() - meta_mat.edge_material = edge_material diff --git a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd.uid b/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd.uid deleted file mode 100644 index c52e58d..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://q7ib6381dxe8 diff --git a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.tscn b/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.tscn deleted file mode 100644 index 5fbace3..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.tscn +++ /dev/null @@ -1,100 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cy1l6tyadc4s3"] - -[ext_resource type="Theme" uid="uid://dud4fe6fsicvm" path="res://addons/rmsmartshape/assets/gui_theme.res" id="1_pwu3l"] -[ext_resource type="Script" uid="uid://q7ib6381dxe8" path="res://addons/rmsmartshape/scenes/GUI_Edge_InfoPanel.gd" id="2"] - -[node name="GUI_Edge_InfoPanel" type="PanelContainer"] -anchors_preset = -1 -anchor_right = 0.203125 -anchor_bottom = 0.345679 -offset_bottom = -62.0 -size_flags_horizontal = 4 -size_flags_vertical = 4 -mouse_filter = 2 -theme = ExtResource("1_pwu3l") -script = ExtResource("2") -metadata/_edit_use_anchors_ = true - -[node name="Panel" type="Panel" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="Container" type="VBoxContainer" parent="."] -layout_mode = 2 - -[node name="Properties" type="VBoxContainer" parent="Container"] -layout_mode = 2 -mouse_filter = 2 - -[node name="IDX" type="Label" parent="Container/Properties"] -unique_name_in_owner = true -layout_mode = 2 -text = "IDX: [1,2]" - -[node name="Functions" type="VBoxContainer" parent="Container"] -layout_mode = 2 -mouse_filter = 2 - -[node name="Make Inner Curve" type="Button" parent="Container/Functions"] -visible = false -layout_mode = 2 -text = "Make Inner Curve" - -[node name="Make Outer Curve" type="Button" parent="Container/Functions"] -visible = false -layout_mode = 2 -text = "Make Outer Curve" - -[node name="MaterialOverride" type="Button" parent="Container/Functions"] -unique_name_in_owner = true -layout_mode = 2 -toggle_mode = true -text = "Material Override" - -[node name="OverrideContainer" type="VBoxContainer" parent="Container"] -unique_name_in_owner = true -visible = false -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="Container/OverrideContainer"] -layout_mode = 2 - -[node name="Render" type="CheckBox" parent="Container/OverrideContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Render" - -[node name="Weld" type="CheckBox" parent="Container/OverrideContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -text = "Weld" - -[node name="ZIndexSection" type="HBoxContainer" parent="Container/OverrideContainer"] -visible = false -layout_mode = 2 - -[node name="lbl" type="Label" parent="Container/OverrideContainer/ZIndexSection"] -layout_mode = 2 -text = "Z:" - -[node name="ZIndex" type="SpinBox" parent="Container/OverrideContainer/ZIndexSection"] -unique_name_in_owner = true -layout_mode = 2 -min_value = -100.0 - -[node name="SetMaterial" type="Button" parent="Container/OverrideContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "Set Material" - -[node name="ClearMaterial" type="Button" parent="Container/OverrideContainer"] -unique_name_in_owner = true -visible = false -layout_mode = 2 -text = "Clear Material" - -[node name="MaterialStatus" type="Label" parent="Container/OverrideContainer"] -unique_name_in_owner = true -layout_mode = 2 -text = "[No Material]" diff --git a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd b/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd deleted file mode 100644 index 1ff15f2..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd +++ /dev/null @@ -1,25 +0,0 @@ -@tool -extends PanelContainer -class_name SS2D_PointInfoPanel - - -@onready var idx_label: Label = %IDX -@onready var tex_label: Label = %Tex -@onready var width_label: Label = %Width -@onready var flip_label: Label = %Flip - - -func set_idx(i: int) -> void: - idx_label.text = "IDX: %s" % i - - -func set_texture_idx(i: int) -> void: - tex_label.text = "Texture2D: %s" % i - - -func set_width(f: float) -> void: - width_label.text = "Width: %s" % f - - -func set_flip(b: bool) -> void: - flip_label.text = "Flip: %s" % b diff --git a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd.uid b/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd.uid deleted file mode 100644 index 2fcb38c..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://jmh3fa1lggij diff --git a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.tscn b/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.tscn deleted file mode 100644 index 66212fa..0000000 --- a/godot/addons/rmsmartshape/scenes/GUI_InfoPanel.tscn +++ /dev/null @@ -1,44 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://cxu6258urdtf1"] - -[ext_resource type="Theme" uid="uid://dud4fe6fsicvm" path="res://addons/rmsmartshape/assets/gui_theme.res" id="1_byls6"] -[ext_resource type="Script" uid="uid://jmh3fa1lggij" path="res://addons/rmsmartshape/scenes/GUI_InfoPanel.gd" id="2"] - -[node name="GUI_InfoPanel" type="PanelContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -918.0 -offset_bottom = -486.0 -size_flags_horizontal = 4 -size_flags_vertical = 4 -mouse_filter = 2 -theme = ExtResource("1_byls6") -script = ExtResource("2") - -[node name="Panel" type="Panel" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="Properties" type="VBoxContainer" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="IDX" type="Label" parent="Properties"] -unique_name_in_owner = true -layout_mode = 2 -text = "IDX: 13" - -[node name="Tex" type="Label" parent="Properties"] -unique_name_in_owner = true -layout_mode = 2 -text = "Tex: 1" - -[node name="Width" type="Label" parent="Properties"] -unique_name_in_owner = true -layout_mode = 2 -text = "Width: 1.0" - -[node name="Flip" type="Label" parent="Properties"] -unique_name_in_owner = true -layout_mode = 2 -text = "Flip: N" diff --git a/godot/addons/rmsmartshape/scenes/SnapPopup.gd b/godot/addons/rmsmartshape/scenes/SnapPopup.gd deleted file mode 100644 index cb87ea0..0000000 --- a/godot/addons/rmsmartshape/scenes/SnapPopup.gd +++ /dev/null @@ -1,16 +0,0 @@ -@tool -extends Popup -class_name SS2D_SnapPopup - -@onready var snap_offset_x: SpinBox = %SnapOffsetX -@onready var snap_offset_y: SpinBox = %SnapOffsetY -@onready var snap_step_x: SpinBox = %SnapStepX -@onready var snap_step_y: SpinBox = %SnapStepY - - -func get_snap_offset() -> Vector2: - return Vector2(snap_offset_x.value, snap_offset_y.value) - - -func get_snap_step() -> Vector2: - return Vector2(snap_step_x.value, snap_step_y.value) diff --git a/godot/addons/rmsmartshape/scenes/SnapPopup.gd.uid b/godot/addons/rmsmartshape/scenes/SnapPopup.gd.uid deleted file mode 100644 index 722e995..0000000 --- a/godot/addons/rmsmartshape/scenes/SnapPopup.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://xh70vbcfch5q diff --git a/godot/addons/rmsmartshape/scenes/SnapPopup.tscn b/godot/addons/rmsmartshape/scenes/SnapPopup.tscn deleted file mode 100644 index b092d10..0000000 --- a/godot/addons/rmsmartshape/scenes/SnapPopup.tscn +++ /dev/null @@ -1,58 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://d1acvw8yuubxo"] - -[ext_resource type="Script" uid="uid://xh70vbcfch5q" path="res://addons/rmsmartshape/scenes/SnapPopup.gd" id="1"] -[ext_resource type="Theme" uid="uid://dud4fe6fsicvm" path="res://addons/rmsmartshape/assets/gui_theme.res" id="1_6ft7o"] - -[node name="SnapPopup" type="PopupPanel"] -size = Vector2i(301, 128) -visible = true -theme = ExtResource("1_6ft7o") -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -offset_left = 12.0 -offset_top = 12.0 -offset_right = 289.0 -offset_bottom = 116.0 - -[node name="Label" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "Configure Snap" - -[node name="SnapOffset" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 2 - -[node name="Label" type="Label" parent="VBoxContainer/SnapOffset"] -layout_mode = 2 -text = "Grid Offset:" - -[node name="SnapOffsetX" type="SpinBox" parent="VBoxContainer/SnapOffset"] -unique_name_in_owner = true -layout_mode = 2 -suffix = "px" - -[node name="SnapOffsetY" type="SpinBox" parent="VBoxContainer/SnapOffset"] -unique_name_in_owner = true -layout_mode = 2 -suffix = "px" - -[node name="SnapStep" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 2 - -[node name="Label" type="Label" parent="VBoxContainer/SnapStep"] -layout_mode = 2 -text = "Grid Step: " - -[node name="SnapStepX" type="SpinBox" parent="VBoxContainer/SnapStep"] -unique_name_in_owner = true -layout_mode = 2 -value = 8.0 -suffix = "px" - -[node name="SnapStepY" type="SpinBox" parent="VBoxContainer/SnapStep"] -unique_name_in_owner = true -layout_mode = 2 -value = 8.0 -suffix = "px" diff --git a/godot/addons/rmsmartshape/shape_renderer.gd b/godot/addons/rmsmartshape/shape_renderer.gd deleted file mode 100644 index 46e9194..0000000 --- a/godot/addons/rmsmartshape/shape_renderer.gd +++ /dev/null @@ -1,68 +0,0 @@ -extends RefCounted -class_name SS2D_Renderer - -var _shape: SS2D_Shape -var _render_parent: RID -var _render_nodes: Array[RID] = [] - - -func _init(shape: SS2D_Shape) -> void: - _shape = shape - _render_parent = RenderingServer.canvas_item_create() - RenderingServer.canvas_item_set_visibility_layer(_render_parent, 0xFFFFFFFF) # Let all layers pass through - RenderingServer.canvas_item_set_parent(_render_parent, _shape.get_canvas_item()) - # NOTE: Light mask is not needed for the parent because it renders nothing itself - - -func _notification(what: int) -> void: - if what == NOTIFICATION_PREDELETE: - for node in _render_nodes: - RenderingServer.free_rid(node) - RenderingServer.free_rid(_render_parent) - - -func _setup_render_nodes(size: int) -> void: - var delta := size - _render_nodes.size() - - # Fewer children than needed - if delta > 0: - for i in delta: - var item := RenderingServer.canvas_item_create() - RenderingServer.canvas_item_set_parent(item, _render_parent) - _render_nodes.push_back(item) - - # More children than needed - elif delta < 0: - for i in absi(delta): - RenderingServer.free_rid(_render_nodes[-1]) - _render_nodes.pop_back() - - -func _update_canvas_item_properties(item: RID, mesh: SS2D_Mesh) -> void: - # TODO: These should be included in the edge material - RenderingServer.canvas_item_set_visibility_layer(item, _shape.visibility_layer) - RenderingServer.canvas_item_set_light_mask(item, _shape.light_mask) - - RenderingServer.canvas_item_set_material(item, mesh.material.get_rid() if mesh.material else RID()) - RenderingServer.canvas_item_set_z_index(item, mesh.z_index) - RenderingServer.canvas_item_set_z_as_relative_to_parent(item, mesh.z_as_relative) - RenderingServer.canvas_item_set_draw_behind_parent(item, mesh.show_behind_parent) - - if mesh.force_no_tiling: - RenderingServer.canvas_item_set_default_texture_repeat(item, RenderingServer.CANVAS_ITEM_TEXTURE_REPEAT_DISABLED) - else: - # Force texture repeat because there is no reason to not repeat edges - # TODO: Support mirrored repeat by adding an edge material property. for repeat method - RenderingServer.canvas_item_set_default_texture_repeat(item, RenderingServer.CANVAS_ITEM_TEXTURE_REPEAT_ENABLED) - - RenderingServer.canvas_item_clear(item) - - if mesh.mesh and mesh.texture: - RenderingServer.canvas_item_add_mesh(item, mesh.mesh.get_rid(), Transform2D(), Color.WHITE, mesh.texture.get_rid()) - - -func render(meshes: Array[SS2D_Mesh]) -> void: - _setup_render_nodes(meshes.size()) - - for i in meshes.size(): - _update_canvas_item_properties(_render_nodes[i], meshes[i]) diff --git a/godot/addons/rmsmartshape/shape_renderer.gd.uid b/godot/addons/rmsmartshape/shape_renderer.gd.uid deleted file mode 100644 index 36de843..0000000 --- a/godot/addons/rmsmartshape/shape_renderer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dq85c8wcy410i diff --git a/godot/addons/rmsmartshape/shapes/edge.gd b/godot/addons/rmsmartshape/shapes/edge.gd deleted file mode 100644 index 1a59544..0000000 --- a/godot/addons/rmsmartshape/shapes/edge.gd +++ /dev/null @@ -1,349 +0,0 @@ -@tool -extends RefCounted -class_name SS2D_Edge - -## An SS2D_Edge represents an edge that will be rendered. -## -## It contains: [br] -## - A list of quads that should be rendered [br] -## - A [Material] that dictates how the edge should be rendered [br] - -## What to encode in the color data (for use by shaders). -enum COLOR_ENCODING { - COLOR, ## Encode a diffuse value to offset the quads color by (currently only ever white). - NORMALS, ## Encode normal data in the colors to be unpacked by a shader later. -} - -var quads: Array[SS2D_Quad] = [] -var first_point_key: int = -1 -var last_point_key: int = -1 -var z_index: int = 0 -var z_as_relative: bool = false -## If final point is connected to first point. -var wrap_around: bool = false -var material: Material = null - - -## Will return true if the 2 quads must be drawn in two calls. -static func different_render(q1: SS2D_Quad, q2: SS2D_Quad) -> bool: - if q1.matches_quad(q2): - return false - return true - - -static func get_consecutive_quads_for_mesh(_quads: Array[SS2D_Quad]) -> Array[Array]: - var quad_ranges: Array[Array] = [] - - if _quads.is_empty(): - return quad_ranges - - var quad_range: Array[SS2D_Quad] = [] - quad_range.push_back(_quads[0]) - for i in range(1, _quads.size(), 1): - var quad_prev: SS2D_Quad = _quads[i - 1] - var quad: SS2D_Quad = _quads[i] - if different_render(quad, quad_prev): - quad_ranges.push_back(quad_range) - quad_range = [quad] - else: - quad_range.push_back(quad) - - quad_ranges.push_back(quad_range) - return quad_ranges - - -## Will generate normals for a given quad -## and interpolate with previous and next quads. -static func generate_normals_for_quad_interpolated(qp: SS2D_Quad, q: SS2D_Quad, qn: SS2D_Quad) -> Array[Color]: - # Interpolation and normalization - #First, consider everything to be a non corner - var tg_a: Vector2 = (q.tg_a + qp.tg_d) - var bn_a: Vector2 = (q.bn_a + qp.bn_d) - - var tg_b: Vector2 = (q.tg_b + qp.tg_c) - var bn_b: Vector2 = (q.bn_b + qp.bn_c) - - var tg_c: Vector2 = (q.tg_c + qn.tg_b) - var bn_c: Vector2 = (q.bn_c + qn.bn_b) - - var tg_d: Vector2 = (q.tg_d + qn.tg_a) - var bn_d: Vector2 = (q.bn_d + qn.bn_a) - - #then, fix values for corner cases (and edge ends) - if q.corner == q.CORNER.NONE: - if qp.corner == q.CORNER.NONE: - #check validity - if (not q.pt_a.is_equal_approx(qp.pt_d)) or (not q.pt_b.is_equal_approx(qp.pt_c)): - tg_a = q.tg_a - tg_b = q.tg_b - bn_a = q.bn_a - bn_b = q.bn_b - elif qp.corner == q.CORNER.INNER: - tg_a = (-qp.bn_d) - bn_a = (-qp.tg_d) - tg_b = (q.tg_b - qp.bn_a) - bn_b = (q.bn_b - qp.tg_a) - #check validity - if (not q.pt_a.is_equal_approx(qp.pt_d)) or (not q.pt_b.is_equal_approx(qp.pt_a)): - tg_a = q.tg_a - tg_b = q.tg_b - bn_a = q.bn_a - bn_b = q.bn_b - elif qp.corner == q.CORNER.OUTER: - tg_a = (q.tg_a + qp.bn_c) - bn_a = (q.bn_a - qp.tg_c) - tg_b = (qp.bn_b) - bn_b = (-qp.tg_b) - #check validity - if (not q.pt_a.is_equal_approx(qp.pt_c)) or (not q.pt_b.is_equal_approx(qp.pt_b)): - tg_a = q.tg_a - tg_b = q.tg_b - bn_a = q.bn_a - bn_b = q.bn_b - if qn.corner == q.CORNER.NONE: - #check validity - if (not q.pt_c.is_equal_approx(qn.pt_b)) or (not q.pt_d.is_equal_approx(qn.pt_a)): - tg_c = q.tg_c - tg_d = q.tg_d - bn_c = q.bn_c - bn_d = q.bn_d - elif qn.corner == q.CORNER.INNER: - tg_d = (-qn.tg_d) - bn_d = (qn.bn_d) - tg_c = (q.tg_c - qn.tg_c) - bn_c = (q.bn_c + qn.bn_c) - #check validity - if (not q.pt_c.is_equal_approx(qn.pt_c)) or (not q.pt_d.is_equal_approx(qn.pt_d)): - tg_c = q.tg_c - tg_d = q.tg_d - bn_c = q.bn_c - bn_d = q.bn_d - elif qn.corner == q.CORNER.OUTER: - tg_c = (qn.tg_b) - bn_c = (qn.bn_b) - #check validity - if (not q.pt_c.is_equal_approx(qn.pt_b)) or (not q.pt_d.is_equal_approx(qn.pt_a)): - tg_c = q.tg_c - tg_d = q.tg_d - bn_c = q.bn_c - bn_d = q.bn_d - - elif q.corner == q.CORNER.INNER: - #common - tg_d = q.tg_d - bn_d = q.bn_d - tg_b = (q.tg_b) - bn_b = (q.bn_b) - #previous - tg_c = (q.tg_c - qp.tg_c) - bn_c = (q.bn_c + qp.bn_c) - #next - tg_a = (q.tg_a - qn.bn_b) - bn_a = (q.bn_a - qn.tg_b) - #check validity - if qp.corner != qp.CORNER.NONE or (not q.pt_c.is_equal_approx(qp.pt_c)) or (not q.pt_d.is_equal_approx(qp.pt_d)): - tg_c = q.tg_c - bn_c = q.bn_c - if qn.corner != qp.CORNER.NONE or (not q.pt_a.is_equal_approx(qn.pt_b)) or (not q.pt_d.is_equal_approx(qn.pt_a)): - tg_a = q.tg_a - bn_a = q.bn_a - - elif q.corner == q.CORNER.OUTER: - tg_d = q.tg_d - bn_d = q.bn_d - tg_b = (q.tg_b) - bn_b = (q.bn_b) - #previous - tg_a = (q.tg_a + qp.tg_d) - bn_a = (q.bn_a + qp.bn_d) - #qn - tg_c = (q.tg_c - qn.bn_a) - bn_c = (q.bn_c + qn.tg_a) - #check validity - if qp.corner != qp.CORNER.NONE or (not q.pt_a.is_equal_approx(qp.pt_d)) or (not q.pt_b.is_equal_approx(qp.pt_c)): - tg_a = q.tg_a - bn_a = q.bn_a - if qn.corner != qp.CORNER.NONE or (not q.pt_b.is_equal_approx(qn.pt_b)) or (not q.pt_c.is_equal_approx(qn.pt_a)): - tg_c = q.tg_c - bn_c = q.bn_c - - if q.flip_texture: - bn_a = -bn_a; - bn_b = -bn_b; - bn_c = -bn_c; - bn_d = -bn_d; - - #Normalize the values - var half_vector: Vector2 = Vector2.ONE * 0.5 - tg_a = tg_a.normalized()*0.5 + half_vector - tg_b = tg_b.normalized()*0.5 + half_vector - tg_c = tg_c.normalized()*0.5 + half_vector - tg_d = tg_d.normalized()*0.5 + half_vector - - bn_a = bn_a.normalized()*0.5 + half_vector - bn_b = bn_b.normalized()*0.5 + half_vector - bn_c = bn_c.normalized()*0.5 + half_vector - bn_d = bn_d.normalized()*0.5 + half_vector - - var normal_pt_a := Color(tg_a.x, tg_a.y, bn_a.x, bn_a.y) - var normal_pt_b := Color(tg_b.x, tg_b.y, bn_b.x, bn_b.y) - var normal_pt_c := Color(tg_c.x, tg_c.y, bn_c.x, bn_c.y) - var normal_pt_d := Color(tg_d.x, tg_d.y, bn_d.x, bn_d.y) - - return [normal_pt_a, normal_pt_b, normal_pt_c, normal_pt_d] - - -## Assumes each quad in the sequence is of the same render type (same textures, values, etc...).[br] -## [param _quads] should have been generated by [method get_consecutive_quads_for_mesh]. -static func generate_array_mesh_from_quad_sequence(_quads: Array[SS2D_Quad], _wrap_around: bool, color_encoding: int) -> SurfaceTool: - # FIXME: _wrap_around is unused. - if _quads.is_empty(): - return null - - var total_length: float = 0.0 - for q in _quads: - total_length += q.get_length_average() - if total_length == 0.0: - return null - - var first_quad: SS2D_Quad = _quads[0] - var tex: Texture2D = first_quad.texture - # The change in length required to apply to each quad - # to make the textures begin and end at the start and end of each texture - var change_in_length: float = -1.0 - if tex != null: - # How many times the texture is repeated - var texture_reps: float = roundf(total_length / tex.get_size().x) - # Length required to display all the reps with the texture's full width - var texture_full_length: float = texture_reps * tex.get_size().x - # How much each quad's texture must be offset to make up the difference in full length vs total length - change_in_length = (texture_full_length / total_length) - - if first_quad.fit_texture == SS2D_Material_Edge.FITMODE.CROP: - change_in_length = 1.0 - - var length_elapsed: float = 0.0 - var st := SurfaceTool.new() - st.begin(Mesh.PRIMITIVE_TRIANGLES) - for q in _quads: - q.update_tangents() - for i in _quads.size(): - var q: SS2D_Quad = _quads[i] - var section_length: float = q.get_length_average() * change_in_length -# var highest_value: float = max(q.get_height_left(), q.get_height_right()) - # When welding and using different widths, quads can look a little weird - # This is because they are no longer parallelograms - # This is a tough problem to solve - # See http://reedbeta.com/blog/quadrilateral-interpolation-part-1/ - var uv_a := Vector2(0, 0) - var uv_b := Vector2(0, 1) - var uv_c := Vector2(1, 1) - var uv_d := Vector2(1, 0) - # If we have a valid texture and this quad isn't a corner - if tex != null and q.corner == q.CORNER.NONE: - var x_left: float = (length_elapsed) / tex.get_size().x - var x_right: float = (length_elapsed + section_length) / tex.get_size().x - uv_a.x = x_left - uv_b.x = x_left - uv_c.x = x_right - uv_d.x = x_right - if q.flip_texture: - var t: Vector2 = uv_a - uv_a = uv_b - uv_b = t - t = uv_c - uv_c = uv_d - uv_d = t - - var color_a := q.color - var color_b := q.color - var color_c := q.color - var color_d := q.color - - if color_encoding == COLOR_ENCODING.NORMALS: - var next := _quads[wrapi(i + 1, 0, _quads.size())] - var prev := _quads[wrapi(i - 1, 0, _quads.size())] - - var normals: Array[Color] = generate_normals_for_quad_interpolated(next, q, prev) - color_a = normals[0] - color_b = normals[1] - color_c = normals[2] - color_d = normals[3] - - # A - _add_uv_to_surface_tool(st, uv_a) - st.set_color(color_a) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_a)) - - # B - _add_uv_to_surface_tool(st, uv_b) - st.set_color(color_b) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_b)) - - # C - _add_uv_to_surface_tool(st, uv_c) - st.set_color(color_c) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_c)) - - # A - _add_uv_to_surface_tool(st, uv_a) - st.set_color(color_a) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_a)) - - # C - _add_uv_to_surface_tool(st, uv_c) - st.set_color(color_c) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_c)) - - # D - _add_uv_to_surface_tool(st, uv_d) - st.set_color(color_d) - st.add_vertex(SS2D_Common_Functions.to_vector3(q.pt_d)) - - length_elapsed += section_length - - st.index() - st.generate_normals() - st.generate_tangents() - return st - - -## Writes meshes in the given mesh buffer starting at the given index. -## If the index is out of range, new elements will be added. -## Only visible meshes are generated, quads without a texture are skipped. -## Returns the resulting buffer index, i.e. the next index after the last added mesh. -func get_meshes(color_encoding: SS2D_Edge.COLOR_ENCODING, mesh_buffer: Array[SS2D_Mesh], buffer_idx: int) -> int: - # Get Arrays of consecutive quads with the same mesh data. - # For each array, generate Mesh Data from the quad. - - var consecutive_quad_arrays := SS2D_Edge.get_consecutive_quads_for_mesh(quads) - #print("Arrays: %s" % consecutive_quad_arrays.size()) - for consecutive_quads in consecutive_quad_arrays: - if consecutive_quads.is_empty(): - continue - - var quad: SS2D_Quad = consecutive_quads[0] - - if not quad.texture: - continue - - var st := SS2D_Edge.generate_array_mesh_from_quad_sequence(consecutive_quads, wrap_around, color_encoding) - - if not st: - continue - - var mesh := SS2D_Common_Functions.mesh_buffer_get_or_create(mesh_buffer, buffer_idx) - st.commit(mesh.mesh) - mesh.texture = quad.texture - mesh.material = material - mesh.z_index = z_index - mesh.z_as_relative = z_as_relative - mesh.force_no_tiling = quad.is_tapered or quad.corner != SS2D_Quad.CORNER.NONE - buffer_idx += 1 - - return buffer_idx - - -static func _add_uv_to_surface_tool(surface_tool: SurfaceTool, uv: Vector2) -> void: - surface_tool.set_uv(uv) - surface_tool.set_uv2(uv) diff --git a/godot/addons/rmsmartshape/shapes/edge.gd.uid b/godot/addons/rmsmartshape/shapes/edge.gd.uid deleted file mode 100644 index 6c8a8b0..0000000 --- a/godot/addons/rmsmartshape/shapes/edge.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ddvkb1dha4sd0 diff --git a/godot/addons/rmsmartshape/shapes/index_map.gd b/godot/addons/rmsmartshape/shapes/index_map.gd deleted file mode 100644 index 31f7eda..0000000 --- a/godot/addons/rmsmartshape/shapes/index_map.gd +++ /dev/null @@ -1,264 +0,0 @@ -@tool -extends RefCounted -class_name SS2D_IndexMap - -## Maps a set of indicies to an object. - -var object: Variant = null -var indicies: PackedInt32Array - - -## Parameter [param subresources] has no effect, no subresources to duplicate. -func duplicate(_subresources: bool = false) -> SS2D_IndexMap: - return SS2D_IndexMap.new(indicies.duplicate(), object) - - -func _init(i: PackedInt32Array, o: Variant) -> void: - indicies = i - object = o - - -func _to_string() -> String: - return "[M_2_IDX] (%s) | %s" % [str(object), indicies] - - -static func is_index_array_valid(idx_array: PackedInt32Array) -> bool: - return idx_array.size() >= 2 - - -func is_valid() -> bool: - return SS2D_IndexMap.is_index_array_valid(indicies) - - -# FIXME: Unused. Remove eventually -# func get_contiguous_segments() -> Array: -# if is_contiguous(): -# return [indicies.duplicate()] -# var segments: Array = [] -# var break_idx: int = find_break() -# var remainder: Array[int] = indicies.duplicate() -# while break_idx != -1: -# var new_slice: Array[int] = [] -# for i in range(0, break_idx): -# new_slice.push_back(remainder[i]) -# segments.push_back(new_slice) -# remainder = remainder.slice(break_idx, remainder.size()) -# break_idx = SS2D_IndexMap.find_break_in_array(remainder) -# if not remainder.is_empty(): -# segments.push_back(remainder) -# return segments - - -## Will join together segments that share the same idx, -## ex. [1,2], [4,5], and [2,3,4] become [1,2,3,4,5] -static func join_segments(segments: Array[PackedInt32Array]) -> Array[PackedInt32Array]: - var final_segments: Array[PackedInt32Array] = [] - final_segments.assign(segments.duplicate()) - - var to_join_tuple: Vector2i - var join_performed := true - while join_performed: - join_performed = false - for i in range(0, final_segments.size()): - if join_performed: - break - for ii in range(i + 1, final_segments.size()): - var a := final_segments[i] - var b := final_segments[ii] - if a[-1] == b[0]: - to_join_tuple = Vector2i(i, ii) - join_performed = true - if b[-1] == a[0]: - to_join_tuple = Vector2i(ii, i) - join_performed = true - if join_performed: - break - if join_performed: - var idx_lowest: int = to_join_tuple[0] - var idx_highest: int = to_join_tuple[1] - var lowest: PackedInt32Array = final_segments[idx_lowest] - var highest: PackedInt32Array = final_segments[idx_highest] - final_segments.erase(lowest) - final_segments.erase(highest) - # pop the shared idx from lowest - lowest.remove_at(lowest.size() - 1) - var new_segment := lowest + highest - final_segments.push_back(new_segment) - - return final_segments - - -## Does each index increment by 1 without any breaks. -func is_contiguous() -> bool: - return SS2D_IndexMap.is_array_contiguous(indicies) - - -static func is_array_contiguous(a: PackedInt32Array) -> bool: - return find_break_in_array(a) == -1 - - -## Find a break in the indexes where they aren't contiguous.[br] -## Will return -1 if there's no break.[br] -func find_break() -> int: - return SS2D_IndexMap.find_break_in_array(indicies) - - -static func find_break_in_array(a: PackedInt32Array, offset: int = 0) -> int: - for i in range(offset, a.size() - 1, 1): - if is_break_at_index_in_array(a, i): - return i + 1 - return -1 - - -## Whether there is a break at the given index.[br] -## Will return -1 if there's no break.[br] -func is_break_at_index(i: int) -> bool: - return SS2D_IndexMap.is_break_at_index_in_array(indicies, i) - - -static func is_break_at_index_in_array(a: PackedInt32Array, i: int) -> bool: - var difference: int = absi((a[i]) - (a[i + 1])) - return difference != 1 - - -func has_index(idx: int) -> bool: - return indicies.has(idx) - - -# FIXME: Unused, remove eventually. -# func lowest_index() -> int: -# return indicies.min() -# -# -# func highest_index() -> int: -# return indicies.max() - - -# FIXME: Unused, remove eventually -func _split_indicies_into_multiple_mappings(new_indicies: PackedInt32Array) -> Array[SS2D_IndexMap]: - var maps: Array[SS2D_IndexMap] = [] - var break_idx := SS2D_IndexMap.find_break_in_array(new_indicies) - var offset := 0 - var sub_indicies: PackedInt32Array - - while break_idx != -1: - sub_indicies = new_indicies.slice(offset, break_idx) - - if SS2D_IndexMap.is_index_array_valid(sub_indicies): - maps.push_back(SS2D_IndexMap.new(sub_indicies, object)) - - offset = break_idx - break_idx = SS2D_IndexMap.find_break_in_array(new_indicies, offset) - - sub_indicies = new_indicies.slice(offset) - - if SS2D_IndexMap.is_index_array_valid(sub_indicies): - maps.push_back(SS2D_IndexMap.new(sub_indicies, object)) - - return maps - - -## FIXME: Unused, remove eventually -## Will create a new set of SS2D_IndexMaps. [br][br] -## -## The new set will contain all of the indicies of the current set, -## minus the ones specified in the indicies parameter. [br][br] -## -## Example: [br] -## indicies = [0,1,2,3,4,5,6] [br] -## to_remove = [3,4] [br] -## new_sets = [0,1,2] [5,6] [br][br] -## -## This may split the IndexMap or make it invalid entirely. -## As a result, the returned array could have 0 or several IndexMaps. -func remove_indicies(to_remove: PackedInt32Array) -> Array[SS2D_IndexMap]: - var out: Array[SS2D_IndexMap] = [] - var new_indicies := indicies.duplicate() - - for r in to_remove: - var idx := new_indicies.find(r) - if idx >= 0: - new_indicies.remove_at(idx) - - if not SS2D_IndexMap.is_index_array_valid(new_indicies): - return out - - if SS2D_IndexMap.is_array_contiguous(new_indicies): - out.push_back(SS2D_IndexMap.new(new_indicies, object)) - return out - - return _split_indicies_into_multiple_mappings(new_indicies) - - -## Will create a new set of SS2D_IndexMaps. [br][br] -## -## The new set will contain all of the edges of the current set, -## minus the ones specified in the indicies parameter. [br][br] -## -## Example: [br] -## indicies = [0,1,2,3,4,5,6] [br] -## to_remove = [4,5] [br] -## new_sets = [0,1,2,3,4] [4,5,6] [br][br] -## -## This may split the IndexMap or make it invalid entirely. -## As a result, the returned array could have 0 or several IndexMaps. -func remove_edges(to_remove: PackedInt32Array) -> Array[SS2D_IndexMap]: - # Corner case - if to_remove.size() == 2: - var idx: int = indicies.find(to_remove[0]) - if idx != indicies.size()-1: - if indicies[idx+1] == to_remove[1]: - # Need one split - var set_1 := indicies.slice(0, idx+1) - var set_2 := indicies.slice(idx+1, indicies.size()) - var new_maps: Array[SS2D_IndexMap] = [] - if SS2D_IndexMap.is_index_array_valid(set_1): - new_maps.push_back(SS2D_IndexMap.new(set_1, object)) - if SS2D_IndexMap.is_index_array_valid(set_2): - new_maps.push_back(SS2D_IndexMap.new(set_2, object)) - return new_maps - return [SS2D_IndexMap.new(indicies, object)] - - # General case - var new_edges := SS2D_IndexMap.indicies_to_edges(indicies) - for i in range(0, to_remove.size() - 1, 1): - var idx1: int = to_remove[i] - var idx2: int = to_remove[i + 1] - var edges_to_remove := PackedInt32Array() - for ii in new_edges.size(): - var edge := new_edges[ii] - if (edge[0] == idx1 or edge[0] == idx2) and (edge[1] == idx1 or edge[1] == idx2): - edges_to_remove.push_back(ii) - # Reverse iterate - for ii in range(edges_to_remove.size()-1, -1, -1): - new_edges.remove_at(edges_to_remove[ii]) - - new_edges = SS2D_IndexMap.join_segments(new_edges) - var new_index_mappings: Array[SS2D_IndexMap] = [] - for e in new_edges: - new_index_mappings.push_back(SS2D_IndexMap.new(e, object)) - return new_index_mappings - - -# NOTE: Even though it makes more sense to return an Array[Vector2i], we return PackedInt32Arrays -# instead because it makes things easier in the context where this function output is needed. -static func indicies_to_edges(p_indicies: PackedInt32Array) -> Array[PackedInt32Array]: - var edges: Array[PackedInt32Array] = [] - for i in p_indicies.size() - 1: - var edge := PackedInt32Array([ i, i+1 ]) - if absi(edge[0] - edge[1]) == 1: - edges.push_back(edge) - return edges - - -## Returns a Dict[Variant, Array[SS2D_IndexMap]] -static func index_map_array_sort_by_object(imaps: Array) -> Dictionary: - var dict := {} - for imap: SS2D_IndexMap in imaps: - if not dict.has(imap.object): - var arr: Array[SS2D_IndexMap] = [ imap ] - dict[imap.object] = arr - else: - var arr: Array[SS2D_IndexMap] = dict[imap.object] - arr.push_back(imap) - return dict diff --git a/godot/addons/rmsmartshape/shapes/index_map.gd.uid b/godot/addons/rmsmartshape/shapes/index_map.gd.uid deleted file mode 100644 index 9a9c7cd..0000000 --- a/godot/addons/rmsmartshape/shapes/index_map.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cef0jvlfgj141 diff --git a/godot/addons/rmsmartshape/shapes/mesh.gd b/godot/addons/rmsmartshape/shapes/mesh.gd deleted file mode 100644 index fd3a753..0000000 --- a/godot/addons/rmsmartshape/shapes/mesh.gd +++ /dev/null @@ -1,24 +0,0 @@ -@tool -extends Resource -class_name SS2D_Mesh - -## This is essentially a serializable data buffer with Node2D properties that will be assigned to a -## rendering node later. - -@export var texture: Texture2D = null -@export var mesh := ArrayMesh.new() -@export var material: Material = null -@export var z_index: int = 0 -@export var z_as_relative: bool = true -@export var show_behind_parent: bool = false -@export var force_no_tiling: bool = false - - -func clear() -> void: - texture = null - mesh.clear_surfaces() - material = null - z_index = 0 - z_as_relative = true - show_behind_parent = false - force_no_tiling = false diff --git a/godot/addons/rmsmartshape/shapes/mesh.gd.uid b/godot/addons/rmsmartshape/shapes/mesh.gd.uid deleted file mode 100644 index c1961bc..0000000 --- a/godot/addons/rmsmartshape/shapes/mesh.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://llobjh5hvry diff --git a/godot/addons/rmsmartshape/shapes/point.gd b/godot/addons/rmsmartshape/shapes/point.gd deleted file mode 100644 index 0e0c397..0000000 --- a/godot/addons/rmsmartshape/shapes/point.gd +++ /dev/null @@ -1,92 +0,0 @@ -@tool -extends Resource -class_name SS2D_Point - -@export var position: Vector2 : set = _set_position -@export var point_in: Vector2 : set = _set_point_in -@export var point_out: Vector2 : set = _set_point_out -@export var texture_idx: int = 0 : set = set_texture_idx -@export var flip: bool = false : set = set_flip -@export var width: float = 1.0 : set = set_width - -## Deprecated. Exists only for backwards compatibility (scene loading). -## Will always be null when accessed! -## @deprecated -@export_storage var properties: SS2D_VertexProperties : set = _set_properties, get = _get_properties - -# If class members are written to, the 'changed' signal may not be emitted -# Signal is only emitted when data is actually changed -# If assigned data is the same as the existing data, no signal is emitted - - -func _init(pos: Vector2 = Vector2.ZERO) -> void: - position = pos - - -func equals(other: SS2D_Point) -> bool: - return other and \ - position == other.position and \ - point_in == other.point_in and \ - point_out == other.point_out and \ - texture_idx == other.texture_idx and \ - flip == other.flip and \ - width == other.width - - -func _set_position(v: Vector2) -> void: - if position != v: - position = v - emit_changed() - - -func _set_point_in(v: Vector2) -> void: - if point_in != v: - point_in = v - emit_changed() - - -func _set_point_out(v: Vector2) -> void: - if point_out != v: - point_out = v - emit_changed() - - -func _set_properties(other: SS2D_VertexProperties) -> void: - if not other: # Happens when duplicate()ing an SS2D_Point - return - - if texture_idx != other.texture_idx or flip != other.flip or width != other.width: - # This generates warnings upon scene load but it's unavoidable - SS2D_PluginFunctionality.show_deprecation_warning("SS2D_VertexProperties", "SS2D_Point members", "A scene re-save likely fixes this warning.") - - # Copy values to members but leave `properties` null to update scene files. - texture_idx = other.texture_idx - flip = other.flip - width = other.width - - -func _get_properties() -> SS2D_VertexProperties: - # This will break existing user code (if any), but it's the only effective way to prevent saving and ID changing. - return null - - -func set_texture_idx(i: int) -> void: - if texture_idx != i: - texture_idx = i - emit_changed() - - -func set_flip(b: bool) -> void: - if flip != b: - flip = b - emit_changed() - - -func set_width(w: float) -> void: - if width != w: - width = w - emit_changed() - - -func _to_string() -> String: - return "" % [position] diff --git a/godot/addons/rmsmartshape/shapes/point.gd.uid b/godot/addons/rmsmartshape/shapes/point.gd.uid deleted file mode 100644 index 9c4e51c..0000000 --- a/godot/addons/rmsmartshape/shapes/point.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwcf4pjgprn0k diff --git a/godot/addons/rmsmartshape/shapes/point_array.gd b/godot/addons/rmsmartshape/shapes/point_array.gd deleted file mode 100644 index 66d646f..0000000 --- a/godot/addons/rmsmartshape/shapes/point_array.gd +++ /dev/null @@ -1,873 +0,0 @@ -@tool -extends Resource -class_name SS2D_Point_Array - -# TODO: Ensure point order is always clockwise -# Relevant SS2D_Actions already perform this check and automatically invert the point order when -# needed. -# This is not ensured when manually modifying points using the provided functions. -# -# Corner generation will break and edge generation will behave slightly different with -# counter-clockwise order. -# Automatically inverting the point order as necessary sounds much simpler than debugging the edge -# generation code. - -enum CONSTRAINT { NONE = 0, AXIS_X = 1, AXIS_Y = 2, CONTROL_POINTS = 4, PROPERTIES = 8, ALL = 15 } -enum ORIENTATION { COLINEAR, CLOCKWISE, C_CLOCKWISE } - -# Maps a key to each point: Dict[int, SS2D_Point] -@export var _points: Dictionary = {} : set = _set_points -# Contains all keys; the order of the keys determines the order of the points -@export var _point_order := PackedInt32Array() : set = set_point_order - -## Dict[Vector2i, CONSTRAINT] -## Key is tuple of point_keys; Value is the CONSTRAINT enum. -@export var _constraints: Dictionary = {} : set = _set_constraints -# Next key value to generate -@export var _next_key: int = 0 : set = set_next_key - -## Dict[Vector2i, SS2D_Material_Edge_Metadata] -## Dictionary of specific materials to use for specific tuples of points. -## Key is tuple of two point keys, value is material. -@export var _material_overrides: Dictionary = {} : set = set_material_overrides - -## Controls how many subdivisions a curve segment may face before it is considered -## approximate enough. -@export_range(0, 8, 1) -var tessellation_stages: int = 3 : set = set_tessellation_stages - -## Controls how many degrees the midpoint of a segment may deviate from the real -## curve, before the segment has to be subdivided. -@export_range(0.1, 16.0, 0.1, "or_greater", "or_lesser") -var tessellation_tolerance: float = 6.0 : set = set_tessellation_tolerance - -@export_range(1, 512) var curve_bake_interval: float = 20.0 : set = set_curve_bake_interval - -var _constraints_enabled: bool = true -var _updating_constraints := false -var _keys_to_update_constraints := PackedInt32Array() - -var _changed_during_update := false -var _updating := false - -# Point caches -var _point_cache_dirty := true -var _vertex_cache := PackedVector2Array() -var _curve := Curve2D.new() -var _curve_no_control_points := Curve2D.new() -var _tesselation_cache := PackedVector2Array() -var _tess_vertex_mapping := SS2D_TesselationVertexMapping.new() - -## Gets called when points were modified. -## In comparison to the "changed" signal, "update_finished" will only be called once after -## begin/end_update() blocks, while "changed" will be called for every singular change. -## Hence, this signal is usually better suited to react to point updates. -signal update_finished() - -signal constraint_removed(key1: int, key2: int) -signal material_override_changed(tuple: Vector2i) - -################### -# HANDLING POINTS # -################### - - -func _init() -> void: - # Required by Godot to correctly make unique instances of this resource - _points = {} - _constraints = {} - _next_key = 0 - # Assigning an empty dict to _material_overrides this way - # instead of assigning in the declaration appears to bypass - # a weird Godot bug where _material_overrides of one shape - # interfere with another - if _material_overrides == null: - _material_overrides = {} - - -func clone(deep: bool = false) -> SS2D_Point_Array: - var copy := SS2D_Point_Array.new() - copy._next_key = _next_key - copy.tessellation_stages = tessellation_stages - copy.tessellation_tolerance = tessellation_tolerance - copy.curve_bake_interval = curve_bake_interval - - if deep: - var new_point_dict := {} - for k: int in _points: - new_point_dict[k] = get_point(k).duplicate(true) - copy._points = new_point_dict - copy._point_order = _point_order.duplicate() - copy._constraints = _constraints.duplicate() - copy._material_overrides = _material_overrides.duplicate() - else: - copy._points = _points - copy._point_order = _point_order - copy._constraints = _constraints - copy._material_overrides = _material_overrides - - return copy - - -## Clears all existing points and recreates the shape from the given curve. -func set_from_curve(curve: Curve2D) -> void: - begin_update() - clear() - - for i in curve.get_point_count(): - add_point(curve.get_point_position(i)) - - end_update() - - -## Called by Godot when loading from a saved scene -func _set_points(ps: Dictionary) -> void: - _points = ps - for k: int in _points: - _hook_point(k) - _changed() - - -func set_point_order(po: PackedInt32Array) -> void: - _point_order = po - _changed() - - -func _set_constraints(cs: Dictionary) -> void: - _constraints = cs - - # For backwards compatibility (Array to Vector2i transition) - # FIXME: Maybe remove during the next breaking release - SS2D_IndexTuple.dict_validate(_constraints, TYPE_INT) - - -func set_next_key(i: int) -> void: - _next_key = i - - -func __generate_key(next: int) -> int: - if not is_key_valid(next): - return __generate_key(maxi(next + 1, 0)) - return next - - -## Reserve a key. It will not be generated again. -func reserve_key() -> int: - var next: int = __generate_key(_next_key) - _next_key = next + 1 - return next - - -## Returns next key that would be generated when adding a new point, e.g. when [method add_point] is called. -func get_next_key() -> int: - return __generate_key(_next_key) - - -func is_key_valid(k: int) -> bool: - return k >= 0 and not _points.has(k) - - -## Add a point and insert it at the given index or at the end by default, regardless whether the -## shape is closed or not. -## See also add_point(). -## Returns the key of the added point. -func add_point_direct(point: Vector2, idx: int = -1, use_key: int = -1) -> int: - return add_point_object_direct(SS2D_Point.new(point), idx, use_key) - - -## Add a point and insert it at the given index or at the end by default, regardless whether the -## shape is closed or not. -## See also add_point(). -## Returns the key of the added point. -func add_point_object_direct(point: SS2D_Point, idx: int = -1, use_key: int = -1) -> int: -# print("Add Point :: ", point, " | idx: ", idx, " | key: ", use_key, " |") - if use_key == -1 or not is_key_valid(use_key): - use_key = reserve_key() - if use_key == _next_key: - _next_key += 1 - _points[use_key] = point - _hook_point(use_key) - _point_order.push_back(use_key) - if idx != -1: - set_point_index(use_key, idx) - _changed() - return use_key - - -## Add a point and insert it at the given index or at the end by default. -## If the shape is closed, the point will always be created before the last and after the first point. -## If explicitly you do not want this, use add_point_direct() instead. -## Returns the key of the added point. -func add_point(pos: Vector2, index: int = -1, key: int = -1) -> int: - return add_point_object(SS2D_Point.new(pos), index, key) - - -## Add a point and insert it at the given index or at the end by default. -## If the shape is closed, the point will always be created before the last and after the first point. -## If explicitly you do not want this, use add_point_direct() instead. -## Returns the key of the added point. -func add_point_object(point: SS2D_Point, index: int = -1, key: int = -1) -> int: - return add_point_object_direct(point, _adjust_add_point_index(index), key) - - -## Don't allow a point to be added after the last point of the closed shape or before the first. -func _adjust_add_point_index(index: int) -> int: - if is_shape_closed(): - if index < 0 or (index > get_point_count() - 1): - index = maxi(get_point_count() - 1, 0) - if index < 1: - index = 1 - return index - - -# FIXME: Only unit tests use this. -func add_points(verts: PackedVector2Array, starting_index: int = -1, key: int = -1) -> PackedInt32Array: - starting_index = _adjust_add_point_index(starting_index) - var keys := PackedInt32Array() - begin_update() - for i in range(0, verts.size(), 1): - var v: Vector2 = verts[i] - if starting_index != -1: - keys.push_back(add_point_direct(v, starting_index + i, key)) - else: - keys.push_back(add_point_direct(v, starting_index, key)) - end_update() - return keys - - -## Deprecated. There is no reason to use this function, points can be modified directly. -## @deprecated -func set_point(key: int, value: SS2D_Point) -> void: - SS2D_PluginFunctionality.show_deprecation_warning("set_point()", "") - if has_point(key): - # FIXME: Should there be a call to remove_constraints() like in remove_point()? Because - # we're technically deleting a point and replacing it with another. - _unhook_point(get_point(key)) - _points[key] = value - _hook_point(key) - _changed() - - -## Connects the changed signal of the given point. Requires that the point exists in _points. -func _hook_point(key: int) -> void: - var p := get_point(key) - if not p.changed.is_connected(_on_point_changed): - p.changed.connect(_on_point_changed.bind(key)) - - -## Disconnects the changed signal of the given point. See also _hook_point(). -func _unhook_point(p: SS2D_Point) -> void: - if p.changed.is_connected(_on_point_changed): - p.changed.disconnect(_on_point_changed) - - -func is_index_in_range(idx: int) -> bool: - return idx >= 0 and idx < _point_order.size() - - -func get_point_key_at_index(idx: int) -> int: - return _point_order[idx] - - -func get_edge_keys_for_indices(indices: Vector2i) -> Vector2i: - return Vector2i( - get_point_key_at_index(indices.x), - get_point_key_at_index(indices.y) - ) - - -func get_point_at_index(idx: int) -> SS2D_Point: - return _points[_point_order[idx]] - - -## Returns the point with the given key as reference or null if it does not exist. -func get_point(key: int) -> SS2D_Point: - return _points.get(key) - - -func get_point_count() -> int: - return _point_order.size() - - -func get_point_index(key: int) -> int: - if has_point(key): - var idx := 0 - for k in _point_order: - if key == k: - return idx - idx += 1 - return -1 - - -static func get_points_orientation(points: PackedVector2Array) -> ORIENTATION: - var point_count: int = points.size() - if point_count < 3: - return ORIENTATION.COLINEAR - - var sum := 0.0 - for i in point_count: - var pt := points[i] - var pt2 := points[(i + 1) % point_count] - sum += pt.cross(pt2) - - # Colinear - if sum == 0.0: - return ORIENTATION.COLINEAR - - # Clockwise - if sum > 0.0: - return ORIENTATION.CLOCKWISE - return ORIENTATION.C_CLOCKWISE - - -func are_points_clockwise() -> bool: - return get_points_orientation(get_vertices()) == ORIENTATION.CLOCKWISE - - -## Reverse order of points in point array.[br] -## I.e. [1, 2, 3, 4] will become [4, 3, 2, 1].[br] -func invert_point_order() -> void: - # Postpone `changed` and disable constraints. - var was_updating: bool = _updating - _updating = true - disable_constraints() - - _point_order.reverse() - # Swap Bezier points. - for p: SS2D_Point in _points.values(): - if p.point_out != p.point_in: - var tmp: Vector2 = p.point_out - p.point_out = p.point_in - p.point_in = tmp - - # Re-enable contraits and emit `changed`. - enable_constraints() - _updating = was_updating - _changed() - - -func set_point_index(key: int, idx: int) -> void: - if not has_point(key): - return - var old_idx: int = get_point_index(key) - if idx < 0 or idx >= _points.size(): - idx = _points.size() - 1 - if idx == old_idx: - return - _point_order.remove_at(old_idx) - _point_order.insert(idx, key) - _changed() - - -func has_point(key: int) -> bool: - return _points.has(key) - - -func get_all_point_keys() -> PackedInt32Array: - # _point_order should contain every single point ONLY ONCE - return _point_order - - -func remove_point(key: int) -> bool: - if has_point(key): -# print("Remove Point :: ", get_point_position(key), " | idx: ", get_point_index(key), " | key: ", key, " |") - remove_constraints(key) - _unhook_point(get_point(key)) - _point_order.remove_at(get_point_index(key)) - _points.erase(key) - _changed() - return true - return false - - -func remove_point_at_index(idx: int) -> void: - remove_point(get_point_key_at_index(idx)) - - -## Remove all points from point array. -func clear() -> void: - _points.clear() - _point_order.clear() - _constraints.clear() - _next_key = 0 - _changed() - - -## point_in controls the edge leading from the previous vertex to this one -func set_point_in(key: int, value: Vector2) -> void: - if has_point(key): - _points[key].point_in = value - _changed() - - -func get_point_in(key: int) -> Vector2: - if has_point(key): - return _points[key].point_in - return Vector2(0, 0) - - -## point_out controls the edge leading from this vertex to the next -func set_point_out(key: int, value: Vector2) -> void: - if has_point(key): - _points[key].point_out = value - _changed() - - -func get_point_out(key: int) -> Vector2: - if has_point(key): - return _points[key].point_out - return Vector2(0, 0) - - -func set_point_position(key: int, value: Vector2) -> void: - if has_point(key): - _points[key].position = value - _changed() - - -func get_point_position(key: int) -> Vector2: - if has_point(key): - return _points[key].position - return Vector2(0, 0) - - -## Deprecated. Use respective members in SS2D_Point directly. -## @deprecated -func set_point_properties(key: int, value: SS2D_VertexProperties) -> void: - SS2D_PluginFunctionality.show_deprecation_warning("set_point_properties", "SS2D_Point") - var p := get_point(key) - if p: - p.texture_idx = value.texture_idx - p.flip = value.flip - p.width = value.width - _changed() - - -## Deprecated. Use respective members in SS2D_Point directly. -## @deprecated -func get_point_properties(key: int) -> SS2D_VertexProperties: - SS2D_PluginFunctionality.show_deprecation_warning("get_point_properties", "SS2D_Point") - var p := get_point(key) - - if not p: - return null - - var props := SS2D_VertexProperties.new() - props.texture_idx = p.texture_idx - props.flip = p.flip - props.width = p.width - return props - - -## Returns the corresponding key for a given point or -1 if it does not exist. -func get_key_from_point(p: SS2D_Point) -> int: - for k: int in _points: - if p == _points[k]: - return k - return -1 - - -func _on_point_changed(key: int) -> void: - if _updating_constraints: - _keys_to_update_constraints.push_back(key) - else: - update_constraints(key) - - -## Begin updating the shape.[br] -## Shape mesh and curve will only be updated after [method end_update] is called. -func begin_update() -> void: - _updating = true - - -## End updating the shape.[br] -## Mesh and curve will be updated, if changes were made to points array after -## [method begin_update] was called. -func end_update() -> bool: - var was_dirty := _changed_during_update - _updating = false - _changed_during_update = false - if was_dirty: - update_finished.emit() - return was_dirty - - -## Is shape in the middle of being updated. -## Returns [code]true[/code] after [method begin_update] and before [method end_update]. -func is_updating() -> bool: - return _updating - - -func _changed() -> void: - _point_cache_dirty = true - - emit_changed() - - if _updating: - _changed_during_update = true - else: - update_finished.emit() - -############### -# CONSTRAINTS # -############### - - -func disable_constraints() -> void: - _constraints_enabled = false - - -func enable_constraints() -> void: - _constraints_enabled = true - - -func _update_constraints(src: int) -> void: - if not _constraints_enabled: - return - - var constraints := get_point_constraints_tuples(src) - - for tuple in constraints: - var constraint: CONSTRAINT = SS2D_IndexTuple.dict_get(_constraints, tuple) - - if constraint == CONSTRAINT.NONE: - continue - - var dst: int = SS2D_IndexTuple.get_other_value(tuple, src) - - if constraint & CONSTRAINT.AXIS_X: - set_point_position(dst, Vector2(get_point_position(src).x, get_point_position(dst).y)) - if constraint & CONSTRAINT.AXIS_Y: - set_point_position(dst, Vector2(get_point_position(dst).x, get_point_position(src).y)) - if constraint & CONSTRAINT.CONTROL_POINTS: - set_point_in(dst, get_point_in(src)) - set_point_out(dst, get_point_out(src)) - if constraint & CONSTRAINT.PROPERTIES: - var pdst := get_point(dst) - var psrc := get_point(src) - - if pdst and psrc: - pdst.texture_idx = psrc.texture_idx - pdst.flip = psrc.flip - pdst.width = psrc.width - - -## Will mutate points based on constraints.[br] -## Values from Passed key will be used to update constrained points.[br] -func update_constraints(src: int) -> void: - if not has_point(src) or _updating_constraints: - return - - _updating_constraints = true - # Initial pass of updating constraints - _update_constraints(src) - - # Subsequent required passes of updating constraints - while not _keys_to_update_constraints.is_empty(): - var key_set := _keys_to_update_constraints - _keys_to_update_constraints = PackedInt32Array() - for k in key_set: - _update_constraints(k) - - _updating_constraints = false - _changed() - - -## Returns all point constraint that include the given point key. -## Returns a Dictionary[Vector2i, CONSTRAINT]. -func get_point_constraints(key1: int) -> Dictionary: - var constraints := {} - var tuples := get_point_constraints_tuples(key1) - - for t in tuples: - constraints[t] = get_point_constraint(t.x, t.y) - - return constraints - - -## Returns all point constraint tuples that include the given point key. -func get_point_constraints_tuples(key1: int) -> Array[Vector2i]: - return SS2D_IndexTuple.dict_find_partial(_constraints, key1) - - -## Returns the constraint for a pair of keys or CONSTRAINT.NONE if no constraint exists. -func get_point_constraint(key1: int, key2: int) -> CONSTRAINT: - return SS2D_IndexTuple.dict_get(_constraints, Vector2i(key1, key2), CONSTRAINT.NONE) - - -## Set a constraint between two points. If the constraint is NONE, remove_constraint() is called instead. -func set_constraint(key1: int, key2: int, constraint: CONSTRAINT) -> void: - var t := Vector2i(key1, key2) - - if constraint == CONSTRAINT.NONE: - remove_constraint(t) - return - - SS2D_IndexTuple.dict_set(_constraints, t, constraint) - update_constraints(key1) - _changed() - - -## Remove all constraints involving the given point key. -func remove_constraints(key1: int) -> void: - for tuple in get_point_constraints_tuples(key1): - remove_constraint(tuple) - - -## Remove the constraint between the two point indices of the given tuple. -func remove_constraint(point_index_tuple: Vector2i) -> void: - if SS2D_IndexTuple.dict_erase(_constraints, point_index_tuple): - emit_signal("constraint_removed", point_index_tuple.x, point_index_tuple.y) - - -## Whether the shape is closed, i.e. last point is constrained to the first point. -func is_shape_closed() -> bool: - if get_point_count() < 2: - return false - var key1: int = get_point_key_at_index(0) - var key2: int = get_point_key_at_index(get_point_count() - 1) - return get_point_constraint(key1, key2) == SS2D_Point_Array.CONSTRAINT.ALL - - -## Return whether the shape can be closed, i.e. has at least two points and is not yet closed. -func can_close() -> bool: - return get_point_count() >= 2 and not is_shape_closed() - - -## Open shape by removing edge that starts at specified point index. -func open_shape_at_edge(edge_start_idx: int) -> void: - var last_idx: int = get_point_count() - 1 - if is_shape_closed(): - remove_point(get_point_key_at_index(last_idx)) - if edge_start_idx < last_idx: - for i in range(edge_start_idx + 1): - set_point_index(get_point_key_at_index(0), last_idx) - else: - push_warning("Can't open a shape that is not a closed shape.") - - -## Undo shape opening done by [method open_shape_at_edge]. -func undo_open_shape_at_edge(edge_start_idx: int, closing_index: int) -> void: - var last_idx := get_point_count() - 1 - if edge_start_idx < last_idx: - for i in range(edge_start_idx + 1): - set_point_index(get_point_key_at_index(last_idx), 0) - if can_close(): - close_shape(closing_index) - - -## Closes the shape by constraining the last point to the first point.[br] -## If last and first point are not identical, a new point is added to keep the existing shape intact.[br] -## Does nothing when the shape is already closed or not closable.[br] -## Returns the key of the last point or -1 if unchanged.[br] -## [param key] suggests which key ID to use when creating a new point. -func close_shape(key: int = -1) -> int: - if not can_close(): - return -1 - - var key_first: int = get_point_key_at_index(0) - var key_last: int = get_point_key_at_index(get_point_count() - 1) - - if get_point_position(key_first) != get_point_position(key_last): - key_last = add_point_direct(get_point_position(key_first), -1, key) - - set_constraint(key_first, key_last, SS2D_Point_Array.CONSTRAINT.ALL) - - return key_last - - -######## -# MISC # -######## -func debug_print() -> void: - for k in get_all_point_keys(): - var pos: Vector2 = get_point_position(k) - var _in: Vector2 = get_point_in(k) - var out: Vector2 = get_point_out(k) - print("%s = P:%s | I:%s | O:%s" % [k, pos, _in, out]) - - -###################### -# MATERIAL OVERRIDES # -###################### -## dict: Dict[Vector2i, SS2D_Material_Edge_Metadata] -func set_material_overrides(dict: Dictionary) -> void: - # For backwards compatibility (Array to Vector2i transition) - # FIXME: Maybe remove during the next breaking release - SS2D_IndexTuple.dict_validate(dict, SS2D_Material_Edge_Metadata) - - if _material_overrides != null: - for old: SS2D_Material_Edge_Metadata in _material_overrides.values(): - _unhook_mat(old) - - _material_overrides = dict - - for tuple: Vector2i in _material_overrides: - _hook_mat(tuple, _material_overrides[tuple]) - - -func has_material_override(tuple: Vector2i) -> bool: - return SS2D_IndexTuple.dict_has(_material_overrides, tuple) - - -func remove_material_override(tuple: Vector2i) -> void: - var old := get_material_override(tuple) - - if old != null: - _unhook_mat(old) - SS2D_IndexTuple.dict_erase(_material_overrides, tuple) - _on_material_override_changed(tuple) - - -func set_material_override(tuple: Vector2i, mat: SS2D_Material_Edge_Metadata) -> void: - var old := get_material_override(tuple) - - if old != null: - if old == mat: - return - else: - _unhook_mat(old) - - _hook_mat(tuple, mat) - SS2D_IndexTuple.dict_set(_material_overrides, tuple, mat) - _on_material_override_changed(tuple) - - -## Returns the material override for the edge defined by the given point index tuple, or null if -## there is no override. -func get_material_override(tuple: Vector2i) -> SS2D_Material_Edge_Metadata: - return SS2D_IndexTuple.dict_get(_material_overrides, tuple) - - -func _hook_mat(tuple: Vector2i, mat: SS2D_Material_Edge_Metadata) -> void: - if not mat.changed.is_connected(_on_material_override_changed): - mat.changed.connect(_on_material_override_changed.bind(tuple)) - - -func _unhook_mat(mat: SS2D_Material_Edge_Metadata) -> void: - if mat.changed.is_connected(_on_material_override_changed): - mat.changed.disconnect(_on_material_override_changed) - - -## Returns a list of index tuples for wich material overrides exist. -func get_material_overrides() -> Array[Vector2i]: - var keys: Array[Vector2i] = [] - keys.assign(_material_overrides.keys()) - return keys - - -func clear_all_material_overrides() -> void: - _material_overrides = {} - - - -## Returns a PackedVector2Array with all points of the shape. -func get_vertices() -> PackedVector2Array: - _update_cache() - return _vertex_cache - - -## Returns a Curve2D representing the shape including bezier handles. -func get_curve() -> Curve2D: - _update_cache() - return _curve - - -## Returns a Curve2D representing the shape, disregarding bezier handles. -func get_curve_no_control_points() -> Curve2D: - _update_cache() - return _curve_no_control_points - - -## Returns a PackedVector2Array with all points -func get_tessellated_points() -> PackedVector2Array: - _update_cache() - return _tesselation_cache - - -func set_tessellation_stages(value: int) -> void: - tessellation_stages = value - _changed() - - -func set_tessellation_tolerance(value: float) -> void: - tessellation_tolerance = value - _changed() - - -func set_curve_bake_interval(f: float) -> void: - curve_bake_interval = f - _curve.bake_interval = f - _changed() - - -func get_tesselation_vertex_mapping() -> SS2D_TesselationVertexMapping: - _update_cache() - return _tess_vertex_mapping - - -## Returns the closest point on the shape. -func get_closest_point(to_point: Vector2) -> Vector2: - return get_curve().get_closest_point(to_point) - - -## Returns the offset of the closest point on the shape. -func get_closest_offset(to_point: Vector2) -> float: - return get_curve().get_closest_offset(to_point) - - -## Returns the closest point on the shape, disregarding bezier modifiers. -func get_closest_point_straight_edge(to_point: Vector2) -> Vector2: - return get_curve_no_control_points().get_closest_point(to_point) - - -## Returns the offset of the closest point on the shape, disregarding bezier modifiers. -func get_closest_offset_straight_edge(to_point: Vector2) -> float: - return get_curve_no_control_points().get_closest_offset(to_point) - - -func _update_cache() -> void: - # NOTE: Theoretically one could differentiate between vertex list dirty, curve dirty and - # tesselation dirty to never waste any computation time. - # However, 99% of the time, the cache will be dirty due to vertex updates, so we don't bother. - - if not _point_cache_dirty: - return - - var keys := get_all_point_keys() - - _vertex_cache.resize(keys.size()) - _curve.clear_points() - _curve_no_control_points.clear_points() - - for i in keys.size(): - var key := keys[i] - var pos := get_point_position(keys[i]) - - # Vertex cache - _vertex_cache[i] = pos - - # Curves - _curve.add_point(pos, get_point_in(key), get_point_out(key)) - _curve_no_control_points.add_point(pos) - - # Tesselation - # Point 0 will be the same on both the curve points and the vertices - # Point size - 1 will be the same on both the curve points and the vertices - _tesselation_cache = _curve.tessellate(tessellation_stages, tessellation_tolerance) - - if _tesselation_cache.size() >= 2: - _tesselation_cache[0] = _curve.get_point_position(0) - _tesselation_cache[-1] = _curve.get_point_position(_curve.get_point_count() - 1) - - _tess_vertex_mapping.build(_tesselation_cache, _vertex_cache) - - _point_cache_dirty = false - - -func _to_string() -> String: - return "" % [_points.keys(), _point_order] - - -func _on_material_override_changed(tuple: Vector2i) -> void: - material_override_changed.emit(tuple) diff --git a/godot/addons/rmsmartshape/shapes/point_array.gd.uid b/godot/addons/rmsmartshape/shapes/point_array.gd.uid deleted file mode 100644 index c45a952..0000000 --- a/godot/addons/rmsmartshape/shapes/point_array.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bo5f7qe27jfje diff --git a/godot/addons/rmsmartshape/shapes/quad.gd b/godot/addons/rmsmartshape/shapes/quad.gd deleted file mode 100644 index a5d3375..0000000 --- a/godot/addons/rmsmartshape/shapes/quad.gd +++ /dev/null @@ -1,210 +0,0 @@ -@tool -extends RefCounted -class_name SS2D_Quad - -enum ORIENTATION { COLINEAR = 0, CCW, CW } -enum CORNER { NONE = 0, OUTER, INNER } - -var pt_a: Vector2 -var pt_b: Vector2 -var pt_c: Vector2 -var pt_d: Vector2 - -var tg_a : Vector2 -var tg_b : Vector2 -var tg_c : Vector2 -var tg_d : Vector2 - -var bn_a : Vector2 -var bn_b : Vector2 -var bn_c : Vector2 -var bn_d : Vector2 - -var texture: Texture2D = null -var color: Color = Color(1.0, 1.0, 1.0, 1.0) - -var is_tapered: bool = false -var ignore_weld_next: bool = false -var flip_texture: bool = false -# Deprecated, should remove control_point_index -var control_point_index: int -var fit_texture := SS2D_Material_Edge.FITMODE.SQUISH_AND_STRETCH - -# Contains value from CORNER enum -var corner: int = 0 - - -# Will return two quads split down the middle of this one -func bisect() -> Array[SS2D_Quad]: - var delta: Vector2 = pt_d - pt_a - var delta_normal := delta.normalized() - var quad_left: SS2D_Quad = duplicate() - var quad_right: SS2D_Quad = duplicate() - var mid_point := Vector2(get_length_average(), 0.0) * delta_normal - quad_left.pt_d = pt_a + mid_point - quad_left.pt_c = pt_b + mid_point - quad_right.pt_a = pt_d - mid_point - quad_right.pt_b = pt_c - mid_point - return [quad_left, quad_right] - - -func _to_string() -> String: - return "[Quad] A:%s B:%s C:%s D:%s | Corner: %s" % [pt_a, pt_b, pt_c, pt_d, corner] - - -func matches_quad(q: SS2D_Quad) -> bool: - return ( - texture == q.texture - and color == q.color - and flip_texture == q.flip_texture - and fit_texture == q.fit_texture - ) - - -func duplicate() -> SS2D_Quad: - var q := SS2D_Quad.new() - q.pt_a = pt_a - q.pt_b = pt_b - q.pt_c = pt_c - q.pt_d = pt_d - - q.texture = texture - q.color = color - - q.flip_texture = flip_texture - q.control_point_index = control_point_index - - q.corner = corner - return q - - -func update_tangents() -> void: - tg_a = (pt_d-pt_a).normalized() - tg_b = (pt_c-pt_b).normalized() - tg_c = tg_b - tg_d = tg_a - - bn_a = (pt_b - pt_a).normalized() - bn_b = bn_a - bn_c = (pt_c - pt_d).normalized() - bn_d = bn_c - - -func _init( - a: Vector2 = Vector2.ZERO, - b: Vector2 = Vector2.ZERO, - c: Vector2 = Vector2.ZERO, - d: Vector2 = Vector2.ZERO, - t: Texture2D = null, - f: bool = false -) -> void: - pt_a = a - pt_b = b - pt_c = c - pt_d = d - - texture = t - flip_texture = f - - -func get_rotation() -> float: - return SS2D_NormalRange.get_angle_from_vector(pt_c - pt_a) - - -## Given three colinear points p, q, r, the function checks if -## point q lies on line segment 'pr'. -func on_segment(p: Vector2, q: Vector2, r: Vector2) -> bool: - return ( - (q.x <= maxf(p.x, r.x)) - and (q.x >= minf(p.x, r.x)) - and (q.y <= maxf(p.y, r.y)) - and (q.y >= minf(p.y, r.y)) - ) - - -## Returns CCW, CW, or colinear.[br] -## see https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ -func get_orientation(a: Vector2, b: Vector2, c: Vector2) -> ORIENTATION: - var val := (float(b.y - a.y) * (c.x - b.x)) - (float(b.x - a.x) * (c.y - b.y)) - if val > 0: - return ORIENTATION.CW - elif val < 0: - return ORIENTATION.CCW - return ORIENTATION.COLINEAR - - -## Return true if line segments p1q1 and p2q2 intersect. -func edges_intersect(p1: Vector2, q1: Vector2, p2: Vector2, q2: Vector2) -> bool: - var o1 := get_orientation(p1, q1, p2) - var o2 := get_orientation(p1, q1, q2) - var o3 := get_orientation(p2, q2, p1) - var o4 := get_orientation(p2, q2, q1) - # General case - if (o1 != o2) and (o3 != o4): - return true - - # Special Cases - # p1 , q1 and p2 are colinear and p2 lies on segment p1q1 - if (o1 == 0) and on_segment(p1, p2, q1): - return true - - # p1 , q1 and q2 are colinear and q2 lies on segment p1q1 - if (o2 == 0) and on_segment(p1, q2, q1): - return true - - # p2 , q2 and p1 are colinear and p1 lies on segment p2q2 - if (o3 == 0) and on_segment(p2, p1, q2): - return true - - # p2 , q2 and q1 are colinear and q1 lies on segment p2q2 - if (o4 == 0) and on_segment(p2, q1, q2): - return true - - return false - - -func self_intersects() -> bool: - return edges_intersect(pt_a, pt_d, pt_b, pt_c) or edges_intersect(pt_a, pt_b, pt_d, pt_c) - - -func render_lines(ci: CanvasItem) -> void: - ci.draw_line(pt_a, pt_b, color) - ci.draw_line(pt_b, pt_c, color) - ci.draw_line(pt_c, pt_d, color) - ci.draw_line(pt_d, pt_a, color) - - -func render_points(rad: float, intensity: float, ci: CanvasItem) -> void: - ci.draw_circle(pt_a, rad, Color(intensity, 0, 0)) - ci.draw_circle(pt_b, rad, Color(0, 0, intensity)) - ci.draw_circle(pt_c, rad, Color(0, intensity, 0)) - ci.draw_circle(pt_d, rad, Color(intensity, 0, intensity)) - - -func get_height_average() -> float: - return (get_height_left() + get_height_right()) / 2.0 - - -func get_height_left() -> float: - return pt_a.distance_to(pt_b) - - -func get_height_right() -> float: - return pt_d.distance_to(pt_c) - - -## Returns the difference in height between the left and right sides. -func get_height_difference() -> float: - return get_height_left() - get_height_right() - - -func get_length_average() -> float: - return (get_length_top() + get_length_bottom()) / 2.0 - - -func get_length_top() -> float: - return pt_d.distance_to(pt_a) - - -func get_length_bottom() -> float: - return pt_c.distance_to(pt_b) diff --git a/godot/addons/rmsmartshape/shapes/quad.gd.uid b/godot/addons/rmsmartshape/shapes/quad.gd.uid deleted file mode 100644 index f27cfb7..0000000 --- a/godot/addons/rmsmartshape/shapes/quad.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://g8wukvwxhvc4 diff --git a/godot/addons/rmsmartshape/shapes/shape.gd b/godot/addons/rmsmartshape/shapes/shape.gd deleted file mode 100644 index 26bafde..0000000 --- a/godot/addons/rmsmartshape/shapes/shape.gd +++ /dev/null @@ -1,1780 +0,0 @@ -@tool -@icon("../assets/closed_shape.png") -extends Node2D -class_name SS2D_Shape - -## Represents the base functionality for all smart shapes. - -# Functions consist of the following categories:[br] -# - Setters / Getters -# - Curve -# - Curve Wrapper -# - Godot -# - Misc -# -# To use search to jump between categories, use the regex: # .+ # - -################ -#-DECLARATIONS-# -################ - -const CLICK_RECT_TAG := "__ss2d_click_rect__" - -var _dirty: bool = false -var _edges: Array[SS2D_Edge] = [] -var _collision_polygon_node: CollisionPolygon2D -# Whether or not the plugin should allow editing this shape -var can_edit: bool = true -var _renderer: SS2D_Renderer -var _click_rect: ColorRect -var _first_update: bool = true - -signal points_modified -signal on_dirty_update -signal make_unique_pressed(shape: SS2D_Shape) - -enum CollisionGenerationMethod { - ## Uses the shape curve to generate a collision polygon. - Default, - ## Uses the edge generation algorithm to create a collision representation that sometimes - ## matches the shape's visuals more accurately. - ## This method is much slower and less consistent than [enum Default]. It should not be used - ## unless absolutely needed. - Legacy, - ## Same as [enum Default] but only generates edge collisions and keeps the inside open. - ## Only relevant for closed shapes. Behaves the same as [enum Default] for open shapes. - Hollow, -} - -enum CollisionUpdateMode { - ## Only update collisions in editor. If the corresponding CollisionPolygon2D is part of the same - ## scene, it will be saved automatically by Godot, hence no additional regeneration at runtime - ## is necessary, which reduces the loading times. - ## Does not work if the CollisionPolygon2D is part of an instanced scene, as only the scene root - ## node will be saved by Godot. - Editor, - ## Only update collisions during runtime. Improves the shape-editing performance in editor but - ## increases loading times as collision generation is deferred to runtime. - Runtime, - ## Update collisions both in editor and during runtime. This is the default behavior in older - ## SS2D versions. - EditorAndRuntime, -} - -########### -#-EXPORTS-# -########### - -# Execute to refresh shape rendered geometry and textures. -@warning_ignore("unused_private_class_variable") -@export_placeholder("ActionProperty") var _refresh: String = "" : set = _refresh_action -# ActionProperty will add a button to inspector to execute this action. -# When non-empty string is passed into setter, action is considerd executed. - -## Visualize generated quads and edges. -@export var editor_debug: bool = false : set = _set_editor_debug - -## @deprecated -@export_range(1, 512) var curve_bake_interval: float = 20.0 : - set(value): - if value != _points.curve_bake_interval: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("curve_bake_interval") - _points.curve_bake_interval = value - get: - return _points.curve_bake_interval - -## How to treat color data. See [enum SS2D_Edge.COLOR_ENCODING]. -@export var color_encoding: SS2D_Edge.COLOR_ENCODING = SS2D_Edge.COLOR_ENCODING.COLOR : set = set_color_encoding - -@export_group("Geometry") - -# Execute to make shape point geometry unique (not materials). -@warning_ignore("unused_private_class_variable") -@export_placeholder("ActionProperty") var _make_unique: String = "" : set = _make_unique_action -# ActionProperty will add a button to inspector to execute this action. -# When non-empty string is passed into setter, action is considerd executed. - -## Resource that holds shape point geometry (aka point array). -@export var _points: SS2D_Point_Array : set = set_point_array - -## Caches generated meshes for faster loading times. -@export_storage var _meshes: Array[SS2D_Mesh] = [] - -@export_group("Edges") - -@export var flip_edges: bool = false : set = set_flip_edges - -## Enable/disable rendering of the edges. -@export var render_edges: bool = true : set = set_render_edges - -@export_group("Materials") - -## Contains textures and data on how to visualize the shape. -@export var shape_material := SS2D_Material_Shape.new() : set = _set_material - -## Dictionary of (Array of 2 keys) to (SS2D_Material_Edge_Metadata) -## Deprecated, exists for Support of older versions -## @deprecated -@export var material_overrides: Dictionary = {} : set = set_material_overrides - -@export_group("Tesselation") - -## Controls how many subdivisions a curve segment may face before it is considered -## approximate enough. -## @deprecated -@export_range(0, 8, 1) -var tessellation_stages: int = 3 : - set(value): - if value != _points.tessellation_stages: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("tesselation_stages") - _points.tessellation_stages = value - get: - return _points.tessellation_stages - -## Controls how many degrees the midpoint of a segment may deviate from the real -## curve, before the segment has to be subdivided. -## @deprecated -@export_range(0.1, 16.0, 0.1, "or_greater", "or_lesser") -var tessellation_tolerence: float = 6.0 : - set(value): - if value != _points.tessellation_tolerance: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("tesselation_tolerance") - _points.tessellation_tolerance = value - get: - return _points.tessellation_tolerance - -@export_group("Collision") - -## Controls which method should be used to generate the collision shape. -@export var collision_generation_method := CollisionGenerationMethod.Default : set = set_collision_generation_method - -## Controls when to update collisions. -@export var collision_update_mode := CollisionUpdateMode.Editor : set = set_collision_update_mode - -## Controls size of generated polygon for CollisionPolygon2D. -@export var collision_size: float = 32 : set = set_collision_size - -## Controls offset of generated polygon for CollisionPolygon2D. -@export var collision_offset: float = 0.0 : set = set_collision_offset - -## NodePath to CollisionPolygon2D node for which polygon data will be generated. -@export_node_path("CollisionPolygon2D") var collision_polygon_node_path: NodePath : set = set_collision_polygon_node_path - -##################### -#-SETTERS / GETTERS-# -##################### - -func set_collision_polygon_node_path(value: NodePath) -> void: - collision_polygon_node_path = value - set_as_dirty() - - if not is_inside_tree(): - return - - if collision_polygon_node_path.is_empty(): - _collision_polygon_node = null - return - - _collision_polygon_node = get_node(collision_polygon_node_path) as CollisionPolygon2D - - if not _collision_polygon_node: - push_error("collision_polygon_node_path should point to proper CollisionPolygon2D node.") - - -func get_collision_polygon_node() -> CollisionPolygon2D: - return _collision_polygon_node - - -func get_point_array() -> SS2D_Point_Array: - return _points - - -func set_point_array(a: SS2D_Point_Array) -> void: - if _points != null: - if _points.is_connected("update_finished", self._points_modified): - _points.disconnect("update_finished", self._points_modified) - if _points.material_override_changed.is_connected(_handle_material_override_change): - _points.material_override_changed.disconnect(_handle_material_override_change) - if a == null: - a = SS2D_Point_Array.new() - _points = a - _points.connect("update_finished", self._points_modified) - _points.material_override_changed.connect(_handle_material_override_change) - set_as_dirty() - notify_property_list_changed() - - -func _refresh_action(value: String) -> void: - if value.length() > 0: - _points_modified() - - -func _make_unique_action(value: String) -> void: - if value.length() > 0: - make_unique_pressed.emit(self) - - -func set_flip_edges(b: bool) -> void: - flip_edges = b - set_as_dirty() - notify_property_list_changed() - - -func set_render_edges(b: bool) -> void: - render_edges = b - set_as_dirty() - notify_property_list_changed() - - -func set_collision_generation_method(value: CollisionGenerationMethod) -> void: - collision_generation_method = value - set_as_dirty() - - -func set_collision_update_mode(value: CollisionUpdateMode) -> void: - collision_update_mode = value - set_as_dirty() - - -func set_collision_size(s: float) -> void: - collision_size = s - set_as_dirty() - - -func set_collision_offset(s: float) -> void: - collision_offset = s - set_as_dirty() - - -## Deprecated. Use get_point_array().set_from_curve() instead. -## @deprecated -func set_curve(curve: Curve2D) -> void: - SS2D_PluginFunctionality.show_deprecation_warning("set_curve()", "get_point_array().set_from_curve()") - _points.set_from_curve(curve) - - -## Deprecated. Use get_point_array().get_curve() instead. -## @deprecated -func get_curve() -> Curve2D: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_curve()") - return _points.get_curve() - - -func _set_editor_debug(value: bool) -> void: - editor_debug = value - queue_redraw() - - -## Deprecated. Use get_point_array().tessellation_stages instead. -## @deprecated -func set_tessellation_stages(value: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_tessellation_stages()") - _points.tessellation_stages = value - - -## Deprecated. Use get_point_array().tessellation_tolerance instead. -## @deprecated -func set_tessellation_tolerence(value: float) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_tessellation_tolerance()") - _points.tessellation_tolerance = value - - -## Deprecated. Use get_point_array().curve_bake_interval instead. -## @deprecated -func set_curve_bake_interval(f: float) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_curve_bake_interval()") - _points.curve_bake_interval = f - - -func set_color_encoding(i: SS2D_Edge.COLOR_ENCODING) -> void: - color_encoding = i - notify_property_list_changed() - set_as_dirty() - - -func _set_material(value: SS2D_Material_Shape) -> void: - if ( - shape_material != null - and shape_material.is_connected("changed", self._handle_material_change) - ): - shape_material.disconnect("changed", self._handle_material_change) - - shape_material = value - if shape_material != null: - shape_material.connect("changed", self._handle_material_change) - set_as_dirty() - notify_property_list_changed() - - -func set_material_overrides(dict: Dictionary) -> void: - material_overrides = {} - if dict.is_empty(): - return - _points.set_material_overrides(dict) - - -######### -#-CURVE-# -######### - -## Deprecated. Use get_point_array().get_vertices() instead. -## @deprecated -func get_vertices() -> PackedVector2Array: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_vertices()") - return _points.get_vertices() - - -## Deprecated. Use get_point_array().get_tessellated_points() instead. -## @deprecated -func get_tessellated_points() -> PackedVector2Array: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_tessellated_points()") - return _points.get_tessellated_points() - - -## Deprecated. Use get_point_array().invert_point_order() instead. -## @deprecated -func invert_point_order() -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("invert_point_order()") - _points.invert_point_order() - - -## Deprecated. Use get_point_array().clear() instead. -## @deprecated -func clear_points() -> void: - SS2D_PluginFunctionality.show_deprecation_warning("clear_points()", "shape.get_point_array().clear()") - _points.clear() - - -## Deprecated. This is now integrated in get_point_array().add_point(). -## @deprecated -func adjust_add_point_index(index: int) -> int: - SS2D_PluginFunctionality.show_deprecation_warning("adjust_add_point_index()", "") - return _points._adjust_add_point_index(index) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func add_points(verts: PackedVector2Array, starting_index: int = -1, key: int = -1) -> PackedInt32Array: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("add_points()") - return _points.add_points(verts, starting_index, key) - - -## Deprecated. Use get_point_array().add_point() instead. -## @deprecated -func add_point(pos: Vector2, index: int = -1, key: int = -1) -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("add_point()") - return _points.add_point(pos, adjust_add_point_index(index), key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func is_shape_closed() -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("is_shape_closed()") - return _points.is_shape_closed() - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func can_close() -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("can_close()") - return _points.can_close() - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func close_shape(key: int = -1) -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("close_shape()") - return _points.close_shape(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func open_shape_at_edge(edge_start_idx: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("open_shape_at_edge()") - _points.open_shape_at_edge(edge_start_idx) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func undo_open_shape_at_edge(edge_start_idx: int, closing_index: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("undo_open_shape_at_edge()") - _points.undo_open_shape_at_edge(edge_start_idx, closing_index) - - -## Deprecated. Use get_point_array().begin_update() instead. -## @deprecated -func begin_update() -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("begin_update()") - _points.begin_update() - - -## Deprecated. Use get_point_array().end_update() instead. -## @deprecated -func end_update() -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("end_update()") - _points.end_update() - - -## Deprecated. Use get_point_array().is_updating() instead. -## @deprecated -func is_updating() -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("is_updating()") - return _points.is_updating() - - -## Deprecated. Use get_point_array().get_next_key() instead. -## @deprecated -func get_next_key() -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_next_key()") - return _points.get_next_key() - - -## Deprecated. Use get_point_array().reserve_key() instead. -## @deprecated -func reserve_key() -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("reserve_key()") - return _points.reserve_key() - - -func _points_modified() -> void: - set_as_dirty() - points_modified.emit() - - -func _is_array_index_in_range(a: Array, i: int) -> bool: - return a.size() > i and i >= 0; - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func is_index_in_range(idx: int) -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("is_index_in_range()") - return _points.is_index_in_range(idx) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func set_point_position(key: int, pos: Vector2) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_position()") - _points.set_point_position(key, pos) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func remove_point(key: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("remove_point()") - _points.remove_point(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func remove_point_at_index(idx: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("remove_point_at_index()") - _points.remove_point_at_index(idx) - - -func clone(clone_point_array: bool = true) -> SS2D_Shape: - var copy := SS2D_Shape.new() - copy.transform = transform - copy.modulate = modulate - copy.shape_material = shape_material - copy.editor_debug = editor_debug - copy.flip_edges = flip_edges - copy.collision_size = collision_size - copy.collision_offset = collision_offset - #copy.material_overrides = s.material_overrides - copy.name = get_name().rstrip("0123456789") - if clone_point_array: - copy.set_point_array(_points.clone(true)) - return copy - - -####################### -#-POINT ARRAY WRAPPER-# -####################### - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func has_point(key: int) -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("has_point()") - return _points.has_point(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_all_point_keys() -> PackedInt32Array: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_all_point_keys()") - return _points.get_all_point_keys() - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_key_at_index(idx: int) -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_key_at_index()") - return _points.get_point_key_at_index(idx) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_at_index(idx: int) -> SS2D_Point: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_at_index()") - return _points.get_point_at_index(idx) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_index(key: int) -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_index()") - return _points.get_point_index(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func set_point_in(key: int, v: Vector2) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_in()") - _points.set_point_in(key, v) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func set_point_out(key: int, v: Vector2) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_out()") - _points.set_point_out(key, v) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_in(key: int) -> Vector2: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_in()") - return _points.get_point_in(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_out(key: int) -> Vector2: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_out()") - return _points.get_point_out(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_closest_point(to_point: Vector2) -> Vector2: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_closest_point()") - return _points.get_closest_point(to_point) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_closest_point_straight_edge(to_point: Vector2) -> Vector2: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_closest_point_straight_edge()") - return _points.get_closest_point_straight_edge(to_point) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_closest_offset_straight_edge(to_point: Vector2) -> float: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_closest_offset_straight_edge()") - return _points.get_closest_offset_straight_edge(to_point) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_closest_offset(to_point: Vector2) -> float: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_closest_offset()") - return _points.get_closest_offset(to_point) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func disable_constraints() -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("disable_constraints()") - _points.disable_constraints() - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func enable_constraints() -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("enable_constraints()") - _points.enable_constraints() - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_count() -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_count()") - return _points.get_point_count() - - -func get_edges() -> Array[SS2D_Edge]: - return _edges - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_position(key: int) -> Vector2: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_position()") - return _points.get_point_position(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point(key: int) -> SS2D_Point: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point()") - return _points.get_point(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_constraints(key: int) -> Dictionary: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_constraints()") - return _points.get_point_constraints(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_constraint(key1: int, key2: int) -> SS2D_Point_Array.CONSTRAINT: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_constraint()") - return _points.get_point_constraint(key1, key2) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func set_constraint(key1: int, key2: int, c: SS2D_Point_Array.CONSTRAINT) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_constraint()") - _points.set_constraint(key1, key2, c) - - -## Deprecated. -## @deprecated -func set_point(key: int, value: SS2D_Point) -> void: - SS2D_PluginFunctionality.show_deprecation_warning("set_point()", "") - _points.set_point(key, value) - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func set_point_width(key: int, w: float) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_width()") - _points.get_point(key).width = w - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func get_point_width(key: int) -> float: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_width()") - return _points.get_point(key).width - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func set_point_texture_index(key: int, tex_idx: int) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_texture_index()") - _points.get_point(key).texture_idx = tex_idx - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func get_point_texture_index(key: int) -> int: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_texture_index()") - return _points.get_point(key).texture_idx - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func set_point_texture_flip(key: int, flip: bool) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_texture_flip()") - _points.get_point(key).flip = flip - - -## Deprecated. Use respective property in get_point_array().get_point() instead. -## @deprecated -func get_point_texture_flip(key: int) -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_texture_flip()") - return _points.get_point(key).flip - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func get_point_properties(key: int) -> SS2D_VertexProperties: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_point_properties()") - return _points.get_point_properties(key) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func set_point_properties(key: int, properties: SS2D_VertexProperties) -> void: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("set_point_properties()") - _points.set_point_properties(key, properties) - - -######### -#-GODOT-# -######### - -func _init() -> void: - set_point_array(SS2D_Point_Array.new()) - - -func _enter_tree() -> void: - # Call this again because get_node() only works when the node is inside the tree - set_collision_polygon_node_path(collision_polygon_node_path) - - # Handle material changes if scene is (re-)entered (e.g. after switching to another) - if shape_material != null: - if not shape_material.is_connected("changed", self._handle_material_change): - shape_material.connect("changed", self._handle_material_change) - - -func _ready() -> void: - # This must run in _ready() because the shape node itself must be ready and registered at the RenderingServer. - _renderer = SS2D_Renderer.new(self) - - if Engine.is_editor_hint(): - _setup_click_rect() - - -func _draw() -> void: - if editor_debug and Engine.is_editor_hint(): - _draw_debug(SS2D_Shape.sort_by_z_index(_edges)) - - -func _draw_debug(edges: Array[SS2D_Edge]) -> void: - for e in edges: - for q in e.quads: - q.render_lines(self) - - var _range := range(0, e.quads.size(), 1) - for i: int in _range: - var q := e.quads[i] - if not (i % 3 == 0): - continue - q.render_points(3, 0.5, self) - - for i: int in _range: - var q := e.quads[i] - if not ((i + 1) % 3 == 0): - continue - q.render_points(2, 0.75, self) - - for i: int in _range: - var q := e.quads[i] - if not ((i + 2) % 3 == 0): - continue - q.render_points(1, 1.0, self) - - -func _exit_tree() -> void: - if shape_material != null: - if shape_material.is_connected("changed", self._handle_material_change): - shape_material.disconnect("changed", self._handle_material_change) - - -############ -#-GEOMETRY-# -############ - - -func should_flip_edges() -> bool: - if _points.is_shape_closed(): - return (_points.are_points_clockwise() == flip_edges) - else: - return flip_edges - - -func bake_collision() -> void: - if not _collision_polygon_node: - return - - if collision_update_mode == CollisionUpdateMode.Editor and not Engine.is_editor_hint() \ - or collision_update_mode == CollisionUpdateMode.Runtime and Engine.is_editor_hint(): - return - - if _points.get_point_count() < 2: - _collision_polygon_node.polygon = PackedVector2Array() - return - - var generated_points: PackedVector2Array - var input_points := _points.get_tessellated_points() - var gen := SS2D_CollisionGen.new() - gen.collision_size = collision_size - gen.collision_offset = collision_offset - - match collision_generation_method: - CollisionGenerationMethod.Legacy: - generated_points = gen.generate_legacy(self) - - CollisionGenerationMethod.Hollow: - if _points.is_shape_closed(): - generated_points = gen.generate_hollow(input_points) - else: - generated_points = gen.generate_open(input_points) - - CollisionGenerationMethod.Default: - if _points.is_shape_closed(): - generated_points = gen.generate_filled(input_points) - else: - generated_points = gen.generate_open(input_points) - - # Always apply xform afterwards so node scaling also affects collision offset and size - var xform := _collision_polygon_node.get_global_transform().affine_inverse() * get_global_transform() - generated_points = xform * generated_points - - if generated_points.size() > 1 and generated_points[0] == generated_points[-1]: - generated_points.resize(generated_points.size() - 1) - - _collision_polygon_node.polygon = generated_points - - -func _build_meshes() -> void: - if _points == null or shape_material == null or _points.get_point_count() < 2: - _edges.clear() - _meshes.clear() - return - - # Reuse SS2D_Mesh objects to reduce VCS noise due to ever-changing IDs even if there was no change. - var mesh_idx: int = 0 - - mesh_idx = _build_fill_mesh(_points.get_tessellated_points(), shape_material, _meshes, mesh_idx) - - if render_edges: - # TODO: Do not create individual meshes for each edge, corner, taper, etc. Merge meshes with same properties. - _edges = _build_edges(shape_material, _points.get_vertices()) - - for e in _edges: - mesh_idx = e.get_meshes(color_encoding, _meshes, mesh_idx) - else: - _edges.clear() - - _meshes.resize(mesh_idx) # Trim if larger - - -## Generates a fill mesh if applicable and stores it in the given mesh buffer. -## Only visible meshes are generated, meshes without a texture are skipped. -## Returns the resulting buffer index, i.e. the next index after the last added mesh. -func _build_fill_mesh(points: PackedVector2Array, s_mat: SS2D_Material_Shape, mesh_buffer: Array[SS2D_Mesh], buffer_idx: int) -> int: - if not _points.is_shape_closed() or \ - s_mat == null or \ - s_mat.fill_textures.is_empty() or \ - points.size() < 3: - return buffer_idx - - # TODO: Support all fill textures not just the first - var tex: Texture2D = s_mat.fill_textures[0] - - if tex == null: - return buffer_idx - - var tex_size: Vector2 = tex.get_size() - points = Geometry2D.offset_polygon(points, tex_size.x * s_mat.fill_mesh_offset).front() - var indices: PackedInt32Array = Geometry2D.triangulate_polygon(points) - - if indices.is_empty(): - push_error("'%s': Couldn't Triangulate shape" % name) - return buffer_idx - - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX) - arrays[Mesh.ARRAY_VERTEX] = points - arrays[Mesh.ARRAY_INDEX] = indices - - var uv_points: PackedVector2Array = _get_uv_points(points, s_mat, tex_size) - arrays[Mesh.ARRAY_TEX_UV] = uv_points - arrays[Mesh.ARRAY_TEX_UV2] = uv_points - - var colors := PackedColorArray() - colors.resize(points.size()) - colors.fill(Color.WHITE) - arrays[Mesh.ARRAY_COLOR] = colors - - var st := SurfaceTool.new() - st.create_from_arrays(arrays, Mesh.PRIMITIVE_TRIANGLES) - st.generate_normals() - st.generate_tangents() - - var mesh := SS2D_Common_Functions.mesh_buffer_get_or_create(mesh_buffer, buffer_idx) - st.commit(mesh.mesh) - mesh.texture = tex - mesh.material = s_mat.fill_mesh_material - mesh.z_index = s_mat.fill_texture_z_index - mesh.show_behind_parent = s_mat.fill_texture_show_behind_parent - buffer_idx += 1 - - return buffer_idx - - -func _get_uv_points( - points: PackedVector2Array, - s_material: SS2D_Material_Shape, - tex_size: Vector2 -) -> PackedVector2Array: - var transformation: Transform2D = global_transform - - # If relative position ... undo translation from global_transform - if not s_material.fill_texture_absolute_position: - transformation = transformation.translated(-global_position) - - # Scale - var tex_scale := 1.0 / s_material.fill_texture_scale - transformation = transformation.scaled(Vector2(tex_scale, tex_scale)) - - # If relative rotation ... undo rotation from global_transform - if not s_material.fill_texture_absolute_rotation: - transformation = transformation.rotated(-global_rotation) - - # Rotate the desired extra amount - transformation = transformation.rotated(-deg_to_rad(s_material.fill_texture_angle_offset)) - - # Shift the desired amount (adjusted so it's scale independent) - transformation = transformation.translated(-s_material.fill_texture_offset / s_material.fill_texture_scale) - - # Convert local space to UV - transformation = transformation.scaled(Vector2(1 / tex_size.x, 1 / tex_size.y)) - - return transformation * points - - -## Given three colinear points p, q, r, the function checks if point q lies on line segment 'pr'.[br] -## See: https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ -static func on_segment(p: Vector2, q: Vector2, r: Vector2) -> bool: - return ( - q.x <= maxf(p.x, r.x) - and q.x >= minf(p.x, r.x) - and q.y <= maxf(p.y, r.y) - and q.y >= minf(p.y, r.y) - ) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -static func get_points_orientation(points: PackedVector2Array) -> SS2D_Point_Array.ORIENTATION: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("get_points_orientation()") - return SS2D_Point_Array.get_points_orientation(points) - - -## Deprecated. Use respective function in get_point_array() instead. -## @deprecated -func are_points_clockwise() -> bool: - SS2D_PluginFunctionality.show_point_array_deprecation_warning("are_points_clockwise()") - return _points.are_points_clockwise() - - -static func build_quad_from_two_points( - pt: Vector2, - pt_next: Vector2, - tex: Texture2D, - width: float, - flip_x: bool, - flip_y: bool, - first_point: bool, - last_point: bool, - custom_offset: float, - custom_extends: float, - fit_texture: SS2D_Material_Edge.FITMODE -) -> SS2D_Quad: - # Create new quad - var quad := SS2D_Quad.new() - quad.texture = tex - quad.color = Color(1.0, 1.0, 1.0, 1.0) - quad.flip_texture = flip_x - quad.fit_texture = fit_texture - - # Calculate the normal - var delta: Vector2 = pt_next - pt - var delta_normal := delta.normalized() - var normal_direction := Vector2(delta.y, -delta.x).normalized() - var normal_length: float = width - var normal_with_magnitude: Vector2 = normal_direction * (normal_length * 0.5) - if flip_y: - normal_with_magnitude *= -1 - var offset: Vector2 = normal_with_magnitude * custom_offset - - # If is first or last point, extend past the normal boundary by 'custom_extends' pixels - if first_point: - pt -= (delta_normal * custom_extends) - if last_point: - pt_next += (delta_normal * custom_extends) - - ############################################## - # QUAD POINT ILLUSTRATION # # - ############################################## - # LENGTH # - # <--------------> # - # pt_a -> O--------O <- pt_d ▲ # - # | | | # - # | pt | | WIDTH # - # | | | # - # pt_b -> O--------O <- pt_c ▼ # - ############################################## - ############################################## - - quad.pt_a = pt + normal_with_magnitude + offset - quad.pt_b = pt - normal_with_magnitude + offset - quad.pt_c = pt_next - normal_with_magnitude + offset - quad.pt_d = pt_next + normal_with_magnitude + offset - - return quad - - -## Builds a corner quad. [br] -## - [param pt] is the center of this corner quad. [br] -## - [param width] will scale the quad in line with the next point (one dimension). [br] -## - [param prev_width] will scale the quad in line with the prev point (hte other dimension). [br] -## - [param custom_scale] will scale the quad in both dimensions. [br] -static func build_quad_corner( - pt_next: Vector2, - pt: Vector2, - pt_prev: Vector2, - pt_width: float, - pt_prev_width: float, - flip_edges_: bool, - corner_status: int, - tex: Texture2D, - size: Vector2, - custom_scale: float, - custom_offset: float -) -> SS2D_Quad: - var new_quad := SS2D_Quad.new() - - # :BUILD PLAN: - # OUTER CORNER INNER CORNER - # - # 0------A-----D 0-----0 - # | 1 : 2 | | 3 : - # 0......B.....C | : - # : | 0-------D-----A - # : 3 | | 1 | 2 : - # 0-----0 0.......C.....B - # - # 1-previous, 2-current, 3-next (points) - - var quad_size: Vector2 = size * 0.5 - var dir_12: Vector2 = (pt - pt_prev).normalized() - var dir_23: Vector2 = (pt_next - pt).normalized() - var offset_12: Vector2 = dir_12 * custom_scale * pt_width * quad_size - var offset_23: Vector2 = dir_23 * custom_scale * pt_prev_width * quad_size - var custom_offset_13: Vector2 = (dir_12 - dir_23) * custom_offset * quad_size - - if flip_edges_: - offset_12 *= -1 - offset_23 *= -1 - custom_offset_13 *= -1 - - # Should we mirror internal ABCD vertices relative to quad center. - # - Historically, quad internal vertices are flipped for inner corner quads (see illustration). - # - Value: 1.0 for outer, -1.0 for inner (mirrored). - var mirror: float = -1.0 if corner_status == SS2D_Quad.CORNER.INNER else 1.0 - - new_quad.pt_a = pt + (-offset_12 - offset_23 + custom_offset_13) * mirror - new_quad.pt_b = pt + (-offset_12 + offset_23 + custom_offset_13) * mirror - new_quad.pt_c = pt + (offset_12 + offset_23 + custom_offset_13) * mirror - new_quad.pt_d = pt + (offset_12 - offset_23 + custom_offset_13) * mirror - - new_quad.corner = corner_status - new_quad.texture = tex - - return new_quad - - -func _get_width_for_tessellated_point( - points: PackedVector2Array, - t_idx: int -) -> float: - var v_idx := _points.get_tesselation_vertex_mapping().tess_to_vertex_index(t_idx) - var v_idx_next := SS2D_PluginFunctionality.get_next_point_index(v_idx, points) - var w1: float = _points.get_point(_points.get_point_key_at_index(v_idx)).width - var w2: float = _points.get_point(_points.get_point_key_at_index(v_idx_next)).width - var ratio: float = get_ratio_from_tessellated_point_to_vertex(t_idx) - return lerp(w1, w2, ratio) - - -## Mutates two quads to be welded.[br] -## Returns the midpoint of the weld.[br] -static func weld_quads(a: SS2D_Quad, b: SS2D_Quad, custom_scale: float = 1.0) -> Vector2: - var midpoint := Vector2(0, 0) - # If both quads are not a corner - if a.corner == SS2D_Quad.CORNER.NONE and b.corner == SS2D_Quad.CORNER.NONE: - var needed_height: float = (a.get_height_average() + b.get_height_average()) / 2.0 - - var pt1: Vector2 = (a.pt_d + b.pt_a) * 0.5 - var pt2: Vector2 = (a.pt_c + b.pt_b) * 0.5 - - midpoint = Vector2(pt1 + pt2) / 2.0 - var half_line: Vector2 = (pt2 - midpoint).normalized() * needed_height * custom_scale / 2.0 - - if half_line != Vector2.ZERO: - pt2 = midpoint + half_line - pt1 = midpoint - half_line - - a.pt_d = pt1 - a.pt_c = pt2 - b.pt_a = pt1 - b.pt_b = pt2 - - # If either quad is a corner - else: - if a.corner == SS2D_Quad.CORNER.OUTER: - b.pt_a = a.pt_c - b.pt_b = a.pt_b - midpoint = (b.pt_a + b.pt_b) / 2.0 - - elif a.corner == SS2D_Quad.CORNER.INNER: - b.pt_a = a.pt_d - b.pt_b = a.pt_a - midpoint = (b.pt_a + b.pt_b) / 2.0 - - elif b.corner == SS2D_Quad.CORNER.OUTER: - a.pt_d = b.pt_a - a.pt_c = b.pt_b - midpoint = (a.pt_d + a.pt_c) / 2.0 - - elif b.corner == SS2D_Quad.CORNER.INNER: - a.pt_d = b.pt_d - a.pt_c = b.pt_c - midpoint = (a.pt_d + a.pt_c) / 2.0 - - return midpoint - - -func _weld_quad_array( - quads: Array[SS2D_Quad], weld_first_and_last: bool, start_idx: int = 0 -) -> void: - if quads.is_empty(): - return - - for index in range(start_idx, quads.size() - 1, 1): - var this_quad: SS2D_Quad = quads[index] - var next_quad: SS2D_Quad = quads[index + 1] - if not this_quad.ignore_weld_next: - SS2D_Shape.weld_quads(this_quad, next_quad) - # If this quad self_intersects after welding, it's likely very small and can be removed - # Usually happens when welding a very large and very small quad together - # Generally looks better when simply being removed - # - # When welding and using different widths, quads can look a little weird - # This is because they are no longer parallelograms - # This is a tough problem to solve - # See http://reedbeta.com/blog/quadrilateral-interpolation-part-1/ - if this_quad.self_intersects(): - quads.remove_at(index) - if index < quads.size(): - var new_index: int = maxi(index - 1, 0) - _weld_quad_array(quads, weld_first_and_last, new_index) - return - - if weld_first_and_last: - if not quads[-1].ignore_weld_next: - SS2D_Shape.weld_quads(quads[-1], quads[0]) - - -func _merge_index_maps(imaps: Array[SS2D_IndexMap], verts: PackedVector2Array) -> Array[SS2D_IndexMap]: - if not _points.is_shape_closed(): - return imaps - # See if any edges have both the first (0) and last idx (size) - # Merge them into one if so - var final_edges: Array[SS2D_IndexMap] = imaps.duplicate() - var edges_by_material: Dictionary = SS2D_IndexMap.index_map_array_sort_by_object(final_edges) - # Erase any with null material - edges_by_material.erase(null) - for mat: Variant in edges_by_material: - var edge_first_idx: SS2D_IndexMap = null - var edge_last_idx: SS2D_IndexMap = null - for e: SS2D_IndexMap in edges_by_material[mat]: - if e.indicies.has(0): - edge_first_idx = e - if e.indicies.has(verts.size()-1): - edge_last_idx = e - if edge_first_idx != null and edge_last_idx != null: - break - if edge_first_idx != null and edge_last_idx != null: - if edge_first_idx == edge_last_idx: - pass - else: - final_edges.erase(edge_last_idx) - final_edges.erase(edge_first_idx) - var indicies := edge_last_idx.indicies + edge_first_idx.indicies - var merged_edge := SS2D_IndexMap.new(indicies, mat) - final_edges.push_back(merged_edge) - return final_edges - - -func _build_edges(s_mat: SS2D_Material_Shape, verts: PackedVector2Array) -> Array[SS2D_Edge]: - var edges: Array[SS2D_Edge] = [] - if s_mat == null: - return edges - - var index_maps: Array[SS2D_IndexMap] = _get_meta_material_index_mapping(s_mat, verts) - var overrides: Array[SS2D_IndexMap] = SS2D_Shape.get_meta_material_index_mapping_for_overrides(s_mat, _points) - - # Remove the override indicies from the default index_maps - for override in overrides: - var old_to_new_imaps := {} - for index_map in index_maps: - var new_imaps: Array[SS2D_IndexMap] = index_map.remove_edges(override.indicies) - old_to_new_imaps[index_map] = new_imaps - for k: SS2D_IndexMap in old_to_new_imaps: - index_maps.erase(k) - for new_imap: SS2D_IndexMap in old_to_new_imaps[k]: - index_maps.push_back(new_imap) - - # Merge index maps - index_maps = _merge_index_maps(index_maps, verts) - - # Add the overrides to the mappings to be rendered - index_maps.append_array(overrides) - - for index_map in index_maps: - edges.push_back(_build_edge_with_material(index_map, s_mat.render_offset, 0.0)) - - return edges - - -## Will return an array of SS2D_IndexMaps.[br] -## Each index map will map a set of indicies to a meta_material.[br] -static func get_meta_material_index_mapping_for_overrides( - _s_material: SS2D_Material_Shape, pa: SS2D_Point_Array -) -> Array[SS2D_IndexMap]: - var mappings: Array[SS2D_IndexMap] = [] - for key_tuple in pa.get_material_overrides(): - var indices := SS2D_IndexTuple.sort_ascending(Vector2i(pa.get_point_index(key_tuple.x), pa.get_point_index(key_tuple.y))) - var m: SS2D_Material_Edge_Metadata = pa.get_material_override(key_tuple) - var new_mapping := SS2D_IndexMap.new(PackedInt32Array([ indices.x, indices.y ]), m) - mappings.push_back(new_mapping) - - return mappings - - -## Will return a dictionary containing array of SS2D_IndexMap.[br] -## Each element in the array is a contiguous sequence of indicies that fit inside -## the meta_material's normalrange.[br] -func _get_meta_material_index_mapping( - s_material: SS2D_Material_Shape, verts: PackedVector2Array -) -> Array[SS2D_IndexMap]: - return SS2D_Shape.get_meta_material_index_mapping(s_material, verts, _points.is_shape_closed()) - - -static func get_meta_material_index_mapping( - s_material: SS2D_Material_Shape, verts: PackedVector2Array, wrap_around: bool -) -> Array[SS2D_IndexMap]: - var final_edges: Array[SS2D_IndexMap] = [] - var edge_building: Dictionary = {} # Dict[SS2D_Material_Edge_Metadata, SS2D_IndexMap] - for idx in range(0, verts.size() - 1, 1): - var idx_next: int = SS2D_PluginFunctionality.get_next_point_index(idx, verts, wrap_around) - var pt: Vector2 = verts[idx] - var pt_next: Vector2 = verts[idx_next] - var delta: Vector2 = pt_next - pt - var normal := Vector2(delta.y, -delta.x).normalized() - - # Get all valid edge_meta_materials for this normal value - var edge_meta_materials := s_material.get_edge_meta_materials(normal) - - # Append to existing edges being built. Add new ones if needed - for e in edge_meta_materials: - var imap: SS2D_IndexMap = edge_building.get(e) - - # Is exsiting, append - if imap: - if not idx_next in imap.indicies: - imap.indicies.push_back(idx_next) - # Isn't existing, make a new mapping - else: - edge_building[e] = SS2D_IndexMap.new([idx, idx_next], e) - - # Closeout and stop building edges that are no longer viable - for e: SS2D_Material_Edge_Metadata in edge_building.keys(): - if not edge_meta_materials.has(e): - final_edges.push_back(edge_building[e]) - edge_building.erase(e) - - # Closeout all edge building - for e: SS2D_Material_Edge_Metadata in edge_building.keys(): - final_edges.push_back(edge_building[e]) - - return final_edges - -######## -#-MISC-# -######## -func _handle_material_change() -> void: - set_as_dirty() - - -func _handle_material_override_change(_tuple: Vector2i) -> void: - set_as_dirty() - - -func set_as_dirty() -> void: - if not _dirty: - call_deferred("_on_dirty_update") - _dirty = true - - -static func sort_by_z_index(a: Array) -> Array: - a.sort_custom(Callable(SS2D_Common_Functions, "sort_z")) - return a - - -static func sort_by_int_ascending(a: Array) -> Array: - a.sort_custom(Callable(SS2D_Common_Functions, "sort_int_ascending")) - return a - - -func _on_dirty_update() -> void: - if _dirty: - force_update() - on_dirty_update.emit() - - -func force_update() -> void: - bake_collision() # TODO: Get rid of CollisionUpdateMode and use _first_update as well. - - if not _first_update or not _meshes: - _build_meshes() - - _renderer.render(_meshes) - queue_redraw() # Debug drawing - _update_click_rect() - - _first_update = false - _dirty = false - - -## Returns a float between 0.0 and 1.0.[br] -## 0.0 means that this tessellated point is at the same position as the vertex.[br] -## 0.5 means that this tessellated point is half-way between this vertex and the next.[br] -## 0.999 means that this tessellated point is basically at the next vertex.[br] -## 1.0 isn't going to happen; If a tess point is at the same position as a vert, it gets a ratio of 0.0.[br] -func get_ratio_from_tessellated_point_to_vertex(t_point_idx: int) -> float: - # Index of the starting vertex - var point_idx := _points.get_tesselation_vertex_mapping().tess_to_vertex_index(t_point_idx) - # Index of the first tesselated point with the same vertex - var tess_point_first_idx: int = _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(point_idx)[0] - # The total tessellated points with the same vertex - var tess_point_count := _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(point_idx).size() - # The index of the passed t_point_idx relative to the starting vert - var tess_index_count := t_point_idx - tess_point_first_idx - return tess_index_count / float(tess_point_count) - - -func debug_print_points() -> void: - _points.debug_print() - - -################### -#-EDGE GENERATION-# -################### - -## Get Number of TessPoints from the start and end indicies of the index_map parameter. -func _edge_data_get_tess_point_count(index_map: SS2D_IndexMap) -> int: - ## TODO Test this function - var count: int = 0 - for i in range(index_map.indicies.size() - 1): - var this_idx := index_map.indicies[i] - var next_idx := index_map.indicies[i + 1] - if this_idx > next_idx: - count += 1 - continue - var this_t_idx: int = _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(this_idx)[0] - var next_t_idx: int = _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(next_idx)[0] - var delta: int = next_t_idx - this_t_idx - count += delta - return count - - -## This function determines if a corner quad should be generated.[br] -## if so, OUTER or INNER? [br] -## - The conditions deg < 0 and flip_edges are used to determine this.[br] -## - These conditions works correctly so long as the points are in Clockwise order.[br] -static func edge_should_generate_corner(pt_prev: Vector2, pt: Vector2, pt_next: Vector2, flip_edges_: bool) -> SS2D_Quad.CORNER: - var generate_corner := SS2D_Quad.CORNER.NONE - var ab: Vector2 = pt - pt_prev - var bc: Vector2 = pt_next - pt - var dot_prod: float = ab.dot(bc) - var determinant: float = (ab.x * bc.y) - (ab.y * bc.x) - var angle := atan2(determinant, dot_prod) - # This angle has a range of 360 degrees - # Is between 180 and - 180 - var deg := rad_to_deg(angle) - var corner_range := 10.0 - var corner_angle := 90.0 - if absf(deg) >= corner_angle - corner_range and absf(deg) <= corner_angle + corner_range: - var inner := false - if deg < 0: - inner = true - if flip_edges_: - inner = not inner - if inner: - generate_corner = SS2D_Quad.CORNER.INNER - else: - generate_corner = SS2D_Quad.CORNER.OUTER - return generate_corner - - -func _edge_generate_corner( - pt_prev: Vector2, - pt: Vector2, - pt_next: Vector2, - width_prev: float, - width: float, - size: float, - edge_material: SS2D_Material_Edge, - texture_idx: int, - c_scale: float, - c_offset: float -) -> SS2D_Quad: - var generate_corner := SS2D_Shape.edge_should_generate_corner(pt_prev, pt, pt_next, flip_edges) - if generate_corner == SS2D_Quad.CORNER.NONE: - return null - var corner_texture: Texture2D = null - if edge_material != null: - if generate_corner == SS2D_Quad.CORNER.OUTER: - corner_texture = edge_material.get_texture_corner_outer(texture_idx) - elif generate_corner == SS2D_Quad.CORNER.INNER: - corner_texture = edge_material.get_texture_corner_inner(texture_idx) - var corner_quad: SS2D_Quad = SS2D_Shape.build_quad_corner( - pt_next, - pt, - pt_prev, - width, - width_prev, - flip_edges, - generate_corner, - corner_texture, - Vector2(size, size), - c_scale, - c_offset - ) - return corner_quad - - -func _imap_contains_all_points(imap: SS2D_IndexMap, verts: PackedVector2Array) -> bool: - return imap.indicies[0] == 0 and imap.indicies[-1] == verts.size()-1 - - -func _is_edge_contiguous(imap: SS2D_IndexMap, verts: PackedVector2Array) -> bool: - if not _points.is_shape_closed(): - return false - return _imap_contains_all_points(imap, verts) - - -# Will construct an SS2D_Edge from the passed parameters. -# index_map must be a SS2D_IndexMap with a SS2D_Material_Edge_Metadata for an object -# the indicies used by index_map should match up with the get_verticies() indicies -# -# default_quad_width is the quad width used if a texture isn't available -# -# c_offset is the magnitude to offset all of the points -# the direction of the offset is the surface_normal -func _build_edge_with_material( - index_map: SS2D_IndexMap, c_offset: float, default_quad_width: float -) -> SS2D_Edge: - var verts_t: PackedVector2Array = _points.get_tessellated_points() - var verts: PackedVector2Array = _points.get_vertices() - var edge := SS2D_Edge.new() - var is_edge_contiguous: bool = _is_edge_contiguous(index_map, verts) - edge.wrap_around = is_edge_contiguous - if not index_map.is_valid(): - return edge - var c_scale := 1.0 - var c_extends := 0.0 - - var edge_material_meta: SS2D_Material_Edge_Metadata = null - var edge_material: SS2D_Material_Edge = null - if index_map.object != null: - edge_material_meta = index_map.object - if edge_material_meta == null: - return edge - if not edge_material_meta.render: - return edge - edge_material = edge_material_meta.edge_material - if edge_material == null: - return edge - c_offset += edge_material_meta.offset - - edge.z_index = edge_material_meta.z_index - edge.z_as_relative = edge_material_meta.z_as_relative - edge.material = edge_material_meta.edge_material.material - - var first_idx: int = index_map.indicies[0] - var last_idx: int = index_map.indicies[-1] - var first_idx_t: int = _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(first_idx)[0] - var last_idx_t: int = _points.get_tesselation_vertex_mapping().vertex_to_tess_indices(last_idx)[-1] - edge.first_point_key = _points.get_point_key_at_index(first_idx) - edge.last_point_key = _points.get_point_key_at_index(last_idx) - - var should_flip := should_flip_edges() - - # How many tessellated points are contained within this index map? - var tess_point_count: int = _edge_data_get_tess_point_count(index_map) - - var i := 0 - var texture_idx := 0 - var sharp_taper_next: SS2D_Quad = null - var is_not_corner: bool = true - var taper_sharp: bool = edge_material_meta != null and edge_material_meta.taper_sharp_corners - while i < tess_point_count: - var tess_idx: int = (first_idx_t + i) % verts_t.size() - var tess_idx_next: int = SS2D_PluginFunctionality.get_next_unique_point_idx(tess_idx, verts_t, true) - var tess_idx_prev: int = SS2D_PluginFunctionality.get_previous_unique_point_idx(tess_idx, verts_t, true) - - # set next_point_delta - # next_point_delta is the number of tess_pts from - # the current tess_pt to the next unique tess_pt - # unique meaning it has a different position from the current tess_pt - var next_point_delta := 0 - for j in range(verts_t.size()): - if ((tess_idx + j) % verts_t.size()) == tess_idx_next: - next_point_delta = j - break - - var vert_idx: int = _points.get_tesselation_vertex_mapping().tess_to_vertex_index(tess_idx) - var vert_key: int = _points.get_point_key_at_index(vert_idx) - var vert_props := _points.get_point(vert_key) - var pt: Vector2 = verts_t[tess_idx] - var pt_next: Vector2 = verts_t[tess_idx_next] - var pt_prev: Vector2 = verts_t[tess_idx_prev] - var flip_x: bool = vert_props.flip - - var width_scale: float = _get_width_for_tessellated_point(verts, tess_idx) - var is_first_point: bool = (vert_idx == first_idx) and not is_edge_contiguous - var is_last_point: bool = (vert_idx == last_idx - 1) and not is_edge_contiguous - var is_first_tess_point: bool = (tess_idx == first_idx_t) and not is_edge_contiguous - var is_last_tess_point: bool = (tess_idx == last_idx_t - 1) and not is_edge_contiguous - - var tex: Texture2D = null - var tex_size := Vector2(default_quad_width, default_quad_width) - var fitmode := SS2D_Material_Edge.FITMODE.SQUISH_AND_STRETCH - if edge_material != null: - if edge_material.randomize_texture: - texture_idx = randi() % edge_material.textures.size() - else : - texture_idx = vert_props.texture_idx - tex = edge_material.get_texture(texture_idx) - tex_size = tex.get_size() - fitmode = edge_material.fit_mode - # Exit if we have an edge material defined but no texture to render - if tex == null: - i += next_point_delta - continue - - var new_quad: SS2D_Quad = SS2D_Shape.build_quad_from_two_points( - pt, - pt_next, - tex, - width_scale * c_scale * tex_size.y, - flip_x, - should_flip, - is_first_point, - is_last_point, - c_offset, - c_extends, - fitmode - ) - var new_quads: Array[SS2D_Quad] = [] - new_quads.push_back(new_quad) - - # Corner Quad - if edge_material != null and edge_material.use_corner_texture: - if tess_idx != first_idx_t or is_edge_contiguous: - var prev_width: float = _get_width_for_tessellated_point(verts, tess_idx_prev) - var q: SS2D_Quad = _edge_generate_corner( - pt_prev, - pt, - pt_next, - prev_width, - width_scale, - tex_size.y, - edge_material, - texture_idx, - c_scale, - c_offset - ) - if q != null: - new_quads.push_front(q) - is_not_corner = false - else: - is_not_corner = true - - # Taper Quad - # Bear in mind, a point can be both first AND last - # Consider an edge that consists of two points (one edge) - # This first point is used to generate the quad; it is both first and last - var did_taper_left: bool = false - var did_taper_right: bool = false - if is_first_tess_point and edge_material != null and edge_material.use_taper_texture: - did_taper_left = true - var taper_quad := _taper_quad(new_quad, edge_material, texture_idx, false, false) - if taper_quad != null: - new_quads.push_front(taper_quad) - if is_last_tess_point and edge_material != null and edge_material.use_taper_texture: - did_taper_right = true - var taper_quad := _taper_quad(new_quad, edge_material, texture_idx, true, false) - if taper_quad != null: - new_quads.push_back(taper_quad) - - # Taper sharp corners - if taper_sharp: - var ang_threshold := PI * 0.5 - if sharp_taper_next != null and is_not_corner: - var taper := _taper_quad(sharp_taper_next, edge_material, texture_idx, true, true) - if taper != null: - taper.ignore_weld_next = true - edge.quads.push_back(taper) - else: - sharp_taper_next.ignore_weld_next = true - sharp_taper_next = null - var vert := verts[vert_idx] - var prev_vert := verts[wrapi(vert_idx - 1, 0, verts.size() - 1)] - var next_vert := verts[wrapi(vert_idx + 1, 0, verts.size() - 1)] - if not did_taper_left and is_not_corner: - var ang_from := prev_vert.angle_to_point(vert) - var ang_to := vert.angle_to_point(next_vert) - var ang_dif := angle_difference(ang_from, ang_to) - if absf(ang_dif) > ang_threshold: - var taper := _taper_quad(new_quad, edge_material, texture_idx, false, true) - if taper != null: - new_quads.push_front(taper) - if not did_taper_right: - var next_next_vert := verts[wrapi(vert_idx + 2, 0, verts.size() - 1)] - var ang_from := vert.angle_to_point(next_vert) - var ang_to := next_vert.angle_to_point(next_next_vert) - var ang_dif := angle_difference(ang_from, ang_to) - if absf(ang_dif) > ang_threshold: - sharp_taper_next = new_quad - - # Final point for closed shapes fix - # Corner quads aren't always correctly when the corner is between final and first pt - if is_last_point and is_edge_contiguous: - var idx_mid: int = verts_t.size() - 1 - var idx_next: int = SS2D_PluginFunctionality.get_next_unique_point_idx(idx_mid, verts_t, true) - var idx_prev: int = SS2D_PluginFunctionality.get_previous_unique_point_idx(idx_mid, verts_t, true) - var p_p: Vector2 = verts_t[idx_prev] - var p_m: Vector2 = verts_t[idx_mid] - var p_n: Vector2 = verts_t[idx_next] - var w_p: float = _get_width_for_tessellated_point(verts, idx_prev) - var w_m: float = _get_width_for_tessellated_point(verts, idx_mid) - var q: SS2D_Quad = _edge_generate_corner( - p_p, p_m, p_n, w_p, w_m, tex_size.y, edge_material, texture_idx, c_scale, c_offset - ) - if q != null: - new_quads.push_back(q) - - # Add new quads to edge - for q in new_quads: - edge.quads.push_back(q) - i += next_point_delta - - # leftover final taper for the last sharp corner if required - if taper_sharp: - if sharp_taper_next != null and edge.quads[0].corner == SS2D_Quad.CORNER.NONE: - var taper := _taper_quad(sharp_taper_next, edge_material, texture_idx, true, true) - if taper != null: - taper.ignore_weld_next = true - edge.quads.push_back(taper) - else: - sharp_taper_next.ignore_weld_next = true - sharp_taper_next = null - - if edge_material_meta != null: - if edge_material_meta.weld: - _weld_quad_array(edge.quads, edge.wrap_around) - - return edge - - -# get the appropriate tapering texture based on direction and whether the current taper is a sharp -# corner taper or normal material edge taper -func get_taper_tex(edge_mat: SS2D_Material_Edge, tex_idx: int, facing_right: bool, corner_taper: bool) -> Texture2D: - if facing_right: - if corner_taper: - return edge_mat.get_texture_taper_corner_right(tex_idx) - else: - return edge_mat.get_texture_taper_right(tex_idx) - else: - if corner_taper: - return edge_mat.get_texture_taper_corner_left(tex_idx) - else: - return edge_mat.get_texture_taper_left(tex_idx) - - -func _taper_quad( - quad: SS2D_Quad, - edge_mat: SS2D_Material_Edge, - tex_idx: int, - facing_right: bool, - corner_taper: bool -) -> SS2D_Quad: - var taper_texture: Texture2D = get_taper_tex(edge_mat, tex_idx, facing_right, corner_taper) - if taper_texture != null: - var taper_size: Vector2 = taper_texture.get_size() - var fit: bool = absf(taper_size.x) <= quad.get_length_average() - if fit: - var taper_quad := quad.duplicate() - taper_quad.corner = SS2D_Quad.CORNER.NONE - taper_quad.texture = taper_texture - var delta_normal: Vector2 = (taper_quad.pt_d - taper_quad.pt_a).normalized() - var offset: Vector2 = delta_normal * taper_size - if facing_right: - taper_quad.pt_a = taper_quad.pt_d - offset - taper_quad.pt_b = taper_quad.pt_c - offset - quad.pt_d = taper_quad.pt_a - quad.pt_c = taper_quad.pt_b - else: - taper_quad.pt_d = taper_quad.pt_a + offset - taper_quad.pt_c = taper_quad.pt_b + offset - quad.pt_a = taper_quad.pt_d - quad.pt_b = taper_quad.pt_c - - taper_quad.is_tapered = true - return taper_quad - # If a new taper quad doesn't fit, re-texture the new_quad - else: - quad.is_tapered = true - quad.texture = taper_texture - return null - - -## Create an invisible rect that catches mouse clicks in editor so we can get clickable shapes. -## It is not very accurate but good enough. MeshInstance2D also only performs a bounding box check. -func _setup_click_rect() -> void: - # NOTE: When duplicating the shape (ctrl+d), Godot will also duplicate the click rect node - # and update its owner to current scene root, which makes it appear in editor. - # Hence we need to check if the node already exists and delete it. - # Updating its owner again to hide it, does not work for some reason. - # add_child() with INTERNAL_MODE_FRONT seems to prevent this whole issue in 4.5 but not in 4.4. - - for i in get_child_count(true): - var node := get_child(i) - - if node.has_meta(CLICK_RECT_TAG): - node.queue_free() - break - - _click_rect = ColorRect.new() - _click_rect.modulate = Color.TRANSPARENT - _click_rect.set_meta(CLICK_RECT_TAG, true) - add_child(_click_rect, false, INTERNAL_MODE_FRONT) - _click_rect.owner = self # Needed to make it clickable - - -## Computes a bounding box of the tesselated curve and assigns it to the click rect. -func _update_click_rect() -> void: - if not _click_rect: - return - - if _points.get_point_count() == 0: - _click_rect.size = Vector2.ZERO - return - - var points := _points.get_tessellated_points() - var rect_min: Vector2 = points[0] - var rect_max: Vector2 = points[0] - - for i in range(1, points.size()): - var p := points[i] - rect_min.x = min(rect_min.x, p.x) - rect_min.y = min(rect_min.y, p.y) - rect_max.x = max(rect_max.x, p.x) - rect_max.y = max(rect_max.y, p.y) - - _click_rect.size = rect_max - rect_min - _click_rect.position = rect_min diff --git a/godot/addons/rmsmartshape/shapes/shape.gd.uid b/godot/addons/rmsmartshape/shapes/shape.gd.uid deleted file mode 100644 index 1270319..0000000 --- a/godot/addons/rmsmartshape/shapes/shape.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dhdc4b8yddyej diff --git a/godot/addons/rmsmartshape/shapes/shape_anchor.gd b/godot/addons/rmsmartshape/shapes/shape_anchor.gd deleted file mode 100644 index bd17f79..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_anchor.gd +++ /dev/null @@ -1,200 +0,0 @@ -@tool -@icon("../assets/Anchor.svg") -extends Node2D -class_name SS2D_Shape_Anchor - -const DEBUG_DRAW_LINE_LENGTH := 128.0 - -@export var shape_path: NodePath : set = set_shape_path -@export var shape_point_index: int = 0 : set = set_shape_point_index -@export_range (0.0, 1.0) var shape_point_offset: float = 0.0 : set = set_shape_point_offset -@export_range (0, 3.14) var child_rotation: float = 3.14 : set = set_child_rotation -@export var use_shape_scale: bool = false : set = set_use_shape_scale - -@export var debug_draw: bool = false : set = set_debug_draw - -var cached_shape_transform: Transform2D = Transform2D.IDENTITY -var shape: SS2D_Shape = null - - -########### -#-SETTERS-# -########### - -func set_shape_path(value: NodePath) -> void: - # Assign path value - shape_path = value - set_shape() - - refresh() - - -func set_shape() -> void: - # Disconnect old shape - if shape != null: - disconnect_shape(shape) - - # Set shape if path is valid and connect - shape = null - if has_node(shape_path): - var new_node: Node = get_node(shape_path) - if not new_node is SS2D_Shape: - push_error("Shape Path isn't a valid subtype of SS2D_Shape! Aborting...") - return - shape = new_node - connect_shape(shape) - shape_point_index = get_shape_index_range(shape, shape_point_index) - - -func get_shape_index_range(s: SS2D_Shape, idx: int) -> int: - var point_count: int = s.get_point_array().get_point_count() - # Subtract 2; - # 'point_count' is out of bounds; subtract 1 - # cannot use final idx as starting point_index; subtract another 1 - var final_idx: int = point_count - 2 - if idx < 0: - idx = final_idx - idx = idx % (final_idx + 1) - return idx - - -func set_shape_point_index(value: int) -> void: - if value == shape_point_index: - return - - if shape == null: - shape_point_index = value - return - - shape_point_index = get_shape_index_range(shape, value) - refresh() - - -func set_shape_point_offset(value: float) -> void: - shape_point_offset = value - refresh() - - -func set_use_shape_scale(value: bool) -> void: - use_shape_scale = value - refresh() - - -func set_child_rotation(value: float) -> void: - child_rotation = value - refresh() - - -func set_debug_draw(v: bool) -> void: - debug_draw = v - refresh() - - -########## -#-EVENTS-# -########## -func _process(_delta: float) -> void: - if shape == null: - set_shape() - return - if shape.is_queued_for_deletion(): - return - if shape.get_global_transform() != cached_shape_transform: - cached_shape_transform = shape.get_global_transform() - refresh() - - -func _monitored_node_leaving() -> void: - pass - - -func _handle_point_change() -> void: - refresh() - - -######### -#LOGIC-# -######### -func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float) -> Vector2: - var q0 := p0.lerp(p1, t) - var q1 := p1.lerp(p2, t) - var q2 := p2.lerp(p3, t) - - var r0 := q0.lerp(q1, t) - var r1 := q1.lerp(q2, t) - - var s := r0.lerp(r1, t) - return s - - -func disconnect_shape(s: SS2D_Shape) -> void: - s.disconnect("points_modified", self._handle_point_change) - s.disconnect("tree_exiting", self._monitored_node_leaving) - - -func connect_shape(s: SS2D_Shape) -> void: - s.connect("points_modified", self._handle_point_change) - s.connect("tree_exiting", self._monitored_node_leaving) - - -func refresh() -> void: - if shape == null: - return - if not is_instance_valid(shape): - return - if shape.is_queued_for_deletion(): - disconnect_shape(shape) - shape = null - return - - var pa := shape.get_point_array() - var pt_a_index: int = shape_point_index - var pt_b_index: int = shape_point_index + 1 - var pt_a_key: int = pa.get_point_key_at_index(pt_a_index) - var pt_b_key: int = pa.get_point_key_at_index(pt_b_index) - - var pt_a: Vector2 = shape.global_transform * pa.get_point_position(pt_a_key) - var pt_b: Vector2 = shape.global_transform * pa.get_point_position(pt_b_key) - - var pt_a_handle: Vector2 - var pt_b_handle: Vector2 - - var n_pt: Vector2 - var n_pt_a: Vector2 - var n_pt_b: Vector2 - - var angle := 0.0 - - pt_a_handle = shape.global_transform * ( - pa.get_point_position(pt_a_key) + pa.get_point_out(pt_a_key) - ) - pt_b_handle = shape.global_transform * ( - pa.get_point_position(pt_b_key) + pa.get_point_in(pt_b_key) - ) - - # If this segment uses no bezier curve, use linear interpolation instead - if pt_a_handle != pt_a or pt_b_handle != pt_b: - n_pt = _cubic_bezier(pt_a, pt_a_handle, pt_b_handle, pt_b, shape_point_offset) - else: - n_pt = pt_a.lerp(pt_b, shape_point_offset) - - n_pt_a = _cubic_bezier( - pt_a, pt_a_handle, pt_b_handle, pt_b, clampf(shape_point_offset - 0.1, 0.0, 1.0) - ) - n_pt_b = _cubic_bezier( - pt_a, pt_a_handle, pt_b_handle, pt_b, clampf(shape_point_offset + 0.1, 0.0, 1.0) - ) - - angle = atan2(n_pt_a.y - n_pt_b.y, n_pt_a.x - n_pt_b.x) - - self.global_transform = Transform2D(angle + child_rotation, n_pt) - - if use_shape_scale: - self.scale = shape.scale - - queue_redraw() - - -func _draw() -> void: - if Engine.is_editor_hint() and debug_draw: - draw_line(Vector2.ZERO, Vector2(0, -DEBUG_DRAW_LINE_LENGTH), self.modulate) diff --git a/godot/addons/rmsmartshape/shapes/shape_anchor.gd.uid b/godot/addons/rmsmartshape/shapes/shape_anchor.gd.uid deleted file mode 100644 index 673a9d7..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_anchor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cq1mme2wkbhor diff --git a/godot/addons/rmsmartshape/shapes/shape_closed.gd b/godot/addons/rmsmartshape/shapes/shape_closed.gd deleted file mode 100644 index 4f5dab5..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_closed.gd +++ /dev/null @@ -1,56 +0,0 @@ -@tool -@icon("../assets/closed_shape.png") -extends SS2D_Shape -class_name SS2D_Shape_Closed -## DEPRECATED: Use [SS2D_Shape] instead. -## @deprecated - -# UNUSED FUNCTIONS: - -## Returns true if line segment 'a1a2' and 'b1b2' intersect.[br] -## Find the four orientations needed for general and special cases.[br] -#func do_edges_intersect(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2) -> bool: -# var o1: int = get_points_orientation([a1, a2, b1]) -# var o2: int = get_points_orientation([a1, a2, b2]) -# var o3: int = get_points_orientation([b1, b2, a1]) -# var o4: int = get_points_orientation([b1, b2, a2]) -# -# # General case -# if o1 != o2 and o3 != o4: -# return true -# -# # Special Cases -# # a1, a2 and b1 are colinear and b1 lies on segment p1q1 -# if o1 == ORIENTATION.COLINEAR and on_segment(a1, b1, a2): -# return true -# -# # a1, a2 and b2 are colinear and b2 lies on segment p1q1 -# if o2 == ORIENTATION.COLINEAR and on_segment(a1, b2, a2): -# return true -# -# # b1, b2 and a1 are colinear and a1 lies on segment p2q2 -# if o3 == ORIENTATION.COLINEAR and on_segment(b1, a1, b2): -# return true -# -# # b1, b2 and a2 are colinear and a2 lies on segment p2q2 -# if o4 == ORIENTATION.COLINEAR and on_segment(b1, a2, b2): -# return true -# -# # Doesn't fall in any of the above cases -# return false - - -#static func get_edge_intersection(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2) -> Variant: -# var den: float = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y) -# -# # Check if lines are parallel or coincident -# if den == 0: -# return null -# -# var ua: float = ((b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)) / den -# var ub: float = ((a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)) / den -# -# if ua < 0 or ub < 0 or ua > 1 or ub > 1: -# return null -# -# return Vector2(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)) diff --git a/godot/addons/rmsmartshape/shapes/shape_closed.gd.uid b/godot/addons/rmsmartshape/shapes/shape_closed.gd.uid deleted file mode 100644 index fc647aa..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_closed.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c6kxvfqr4ewu1 diff --git a/godot/addons/rmsmartshape/shapes/shape_open.gd b/godot/addons/rmsmartshape/shapes/shape_open.gd deleted file mode 100644 index 76d11d3..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_open.gd +++ /dev/null @@ -1,7 +0,0 @@ -@tool -@icon("../assets/open_shape.png") -extends SS2D_Shape -class_name SS2D_Shape_Open - -## DEPRECATED: Use [SS2D_Shape] instead. -## @deprecated diff --git a/godot/addons/rmsmartshape/shapes/shape_open.gd.uid b/godot/addons/rmsmartshape/shapes/shape_open.gd.uid deleted file mode 100644 index de0d8a9..0000000 --- a/godot/addons/rmsmartshape/shapes/shape_open.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://xvj68crt1xbu diff --git a/godot/addons/rmsmartshape/strings.gd b/godot/addons/rmsmartshape/strings.gd deleted file mode 100644 index 7efacde..0000000 --- a/godot/addons/rmsmartshape/strings.gd +++ /dev/null @@ -1,18 +0,0 @@ -@tool -extends Resource -class_name SS2D_Strings - -const EN_TOOLTIP_CREATE_VERT := "Create Vertices Tool\nLMB: Add vertex\nShift+LMB: Create Bezier curve using Control Points\nControl+LMB: Set Pivot Point\nLMB+Drag: Move Point\nLMB: Click on edge to split\nRMB: Delete Point" -const EN_TOOLTIP_EDIT_VERT := "Edit Vertices Tool\nShift+LMB: Create Bezier curve using Control Points\nAlt+LMB: Add vertex\nControl+LMB: Set Pivot Point\nLMB+Drag: Move Point\nLMB: Click on edge to split\nRMB: Delete Point" -const EN_TOOLTIP_EDIT_EDGE := "Edit Edge Tool\nSelect each edge's properties" -const EN_TOOLTIP_CUT_EDGE := "Cut Edge Tool\nRemoves the edge between vertices, opening the shape.\nCan be used to split the shape into two separate shapes." -const EN_TOOLTIP_FREEHAND := "Freehand Tool\nHold LMB: Add vertices along the drag line.\nControl+LMB: remove vertices inside the circle while dragging.\nShift+Mousewheel: Change circle size for drawing.\nShift+Control+Mousewheel: Change circle size for eraser." -const EN_TOOLTIP_PIVOT := "Set Pivot Tool\nSets the origin of the shape" -const EN_TOOLTIP_CENTER_PIVOT := "Center Pivot\nSets the origin to the centroid of the shape" -const EN_TOOLTIP_COLLISION := "Collision Tool\nAdds a CollisionPolygon2D and assigns it to the shape.\nUse this to auto-setup shape collisions." -const EN_TOOLTIP_SNAP := "Snapping Options" -const EN_TOOLTIP_MORE_OPTIONS := "More Options" - -const EN_OPTIONS_DEFER_MESH_UPDATES := "Defer Mesh Updates" -const EN_OPTIONS_CHECK_VERSION := "Perform Version Check" -const EN_OPTIONS_COLLISIONS := "Collision Generation Options" diff --git a/godot/addons/rmsmartshape/strings.gd.uid b/godot/addons/rmsmartshape/strings.gd.uid deleted file mode 100644 index f650250..0000000 --- a/godot/addons/rmsmartshape/strings.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cx6sjvnurso06 diff --git a/godot/addons/rmsmartshape/tools/collision_tool.gd b/godot/addons/rmsmartshape/tools/collision_tool.gd deleted file mode 100644 index ab31bee..0000000 --- a/godot/addons/rmsmartshape/tools/collision_tool.gd +++ /dev/null @@ -1,107 +0,0 @@ -extends SS2D_EditorTool -class_name SS2D_CollisionEditorTool - -const ICON_COLLISION: Texture2D = preload("res://addons/rmsmartshape/assets/icon_collision_polygon_2d.svg") -const CONFIG_KEY = "collision_container_path" - -var _collision_container_path: String -var _options_dialog := OptionsDialog.new() - - -# NOTE: Could be a scene, but it's rather simple and has static typing without polluting the "Add node" dialog. -class OptionsDialog: - extends AcceptDialog - - var line_edit: LineEdit - - func _init() -> void: - title = SS2D_Strings.EN_OPTIONS_COLLISIONS - exclusive = false # Prevent error when opening node selection dialog - - var content := VBoxContainer.new() - add_child(content) - - var label := Label.new() - label.text = """ - Enter a node path, a group name or a scene unique name. - The first node found is used as parent for collision polygons generated using the Collision Tool. - If empty, the collision polygon is created as sibling to the shape node. - - For example: %StaticBody2D, %level/StaticBody2D, collision_body_group, etc. - """.dedent().strip_edges() - content.add_child(label) - - line_edit = LineEdit.new() - line_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL - register_text_enter(line_edit) - - var select_node := Button.new() - select_node.text = "Select" - select_node.pressed.connect(EditorInterface.popup_node_selector.bind(_on_node_selected)) - - var hbox := HBoxContainer.new() - hbox.add_child(line_edit) - hbox.add_child(select_node) - content.add_child(hbox) - - func _on_node_selected(path: NodePath) -> void: - if not visible: # Dialog could be closed while node selection is still open - return - - if not path.is_empty(): - var node := get_tree().edited_scene_root.get_node(path) - - if node.unique_name_in_owner: - line_edit.text = "%" + node.name - else: - line_edit.text = path - - func set_selected_node_path(path: NodePath) -> void: - line_edit.text = path - - func get_selected_node_path() -> NodePath: - return NodePath(line_edit.text) - - -func load_config(conf: ConfigFile) -> void: - _collision_container_path = conf.get_value(CONFIG_OPTIONS_SECTION, CONFIG_KEY, "") - - -func save_config(conf: ConfigFile) -> void: - conf.set_value(CONFIG_OPTIONS_SECTION, CONFIG_KEY, _collision_container_path) - - -func register(editor_plugin: EditorPlugin) -> void: - super.register(editor_plugin) - create_options_item(SS2D_Strings.EN_OPTIONS_COLLISIONS, _on_options_clicked) - create_tool_button(ICON_COLLISION, SS2D_Strings.EN_TOOLTIP_COLLISION, false).pressed.connect(_on_tool_clicked) - - _options_dialog.confirmed.connect(_on_options_confirmed) - get_plugin().add_child(_options_dialog) - - -func _on_tool_clicked() -> void: - if get_shape(): - perform_action(SS2D_ActionAddCollisionNodes.new(get_shape(), _get_collision_container_node())) - - -func _on_options_clicked() -> void: - _options_dialog.set_selected_node_path(_collision_container_path) - _options_dialog.popup_centered() - - -func _on_options_confirmed() -> void: - _collision_container_path = _options_dialog.get_selected_node_path() - - -func _get_collision_container_node() -> Node: - if not _collision_container_path: - return null - - var tree := get_plugin().get_tree() - var node := tree.edited_scene_root.get_node_or_null(_collision_container_path) - - if node: - return node - - return tree.get_first_node_in_group(_collision_container_path) diff --git a/godot/addons/rmsmartshape/tools/collision_tool.gd.uid b/godot/addons/rmsmartshape/tools/collision_tool.gd.uid deleted file mode 100644 index efaef40..0000000 --- a/godot/addons/rmsmartshape/tools/collision_tool.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://baklv7u5sw7rp diff --git a/godot/addons/rmsmartshape/tools/editor_tool.gd b/godot/addons/rmsmartshape/tools/editor_tool.gd deleted file mode 100644 index 6fb48a9..0000000 --- a/godot/addons/rmsmartshape/tools/editor_tool.gd +++ /dev/null @@ -1,74 +0,0 @@ -extends RefCounted -class_name SS2D_EditorTool - -const CONFIG_OPTIONS_SECTION = "options" - -var _editor_plugin: SS2D_Plugin -var _toolbar: Control -var _options_menu: PopupMenu -var _options_entries := {} ## Dict[int, Callable] - - -func load_config(_conf: ConfigFile) -> void: - pass - - -func save_config(_conf: ConfigFile) -> void: - pass - - -## Initialize the tool and register UI controls. -## Derived classes must call the base implementation! -func register(editor_plugin: EditorPlugin) -> void: - _editor_plugin = editor_plugin - - # TODO: Add an abstraction with tighter interface for the toolbar, e.g. SS2D_Toolbar - _toolbar = _editor_plugin.tb_hb - - _options_menu = _editor_plugin.tb_options_popup - _options_menu.index_pressed.connect(_on_options_index_pressed_dispatch) - - -## Create a tool button in the toolbar. -func create_tool_button(icon: Texture2D, tooltip: String, toggle: bool = true) -> Button: - return _editor_plugin.create_tool_button(icon, tooltip, toggle) - - -func perform_action(action: SS2D_Action) -> void: - _editor_plugin.perform_action(action) - - -func create_options_item(label: String, callback: Callable) -> void: - _options_menu.add_item(label) - _options_entries[_options_menu.item_count - 1] = callback - - -func get_options_menu() -> PopupMenu: - return _options_menu - - -func get_toolbar() -> Control: - return _toolbar - - -func get_plugin() -> EditorPlugin: - return _editor_plugin - - -func get_shape() -> SS2D_Shape: - return _editor_plugin.shape - - -## Adds the dialog node to the tree and displays it. -## Connects to `confirmed` and `canceled` signals to `queue_free()` it when closed. -func show_oneshot_dialog(dialog: AcceptDialog) -> void: - dialog.confirmed.connect(dialog.queue_free) - dialog.canceled.connect(dialog.queue_free) - _editor_plugin.add_child(dialog) - dialog.popup_centered() - - -func _on_options_index_pressed_dispatch(idx: int) -> void: - var callback: Callable = _options_entries.get(idx) - if callback: - callback.call() diff --git a/godot/addons/rmsmartshape/tools/editor_tool.gd.uid b/godot/addons/rmsmartshape/tools/editor_tool.gd.uid deleted file mode 100644 index 19bac02..0000000 --- a/godot/addons/rmsmartshape/tools/editor_tool.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://btoqcxgi2t35b diff --git a/godot/addons/rmsmartshape/version_transition.gd b/godot/addons/rmsmartshape/version_transition.gd deleted file mode 100644 index 99745d8..0000000 --- a/godot/addons/rmsmartshape/version_transition.gd +++ /dev/null @@ -1,203 +0,0 @@ -extends RefCounted -class_name SS2D_VersionTransition - - -class IVersionConverter: - extends RefCounted - - # Initialize internal state. Must be called before using any other functionality. - func init() -> void: - pass - - func needs_conversion() -> bool: - return false - - # Perform conversion. Should return true and do nothing if no conversion is needed. - func convert() -> bool: - return true - - -class ShapeNodeTypeConverter: - extends IVersionConverter - - var _files: PackedStringArray - var _from_type: String - var _to_type: String - - func _init(from: String, to: String) -> void: - _from_type = from - _to_type = to - - func init() -> void: - var analyzer := TscnAnalyzer.new() - for path in SS2D_VersionTransition.find_files("res://", [ "*.tscn" ]): - if analyzer.load(path): - if analyzer.change_shape_node_type(_from_type, _to_type, true): - _files.append(path) - - func needs_conversion() -> bool: - return _files.size() > 0 - - func convert() -> bool: - var analyzer := TscnAnalyzer.new() - - for path in _files: - analyzer.load(path) - analyzer.change_shape_node_type(_from_type, _to_type) - - if not analyzer.write(): - return false - - print("SS2D: Converted scene ", path) - - return true - - -class TscnAnalyzer: - extends RefCounted - - var _path: String - var _lines: PackedStringArray - var _shape_script_ids: PackedStringArray - var _content_start_line: int # Points to the first line after [ext_resource] section - - func load(tscn_path: String) -> bool: - _path = tscn_path - _shape_script_ids.clear() - var content := FileAccess.get_file_as_string(tscn_path) - - if not content: - _lines.clear() - _content_start_line = 0 - return false - - _lines = content.split("\n") - _content_start_line = _extract_shape_script_ids(_shape_script_ids) - return true - - func contains_shapes() -> bool: - return _shape_script_ids.size() > 0 - - ## Writes the internal buffer to the given file. If no file is specified, writes to the loaded file. - ## Returns true on success. - func write(file_path: String = "") -> bool: - file_path = file_path if file_path else _path - - var f := FileAccess.open(file_path, FileAccess.WRITE) - - if not f: - push_error("Failed to open file for writing: ", file_path) - return false - - f.store_string("\n".join(_lines)) - f.close() - return true - - ## Changes the node type of shape nodes from the given type to the given type. - ## Returns true if changes were made. - ## If check_only is true, it returns true when conversion is needed, but no modifications are made. - func change_shape_node_type(from: String, to: String, check_only: bool = false) -> bool: - if not _shape_script_ids or _content_start_line == -1: - return false - - var next_line := _content_start_line - var re_match_script := RegEx.create_from_string("^script\\s*=\\s*ExtResource\\(\"(%s)\"\\)" % "|".join(_shape_script_ids)) - var re_match_node_type := RegEx.create_from_string("type=\"%s\"" % from) - var replace_string := "type=\"%s\"" % to - var dirty := false - - while true: - var node_line := _find_node_with_property_re(next_line, re_match_script) - next_line = node_line + 1 - - if node_line == -1: - break - - var replaced := re_match_node_type.sub(_lines[node_line], replace_string) - - # No change -> nothing to do here - if replaced == _lines[node_line]: - continue - - if check_only: - return true - - _lines[node_line] = replaced - dirty = true - - return dirty - - ## Examines [ext_resource] entries and updates the given list to include all resource IDs referring - ## to shapes (shape/shape_open/shape_closed.gd). - ## Returns -1 when EOF was reached, otherwise the index of the first non-[ext_resource] line. - func _extract_shape_script_ids(out_shape_ids: PackedStringArray) -> int: - var re_ext_resource_path_is_shape := RegEx.create_from_string("path=\"(res://addons/rmsmartshape/shapes/(?:shape|shape_closed|shape_open).gd\")") - var re_extract_id := RegEx.create_from_string("id=\"([0-9a-z_]+)\"") - var found_something := false - - for i in _lines.size(): - var line := _lines[i] - - if line.begins_with("[ext_resource"): - if re_ext_resource_path_is_shape.search(line): - out_shape_ids.append(re_extract_id.search(line).get_string(1)) - found_something = true - continue - - # Any other tag like [sub_resource] or [node]. Usually there shouldn't be any intermixed ext_resource tags - if found_something and line.begins_with("["): - return i - - return -1 - - ## Searches for property definitions under [node] tags matching the given regex. - ## Returns the line of the [node] tag if a match was found, otherwise -1. - func _find_node_with_property_re(start_line: int, re: RegEx) -> int: - var node_line: int = -1 - - for i in range(start_line, _lines.size()): - var line := _lines[i] - - if line.begins_with("[node"): - node_line = i - elif line.begins_with("["): # There are likely no other tags intermixed but just to be sure - node_line = -1 - elif node_line != -1: - if re.search(line): - return node_line - - return -1 - - -## Recursively searches for files in the given searchpath. -## Returns a list of files matching the given glob expressions. -static func find_files(searchpath: String, globs: PackedStringArray) -> PackedStringArray: - var root := DirAccess.open(searchpath) - - if not root: - push_error("Failed to open directory: ", searchpath) - - root.include_navigational = false - root.list_dir_begin() - - var files: PackedStringArray - var root_path := root.get_current_dir() - - while true: - var fname := root.get_next() - - if fname.is_empty(): - break - - var path := root_path.path_join(fname) - - if root.current_is_dir(): - files.append_array(find_files(path, globs)) - else: - for expr in globs: - if fname.match(expr): - files.append(path) - break - - root.list_dir_end() - return files diff --git a/godot/addons/rmsmartshape/version_transition.gd.uid b/godot/addons/rmsmartshape/version_transition.gd.uid deleted file mode 100644 index 0762c4b..0000000 --- a/godot/addons/rmsmartshape/version_transition.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bde4ph07ai081 diff --git a/godot/addons/rmsmartshape/vertex_properties.gd b/godot/addons/rmsmartshape/vertex_properties.gd deleted file mode 100644 index b16eba7..0000000 --- a/godot/addons/rmsmartshape/vertex_properties.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -extends Resource -class_name SS2D_VertexProperties - -## Deprecated. These properties are now included in SS2D_Point -## @deprecated - -@export var texture_idx: int : set = set_texture_idx -@export var flip: bool : set = set_flip -@export var width: float : set = set_width - - -func set_texture_idx(i: int) -> void: - texture_idx = i - emit_changed() - - -func set_flip(b: bool) -> void: - flip = b - emit_changed() - - -func set_width(w: float) -> void: - width = w - emit_changed() - - -func _init() -> void: - texture_idx = 0 - flip = false - width = 1.0 - - -func equals(other: SS2D_VertexProperties) -> bool: - if other.flip != flip: - return false - if other.texture_idx != texture_idx: - return false - if other.width != width: - return false - return true diff --git a/godot/addons/rmsmartshape/vertex_properties.gd.uid b/godot/addons/rmsmartshape/vertex_properties.gd.uid deleted file mode 100644 index dd90961..0000000 --- a/godot/addons/rmsmartshape/vertex_properties.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://byp4h2084wgn2 diff --git a/godot/addons/rubonnek.inventory_manager/LICENSE.md b/godot/addons/rubonnek.inventory_manager/LICENSE.md deleted file mode 100644 index ce5812c..0000000 --- a/godot/addons/rubonnek.inventory_manager/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024-2025 Wilson Enrique Alvarez Torres - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd b/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd deleted file mode 100644 index 76f5fce..0000000 --- a/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd +++ /dev/null @@ -1,33 +0,0 @@ -@tool -extends EditorDebuggerPlugin - - -var session_id_to_inventory_manager_viewer : Dictionary = {} - - -func _setup_session(p_session_id : int) -> void: - # Instantiate the inventory manager viewer and grab the debugger session - var inventory_manager_viewer : Control = preload("./inventory_manager_viewer.tscn").instantiate() - var editor_debugger_session : EditorDebuggerSession = get_session(p_session_id) - - # Listen to the debugger session started signal. - @warning_ignore("unsafe_property_access", "unsafe_call_argument") - var _success : int = editor_debugger_session.started.connect(inventory_manager_viewer.__on_session_started) - @warning_ignore("unsafe_property_access", "unsafe_call_argument") - _success = editor_debugger_session.stopped.connect(inventory_manager_viewer.__on_session_stopped) - - # Add the inventory manager viewer to the debugger tabs - editor_debugger_session.add_session_tab(inventory_manager_viewer) - - # Track sessions so that we can push the data from _capture into the right session - session_id_to_inventory_manager_viewer[p_session_id] = inventory_manager_viewer - - -func _has_capture(p_prefix : String) -> bool: - return p_prefix == "inventory_manager" - - -func _capture(p_message : String, p_data : Array, p_session_id : int) -> bool: - var inventory_manager_viewer : Control = session_id_to_inventory_manager_viewer[p_session_id] - @warning_ignore("unsafe_method_access") - return inventory_manager_viewer.on_editor_debugger_plugin_capture(p_message, p_data) diff --git a/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd.uid b/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd.uid deleted file mode 100644 index 197f90b..0000000 --- a/godot/addons/rubonnek.inventory_manager/debugger/editor_debugger_plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bu8iwttw2no6j diff --git a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd b/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd deleted file mode 100644 index c0356df..0000000 --- a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd +++ /dev/null @@ -1,476 +0,0 @@ -@tool -extends PanelContainer - -@export var inventory_manager_viewer_manager_selection_line_edit_ : LineEdit -@export var inventory_manager_viewer_manager_selection_tree_ : Tree -@export var inventory_manager_viewer_item_slots_tree_ : Tree -@export var inventory_manager_viewer_item_slots_view_warning_label_ : Label -@export var inventory_manager_viewer_inventory_data_view_text_edit_ : TextEdit -@export var inventory_manager_viewer_inventory_data_view_warning_label_ : Label - -var _m_original_inventory_entry_view_warning_text : String -var _m_original_inventory_data_view_warning_text : String - -var _m_remote_item_registry_cache : Dictionary = {} -var _m_remote_inventory_manager_to_its_tree_item_map : Dictionary = {} - - -func _ready() -> void: - # Connect InventoryManager tree signals - var _success : int = inventory_manager_viewer_manager_selection_tree_.item_selected.connect(__on_inventory_manager_selection_tree_item_selected) - _success = inventory_manager_viewer_manager_selection_tree_.nothing_selected.connect(__on_inventory_manager_selection_tree_nothing_selected) - - # Connect ItemSlot tree signals - _success = inventory_manager_viewer_item_slots_tree_.item_selected.connect(__on_inventory_view_selection_item_selected) - _success = inventory_manager_viewer_item_slots_tree_.nothing_selected.connect(__on_inventory_view_selection_nothing_selected) - - # Connect line edit for filtering the InventoryManagers list - _success = inventory_manager_viewer_manager_selection_line_edit_.text_changed.connect(__on_inventory_manager_selection_line_edit_text_changed) - - # Grab the original metadata warning text -- we'll need this to restore their state once the debugger session is stopped - _m_original_inventory_entry_view_warning_text = inventory_manager_viewer_item_slots_view_warning_label_.get_text() - _m_original_inventory_data_view_warning_text = inventory_manager_viewer_inventory_data_view_warning_label_.get_text() - - # Configure the Item Entry Viewer Tree - inventory_manager_viewer_item_slots_tree_.set_columns(2) - inventory_manager_viewer_item_slots_tree_.set_column_title(0, "Name") - inventory_manager_viewer_item_slots_tree_.set_column_title(1, "Amount") - inventory_manager_viewer_item_slots_tree_.set_column_titles_visible(true) - inventory_manager_viewer_item_slots_tree_.set_select_mode(Tree.SelectMode.SELECT_ROW) - inventory_manager_viewer_item_slots_tree_.set_column_title_alignment(0, HORIZONTAL_ALIGNMENT_LEFT) - inventory_manager_viewer_item_slots_tree_.set_column_title_alignment(1, HORIZONTAL_ALIGNMENT_LEFT) - - -# ==== EDITOR DEBUGGER PLUGIN PASSTHROUGH FUNCTIONS BEGIN ====== -func on_editor_debugger_plugin_capture(p_message : String, p_data : Array) -> bool: - match p_message: - "inventory_manager:register_item_registry": - var item_registry_id : int = p_data[0] - var item_registry : ItemRegistry = ItemRegistry.new() - _m_remote_item_registry_cache[item_registry_id] = item_registry - return true - - "inventory_manager:item_registry_sync_item_registry_entry": - var item_registry_id : int = p_data[0] - var item_id : int = p_data[1] - var item_registry_data : Dictionary = p_data[2] - - # Convert the image bytes back into the image object: - if item_registry_data.has(ItemRegistry._item_entry_key.ICON): - var bytes : PackedByteArray = item_registry_data[ItemRegistry._item_entry_key.ICON] - var image : Image = bytes_to_var_with_objects(bytes) - image.resize(16,16) - var texture : ImageTexture = ImageTexture.create_from_image(image) - item_registry_data[ItemRegistry._item_entry_key.ICON] = texture - - var item_registry : ItemRegistry = _m_remote_item_registry_cache[item_registry_id] - item_registry.__inject(item_id, item_registry_data) - return true - - "inventory_manager:item_registry_set_data": - var item_registry_id : int = p_data[0] - var item_registry_data : Dictionary = p_data[1] - var item_registry_entries_data : Dictionary = item_registry_data[ItemRegistry._registry_key.ITEM_ENTRIES] - - # Convert the image bytes back into the image object: - for item_id : int in item_registry_entries_data: - var item_registry_entry_data : Dictionary = item_registry_entries_data[item_id] - if item_registry_entry_data.has(ItemRegistry._item_entry_key.ICON): - var bytes : PackedByteArray = item_registry_data[ItemRegistry._item_entry_key.ICON] - var image : Image = bytes_to_var_with_objects(bytes) - var texture : ImageTexture = ImageTexture.create_from_image(image) - item_registry_data[ItemRegistry._item_entry_key.ICON] = texture - - var item_registry : ItemRegistry = _m_remote_item_registry_cache[item_registry_id] - item_registry.set_data(item_registry_data) - return true - - "inventory_manager:item_registry_sync_metadata": - var item_registry_id : int = p_data[0] - var item_registry_metadata : Dictionary = p_data[1] - var item_registry : ItemRegistry = _m_remote_item_registry_cache[item_registry_id] - var item_registry_data : Dictionary = item_registry.get_data() - item_registry_data[ItemRegistry._registry_key.METADATA] = item_registry_metadata - return true - - "inventory_manager:register_inventory_manager": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_name : String = p_data[1] - var inventory_manager_path : String = p_data[2] - var item_registry_id : int = p_data[3] - - # Generate name - var target_name : String - if not inventory_manager_name.is_empty(): - target_name = inventory_manager_name - else: - if not inventory_manager_path.is_empty(): - target_name = inventory_manager_path.trim_prefix(inventory_manager_path.get_base_dir().path_join("/")) - else: - target_name = "Manager" - target_name = target_name + ":" + String.num_uint64(inventory_manager_id) - - # Create local copy of the InventoryManager - var item_registry : ItemRegistry = _m_remote_item_registry_cache[item_registry_id] - var inventory_manager : InventoryManager = InventoryManager.new(item_registry) - - # Create the associated tree_item and add it as metadata against the tree itself so that we can extract it easily when we receive messages from this specific InventoryManager instance id - var inventory_manager_tree_item : TreeItem = inventory_manager_viewer_manager_selection_tree_.create_item() - inventory_manager_tree_item.set_text(column, target_name) - inventory_manager_tree_item.set_metadata(column, inventory_manager) - - # Map the inventory manager instance id to its tree item -- we'll use this later - _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] = inventory_manager_tree_item - return true - - "inventory_manager:deregister_inventory_manager": - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - - # Select nothing on the inventory manager list if the currently selected inventory manager is the same we are deregistering: - var selected_tree_item : TreeItem = inventory_manager_viewer_manager_selection_tree_.get_selected() - if is_instance_valid(selected_tree_item): - if selected_tree_item == inventory_manager_tree_item: - # Clear the inventory manager selection - __on_inventory_manager_selection_tree_nothing_selected() - - # Clear the cache and free the TreeItem - var _success : bool = _m_remote_inventory_manager_to_its_tree_item_map.erase(inventory_manager_id) - inventory_manager_tree_item.free() - return true - - "inventory_manager:resize": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - var new_size : int = p_data[1] - var _ignore : Array[ExcessItems] = stored_inventory_manager.resize(new_size) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:set_data": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - var new_data : Dictionary = p_data[1] - stored_inventory_manager.set_data(new_data) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:resize": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Resize - var new_size : int = p_data[1] - var _ignore : Array[ExcessItems] = stored_inventory_manager.resize(new_size) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:add_items_to_slot": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Inject the remote item entry data: - var remote_item_slot_index : int = p_data[1] - var remote_item_id : int = p_data[2] - var remote_item_amount : int = p_data[3] - stored_inventory_manager.__allocate_if_needed(remote_item_slot_index) - var _ignore : int = stored_inventory_manager.__add_items_to_slot(remote_item_slot_index, remote_item_id, remote_item_amount) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:remove_items_from_slot": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Inject the remote item entry data: - var remote_item_slot_index : int = p_data[1] - var remote_item_id : int = p_data[2] - var remote_item_amount : int = p_data[3] - stored_inventory_manager.__allocate_if_needed(remote_item_slot_index) - var _ignore : int = stored_inventory_manager.__remove_items_from_slot(remote_item_slot_index, remote_item_id, remote_item_amount) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:clear": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Clear - stored_inventory_manager.clear() - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:swap": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Get the function parameters and execute the action: - var first_slot : int = p_data[1] - var second_slot : int = p_data[2] - stored_inventory_manager.swap(first_slot, second_slot) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - "inventory_manager:set_name": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var remote_name : String = p_data[1] - inventory_manager_tree_item.set_text(column, remote_name) - return true - - "inventory_manager:organize": - var column : int = 0 - var inventory_manager_id : int = p_data[0] - var inventory_manager_tree_item : TreeItem = _m_remote_inventory_manager_to_its_tree_item_map[inventory_manager_id] - var stored_inventory_manager : InventoryManager = inventory_manager_tree_item.get_metadata(column) - - # Get the function parameters and execute the action: - var item_ids_array : PackedInt64Array = p_data[1] - stored_inventory_manager.organize(item_ids_array) - - # Refresh the item entries if needed: - __refresh_item_slots_if_needed(stored_inventory_manager) - return true - - - push_warning("InventoryManagerViewer: This should not happen. Unmanaged capture: %s %s" % [p_message, p_data]) - return false -# ==== EDITOR DEBUGGER PLUGIN PASSTHROUGH FUNCTIONS ENDS ====== - - -# ===== VISUALIZATION FUNCTIONS BEGIN ==== -func __on_session_started() -> void: - # Clear caches - _m_remote_item_registry_cache.clear() - _m_remote_inventory_manager_to_its_tree_item_map.clear() - - # Clear the item manager tree - inventory_manager_viewer_manager_selection_tree_.clear() - var _root : TreeItem = inventory_manager_viewer_manager_selection_tree_.create_item() # need to recreate the root TreeItem which gets ignored - - # Clear the item entry tree view - inventory_manager_viewer_item_slots_tree_.clear() - inventory_manager_viewer_item_slots_view_warning_label_.set_text("Select an InventoryManager to display its item entries.") - inventory_manager_viewer_item_slots_view_warning_label_.show() - - # Clear the data view - inventory_manager_viewer_inventory_data_view_text_edit_.set_text("") - inventory_manager_viewer_inventory_data_view_warning_label_.set_text("Select a ItemSlot to display its data.") - inventory_manager_viewer_inventory_data_view_warning_label_.show() - -func __on_session_stopped() -> void: - if not is_instance_valid(inventory_manager_viewer_manager_selection_tree_.get_root()) or inventory_manager_viewer_manager_selection_tree_.get_root().get_child_count() == 0: - inventory_manager_viewer_item_slots_view_warning_label_.set_text(_m_original_inventory_entry_view_warning_text) - - -func __on_inventory_manager_selection_line_edit_text_changed(p_filter : String) -> void: - # Hide the TreeItem that don't match the filter - var root : TreeItem = inventory_manager_viewer_manager_selection_tree_.get_root() - var column : int = 0 - for child : TreeItem in root.get_children(): - if p_filter.is_empty() or p_filter in child.get_text(column): - child.set_visible(true) - else: - child.set_visible(false) - - # Select an item (if any): - inventory_manager_viewer_manager_selection_tree_.deselect_all() - var did_select_item : bool = false - for child : TreeItem in root.get_children(): - if child.is_visible(): - inventory_manager_viewer_manager_selection_tree_.set_selected(child, column) # emits item_selected signal - child.select(column) # highlights the item on the Tree - did_select_item = true - break - if not did_select_item: - __on_inventory_manager_selection_tree_nothing_selected() - - -func __on_inventory_manager_selection_tree_nothing_selected() -> void: - # Deselect - inventory_manager_viewer_manager_selection_tree_.deselect_all() - - # Clear the item view - inventory_manager_viewer_item_slots_tree_.clear() - inventory_manager_viewer_item_slots_view_warning_label_.set_text("Select a InventoryManager to display its item entries.") - inventory_manager_viewer_item_slots_view_warning_label_.show() - - # Clear the data view - inventory_manager_viewer_inventory_data_view_text_edit_.set_text("") - inventory_manager_viewer_inventory_data_view_warning_label_.set_text("Select a ItemSlot to display its data.") - inventory_manager_viewer_inventory_data_view_warning_label_.show() - - -func __refresh_item_slots_if_needed(p_updated_inventory_manager : InventoryManager) -> void: - var selected_tree_item : TreeItem = inventory_manager_viewer_manager_selection_tree_.get_selected() - if is_instance_valid(selected_tree_item): - var column : int = 0 - var stored_inventory_manager : InventoryManager = selected_tree_item.get_metadata(column) - if p_updated_inventory_manager == stored_inventory_manager: - __refresh_item_slots() - - -func __refresh_item_slots() -> void: - # Populate item entries - - # Update item view warning label: - if inventory_manager_viewer_item_slots_view_warning_label_.is_visible(): - inventory_manager_viewer_item_slots_view_warning_label_.hide() - - # Grab the selected tree item and item manager: - var inventory_manager_selected_tree_item : TreeItem = inventory_manager_viewer_manager_selection_tree_.get_selected() - var item_name_column : int = 0 - var inventory_manager : InventoryManager = inventory_manager_selected_tree_item.get_metadata(item_name_column) - - # Clear the item selection tree as well - var selected_item_slot_id : int = -1 # -1 is used as a sentinel value -- item IDs begin at 0 - if inventory_manager_viewer_item_slots_tree_.has_meta(&"item_slot_id_to_tree_item_map"): - var inventory_entry_selected_tree_item : TreeItem = inventory_manager_viewer_item_slots_tree_.get_selected() - if is_instance_valid(inventory_entry_selected_tree_item): - var previous_item_slot_id_to_tree_item_map : Dictionary = inventory_manager_viewer_item_slots_tree_.get_meta(&"item_slot_id_to_tree_item_map") - selected_item_slot_id = previous_item_slot_id_to_tree_item_map.find_key(inventory_entry_selected_tree_item) - inventory_manager_viewer_item_slots_tree_.clear() - var _root : TreeItem = inventory_manager_viewer_item_slots_tree_.create_item() - - # Traverse all item entries and add them to the tree: - var item_slot_id_to_tree_item_map : Dictionary = {} - var item_name_title_alignment : HorizontalAlignment = inventory_manager_viewer_item_slots_tree_.get_column_title_alignment(0) - var item_amount_title_alignment : HorizontalAlignment = inventory_manager_viewer_item_slots_tree_.get_column_title_alignment(1) - var item_amount_column : int = 1 - for slot_number : int in inventory_manager.slots(): - if inventory_manager.__is_slot_empty(slot_number): - continue - - # Create the associated tree item and configure it - var inventory_tree_item : TreeItem = inventory_manager_viewer_item_slots_tree_.create_item() - - var item_id : int = inventory_manager.__get_slot_item_id(slot_number) - var item_registry : ItemRegistry = inventory_manager.get_item_registry() - - # Install the item icon: - var texture : Texture2D = item_registry.get_icon(item_id) - if is_instance_valid(texture): - inventory_tree_item.set_icon(item_name_column, texture) - - - # Install the item tooltip: - var tooltip_string : String = "" - tooltip_string += "Slot: %d\n" % slot_number - tooltip_string += "Item ID: %d\n" % inventory_manager.__get_slot_item_id(slot_number) - var item_name : String = item_registry.get_name(item_id) - if item_name.is_empty(): - item_name = "(Empty Item Name)" - tooltip_string += "Name: %s\n" % item_name - var item_description : String = item_registry.get_description(item_id) - if item_description.is_empty(): - item_description = "(Empty Item Description)" - tooltip_string += "Description: %s\n" % item_description - tooltip_string += "Amount: %d\n" % inventory_manager.__get_slot_item_amount(slot_number) - tooltip_string += "Stack Size: %d\n" % item_registry.get_stack_capacity(item_id) - var amount : int = inventory_manager.__get_slot_item_amount(slot_number) - inventory_tree_item.set_text(item_name_column, item_name) - inventory_tree_item.set_text(item_amount_column, str(amount)) - inventory_tree_item.set_text_alignment(item_name_column, item_name_title_alignment) - inventory_tree_item.set_text_alignment(item_amount_column, item_amount_title_alignment) - inventory_tree_item.set_tooltip_text(item_name_column, tooltip_string.strip_edges(true, true)) - - # Store the item manager and item ID on its tree item so that we can retrieve its data easily later. - var inventory_tree_item_metadata : Array = [inventory_manager, slot_number] - inventory_tree_item.set_metadata(item_name_column, inventory_tree_item_metadata) - - # Also map the item id to their tree items - we need to to refresh the item data view if needed - item_slot_id_to_tree_item_map[slot_number] = inventory_tree_item - - # Store the item_slot_id_to_tree_item_map -- this will be needed the next time we refresh the item entries - if selected_item_slot_id >= 0: - if item_slot_id_to_tree_item_map.has(selected_item_slot_id): - var tree_item_to_select : TreeItem = item_slot_id_to_tree_item_map[selected_item_slot_id] - tree_item_to_select.select(item_name_column) - else: - __on_inventory_view_selection_nothing_selected() - - -func __on_inventory_manager_selection_tree_item_selected() -> void: - var selected_tree_item : TreeItem = inventory_manager_viewer_manager_selection_tree_.get_selected() - if is_instance_valid(selected_tree_item): - __refresh_item_slots() - - -func __on_inventory_view_selection_nothing_selected() -> void: - if inventory_manager_viewer_item_slots_tree_.get_selected_column() != -1: - # Deselect the item - inventory_manager_viewer_item_slots_tree_.deselect_all() - - # Clear the data view - inventory_manager_viewer_inventory_data_view_text_edit_.set_text("") - inventory_manager_viewer_inventory_data_view_warning_label_.set_text("Select a ItemSlot to display its data.") - inventory_manager_viewer_inventory_data_view_warning_label_.show() - - -func __on_inventory_view_selection_item_selected() -> void: - var selected_tree_item : TreeItem = inventory_manager_viewer_item_slots_tree_.get_selected() - if is_instance_valid(selected_tree_item): - if inventory_manager_viewer_inventory_data_view_warning_label_.is_visible(): - inventory_manager_viewer_inventory_data_view_warning_label_.hide() - - var column : int = 0 - var inventory_tree_item_metadata : Array = selected_tree_item.get_metadata(column) - var inventory_manager : InventoryManager = inventory_tree_item_metadata[0] - var slot_number : int = inventory_tree_item_metadata[1] - - - var item_id : int = inventory_manager.__get_slot_item_id(slot_number) - var item_registry : ItemRegistry = inventory_manager.get_item_registry() - - # Update the data view - var data_view : String = "" - data_view += "Slot: %d\n" % slot_number - data_view += "Item ID: %d\n" % inventory_manager.__get_slot_item_id(slot_number) - var item_name : String = item_registry.get_name(item_id) - if item_name.is_empty(): - item_name = "(Empty Item Name)" - data_view += "Name: %s\n" % item_name - var item_description : String = item_registry.get_description(item_id) - if item_description.is_empty(): - item_description = "(Empty Item Description)" - data_view += "Description: %s\n" % item_description - data_view += "Amount: %d\n" % inventory_manager.__get_slot_item_amount(slot_number) - data_view += "Stack Size: %d\n" % item_registry.get_stack_capacity(item_id) - if item_registry.has_item_metadata(item_id): - var item_metadata : Dictionary = item_registry.get_item_metadata_data(item_id) - data_view += "Item Metadata:\n%s\n" % JSON.stringify(item_metadata, "\t") - - inventory_manager_viewer_inventory_data_view_text_edit_.set_text(data_view.strip_edges(true,true)) -# ===== VISUALIZATION FUNCTIONS END ==== diff --git a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd.uid b/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd.uid deleted file mode 100644 index 5dc821c..0000000 --- a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://3iav56glredn diff --git a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.tscn b/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.tscn deleted file mode 100644 index 0cfa5b7..0000000 --- a/godot/addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.tscn +++ /dev/null @@ -1,94 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://c7icg0tbtwioq"] - -[ext_resource type="Script" path="res://addons/rubonnek.inventory_manager/debugger/inventory_manager_viewer.gd" id="1_tvtkg"] - -[node name="InventoryManager" type="PanelContainer" node_paths=PackedStringArray("inventory_manager_viewer_manager_selection_line_edit_", "inventory_manager_viewer_manager_selection_tree_", "inventory_manager_viewer_item_slots_tree_", "inventory_manager_viewer_item_slots_view_warning_label_", "inventory_manager_viewer_inventory_data_view_text_edit_", "inventory_manager_viewer_inventory_data_view_warning_label_")] -custom_minimum_size = Vector2(0, 240) -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1_tvtkg") -inventory_manager_viewer_manager_selection_line_edit_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerManagerSelectionVBoxContainer/InventoryManagerViewerEngineSelectionLineEdit") -inventory_manager_viewer_manager_selection_tree_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerManagerSelectionVBoxContainer/InventoryManagerViewerEngineSelectionTree") -inventory_manager_viewer_item_slots_tree_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsVBoxContainer/InventoryManagerViewerItemSlotsTree") -inventory_manager_viewer_item_slots_view_warning_label_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsVBoxContainer/InventoryManagerViewerItemSlotsTree/InventoryManagerViewerItemSlotsViewWarningLabel") -inventory_manager_viewer_inventory_data_view_text_edit_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsViewTabContainer/Slot Data/InventoryManagerViewerInventoryDataViewTextEditLabel") -inventory_manager_viewer_inventory_data_view_warning_label_ = NodePath("InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsViewTabContainer/Slot Data/InventoryManagerViewerInventoryDataViewTextEditLabel/InventoryManagerViewerInventoryDataViewWarningLabel") - -[node name="InventoryManagerViewerHSplitContainer" type="HSplitContainer" parent="."] -layout_mode = 2 - -[node name="InventoryManagerViewerManagerSelectionVBoxContainer" type="VBoxContainer" parent="InventoryManagerViewerHSplitContainer"] -layout_mode = 2 - -[node name="InventoryManagerViewerEngineSelectionLineEdit" type="LineEdit" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerManagerSelectionVBoxContainer"] -custom_minimum_size = Vector2(150, 0) -layout_mode = 2 -placeholder_text = "Filter Managers" - -[node name="InventoryManagerViewerEngineSelectionTree" type="Tree" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerManagerSelectionVBoxContainer"] -custom_minimum_size = Vector2(120, 0) -layout_mode = 2 -size_flags_vertical = 3 -hide_root = true - -[node name="InventoryManagerViewerHSplitContainer" type="HSplitContainer" parent="InventoryManagerViewerHSplitContainer"] -layout_mode = 2 - -[node name="InventoryManagerViewerItemSlotsVBoxContainer" type="VBoxContainer" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="InventoryManagerViewerItemSlotsLabel" type="Label" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsVBoxContainer"] -layout_mode = 2 -text = "Inventory Slots" -horizontal_alignment = 1 - -[node name="InventoryManagerViewerItemSlotsTree" type="Tree" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsVBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 -columns = 2 -column_titles_visible = true -hide_root = true -select_mode = 1 - -[node name="InventoryManagerViewerItemSlotsViewWarningLabel" type="Label" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsVBoxContainer/InventoryManagerViewerItemSlotsTree"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -text = "Run project to select an InventoryManager." -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="InventoryManagerViewerItemSlotsViewTabContainer" type="TabContainer" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Slot Data" type="VBoxContainer" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsViewTabContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="InventoryManagerViewerInventoryDataViewTextEditLabel" type="TextEdit" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsViewTabContainer/Slot Data"] -layout_mode = 2 -size_flags_vertical = 3 -editable = false -deselect_on_focus_loss_enabled = false -drag_and_drop_selection_enabled = false -virtual_keyboard_enabled = false -middle_mouse_paste_enabled = false - -[node name="InventoryManagerViewerInventoryDataViewWarningLabel" type="Label" parent="InventoryManagerViewerHSplitContainer/InventoryManagerViewerHSplitContainer/InventoryManagerViewerItemSlotsViewTabContainer/Slot Data/InventoryManagerViewerInventoryDataViewTextEditLabel"] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -text = "Run project to select a ItemSlot" -horizontal_alignment = 1 -vertical_alignment = 1 diff --git a/godot/addons/rubonnek.inventory_manager/plugin.cfg b/godot/addons/rubonnek.inventory_manager/plugin.cfg deleted file mode 100644 index c7c6102..0000000 --- a/godot/addons/rubonnek.inventory_manager/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Inventory Manager Viewer" -description="Inventory Manager Viewer" -author="Wilson Enrique Alvarez Torres" -version="1.2.1" -script="plugin.gd" diff --git a/godot/addons/rubonnek.inventory_manager/plugin.gd b/godot/addons/rubonnek.inventory_manager/plugin.gd deleted file mode 100644 index 505f8c5..0000000 --- a/godot/addons/rubonnek.inventory_manager/plugin.gd +++ /dev/null @@ -1,26 +0,0 @@ -@tool -extends EditorPlugin - -@warning_ignore("unsafe_cast") -var m_editor_debugger_plugin : EditorDebuggerPlugin = (load((get_script() as Resource).get_path().get_base_dir().path_join("debugger/editor_debugger_plugin.gd")) as GDScript).new() - - -func _has_main_screen() -> bool: - return false - - -func _get_plugin_name() -> String: - return "InventoryManagerDebugger" - - -func _disable_plugin() -> void: - remove_debugger_plugin(m_editor_debugger_plugin) - - -func _enter_tree() -> void: - @warning_ignore("unsafe_method_access") - add_debugger_plugin(m_editor_debugger_plugin) - - -func _exit_tree() -> void: - remove_debugger_plugin(m_editor_debugger_plugin) diff --git a/godot/addons/rubonnek.inventory_manager/plugin.gd.uid b/godot/addons/rubonnek.inventory_manager/plugin.gd.uid deleted file mode 100644 index c800ecb..0000000 --- a/godot/addons/rubonnek.inventory_manager/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bpvw8ti6aebgg diff --git a/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd b/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd deleted file mode 100644 index 0c605c1..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd +++ /dev/null @@ -1,81 +0,0 @@ -#============================================================================ -# excess_items.gd | -#============================================================================ -# This file is part of: | -# INVENTORY MANAGER | -# https://github.com/Rubonnek/inventory-manager | -#============================================================================ -# Copyright (c) 2024-2025 Wilson Enrique Alvarez Torres | -# | -# Permission is hereby granted, free of charge, to any person obtaining | -# a copy of this software and associated documentation files (the | -# "Software"), to deal in the Software without restriction, including | -# without limitation the rights to use, copy, modify, merge, publish, | -# distribute, sublicense, andor sell copies of the Software, and to | -# permit persons to whom the Software is furnished to do so, subject to | -# the following conditions: | -# | -# The above copyright notice and this permission notice shall be | -# included in all copies or substantial portions of the Software. | -# | -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | -#============================================================================ - -extends RefCounted -class_name ExcessItems -## Represents the amount of items not added to, or not removed from, an inventory. -## -## The item amount is always positive and not clamped. - -var _m_item_registry : ItemRegistry -var _m_item_slot_data : PackedInt64Array - - -## Returns the item ID. -func get_item_id() -> int: - return _m_item_slot_data[0] - - -## Sets the item_amount. -func set_amount(p_amount : int) -> void: - _m_item_slot_data[1] = p_amount - - -## Returns the item amount. -func get_amount() -> int: - return _m_item_slot_data[1] - - -## Returns the associated [ItemRegistry]. -func get_registry() -> ItemRegistry: - return _m_item_registry - - -## Returns the item name from its associated [ItemRegistry]. -func get_name() -> String: - return get_registry().get_name(get_item_id()) - - -## Returns the item description from its associated [ItemRegistry]. -func get_description() -> String: - return get_registry().get_description(get_item_id()) - - -## Returns the item icon from its associated [ItemRegistry]. -func get_icon() -> Texture2D: - return get_registry().get_icon(get_item_id()) - - -func _to_string() -> String: - return " Item ID: %d, Name: \"%s\", Amount: %d" % [get_instance_id(), get_item_id(), get_name(), get_amount()] - - -func _init(p_item_registry : ItemRegistry, p_item_slot_data : PackedInt64Array) -> void: - _m_item_registry = p_item_registry - _m_item_slot_data = p_item_slot_data diff --git a/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd.uid b/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd.uid deleted file mode 100644 index 3f59355..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/excess_items.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cc2vsn3kn48uq diff --git a/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd b/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd deleted file mode 100644 index 2f58f4b..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd +++ /dev/null @@ -1,1161 +0,0 @@ -#============================================================================ -# inventory_manager.gd | -#============================================================================ -# This file is part of: | -# INVENTORY MANAGER | -# https://github.com/Rubonnek/inventory-manager | -#============================================================================ -# Copyright (c) 2024-2025 Wilson Enrique Alvarez Torres | -# | -# Permission is hereby granted, free of charge, to any person obtaining | -# a copy of this software and associated documentation files (the | -# "Software"), to deal in the Software without restriction, including | -# without limitation the rights to use, copy, modify, merge, publish, | -# distribute, sublicense, andor sell copies of the Software, and to | -# permit persons to whom the Software is furnished to do so, subject to | -# the following conditions: | -# | -# The above copyright notice and this permission notice shall be | -# included in all copies or substantial portions of the Software. | -# | -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | -#============================================================================ - -extends RefCounted -class_name InventoryManager -## Holds a list of items and their amount. -## -## Holds a list of item IDs and their amount and provides methods for adding, removing, transfering, etc, these items by their slots. - -# Design choices: -# * Item slots do not hold any data other than the item ID and their amount. Item name, description, price, etc, are optional. -# * Whenever possible, avoid explicit use of range() to avoid creating an array with all the indices we need to loop over. Avoiding the array creation is way faster for inventories of infinite size. For this reason, under some specific circumstances two loops with the same operations but slightly modified indexes are used. -# * Before extracting data from the item slots array, the indices must be validated and allocated in memory. - -var _m_inventory_manager_dictionary : Dictionary -var _m_item_slots_packed_array : PackedInt64Array -var _m_item_stack_count_tracker : Dictionary -var _m_item_total_tracker : Dictionary -var _m_item_slots_tracker : Dictionary -var _m_item_registry : ItemRegistry - - -## Emitted when an item fills an empty slot. -signal item_added(p_slot_index : int, p_item_id : int) - -## Emitted when an item slot is modified. -signal slot_modified(p_slot_index : int) - -## Emitted when a slot is emptied and the item is removed. -signal item_removed(p_slot_index : int, p_item_id : int) - -## Emitted when the inventory is cleared. -signal inventory_cleared() - -enum _key { - ITEM_ENTRIES, - SIZE, -} - -const _DEFAULT_SIZE : int = 200 -const INFINITE_SIZE : int = -1 -const _INT64_MAX : int = 2 ** 63 - 1 - - -## Adds the specified item amount to the inventory.[br] -## When [code]p_start_slot_number[/code] is specified and it is possible to create more stacks for the specified item, the manager will attempt to add items at the specified slot or at any higher slot if needed, also looping around to the beginning of the inventory when necessary as well.[br][br] -## When [code]p_partial_add[/code] is true (default), if the amount exceeds what can be added to the inventory and there is still some capacity for the item, the remaining item amount not added to the inventory will be returned as an [ExcessItems].[br][br] -## When [code]p_partial_add[/code] is false, if the amount exceeds what can be added to the inventory, the item amount will not be added at all to the inventory and will be returned as an [ExcessItems]. -func add(p_item_id : int, p_amount : int, p_start_slot_number : int = -1, p_partial_add : bool = true) -> ExcessItems: - if p_item_id < 0: - push_warning("InventoryManager: Attempted to add an item with invalid item ID (%d). Ignoring call. The item ID must be equal or greater than zero." % p_item_id) - return null - if p_amount == 0: - return null - if p_amount < 0: - push_warning("InventoryManager: Attempted to add an item with negative amount. Ignoring call. The amount must be positive.") - return null - var inventory_size : int = size() - if p_start_slot_number != -1 and not is_slot_valid(p_start_slot_number): - push_warning("InventoryManager: Attempted to add item ID (%d) with an invalid start index (%d). Forcing start index to -1." % [p_item_id, p_start_slot_number]) - p_start_slot_number = -1 - - if not p_partial_add: - if p_amount > get_remaining_capacity_for_item(p_item_id): - return __create_excess_items(p_item_id, p_amount) - - var registered_stack_count : int = _m_item_registry.get_stack_count(p_item_id) - var is_stack_count_limited : bool = _m_item_registry.is_stack_count_limited(p_item_id) - if p_start_slot_number < 0: - # Then a start index was not passed. - # First fill all the slots with available stack space while skipping empty slots - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker.get(p_item_id, PackedInt64Array()) - for slot_number : int in item_id_slots_array: - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - return null - if is_stack_count_limited: - # We've stumbled upon the maximum number of stacks and added items to all of them. No more items can be added. - return __create_excess_items(p_item_id, p_amount) - - # We still have some more item amount to add. We'll need to create the item slots for these. - var current_stack_count : int = _m_item_stack_count_tracker.get(p_item_id, 0) - if is_infinite(): - # Add items to empty slots either until we hit the stack count limit or the amount of items remainind to add reaches 0. - var slot_number : int = 0 - while true: - # Increase the inventory size if needed - if not __is_slot_allocated(slot_number): - __increase_size(slot_number) - - if __is_slot_empty(slot_number): - # Add item: - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - # We are done adding items. There's no excess. - return null - - # Update the stack count - current_stack_count += 1 - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # We can't add any more of this item. Return the excess items. - return __create_excess_items(p_item_id, p_amount) - slot_number += 1 - if slot_number < 0: - push_warning("InventoryManager: Detected integer overflow in add(). Exiting loop.") - return __create_excess_items(p_item_id, p_amount) - else: # Inventory size is limited. - # Add items to empty slots either until we hit the stack count limit or the amount of items remaining to add reaches 0. - for slot_number : int in inventory_size: - # Increase the inventory size if needed - if not __is_slot_allocated(slot_number): - __increase_size(slot_number) - - if __is_slot_empty(slot_number): - # Add item: - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - - if p_amount == 0: - # We are done adding items. There's no excess. - return null - - # Check if we've reached to all the stacks we can add: - current_stack_count += 1 - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # Couldn't add all the items to the inventory. Return the excess items. - return __create_excess_items(p_item_id, p_amount) - return __create_excess_items(p_item_id, p_amount) - else: - # If the current stack capacity is greater or equal to the registered size, no more stacks can be added. - var current_stack_count : int = _m_item_stack_count_tracker.get(p_item_id, 0) - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # No more stacks can be added. We can only add items to the current stacks - # Let's do so: - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker.get(p_item_id, PackedInt64Array()) - for slot_number : int in item_id_slots_array: - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - return null - # Couldn't add all the items to the inventory. Return the excess items. - return __create_excess_items(p_item_id, p_amount) - - # We can add more stacks to the inventory. Let's do so. - if is_infinite(): - var slot_number : int = p_start_slot_number - while true: - # Increase the inventory size if needed - if not __is_slot_allocated(slot_number): - __increase_size(slot_number) - - if __is_slot_empty(slot_number) and (not is_stack_count_limited or current_stack_count < registered_stack_count): - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - current_stack_count += 1 - elif __get_slot_item_id(slot_number) == p_item_id: - # NOTE: We don't count this stack since it already has been accounted for - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - # There's nothing else to add. - return null - slot_number += 1 - if slot_number < 0: - push_warning("InventoryManager: Detected integer overflow. Exiting loop.") - break - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # Cannot add any more items. - break - - # It may be possible to add some more items. Go over all the current stacks and attempt to add more items: - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker.get(p_item_id, PackedInt64Array()) - for slot_number_loop_around : int in item_id_slots_array: - p_amount = __add_items_to_slot(slot_number_loop_around, p_item_id, p_amount) - if p_amount == 0: - return null - # Couldn't add all the items to the inventory. Return the excess items. - return __create_excess_items(p_item_id, p_amount) - else: # the inventory size is limited, but it's possible we can add more stacks - for slot_number : int in inventory_size - p_start_slot_number: - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # Cannot add any more items. We may need to either loop around the remaining items or return the excess items. - break - # Increase the inventory size if needed - if not __is_slot_allocated(slot_number + p_start_slot_number): - __increase_size(slot_number + p_start_slot_number) - if __is_slot_empty(slot_number + p_start_slot_number) and (not is_stack_count_limited or current_stack_count < registered_stack_count): - p_amount = __add_items_to_slot(slot_number + p_start_slot_number, p_item_id, p_amount) - current_stack_count += 1 - elif __get_slot_item_id(slot_number + p_start_slot_number) == p_item_id: - # NOTE: We don't count this stack since it already has been accounted for - p_amount = __add_items_to_slot(slot_number + p_start_slot_number, p_item_id, p_amount) - if p_amount == 0: - # There's nothing else to add. - return null - if is_stack_count_limited and current_stack_count >= registered_stack_count: - # Couldn't add all the items to the inventory. There are still more items to add. - break - if p_start_slot_number != 0: - # Loop around the remaining slots. - for slot_number : int in p_start_slot_number: - if __is_slot_empty(slot_number) and (not is_stack_count_limited or current_stack_count < registered_stack_count): - current_stack_count += 1 - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - elif __get_slot_item_id(slot_number) == p_item_id: - p_amount = __add_items_to_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - # There's nothing else to add. - return null - # We've looped through the remaining slots and not all items could be added. Return the excess items. - return __create_excess_items(p_item_id, p_amount) - # Could not add some items to the inventory. Return those. - return __create_excess_items(p_item_id, p_amount) - - -## Removes the specified item amount to the inventory.[br] -## When [code]p_start_slot_number[/code] is specified, the manager will attempt to remove items from the specified slot or at any higher slot if needed, also looping around to the beginning of the inventory when necessary as well.[br][br] -## When [code]p_partial_add[/code] is true (default), if the amount exceeds what can be removed from the inventory and there are still some items in the inventory, the remaining item amount within the inventory will be removed and the non-removed items will be returned as an [ExcessItems].[br][br] -## When [code]p_partial_add[/code] is false, if the amount exceeds what can be removed from the inventory, the item amount will not be removed at all from the inventory and instead will be returned as an [ExcessItems]. -func remove(p_item_id : int, p_amount : int, p_start_slot_number : int = -1, p_partial_removal : bool = true) -> ExcessItems: - if not _m_item_registry.has_item(p_item_id): - push_warning("InventoryManager: Adding unregistered item with id (%d) to the inventory. The default stack capacity and max stacks values will be used. Register item ID within the item registry before adding item to the inventory to silence this message." % p_item_id) - if p_amount == 0: - return null - if p_amount < 0: - push_warning("InventoryManager: Attempted to remove item ID (%d) with a negative amount (%d). Ignoring call." % [p_item_id, p_amount]) - return null - if p_start_slot_number != -1 and not is_slot_valid(p_start_slot_number): - push_warning("InventoryManager: Attempted to add item ID (%d) with an invalid start index (%d). Forcing start index to -1." % [p_item_id, p_start_slot_number]) - p_start_slot_number = -1 - - if not p_partial_removal: - if p_amount > get_remaining_capacity_for_item(p_item_id): - return __create_excess_items(p_item_id, p_amount) - - if p_start_slot_number < 0: - # A start index was not given. We can start removing items from all the slots. - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - # Nothing to remove here - continue - if __get_slot_item_id(slot_number) == p_item_id: - p_amount = __remove_items_from_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - # We are done removing items. There's nothing more to remove. - return null - return __create_excess_items(p_item_id, p_amount) - else: - # A start index was given. We can start removing items from all the slots, starting from there. - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - # Nothing to remove here - continue - if __get_slot_item_id(slot_number) == p_item_id: - p_amount = __remove_items_from_slot(slot_number, p_item_id, p_amount) - if p_amount == 0: - # There's nothing else to remove. - return null - if p_start_slot_number != 0: - # Loop around the remaining slots. See implementation note above. - for slot_number_loop_around : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - p_start_slot_number: - if __is_slot_empty(slot_number_loop_around): - # Nothing to remove here - continue - if __get_slot_item_id(slot_number_loop_around) == p_item_id: - p_amount = __remove_items_from_slot(slot_number_loop_around, p_item_id, p_amount) - if p_amount == 0: - # There's nothing else to remove. - return null - return __create_excess_items(p_item_id, p_amount) - - -## Adds items to the specified slot number. Returns the number of items not added to the slot. -func add_items_to_slot(p_slot_index : int, p_item_id : int, p_amount : int) -> int: - if not is_slot_valid(p_slot_index): - push_warning("InventoryManager: Attempted to add an item to invalid slot '%d'. Ignoring call." % [p_slot_index]) - return p_amount - if not __is_slot_allocated(p_slot_index): - __increase_size(p_slot_index) - var was_slot_empty : int = __is_slot_empty(p_slot_index) - if not was_slot_empty: - var slot_item_id : int = __get_slot_item_id(p_slot_index) - if p_item_id != slot_item_id: - push_warning("InventoryManager: attempted to add an item to slot '%d' with ID '%d'. Expected ID '%d'. Ignoring call." % [p_slot_index, p_item_id, slot_item_id]) - return p_amount - if p_amount < 0: - push_warning("InventoryManager: add amount must be positive. Ignoring.") - return p_amount - elif p_amount == 0: - # There's nothing to do. - return p_amount - - # Processed the item addition to the slot - return __add_items_to_slot(p_slot_index, p_item_id, p_amount) - -## Removes items from the specified slot number. Returns the number of items not removed from the slot. -func remove_items_from_slot(p_slot_index : int, p_item_id : int, p_amount : int) -> int: - if not is_slot_valid(p_slot_index): - push_warning("InventoryManager: attempted to remove items on an invalid slot number '%d'. Ignoring." % p_slot_index) - return p_amount - if __is_slot_empty(p_slot_index): - push_warning("InventoryManager: attempted to remove an amount an empty item slot '%d'. Ignoring." % p_slot_index) - return p_amount - if p_item_id < 0: - push_warning("InventoryManager: attempted to remove an amount an invanlid item ID '%d'. Ignoring." % p_item_id) - return p_amount - if p_amount < 0: - push_warning("InventoryManager: remove amount must be positive. Ignoring.") - return p_amount - elif p_amount == 0: - # There's nothing to do. - return p_amount - var item_id : int = __get_slot_item_id(p_slot_index) - if item_id != p_item_id: - push_warning("InventoryManager: attempted to remove an item with ID '%d'. Expected '%d'. Ignoring call." % [p_item_id, item_id]) - return p_amount - return __remove_items_from_slot(p_slot_index, p_item_id, p_amount) - - -## Swaps the items from the specified slots. -func swap(p_first_slot_number : int, p_second_slot_number : int) -> void: - if not is_slot_valid(p_first_slot_number): - push_warning("InventoryManager: Attempted to swap an item to invalid slot '%d'. Ignoring call." % [p_first_slot_number]) - return - if not is_slot_valid(p_second_slot_number): - push_warning("InventoryManager: Attempted to swap an item to invalid slot '%d'. Ignoring call." % [p_second_slot_number]) - return - - # Increase inventory size if needed - var max_slot_number : int = maxi(p_first_slot_number, p_second_slot_number) - if not __is_slot_allocated(max_slot_number): - __increase_size(max_slot_number) - - if is_slot_empty(p_first_slot_number) and is_slot_empty(p_second_slot_number): - # There's nothing to do - return - - elif not is_slot_empty(p_first_slot_number) and is_slot_empty(p_second_slot_number): - # Get data - var first_slot_item_id : int = __get_slot_item_id(p_first_slot_number) - var first_slot_item_amount : int = __get_slot_item_amount(p_first_slot_number) - - # Calculate target indexes - var second_slot_item_id_index : int = __calculate_slot_item_id_index(p_second_slot_number) - var second_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_second_slot_number) - - # Inject data - _m_item_slots_packed_array[second_slot_item_id_index] = first_slot_item_id - _m_item_slots_packed_array[second_slot_item_amount_index] = first_slot_item_amount - - # Update item id slot tracker - __remove_item_id_slot_from_tracker(first_slot_item_id, p_first_slot_number) - __add_item_id_slot_to_tracker(first_slot_item_id, p_second_slot_number) - - # Clear - var first_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_first_slot_number) - _m_item_slots_packed_array[first_slot_item_amount_index] = 0 - elif is_slot_empty(p_first_slot_number) and not is_slot_empty(p_second_slot_number): - # Get data - var second_slot_item_id : int = __get_slot_item_id(p_second_slot_number) - var second_slot_item_amount : int = __get_slot_item_amount(p_second_slot_number) - - # Calculate target indexes - var first_slot_item_id_index : int = __calculate_slot_item_id_index(p_first_slot_number) - var first_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_first_slot_number) - - # Inject data - _m_item_slots_packed_array[first_slot_item_id_index] = second_slot_item_id - _m_item_slots_packed_array[first_slot_item_amount_index] = second_slot_item_amount - - # Update item id slot tracker - __remove_item_id_slot_from_tracker(second_slot_item_id, p_second_slot_number) - __add_item_id_slot_to_tracker(second_slot_item_id, p_first_slot_number) - - # Clear - var second_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_second_slot_number) - _m_item_slots_packed_array[second_slot_item_amount_index] = 0 - elif not is_slot_empty(p_second_slot_number) and not is_slot_empty(p_first_slot_number): - # Get data - var first_slot_item_id : int = __get_slot_item_id(p_first_slot_number) - var first_slot_item_amount : int = __get_slot_item_amount(p_first_slot_number) - var second_slot_item_id : int = __get_slot_item_id(p_second_slot_number) - var second_slot_item_amount : int = __get_slot_item_amount(p_second_slot_number) - - # Calculate target indexes - var first_slot_item_id_index : int = __calculate_slot_item_id_index(p_first_slot_number) - var first_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_first_slot_number) - var second_slot_item_id_index : int = __calculate_slot_item_id_index(p_second_slot_number) - var second_slot_item_amount_index : int = __calculate_slot_item_amount_index(p_second_slot_number) - - # Inject data - _m_item_slots_packed_array[first_slot_item_id_index] = second_slot_item_id - _m_item_slots_packed_array[first_slot_item_amount_index] = second_slot_item_amount - _m_item_slots_packed_array[second_slot_item_id_index] = first_slot_item_id - _m_item_slots_packed_array[second_slot_item_amount_index] = first_slot_item_amount - - # Update item id slot tracker - __remove_item_id_slot_from_tracker(first_slot_item_id, p_first_slot_number) - __add_item_id_slot_to_tracker(first_slot_item_id, p_second_slot_number) - __remove_item_id_slot_from_tracker(second_slot_item_id, p_second_slot_number) - __add_item_id_slot_to_tracker(second_slot_item_id, p_first_slot_number) - - slot_modified.emit(p_first_slot_number) - slot_modified.emit(p_second_slot_number) - - # Sync change with the debugger: - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:swap", [get_instance_id(), p_first_slot_number, p_second_slot_number]) - - -## Transfers items from first specified slot to the second specified slot. -func transfer(p_first_slot_number : int, p_first_amount : int, p_second_slot_number : int) -> void: - if not is_slot_valid(p_first_slot_number): - push_warning("InventoryManager: Attempted to transfer an item from invalid slot '%d'. Ignoring call." % [p_first_slot_number]) - return - if not is_slot_valid(p_second_slot_number): - push_warning("InventoryManager: Attempted to transfer an item to invalid slot '%d'. Ignoring call." % [p_second_slot_number]) - return - if p_first_amount < 0: - push_warning("InventoryManager: Attempted to transfer an item from slot '%d' with invalid slot with negative amount '%d'. Ignoring call." % [p_first_slot_number, p_first_amount]) - return - if __is_slot_empty(p_first_slot_number): - # There's nothing to do - return - # Increase inventory size if needed - var max_slot_number : int = maxi(p_first_slot_number, p_second_slot_number) - if not __is_slot_allocated(max_slot_number): - __increase_size(max_slot_number) - - # Get IDs - var first_item_id : int = __get_slot_item_id(p_first_slot_number) - var second_item_id : int = __get_slot_item_id(p_second_slot_number) - - # Check if it's possible to transfer: - if first_item_id == second_item_id or second_item_id < 0: - # Then it's possible to transfer. Check for amounts. - var first_slot_item_amount : int = __get_slot_item_amount(p_first_slot_number) - var target_amount : int = clampi(p_first_amount, 0, first_slot_item_amount) - if target_amount != first_slot_item_amount: - var current_stack_count : int = _m_item_stack_count_tracker[first_item_id] - var max_stack_count : int = _m_item_registry.get_stack_count(first_item_id) - var is_stack_count_limited : bool = _m_item_registry.is_stack_count_limited(first_item_id) - if is_stack_count_limited and current_stack_count + 1 > max_stack_count: - push_warning("InventoryManager: Attempted partial item amount transfer on item id (%d) from slot '%d' to slot '%d' but this transfer violates the item's maximum stack count (%d). After the transfer the stack count would have been %d. Ignoring call." % [first_item_id, p_first_slot_number, p_second_slot_number, max_stack_count, current_stack_count + 1]) - return - var _ignore : int = __remove_items_from_slot(p_first_slot_number, first_item_id, target_amount) - _ignore = __add_items_to_slot(p_second_slot_number, first_item_id, target_amount) - else: - push_warning("InventoryManager: Attempted to transfer an item id (%d) from slot '%d' to slot '%d' with mismatching IDs. Ignoring call." % [first_item_id, p_first_slot_number, p_second_slot_number]) - return - - -## Reserves memory up to the desired number of slots in memory as long as the inventory size allows. Returns OK when successful. -func reserve(p_number_of_slots : int = -1) -> Error: - var allocated_slots : int = __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - if p_number_of_slots <= allocated_slots: - return OK - var max_size_limit : int = 0 - var inventory_size : int = size() - if is_infinite(): - max_size_limit = _INT64_MAX - else: - max_size_limit = inventory_size - p_number_of_slots = clampi(p_number_of_slots, 0, max_size_limit) - var max_slot_index : int = p_number_of_slots - 1 - var array_size : int = __calculate_array_size_needed_to_access_slot_index(max_slot_index) - var error : int = _m_item_slots_packed_array.resize(array_size) - if error != OK: - push_warning("InventoryManager: could not properly preallocate the array") - return error as Error - return OK - - -## Returns the item ID for the given item slot. Returns -1 on invalid slots. -func get_slot_item_id(p_slot_index : int) -> int: - if not is_slot_valid(p_slot_index): - push_warning("InventoryManager: Invalid slot (%d) passed to get_slot_item_id()." % p_slot_index) - return -1 - if not __is_slot_allocated(p_slot_index): - return -1 - var item_id : int = __get_slot_item_id(p_slot_index) - return item_id - - -## Returns the item amount for the given item slot. Returns 0 on empty or invalid slots. -func get_slot_item_amount(p_slot_index : int) -> int: - if not is_slot_valid(p_slot_index): - push_warning("InventoryManager: Invalid slot (%d) passed to get_slot_item_amount()." % p_slot_index) - return 0 - if not __is_slot_allocated(p_slot_index): - return 0 - var amount : int = __get_slot_item_amount(p_slot_index) - return amount - - -## Returns true when the item slot is is empty. Returns false otherwise. Checking if the slot is empty does not mean it is valid or reachable if the inventory is strictly sized. -func is_slot_empty(p_slot_index : int) -> bool: - if not is_slot_valid(p_slot_index): - push_warning("InventoryManager: Invalid slot (%d) passed to is_slot_empty()." % p_slot_index) - return false - if not __is_slot_allocated(p_slot_index): - return true - var slot_item_amount : int = __get_slot_item_amount(p_slot_index) - return slot_item_amount <= 0 - -## Returns true if the slot index is valid. -func is_slot_valid(p_slot_index : int) -> bool: - if p_slot_index < 0: - return false - var inventory_size : int = size() - if is_infinite(): - return true - return p_slot_index < inventory_size - - -## Returns the remaining amount of items the specified slot can hold. Returns -1 on an invalid slot number. -func get_remaining_slot_capacity(p_slot_index : int) -> int: - if not is_slot_valid(p_slot_index): - return -1 - var remaining_capacity : int = __get_remaining_slot_capacity(p_slot_index) - return remaining_capacity - - -## Returns true when the inventory is empty. Returns false otherwise. -func is_empty() -> bool: - return _m_item_slots_packed_array.is_empty() - - -## Returns the total sum of the specified item across all stacks within the inventory. -func get_item_total(p_item_id : int) -> int: - return _m_item_total_tracker.get(p_item_id, 0) - - -## Returns true if the inventory holds at least the specified amount of the item in question. -func has_item_amount(p_item_id : int, p_amount : int) -> bool: - var item_total : int = get_item_total(p_item_id) - return p_amount <= item_total - - -## Returns true when one item with the specified item ID is found within the inventory. Returns false otherwise. -func has_item(p_item_id : int) -> bool: - return p_item_id in _m_item_slots_tracker - - -## Changes the inventory size and returns an array of excess items after the specified slot number if any are found.[br][br] -## When the size is set to [code]InventoryManager.INFINITE_SIZE[/code], the inventory size is not increased in memory but increased upon demand. If slot preallocation is required for its performance benefit, use [method reserve]. -func resize(p_new_slot_count : int) -> Array[ExcessItems]: - var excess_items_array : Array[ExcessItems] = [] - if p_new_slot_count != INFINITE_SIZE and p_new_slot_count < 0: - push_warning("InventoryManager: Invalid new inventory size detected (%d). The new size should be greater or equal to zero. Ignoring." % p_new_slot_count) - return excess_items_array - - if p_new_slot_count != INFINITE_SIZE: - # The inventory is currently of finite size. We need to extract the excess items that can be found after the new size (if any) - var available_slots : int = __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - if p_new_slot_count < available_slots: - for slot_number : int in available_slots - p_new_slot_count: - if __is_slot_empty(slot_number + p_new_slot_count): - continue - - # The slot is not empty. This slot is now an excess items object: - var item_id : int = __get_slot_item_id(slot_number + p_new_slot_count) - var item_amount : int = __get_slot_item_amount(slot_number + p_new_slot_count) - var excess_items : ExcessItems = __create_excess_items(item_id, item_amount) - excess_items_array.push_back(excess_items) - - # And remove those from the inventory to update the internal counters: - var _result_is_zero : int = __remove_items_from_slot(slot_number, item_id, item_amount) - - # Resize the slots data: - var last_slot_index : int = p_new_slot_count - 1 - var new_array_size : int = __calculate_array_size_needed_to_access_slot_index(last_slot_index) - var _error : int = _m_item_slots_packed_array.resize(new_array_size) - if _error != OK: - push_warning("InventoryManager: unable to resize slots array to the desired size.") - - # Track the new size: - __set_size(p_new_slot_count) - - # Synchronize change with the debugger: - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:resize", [get_instance_id(), p_new_slot_count]) - return excess_items_array - - -# Adds items to the specified slot number. Returns the number of items not added to the slot. -# NOTE: The slot number is assumed to be within bounds in this function. -func __add_items_to_slot(p_slot_index : int, p_item_id : int, p_amount : int) -> int: - var was_slot_empty : int = __is_slot_empty(p_slot_index) - if was_slot_empty: - # The slot was empty. Inject the item id. - var item_id_index : int = __calculate_slot_item_id_index(p_slot_index) - _m_item_slots_packed_array[item_id_index] = p_item_id - var amount_to_add : int = clampi(p_amount, 0, __get_remaining_slot_capacity(p_slot_index)) - var item_amount_index : int = __calculate_slot_item_amount_index(p_slot_index) - _m_item_slots_packed_array[item_amount_index] = __get_slot_item_amount(p_slot_index) + amount_to_add - __increase_item_total(p_item_id, amount_to_add) # used to quickly get the total amount of a specific in the inventory - if was_slot_empty: - __increase_stack_count(p_item_id) - __add_item_id_slot_to_tracker(p_item_id, p_slot_index) - item_added.emit(p_slot_index, p_item_id) - slot_modified.emit(p_slot_index) - var remaining_amount_to_add : int = p_amount - amount_to_add - if EngineDebugger.is_active(): - var item_manager_id : int = get_instance_id() - EngineDebugger.send_message("inventory_manager:add_items_to_slot", [item_manager_id, p_slot_index, p_item_id, p_amount]) - return remaining_amount_to_add - - -# Sets the size of the inventory. -func __set_size(p_new_size : int) -> void: - if p_new_size == _DEFAULT_SIZE: - var _success : int = _m_inventory_manager_dictionary.erase(_key.SIZE) - else: - _m_inventory_manager_dictionary[_key.SIZE] = p_new_size - - -# Removes items from the specified slot number. Returns the number of items not removed from the slot. -# NOTE: The slot number is assumed to be within bounds in this function. -func __remove_items_from_slot(p_slot_index : int, p_item_id : int, p_amount : int) -> int: - var item_amount : int = __get_slot_item_amount(p_slot_index) - var amount_to_remove : int = clampi(p_amount, 0, item_amount) - var new_amount : int = item_amount - amount_to_remove - _m_item_slots_packed_array[__calculate_slot_item_amount_index(p_slot_index)] = new_amount - __decrease_item_total(p_item_id, amount_to_remove) # used to quickly get the total amount of a specific in the inventory - if new_amount == 0: - __decrease_stack_count(p_item_id) - __remove_item_id_slot_from_tracker(p_item_id, p_slot_index) - item_removed.emit(p_slot_index, p_item_id) - slot_modified.emit(p_slot_index) - var remaining_amount_to_remove : int = p_amount - amount_to_remove - if EngineDebugger.is_active(): - var item_manager_id : int = get_instance_id() - EngineDebugger.send_message("inventory_manager:remove_items_from_slot", [item_manager_id, p_slot_index, p_item_id, p_amount]) - return remaining_amount_to_remove - - -# Increases the inventory to fix at most the passed slot number. -# NOTE: The slot number is assumed to be within bounds in this function. -func __increase_size(p_slot_index : int) -> void: - var expected_new_size : int = __calculate_array_size_needed_to_access_slot_index(p_slot_index) - var error : int = _m_item_slots_packed_array.resize(expected_new_size) - if error != OK: - push_warning("InventoryManager: Unable to resize inventory properly. New inventory size is: %d. Expected size: %d." % [_m_item_slots_packed_array.size(), expected_new_size]) - - -# Returns the item ID for the given item slot. Returns -1 on empty slots. -# NOTE: The slot number is assumed to be within bounds in this function. -func __get_slot_item_id(p_slot_index : int) -> int: - var p_slot_item_id_index : int = __calculate_slot_item_id_index(p_slot_index) - return _m_item_slots_packed_array[p_slot_item_id_index] - - -# Returns the item amount for the given item slot. Returns 0 on empty slots. -# NOTE: The slot number is assumed to be within bounds in this function. -func __get_slot_item_amount(p_slot_index : int) -> int: - var slot_item_amount_index : int = __calculate_slot_item_amount_index(p_slot_index) - var amount : int = clampi(_m_item_slots_packed_array[slot_item_amount_index], 0, _INT64_MAX) - return amount - - -# Returns the remaining amount of items this slot can hold. -# NOTE: The slot number is assumed to be within bounds in this function. -func __get_remaining_slot_capacity(p_slot_index : int) -> int: - var item_id : int = __get_slot_item_id(p_slot_index) - var amount : int = __get_slot_item_amount(p_slot_index) - var stack_capacity : int = _m_item_registry.get_stack_capacity(item_id) - var remaining_capacity : int = clampi(stack_capacity - amount, 0, stack_capacity) - return remaining_capacity - -# Returns true when the item slot is is empty. Returns false otherwise. Checking if the slot is empty does not mean it is valid or reachable if the inventory is strictly sized. -# NOTE: The slot number is assumed to be within bounds in this function. -func __is_slot_empty(p_slot_index : int) -> bool: - var slot_item_amount : int = __get_slot_item_amount(p_slot_index) - return slot_item_amount <= 0 - - -# Returns true if the slot has been allocated in memory. Returns false otherwise. -# NOTE: The slot number is assumed to be within bounds in this function. -func __is_slot_allocated(p_slot_index : int) -> bool: - return p_slot_index < __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - - -# Returns the excess items when the current stack capacity is bigger than the registered stack capacity for the current item ID and modifies the item amount if needed. Returns null when there are no excess items to extract. -# NOTE: The slot number is assumed to be within bounds in this function. -func __extract_excess_items(p_slot_index : int) -> ExcessItems: - var item_id : int = __get_slot_item_id(p_slot_index) - var registry_stack_capacity : int = _m_item_registry.get_stack_capacity(item_id) - var item_amount : int = __get_slot_item_amount(p_slot_index) - if item_amount > registry_stack_capacity: - var excess_item_amount : int = item_amount - registry_stack_capacity - var excess_items : ExcessItems = __create_excess_items(item_id, excess_item_amount) - var _result_is_zero : int = __remove_items_from_slot(p_slot_index, item_id, excess_item_amount) - return excess_items - return null - - -# Given a slot number, calculates the index for the item ID index of that slot. -func __calculate_slot_item_id_index(p_slot_index : int) -> int: - return p_slot_index * 2 - - -# Given a slot number, calculates the index for the item amount index of that slot. -func __calculate_slot_item_amount_index(p_slot_index : int) -> int: - return clampi(p_slot_index * 2 + 1, 0, _INT64_MAX) - - -# Given a slot number, returns the minimum array size needed to fit that slot number. -func __calculate_array_size_needed_to_access_slot_index(p_slot_index : int) -> int: - return clampi(p_slot_index * 2 + 2, 0, _INT64_MAX) - - -# Given a slot number, returns the minimum array size needed to fit that slot number. -func __calculate_slot_numbers_given_array_size(p_array_size : int) -> int: - @warning_ignore("integer_division") - return p_array_size / 2 - - -## Returns the number of slots inventory has. If the inventory is set to infinite size, returns the number of slots currently allocated in memory.[br][br] -## To check if the inventory is set to infinite size, use [method is_infinite].[br][br] -## To always return the number of slots allocated in memory, use [method slots]. -func size() -> int: - if is_infinite(): - return __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - else: - var inventory_size : int = _m_inventory_manager_dictionary.get(_key.SIZE, _DEFAULT_SIZE) - return inventory_size - - -## Returns the number of slots allocated in memory. -func slots() -> int: - return __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - - -## Returns true if the inventory is finite or limited. Returns false if the inventory is set to infinite size. -func is_infinite() -> bool: - var inventory_size : int = _m_inventory_manager_dictionary.get(_key.SIZE, _DEFAULT_SIZE) - return inventory_size == INFINITE_SIZE - - -## Returns the item registry the inventory manager was initialized with. -func get_item_registry() -> ItemRegistry: - return _m_item_registry - - -## Sets a name to the manager. Only used for identifying the inventory in the debugger. -func set_name(p_name : String) -> void: - set_meta(&"name", p_name) - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:set_name", [get_instance_id(), p_name]) - - -## Gets the name of the manager. -func get_name() -> String: - return get_meta(&"name", "") - - -## Returns true if the inventory can handle the item in question. Returns false otherwise. This function is a wrapper around [method ItemRegistry.has_item], specifically for inventory manager instances should only handle items from the registry. -func is_item_registered(p_item_id : int) -> bool: - return _m_item_registry.has_item(p_item_id) - - -## Returns a duplicated slots array with internal keys replaced with strings for easier reading/debugging.[br] -## [br] -## [b]Example[/b]: -## [codeblock] -## var inventory_manager : InventoryManager = InventoryManager.new() -## var inventory_manager.add(0, 0) -## print(JSON.stringify(inventory_manager.prettify(), "\t")) -## [/codeblock] -func prettify() -> Array: - var prettified_data : Array = [] - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - continue - - var item_id : int = __get_slot_item_id(slot_number) - var item_amount : int = __get_slot_item_amount(slot_number) - - var readable_dictionary : Dictionary = {} - - # ItemRegistry data: - var name : String = _m_item_registry.get_name(item_id) - if not name.is_empty(): - readable_dictionary["name"] = name - var description : String = _m_item_registry.get_description(item_id) - if not description.is_empty(): - readable_dictionary["description"] = description - var registry_entry_metadata : Dictionary = _m_item_registry.get_registry_metadata_data() - if not registry_entry_metadata.is_empty(): - readable_dictionary["metadata"] = registry_entry_metadata - - # Slot data: - readable_dictionary["slot"] = slot_number - readable_dictionary["item_id"] = item_id - readable_dictionary["amount"] = item_amount - - prettified_data.push_back(readable_dictionary) - return prettified_data - - -## Returns a dictionary of all the data processed by the manager. Use [method set_data] initialize an inventory back to the extracted data.[br] -## [br] -## [color=yellow]Warning:[/color] Use with caution. Modifying this dictionary will directly modify the inventory manager data. -func get_data() -> Dictionary: - return _m_inventory_manager_dictionary - - -## Sets the inventory manager data. -func set_data(p_data : Dictionary) -> void: - # Clear the inventory - clear() - - # Inject the new data - _m_inventory_manager_dictionary = p_data - _m_item_slots_packed_array = _m_inventory_manager_dictionary[_key.ITEM_ENTRIES] - - # Send a signal about all the new slots that changed and also count the stacks: - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - continue - var item_id : int = __get_slot_item_id(slot_number) - __increase_stack_count(item_id) - __increase_item_total(item_id, __get_slot_item_amount(slot_number)) - __add_item_id_slot_to_tracker(item_id, slot_number) - item_added.emit(slot_number, item_id) - slot_modified.emit(slot_number) - - # Data is not auto-fixed. Do a sanity check only on debug builds to report the issues. - if OS.is_debug_build(): - var sanity_check_messages : PackedStringArray = sanity_check() - var joined_messages : String = "".join(sanity_check_messages) - if not joined_messages.is_empty(): - push_warning("InventoryManager: Found the following issues in the inventory:\n%s", joined_messages) - - # Synchronize change with the debugger: - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:set_data", [get_instance_id(), _m_inventory_manager_dictionary]) - - -## Automatically applies the item registry constraints to the inventory. Returns an array of excess items found, if any. -func apply_registry_constraints() -> Array[ExcessItems]: - # Extract excess items if any - var excess_items_array : Array[ExcessItems] = [] - var item_id_to_stack_count_map : Dictionary = {} - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - # Nothing to do here. - continue - - # Track item stack count - var item_id : int = __get_slot_item_id(slot_number) - var stack_count : int = item_id_to_stack_count_map.get(item_id, 0) + 1 - item_id_to_stack_count_map[item_id] = stack_count - var registry_stack_count : int = _m_item_registry.get_stack_count(item_id) - - # Extract the excess items from the stack if any: - var excess_items : ExcessItems = __extract_excess_items(slot_number) - if is_instance_valid(excess_items): - excess_items_array.push_back(excess_items) - - # If the item stack count is limited and we are over the stack count limit, the whole stack is an excess items. - if _m_item_registry.is_stack_count_limited(item_id) and stack_count > registry_stack_count: - # Then convert the whole item slot into excess items - var item_amount : int = __get_slot_item_amount(slot_number) - var excess_stack : ExcessItems = __create_excess_items(item_id, item_amount) - if is_instance_valid(excess_stack): - excess_items_array.push_back(excess_stack) - - # Empty the slot. - var _result_is_zero : int = __remove_items_from_slot(slot_number, item_id, item_amount) - return excess_items_array - - -## Preforms a sanity check over the data. -func sanity_check() -> PackedStringArray: - # Extract excess items if any - var item_id_to_stack_count_map : Dictionary = {} - var message_array : PackedStringArray = PackedStringArray() - var new_size : int = __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()) - var _error : int = message_array.resize(new_size) - var message_array_index : int = 0 - for slot_number : int in new_size: - if __is_slot_empty(slot_number): - continue - - var message : String = "" - - # Check if item is registered in registry: - var item_id : int = __get_slot_item_id(slot_number) - var item_registry : ItemRegistry = get_item_registry() - if not item_registry.has_item(item_id): - message += "Slot %d: Could not find item ID \'%d\' in associated registry.\n" % [slot_number, item_id] - - # Track item stack count: - var stack_count : int = item_id_to_stack_count_map.get(item_id, 0) + 1 - item_id_to_stack_count_map[item_id] = stack_count - var registry_stack_count : int = _m_item_registry.get_stack_count(item_id) - - # Check if the slot has excess items and warn about these as well: - if __does_slot_have_excess_items(slot_number): - var registry_stack_capacity : int = _m_item_registry.get_stack_capacity(item_id) - message += "Slot %d: Stack with item ID '%d' has excess items. Current stack capacity: %d. Registered stack capacity: %d.\n" % [slot_number, item_id, __get_slot_item_amount(slot_number), registry_stack_capacity] - - # If the stack count is limited and greater than the registered stack count, the stack shouldn't be present in the inventory: - if _m_item_registry.is_stack_count_limited(item_id) and stack_count > registry_stack_count: - message += "Slot %d: Stack with item ID '%d' should not be pressent since the max stack count has already been reached.\n" % [slot_number, item_id] - - message_array[message_array_index] = message - message_array_index += 1 - return message_array - - -# Returns the true if the item slot has excess items. Returns false otherwise. -func __does_slot_have_excess_items(p_slot_index : int) -> bool: - var item_id : int = __get_slot_item_id(p_slot_index) - var registered_stack_capacity : int = _m_item_registry.get_stack_capacity(item_id) - var item_amount : int = __get_slot_item_amount(p_slot_index) - return item_amount > registered_stack_capacity - - -## Returns the count of empty slots. -func get_empty_slot_count() -> int: - var inventory_size : int = size() - if is_infinite(): - inventory_size = _INT64_MAX - var total_slots_filled : int = 0 - for stack_count : int in _m_item_stack_count_tracker.values(): - total_slots_filled += stack_count - return inventory_size - total_slots_filled - - -## Returns the remaining item capacity for the specified item ID. -func get_remaining_capacity_for_item(p_item_id : int) -> int: - # Check if the inventory is infinite because then that simplifies this operation. - var inventory_size : int = size() - if inventory_size == 0: - return 0 - - var registered_stack_count : int = _m_item_registry.get_stack_count(p_item_id) - if is_infinite(): - if registered_stack_count == INFINITE_SIZE: - # There's no limit to the number of stacks. The amount we can store of this item is infinite. - return _INT64_MAX - - # Get the remaining item capacity within all the slot: - var remaining_item_capacity_within_slots : int = 0 - var registered_stack_capacity : int = _m_item_registry.get_stack_capacity(p_item_id) - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker.get(p_item_id, PackedInt64Array()) - for slot_number : int in item_id_slots_array: - var remaining_slot_capacity : int = clampi(registered_stack_capacity - get_slot_item_amount(slot_number), 0, registered_stack_capacity) - remaining_item_capacity_within_slots += remaining_slot_capacity - - # Count the remaining stack count - var item_stack_count : int = _m_item_stack_count_tracker.get(p_item_id, 0) - var remaining_stack_count : int = registered_stack_count - item_stack_count - if not _m_item_registry.is_stack_count_limited(p_item_id): - # The stack count is not limited. Infinitely many items can be added to the inventory. - remaining_stack_count = _INT64_MAX - - # Clamp the remaining stacks to the available slots left: - var remaining_stack_count_limited_by_empty_slot_count : int = clampi(remaining_stack_count, 0, get_empty_slot_count()) - - # Calculate the remaining capacity - var remaining_capacity : int = remaining_stack_count_limited_by_empty_slot_count * registered_stack_capacity + remaining_item_capacity_within_slots - if remaining_capacity < 0: - # The remaining_capacity calculation above overflowed. Reset back to max value. - remaining_capacity = _INT64_MAX - return remaining_capacity - - -## Organizes the inventory by maximizing its space usage and moving items closer to the beginning of the inventory by avoiding empty slots. [br] -## If an array of item IDs is passed to the function, the items will be organized in the order found within the array. -func organize(p_item_ids_array : PackedInt64Array = []) -> void: - # Collect item totals for every item: - var item_totals : Dictionary = {} - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - continue - var item_id : int = __get_slot_item_id(slot_number) - item_totals[item_id] = __get_slot_item_amount(slot_number) + item_totals.get(item_id, 0) - - # Clear all the statistics but keep the inventory memory allocated to the same size - clear() - - # Re-add the items to the inventory: - if p_item_ids_array.is_empty(): - # No specific sorting. Use the item IDs themselves as a sorting value. - var sorted_item_ids : PackedInt64Array = item_totals.keys() - sorted_item_ids.sort() - for item_id : int in sorted_item_ids: - var amount : int = item_totals[item_id] - var excess_items : ExcessItems = add(item_id, amount) - if is_instance_valid(excess_items): - push_warning("InventoryManager: Stumpled upon excess items with upon inventory reorganization.\n%s\n" % excess_items) - else: - # Specific sorting given. Track unprocessed item IDs. - var item_ids_not_processed : PackedInt64Array = item_totals.keys() - for item_id : int in p_item_ids_array: - if item_totals.has(item_id): - var amount : int = item_totals[item_id] - var excess_items : ExcessItems = add(item_id, amount) - if is_instance_valid(excess_items): - push_warning("InventoryManager: Stumpled upon excess items with ID '%d' upon inventory reorganization." % item_id) - var index_found : int = item_ids_not_processed.find(item_id) - if index_found != -1: - item_ids_not_processed.remove_at(index_found) - item_ids_not_processed.sort() - if not item_ids_not_processed.is_empty(): - var message_format : String = "InventoryManager: organize function called with a list of item IDs but not all the item IDs were found.\n" - message_format += "\tHere are the missing item IDs that will be ordered as they appear:\n" - message_format += "\t%s" - push_warning(message_format % item_ids_not_processed) - for item_id : int in item_ids_not_processed: - if item_totals.has(item_id): - var amount : int = item_totals[item_id] - var excess_items : ExcessItems = add(item_id, amount) - if is_instance_valid(excess_items): - push_warning("InventoryManager: Stumpled upon excess items with ID '%d' upon inventory reorganization." % item_id) - - # Emit signals for all the slots changed, and resize the slots array to fit only the used item slots to save memory. - var last_slot_number_filled : int = 0 - for slot_number : int in __calculate_slot_numbers_given_array_size(_m_item_slots_packed_array.size()): - if __is_slot_empty(slot_number): - break - slot_modified.emit(slot_number) - last_slot_number_filled = slot_number - var expected_size : int = __calculate_array_size_needed_to_access_slot_index(last_slot_number_filled) - var error : int = _m_item_slots_packed_array.resize(expected_size) - if error != OK: - push_warning("InventoryManager: slot array resize did not go as expected within organize(). Got new size %d, but expected %d." % [_m_item_slots_packed_array.size(), expected_size]) - - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:organize", [get_instance_id(), p_item_ids_array]) - - -## Clears the inventory. Keeps the current size. -func clear() -> void: - _m_item_slots_packed_array.fill(0) - _m_item_stack_count_tracker.clear() - _m_item_total_tracker.clear() - _m_item_slots_tracker.clear() - inventory_cleared.emit() - - -## Deregisters the inventory manager from the debugger. -func deregister() -> void: - if EngineDebugger.is_active(): - EngineDebugger.send_message("inventory_manager:deregister_inventory_manager", [get_instance_id()]) - - -# Creates and returns an [ExcessItems] object meant to represent either the unprocessed addition or removal of items from the inventory. -func __create_excess_items(p_item_id : int, p_amount : int) -> ExcessItems: - if p_amount == 0: - return null - var excess_items_array : PackedInt64Array = PackedInt64Array() - var _new_size : int = excess_items_array.resize(2) - excess_items_array[0] = p_item_id - excess_items_array[1] = p_amount - return ExcessItems.new(_m_item_registry, excess_items_array) - - -# Function used by the debugger only. Used to increase the InventoryManager data arrays if needed. -func __allocate_if_needed(p_slot_index : int) -> void: - if not __is_slot_allocated(p_slot_index): - __increase_size(p_slot_index) - - -# Every time an item slot is modified, synchronize it with the debugger -func __synchronize_inventory_with_debugger_when_cleared() -> void: - var item_manager_id : int = get_instance_id() - EngineDebugger.send_message("inventory_manager:clear", [item_manager_id]) - - -# Increases the item id stack count. -func __increase_stack_count(p_item_id : int) -> void: - _m_item_stack_count_tracker[p_item_id] = _m_item_stack_count_tracker.get(p_item_id, 0) + 1 - - -# Decreases the item id stack count. -func __decrease_stack_count(p_item_id : int) -> void: - var new_stack_count : int = _m_item_stack_count_tracker.get(p_item_id, 0) - 1 - if new_stack_count == 0: - var _erase_success : bool = _m_item_stack_count_tracker.erase(p_item_id) - else: - _m_item_stack_count_tracker[p_item_id] = new_stack_count - - -# Increases the total item amount count -func __increase_item_total(p_item_id : int, p_amount : int) -> void: - _m_item_total_tracker[p_item_id] = _m_item_total_tracker.get(p_item_id, 0) + p_amount - - -# Decreases the total item amount count -func __decrease_item_total(p_item_id : int, p_amount : int) -> void: - var new_total : int = _m_item_total_tracker.get(p_item_id, 0) - p_amount - if new_total == 0: - var _erase_success : bool = _m_item_total_tracker.erase(p_item_id) - else: - _m_item_total_tracker[p_item_id] = new_total - - -# Adds a slot to the item id slot tracker -func __add_item_id_slot_to_tracker(p_item_id : int, p_slot_index : int) -> void: - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker.get(p_item_id, []) - var was_empty : bool = item_id_slots_array.is_empty() - var _success : bool = item_id_slots_array.push_back(p_slot_index) - if was_empty: - _m_item_slots_tracker[p_item_id] = item_id_slots_array - - -# Removes a slot from the item id slot tracker -func __remove_item_id_slot_from_tracker(p_item_id : int, p_slot_index : int) -> void: - var item_id_slots_array : PackedInt64Array = _m_item_slots_tracker[p_item_id] - var index_to_remove : int = item_id_slots_array.find(p_slot_index) - item_id_slots_array.remove_at(index_to_remove) - if item_id_slots_array.is_empty(): - var _success : bool = _m_item_slots_tracker.erase(p_item_id) - - -func _to_string() -> String: - return " Size: %d, Allocated Slots: %d" % [get_instance_id(), size(), slots()] - - -func _init(p_item_registry : ItemRegistry = null) -> void: - _m_item_registry = p_item_registry - _m_inventory_manager_dictionary[_key.ITEM_ENTRIES] = _m_item_slots_packed_array - - if not is_instance_valid(_m_item_registry): - _m_item_registry = ItemRegistry.new() - if EngineDebugger.is_active(): - # Register with the debugger - var current_script : Resource = get_script() - var path : String = current_script.get_path() - var name : String = get_name() - EngineDebugger.send_message("inventory_manager:register_inventory_manager", [get_instance_id(), name, path, _m_item_registry.get_instance_id()]) - - # Update remote - var _success : int = inventory_cleared.connect(__synchronize_inventory_with_debugger_when_cleared) diff --git a/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd.uid b/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd.uid deleted file mode 100644 index ffc6103..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/inventory_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4an4qv3k4tk7 diff --git a/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd b/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd deleted file mode 100644 index e6be999..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd +++ /dev/null @@ -1,476 +0,0 @@ -#============================================================================ -# item_registry.gd | -#============================================================================ -# This file is part of: | -# INVENTORY MANAGER | -# https://github.com/Rubonnek/inventory-manager | -#============================================================================ -# Copyright (c) 2024-2025 Wilson Enrique Alvarez Torres | -# | -# Permission is hereby granted, free of charge, to any person obtaining | -# a copy of this software and associated documentation files (the | -# "Software"), to deal in the Software without restriction, including | -# without limitation the rights to use, copy, modify, merge, publish, | -# distribute, sublicense, andor sell copies of the Software, and to | -# permit persons to whom the Software is furnished to do so, subject to | -# the following conditions: | -# | -# The above copyright notice and this permission notice shall be | -# included in all copies or substantial portions of the Software. | -# | -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | -#============================================================================ - -extends RefCounted -class_name ItemRegistry -## Holds a list of items and data the InventoryManager will use to handle them. -## -## Each ItemRegistry must initialized with a set of item IDs provided by the user which can then be used to track item metadata such as item name, description, stack capacity, stack count limit and their metadata. - - -## Emitted when an item is modified. -signal item_modified(p_item_id : int) - -var _m_item_registry_dictionary : Dictionary -var _m_item_registry_entries_dictionary : Dictionary - -enum _registry_key { - ITEM_ENTRIES, - METADATA, -} - -enum _item_entry_key { - NAME, - DESCRIPTION, - ICON, - STACK_CAPACITY, - STACK_COUNT_LIMIT, - METADATA, -} - -const DEFAULT_STACK_CAPACITY : int = 99 -const DEFAULT_STACK_COUNT_LIMIT : int = 0 # a stack count of 0 means the stack count limit is infinite - - -## Adds an item to the registry. -func add_item(p_item_id : int, p_name : String = "", p_description : String = "", p_icon : Texture2D = null, p_stack_capacity : int = DEFAULT_STACK_CAPACITY, p_stack_count : int = DEFAULT_STACK_COUNT_LIMIT, p_metadata : Dictionary = {}) -> void: - if not p_item_id >= 0: - push_error("ItemRegistry: Unable to add item to registry. The item IDs are required to be greater or equal to 0.") - return - if p_stack_capacity <= 0: - push_error("ItemRegistry: : Attempting to add item ID %d with invalid stack capacity %d. Stack capacity must be a positive integer." % p_item_id, p_stack_capacity) - return - if p_stack_count < 0: - push_error("ItemRegistry: : Attempting to add item ID %d with invalid stack count %d. Stack count must be equal or greater than zero." % p_item_id, p_stack_count) - return - if _m_item_registry_entries_dictionary.has(p_item_id): - push_warning("ItemRegistry: Item ID %d is already registered:\n\n%s\n\nRe-registering will overwrite previous data." % [p_item_id, str(prettify(p_item_id))]) - - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if not p_name.is_empty(): - item_registry_entry_dictionary[_item_entry_key.NAME] = p_name - if not p_description.is_empty(): - item_registry_entry_dictionary[_item_entry_key.DESCRIPTION] = p_description - if is_instance_valid(p_icon): - item_registry_entry_dictionary[_item_entry_key.ICON] = p_icon - if p_stack_capacity != DEFAULT_STACK_CAPACITY: - item_registry_entry_dictionary[_item_entry_key.STACK_CAPACITY] = p_stack_capacity - if p_stack_count != DEFAULT_STACK_COUNT_LIMIT: - item_registry_entry_dictionary[_item_entry_key.STACK_COUNT_LIMIT] = p_stack_count - if not p_metadata.is_empty(): - item_registry_entry_dictionary[_item_entry_key.METADATA] = p_metadata - item_modified.emit(p_item_id) - - -## Removes the item and all the associated data from the registry. -func remove_item(p_item_id : int) -> void: - var success : bool = _m_item_registry_entries_dictionary.erase(p_item_id) - if success: - item_modified.emit(p_item_id) - - -## Returns true if the item is registered. Returns false otherwise. -func has_item(p_item_id : int) -> bool: - return _m_item_registry_entries_dictionary.has(p_item_id) - - -## Sets the item name. -func set_name(p_item_id : int, p_name : String) -> void: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if p_name.is_empty(): - var _success : bool = item_registry_entry_dictionary.erase(_item_entry_key.NAME) - else: - item_registry_entry_dictionary[_item_entry_key.NAME] = p_name - item_modified.emit(p_item_id) - - -## Returns the item name. -func get_name(p_item_id : int) -> String: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.get(_item_entry_key.NAME, "") - - -## Returns true if the item has a registered name. -func has_name(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.has(_item_entry_key.NAME) - - -## Sets the item description. -func set_description(p_item_id : int, p_description : String) -> void: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if p_description.is_empty(): - var _success : bool = item_registry_entry_dictionary.erase(_item_entry_key.DESCRIPTION) - else: - item_registry_entry_dictionary[_item_entry_key.DESCRIPTION] = p_description - item_modified.emit(p_item_id) - - -## Returns the item description. -func get_description(p_item_id : int) -> String: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.get(_item_entry_key.DESCRIPTION, "") - - -## Returns true if the item has a description. -func has_description(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.has(_item_entry_key.DESCRIPTION) - - -## Sets the item icon. -func set_icon(p_item_id : int, p_texture : Texture2D) -> void: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if not is_instance_valid(p_texture): - var _success : bool = item_registry_entry_dictionary.erase(_item_entry_key.ICON) - else: - item_registry_entry_dictionary[_item_entry_key.ICON] = p_texture - item_modified.emit(p_item_id) - - -## Returns the item icon. Returns [code]null[/code] if there's none. -func get_icon(p_item_id : int) -> Texture2D: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.get(_item_entry_key.ICON, null) - - -## Returns true if the item has an icon. -func has_icon(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.has(_item_entry_key.ICON) - - -## Sets the maximum number of items per stack for the item. -func set_stack_capacity(p_item_id : int, p_stack_capacity : int) -> void: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if p_stack_capacity <= 0: - push_warning("ItemRegistry: Attempted to set a stack capacity with a negative number which should be positive instead. Ignoring.") - return - elif p_stack_capacity == DEFAULT_STACK_CAPACITY: - var _success : bool = item_registry_entry_dictionary.erase(_item_entry_key.STACK_CAPACITY) - else: - item_registry_entry_dictionary[_item_entry_key.STACK_CAPACITY] = p_stack_capacity - item_modified.emit(p_item_id) - - -## Returns the stack capacity for the item. -func get_stack_capacity(p_item_id : int) -> int: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.get(_item_entry_key.STACK_CAPACITY, DEFAULT_STACK_CAPACITY) - - -## Returns true if the item has a stack_capacity different than 99, the default value. -func has_stack_capacity(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.has(_item_entry_key.STACK_CAPACITY) - - -## Sets the maximum number of stacks for the item. -func set_stack_count_limit(p_item_id : int, p_stack_count : int = 0) -> void: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - if p_stack_count < 0: - push_warning("ItemRegistry: Attempted to set an invalid stack count. The stack count must be equal or greater than zero. Ignoring.") - return - elif p_stack_count == DEFAULT_STACK_COUNT_LIMIT: - var _success : bool = item_registry_entry_dictionary.erase(_item_entry_key.STACK_COUNT_LIMIT) - else: - item_registry_entry_dictionary[_item_entry_key.STACK_COUNT_LIMIT] = p_stack_count - item_modified.emit(p_item_id) - - -## Returns the maximum number of items per stack for the item. -func get_stack_count(p_item_id : int) -> int: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - return item_registry_entry_dictionary.get(_item_entry_key.STACK_COUNT_LIMIT, DEFAULT_STACK_COUNT_LIMIT) - - -## Returns true if the item has a stack count set different than 0, the default value.. -func has_stack_count(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - if not _m_item_registry_entries_dictionary.has(p_item_id): - _m_item_registry_entries_dictionary[p_item_id] = item_registry_entry_dictionary - return item_registry_entry_dictionary.has(_item_entry_key.STACK_COUNT_LIMIT) - - -## Returns true if the stack count for the item is set to greater than 0. Returns false otherwise. -func is_stack_count_limited(p_item_id : int) -> bool: - return get_stack_count(p_item_id) > 0 - - -## Returns an array with the registered items. -func keys() -> PackedInt64Array: - var array : PackedInt64Array = _m_item_registry_entries_dictionary.keys() - return array - - -## Attaches the specified metadata to the related item. -func set_item_metadata(p_item_id : int, p_key : Variant, p_value : Variant) -> void: - if not _m_item_registry_entries_dictionary.has(p_item_id): - push_error("ItemRegistry: Attempting to set item metadata on unregistered item with id %d. Ignoring call." % p_item_id) - return - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary[p_item_id] - var item_metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - if item_metadata.is_empty(): - item_registry_entry_dictionary[_item_entry_key.METADATA] = item_metadata - item_metadata[p_key] = p_value - item_modified.emit(p_item_id) - - -## Sets the item metadata data. -func set_item_metadata_data(p_item_id : int, p_metadata : Dictionary) -> void: - if not _m_item_registry_entries_dictionary.has(p_item_id): - push_error("ItemRegistry: Attempting to set item metadata on unregistered item with id %d. Ignoring call." % p_item_id) - return - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary[p_item_id] - item_registry_entry_dictionary[_item_entry_key.METADATA] = p_metadata - item_modified.emit(p_item_id) - - -## Returns the specified metadata for the item. -func get_item_metadata(p_item_id : int, p_key : Variant, p_default_value : Variant = null) -> Variant: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - var item_metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - return item_metadata.get(p_key, p_default_value) - - -## Returns a reference to the internal metadata dictionary.[br] -## [br] -## [color=yellow]Warning:[/color] Use with caution. Modifying this dictionary will directly modify the installed metadata for the item. -func get_item_metadata_data(p_item_id : int) -> Dictionary: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - var item_metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - if not _m_item_registry_dictionary.has(_item_entry_key.METADATA): - # There's a chance the user wants to modify it externally and have it update the ItemRegistry automatically -- make sure we store a reference of that metadata: - _m_item_registry_dictionary[_item_entry_key.METADATA] = item_metadata - return item_metadata - - -## Returns true if the item metadata has the specified key: -func has_item_metadata_key(p_item_id : int, p_key : Variant) -> bool: - if not _m_item_registry_entries_dictionary.has(p_item_id): - push_error("ItemRegistry: Attempting to get item metadata on unregistered item with id %d. Returning false." % p_item_id) - return false - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary[p_item_id] - var item_metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - return item_metadata.has(p_key) - - -## Returns true if the item has some metadata. -func has_item_metadata(p_item_id : int) -> bool: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - var item_metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - return not item_metadata.is_empty() - - -## Sets the specified metadata for the item registry. -func set_registry_metadata(p_key : Variant, p_value : Variant) -> void: - var metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - metadata[p_key] = p_value - if not _m_item_registry_dictionary.has(_registry_key.METADATA): - _m_item_registry_dictionary[_registry_key.METADATA] = metadata - __sync_registry_metadata_with_debugger() - - -## Returns the specified metadata from the item registry. -func get_registry_metadata(p_key : Variant, p_default_value : Variant = null) -> Variant: - var metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - return metadata.get(p_key, p_default_value) - - -## Returns a reference to the internal metadata dictionary. -func get_registry_metadata_data() -> Dictionary: - var metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - if not _m_item_registry_dictionary.has(_registry_key.METADATA): - # There's a chance the user wants to modify it externally and have it update the item registry automatically -- make sure we store a reference of that metadata: - _m_item_registry_dictionary[_registry_key.METADATA] = metadata - return metadata - - -## Returns true if the item registry has some metadata. -func has_registry_metadata() -> bool: - var metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - return not metadata.is_empty() - - -## Appends all the items of another item registry. -func append(p_item_registry : ItemRegistry) -> void: - var registry_data : Dictionary = p_item_registry.get_data() - var entries_data : Dictionary = registry_data.get(_registry_key.ITEM_ENTRIES, {}) - for item_id : int in entries_data: - var item_registry_entry_dictionary : Dictionary = entries_data[item_id] - var name : String = item_registry_entry_dictionary.get(_item_entry_key.NAME, "") - var description : String = item_registry_entry_dictionary.get(_item_entry_key.DESCRIPTION, "") - var icon : Texture2D = item_registry_entry_dictionary.get(_item_entry_key.ICON, null) - var stack_capacity : int = item_registry_entry_dictionary.get(_item_entry_key.STACK_CAPACITY, DEFAULT_STACK_CAPACITY) - var stack_count : int = item_registry_entry_dictionary.get(_item_entry_key.STACK_COUNT_LIMIT, DEFAULT_STACK_COUNT_LIMIT) - var metadata : Dictionary = item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - add_item(item_id, name, description, icon, stack_capacity, stack_count, metadata) - - -## Returns a reference to the internal dictionary where all the item registry data is stored.[br] -## [br] -## [color=yellow]Warning:[/color] Use with caution. Modifying this dictionary will directly modify the item registry data. -func get_data() -> Dictionary: - return _m_item_registry_dictionary - - -## Overwrites the item registry data. -func set_data(p_data : Dictionary) -> void: - # Track old item IDs: - var item_ids_changed : Dictionary = _m_item_registry_entries_dictionary - - # Update data - _m_item_registry_dictionary = p_data - _m_item_registry_entries_dictionary = _m_item_registry_dictionary[_registry_key.ITEM_ENTRIES] - - # Track new item IDs: - for item_id : int in _m_item_registry_entries_dictionary: - item_ids_changed[item_id] = true - - # Send a signal about all the ids that changed: - for item_id : int in item_ids_changed: - item_modified.emit(item_id) - - if EngineDebugger.is_active(): - # NOTE: Do not use any of API calls directly here when setting values to avoid sending unnecessary data to the debugger about the duplicated item_registry entry being sent to display - - # Process each entry data - var duplicated_registry_data : Dictionary = _m_item_registry_dictionary.duplicate(true) - for item_id : int in duplicated_registry_data: - # The debugger viewer requires certain objects to be stringified before sending -- duplicate the entry data to avoid overriding the runtime data: - var duplicated_item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary[item_id] - duplicated_item_registry_entry_dictionary = duplicated_item_registry_entry_dictionary.duplicate(true) - - # Convert the image into an object that we can send into the debugger - if duplicated_item_registry_entry_dictionary.has(_item_entry_key.ICON): - var image : Image = duplicated_item_registry_entry_dictionary[_item_entry_key.ICON] - duplicated_item_registry_entry_dictionary[_item_entry_key.ICON] = var_to_bytes_with_objects(image) - - # Process the ItemRegistry metadata: - var metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - if not metadata.is_empty(): - var stringified_metadata : Dictionary = {} - for key : Variant in metadata: - var value : Variant = metadata[key] - if key is Callable or key is Object: - stringified_metadata[str(key)] = str(value) - else: - stringified_metadata[key] = str(value) - # Replaced the source metadata with the stringified version that can be displayed remotely: - duplicated_registry_data[_registry_key.METADATA] = stringified_metadata - - # Send the data - EngineDebugger.send_message("inventory_manager:item_registry_set_data", [get_instance_id(), duplicated_registry_data]) - - -# Only used by the debugger to inject the data it receives -func __inject(p_item_id : int, p_item_registry_entry_dictionary : Dictionary) -> void: - if p_item_registry_entry_dictionary.is_empty(): - var _success : bool = _m_item_registry_entries_dictionary.erase(p_item_id) - else: - _m_item_registry_entries_dictionary[p_item_id] = p_item_registry_entry_dictionary - - -func __synchronize_item_data_with_the_debugger(p_item_id : int) -> void: - if EngineDebugger.is_active(): - # NOTE: Do not use the item_registry API directly here when setting values to avoid sending unnecessary data to the debugger about the duplicated item_registry entry being sent to display - - # The debugger viewer requires certain objects to be stringified before sending -- duplicate the entry data to avoid overriding the runtime data: - var item_registry_entry_dictionary : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - var duplicated_item_registry_entry_dictionary : Dictionary = item_registry_entry_dictionary.duplicate(true) - - # Stringify item metadata - var item_metadata : Dictionary = duplicated_item_registry_entry_dictionary.get(_item_entry_key.METADATA, {}) - if not item_metadata.is_empty(): - var stringified_item_metadata : Dictionary = {} - for key : Variant in item_metadata: - var value : Variant = item_metadata[key] - if key is Callable or key is Object: - stringified_item_metadata[str(key)] = str(value) - else: - stringified_item_metadata[key] = str(value) - duplicated_item_registry_entry_dictionary[_item_entry_key.METADATA] = stringified_item_metadata - - # Convert the image into an object that we can send into the debugger - if duplicated_item_registry_entry_dictionary.has(_item_entry_key.ICON): - var texture : Texture2D = duplicated_item_registry_entry_dictionary[_item_entry_key.ICON] - var image : Image = texture.get_image() - duplicated_item_registry_entry_dictionary[_item_entry_key.ICON] = var_to_bytes_with_objects(image) - - var item_registry_manager_id : int = get_instance_id() - EngineDebugger.send_message("inventory_manager:item_registry_sync_item_registry_entry", [item_registry_manager_id, p_item_id, duplicated_item_registry_entry_dictionary]) - - -## Returns a human-readable dictionary for the item. -func prettify(p_item_id : int) -> Dictionary: - var item_data : Dictionary = _m_item_registry_entries_dictionary.get(p_item_id, {}) - var prettified_item_data : Dictionary = item_data.duplicate(true) - for enum_key : String in _item_entry_key: - var enum_id : int = _item_entry_key[enum_key] - if enum_id in prettified_item_data: - var data : Variant = prettified_item_data[enum_id] - var _success : bool = prettified_item_data.erase(enum_id) - prettified_item_data[enum_key.to_snake_case()] = data - return prettified_item_data - - -func __sync_registry_metadata_with_debugger() -> void: - if EngineDebugger.is_active(): - # Stringify registry metadata - var registry_metadata : Dictionary = _m_item_registry_dictionary.get(_registry_key.METADATA, {}) - registry_metadata = registry_metadata.duplicate(true) - var stringified_metadata : Dictionary = {} - for key : Variant in registry_metadata: - var value : Variant = registry_metadata[key] - if key is Callable or key is Object: - stringified_metadata[str(key)] = str(value) - else: - stringified_metadata[key] = str(value) - - # Send the stringified metadata - EngineDebugger.send_message("inventory_manager:item_registry_sync_metadata", [get_instance_id(), stringified_metadata]) - - -func _init() -> void: - _m_item_registry_dictionary[_registry_key.ITEM_ENTRIES] = _m_item_registry_entries_dictionary - if EngineDebugger.is_active(): - # Register with the debugger - EngineDebugger.send_message("inventory_manager:register_item_registry", [get_instance_id()]) - var _success : int = item_modified.connect(__synchronize_item_data_with_the_debugger) diff --git a/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd.uid b/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd.uid deleted file mode 100644 index 0256e56..0000000 --- a/godot/addons/rubonnek.inventory_manager/runtime/item_registry.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dcijwilnuwjyc diff --git a/godot/addons/zylann.hterrain/LICENSE.md b/godot/addons/zylann.hterrain/LICENSE.md deleted file mode 100644 index a71a954..0000000 --- a/godot/addons/zylann.hterrain/LICENSE.md +++ /dev/null @@ -1,11 +0,0 @@ -HeightMap terrain for Godot Engine ------------------------------------- - -Copyright (c) 2016-2023 Marc Gilleron - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/godot/addons/zylann.hterrain/doc/.gdignore b/godot/addons/zylann.hterrain/doc/.gdignore deleted file mode 100644 index e69de29..0000000 diff --git a/godot/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png b/godot/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png deleted file mode 100644 index e26ecfa..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/alpha_blending_and_depth_blending.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png b/godot/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png deleted file mode 100644 index 7cf6d49..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/bad_array_blending.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/brush_editor.png b/godot/addons/zylann.hterrain/doc/docs/images/brush_editor.png deleted file mode 100644 index 6641352..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/brush_editor.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/channel_packer.png b/godot/addons/zylann.hterrain/doc/docs/images/channel_packer.png deleted file mode 100644 index 1edd264..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/channel_packer.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png b/godot/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png deleted file mode 100644 index 0ee70ae..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/choose_bullet_physics.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/color_painting.png b/godot/addons/zylann.hterrain/doc/docs/images/color_painting.png deleted file mode 100644 index c8f7ad1..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/color_painting.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/data_directory_property.png b/godot/addons/zylann.hterrain/doc/docs/images/data_directory_property.png deleted file mode 100644 index 29ecfc7..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/data_directory_property.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/default_terrain.png b/godot/addons/zylann.hterrain/doc/docs/images/default_terrain.png deleted file mode 100644 index 106cedf..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/default_terrain.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/detail_layers.png b/godot/addons/zylann.hterrain/doc/docs/images/detail_layers.png deleted file mode 100644 index c0e3975..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/detail_layers.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/dilation.png b/godot/addons/zylann.hterrain/doc/docs/images/dilation.png deleted file mode 100644 index 820dbd2..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/dilation.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/erosion_slope.png b/godot/addons/zylann.hterrain/doc/docs/images/erosion_slope.png deleted file mode 100644 index 698ac62..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/erosion_slope.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/erosion_steps.png b/godot/addons/zylann.hterrain/doc/docs/images/erosion_steps.png deleted file mode 100644 index 9498f70..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/erosion_steps.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/generator.png b/godot/addons/zylann.hterrain/doc/docs/images/generator.png deleted file mode 100644 index 44012b6..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/generator.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png b/godot/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png deleted file mode 100644 index c1a1729..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/gimp_png_preserve_colors.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/grass_models.png b/godot/addons/zylann.hterrain/doc/docs/images/grass_models.png deleted file mode 100644 index 2e9370f..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/grass_models.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/hole_painting.png b/godot/addons/zylann.hterrain/doc/docs/images/hole_painting.png deleted file mode 100644 index c9ad329..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/hole_painting.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png b/godot/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png deleted file mode 100644 index 702facd..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/ignore_tools_on_export.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/importer.png b/godot/addons/zylann.hterrain/doc/docs/images/importer.png deleted file mode 100644 index 84f372f..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/importer.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png b/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png deleted file mode 100644 index 3cca8f8..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png b/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png deleted file mode 100644 index e4c48a1..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/inspector_texture_set_save.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/lod_geometry.png b/godot/addons/zylann.hterrain/doc/docs/images/lod_geometry.png deleted file mode 100644 index 4b898be..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/lod_geometry.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png b/godot/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png deleted file mode 100644 index 3c5c939..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/lookdev_grass.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png b/godot/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png deleted file mode 100644 index 17b61c8..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/lookdev_menu.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png b/godot/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png deleted file mode 100644 index 0ef702b..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/lots_of_textures_blending.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/low_poly.png b/godot/addons/zylann.hterrain/doc/docs/images/low_poly.png deleted file mode 100644 index d518309..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/low_poly.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png b/godot/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png deleted file mode 100644 index ef9e4b1..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/normalmap_conventions.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/overview.png b/godot/addons/zylann.hterrain/doc/docs/images/overview.png deleted file mode 100644 index b84815a..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/overview.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/panel_import_button.png b/godot/addons/zylann.hterrain/doc/docs/images/panel_import_button.png deleted file mode 100644 index d0eb5b7..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/panel_import_button.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png b/godot/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png deleted file mode 100644 index 58b48b1..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/panel_textures_edit_button.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/pbr_textures.png b/godot/addons/zylann.hterrain/doc/docs/images/pbr_textures.png deleted file mode 100644 index ffc3188..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/pbr_textures.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/resize_tool.png b/godot/addons/zylann.hterrain/doc/docs/images/resize_tool.png deleted file mode 100644 index c78350e..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/resize_tool.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png b/godot/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png deleted file mode 100644 index dcfddf3..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/sculpting_tools.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png b/godot/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png deleted file mode 100644 index 1eb05e9..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/single_sampling_and_triplanar_sampling.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png b/godot/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png deleted file mode 100644 index 1320d58..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/slope_limit_tool.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png b/godot/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png deleted file mode 100644 index 5c9f008..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/splatmap_and_textured_result.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png deleted file mode 100644 index 17e0ea1..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_array_import_dock.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png deleted file mode 100644 index 6a04498..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_atlas_example.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_dialog.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_dialog.png deleted file mode 100644 index 431b5c9..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_dialog.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png deleted file mode 100644 index f80d478..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_editor.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png deleted file mode 100644 index bf5daf0..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png deleted file mode 100644 index 1ce61f0..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_directory.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png deleted file mode 100644 index 5a75cf8..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_success.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png deleted file mode 100644 index 55ce92a..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_set_import_tool_texture_types.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/texture_slots.png b/godot/addons/zylann.hterrain/doc/docs/images/texture_slots.png deleted file mode 100644 index cfebe7b..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/texture_slots.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png b/godot/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png deleted file mode 100644 index 37b9d2c..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/tiling_artifacts.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png b/godot/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png deleted file mode 100644 index af36cb3..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/tiling_reduction.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png b/godot/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png deleted file mode 100644 index 45d2c8e..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/transition_array_blending.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png b/godot/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png deleted file mode 100644 index 7c58aa5..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/update_editor_collider.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png b/godot/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png deleted file mode 100644 index 4e756f6..0000000 Binary files a/godot/addons/zylann.hterrain/doc/docs/images/warped_checker_variations.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/doc/docs/index.md b/godot/addons/zylann.hterrain/doc/docs/index.md deleted file mode 100644 index 6c79ab4..0000000 --- a/godot/addons/zylann.hterrain/doc/docs/index.md +++ /dev/null @@ -1,1104 +0,0 @@ -HTerrain plugin documentation -=============================== - -Overview ----------- - -This plugin allows to create heightmap-based terrains in Godot Engine. This kind of terrain uses 2D images, such as for heights or texturing information, which makes it cheap to implement while covering most use cases. - -It is entirely built on top of the `VisualServer` scripting API, which means it should be expected to work on all platforms supported by Godot's `GLES3` renderer. - -![Screenshot of the editor with the plugin enabled and arrows showing where UIs are](images/overview.png) - - -### Video tutorials - -This written doc should be the most up to date and precise information, but video tutorials exist for a quick start. - -- [Kasper's tutorial](https://www.youtube.com/watch?v=Af1f2JPvSIs) about version 1.5.2 (16 Jan 2021) -- [GamesFromScratch presentation](https://www.youtube.com/watch?v=jYVO0-_sXZs), also featuring the [WaterWays](https://github.com/Arnklit/WaterGenGodot) plugin (23 dec 2020) -- [qubodupDev's Tutorial](https://www.youtube.com/watch?v=k_ISq6JyVSs) about version 1.3.3 (27 aug 2020) -- [Old tutorial](https://www.youtube.com/watch?v=eZuvfIHDeT4&) about version 0.8 (10 aug 2018! A lot is outdated in it but let's keep it here for the record) - -### How to install - -You will need to use Godot 4.1 or later. - -To get the last version that supported Godot 3.x, checkout the `godot3` branch in the Git repository. - -#### Automatically - -In Godot, go to the Asset Library tab, search for the terrain plugin, download it and then install it. -Then you need to activate the plugin in your `ProjectSettings`. - -#### Manually - -The plugin can be found on the [Asset Library website](https://godotengine.org/asset-library/asset/231). The download will give you a `.zip` file. Decompress it at the root of your project. This should make it so the following hierarchy is respected: - -``` -addons/ - zylann.hterrain/ - -``` - -Then you need to activate the plugin in your `ProjectSettings`. - - -### How to update - -When a new version of the plugin comes up, you may want to update. If you re-run the same installation steps, it should work most of the time. However this is not a clean way to update, because files might have been renamed, moved or deleted, and they won't be cleaned up. This is an issue with Godot's plugin management in general (TODO: [make a proposal](https://github.com/godotengine/godot-proposals/issues)). - -So a cleaner way would be: - -- Turn off the plugin -- Close all your scenes (or close Godot entirely) -- Delete the `addons/zylann.hterrain` folder -- Then install the new version and enable it - - -### Development versions - -The latest development version of the plugin can be found on [Github](https://github.com/Zylann/godot_heightmap_plugin). -It is the most recently developed version, but might also have some bugs. - - -Creating a terrain --------------------- - -### Creating a HTerrain node - -Features of this plugin are mainly available from the `HTerrain` node. To create one, click the `+` icon at the top of the scene tree dock, and navigate to this node type to select it. - -There is one last step until you can work on the terrain: you need to specify a folder in which all the data will be stored. The reason is that terrain data is very heavy, and it's a better idea to store it separately from the scene. -Select the `HTerrain` node, and click on the folder icon to choose that folder. - -![Screenshot of the data dir property](images/data_directory_property.png) - -Once the folder is set, a default terrain should show up, ready to be edited. - -![Screenshot of the default terrain](images/default_terrain.png) - -!!! note - If you don't have a default environment, it's possible that you won't see anything, so make sure you either have one, or add a light to the scene to see it. Also, because terrains are pretty large (513 units by default), it is handy to change the view distance of the editor camera so that you can see further: go to `View`, `Options`, and then increase `far distance`. - -### Terrain dimensions - -By default, the terrain is a bit small, so if you want to make it bigger, there are two ways: - -- Modify `map_scale`, which will scale the ground without modifying the scale of all child nodes while using the same memory. As the scale cannot be equal or less than `0`, the limit of `0.01` (1 cm per cell) was set as an arbitrary safety guard. This value is still high enough to not run into precision floating-point problems. -- Use the `resize` tool in the `Terrain` menu, which will increase the resolution instead and take more memory. - -![Screenshot of the resize tool](images/resize_tool.png) - -If you use the `resize` tool, you can also choose to either stretch the existing terrain, or crop it by selecting an anchor point. Currently, this operation is permanent and cannot be undone, so if you want to go back, you should make a backup. - -!!! note - The resolution of the terrain is limited to powers of two + 1, mainly because of the way LOD was implemented. The reason why there is an extra 1 is down to the fact that to make 1 quad, you need 2x2 vertices. If you need LOD, you must have an even number of quads that you can divide by 2, and so on. However there is a possibility to tweak that in the future because this might not play well with the way older graphics cards store textures. - - -Sculpting ------------ - -### Brush types - -The default terrain is flat, but you may want to create hills and mountains. Because it uses a heightmap, editing this terrain is equivalent to editing an image. Because of this, the main tool is a brush with a configurable size and shape. You can see which area will be affected inside a 3D red circle appearing under your mouse, and you can choose how strong painting is by changing the `Brush opacity` slider. - -![Screenshot of the brush widget](images/brush_editor.png) - -To modify the heightmap, you can use the following brush modes, available at the top of the viewport: - -![Screenshot of the sculpting tools](images/sculpting_tools.png) - -- **Raise**: raises the height of the terrain to produce hills -- **Lower**: digs down to create crevices -- **Smooth**: smoothes heights locally -- **Level**: averages the heights within the radius of the brush until ground eventually becomes flat -- **Flatten**: directly sets the height to a given value, which can be useful as an eraser or to make plateaux. It is also possible to pick a height from the viewport using the picking button. -- **Erode**: smoothes the landscape by simulating erosion. When used on noisy terrain, it often produces characteristic shapes found in nature. - -!!! note - Heightmaps work best for hills and large mountains. Making sharp cliffs or walls are not recommended because it stretches geometry too much, and might cause issues with collisions. To make cliffs it's a better idea to place actual meshes on top. - -### Normals - -As you sculpt, the plugin automatically recomputes normals of the terrain, and saves it in a texture. This way, it can be used directly in ground shaders, grass shaders and previews at a smaller cost. Also, it allows to keep the same amount of details in the distance independently from geometry, which allows for levels of detail to work without affecting perceived quality too much. - - -### Collisions - -You can enable or disable collisions by checking the `Collisions enabled` property in the inspector. - -Heightmap-based terrains usually implement collisions directly using the heightmap, which saves a lot of computations compared to a classic mesh collider. - -![Screenshot of the option to choose physics engines in project settings](images/choose_bullet_physics.png) - -Some editor tools rely on colliders to work, such as snapping to ground or plugins like Scatter or other prop placement utilities. To make sure the collider is up to date, you can force it to update after sculpting with the `Terrain -> Update Editor Collider` menu: - -![Screenshot of the menu to update the collider](images/update_editor_collider.png) - -Note: if you use Godot 3.3, you need to make sure to use the Bullet physics engine in your project settings. - - -#### Known issues - -- **Updating the collider**: In theory, Bullet allows us to specify a direct reference to the image data. This would allow the collider to automatically update for free. However, we still had to duplicate the heightmap for safety, to avoid potential crashes if it gets mis-used. Even if we didn't copy it, the link could be broken anytime because of internal Copy-on-Write behavior in Godot. This is why the collider update is manual, because copying the heightmap results in an expensive operation. It can't be threaded as well because in Godot physics engines are not thread-safe yet. It might be improved in the future, hopefully. - -- **Misaligned collider in editor**: At time of writing, the Bullet integration has an issue about colliders in the editor if the terrain is translated, which does not happen in game: [Godot issue #37337](https://github.com/godotengine/godot/issues/37337) - - -### Holes - -It is possible to cut holes in the terrain by using the `Holes` brush. Use it with `draw holes` checked to cut them, and uncheck it to erase them. This can be useful if you want to embed a cave mesh or a well on the ground. You can still use the brush because holes are also a texture covering the whole terrain, and the ground shader will basically discard pixels that are over an area where pixels have a value of zero. - -![Screenshot with holes](images/hole_painting.png) - -At the moment, this brush uses the alpha channel of the color map to store where the holes are. - -!!! note - This brush only produces holes visually. In order to have holes in the collider too, you have to do some tricks with collision layers because the collision shape this plugin uses (Bullet heightfield) cannot have holes. It might be added in the future, because it can be done by editing the C++ code and drop collision triangles in the main heightmap collision routine. - - See [issue 125](https://github.com/Zylann/godot_heightmap_plugin/issues/125) - - -### Level of detail - -This terrain supports level of details on the geometry using a quad tree. It is divided in chunks of 32x32 (or 16x16 depending on your settings), which can be scaled by a power of two depending on the distance from the camera. If a group of 4 chunks are far enough, they will join into a single one. If a chunk is close enough, it will split in 4 smaller ones. Having chunks also improves culling because if you had a single big mesh for the whole terrain, that would be a lot of vertices for the GPU to go through. -Care is also taken to make sure transitions between LODs are seamless, so if you toggle wireframe rendering in the editor you can see variants of the same meshes being used depending on which LOD their neighbors are using. - -![Screenshot of how LOD vertices decimate in the distance](images/lod_geometry.png) - -LOD can be mainly tweaked in two ways: - -- `lod scale`: this is a factor determining at which distance chunks will split or join. The higher it is, the more details there will be, but the slower the game will be. The lower it is, the faster quality will decrease over distance, but will increase speed. -- `chunk size`: this is the base size of a chunk. There aren't many values that it can be, and it has a similar relation as `lod scale`. The difference is, it affects how many geometry instances will need to be culled and drawn, so higher values will actually reduce the number of draw calls. But if it's too big, it will take more memory due to all chunk variants that are precalculated. - -In the future, this technique could be improved by using GPU tessellation, once the Godot rendering engine supports it. GPU clipmaps are also a possibility, because at the moment the quad tree is updated on the CPU. - -!!! note - Due to limitations of the Godot renderer's scripting API, LOD only works around one main camera, so it's not possible to have two cameras with split-screen for example. Also, in the editor, LOD only works while the `HTerrain` node is selected, because it's the only time the EditorPlugin is able to obtain camera information (but it should work regardless when you launch the game). - - -Texturing ------------ - -### Overview - -Applying textures to terrains is a bit different than single models, because they are very large and a more optimal approach needs to be taken to keep memory and performance to an acceptable level. One very common way of doing it is by using a splatmap. A splatmap is another texture covering the whole terrain, whose role is to store which detail textures should be blended, and these textures may repeat seamlessly. - -![Screenshot showing splatmap and textured result](images/splatmap_and_textured_result.png) - -This magic is done with a single shader, i.e a single `ShaderMaterial` in Godot's terminology. This material is handled internally by the plugin, but you can customize it in several ways. - -There are mainly 3 families of shaders this plugin supports: - -- `CLASSIC4`: simple shaders where each texture may be a separate resource. They are limited to 4 textures. -- `MULTISPLAT16`: more advanced shader using more splatmaps and texture arrays. It's expensive but supports up to 16 textures. -- `ARRAY`: experimental shader also using texture arrays, which comes with constraints, but allows to paint a lot more different textures. -- Other shaders don't need textures, like `LOW_POLY`, which only uses colors. - -On the `HTerrain` node, there is a property called `shader_type`, which lets you choose among built-in shaders. The one you choose will define which workflow to follow: textures, or texture arrays. - -At time of writing, `CLASSIC4` shaders are better supported, and are the default choice. -Texture array shaders may be used more in the future. - - -### Getting PBR textures - -*If you only plan to use simple color textures, you can skip to [Texture Sets](#texture-sets).* - -Before you can paint textures, you have to set them up. It is recommended to pick textures which can tile infinitely, and preferably use "organic" ones, because terrains are best-suited for exterior natural environments. -For each texture, you may find the following types of images, common in PBR shading: - -- Albedo, color, or diffuse (required) -- Bump, height, or displacement (optional) -- Normal, or normalmap (optional) -- Roughness (optional) - -![Screenshot of PBR textures](images/pbr_textures.png) - -You can find some of these textures for free at [cc0textures.com](http://cc0textures.com). - -!!! note: Some shaders have a `Lite` and non-lite versions. One main difference between them is that `Lite` versions don't require normal maps, but the others require them. If you use a non-lite shader and forget to assign normal maps, shading will look wrong. - -It is preferable to place those source images under a specific directory. Also, since the images will only serve as an input to generate the actual game resources, it is better to place a `.gdignore` file inside that directory. This way, Godot will not include those source files in the exported game: - -``` -terrain_test/ - terrain_data/ - height.res - data.hterrain - ... - textures_src/ - .gdignore - grass_albedo.png - grass_bump.png - grass_normal.png - grass_roughness.png - rocks_albedo.png - rocks_bump.png - rocks_normal.png - rocks_roughness.png - ... - terrain_scene.tscn - ... -``` - -!!! note - While bump might not be used often, this plugin actually uses it to achieve [better blending effects](#depth-blending). - - -### Using the import tool - -Ground textures are stored in a `HTerrainTextureSet` resource. All terrains come with a default one. However, it can be tedious to setup every texture and pack them, especially if you need PBR. - -This plugin comes with an optional import tool. Select your `HTerrain` node, and in the bottom panel, click the `Import...` button: - -![Screenshot of bottom panel import button](images/panel_import_button.png) - -This brings up the import tool dialog: - -![Screenshot of the texture set import tool](images/texture_set_import_tool.png) - -#### Import mode - -One of the first important things is to decide which import mode you want to use: - -- `Textures`: For simple terrains with up to 4 textures (in use with `CLASSIC4` shaders) -- `TextureArrays`: For more complex terrains with up to 16 textures (in use with `MULTISPLAT16` and `ARRAY` shaders) - -This choice depends on the shader you will use for the terrain. Some shaders expect individual textures and others expect texture arrays. - -#### Smart file pick - -If you use PBR textures, there might be a lot of files to assign. If you use a naming convention, you can start loading an albedo texture, and the tool will attempt to find all the other maps automatically by recognizing other image file names. For example, using this convention may allow this shortcut to work: - -- `grass_albedo.png` -- `grass_bump.png` -- `grass_normal.png` -- `grass_roughness.png` - -![Screenshot of texture types in import tool](images/texture_set_import_tool_texture_types.png) - - -#### Normal maps - -As indicated in the [Godot documentation](https://docs.godotengine.org/en/stable/tutorials/3d/spatial_material.html#normal-map), normal maps are expected to use OpenGL convention (X+, Y+, Z+). So it is possible that normalmaps you find online use a different convention. - -To help with this, the import tool allows you to flip Y, in case the normalmap uses DirectX convention. - -![Examples of normalmap conventions](images/normalmap_conventions.png) - - -#### Importing - -When importing, this tool will need to generate a few files representing intermediate Godot resources. You may have to choose the directory where those resources will be created, otherwise they will be placed at the root of your project. - -![Screenshot of directory option in import tool](images/texture_set_import_tool_directory.png) - -Once everything is ready, you can click `Import`. This can take a little while. -If all goes well, a popup will tell you when it's done, and your terrain's texture set will be filled up with the imported textures. - -![Screenshot of import success](images/texture_set_import_tool_success.png) - -If importing goes wrong, most of the time an error will show up and the `HTerrainTextureSet` will not be modified. -If it succeeded but you are unhappy with the result, it is possible to undo the changes done to the terrain using `Ctrl+Z`. - -!!! note - - If you need to change something after the first import, you can go back to the importing tool and change settings, then click `Import` again. - - Importing with this tool will overwrite the whole set each time. - - The tool does not store the settings anywhere, but it should fill them up as much as it can from existing sets so you shouldn't need to fill everything up again. - - Custom importers are used as backend in order to support these features automatically, instead of default Godot importers. If you need more tinkering, you can take a look at [packed texture importers](#packed-texture-importers). - - -### Texture Sets - -#### Description - -`HTerrainTextureSet` is a custom resource which contains all textures a terrain can blend on the ground (grass, dirt, rocks, leaves, snow, sand...). All terrains come with an empty one assigned by default. - -The import tool seen earlier is the quickest way to fill one up from base textures, but it is not mandatory if you prefer to do things manually. - -You can inspect and edit the current set by selecting your `HTerrain` node, and in the bottom panel "Textures" section, click `Edit...`: - -![Screenshot of the bottom panel edit button](images/panel_textures_edit_button.png) - -This opens the following dialog: - -![Screenshot of the texture set editor](images/texture_set_editor.png) - -Unlike the import tool, this dialog shows you the actual resources used by the terrain. They may be either pairs of two packed textures for each slot, or two `TextureArray` resources. - -If you are using a `CLASSIC4` shader, you should be able to add and remove slots using the `+` and `-` buttons, and directly load color textures in the `Albedo` channel. -For using texture arrays or PBR textures, it might be better to use the [import tool](#getting-pbr-textures). - -Actions done in this dialog behave like an extension of the inspector, and can be undone with `Ctrl+Z`. - - -#### Re-using a texture set - -Texture sets are embedded in terrains by default, but it is possible to use the same set on another terrain. To do this, the `HTerrainTextureSet` must be saved as a `.tres` file. - -![Screenshot of texture set in the inspector](images/inspector_texture_set.png) - -- Select your `HTerrain` node -- In the inspector, right-click on the value of the `texture_set` property -- A HUGE menu will open (this is a Godot issue). Scroll all the way down with mouse wheel. -- Click the `Edit...` menu item to edit the resource -- On top of the inspector, a floppy disk icon should appear. You can click on it and choose `Save As...` - -![Screenshot of saving a texture set from inspector](images/inspector_texture_set_save.png) - -- A file dialog will prompt you for the location you want to put the resource file. Once you're done, click `Save`. - -Once you have a `.tres` file, you will be able to pick it up in your other terrain, by clicking on the `texture_set` property, but choosing `Load` this time. -You can also navigate to the `.tres` file in the `FileSystem` dock, then drag and drop to the property. - - -### Shader types - -#### Classic4 - -The `CLASSIC4` shader is a simple splatmap technique, where R, G, B, A match the weight of 4 respective textures. Then are all blended together in every pixel of the ground. Here is how it looks when applied: - -![Screenshot showing splatmap and textured result](images/splatmap_and_textured_result.png) - -It comes in two variants: - -- `CLASSIC4`: full-featured shader, however it requires your textures to have normal maps. If you don't assign them, shading will look wrong. -- `CLASSIC4_LITE`: simpler shader with less features. It only requires albedo textures. - - -#### MultiSplat16 - -the `MULTISPLAT16` shader is an extension of the splatmap technique, but uses 4 splatmaps instead of 1. It also uses `TextureArrays` instead of individual textures. It allows to support up to 16 textures at once, and can blend up to 4 in the same pixel. It dynamically chooses the 4 most-representative textures to blend them. - -It also comes in two variants: - -- `MULTISPLAT16`: full-featured shader, however it requires your texture arrays to have normal maps. -- `MULTISPLAT16_LITE`: simpler shader with less features. It only requires albedo texture arrays. - -It is the recommended choice if you need more than 4 textures, because it is much easier to use than the `ARRAY` shader and produces less artifacts. - -One downside is performance: it is about twice slower than `CLASSIC4` (on an nVidia 1060, a fullscreen `CLASSIC4` is 0.8 ms, while `MULTISPLAT16` is 1.8 ms). -Although, considering objects placed on the terrain should usually occlude ground pixels, the cost might be lower in a real game scenario. - - -#### LowPoly - -The `LOWPOLY` shader is the simplest shader. It produces a faceted look with only simple colors, and no textures. You will need to use the color brush to paint it. - -![Screenshot of the lowpoly shader](images/low_poly.png) - -!!! note - If you need faceted visuals with other shaders using textures, you can obtain the same result by [customizing the shader](#custom-shaders), and adding this line at the end of `fragment()`: - `NORMAL = normalize(cross(dFdx(VERTEX), dFdy(VERTEX)));` - - -#### Array - -**WARNING: this shader is still experimental. It's not ideal and has known flaws, so it may change in the future.** - -The `ARRAY` shader uses a more advanced technique to render ground textures. Instead of one splatmap and many individual textures, it uses a weightmap, an index map, and a `TextureArray`. - -The two maps are different from the classic one: - -- `SPLAT_INDEX`: this one stores the indexes of the textures to blend in every pixel of the ground. Indexes are stored respectively in R, G and B, and correspond to layers of the `TextureArray`. -- `SPLAT_WEIGHT`: this one stores the weight of the 3 textures to blend on each pixel. It only has R and G channels, because the third one can be inferred (their sum must be 1). - -This allows to paint up to 256 different textures, however it introduces an important constraint: you cannot blend more than 3 textures at a given pixel. - -Painting the proper indexes and weights can be a challenge, so for now, the plugin comes with a compromise. Each texture is assigned a fixed color component, R, G or B. So for a given texture, all textures that have an index separated by a multiple of 3 from this texture will not always be able to blend with it. For example, texture `2` might not blend with texture `5`, `8`, `11`, `14` etc. So choosing where you place textures in the `TextureArray` can be important. - -Here is a close-up on an area where some textures are not totally blending, because they use the same color component: - -![Bad transition](images/bad_array_blending.png) - -In this situation, another workaround is to use a transition texture: if A and B cannot blend, use texture C which can blend with A and B: - -![Fixed transition](images/transition_array_blending.png) - -You may see this pop up quite often when using this shader, but it can often be worked around. -The brush for this isn't perfect. This limitation can be smoothed out in the future, if a better algorithm is found which can work in real-time. - - -### Creating a `TextureArray` manually - -!!! note - It is now possible to use the [import tool](#using-the-import-tool) to set this up automatically. The following description explains how to do it manually. - -Contrary to `CLASSIC4` shaders, you cannot directly assign individual textures with a shader that requires `TextureArray`. Instead, you'll have to import one. - -1) With an image editor, create an image, which you subdivide in square tiles, like an atlas. I each of them, place one ground texture, like so: - -![Example of an atlas for creating a Texture Array](images/texture_atlas_example.png) - -2) Place that atlas in your Godot project. The editor will attempt to import it a first time, it can take a while if it's big. - -3) Select the atlas, and go to the `Import` dock. Change the import type to `TextureArray`. - -![Texture Array import dock](images/texture_array_import_dock.png) - -4) Make sure the `Repeat` mode is enabled. Then, change the tile counts below to match your grid. Once you're done, click `Re-import`. Godot will ask you to restart the editor, do that (I have no idea why). - -5) Once the editor has restarted, select your terrain node, and make sure it uses the `ARRAY` shader type (or a similar custom shader). In the bottom panel, click on the `Edit...` button to edit the `HTerrainTextureSet` used by the terrain. - -6) In the dialog, click on the `Load Array...` button under `Albedo` to load your texture array. You can do the same process with normal maps if needed. - -7) The bottom panel should now update to show much more texture slots. They will appear in the same order they are in the atlas, from left-to-right. If the panel doesn't update, select another node and click the terrain again. You should now be able to paint. - -![Lots of textures blending](images/lots_of_textures_blending.png) - - - -### Packing textures manually - -!!! note - It is now possible to use the [import tool](#using-the-import-tool) to set this up automatically. The following description explains how to do it manually. - -The main ground shaders provided by the plugin should work fine with only regular albedo, but it supports a few features to make the ground look more realistic, such as normal maps, bump and roughness. To achieve this, shaders expects packed textures. The main reason is that more than one texture has to be sampled at a time, to allow them to blend. With a classic splatmap, it's 4 at once. If we want normalmaps, it becomes 8, and if we want roughness it becomes 12 etc, which is already a lot, in addition to internal textures Godot uses in the background. Not all GPUs allow that many textures in the shader, so a better approach is to combine them as much as possible into single images. This reduces the number of texture units, and reduces the number of fetches to do in the pixel shader. - -![Screenshot of the channel packer plugin](images/channel_packer.png) - -For this reason, the plugin uses the following convention in ground textures: - -- `Albedo` in RGB, `Bump` in A -- `Normal` in RGB, `Roughness` in A - -This operation can be done in an image editing program such as Gimp, or with a Godot plugin such as [Channel Packer](https://godotengine.org/asset-library/asset/230). -It can also be done using [packed texture importers](packed-texture-importers), which are now included in the plugin. - -!!! note - Normal maps must follow the OpenGL convention, where Y goes up. They are recognizable by being "brighter" on the top of bumpy features (because Y is green, which is the most energetic color to the human eye): - - ![Examples of normalmap conventions](images/normalmap_conventions.png) - - See also [Godot's documentation notes about normal maps](https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_images.html#normal-map) - -!!! note - Because Godot would strip out the alpha channel if a packed texture was imported as a normal map, you should not make your texture import as "Normal Map" in the importer dock. - - -### Depth blending - -`Bump` textures holds a particular usage in this plugin: -You may have noticed that when you paint multiple textures, the terrain blends them together to produce smooth transitions. Usually, a classic way is to do a "transparency" transition using the splatmap. However, this rarely gives realistic visuals, so an option is to enable `depth blending` under `Shader Params`. - -![Screenshot of depth blending VS alpha blending](images/alpha_blending_and_depth_blending.png) - -This feature changes the way blending operates by taking the bump of the ground textures into account. For example, if you have sand blending with pebbles, at the transition you will see sand infiltrate between the pebbles because the pixels between pebbles have lower bump than the pebbles. You can see this technique illustrated in a [Gamasutra article](https://www.gamasutra.com/blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php). -It was tweaked a bit to work with 3 or 4 textures, and works best with fairly low brush opacity, around 10%. - - -### Triplanar mapping - -Making cliffs with a heightmap terrain is not recommended, because it stretches the geometry too much and makes textures look bad. Nevertheless, you can enable triplanar mapping on such texture in order for it to not look stretched. This option is in the shader section in the inspector. - -![Screenshot of triplanar mapping VS no triplanar](images/single_sampling_and_triplanar_sampling.png) - -In the case of the `CLASSIC4` shader, cliffs usually are made of the same ground texture, so it is only available for textures setup in the 4th slot, called `cliff`. It could be made to work on all slots, however it involves modifying the shader to add more options, which you may see in a later article. - -The `ARRAY` shader does not have triplanar mapping yet, but it may be added in the future. - - -### Tiling reduction - -The fact repeating textures are used for the ground also means they will not look as good at medium to far distance, due to the pattern it produces: - -![Screenshot of tiling artifacts](images/tiling_artifacts.png) - -On shaders supporting it, the `tile_reduction` parameter allows to break the patterns a bit to attenuate the effect: - -![Screenshot of reduced tiling artifacts](images/tiling_reduction.png) - -This option is present under the form of a `vec4`, where each component correspond to a texture, so you can enable it for some of them and not the others. Set a component to `1` to enable it, and `0` to disable it. - -This algorithm makes the shader sample the texture a second time, at a different orientation and scale, at semi-random areas of the ground: - -![Screenshot of the warped checker pattern used to break repetitions](images/warped_checker_variations.png) - -Here you can see where each of the two texture variants are being rendered. The pattern is a warped checker, which is simple enough to be procedural (avoiding the use of a noise texture), but organic enough so it shouldn't create artifacts itself. The result is made seamless by using depth blending (see [Depth blending](#depth-blending)). - -Although it's still possible to notice repetition over larger distances, this can be better covered by using a fade to global map (see [Global map](#global-map)). -In addition, many games don't present a naked terrain to players: there are usually many props on top of it, such as grass, vegetation, trees, rocks, buildings, fog etc. so overall tiling textures should not really be a big deal. - - -### Painting only on slopes - -The texture painting tool has a special option to limit the brush based on the slope of the terrain. This helps painting cliffs only or flat grounds only, without having to aim. It can even be used to paint a big area in one go, by increasing the brush size. - -![Screenshot of the slope limit tool](images/slope_limit_tool.png) - -The control consists in a two-ways slider. You can drag two handles. The left handle controls minimum slope, the right handle controls maximum slope. The range between the two handles determines which slopes the brush will paint on. - - -### Color tint - -You can color the terrain using the `Color` brush. This is pretty much modulating the albedo, which can help adding a touch of variety to the landscape. If you make custom shader tweaks, color can also be used for your own purpose if you need to. - -![Screenshot with color painting](images/color_painting.png) - -Depending on the shader, you may be able to choose which textures are affected by the colormap. - - -### Global map - -For shading purposes, it can be useful to bake a global map of the terrain. A global map takes the average albedo of the ground all over the terrain, which allows other elements of the scene to use that without having to recompute the full blending process that the ground shader goes through. The current use cases for a global map is to tint grass, and use it as a distance fade in order to hide texture tiling in the very far distance. Together with the terrain's normal map it could also be used to make minimap previews. - -To bake a global map, select the `HTerrain` node, go to the `Terrain` menu and click `Bake global map`. This will produce a texture in the terrain data directory which will be used by the default shaders automatically, depending on your settings. - -If you use a custom shader, you can define a specific one to use for the global map, by assigning the `custom_globalmap_shader` property. This is usually a stripped-down version of the main ground shader, where only `ALBEDO` is important. - -!!! note - The globalmap is also used in the minimap to show the color of the terrain. - - -Terrain generator -------------------- - -Basic sculpting tools can be useful to get started or tweaking, but it's cumbersome to make a whole terrain only using them. For larger scale terrain modeling, procedural techniques are often preferred, and then adjusted later on. - -This plugin provides a simple procedural generator. To open it, click on the `HTerrain` node to see the `Terrain` menu, in which you select `generate...`. Note that you should have a properly setup terrain node before you can use it. - -![Screenshot of the terrain generator](images/generator.png) - -The generator is quite simple and combines a few common techniques to produce a heightmap. You can see a 3D preview which can be zoomed in with the mouse wheel and rotated by dragging holding middle click. - -### Height range - -`height range` and `base height` define which is the minimum and maximum heights of the terrain. The result might not be exactly reaching these boundaries, but it is useful to determine in which region the generator has to work in. - -### Perlin noise - -Perlin noise is very common in terrain generation, and this one is no exception. Multiple octaves (or layers) of noise are added together at varying strength, forming a good base that already looks like a good environment. - -The usual parameters are available: - -- `seed`: this chooses the random seed the perlin noise will be based on. Same number gives the same landscape. -- `offset`: this chooses where in the landscape the terrain will be cropped into. You can also change that setting by panning the preview with the right mouse button held. -- `scale`: expands or shrinks the length of the patterns. Higher scale gives lower-frequency relief. -- `octaves`: how many layers of noise to use. The more octaves, the more details there will be. -- `roughness`: this controls the strength of each octave relatively to the previous. The more you increase it, the more rough the terrain will be, as high-frequency octaves get a higher weight. - -Try to tweak each of them to get an idea of how they affect the final shape. - -### Erosion - -The generator features morphological erosion. Behind this barbaric name hides a simple image processing algorithm, ![described here](https://en.wikipedia.org/wiki/Erosion_(morphology)). -In the context of terrains, what it does is to quickly fake real-life erosion, where rocks might slide along the slopes of the mountains over time, giving them a particular appearance. Perlin noise alone is nice, but with erosion it makes the result look much more realistic. - -![Screenshot with the effect of erosion](images/erosion_steps.png) - -It's also possible to use dilation, which gives a mesa-like appearance. - -![Screenshot with the effect of dilation](images/dilation.png) - -There is also a slope direction parameter, this one is experimental but it has a tendency to simulate wind, kind of "pushing" the ground in the specified direction. It can be tricky to find a good value for this one but I left it because it can give interesting results, like sand-like ripples, which are an emergent behavior. - -![Screenshot of slope erosion](images/erosion_slope.png) - -!!! note - Contrary to previous options, erosion is calculated over a bunch of shader passes. In Godot 3, it is only possible to wait for one frame to be rendered every 16 milliseconds, so the more erosion steps you have, the slower the preview will be. In the future it would be nice if Godot allowed multiple frames to be rendered on demand so the full power of the GPU could be used. - -### Applying - -Once you are happy with the result, you can click "Apply", which will calculate the generated terrain at full scale on your scene. This operation currently can't be undone, so if you want to go back you should make a backup. - - -Import an existing terrain ------------------------------ - -Besides using built-in tools to make your landscape, it can be convenient to import an existing one, which you might have made in specialized software such as WorldMachine, Scape or Lithosphere. - -### Import dialog - -To do this, select the `HTerrain` node, click on the `Terrain` menu and chose `Import`. -This window allows you to import several kinds of data, such as heightmap but also splatmap or color map. - -![Screenshot of the importer](images/importer.png) - -There are a few things to check before you can successfully import a terrain though: - -- The resolution should be power of two + 1, and square. If it isn't, the plugin will attempt to crop it, which might be OK or not if you can deal with map borders that this will produce. -- If you import a RAW heightmap, it has to be encoded using either 16-bit or 32-bit unsigned integer format. Upon selecting a file via the file chooser dialog, the importer will attempt to deduce the bit depth. -- If you import a PNG heightmap, Godot can only load it as 8-bit depth, so it is not recommended for high-range terrains because it doesn't have enough height precision. - -This feature also can't be undone when executed, as all terrain data will be overwritten with the new one. If anything isn't correct, the tool will warn you before to prevent data loss. - -It is possible that the height range you specify doesn't works out that well after you see the result, so for now it is possible to just re-open the importer window, change the height scale and apply again. - - -### 4-channel splatmaps caveat - -Importing a 4-channel splatmap requires an RGBA image, where each channel will be used to represent the weight of a texture. However, if you are creating a splatmap by going through an image editor, *you must make sure the color data is preserved*. - -Most image editors assume you create images to be seen. When you save a PNG, they assume fully-transparent areas don't need to store any color data, because they are invisible. The RGB channels are then compressed away, which can cause blocky artifacts when imported as a splatmap. - -To deal with this, make sure your editor has an option to turn this off. In Gimp, for example, this option is here: - -![Screenshot of the importer](images/gimp_png_preserve_colors.png) - - -Detail layers ---------------- - -Once you have textured ground, you may want to add small detail objects to it, such as grass and small rocks. - -![Screenshot of two grass layers under the terrain node](images/detail_layers.png) - -### Painting details - -Grass is supported through `HTerrainDetailLayer` node. They can be created as children of the `HTerrain` node. Each layer represents one kind of detail, so you may have one layer for grass, and another for flowers, for example. - -Detail layers come in two parts: - -- A 8-bit density texture covering the whole terrain, also called a "detail map" at the moment. You can see how many maps the terrain has in the bottom panel after selecting the terrain. -- A `HTerrainDetailLayer` node, which uses one of the detail maps to render instanced models based on the density. - -You can paint detail maps just like you paint anything else, using the same brush system. It uses opacity to either add more density, or act as an eraser with an opacity of zero. -`HTerrainDetailLayer` nodes will then update in realtime, rendering more or less instances in places you painted. - -!!! note - A detail map can be used by more than one node (by setting the same index in their `layer_index` property), so you can have one for grass, another for flowers, and paint on the shared map to see both nodes update at the same time. - -By default the positions and rotations of each detail is not deterministic, this can be changed by setting fixed_seed_enabled to true on the `HterrainDetailLayer`. - -### Shading options - -At the moment, detail layers only come with a single shader type, which is made for grass. More may be added in the future. - -You can choose which texture will be used, and it will be rendered using alpha-scissor. It is done that way because it allows drawing grass in the opaque render pass, which is cheaper than treating every single quad like a transparent object which would have to be depth-sorted to render properly. Alpha-to-coverage would look better, but isn't supported in Godot 3. - -Like the ground, detail layers use a custom shader that takes advantage of the heightmap to displace each instanced object at a proper position. Also, hardware instancing is used under the hood to allow for a very high number of items with low cost. Multimeshes are generated in chunks, and then instances are hidden from the vertex shader depending on density. For grass, it also uses the normal of the ground so there is no need to provide it. There are also shader options to tint objects with the global map, which can help a lot making grass to blend better with the environment. - -Finally, the shader fades in the distance by increasing the threshold of alpha scissor. This works better with a transparent texture. An alternative is to make it sink in the ground, but that's left to customization. - -For writing custom shaders, see [Custom detail shaders](#grass-shaders). - -### Meshes - -By default, detail layers draw simple quads on top of the ground. But it is possible to choose another kind of geometry, by assigning the `instance_mesh` property. -Several meshes are bundled with the plugin, which you can find in `res://addons/zylann.hterrain/models/`. - -![Bundled grass models](images/grass_models.png) - -They are all thought for grass rendering. You can make your own for things that aren't grass, however there is no built-in shader for conventional objects at the moment (rocks, bits and bobs). So if you want normal shading you need to write a custom shader. That may be bundled too in the future. - -!!! note - Detail meshes must be `Mesh` resources, so the easiest way is to use the `OBJ` format. If you use `GLTF` or `FBX`, Godot will import it as a scene by default, so you may have to configure it to import as single mesh if possible. - - -Custom shaders ------------------ - -This plugin comes with default shaders, but you are allowed to modify them and change things to match your needs. The plugin does not expose materials directly because it needs to set built-in parameters that are always necessary, and some of them cannot be properly saved as material properties, if at all. - -### Ground shaders - -In order to write your own ground shader, select the `HTerrain` node, and change the shader type to `Custom`. Then, select the `custom shader` property and choose `New Shader`. This will create a new shader which is pre-filled with the same source code as the last built-in shader you had selected. Doing it this way can help seeing how every feature is done and find your own way into implementing customizations. - -The plugin does not actually hardcode its features based on its built-in shaders. Instead, it looks at which `uniform` parameters your shader defines, and adapts in consequence. -A list of `uniform` parameters are recognized, some of which are required for heightmap rendering to work: - -Parameter name | Type | Format | Description -------------------------------------|------------------|---------|-------------- -`u_terrain_heightmap` | `sampler2D` | `RH` | The heightmap, a 32-bit float texture which can be sampled in the red channel. Like the other following maps, you have to access it using cell coordinates, which can be computed as seen in the built-in shader. -`u_terrain_normalmap` | `sampler2D` | `RGB8` | The precalculated normalmap of the terrain, which you can use instead of computing it from the heightmap -`u_terrain_colormap` | `sampler2D` | `RGBA8` | The color map, which is the one modified by the color brush. The alpha channel is used for holes. -`u_terrain_splatmap` | `sampler2D` | `RGBA8` | The classic 4-component splatmap, where each channel determines the weight of a given texture. The sum of each channel across all splatmaps must be 1.0. -`u_terrain_splatmap_1` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_splatmap_2` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_splatmap_3` | `sampler2D` | `RGBA8` | Additional splatmap -`u_terrain_globalmap` | `sampler2D` | `RGB8` | The global albedo map. -`u_terrain_splat_index_map` | `sampler2D` | `RGB8` | An index map, used for texturing based on a `TextureArray`. the R, G and B components multiplied by 255.0 will provide the index of the texture. -`u_terrain_splat_weight_map` | `sampler2D` | `RG8` | A 2-component weight map where a 3rd component can be obtained with `1.0 - r - g`, used for texturing based on a `TextureArray`. The sum of R and G must be 1.0. -`u_ground_albedo_bump_0`...`3` | `sampler2D` | `RGBA8` | These are up to 4 albedo textures for the ground, which you have to blend using the splatmap. Their alpha channel can contain bump. -`u_ground_normal_roughness_0`...`3` | `sampler2D` | `RGBA8` | Similar to albedo, these are up to 4 normal textures to blend using the splatmap. Their alpha channel can contain roughness. -`u_ground_albedo_bump_array` | `sampler2DArray` | `RGBA8` | Equivalent of the previous individual albedo textures, as an array. The plugin knows you use this texturing technique by checking the existence of this parameter. -`u_ground_normal_roughness_array` | `sampler2DArray` | `RGBA8` | Equivalent of the previous individual normalmap textures, as an array. -`u_terrain_inverse_transform` | `mat4x4` | | A 4x4 matrix containing the inverse transform of the terrain. This is useful if you need to calculate the position of the current vertex in world coordinates in the vertex shader, as seen in the builtin shader. -`u_terrain_normal_basis` | `mat3x3` | | A 3x3 matrix containing the basis used for transforming normals. It is not always needed, but if you use `map scale` it is required to keep them correct. - -You don't have to declare them all. It's fine if you omit some of them, which is good because it frees a slot in the limited amount of `uniforms`, especially for texture units. -Other parameters are not used by the plugin, and are shown procedurally under the `Shader params` section of the `HTerrain` node. - - -### Grass shaders - -Detail layers follow the same design as ground shaders. In order to make your own, select the `custom shader` property and assign it a new empty shader. This will also fork the built-in shader, which at the moment is specialized into rendering grass quads. - -They share the following parameters with ground shaders: - -- `u_terrain_heightmap` -- `u_terrain_normalmap` -- `u_terrain_globalmap` -- `u_terrain_inverse_transform` - -And there also have specific parameters which you can use: - -Parameter name | Type | Format | Description -------------------------------------|------------------|---------|-------------- -`u_terrain_detailmap` | `sampler2D` | `R8` | This one contains the grass density, from 0 to 1. Depending on this, you may hide instances by outputting degenerate triangles, or let them pass through. The builtin shader contains an example. -`u_albedo_alpha` | `sampler2D` | `RGBA8` | This is the texture applied to the whole model, typically transparent grass. -`u_view_distance` | `float` | | How far details are supposed to render. Beyond this range, the plugin will cull chunks away, so it is a good idea to use this in the shader to smoothly fade pixels in the distance to hide this process. -`u_ambient_wind` | `vec2` | | Combined `vec2` parameter for ambient wind. `x` is the amplitude, and `y` is a time value. It is better to use it instead of directly `TIME` because it allows to animate speed without causing stutters. - - -### Lookdev - -The plugin features an experimental debugging feature in the `Terrain` menu called "Lookdev". It temporarily replaces the ground shader with a simpler one which displays the raw value of a specific map. For example, you can see the actual values taken by a detail map by choosing one of them in the menu: - -![Screenshot of detail map seen with lookdev shader](images/lookdev_grass.png) - -It is very simple at the moment but it can also be used to display data maps which are not necessarily used for rendering. So you could also use it to paint them, even if they don't translate into a visual element in the game. - -To turn it off, select `Disabled` in the menu. - -![Screenshot of detail map seen with lookdev shader](images/lookdev_menu.png) - -!!! note - The heightmap cannot be seen with this feature because its values extend beyond usual color ranges. - - -Scripting --------------- - -### Overview - -Scripts relevant to in-game functionality are located under the plugin's root folder, `res://addons/zylann.hterrain/`. - -``` -res:// -- addons/ - - zylann.hterrain/ - - doc/ - - models/ <-- Models used for grass - - native/ <-- GDNative library - - shaders/ - - tools/ <-- Editor-specific stuff, don't use in game - - util/ <-- Various helper scripts - - - hterrain.gd <-- The HTerrain node - - hterrain_data.gd <-- The HTerrainData resource - - hterrain_detail_layer.gd <-- The HTerrainDetailLayer node - - - (other stuff used internally) -``` - -This plugin does not use global class names, so to use or hint one of these types, you may want to "const-import" them on top of your script, like so: - -```gdscript -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -``` - -There is no API documentation yet, so if you want to see which functions and properties are available, take a look at the source code in the editor. -Functions and properties beginning with a `_` are private and should not be used directly. - - -### Creating the terrain from script - -You can decide to create the terrain from a script. Here is an example: - -```gdscript -extends Node - -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") - -func _ready(): - var data = HTerrainData.new() - data.resize(513) - - var terrain = HTerrain.new() - terrain.set_data(data) - add_child(terrain) -``` - -### Modifying terrain from script - -The terrain is described by several types of large textures, such as heightmap, normal map, grass maps, color map and so on. Modifying the terrain boils down to modifying them using the `Image` API. - -For example, this code will tint the ground red at a specific position (in pixels, not world space): - -```gdscript -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") - -@onready var _terrain = $Path/To/Terrain - -func test(): - # Get the image - var data : HTerrainData = _terrain.get_data() - var colormap : Image = data.get_image(HTerrainData.CHANNEL_COLOR) - - # Modify the image - var position = Vector2(42, 36) - colormap.set_pixel(position, Color(1, 0, 0)) - - # Notify the terrain of our change - data.notify_region_changed(Rect2(position.x, position.y, 1, 1), HTerrainData.CHANNEL_COLOR) -``` - -The same goes for the heightmap and grass maps, however at time of writing, there are several issues with editing it in game: - -- Normals of the terrain don't automatically update, you have to calculate them yourself by also modifying the normalmap. This is a bit tedious and expensive, however it may be improved in the future. Alternatively you could compute them in shader, but it makes rendering a bit more expensive. -- The collider won't update either, for the same reason mentioned in the [section about collisions in the editor](#Collisions). You can force it to update by calling `update_collider()` but it can cause a hiccup. - - -### Procedural generation - -It is possible to generate the terrain data entirely from script. It may be quite slow if you don't take advantage of GPU techniques (such as using a compute viewport), but it's still useful to copy results to the terrain or editing it like the plugin does in the editor. - -Again, we can use the `Image` resource to modify pixels. -Here is a full GDScript example generating a terrain from noise and 3 textures: - -```gdscript -extends Node - -# Import classes -const HTerrain = preload("res://addons/zylann.hterrain/hterrain.gd") -const HTerrainData = preload("res://addons/zylann.hterrain/hterrain_data.gd") -const HTerrainTextureSet = preload("res://addons/zylann.hterrain/hterrain_texture_set.gd") - -# You may want to change paths to your own textures -var grass_texture = load("res://addons/zylann.hterrain_demo/textures/ground/grass_albedo_bump.png") -var sand_texture = load("res://addons/zylann.hterrain_demo/textures/ground/sand_albedo_bump.png") -var leaves_texture = load("res://addons/zylann.hterrain_demo/textures/ground/leaves_albedo_bump.png") - - -func _ready(): - # Create terrain resource and give it a size. - # It must be either 513, 1025, 2049 or 4097. - var terrain_data = HTerrainData.new() - terrain_data.resize(513) - - var noise = FastNoiseLite.new() - var noise_multiplier = 50.0 - - # Get access to terrain maps - var heightmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_HEIGHT) - var normalmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_NORMAL) - var splatmap: Image = terrain_data.get_image(HTerrainData.CHANNEL_SPLAT) - - # Generate terrain maps - # Note: this is an example with some arbitrary formulas, - # you may want to come up with your owns - for z in heightmap.get_height(): - for x in heightmap.get_width(): - # Generate height - var h = noise_multiplier * noise.get_noise_2d(x, z) - - # Getting normal by generating extra heights directly from noise, - # so map borders won't have seams in case you stitch them - var h_right = noise_multiplier * noise.get_noise_2d(x + 0.1, z) - var h_forward = noise_multiplier * noise.get_noise_2d(x, z + 0.1) - var normal = Vector3(h - h_right, 0.1, h_forward - h).normalized() - - # Generate texture amounts - var splat = splatmap.get_pixel(x, z) - var slope = 4.0 * normal.dot(Vector3.UP) - 2.0 - # Sand on the slopes - var sand_amount = clamp(1.0 - slope, 0.0, 1.0) - # Leaves below sea level - var leaves_amount = clamp(0.0 - h, 0.0, 1.0) - splat = splat.linear_interpolate(Color(0,1,0,0), sand_amount) - splat = splat.linear_interpolate(Color(0,0,1,0), leaves_amount) - - heightmap.set_pixel(x, z, Color(h, 0, 0)) - normalmap.set_pixel(x, z, HTerrainData.encode_normal(normal)) - splatmap.set_pixel(x, z, splat) - - # Commit modifications so they get uploaded to the graphics card - var modified_region = Rect2(Vector2(), heightmap.get_size()) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_HEIGHT) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_NORMAL) - terrain_data.notify_region_change(modified_region, HTerrainData.CHANNEL_SPLAT) - - # Create texture set - # NOTE: usually this is not made from script, it can be built with editor tools - var texture_set = HTerrainTextureSet.new() - texture_set.set_mode(HTerrainTextureSet.MODE_TEXTURES) - texture_set.insert_slot(-1) - texture_set.set_texture(0, HTerrainTextureSet.TYPE_ALBEDO_BUMP, grass_texture) - texture_set.insert_slot(-1) - texture_set.set_texture(1, HTerrainTextureSet.TYPE_ALBEDO_BUMP, sand_texture) - texture_set.insert_slot(-1) - texture_set.set_texture(2, HTerrainTextureSet.TYPE_ALBEDO_BUMP, leaves_texture) - - # Create terrain node - var terrain = HTerrain.new() - terrain.set_shader_type(HTerrain.SHADER_CLASSIC4_LITE) - terrain.set_data(terrain_data) - terrain.set_texture_set(texture_set) - add_child(terrain) - - # No need to call this, but you may need to if you edit the terrain later on - #terrain.update_collider() -``` - - -### Reload while the game is running - -If your want to reload a terrain without restarting the game, you can do the following with a script: - -```gdscript -# Reload terrain data from files, disregarding cached resources -terrain.data.reload() - -# Update the collider, as it won't update automatically -terrain.update_collider() -``` - -So the following workflow is possible: - -- While the game runs, do some changes to the terrain in the editor -- Save the scene containing the terrain -- Optional: tab in/out of Godot to make sure terrain textures get re-imported (if you don't do it, only the heightmap will update and shading might look wrong in changed areas) -- Press a hotkey in the game calling the code that reloads the terrain. - - -Export ----------- - -The plugin should work normally in exported games, but there are some files you should be able to remove because they are editor-specific. This allows to reduce the size from the executable a little. - -Everything under `res://addons/zylann.hterrain/tools/` folder is required for the plugin to work in the editor, but it can be removed in exported games. You can specify this folder in your export presets: - -![Screenshot of the export window with tools folder ignored](images/ignore_tools_on_export.png) - -The documentation in `res://addons/zylann.hterrain/doc/` can also be removed, but this one contains a `.gdignore` file so hopefully Godot will automatically ignore it even in the editor. - - -GDNative ------------ - -This plugin contains an optional native component, which speeds up some operations such as sculpting the terrain. However, at time of writing, a prebuilt binary is built-in only on `Windows` and `Linux`, I'm not yet able to build for other platforms so you may need to do it yourself, until I can provide an official one. - -Before doing this, it's preferable to close the Godot editor so it won't lock the library files. -Note that these steps are very similar to GDNative C++ development, which repeats parts of [Godot's documentation](https://docs.godotengine.org/en/3.2/tutorials/plugins/gdnative/gdnative-cpp-example.html). - -### Building instructions - -To build the library, you will need to install the following: - -- Python 3.6 or later -- The SCons build system -- A C++ compiler -- The Git version control system - -#### If you got the plugin from the asset library - -You will need to download C++ bindings for Godot. Go to `res://addons/zylann.hterrain/native`, open a command prompt, and run the following commands: - -``` -git clone https://github.com/GodotNativeTools/godot-cpp -cd godot-cpp -git submodule update --init --recursive -``` - -#### If you cloned the plugin using Git - -In this case the C++ bindings submodule will already be there, and will need to be updated. Go to `res://addons/zylann.hterrain/native`, open a command prompt, and run the following commands: - -``` -git submodule update --init --recursive target=release -``` - -#### Build C++ bindings - -Now go to `res://addons/zylann.hterrain/native/cpp-bindings`, open a command prompt (or re-use the one you have already), and run this command: - -``` -scons platform= generate_bindings=yes target=release -``` - -`yourplatform` must match the platform you want to build for. It should be one of the following: - -- `windows` -- `linux` -- `osx` - -#### Build the HTerrain library - -Go back to `res://addons/zylann.hterrain/native`, and run this command, which has similar options as the one we saw before: - -``` -scons platform= target=release -``` - -This will produce a library file under the `bin/` folder. - -### Register the library - -Now the last step is to tell the plugin the library is available. In the `native/` folder, open the `hterrain.gdnlib` resource in a text editor, and add the path to the library under the `[entry]` category. Here is an example of how it should look like for several platforms: - -``` -[general] - -singleton=false -load_once=true -symbol_prefix="godot_" -reloadable=false - -[entry] - -OSX.64 = "res://addons/zylann.hterrain/native/bin/osx64/libhterrain_native.dylib" -OSX.32 = "res://addons/zylann.hterrain/native/bin/osx32/libhterrain_native.dylib" -Windows.64 = "res://addons/zylann.hterrain/native/bin/win64/libhterrain_native.dll" -X11.64 = "res://addons/zylann.hterrain/native/bin/linux/libhterrain_native.so" - -[dependencies] - -Windows.64=[ ] -X11.64=[ ] -``` - -Finally, open the `factory.gd` script, and add an OS entry for your platform. The plugin should now be ready to use the native library. - -### Debugging - -If you get a crash or misbehavior, check logs first to make sure Godot was able to load the library. If you want to use a C++ debugger, you can repeat this setup, only replacing `release` with `debug` when running SCons. This will then allow you to attach to Godot and place breakpoints (which works best if you also use a debug Godot version). - - -Troubleshooting ------------------ - -We do the best we can on our free time to make this plugin usable, but it's possible bugs appear. Some of them are known issues. If you have a problem, please refer to the [issue tracker](https://github.com/Zylann/godot_heightmap_plugin/issues). - - -### Before reporting any bug - -- Make sure you have the latest version of the plugin -- Make sure it hasn't been reported already (including closed issues) -- Check your Godot version. This plugin only works starting from Godot 3.1, and does not support 4.x yet. It is also possible that some issues exist in Godot 3.1 but could only be fixed in later versions. -- Make sure you are using the GLES3 renderer. GLES2 is not supported. -- Make sure your addons folder is located at `res://addons`, and does not contain uppercase letters. This might work on Windows but it will break after export. - - -### If you report a new bug - -If none of the initial checks help and you want to post a new issue, do the following: - -- Check the console for messages, warnings and errors. These are helpful to diagnose the issue. -- Try to reproduce the bug with precise reproduction steps, and indicate them -- Provide a test project with those steps (unless it's reproducible from an empty project), so that we can reproduce the bug and fix it more easily. Github allows you to drag-and-drop zip files. -- Indicate your OS, Godot version and graphics card model. Those are present in logs as well. - - -### Terrain not saving / not up to date / not showing - -This issue happened a few times and had various causes so if the checks mentioned before don't help: - -- Check the contents of your terrain's data folder. It must contain a `.hterrain` file and a few textures. -- If they are present, make sure Godot has imported those textures. If it didn't, unfocus the editor, and focus it back (you should see a short progress bar as it does it) -- Check if you used Ctrl+Z (undo) after a non-undoable action, like described in [issue #101](https://github.com/Zylann/godot_heightmap_plugin/issues/101) -- Make sure your `res://addons` folder is named `addons` *exactly lowercase*. It should not be named `Addons`. Plugins can fail if this convention is not respected. -- If your problem relates to collisions in editor, update the collider using `Terrain -> Update Editor Collider`, because this one does not update automatically yet -- Godot seems to randomly forget where the terrain saver is, but I need help to find out why because I could never reproduce it. See [issue #120](https://github.com/Zylann/godot_heightmap_plugin/issues/120) - - -### Temporary files - -The plugin creates temporary files to avoid cluttering memory. They are necessary for some functionalities to work. Those files should be cleaned up automatically when you close the editor or if you turn off the plugin. However, if a crash occurs or something else goes wrong, they might not get removed. If you want to check them out, they are located in `user://hterrain_image_cache`. - -On Windows, that directory corresponds to `C:\Users\Username\AppData\Roaming\Godot\app_userdata\ProjectName\hterrain_image_cache`. - -See [Godot's documentation](https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#editor-data-paths) for other platforms. diff --git a/godot/addons/zylann.hterrain/doc/mkdocs.yml b/godot/addons/zylann.hterrain/doc/mkdocs.yml deleted file mode 100644 index 9f01702..0000000 --- a/godot/addons/zylann.hterrain/doc/mkdocs.yml +++ /dev/null @@ -1,11 +0,0 @@ -site_name: HTerrain plugin documentation -theme: readthedocs - -markdown_extensions: - # Makes permalinks appear on headings - - toc: - permalink: True - # Makes boxes for notes and warnings - - admonition - # Better highlighter which supports GDScript - - codehilite diff --git a/godot/addons/zylann.hterrain/doc/requirements.txt b/godot/addons/zylann.hterrain/doc/requirements.txt deleted file mode 100644 index 3143080..0000000 --- a/godot/addons/zylann.hterrain/doc/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -mkdocs>=1.1.2 \ No newline at end of file diff --git a/godot/addons/zylann.hterrain/hterrain.gd b/godot/addons/zylann.hterrain/hterrain.gd deleted file mode 100644 index 1d98c00..0000000 --- a/godot/addons/zylann.hterrain/hterrain.gd +++ /dev/null @@ -1,1757 +0,0 @@ -@tool -extends Node3D - -const HT_NativeFactory = preload("./native/factory.gd") -const HT_Mesher = preload("./hterrain_mesher.gd") -const HT_Grid = preload("./util/grid.gd") -const HTerrainData = preload("./hterrain_data.gd") -const HTerrainChunk = preload("./hterrain_chunk.gd") -const HTerrainChunkDebug = preload("./hterrain_chunk_debug.gd") -const HT_Util = preload("./util/util.gd") -const HTerrainCollider = preload("./hterrain_collider.gd") -const HTerrainTextureSet = preload("./hterrain_texture_set.gd") -const HT_Logger = preload("./util/logger.gd") - -const SHADER_CLASSIC4 = "Classic4" -const SHADER_CLASSIC4_LITE = "Classic4Lite" -const SHADER_LOW_POLY = "LowPoly" -const SHADER_ARRAY = "Array" -const SHADER_MULTISPLAT16 = "MultiSplat16" -const SHADER_MULTISPLAT16_LITE = "MultiSplat16Lite" -const SHADER_CUSTOM = "Custom" - -const MIN_MAP_SCALE = 0.01 - -# Note, the `str()` syntax is no longer accepted in constants in Godot 4 -const _SHADER_TYPE_HINT_STRING = \ - "Classic4," + \ - "Classic4Lite," + \ - "LowPoly," + \ - "Array," + \ - "MultiSplat16," + \ - "MultiSplat16Lite," + \ - "Custom" - -# TODO Had to downgrade this to support Godot 3.1. -# Referring to other constants with this syntax isn't working... -#const _SHADER_TYPE_HINT_STRING = str( -# SHADER_CLASSIC4, ",", -# SHADER_CLASSIC4_LITE, ",", -# SHADER_LOW_POLY, ",", -# SHADER_ARRAY, ",", -# SHADER_CUSTOM -#) - -const _builtin_shaders = { - SHADER_CLASSIC4: { - path = "res://addons/zylann.hterrain/shaders/simple4.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/simple4_global.gdshader" - }, - SHADER_CLASSIC4_LITE: { - path = "res://addons/zylann.hterrain/shaders/simple4_lite.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/simple4_global.gdshader" - }, - SHADER_LOW_POLY: { - path = "res://addons/zylann.hterrain/shaders/low_poly.gdshader", - global_path = "" # Not supported - }, - SHADER_ARRAY: { - path = "res://addons/zylann.hterrain/shaders/array.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/array_global.gdshader" - }, - SHADER_MULTISPLAT16: { - path = "res://addons/zylann.hterrain/shaders/multisplat16.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/multisplat16_global.gdshader" - }, - SHADER_MULTISPLAT16_LITE: { - path = "res://addons/zylann.hterrain/shaders/multisplat16_lite.gdshader", - global_path = "res://addons/zylann.hterrain/shaders/multisplat16_global.gdshader" - } -} - -const _NORMAL_BAKER_PATH = "res://addons/zylann.hterrain/tools/normalmap_baker.gd" -const _LOOKDEV_SHADER_PATH = "res://addons/zylann.hterrain/shaders/lookdev.gdshader" - -const SHADER_PARAM_INVERSE_TRANSFORM = "u_terrain_inverse_transform" -const SHADER_PARAM_NORMAL_BASIS = "u_terrain_normal_basis" - -const SHADER_PARAM_GROUND_PREFIX = "u_ground_" # + name + _0, _1, _2, _3... - -# Those parameters are filtered out in the inspector, -# because they are not supposed to be set through it -const _api_shader_params = { - "u_terrain_heightmap": true, - "u_terrain_normalmap": true, - "u_terrain_colormap": true, - "u_terrain_splatmap": true, - "u_terrain_splatmap_1": true, - "u_terrain_splatmap_2": true, - "u_terrain_splatmap_3": true, - "u_terrain_splat_index_map": true, - "u_terrain_splat_weight_map": true, - "u_terrain_globalmap": true, - - "u_terrain_inverse_transform": true, - "u_terrain_normal_basis": true, - - "u_ground_albedo_bump_0": true, - "u_ground_albedo_bump_1": true, - "u_ground_albedo_bump_2": true, - "u_ground_albedo_bump_3": true, - - "u_ground_normal_roughness_0": true, - "u_ground_normal_roughness_1": true, - "u_ground_normal_roughness_2": true, - "u_ground_normal_roughness_3": true, - - "u_ground_albedo_bump_array": true, - "u_ground_normal_roughness_array": true -} - -const _api_shader_ground_albedo_params = { - "u_ground_albedo_bump_0": true, - "u_ground_albedo_bump_1": true, - "u_ground_albedo_bump_2": true, - "u_ground_albedo_bump_3": true -} - -const _ground_texture_array_shader_params = [ - "u_ground_albedo_bump_array", - "u_ground_normal_roughness_array" -] - -const _splatmap_shader_params = [ - "u_terrain_splatmap", - "u_terrain_splatmap_1", - "u_terrain_splatmap_2", - "u_terrain_splatmap_3" -] - -const MIN_CHUNK_SIZE = 16 -const MAX_CHUNK_SIZE = 64 - -# Same as HTerrainTextureSet.get_texture_type_name, used for shader parameter names. -# Indexed by HTerrainTextureSet.TYPE_* -const _ground_enum_to_name = [ - "albedo_bump", - "normal_roughness" -] - -const _DEBUG_AABB = false - -signal transform_changed(global_transform) - -@export_range(0.0, 1.0) var ambient_wind : float: - get: - return ambient_wind - set(amplitude): - if ambient_wind == amplitude: - return - ambient_wind = amplitude - for layer in _detail_layers: - layer.update_material() - - -@export_range(2, 5) var lod_scale := 2.0: - get: - return _lodder.get_split_scale() - set(value): - _lodder.set_split_scale(value) - - -# Prefer using this instead of scaling the node's transform. -# Node3D.scale isn't used because it's not suitable for terrains, -# it would scale grass too and other environment objects. -# TODO Replace with `size` in world units? -@export var map_scale := Vector3(1, 1, 1): - get: - return map_scale - set(p_map_scale): - if map_scale == p_map_scale: - return - p_map_scale.x = maxf(p_map_scale.x, MIN_MAP_SCALE) - p_map_scale.y = maxf(p_map_scale.y, MIN_MAP_SCALE) - p_map_scale.z = maxf(p_map_scale.z, MIN_MAP_SCALE) - map_scale = p_map_scale - _on_transform_changed() - - -@export var centered := false: - get: - return centered - set(p_centered): - if p_centered == centered: - return - centered = p_centered - _on_transform_changed() - - -var _custom_shader : Shader = null -var _custom_globalmap_shader : Shader = null -var _shader_type := SHADER_CLASSIC4_LITE -var _shader_uses_texture_array := false -var _material := ShaderMaterial.new() -var _material_params_need_update := false -# Possible values are the same as the enum `GeometryInstance.SHADOW_CASTING_SETTING_*`. -var _cast_shadow_setting := GeometryInstance3D.SHADOW_CASTING_SETTING_ON - -var _render_layer_mask := 1 - -# Actual number of textures supported by the shader currently selected -var _ground_texture_count_cache := 0 - -var _used_splatmaps_count_cache := 0 -var _is_using_indexed_splatmap := false - -var _texture_set := HTerrainTextureSet.new() -var _texture_set_migration_textures = null - -var _data: HTerrainData = null - -var _mesher := HT_Mesher.new() -var _lodder = HT_NativeFactory.get_quad_tree_lod() -var _viewer_pos_world := Vector3() - -# [lod][z][x] -> chunk -# This container owns chunks -var _chunks := [] -var _chunk_size: int = 32 -var _pending_chunk_updates := [] - -var _detail_layers := [] - -var _collision_enabled := true -var _collider: HTerrainCollider = null -var _collision_layer := 1 -var _collision_mask := 1 -var _physics_material : PhysicsMaterial = null - -# Stats & debug -var _updated_chunks := 0 -var _logger = HT_Logger.get_for(self) - -# Editor-only -var _normals_baker = null - -var _lookdev_enabled := false -var _lookdev_material : ShaderMaterial - - -func _init(): - _logger.debug("Create HeightMap") - # This sets up the defaults. They may be overridden shortly after by the scene loader. - - _lodder.set_callbacks(_cb_make_chunk, _cb_recycle_chunk, _cb_get_vertical_bounds) - - set_notify_transform(true) - - # TODO Temporary! - # This is a workaround for https://github.com/godotengine/godot/issues/24488 - _material.set_shader_parameter("u_ground_uv_scale", 20) - _material.set_shader_parameter("u_ground_uv_scale_vec4", Color(20, 20, 20, 20)) - _material.set_shader_parameter("u_depth_blending", true) - - _material.shader = load(_builtin_shaders[_shader_type].path) - - _texture_set.changed.connect(_on_texture_set_changed) - - if _collision_enabled: - if _check_heightmap_collider_support(): - _collider = HTerrainCollider.new(self, _collision_layer, _collision_mask) - - -func _get_property_list(): - # A lot of properties had to be exported like this instead of using `export`, - # because Godot 3 does not support easy categorization and lacks some hints - var props = [ - { - # Terrain data is exposed only as a path in the editor, - # because it can only be saved if it has a directory selected. - # That property is not used in scene saving (data is instead). - "name": "data_directory", - "type": TYPE_STRING, - "usage": PROPERTY_USAGE_EDITOR, - "hint": PROPERTY_HINT_DIR - }, - { - # The actual data resource is only exposed for storage. - # I had to name it so that Godot won't try to assign _data directly - # instead of using the setter I made... - "name": "_terrain_data", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - # This actually triggers `ERROR: Cannot get class`, - # if it were to be shown in the inspector. - # See https://github.com/godotengine/godot/pull/41264 - "hint_string": "HTerrainData" - }, - { - "name": "chunk_size", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - #"hint": PROPERTY_HINT_ENUM, - "hint_string": "16, 32" - }, - { - "name": "Collision", - "type": TYPE_NIL, - "usage": PROPERTY_USAGE_GROUP - }, - { - "name": "collision_enabled", - "type": TYPE_BOOL, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE - }, - { - "name": "collision_layer", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_PHYSICS - }, - { - "name": "collision_mask", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_PHYSICS - }, - { - "name": "physics_material", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_DEFAULT, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "PhysicsMaterial" - }, - { - "name": "Rendering", - "type": TYPE_NIL, - "usage": PROPERTY_USAGE_GROUP - }, - { - "name": "shader_type", - "type": TYPE_STRING, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_ENUM, - "hint_string": _SHADER_TYPE_HINT_STRING - }, - { - "name": "custom_shader", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Shader" - }, - { - "name": "custom_globalmap_shader", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Shader" - }, - { - "name": "texture_set", - "type": TYPE_OBJECT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_RESOURCE_TYPE, - "hint_string": "Resource" - # TODO Cannot properly hint the type of the resource in the inspector. - # This triggers `ERROR: Cannot get class 'HTerrainTextureSet'` - # See https://github.com/godotengine/godot/pull/41264 - #"hint_string": "HTerrainTextureSet" - }, - { - "name": "render_layers", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_LAYERS_3D_RENDER - }, - { - "name": "cast_shadow", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE, - "hint": PROPERTY_HINT_ENUM, - "hint_string": "Off,On,DoubleSided,ShadowsOnly" - } - ] - - if _material.shader != null: - var shader_params := _material.shader.get_shader_uniform_list(true) - for p in shader_params: - if _api_shader_params.has(p.name): - continue - var cp := {} - for k in p: - cp[k] = p[k] - # Godot has two ways of grouping properties in the inspector: - # - Prefixed properties using "/", which is part of the API property names - # - Group items in property lists, which are only a hint for the inspector display. - # - # In this plugin, just like ShaderMaterial, we need to nest shader parameters under - # a prefix to prevent conflicts with non-shader properties, which Godot interprets as - # a folder in the inspector. - # - # Godot 4.0 introduced `group_uniforms` in shaders, which also adds group items to - # shader property lists. When such groups are present, it creates repeating subgroups, - # which isn't desired. - # One way to workaround it is to set the `hint_string` of group items, to tell Godot to - # somewhat "ignore" the prefix when displaying them in the inspector, which will get - # rid of the unnecessary folders. - # We also have to prefix the parent group if any. - # - # Caveats: inspector will not display those uniforms under the `shader_params` folder. - # Not sure if we can get around that. ShaderMaterial has the same problem, and actually - # seems to do WAY more stuff to handle group_uniforms, so not sure if this simple code - # here is missing something. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/394 - if p.usage == PROPERTY_USAGE_GROUP: - cp.name = "Rendering/" + cp.name - cp.hint_string = "shader_params/" - else: - cp.name = str("shader_params/", p.name) - props.append(cp) - - return props - - -func _get(key: StringName): - if key == &"data_directory": - return _get_data_directory() - - if key == &"_terrain_data": - if _data == null or _data.resource_path == "": - # Consider null if the data is not set or has no path, - # because in those cases we can't save the terrain properly - return null - else: - return _data - - if key == &"texture_set": - return get_texture_set() - - elif key == &"shader_type": - return get_shader_type() - - elif key == &"custom_shader": - return get_custom_shader() - - elif key == &"custom_globalmap_shader": - return _custom_globalmap_shader - - elif key.begins_with("shader_params/"): - var param_name := key.substr(len("shader_params/")) - return get_shader_param(param_name) - - elif key == &"chunk_size": - return _chunk_size - - elif key == &"collision_enabled": - return _collision_enabled - - elif key == &"collision_layer": - return _collision_layer - - elif key == &"collision_mask": - return _collision_mask - - elif key == &"physics_material": - return _physics_material - - elif key == &"render_layers": - return get_render_layer_mask() - - elif key == &"cast_shadow": - return _cast_shadow_setting - - -func _set(key: StringName, value): - if key == &"data_directory": - _set_data_directory(value) - - # Can't use setget when the exported type is custom, - # because we were also are forced to use _get_property_list... - elif key == &"_terrain_data": - set_data(value) - - elif key == &"texture_set": - set_texture_set(value) - - # Legacy, left for migration from 1.4 - var key_str := String(key) - if key_str.begins_with("ground/"): - for ground_texture_type in HTerrainTextureSet.TYPE_COUNT: - var type_name = _ground_enum_to_name[ground_texture_type] - if key_str.begins_with(str("ground/", type_name, "_")): - var i = key_str.substr(len(key_str) - 1).to_int() - if _texture_set_migration_textures == null: - _texture_set_migration_textures = [] - while i >= len(_texture_set_migration_textures): - _texture_set_migration_textures.append([null, null]) - var texs = _texture_set_migration_textures[i] - texs[ground_texture_type] = value - - elif key == &"shader_type": - set_shader_type(value) - - elif key == &"custom_shader": - set_custom_shader(value) - - elif key == &"custom_globalmap_shader": - _custom_globalmap_shader = value - - elif key.begins_with("shader_params/"): - var param_name := String(key).substr(len("shader_params/")) - set_shader_param(param_name, value) - - elif key == &"chunk_size": - set_chunk_size(value) - - elif key == &"collision_enabled": - set_collision_enabled(value) - - elif key == &"collision_layer": - _collision_layer = value - if _collider != null: - _collider.set_collision_layer(value) - - elif key == &"collision_mask": - _collision_mask = value - if _collider != null: - _collider.set_collision_mask(value) - - elif key == &"physics_material": - set_physics_material(value) - - elif key == &"render_layers": - return set_render_layer_mask(value) - - elif key == &"cast_shadow": - set_cast_shadow(value) - - -func get_texture_set() -> HTerrainTextureSet: - return _texture_set - - -func set_texture_set(new_set: HTerrainTextureSet): - if _texture_set == new_set: - return - - if _texture_set != null: - # TODO This causes `ERROR: Nonexistent signal 'changed' in [Resource:36653]` for some reason - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = new_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - - _material_params_need_update = true - - -func _on_texture_set_changed(): - _material_params_need_update = true - HT_Util.update_configuration_warning(self, false) - - -func get_shader_param(param_name: String): - return HT_Util.get_shader_material_parameter(_material, param_name) - - -func set_shader_param(param_name: String, v): - _material.set_shader_parameter(param_name, v) - - -func set_render_layer_mask(mask: int): - _render_layer_mask = mask - _for_all_chunks(HT_SetRenderLayerMaskAction.new(mask)) - - -func get_render_layer_mask() -> int: - return _render_layer_mask - - -func set_cast_shadow(setting: int): - if setting == _cast_shadow_setting: - return - _cast_shadow_setting = setting - _for_all_chunks(HT_SetCastShadowSettingAction.new(setting)) - - -func get_cast_shadow() -> int: - return _cast_shadow_setting - - -func _set_data_directory(dirpath: String): - if dirpath != _get_data_directory(): - if dirpath == "": - set_data(null) - else: - var fpath := dirpath.path_join(HTerrainData.META_FILENAME) - if FileAccess.file_exists(fpath): - # Load existing - var d = load(fpath) - if d == null: - # Logging this explicitely because otherwise all the log would say is - # that terrain data failed to load. Adding this info gives more context. - _logger.error("Could not load existing data: {}".format([fpath])) - set_data(d) - else: - # Create new - var d := HTerrainData.new() - d.resource_path = fpath - set_data(d) - # TODO This is an attempt to workaround an issue that has plagued the plugin for years. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/232 - # For some reason, randomly, Godot decies to NOT save the resource and leave - # the data directory empty (no .hterrain file) when the user creates a new - # terrain, assigns a data directory and saves the scene. - # Ideally data should only be saved if the user saves the scene... but given - # this random issue (which to this day is still not figured out!) then we - # force saving to be done when assigning a new path. - d.save_data(fpath.get_base_dir()) - else: - _logger.warn("Setting twice the same terrain directory??") - - -func _get_data_directory() -> String: - if _data != null: - return _data.resource_path.get_base_dir() - return "" - - -func _check_heightmap_collider_support() -> bool: - return true - # var v = Engine.get_version_info() - # if v.major == 3 and v.minor == 0 and v.patch < 4: - # _logger.error("Heightmap collision shape not supported in this version of Godot," - # + " please upgrade to 3.0.4 or later") - # return false - # return true - - -func set_collision_enabled(enabled: bool): - if _collision_enabled != enabled: - _collision_enabled = enabled - if _collision_enabled: - if _check_heightmap_collider_support(): - _collider = HTerrainCollider.new(self, _collision_layer, _collision_mask) - _collider.update_physics_material(_physics_material) - # Collision is not updated with data here, - # because loading is quite a mess at the moment... - # 1) This function can be called while no data has been set yet - # 2) I don't want to update the collider more times than necessary - # because it's expensive - # 3) I would prefer not defer that to the moment the terrain is - # added to the tree, because it would screw up threaded loading - else: - # Despite this object being a Reference, - # this should free it, as it should be the only reference - _collider = null - - -func set_physics_material(new_physics_material: PhysicsMaterial) -> void: - if new_physics_material == _physics_material: - return - - if _physics_material != null: - _physics_material.changed.disconnect(_on_physics_material_changed) - - _physics_material = new_physics_material - - if _physics_material != null: - _physics_material.changed.connect(_on_physics_material_changed) - - _on_physics_material_changed() - - -func _on_physics_material_changed() -> void: - if _collider != null: - _collider.update_physics_material(_physics_material) - - -func _for_all_chunks(action): - for lod in len(_chunks): - var grid = _chunks[lod] - for y in len(grid): - var row = grid[y] - for x in len(row): - var chunk = row[x] - if chunk != null: - action.exec(chunk) - - -func get_chunk_size() -> int: - return _chunk_size - - -func set_chunk_size(p_cs: int): - assert(typeof(p_cs) == TYPE_INT) - _logger.debug(str("Setting chunk size to ", p_cs)) - var cs := HT_Util.next_power_of_two(p_cs) - if cs < MIN_CHUNK_SIZE: - cs = MIN_CHUNK_SIZE - if cs > MAX_CHUNK_SIZE: - cs = MAX_CHUNK_SIZE - if p_cs != cs: - _logger.debug(str("Chunk size snapped to ", cs)) - if cs == _chunk_size: - return - _chunk_size = cs - _reset_ground_chunks() - - -# Compat -func set_map_scale(p_map_scale: Vector3): - map_scale = p_map_scale - - -# Compat -func set_centered(p_centered: bool): - centered = p_centered - - -# Gets the global transform to apply to terrain geometry, -# which is different from Node3D.global_transform gives. -# global_transform must only have translation and rotation. Scale support is undefined. -func get_internal_transform() -> Transform3D: - var gt := global_transform - var it := Transform3D(gt.basis * Basis().scaled(map_scale), gt.origin) - if centered and _data != null: - var half_size := 0.5 * (_data.get_resolution() - 1.0) - it.origin += it.basis * (-Vector3(half_size, 0, half_size)) - return it - - -func get_internal_transform_unscaled(): - var gt := global_transform - if centered and _data != null: - var half_size := 0.5 * (_data.get_resolution() - 1.0) - # Map scale still has an effect on origin when the map is centered - gt.origin += gt.basis * (-Vector3(half_size, 0, half_size) * map_scale) - return gt - - -# Converts a world-space position into a map-space position. -# Map space X and Z coordinates correspond to pixel coordinates of the heightmap. -func world_to_map(world_pos: Vector3) -> Vector3: - return get_internal_transform().affine_inverse() * world_pos - - -func _notification(what: int): - match what: - NOTIFICATION_PREDELETE: - _logger.debug("Destroy HTerrain") - # Note: might get rid of a circular ref in GDScript port - _clear_all_chunks() - - NOTIFICATION_ENTER_WORLD: - _logger.debug("Enter world") - - if _texture_set_migration_textures != null and _texture_set.get_slots_count() == 0: - # Convert from 1.4 textures properties to HTerrainTextureSet - # TODO Unfortunately this might not always work, - # once again because Godot wants the editor's UndoRedo to have modified the - # resource for it to be saved... which sucks, sucks, and sucks. - # I'll never say it enough. - _texture_set.set_mode(HTerrainTextureSet.MODE_TEXTURES) - while _texture_set.get_slots_count() < len(_texture_set_migration_textures): - _texture_set.insert_slot(-1) - for slot_index in len(_texture_set_migration_textures): - var texs = _texture_set_migration_textures[slot_index] - for type in len(texs): - _texture_set.set_texture(slot_index, type, texs[type]) - _texture_set_migration_textures = null - - _for_all_chunks(HT_EnterWorldAction.new(get_world_3d())) - if _collider != null: - _collider.set_world(get_world_3d()) - _collider.set_transform(get_internal_transform()) - - NOTIFICATION_EXIT_WORLD: - _logger.debug("Exit world") - _for_all_chunks(HT_ExitWorldAction.new()) - if _collider != null: - _collider.set_world(null) - - NOTIFICATION_TRANSFORM_CHANGED: - _on_transform_changed() - - NOTIFICATION_VISIBILITY_CHANGED: - _logger.debug("Visibility changed") - _for_all_chunks(HT_VisibilityChangedAction.new(is_visible_in_tree())) - - -func _on_transform_changed(): - _logger.debug("Transform changed") - - if not is_inside_tree(): - # The transform and other properties can be set by the scene loader, - # before we enter the tree - return - - var gt = get_internal_transform() - - _for_all_chunks(HT_TransformChangedAction.new(gt)) - - _material_params_need_update = true - - if _collider != null: - _collider.set_transform(gt) - - transform_changed.emit(gt) - - -func _enter_tree(): - _logger.debug("Enter tree") - - if Engine.is_editor_hint() and _normals_baker == null: - _normals_baker = load(_NORMAL_BAKER_PATH).new() - add_child(_normals_baker) - _normals_baker.set_terrain_data(_data) - - set_process(true) - - -func _clear_all_chunks(): - # The lodder has to be cleared because otherwise it will reference dangling pointers - _lodder.clear() - - #_for_all_chunks(DeleteChunkAction.new()) - - for i in len(_chunks): - _chunks[i].clear() - - -func _get_chunk_at(pos_x: int, pos_y: int, lod: int) -> HTerrainChunk: - if lod < len(_chunks): - return HT_Grid.grid_get_or_default(_chunks[lod], pos_x, pos_y, null) - return null - - -func get_data() -> HTerrainData: - return _data - - -func has_data() -> bool: - return _data != null - - -func set_data(new_data: HTerrainData): - assert(new_data == null or new_data is HTerrainData) - - _logger.debug(str("Set new data ", new_data)) - - if _data == new_data: - return - - if has_data(): - _logger.debug("Disconnecting old HeightMapData") - _data.resolution_changed.disconnect(_on_data_resolution_changed) - _data.region_changed.disconnect(_on_data_region_changed) - _data.map_changed.disconnect(_on_data_map_changed) - _data.map_added.disconnect(_on_data_map_added) - _data.map_removed.disconnect(_on_data_map_removed) - - if _normals_baker != null: - _normals_baker.set_terrain_data(null) - _normals_baker.queue_free() - _normals_baker = null - - _data = new_data - - # Note: the order of these two is important - _clear_all_chunks() - - if has_data(): - _logger.debug("Connecting new HeightMapData") - - # This is a small UX improvement so that the user sees a default terrain - if is_inside_tree() and Engine.is_editor_hint(): - if _data.get_resolution() == 0: - _data._edit_load_default() - - if _collider != null: - _collider.create_from_terrain_data(_data) - - _data.resolution_changed.connect(_on_data_resolution_changed) - _data.region_changed.connect(_on_data_region_changed) - _data.map_changed.connect(_on_data_map_changed) - _data.map_added.connect(_on_data_map_added) - _data.map_removed.connect(_on_data_map_removed) - - if _normals_baker != null: - _normals_baker.set_terrain_data(_data) - - _on_data_resolution_changed() - - _material_params_need_update = true - - HT_Util.update_configuration_warning(self, true) - - _logger.debug("Set data done") - - -# The collider might be used in editor for other tools (like snapping to floor), -# so the whole collider can be updated in one go. -# It may be slow for ingame use, so prefer calling it when appropriate. -func update_collider(): - assert(_collision_enabled) - assert(_collider != null) - _data.check_images() - _collider.create_from_terrain_data(_data) - - -func _on_data_resolution_changed(): - _reset_ground_chunks() - - for layer in _detail_layers: - layer.on_heightmap_resolution_changed() - - -func _reset_ground_chunks(): - if _data == null: - return - - _clear_all_chunks() - - _pending_chunk_updates.clear() - - _lodder.create_from_sizes(_chunk_size, _data.get_resolution()) - - _chunks.resize(_lodder.get_lod_count()) - - var cres := _data.get_resolution() / _chunk_size - var csize_x := cres - var csize_y := cres - - for lod in _lodder.get_lod_count(): - _logger.debug(str("Create grid for lod ", lod, ", ", csize_x, "x", csize_y)) - var grid = HT_Grid.create_grid(csize_x, csize_y) - _chunks[lod] = grid - csize_x /= 2 - csize_y /= 2 - - _mesher.configure(_chunk_size, _chunk_size, _lodder.get_lod_count()) - - -func _on_data_region_changed(min_x, min_y, size_x, size_y, channel): - # Testing only heights because it's the only channel that can impact geometry and LOD - if channel == HTerrainData.CHANNEL_HEIGHT: - set_area_dirty(min_x, min_y, size_x, size_y) - - if _normals_baker != null: - _normals_baker.request_tiles_in_region(Vector2(min_x, min_y), Vector2(size_x, size_y)) - - for layer in _detail_layers: - layer.on_heightmap_region_changed(Rect2i(min_x, min_y, size_x, size_y)) - - -func _on_data_map_changed(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL \ - or type == HTerrainData.CHANNEL_HEIGHT \ - or type == HTerrainData.CHANNEL_NORMAL \ - or type == HTerrainData.CHANNEL_GLOBAL_ALBEDO: - - for layer in _detail_layers: - layer.update_material() - - if type != HTerrainData.CHANNEL_DETAIL: - _material_params_need_update = true - - -func _on_data_map_added(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL: - for layer in _detail_layers: - # Shift indexes up since one was inserted - if layer.layer_index >= index: - layer.layer_index += 1 - layer.update_material() - else: - _material_params_need_update = true - HT_Util.update_configuration_warning(self, true) - - -func _on_data_map_removed(type: int, index: int): - if type == HTerrainData.CHANNEL_DETAIL: - for layer in _detail_layers: - # Shift indexes down since one was removed - if layer.layer_index > index: - layer.layer_index -= 1 - layer.update_material() - else: - _material_params_need_update = true - HT_Util.update_configuration_warning(self, true) - - -func get_shader_type() -> String: - return _shader_type - - -func set_shader_type(type: String): - if type == _shader_type: - return - _shader_type = type - - if _shader_type == SHADER_CUSTOM: - _material.shader = _custom_shader - else: - _material.shader = load(_builtin_shaders[_shader_type].path) - - _material_params_need_update = true - - if Engine.is_editor_hint(): - notify_property_list_changed() - - -func get_custom_shader() -> Shader: - return _custom_shader - - -func set_custom_shader(shader: Shader): - if _custom_shader == shader: - return - - if _custom_shader != null: - _custom_shader.changed.disconnect(_on_custom_shader_changed) - - if Engine.is_editor_hint() and shader != null and is_inside_tree(): - # When the new shader is empty, allow to fork from the previous shader - if shader.code.is_empty(): - _logger.debug("Populating custom shader with default code") - var src := _material.shader - if src == null: - src = load(_builtin_shaders[SHADER_CLASSIC4].path) - shader.code = src.code - # TODO If code isn't empty, - # verify existing parameters and issue a warning if important ones are missing - - _custom_shader = shader - - if _shader_type == SHADER_CUSTOM: - _material.shader = _custom_shader - - if _custom_shader != null: - _custom_shader.changed.connect(_on_custom_shader_changed) - if _shader_type == SHADER_CUSTOM: - _material_params_need_update = true - - if Engine.is_editor_hint(): - notify_property_list_changed() - - -func _on_custom_shader_changed(): - _material_params_need_update = true - notify_property_list_changed() - - -func _update_material_params(): - assert(_material != null) - _logger.debug("Updating terrain material params") - - var terrain_textures := {} - var res := Vector2(-1, -1) - - var lookdev_material : ShaderMaterial - if _lookdev_enabled: - lookdev_material = _get_lookdev_material() - - # TODO Only get textures the shader supports - - if has_data(): - for map_type in HTerrainData.CHANNEL_COUNT: - var count := _data.get_map_count(map_type) - for i in count: - var param_name: String = HTerrainData.get_map_shader_param_name(map_type, i) - terrain_textures[param_name] = _data.get_texture(map_type, i) - res.x = _data.get_resolution() - res.y = res.x - - # Set all parameters from the terrain system. - - if is_inside_tree(): - var gt := get_internal_transform() - var t := gt.affine_inverse() - _material.set_shader_parameter(SHADER_PARAM_INVERSE_TRANSFORM, t) - - # This is needed to properly transform normals if the terrain is scaled - var normal_basis = gt.basis.inverse().transposed() - _material.set_shader_parameter(SHADER_PARAM_NORMAL_BASIS, normal_basis) - - if lookdev_material != null: - lookdev_material.set_shader_parameter(SHADER_PARAM_INVERSE_TRANSFORM, t) - lookdev_material.set_shader_parameter(SHADER_PARAM_NORMAL_BASIS, normal_basis) - - for param_name in terrain_textures: - var tex = terrain_textures[param_name] - _material.set_shader_parameter(param_name, tex) - if lookdev_material != null: - lookdev_material.set_shader_parameter(param_name, tex) - - if _texture_set != null: - match _texture_set.get_mode(): - HTerrainTextureSet.MODE_TEXTURES: - var slots_count := _texture_set.get_slots_count() - for type in HTerrainTextureSet.TYPE_COUNT: - for slot_index in slots_count: - var texture := _texture_set.get_texture(slot_index, type) - var shader_param := _get_ground_texture_shader_param_name(type, slot_index) - _material.set_shader_parameter(shader_param, texture) - - HTerrainTextureSet.MODE_TEXTURE_ARRAYS: - for type in HTerrainTextureSet.TYPE_COUNT: - var texture_array := _texture_set.get_texture_array(type) - var shader_params := _get_ground_texture_array_shader_param_name(type) - _material.set_shader_parameter(shader_params, texture_array) - - _shader_uses_texture_array = false - _is_using_indexed_splatmap = false - _used_splatmaps_count_cache = 0 - - var shader := _material.shader - if shader != null: - var param_list := RenderingServer.get_shader_parameter_list(shader.get_rid()) - _ground_texture_count_cache = 0 - for p in param_list: - if _api_shader_ground_albedo_params.has(p.name): - _ground_texture_count_cache += 1 - elif p.name == "u_ground_albedo_bump_array": - _shader_uses_texture_array = true - elif p.name == "u_terrain_splat_index_map": - _is_using_indexed_splatmap = true - elif p.name in _splatmap_shader_params: - _used_splatmaps_count_cache += 1 - - -# TODO Rename is_shader_using_texture_array() -# Tells if the current shader is using a texture array. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func is_using_texture_array() -> bool: - return _shader_uses_texture_array - - -# Gets how many splatmaps the current shader is using. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func get_used_splatmaps_count() -> int: - return _used_splatmaps_count_cache - - -# Tells if the current shader is using a splatmap type based on indexes and weights. -# This will only be valid once the material has been updated internally. -# (for example it won't be valid before the terrain is added to the SceneTree) -func is_using_indexed_splatmap() -> bool: - return _is_using_indexed_splatmap - - -static func _get_common_shader_params(shader1: Shader, shader2: Shader) -> Array: - var shader1_param_names := {} - var common_params := [] - - var shader1_params := RenderingServer.get_shader_parameter_list(shader1.get_rid()) - var shader2_params := RenderingServer.get_shader_parameter_list(shader2.get_rid()) - - for p in shader1_params: - shader1_param_names[p.name] = true - - for p in shader2_params: - if shader1_param_names.has(p.name): - common_params.append(p.name) - - return common_params - - -# Helper used for globalmap baking -func setup_globalmap_material(mat: ShaderMaterial): - mat.shader = get_globalmap_shader() - if mat.shader == null: - _logger.error("Could not find a shader to use for baking the global map.") - return - # Copy all parameters shaders have in common - var common_params = _get_common_shader_params(mat.shader, _material.shader) - for param_name in common_params: - var v = _material.get_shader_parameter(param_name) - mat.set_shader_parameter(param_name, v) - - -# Gets which shader will be used to bake the globalmap -func get_globalmap_shader() -> Shader: - if _shader_type == SHADER_CUSTOM: - if _custom_globalmap_shader != null: - return _custom_globalmap_shader - _logger.warn("The terrain uses a custom shader but doesn't have one for baking the " - + "global map. Will attempt to use a built-in shader.") - if is_using_texture_array(): - return load(_builtin_shaders[SHADER_ARRAY].global_path) as Shader - return load(_builtin_shaders[SHADER_CLASSIC4].global_path) as Shader - return load(_builtin_shaders[_shader_type].global_path) as Shader - - -# Compat -func set_lod_scale(p_lod_scale: float): - lod_scale = p_lod_scale - - -# Compat -func get_lod_scale() -> float: - return lod_scale - - -func get_lod_count() -> int: - return _lodder.get_lod_count() - - -# 3 -# o---o -# 0 | | 1 -# o---o -# 2 -# Directions to go to neighbor chunks -const s_dirs = [ - [-1, 0], # SEAM_LEFT - [1, 0], # SEAM_RIGHT - [0, -1], # SEAM_BOTTOM - [0, 1] # SEAM_TOP -] - -# 7 6 -# o---o---o -# 0 | | 5 -# o o -# 1 | | 4 -# o---o---o -# 2 3 -# -# Directions to go to neighbor chunks of higher LOD -const s_rdirs = [ - [-1, 0], - [-1, 1], - [0, 2], - [1, 2], - [2, 1], - [2, 0], - [1, -1], - [0, -1] -] - - -func _edit_update_viewer_position(camera: Camera3D): - _update_viewer_position(camera) - - -func _update_viewer_position(camera: Camera3D): - if camera == null: - var viewport := get_viewport() - if viewport != null: - camera = viewport.get_camera_3d() - - if camera == null: - return - - if camera.projection == Camera3D.PROJECTION_ORTHOGONAL: - # In this mode, due to the fact Godot does not allow negative near plane, - # users have to pull the camera node very far away, but it confuses LOD - # into very low detail, while the seen area remains the same. - # So we need to base LOD on a different metric. - var cam_pos := camera.global_transform.origin - var cam_dir := -camera.global_transform.basis.z - var max_distance := camera.far * 1.2 - var hit_cell_pos = cell_raycast(cam_pos, cam_dir, max_distance) - - if hit_cell_pos != null: - var cell_to_world := get_internal_transform() - var h := _data.get_height_at(hit_cell_pos.x, hit_cell_pos.y) - _viewer_pos_world = cell_to_world * Vector3(hit_cell_pos.x, h, hit_cell_pos.y) - - else: - _viewer_pos_world = camera.global_transform.origin - - -func _process(delta: float): - if not Engine.is_editor_hint(): - # In editor, the camera is only accessible from an editor plugin - _update_viewer_position(null) - - if has_data(): - if _data.is_locked(): - # Can't use the data for now - return - - if _data.get_resolution() != 0: - var gt := get_internal_transform() - # Viewer position such that 1 unit == 1 pixel in the heightmap - var viewer_pos_heightmap_local := gt.affine_inverse() * _viewer_pos_world - #var time_before = OS.get_ticks_msec() - _lodder.update(viewer_pos_heightmap_local) - #var time_elapsed = OS.get_ticks_msec() - time_before - #if Engine.get_frames_drawn() % 60 == 0: - # _logger.debug(str("Lodder time: ", time_elapsed)) - - if _data.get_map_count(HTerrainData.CHANNEL_DETAIL) > 0: - # Note: the detail system is not affected by map scale, - # so we have to send viewer position in world space - for layer in _detail_layers: - layer.process(delta, _viewer_pos_world) - - _updated_chunks = 0 - - # Add more chunk updates for neighboring (seams): - # This adds updates to higher-LOD chunks around lower-LOD ones, - # because they might not needed to update by themselves, but the fact a neighbor - # chunk got joined or split requires them to create or revert seams - var precount = _pending_chunk_updates.size() - for i in precount: - var u: HT_PendingChunkUpdate = _pending_chunk_updates[i] - - # In case the chunk got split - for d in 4: - var ncpos_x = u.pos_x + s_dirs[d][0] - var ncpos_y = u.pos_y + s_dirs[d][1] - - var nchunk := _get_chunk_at(ncpos_x, ncpos_y, u.lod) - if nchunk != null and nchunk.is_active(): - # Note: this will append elements to the array we are iterating on, - # but we iterate only on the previous count so it should be fine - _add_chunk_update(nchunk, ncpos_x, ncpos_y, u.lod) - - # In case the chunk got joined - if u.lod > 0: - var cpos_upper_x := u.pos_x * 2 - var cpos_upper_y := u.pos_y * 2 - var nlod := u.lod - 1 - - for rd in 8: - var ncpos_upper_x = cpos_upper_x + s_rdirs[rd][0] - var ncpos_upper_y = cpos_upper_y + s_rdirs[rd][1] - - var nchunk := _get_chunk_at(ncpos_upper_x, ncpos_upper_y, nlod) - if nchunk != null and nchunk.is_active(): - _add_chunk_update(nchunk, ncpos_upper_x, ncpos_upper_y, nlod) - - # Update chunks - var lvisible := is_visible_in_tree() - for i in len(_pending_chunk_updates): - var u: HT_PendingChunkUpdate = _pending_chunk_updates[i] - var chunk := _get_chunk_at(u.pos_x, u.pos_y, u.lod) - assert(chunk != null) - _update_chunk(chunk, u.lod, lvisible and chunk.is_active()) - _updated_chunks += 1 - - _pending_chunk_updates.clear() - - if _material_params_need_update: - _update_material_params() - HT_Util.update_configuration_warning(self, false) - _material_params_need_update = false - - # DEBUG -# if(_updated_chunks > 0): -# _logger.debug(str("Updated {0} chunks".format(_updated_chunks))) - - -func _update_chunk(chunk: HTerrainChunk, lod: int, p_visible: bool): - assert(has_data()) - - # Check for my own seams - var seams := 0 - var cpos_x := chunk.cell_origin_x / (_chunk_size << lod) - var cpos_y := chunk.cell_origin_y / (_chunk_size << lod) - var cpos_lower_x := cpos_x / 2 - var cpos_lower_y := cpos_y / 2 - - # Check for lower-LOD chunks around me - for d in 4: - var ncpos_lower_x = (cpos_x + s_dirs[d][0]) / 2 - var ncpos_lower_y = (cpos_y + s_dirs[d][1]) / 2 - if ncpos_lower_x != cpos_lower_x or ncpos_lower_y != cpos_lower_y: - var nchunk := _get_chunk_at(ncpos_lower_x, ncpos_lower_y, lod + 1) - if nchunk != null and nchunk.is_active(): - seams |= (1 << d) - - var mesh := _mesher.get_chunk(lod, seams) - chunk.set_mesh(mesh) - - # Because chunks are rendered using vertex shader displacement, - # the renderer cannot rely on the mesh's AABB. - var s := _chunk_size << lod - var aabb := _data.get_region_aabb(chunk.cell_origin_x, chunk.cell_origin_y, s, s) - aabb.position.x = 0 - aabb.position.z = 0 - chunk.set_aabb(aabb) - - chunk.set_visible(p_visible) - chunk.set_pending_update(false) - - -func _add_chunk_update(chunk: HTerrainChunk, pos_x: int, pos_y: int, lod: int): - if chunk.is_pending_update(): - #_logger.debug("Chunk update is already pending!") - return - - assert(lod < len(_chunks)) - assert(pos_x >= 0) - assert(pos_y >= 0) - assert(pos_y < len(_chunks[lod])) - assert(pos_x < len(_chunks[lod][pos_y])) - - # No update pending for this chunk, create one - var u := HT_PendingChunkUpdate.new() - u.pos_x = pos_x - u.pos_y = pos_y - u.lod = lod - _pending_chunk_updates.push_back(u) - - chunk.set_pending_update(true) - - # TODO Neighboring chunks might need an update too - # because of normals and seams being updated - - -# Used when editing an existing terrain -func set_area_dirty(origin_in_cells_x: int, origin_in_cells_y: int, \ - size_in_cells_x: int, size_in_cells_y: int): - - var cpos0_x := origin_in_cells_x / _chunk_size - var cpos0_y := origin_in_cells_y / _chunk_size - var csize_x := (size_in_cells_x - 1) / _chunk_size + 1 - var csize_y := (size_in_cells_y - 1) / _chunk_size + 1 - - # For each lod - for lod in _lodder.get_lod_count(): - # Get grid and chunk size - var grid = _chunks[lod] - var s : int = _lodder.get_lod_factor(lod) - - # Convert rect into this lod's coordinates: - # Pick min and max (included), divide them, then add 1 to max so it's excluded again - var min_x := cpos0_x / s - var min_y := cpos0_y / s - var max_x := (cpos0_x + csize_x - 1) / s + 1 - var max_y := (cpos0_y + csize_y - 1) / s + 1 - - # Find which chunks are within - for cy in range(min_y, max_y): - for cx in range(min_x, max_x): - var chunk = HT_Grid.grid_get_or_default(grid, cx, cy, null) - if chunk != null and chunk.is_active(): - _add_chunk_update(chunk, cx, cy, lod) - - -# Called when a chunk is needed to be seen -func _cb_make_chunk(cpos_x: int, cpos_y: int, lod: int): - # TODO What if cpos is invalid? _get_chunk_at will return NULL but that's still invalid - var chunk := _get_chunk_at(cpos_x, cpos_y, lod) - - if chunk == null: - # This is the first time this chunk is required at this lod, generate it - - var lod_factor : int = _lodder.get_lod_factor(lod) - var origin_in_cells_x := cpos_x * _chunk_size * lod_factor - var origin_in_cells_y := cpos_y * _chunk_size * lod_factor - - var material = _material - if _lookdev_enabled: - material = _get_lookdev_material() - - if _DEBUG_AABB: - chunk = HTerrainChunkDebug.new( - self, origin_in_cells_x, origin_in_cells_y, material) - else: - chunk = HTerrainChunk.new(self, origin_in_cells_x, origin_in_cells_y, material) - chunk.parent_transform_changed(get_internal_transform()) - - chunk.set_render_layer_mask(_render_layer_mask) - chunk.set_cast_shadow_setting(_cast_shadow_setting) - - var grid = _chunks[lod] - var row = grid[cpos_y] - row[cpos_x] = chunk - - # Make sure it gets updated - _add_chunk_update(chunk, cpos_x, cpos_y, lod) - - chunk.set_active(true) - return chunk - - -# Called when a chunk is no longer seen -func _cb_recycle_chunk(chunk: HTerrainChunk, cx: int, cy: int, lod: int): - chunk.set_visible(false) - chunk.set_active(false) - - -func _cb_get_vertical_bounds(cpos_x: int, cpos_y: int, lod: int): - var chunk_size : int = _chunk_size * _lodder.get_lod_factor(lod) - var origin_in_cells_x := cpos_x * chunk_size - var origin_in_cells_y := cpos_y * chunk_size - # This is a hack for speed, - # because the proper algorithm appears to be too slow for GDScript. - # It should be good enough for most common cases, unless you have super-sharp cliffs. - return _data.get_point_aabb( - origin_in_cells_x + chunk_size / 2, - origin_in_cells_y + chunk_size / 2) -# var aabb = _data.get_region_aabb( -# origin_in_cells_x, origin_in_cells_y, chunk_size, chunk_size) -# return Vector2(aabb.position.y, aabb.end.y) - - -# static func _get_height_or_default(im: Image, pos_x: int, pos_y: int): -# if pos_x < 0 or pos_y < 0 or pos_x >= im.get_width() or pos_y >= im.get_height(): -# return 0.0 -# return im.get_pixel(pos_x, pos_y).r - - -# Performs a raycast to the terrain without using the collision engine. -# This is mostly useful in the editor, where the collider can't be updated in realtime. -# Returns cell hit position as Vector2, or null if there was no hit. -# TODO Cannot type hint nullable return value -func cell_raycast(origin_world: Vector3, dir_world: Vector3, max_distance: float): - assert(typeof(origin_world) == TYPE_VECTOR3) - assert(typeof(dir_world) == TYPE_VECTOR3) - if not has_data(): - return null - # Transform to local (takes map scale into account) - var to_local := get_internal_transform().affine_inverse() - var origin = to_local * origin_world - var dir = to_local.basis * dir_world - return _data.cell_raycast(origin, dir, max_distance) - - -static func _get_ground_texture_shader_param_name(ground_texture_type: int, slot: int) -> String: - assert(typeof(slot) == TYPE_INT and slot >= 0) - _check_ground_texture_type(ground_texture_type) - return str(SHADER_PARAM_GROUND_PREFIX, _ground_enum_to_name[ground_texture_type], "_", slot) - - -# @obsolete -func get_ground_texture(slot: int, type: int) -> Texture: - _logger.error( - "HTerrain.get_ground_texture is obsolete, " + - "use HTerrain.get_texture_set().get_texture(slot, type) instead") - var shader_param = _get_ground_texture_shader_param_name(type, slot) - return _material.get_shader_parameter(shader_param) - - -# @obsolete -func set_ground_texture(slot: int, type: int, tex: Texture): - _logger.error( - "HTerrain.set_ground_texture is obsolete, " + - "use HTerrain.get_texture_set().set_texture(slot, type, texture) instead") - assert(tex == null or tex is Texture) - var shader_param := _get_ground_texture_shader_param_name(type, slot) - _material.set_shader_parameter(shader_param, tex) - - -func _get_ground_texture_array_shader_param_name(type: int) -> String: - return _ground_texture_array_shader_params[type] as String - - -# @obsolete -func get_ground_texture_array(type: int) -> TextureLayered: - _logger.error( - "HTerrain.get_ground_texture_array is obsolete, " + - "use HTerrain.get_texture_set().get_texture_array(type) instead") - var param_name := _get_ground_texture_array_shader_param_name(type) - return _material.get_shader_parameter(param_name) - - -# @obsolete -func set_ground_texture_array(type: int, texture_array: TextureLayered): - _logger.error( - "HTerrain.set_ground_texture_array is obsolete, " + - "use HTerrain.get_texture_set().set_texture_array(type, texarray) instead") - var param_name := _get_ground_texture_array_shader_param_name(type) - _material.set_shader_parameter(param_name, texture_array) - - -func _internal_add_detail_layer(layer): - assert(_detail_layers.find(layer) == -1) - _detail_layers.append(layer) - - -func _internal_remove_detail_layer(layer): - assert(_detail_layers.find(layer) != -1) - _detail_layers.erase(layer) - - -# Returns a list copy of all child HTerrainDetailLayer nodes. -# The order in that list has no relevance. -func get_detail_layers() -> Array: - return _detail_layers.duplicate() - - -# @obsolete -func set_detail_texture(slot, tex): - _logger.error( - "HTerrain.set_detail_texture is obsolete, use HTerrainDetailLayer.texture instead") - - -# @obsolete -func get_detail_texture(slot): - _logger.error( - "HTerrain.get_detail_texture is obsolete, use HTerrainDetailLayer.texture instead") - - -# Compat -func set_ambient_wind(amplitude: float): - ambient_wind = amplitude - - -static func _check_ground_texture_type(ground_texture_type: int): - assert(typeof(ground_texture_type) == TYPE_INT) - assert(ground_texture_type >= 0 and ground_texture_type < HTerrainTextureSet.TYPE_COUNT) - - -# @obsolete -func get_ground_texture_slot_count() -> int: - _logger.error("get_ground_texture_slot_count is obsolete, " \ - + "use get_cached_ground_texture_slot_count instead") - return get_max_ground_texture_slot_count() - -# @obsolete -func get_max_ground_texture_slot_count() -> int: - _logger.error("get_ground_texture_slot_count is obsolete, " \ - + "use get_cached_ground_texture_slot_count instead") - return get_cached_ground_texture_slot_count() - - -# This is a cached value based on the actual number of texture parameters -# in the current shader. It won't update immediately when the shader changes, -# only after a frame. This is mostly used in the editor. -func get_cached_ground_texture_slot_count() -> int: - return _ground_texture_count_cache - - -func _edit_debug_draw(ci: CanvasItem): - _lodder.debug_draw_tree(ci) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - if _data == null: - warnings.append("The terrain is missing data.\n" \ - + "Select the `Data Directory` property in the inspector to assign it.") - - else: - var heightmap := _data.get_image(HTerrainData.CHANNEL_HEIGHT) - if heightmap.get_format() == Image.FORMAT_RH: - # This is in case the user has a heightmap using the old format and didn't convert - # for some reason - warnings.append( - "The heightmap uses a legacy format (RH), which might cause suboptimal authoring.\n" - + "You may convert it to RF by exporting it to 32-bit EXR, then import it back.\n" - + "You can also use a script to convert \"height.res\" (Image resource)") - - if _texture_set == null: - warnings.append("The terrain does not have a HTerrainTextureSet assigned\n" \ - + "This is required if you want to paint textures on it.") - - else: - var mode := _texture_set.get_mode() - - if mode == HTerrainTextureSet.MODE_TEXTURES and is_using_texture_array(): - warnings.append("The current shader needs texture arrays,\n" \ - + "but the current HTerrainTextureSet is setup with individual textures.\n" \ - + "You may need to switch it to TEXTURE_ARRAYS mode,\n" \ - + "or re-import images in this mode with the import tool.") - - elif mode == HTerrainTextureSet.MODE_TEXTURE_ARRAYS and not is_using_texture_array(): - warnings.append("The current shader needs individual textures,\n" \ - + "but the current HTerrainTextureSet is setup with texture arrays.\n" \ - + "You may need to switch it to TEXTURES mode,\n" \ - + "or re-import images in this mode with the import tool.") - - # TODO Warn about unused data maps, have a tool to clean them up - return warnings - - -func set_lookdev_enabled(enable: bool): - if _lookdev_enabled == enable: - return - _lookdev_enabled = enable - _material_params_need_update = true - if _lookdev_enabled: - _for_all_chunks(HT_SetMaterialAction.new(_get_lookdev_material())) - else: - _for_all_chunks(HT_SetMaterialAction.new(_material)) - - -func set_lookdev_shader_param(param_name: String, value): - var mat = _get_lookdev_material() - mat.set_shader_parameter(param_name, value) - - -func is_lookdev_enabled() -> bool: - return _lookdev_enabled - - -func _get_lookdev_material() -> ShaderMaterial: - if _lookdev_material == null: - _lookdev_material = ShaderMaterial.new() - _lookdev_material.shader = load(_LOOKDEV_SHADER_PATH) - return _lookdev_material - - -class HT_PendingChunkUpdate: - var pos_x := 0 - var pos_y := 0 - var lod := 0 - - -class HT_EnterWorldAction: - var world : World3D = null - func _init(w): - world = w - func exec(chunk): - chunk.enter_world(world) - - -class HT_ExitWorldAction: - func exec(chunk): - chunk.exit_world() - - -class HT_TransformChangedAction: - var transform : Transform3D - func _init(t): - transform = t - func exec(chunk): - chunk.parent_transform_changed(transform) - - -class HT_VisibilityChangedAction: - var visible := false - func _init(v): - visible = v - func exec(chunk): - chunk.set_visible(visible and chunk.is_active()) - - -#class HT_DeleteChunkAction: -# func exec(chunk): -# pass - - -class HT_SetMaterialAction: - var material : Material = null - func _init(m): - material = m - func exec(chunk): - chunk.set_material(material) - - -class HT_SetRenderLayerMaskAction: - var mask: int = 0 - func _init(m: int): - mask = m - func exec(chunk): - chunk.set_render_layer_mask(mask) - - -class HT_SetCastShadowSettingAction: - var setting := 0 - func _init(s: int): - setting = s - func exec(chunk): - chunk.set_cast_shadow_setting(setting) diff --git a/godot/addons/zylann.hterrain/hterrain.gd.uid b/godot/addons/zylann.hterrain/hterrain.gd.uid deleted file mode 100644 index 451bc94..0000000 --- a/godot/addons/zylann.hterrain/hterrain.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dv8y8b65knp3n diff --git a/godot/addons/zylann.hterrain/hterrain_chunk.gd b/godot/addons/zylann.hterrain/hterrain_chunk.gd deleted file mode 100644 index c03251e..0000000 --- a/godot/addons/zylann.hterrain/hterrain_chunk.gd +++ /dev/null @@ -1,133 +0,0 @@ -@tool - -var cell_origin_x := 0 -var cell_origin_y := 0 - -var _visible : bool -# This is true when the chunk is meant to be displayed. -# A chunk can be active and hidden (due to the terrain being hidden). -var _active : bool - -var _pending_update : bool - -var _mesh_instance : RID -# Need to keep a reference so that the mesh RID doesn't get freed -# TODO Use RID directly, no need to keep all those meshes in memory -var _mesh : Mesh = null - - -# TODO p_parent is HTerrain, can't add type hint due to cyclic reference -func _init(p_parent: Node3D, p_cell_x: int, p_cell_y: int, p_material: Material): - assert(p_parent is Node3D) - assert(typeof(p_cell_x) == TYPE_INT) - assert(typeof(p_cell_y) == TYPE_INT) - assert(p_material is Material) - - cell_origin_x = p_cell_x - cell_origin_y = p_cell_y - - var rs := RenderingServer - - _mesh_instance = rs.instance_create() - - # Godot 4.4 introduced physics interpolation again, and it's always on. - # Unfortunately that breaks terrain chunks, which start to flicker when created, - # even though they don't move. Terrains are inherently static so that feature must not be used. - # This feature is new in Godot 4.4 so to maintain compatibility with previous versions - # we have to test if the method is available. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/475 - if rs.has_method(&"instance_set_interpolated"): - rs.call(&"instance_set_interpolated", _mesh_instance, false) - - if p_material != null: - rs.instance_geometry_set_material_override(_mesh_instance, p_material.get_rid()) - - var world := p_parent.get_world_3d() - if world != null: - rs.instance_set_scenario(_mesh_instance, world.get_scenario()) - - _visible = true - # TODO Is this needed? - rs.instance_set_visible(_mesh_instance, _visible) - - _active = true - _pending_update = false - - -func _notification(p_what: int): - if p_what == NOTIFICATION_PREDELETE: - if _mesh_instance != RID(): - RenderingServer.free_rid(_mesh_instance) - _mesh_instance = RID() - - -func is_active() -> bool: - return _active - - -func set_active(a: bool): - _active = a - - -func is_pending_update() -> bool: - return _pending_update - - -func set_pending_update(p: bool): - _pending_update = p - - -func enter_world(world: World3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, world.get_scenario()) - - -func exit_world(): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, RID()) - - -func parent_transform_changed(parent_transform: Transform3D): - assert(_mesh_instance != RID()) - var local_transform := Transform3D(Basis(), Vector3(cell_origin_x, 0, cell_origin_y)) - var world_transform := parent_transform * local_transform - RenderingServer.instance_set_transform(_mesh_instance, world_transform) - - -func set_mesh(mesh: Mesh): - assert(_mesh_instance != RID()) - if mesh == _mesh: - return - RenderingServer.instance_set_base(_mesh_instance, mesh.get_rid() if mesh != null else RID()) - _mesh = mesh - - -func set_material(material: Material): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_material_override( \ - _mesh_instance, material.get_rid() if material != null else RID()) - - -func set_visible(visible: bool): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_visible(_mesh_instance, visible) - _visible = visible - - -func is_visible() -> bool: - return _visible - - -func set_aabb(aabb: AABB): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_custom_aabb(_mesh_instance, aabb) - - -func set_render_layer_mask(mask: int): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_layer_mask(_mesh_instance, mask) - - -func set_cast_shadow_setting(setting: int): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_cast_shadows_setting(_mesh_instance, setting) diff --git a/godot/addons/zylann.hterrain/hterrain_chunk.gd.uid b/godot/addons/zylann.hterrain/hterrain_chunk.gd.uid deleted file mode 100644 index 3ea2a7a..0000000 --- a/godot/addons/zylann.hterrain/hterrain_chunk.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwemxkrbq6m2j diff --git a/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd b/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd deleted file mode 100644 index 7bf3d41..0000000 --- a/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd +++ /dev/null @@ -1,67 +0,0 @@ -@tool -extends "hterrain_chunk.gd" - -# I wrote this because Godot has no debug option to show AABBs. -# https://github.com/godotengine/godot/issues/20722 - - -const HT_DirectMeshInstance = preload("./util/direct_mesh_instance.gd") -const HT_Util = preload("./util/util.gd") - - -var _debug_cube : HT_DirectMeshInstance = null -var _aabb := AABB() -var _parent_transform := Transform3D() - - -func _init(p_parent: Node3D, p_cell_x: int, p_cell_y: int, p_material: Material): - super(p_parent, p_cell_x, p_cell_y, p_material) - - var wirecube : Mesh - if not p_parent.has_meta("debug_wirecube_mesh"): - wirecube = HT_Util.create_wirecube_mesh() - var mat := StandardMaterial3D.new() - mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - wirecube.surface_set_material(0, mat) - # Cache the debug cube in the parent node to avoid re-creating each time - p_parent.set_meta("debug_wirecube_mesh", wirecube) - else: - wirecube = p_parent.get_meta("debug_wirecube_mesh") - - _debug_cube = HT_DirectMeshInstance.new() - _debug_cube.set_mesh(wirecube) - _debug_cube.set_world(p_parent.get_world_3d()) - - -func enter_world(world: World3D): - super(world) - _debug_cube.enter_world(world) - - -func exit_world(): - super() - _debug_cube.exit_world() - - -func parent_transform_changed(parent_transform: Transform3D): - super(parent_transform) - _parent_transform = parent_transform - _debug_cube.set_transform(_compute_aabb()) - - -func set_visible(visible: bool): - super(visible) - _debug_cube.set_visible(visible) - - -func set_aabb(aabb: AABB): - super(aabb) - #aabb.position.y += 0.2*randf() - _aabb = aabb - _debug_cube.set_transform(_compute_aabb()) - - -func _compute_aabb(): - var pos = Vector3(cell_origin_x, 0, cell_origin_y) - return _parent_transform * Transform3D(Basis().scaled(_aabb.size), pos + _aabb.position) - diff --git a/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd.uid b/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd.uid deleted file mode 100644 index 3699d28..0000000 --- a/godot/addons/zylann.hterrain/hterrain_chunk_debug.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chsl6cym1vxie diff --git a/godot/addons/zylann.hterrain/hterrain_collider.gd b/godot/addons/zylann.hterrain/hterrain_collider.gd deleted file mode 100644 index bff1305..0000000 --- a/godot/addons/zylann.hterrain/hterrain_collider.gd +++ /dev/null @@ -1,139 +0,0 @@ -@tool - -const HT_Logger = preload("./util/logger.gd") -const HTerrainData = preload("./hterrain_data.gd") - -var _shape_rid := RID() -var _body_rid := RID() -var _terrain_transform := Transform3D() -var _terrain_data : HTerrainData = null -var _logger = HT_Logger.get_for(self) - - -func _init(attached_node: Node, initial_layer: int, initial_mask: int): - _logger.debug("HTerrainCollider: creating body") - assert(attached_node != null) - _shape_rid = PhysicsServer3D.heightmap_shape_create() - _body_rid = PhysicsServer3D.body_create() - PhysicsServer3D.body_set_mode(_body_rid, PhysicsServer3D.BODY_MODE_STATIC) - - PhysicsServer3D.body_set_collision_layer(_body_rid, initial_layer) - PhysicsServer3D.body_set_collision_mask(_body_rid, initial_mask) - - # TODO This is an attempt to workaround https://github.com/godotengine/godot/issues/24390 - PhysicsServer3D.body_set_ray_pickable(_body_rid, false) - - # Assigng dummy data - # TODO This is a workaround to https://github.com/godotengine/godot/issues/25304 - PhysicsServer3D.shape_set_data(_shape_rid, { - "width": 2, - "depth": 2, - "heights": PackedFloat32Array([0, 0, 0, 0]), - "min_height": -1, - "max_height": 1 - }) - - PhysicsServer3D.body_add_shape(_body_rid, _shape_rid) - - # This makes collision hits report the provided object as `collider` - PhysicsServer3D.body_attach_object_instance_id(_body_rid, attached_node.get_instance_id()) - - -func set_collision_layer(layer: int): - PhysicsServer3D.body_set_collision_layer(_body_rid, layer) - - -func set_collision_mask(mask: int): - PhysicsServer3D.body_set_collision_mask(_body_rid, mask) - - -func update_physics_material(physics_material: PhysicsMaterial) -> void: - # Logic based on Godot `static_body.cpp` - - var ps := PhysicsServer3D - if physics_material == null: - # Reset to defaults - ps.body_set_param(_body_rid, PhysicsServer3D.BODY_PARAM_BOUNCE, 0) - ps.body_set_param(_body_rid, PhysicsServer3D.BODY_PARAM_FRICTION, 1) - - else: - var bounce := physics_material.bounce - if physics_material.absorbent: - bounce = -bounce - ps.body_set_param(_body_rid, PhysicsServer3D.BODY_PARAM_BOUNCE, bounce) - - var friction := physics_material.friction - if physics_material.rough: - friction = -friction - ps.body_set_param(_body_rid, PhysicsServer3D.BODY_PARAM_FRICTION, friction) - - -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - _logger.debug("Destroy HTerrainCollider") - PhysicsServer3D.free_rid(_body_rid) - # The shape needs to be freed after the body, otherwise the engine crashes - PhysicsServer3D.free_rid(_shape_rid) - - -func set_transform(transform: Transform3D): - assert(_body_rid != RID()) - _terrain_transform = transform - _update_transform() - - -func set_world(world: World3D): - assert(_body_rid != RID()) - PhysicsServer3D.body_set_space(_body_rid, world.get_space() if world != null else RID()) - - -func create_from_terrain_data(terrain_data: HTerrainData): - assert(terrain_data != null) - assert(not terrain_data.is_locked()) - _logger.debug("HTerrainCollider: setting up heightmap") - - _terrain_data = terrain_data - - var aabb := terrain_data.get_aabb() - - var width := terrain_data.get_resolution() - var depth := terrain_data.get_resolution() - var height := aabb.size.y - - var shape_data = { - "width": terrain_data.get_resolution(), - "depth": terrain_data.get_resolution(), - "heights": terrain_data.get_all_heights(), - "min_height": aabb.position.y, - "max_height": aabb.end.y - } - - PhysicsServer3D.shape_set_data(_shape_rid, shape_data) - - _update_transform(aabb) - - -func _update_transform(aabb=null): - if _terrain_data == null: - _logger.debug("HTerrainCollider: terrain data not set yet") - return - -# if aabb == null: -# aabb = _terrain_data.get_aabb() - - var width := _terrain_data.get_resolution() - var depth := _terrain_data.get_resolution() - #var height = aabb.size.y - - #_terrain_transform - - var trans := Transform3D(Basis(), 0.5 * Vector3(width - 1, 0, depth - 1)) - - # And then apply the terrain transform - trans = _terrain_transform * trans - - PhysicsServer3D.body_set_state(_body_rid, PhysicsServer3D.BODY_STATE_TRANSFORM, trans) - # Cannot use shape transform when scaling is involved, - # because Godot is undoing that scale for some reason. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/70 - #PhysicsServer.body_set_shape_transform(_body_rid, 0, trans) diff --git a/godot/addons/zylann.hterrain/hterrain_collider.gd.uid b/godot/addons/zylann.hterrain/hterrain_collider.gd.uid deleted file mode 100644 index 74047d6..0000000 --- a/godot/addons/zylann.hterrain/hterrain_collider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cwa5ydeme35cg diff --git a/godot/addons/zylann.hterrain/hterrain_data.gd b/godot/addons/zylann.hterrain/hterrain_data.gd deleted file mode 100644 index f16ca55..0000000 --- a/godot/addons/zylann.hterrain/hterrain_data.gd +++ /dev/null @@ -1,2027 +0,0 @@ - -# Holds data of the terrain. -# This is mostly a set of textures using specific formats, some precalculated, and metadata. - -@tool -extends Resource - -const HT_Grid = preload("./util/grid.gd") -const HT_Util = preload("./util/util.gd") -const HT_Errors = preload("./util/errors.gd") -const HT_Logger = preload("./util/logger.gd") -const HT_ImageFileCache = preload("./util/image_file_cache.gd") -const HT_XYZFormat = preload("./util/xyz_format.gd") - -const ENABLE_LEGACY_HEIGHTMAP_RH_CONVERSION_IN_EDITOR = true - -enum { - BIT_DEPTH_UNDEFINED = 0, - BIT_DEPTH_16 = 16, - BIT_DEPTH_32 = 32 -} - -# Note: indexes matters for saving, don't re-order -# TODO Rename "CHANNEL" to "MAP", makes more sense and less confusing with RGBA channels -const CHANNEL_HEIGHT = 0 -const CHANNEL_NORMAL = 1 -const CHANNEL_SPLAT = 2 -const CHANNEL_COLOR = 3 -const CHANNEL_DETAIL = 4 -const CHANNEL_GLOBAL_ALBEDO = 5 -const CHANNEL_SPLAT_INDEX = 6 -const CHANNEL_SPLAT_WEIGHT = 7 -const CHANNEL_COUNT = 8 - -const _map_types = { - CHANNEL_HEIGHT: { - name = "height", - shader_param_name = "u_terrain_heightmap", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RF, - default_fill = Color(0, 0, 0, 1), - default_count = 1, - can_be_saved_as_png = false, - authored = true, - srgb = false - }, - CHANNEL_NORMAL: { - name = "normal", - shader_param_name = "u_terrain_normalmap", - filter = true, - mipmaps = false, - # TODO RGB8 is a lie, we should use RGBA8 and pack something in A I guess - texture_format = Image.FORMAT_RGB8, - default_fill = Color(0.5, 0.5, 1.0), - default_count = 1, - can_be_saved_as_png = true, - authored = false, - srgb = false - }, - CHANNEL_SPLAT: { - name = "splat", - shader_param_name = [ - "u_terrain_splatmap", # not _0 for compatibility - "u_terrain_splatmap_1", - "u_terrain_splatmap_2", - "u_terrain_splatmap_3" - ], - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RGBA8, - default_fill = [Color(1, 0, 0, 0), Color(0, 0, 0, 0)], - default_count = 1, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_COLOR: { - name = "color", - shader_param_name = "u_terrain_colormap", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RGBA8, - default_fill = Color(1, 1, 1, 1), - default_count = 1, - can_be_saved_as_png = true, - authored = true, - srgb = true - }, - CHANNEL_DETAIL: { - name = "detail", - shader_param_name = "u_terrain_detailmap", - filter = true, - mipmaps = false, - # TODO Godot has issues properly using R8 like we intend to. - # - save_png ignores it and saves RGB8 instead - # - the importer always uses RGB8 even if the PNG file is 8-bit - # As a result it triggers warnings in the plugin due to converting back to R8. - # Maybe that's one reason for us to stop relying on the importer at this point. - # It's been nothing but pain to try integrating with it. - # 2024/11/21: L8 appears to create smaller PNG files (not 3x smaller, but it's a start) - # which have bit depth 8 so it seems it does what we want. - # It also imports as L8, but ONLY if we set `mode` to `VRAM uncompressed`, instead of - # `Lossless`, go figure what difference it makes for us - texture_format = Image.FORMAT_L8, - default_fill = Color(0, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_GLOBAL_ALBEDO: { - name = "global_albedo", - shader_param_name = "u_terrain_globalmap", - filter = true, - mipmaps = true, - texture_format = Image.FORMAT_RGB8, - default_fill = null, - default_count = 0, - can_be_saved_as_png = true, - authored = false, - srgb = true - }, - CHANNEL_SPLAT_INDEX: { - name = "splat_index", - shader_param_name = "u_terrain_splat_index_map", - filter = false, - mipmaps = false, - texture_format = Image.FORMAT_RGB8, - default_fill = Color(0, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - }, - CHANNEL_SPLAT_WEIGHT: { - name = "splat_weight", - shader_param_name = "u_terrain_splat_weight_map", - filter = true, - mipmaps = false, - texture_format = Image.FORMAT_RG8, - default_fill = Color(1, 0, 0), - default_count = 0, - can_be_saved_as_png = true, - authored = true, - srgb = false - } -} - -# Resolution is a power of two + 1 -const MAX_RESOLUTION = 4097 -const MIN_RESOLUTION = 65 # must be higher than largest chunk size -const DEFAULT_RESOLUTION = 513 -const SUPPORTED_RESOLUTIONS = [65, 129, 257, 513, 1025, 2049, 4097] - -const VERTICAL_BOUNDS_CHUNK_SIZE = 16 -# TODO Have undo chunk size to emphasise the fact it's independent - -const META_EXTENSION = "hterrain" -const META_FILENAME = "data.hterrain" -const META_VERSION = "0.11" - -signal resolution_changed -signal region_changed(x, y, w, h, channel) -signal map_added(type, index) -signal map_removed(type, index) -signal map_changed(type, index) - - -# A map is a texture covering the terrain. -# The usage of a map depends on its type (heightmap, normalmap, splatmap...). -class HT_Map: - var texture: Texture2D - # Reference used in case we need the data CPU-side - var image: Image - # ID used for saving, because when adding/removing maps, - # we shouldn't rename texture files just because the indexes change. - # This is mostly for internal keeping. - # The API still uses indexes that may shift if your remove a map. - var id := -1 - # Should be set to true if the map has unsaved modifications. - var modified := true - - func _init(p_id: int): - id = p_id - - -var _resolution := 0 - -# There can be multiple maps of the same type, though most of them are single -# [map_type][instance_index] => map -var _maps := [[]] - -# RGF image where R is min height and G is max height -var _chunked_vertical_bounds := Image.new() - -var _locked := false - -var _edit_disable_apply_undo := false -var _logger := HT_Logger.get_for(self) - - -func _init(): - # Initialize default maps - _set_default_maps() - - -func _set_default_maps(): - _maps.resize(CHANNEL_COUNT) - for c in CHANNEL_COUNT: - var maps := [] - var n : int = _map_types[c].default_count - for i in n: - maps.append(HT_Map.new(i)) - _maps[c] = maps - - -func _edit_load_default(): - _logger.debug("Loading default data") - _set_default_maps() - resize(DEFAULT_RESOLUTION) - - -# Don't use the data if this getter returns false -func is_locked() -> bool: - return _locked - - -func get_resolution() -> int: - return _resolution - - -# @obsolete -func set_resolution(p_res): - _logger.error("`HTerrainData.set_resolution()` is obsolete, use `resize()` instead") - resize(p_res) - - -# @obsolete -func set_resolution2(p_res, update_normals): - _logger.error("`HTerrainData.set_resolution2()` is obsolete, use `resize()` instead") - resize(p_res, true, Vector2(-1, -1)) - - -# Resizes all maps of the terrain. This may take some time to complete. -# Note that no upload to GPU is done, you have to do it once you're done with all changes, -# by calling `notify_region_change` or `notify_full_change`. -# p_res: new resolution. Must be a power of two + 1. -# stretch: if true, the terrain will be stretched in X and Z axes. -# If false, it will be cropped or expanded. -# anchor: if stretch is false, decides which side or corner to crop/expand the terrain from. -# -# There is an off-by-one in the data, -# so for example a map of 512x512 will actually have 513x513 cells. -# Here is why: -# If we had an even amount of cells, it would produce this situation when making LOD chunks: -# -# x---x---x---x x---x---x---x -# | | | | | | -# x---x---x---x x x x x -# | | | | | | -# x---x---x---x x---x---x---x -# | | | | | | -# x---x---x---x x x x x -# -# LOD 0 LOD 1 -# -# We would be forced to ignore the last cells because they would produce an irregular chunk. -# We need an off-by-one because quads making up chunks SHARE their consecutive vertices. -# One quad needs at least 2x2 cells to exist. -# Two quads of the heightmap share an edge, which needs a total of 3x3 cells, not 4x4. -# One chunk has 16x16 quads, so it needs 17x17 cells, -# not 16, where the last cell is shared with the next chunk. -# As a result, a map of 4x4 chunks needs 65x65 cells, not 64x64. -func resize(p_res: int, stretch := true, anchor := Vector2(-1, -1)): - assert(typeof(p_res) == TYPE_INT) - assert(typeof(stretch) == TYPE_BOOL) - assert(typeof(anchor) == TYPE_VECTOR2) - - _logger.debug(str("set_resolution ", p_res)) - - if p_res == get_resolution(): - return - - p_res = clampi(p_res, MIN_RESOLUTION, MAX_RESOLUTION) - - # Power of two is important for LOD. - # Also, grid data is off by one, - # because for an even number of quads you need an odd number of vertices. - # To prevent size from increasing at every deserialization, - # remove 1 before applying power of two. - p_res = HT_Util.next_power_of_two(p_res - 1) + 1 - - _resolution = p_res; - - for channel in CHANNEL_COUNT: - var maps : Array = _maps[channel] - - for index in len(maps): - _logger.debug(str("Resizing ", get_map_debug_name(channel, index), "...")) - - var map : HT_Map = maps[index] - var im := map.image - - if im == null: - _logger.debug("Image not in memory, creating it") - im = Image.create(_resolution, _resolution, false, get_channel_format(channel)) - - var fill_color = _get_map_default_fill_color(channel, index) - if fill_color != null: - _logger.debug(str("Fill with ", fill_color)) - im.fill(fill_color) - - else: - if stretch and not _map_types[channel].authored: - # Create a blank new image, it will be automatically computed later - im = Image.create(_resolution, _resolution, false, get_channel_format(channel)) - else: - if stretch: - if im.get_format() == Image.FORMAT_RGB8: - # Can't directly resize this format - var float_heightmap := convert_heightmap_to_float(im, _logger) - float_heightmap.resize(_resolution, _resolution) - im = Image.create( - float_heightmap.get_width(), - float_heightmap.get_height(), im.has_mipmaps(), im.get_format()) - convert_float_heightmap_to_rgb8(float_heightmap, im) - else: - # Assuming float or single-component fixed-point - im.resize(_resolution, _resolution) - else: - var fill_color = _get_map_default_fill_color(channel, index) - im = HT_Util.get_cropped_image(im, _resolution, _resolution, \ - fill_color, anchor) - - map.image = im - map.modified = true - - _update_all_vertical_bounds() - - resolution_changed.emit() - - -# TODO Can't hint it, the return is a nullable Color -static func _get_map_default_fill_color(map_type: int, map_index: int): - var config = _map_types[map_type].default_fill - if config == null: - # No fill required - return null - if typeof(config) == TYPE_COLOR: - # Standard color fill - return config - assert(typeof(config) == TYPE_ARRAY) - assert(len(config) == 2) - if map_index == 0: - # First map has this config - return config[0] - # Others have this - return config[1] - - -# Gets the height at the given cell position. -# This height is raw and doesn't account for scaling of the terrain node. -# This function is relatively slow due to locking, so don't use it to fetch large areas. -func get_height_at(x: int, y: int) -> float: - # Height data must be loaded in RAM - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - return HT_Util.get_pixel_clamped(im, x, y).r - Image.FORMAT_RGB8: - return decode_height_from_rgb8_unorm(HT_Util.get_pixel_clamped(im, x, y)) - _: - _logger.error(str("Invalid heigthmap format ", im.get_format())) - return 0.0 - - -# Gets the height at the given floating-point cell position. -# This height is raw and doesn't account for scaling of the terrain node. -# This function is relatively slow due to locking, so don't use it to fetch large areas -func get_interpolated_height_at(pos: Vector3) -> float: - # Height data must be loaded in RAM - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - var map_type = _map_types[CHANNEL_HEIGHT] - assert(im.get_format() == map_type.texture_format) - - # The function takes a Vector3 for convenience so it's easier to use in 3D scripting - var x0 := int(floorf(pos.x)) - var y0 := int(floorf(pos.z)) - - var xf := pos.x - x0 - var yf := pos.z - y0 - - var h00 : float - var h10 : float - var h01 : float - var h11 : float - - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - h00 = HT_Util.get_pixel_clamped(im, x0, y0).r - h10 = HT_Util.get_pixel_clamped(im, x0 + 1, y0).r - h01 = HT_Util.get_pixel_clamped(im, x0, y0 + 1).r - h11 = HT_Util.get_pixel_clamped(im, x0 + 1, y0 + 1).r - - Image.FORMAT_RGB8: - var c00 := HT_Util.get_pixel_clamped(im, x0, y0) - var c10 := HT_Util.get_pixel_clamped(im, x0 + 1, y0) - var c01 := HT_Util.get_pixel_clamped(im, x0, y0 + 1) - var c11 := HT_Util.get_pixel_clamped(im, x0 + 1, y0 + 1) - - h00 = decode_height_from_rgb8_unorm(c00) - h10 = decode_height_from_rgb8_unorm(c10) - h01 = decode_height_from_rgb8_unorm(c01) - h11 = decode_height_from_rgb8_unorm(c11) - - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - return 0.0 - - # Bilinear filter - var h := lerpf(lerpf(h00, h10, xf), lerpf(h01, h11, xf), yf) - return h - -# Gets all heights within the given rectangle in cells. -# This height is raw and doesn't account for scaling of the terrain node. -# Data is returned as a PackedFloat32Array. -func get_heights_region(x0: int, y0: int, w: int, h: int) -> PackedFloat32Array: - var im = get_image(CHANNEL_HEIGHT) - assert(im != null) - - var min_x := clampi(x0, 0, im.get_width()) - var min_y := clampi(y0, 0, im.get_height()) - var max_x := clampi(x0 + w, 0, im.get_width() + 1) - var max_y := clampi(y0 + h, 0, im.get_height() + 1) - - var heights := PackedFloat32Array() - - var area := (max_x - min_x) * (max_y - min_y) - if area == 0: - _logger.debug("Empty heights region!") - return heights - - heights.resize(area) - - var i := 0 - - if im.get_format() == Image.FORMAT_RF or im.get_format() == Image.FORMAT_RH: - for y in range(min_y, max_y): - for x in range(min_x, max_x): - heights[i] = im.get_pixel(x, y).r - i += 1 - - elif im.get_format() == Image.FORMAT_RGB8: - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var c := im.get_pixel(x, y) - heights[i] = decode_height_from_rgb8_unorm(c) - i += 1 - - else: - _logger.error(str("Unknown heightmap format! ", im.get_format())) - - return heights - - -# Checks that all images stored in maps have the correct format. -# May be called in case someone uses `copy_from()` to update images and uses wrong formats. -func check_images(): - var errors := PackedStringArray() - - for map_type in _maps.size(): - var map_list : Array = _maps[map_type] - - for map_index in map_list.size(): - var map : HT_Map = map_list[map_index] - var im := map.image - - if im == null: - continue - - if im.get_width() != im.get_height(): - errors.append( - str("Terrain image ", get_map_debug_name(map_type, map_index), - " is not square (", im.get_width(), "x", im.get_height(), "). ", - "Did you modify it directly?")) - - elif im.get_width() != get_resolution(): - errors.append( - str("Terrain image ", get_map_debug_name(map_type, map_index), - " resolution (", im.get_width(), ") does not match the expected ", - "resolution (", get_resolution(), "). Did you modify it directly?")) - - var expected_format : int = _map_types[map_type].texture_format - if im.get_format() != expected_format: - errors.append( - str("Terrain image ", get_map_debug_name(map_type, map_index), - " has an unexpected format (expected ", expected_format, ", found ", - im.get_format(), "). Did you modify it directly?")) - - assert(errors.size() == 0, " ".join(errors)) - - -# Gets all heights as an array indexed as [x + y * width]. -# This height is raw and doesn't account for scaling of the terrain node. -func get_all_heights() -> PackedFloat32Array: - var im = get_image(CHANNEL_HEIGHT) - assert(im != null) - if im.get_format() == Image.FORMAT_RF: - return im.get_data().to_float32_array() - else: - # Non-native format, may be slower. Legacy heightmap? - return get_heights_region(0, 0, _resolution, _resolution) - - -# Call this function after you end modifying a map. -# It will commit the change to the GPU so the change will take effect. -# In the editor, it will also mark the map as modified so it will be saved when needed. -# Finally, it will emit `region_changed`, -# which allows other systems to catch up (like physics or grass) -# -# p_rect: -# modified area. -# -# map_type: -# which kind of map changed, see CHANNEL_* constants -# -# index: -# index of the map that changed -# -# p_upload_to_texture: -# the modified region will be copied from the map image to the texture. -# If the change already occurred on GPU, you may set this to false. -# -# p_update_vertical_bounds: -# if the modified map is the heightmap, vertical bounds will be updated. -# -func notify_region_change( - p_rect: Rect2, - p_map_type: int, - p_index := 0, - p_upload_to_texture := true, - p_update_vertical_bounds := true): - - assert(p_map_type >= 0 and p_map_type < CHANNEL_COUNT) - - var min_x := int(p_rect.position.x) - var min_y := int(p_rect.position.y) - var size_x := int(p_rect.size.x) - var size_y := int(p_rect.size.y) - - if p_map_type == CHANNEL_HEIGHT and p_update_vertical_bounds: - assert(p_index == 0) - _update_vertical_bounds(min_x, min_y, size_x, size_y) - - if p_upload_to_texture: - _upload_region(p_map_type, p_index, min_x, min_y, size_x, size_y) - - _maps[p_map_type][p_index].modified = true - - region_changed.emit(min_x, min_y, size_x, size_y, p_map_type) - changed.emit() - - -func notify_full_change(): - for maptype in range(CHANNEL_COUNT): - # Ignore normals because they get updated along with heights - if maptype == CHANNEL_NORMAL: - continue - var maps = _maps[maptype] - for index in len(maps): - notify_region_change(Rect2(0, 0, _resolution, _resolution), maptype, index) - - -func _edit_set_disable_apply_undo(e: bool): - _edit_disable_apply_undo = e - - -func _edit_apply_undo(undo_data: Dictionary, image_cache: HT_ImageFileCache): - if _edit_disable_apply_undo: - return - - var chunk_positions: Array = undo_data["chunk_positions"] - var map_infos: Array = undo_data["maps"] - var chunk_size: int = undo_data["chunk_size"] - - _logger.debug(str("Applying ", len(chunk_positions), " undo/redo chunks")) - - # Validate input - - for map_info in map_infos: - assert(map_info.map_type >= 0 and map_info.map_type < CHANNEL_COUNT) - assert(len(map_info.chunks) == len(chunk_positions)) - for im_cache_id in map_info.chunks: - assert(typeof(im_cache_id) == TYPE_INT) - - # Apply for each map - for map_info in map_infos: - var map_type := map_info.map_type as int - var map_index := map_info.map_index as int - - var regions_changed := [] - - for chunk_index in len(map_info.chunks): - var cpos : Vector2 = chunk_positions[chunk_index] - var cpos_x := int(cpos.x) - var cpos_y := int(cpos.y) - - var min_x := cpos_x * chunk_size - var min_y := cpos_y * chunk_size - var max_x := min_x + chunk_size - var max_y := min_y + chunk_size - - var data_id = map_info.chunks[chunk_index] - var data := image_cache.load_image(data_id) - assert(data != null) - - var dst_image := get_image(map_type, map_index) - assert(dst_image != null) - - if _map_types[map_type].authored: - #_logger.debug(str("Apply undo chunk ", cpos, " to ", Vector2(min_x, min_y))) - var src_rect := Rect2i(0, 0, data.get_width(), data.get_height()) - dst_image.blit_rect(data, src_rect, Vector2i(min_x, min_y)) - else: - _logger.error( - str("Channel ", map_type, " is a calculated channel!, no undo on this one")) - - # Defer this to a second pass, - # otherwise it causes order-dependent artifacts on the normal map - regions_changed.append([ - Rect2(min_x, min_y, max_x - min_x, max_y - min_y), map_type, map_index]) - - for args in regions_changed: - notify_region_change(args[0], args[1], args[2]) - - -#static func _debug_dump_heightmap(src: Image, fpath: String): -# var im = Image.new() -# im.create(src.get_width(), src.get_height(), false, Image.FORMAT_RGB8) -# im.lock() -# src.lock() -# for y in im.get_height(): -# for x in im.get_width(): -# var col = src.get_pixel(x, y) -# var c = col.r - floor(col.r) -# im.set_pixel(x, y, Color(c, 0.0, 0.0, 1.0)) -# im.unlock() -# src.unlock() -# im.save_png(fpath) - - -# TODO Support map indexes -# Used for undoing full-terrain changes -func _edit_apply_maps_from_file_cache(image_file_cache: HT_ImageFileCache, map_ids: Dictionary): - if _edit_disable_apply_undo: - return - for map_type in map_ids: - var id = map_ids[map_type] - var src_im := image_file_cache.load_image(id) - if src_im == null: - continue - var index := 0 - var dst_im := get_image(map_type, index) - var rect := Rect2i(0, 0, src_im.get_height(), src_im.get_height()) - dst_im.blit_rect(src_im, rect, Vector2i()) - notify_region_change(rect, map_type, index) - - -func _upload_channel(channel: int, index: int): - _upload_region(channel, index, 0, 0, _resolution, _resolution) - - -func _upload_region(channel: int, index: int, min_x: int, min_y: int, size_x: int, size_y: int): - #_logger.debug("Upload ", min_x, ", ", min_y, ", ", size_x, "x", size_y) - #var time_before = OS.get_ticks_msec() - - var map : HT_Map = _maps[channel][index] - - var image := map.image - assert(image != null) - assert(size_x > 0 and size_y > 0) - - # TODO Actually, I think the input params should be valid in the first place... - if min_x < 0: - min_x = 0 - if min_y < 0: - min_y = 0 - if min_x + size_x > image.get_width(): - size_x = image.get_width() - min_x - if min_y + size_y > image.get_height(): - size_y = image.get_height() - min_y - if size_x <= 0 or size_y <= 0: - return - - var texture := map.texture - - if texture == null or not (texture is ImageTexture): - # The texture doesn't exist yet in an editable format - if texture != null and not (texture is ImageTexture): - _logger.debug(str( - "_upload_region was used but the texture isn't an ImageTexture. ",\ - "The map ", channel, "[", index, "] will be reuploaded entirely.")) - else: - _logger.debug(str( - "_upload_region was used but the texture is not created yet. ",\ - "The map ", channel, "[", index, "] will be uploaded entirely.")) - - map.texture = ImageTexture.create_from_image(image) - - # Need to notify because other systems may want to grab the new texture object - map_changed.emit(channel, index) - - # TODO Unfortunately Texture2D.get_size() wasn't updated to use Vector2i in Godot 4 - elif Vector2i(texture.get_size()) != image.get_size(): - _logger.debug(str( - "_upload_region was used but the image size is different. ",\ - "The map ", channel, "[", index, "] will be reuploaded entirely.")) - - map.texture = ImageTexture.create_from_image(image) - - # Since Godot 4, need to notify because other systems may want to grab the new texture - # object. In Godot 3 it wasn't necessary because we were able to resize a texture without - # having to recreate it from scratch... - map_changed.emit(channel, index) - - else: - HT_Util.update_texture_partial(texture, image, - Rect2i(min_x, min_y, size_x, size_y), Vector2i(min_x, min_y)) - - #_logger.debug(str("Channel updated ", channel)) - - #var time_elapsed = OS.get_ticks_msec() - time_before - #_logger.debug(str("Texture upload time: ", time_elapsed, "ms")) - - -# Gets how many instances of a given map are present in the terrain data. -# A return value of 0 means there is no such map, and querying for it might cause errors. -func get_map_count(map_type: int) -> int: - if map_type < len(_maps): - return len(_maps[map_type]) - return 0 - - -# TODO Deprecated -func _edit_add_detail_map(): - return _edit_add_map(CHANNEL_DETAIL) - - -# TODO Deprecated -func _edit_remove_detail_map(index): - _edit_remove_map(CHANNEL_DETAIL, index) - - -func _edit_add_map(map_type: int) -> int: - # TODO Check minimum and maximum instances of a given map - _logger.debug(str("Adding map of type ", get_channel_name(map_type))) - while map_type >= len(_maps): - _maps.append([]) - var maps : Array = _maps[map_type] - var map := HT_Map.new(_get_free_id(map_type)) - map.image = Image.create(_resolution, _resolution, false, get_channel_format(map_type)) - var index := maps.size() - var default_color = _get_map_default_fill_color(map_type, index) - if default_color != null: - map.image.fill(default_color) - maps.append(map) - map_added.emit(map_type, index) - return index - - -# Editor-only. Used for undo/redo. -func _edit_insert_map_from_image_cache(map_type: int, index: int, image_cache, image_id: int): - if _edit_disable_apply_undo: - return - _logger.debug(str("Adding map of type ", get_channel_name(map_type), - " from an image at index ", index)) - while map_type >= len(_maps): - _maps.append([]) - var maps : Array = _maps[map_type] - var map := HT_Map.new(_get_free_id(map_type)) - map.image = image_cache.load_image(image_id) - maps.insert(index, map) - map_added.emit(map_type, index) - - -func _edit_remove_map(map_type: int, index: int): - # TODO Check minimum and maximum instances of a given map - _logger.debug(str("Removing map ", get_channel_name(map_type), " at index ", index)) - var maps : Array = _maps[map_type] - maps.remove_at(index) - map_removed.emit(map_type, index) - - -func _get_free_id(map_type: int) -> int: - var maps : Array = _maps[map_type] - var id := 0 - while _get_map_by_id(map_type, id) != null: - id += 1 - return id - - -func _get_map_by_id(map_type: int, id: int) -> HT_Map: - var maps : Array = _maps[map_type] - for map in maps: - if map.id == id: - return map - return null - - -func get_image(map_type: int, index := 0) -> Image: - var maps : Array = _maps[map_type] - var map : HT_Map = maps[index] - return map.image - - -func get_texture(map_type: int, index := 0, writable := false) -> Texture: - # TODO Split into `get_texture` and `get_writable_texture`? - - var maps : Array = _maps[map_type] - var map : HT_Map = maps[index] - - if map.image != null: - if map.texture == null: - _upload_channel(map_type, index) - elif writable and not (map.texture is ImageTexture): - _upload_channel(map_type, index) - else: - if writable: - _logger.warn(str("Requested writable terrain texture ", - get_map_debug_name(map_type, index), ", but it's not available in this context")) - - return map.texture - - -func has_texture(map_type: int, index: int) -> bool: - var maps = _maps[map_type] - return index < len(maps) - - -func get_aabb() -> AABB: - # TODO Why subtract 1? I forgot - # TODO Optimize for full region, this is actually quite costy - return get_region_aabb(0, 0, _resolution - 1, _resolution - 1) - - -# Not so useful in itself, but GDScript is slow, -# so I needed it to speed up the LOD hack I had to do to take height into account -func get_point_aabb(cell_x: int, cell_y: int) -> Vector2: - assert(typeof(cell_x) == TYPE_INT) - assert(typeof(cell_y) == TYPE_INT) - - var cx = cell_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cy = cell_y / VERTICAL_BOUNDS_CHUNK_SIZE - - if cx < 0: - cx = 0 - if cy < 0: - cy = 0 - if cx >= _chunked_vertical_bounds.get_width(): - cx = _chunked_vertical_bounds.get_width() - 1 - if cy >= _chunked_vertical_bounds.get_height(): - cy = _chunked_vertical_bounds.get_height() - 1 - - var b := _chunked_vertical_bounds.get_pixel(cx, cy) - return Vector2(b.r, b.g) - - -func get_region_aabb(origin_in_cells_x: int, origin_in_cells_y: int, - size_in_cells_x: int, size_in_cells_y: int) -> AABB: - - assert(typeof(origin_in_cells_x) == TYPE_INT) - assert(typeof(origin_in_cells_y) == TYPE_INT) - assert(typeof(size_in_cells_x) == TYPE_INT) - assert(typeof(size_in_cells_y) == TYPE_INT) - - # Get info from cached vertical bounds, - # which is a lot faster than directly fetching heights from the map. - # It's not 100% accurate, but enough for culling use case if chunk size is decently chosen. - - var cmin_x := origin_in_cells_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cmin_y := origin_in_cells_y / VERTICAL_BOUNDS_CHUNK_SIZE - - var cmax_x := (origin_in_cells_x + size_in_cells_x - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var cmax_y := (origin_in_cells_y + size_in_cells_y - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - cmin_x = clampi(cmin_x, 0, _chunked_vertical_bounds.get_width() - 1) - cmin_y = clampi(cmin_y, 0, _chunked_vertical_bounds.get_height() - 1) - cmax_x = clampi(cmax_x, 0, _chunked_vertical_bounds.get_width()) - cmax_y = clampi(cmax_y, 0, _chunked_vertical_bounds.get_height()) - - var min_height := _chunked_vertical_bounds.get_pixel(cmin_x, cmin_y).r - var max_height = min_height - - for y in range(cmin_y, cmax_y): - for x in range(cmin_x, cmax_x): - var b = _chunked_vertical_bounds.get_pixel(x, y) - min_height = minf(b.r, min_height) - max_height = maxf(b.g, max_height) - - var aabb = AABB() - aabb.position = Vector3(origin_in_cells_x, min_height, origin_in_cells_y) - aabb.size = Vector3(size_in_cells_x, max_height - min_height, size_in_cells_y) - - return aabb - - -func _update_all_vertical_bounds(): - var csize_x := _resolution / VERTICAL_BOUNDS_CHUNK_SIZE - var csize_y := _resolution / VERTICAL_BOUNDS_CHUNK_SIZE - _logger.debug(str("Updating all vertical bounds... (", csize_x , "x", csize_y, " chunks)")) - _chunked_vertical_bounds = Image.create(csize_x, csize_y, false, Image.FORMAT_RGF) - _update_vertical_bounds(0, 0, _resolution - 1, _resolution - 1) - - -func update_vertical_bounds(p_rect: Rect2): - var min_x := int(p_rect.position.x) - var min_y := int(p_rect.position.y) - var size_x := int(p_rect.size.x) - var size_y := int(p_rect.size.y) - - _update_vertical_bounds(min_x, min_y, size_x, size_y) - - -func _update_vertical_bounds(origin_in_cells_x: int, origin_in_cells_y: int, \ - size_in_cells_x: int, size_in_cells_y: int): - - var cmin_x := origin_in_cells_x / VERTICAL_BOUNDS_CHUNK_SIZE - var cmin_y := origin_in_cells_y / VERTICAL_BOUNDS_CHUNK_SIZE - - var cmax_x := (origin_in_cells_x + size_in_cells_x - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var cmax_y := (origin_in_cells_y + size_in_cells_y - 1) / VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - cmin_x = clampi(cmin_x, 0, _chunked_vertical_bounds.get_width() - 1) - cmin_y = clampi(cmin_y, 0, _chunked_vertical_bounds.get_height() - 1) - cmax_x = clampi(cmax_x, 0, _chunked_vertical_bounds.get_width()) - cmax_y = clampi(cmax_y, 0, _chunked_vertical_bounds.get_height()) - - # Note: chunks in _chunked_vertical_bounds share their edge cells and - # have an actual size of chunk size + 1. - var chunk_size_x := VERTICAL_BOUNDS_CHUNK_SIZE + 1 - var chunk_size_y := VERTICAL_BOUNDS_CHUNK_SIZE + 1 - - for y in range(cmin_y, cmax_y): - var pmin_y := y * VERTICAL_BOUNDS_CHUNK_SIZE - - for x in range(cmin_x, cmax_x): - var pmin_x := x * VERTICAL_BOUNDS_CHUNK_SIZE - var b = _compute_vertical_bounds_at(pmin_x, pmin_y, chunk_size_x, chunk_size_y) - _chunked_vertical_bounds.set_pixel(x, y, Color(b.x, b.y, 0)) - - -func _compute_vertical_bounds_at( - origin_x: int, origin_y: int, size_x: int, size_y: int) -> Vector2: - - var heights := get_image(CHANNEL_HEIGHT) - assert(heights != null) - match heights.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - return _get_heights_range_f(heights, Rect2i(origin_x, origin_y, size_x, size_y)) - Image.FORMAT_RGB8: - return _get_heights_range_rgb8(heights, Rect2i(origin_x, origin_y, size_x, size_y)) - _: - _logger.error(str("Unknown heightmap format ", heights.get_format())) - return Vector2() - - -static func _get_heights_range_rgb8(im: Image, rect: Rect2i) -> Vector2: - assert(im.get_format() == Image.FORMAT_RGB8) - - rect = rect.intersection(Rect2i(0, 0, im.get_width(), im.get_height())) - var min_x := rect.position.x - var min_y := rect.position.y - var max_x := min_x + rect.size.x - var max_y := min_y + rect.size.y - - var min_height := decode_height_from_rgb8_unorm(im.get_pixel(min_x, min_y)) - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h := decode_height_from_rgb8_unorm(im.get_pixel(x, y)) - min_height = minf(h, min_height) - max_height = maxf(h, max_height) - - return Vector2(min_height, max_height) - - -static func _get_heights_range_f(im: Image, rect: Rect2i) -> Vector2: - assert(im.get_format() == Image.FORMAT_RF or im.get_format() == Image.FORMAT_RH) - - rect = rect.intersection(Rect2i(0, 0, im.get_width(), im.get_height())) - var min_x := rect.position.x - var min_y := rect.position.y - var max_x := min_x + rect.size.x - var max_y := min_y + rect.size.y - - var min_height := im.get_pixel(min_x, min_y).r - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h := im.get_pixel(x, y).r - min_height = minf(h, min_height) - max_height = maxf(h, max_height) - - return Vector2(min_height, max_height) - - -func save_data(data_dir: String) -> bool: - _logger.debug("Saving terrain data...") - - _locked = true - - _save_metadata(data_dir.path_join(META_FILENAME)) - - var map_count = _get_total_map_count() - - var all_succeeded = true - - var pi = 0 - for map_type in CHANNEL_COUNT: - var maps : Array = _maps[map_type] - - for index in len(maps): - var map : HT_Map = maps[index] - if not map.modified: - _logger.debug(str( - "Skipping non-modified ", get_map_debug_name(map_type, index))) - continue - - _logger.debug(str("Saving map ", get_map_debug_name(map_type, index), - " as ", _get_map_filename(map_type, index), "...")) - - all_succeeded = all_succeeded and _save_map(data_dir, map_type, index) - - map.modified = false - pi += 1 - - # TODO Cleanup unused map files? - - # TODO In editor, trigger reimport on generated assets - _locked = false - - return all_succeeded - - -func _is_any_map_modified() -> bool: - for maplist in _maps: - for map in maplist: - if map.modified: - return true - return false - - -func _get_total_map_count() -> int: - var s = 0 - for maps in _maps: - s += len(maps) - return s - - -func _load_metadata(path: String): - var f = FileAccess.open(path, FileAccess.READ) - assert(f != null) - var text = f.get_as_text() - f = null # close file - var json = JSON.new() - var json_err := json.parse(text) - # Careful, `assert` is stripped in release exports, including its argument expression... - # See https://github.com/godotengine/godot-proposals/issues/502 - assert(json_err == OK) - _deserialize_metadata(json.data) - - -func _save_metadata(path: String): - var d = _serialize_metadata() - var text = JSON.stringify(d, "\t", true) - var f = FileAccess.open(path, FileAccess.WRITE) - var err = f.get_error() - assert(err == OK) - f.store_string(text) - - -func _serialize_metadata() -> Dictionary: - var data := [] - data.resize(len(_maps)) - - for i in range(len(_maps)): - var maps = _maps[i] - var maps_data := [] - - for j in range(len(maps)): - var map : HT_Map = maps[j] - maps_data.append({ "id": map.id }) - - data[i] = maps_data - - return { - "version": META_VERSION, - "maps": data - } - - -# Parse metadata that we'll then use to load the actual terrain -# (How many maps, which files to load etc...) -func _deserialize_metadata(dict: Dictionary) -> bool: - if not dict.has("version"): - _logger.error("Terrain metadata has no version") - return false - - if dict.version != META_VERSION: - _logger.error("Terrain metadata version mismatch. Got {0}, expected {1}" \ - .format([dict.version, META_VERSION])) - return false - - var data = dict["maps"] - assert(len(data) <= len(_maps)) - - for i in len(data): - var maps = _maps[i] - - var maps_data = data[i] - if len(maps) != len(maps_data): - maps.resize(len(maps_data)) - - for j in len(maps): - var map = maps[j] - # Cast because the data comes from json, where every number is double - var id := int(maps_data[j].id) - if map == null: - map = HT_Map.new(id) - maps[j] = map - else: - map.id = id - - return true - - -func load_data(dir_path: String, - # Same as default in ResourceLoader.load() - resource_loader_cache_mode := ResourceLoader.CACHE_MODE_REUSE): - - _locked = true - - _load_metadata(dir_path.path_join(META_FILENAME)) - - _logger.debug("Loading terrain data...") - - var channel_instance_sum = _get_total_map_count() - var pi = 0 - - # Note: if we loaded all maps at once before uploading them to VRAM, - # it would take a lot more RAM than if we load them one by one - for map_type in len(_maps): - var maps = _maps[map_type] - - for index in len(maps): - _logger.debug(str("Loading map ", get_map_debug_name(map_type, index), - " from ", _get_map_filename(map_type, index), "...")) - - _load_map(dir_path, map_type, index, resource_loader_cache_mode) - - # A map that was just loaded is considered not modified yet - maps[index].modified = false - - pi += 1 - - _logger.debug("Calculating vertical bounds...") - _update_all_vertical_bounds() - - _logger.debug("Notify resolution change...") - - _locked = false - resolution_changed.emit() - - -# Reloads the entire terrain from files, disregarding cached resources. -# This could be useful to reload a terrain while playing the game. You can do some edits in the -# editor, save the terrain and then reload in-game. -func reload(): - _logger.debug("Reloading terrain data...") - var dir_path := resource_path.get_base_dir() - load_data(dir_path, ResourceLoader.CACHE_MODE_IGNORE) - _logger.debug("Reloading terrain data done") - - # Debug -# var heightmap := get_image(CHANNEL_HEIGHT, 0) -# var im = Image.create(heightmap.get_width(), heightmap.get_height(), false, Image.FORMAT_RGB8) -# for y in heightmap.get_height(): -# for x in heightmap.get_width(): -# var h := heightmap.get_pixel(x, y).r * 0.1 -# var g := h - floorf(h) -# im.set_pixel(x, y, Color(g, g, g, 1.0)) -# im.save_png("local_tests/debug_data/reloaded_heightmap.png") - - -func get_data_dir() -> String: - # The HTerrainData resource represents the metadata and entry point for Godot. - # It should be placed within a folder dedicated for terrain storage. - # Other heavy data such as maps are stored next to that file. - return resource_path.get_base_dir() - - -func _save_map(dir_path: String, map_type: int, index: int) -> bool: - var map : HT_Map = _maps[map_type][index] - var im := map.image - if im == null: - var tex := map.texture - if tex != null: - _logger.debug(str("Image not found for map ", map_type, ", downloading from VRAM")) - im = tex.get_image() - else: - _logger.debug(str("No data in map ", map_type, "[", index, "]")) - # This data doesn't have such map - return true - - # The function says "absolute" but in reality it accepts paths like `res://x`, - # which from a user standpoint are not absolute. Also, `FileAccess.file_exists` exists but - # isn't named "absolute" :shrug: - if not DirAccess.dir_exists_absolute(dir_path): - var err := DirAccess.make_dir_absolute(dir_path) - if err != OK: - _logger.error("Could not create directory '{0}', error {1}" \ - .format([dir_path, HT_Errors.get_message(err)])) - return false - - var fpath := dir_path.path_join(_get_map_filename(map_type, index)) - - return _save_map_image(fpath, map_type, im) - - -func _save_map_image(fpath: String, map_type: int, im: Image) -> bool: - if _channel_can_be_saved_as_png(map_type): - fpath += ".png" - var err := im.save_png(fpath) - if err != OK: - _logger.error("Could not save '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return false - _try_write_default_import_options(fpath, map_type, _logger) - - else: - fpath += ".res" - var err := ResourceSaver.save(im, fpath) - if err != OK: - _logger.error("Could not save '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return false - - return true - - -static func _try_write_default_import_options( - fpath: String, channel: int, logger: HT_Logger.HT_LoggerBase): - - var imp_fpath := fpath + ".import" - if FileAccess.file_exists(imp_fpath): - # Already exists - return - - var map_info = _map_types[channel] - var srgb: bool = map_info.srgb - var tex_format: int = map_info.texture_format - - var defaults : Dictionary - - # To this day Godot still has no clean API to know what to write in these .import files. - # We have to find out what to write by manyally setting things up on a test file and see - # what Godot writes in the .import file. - # Sometimes values come directly from enums that are used in importers UI, - # and NOT the corresponding resource classes... - - if channel == CHANNEL_HEIGHT: - defaults = { - "remap": { - # Have the heightmap editable as an image by default - "importer": "image", - "type": "Image" - }, - "deps": { - "source_file": fpath - } - } - - else: - defaults = { - "remap": { - "importer": "texture", - "type": "CompressedTexture2D" - }, - "deps": { - "source_file": fpath - }, - "params": { - # Use lossless compression. - # Lossy ruins quality and makes the editor choke on big textures. - # Also, in case we want 8-bit per pixel uncompressed formats, using VRAM - # Uncompressed imports as L8, unlike Lossless, which imports as RGB8 even if the - # image is 8-bit depth (greyscale PNGs). It's confusing. - # I could not find any options to import as R8. - "compress/mode": 3 if tex_format == Image.FORMAT_L8 else 0, - - "compress/hdr_compression": 0, - "compress/normal_map": 0, - # No mipmaps - "mipmaps/limit": 0, - - # Most textures aren't color. - # Same here, this is mapping something from the import dock UI, - # and doesn't have any enum associated, just raw numbers in C++ code... - # 0 = "disabled", 1 = "enabled", 2 = "detect" - "flags/srgb": 2 if srgb else 0, - - # No need for this, the meaning of alpha is never transparency - "process/fix_alpha_border": false, - - # Don't try to be smart. - # This can actually overwrite the settings with defaults... - # https://github.com/godotengine/godot/issues/24220 - "detect_3d/compress_to": 0, - } - } - - HT_Util.write_import_file(defaults, imp_fpath, logger) - - -func _load_map(dir: String, map_type: int, index: int, resource_loader_cache_mode : int) -> bool: - var fpath := dir.path_join(_get_map_filename(map_type, index)) - - # Maps must be configured before being loaded - var map : HT_Map = _maps[map_type][index] - # while len(_maps) <= map_type: - # _maps.append([]) - # while len(_maps[map_type]) <= index: - # _maps[map_type].append(null) - # var map = _maps[map_type][index] - # if map == null: - # map = Map.new() - # _maps[map_type][index] = map - - if _channel_can_be_saved_as_png(map_type): - fpath += ".png" - else: - fpath += ".res" - - var tex = ResourceLoader.load(fpath, "", resource_loader_cache_mode) - - var must_load_image_in_editor := true - - if Engine.is_editor_hint(): - # Short-term compatibility with RGB8 encoding from the godot4 branch - if tex == null and map_type == CHANNEL_HEIGHT: - var legacy_fpath := fpath.get_basename() + ".png" - var temp = ResourceLoader.load(legacy_fpath, "", resource_loader_cache_mode) - if temp != null: - if temp is Texture2D: - temp = temp.get_image() - if temp is Image and temp.get_format() == Image.FORMAT_RGB8: - _logger.warn(str( - "Found a heightmap using legacy RGB8 format. It will be converted to RF. ", - "You may want to remove the old file: {0}").format([fpath])) - tex = convert_heightmap_to_float(temp, _logger) - # This is a different file so we can save without overwriting the old path - _save_map_image(fpath.get_basename(), map_type, tex) - - # Forward-compatibility with legacy format used in godot3 - if ENABLE_LEGACY_HEIGHTMAP_RH_CONVERSION_IN_EDITOR \ - and tex != null and map_type == CHANNEL_HEIGHT: - var temp := tex as Image - if temp == null and tex is Texture2D: - var tex_format := RenderingServer.texture_get_format(tex.get_rid()) - if tex_format == Image.FORMAT_RH: - # Downloads image from RenderingServer, might be expensive - temp = tex.get_image() - if temp != null and temp.get_format() == Image.FORMAT_RH: - _logger.warn(str( - "Found a heightmap using legacy RH format. It will be converted to RF. ", - "You may edit and re-save to make the upgrade persist.")) - temp.convert(Image.FORMAT_RF) - tex = temp - # Not saving yet to prevent unintentional data loss if anything goes wrong? - #_save_map_image(fpath.get_basename(), map_type, tex) - - if tex != null and tex is Image: - # The texture is imported as Image, - # perhaps the user wants it to be accessible from RAM in game. - _logger.debug("Map {0} is imported as Image. An ImageTexture will be generated." \ - .format([get_map_debug_name(map_type, index)])) - map.image = tex - tex = ImageTexture.create_from_image(map.image) - must_load_image_in_editor = false - - var texture_changed : bool = (tex != map.texture) - map.texture = tex - - if Engine.is_editor_hint(): - if must_load_image_in_editor: - # But in the editor we want textures to be editable, - # so we have to automatically load the data also in RAM - if map.image == null: - map.image = Image.load_from_file(ProjectSettings.globalize_path(fpath)) - else: - map.image.load(ProjectSettings.globalize_path(fpath)) - map.image = _ensure_map_format(map.image, map_type, index) - - if map_type == CHANNEL_HEIGHT: - _resolution = map.image.get_width() - - # Initially added to support reloading of an existing terrain (otherwise it's pointless to emit - # during scene loading when the resource isn't assigned yet) - if texture_changed: - map_changed.emit(map_type, index) - - return true - - -func _ensure_map_format(im: Image, map_type: int, index: int) -> Image: - var format := im.get_format() - var expected_format : int = _map_types[map_type].texture_format - - if format != expected_format: - _logger.warn("Map {0} loaded as format {1}, expected {2}. Will be converted." \ - .format([get_map_debug_name(map_type, index), format, expected_format])) - - if expected_format == Image.FORMAT_L8: - # `convert` won't do what we want here. We actually use L8 as a greyscale format - # because it uses less memory than other formats, not because it happens to be a - # "luminance" format. - # (R8 has issues so we can't use it, see comments elsewhere) - # `convert` takes color brightness into account, so "maximum red" pixels is NOT full - # bright in the L8 format. So R=255 degrades to 54 after conversion. - # In practice, we had density maps incorrectly saved/imported as RGB8 in the past. - # Using the current function to "fix" in case import settings are still wrong - # would make the image darker, and therefore, lower density, which is data loss. - # This behavior makes some sense, but is not clearly documented and not what we want. - # What we want is to keep the exact pixel values, and only - # use the minimal amount of channels to represents those values. - - # Truncate image channels to just what is in R - im.convert(Image.FORMAT_R8) - # Reinterpret as greyscale. - # Unfortunately there is not (anymore!) an API to do this without re-creating the - # object, so we had to modify the function to return the image instead of just - # modifying it. - im = Image.create_from_data( - im.get_width(), im.get_height(), false, Image.FORMAT_L8, im.get_data()) - else: - im.convert(expected_format) - - return im - - -# Imports images into the terrain data by converting them to the internal format. -# It is possible to omit some of them, in which case those already setup will be used. -# This function is quite permissive, and will only fail if there is really no way to import. -# It may involve cropping, so preliminary checks should be done to inform the user. -# -# TODO Plan is to make this function threaded, in case import takes too long. -# So anything that could mess with the main thread should be avoided. -# Eventually, it would be temporarily removed from the terrain node to work -# in isolation during import. -func _edit_import_maps(input: Dictionary) -> bool: - assert(typeof(input) == TYPE_DICTIONARY) - - if input.has(CHANNEL_HEIGHT): - var params = input[CHANNEL_HEIGHT] - if not _import_heightmap( - params.path, params.min_height, params.max_height, params.big_endian, params.bit_depth): - return false - - # TODO Import indexed maps? - var maptypes := [CHANNEL_COLOR, CHANNEL_SPLAT] - - for map_type in maptypes: - if input.has(map_type): - var params = input[map_type] - if not _import_map(map_type, params.path): - return false - - return true - - -# Provided an arbitrary width and height, -# returns the closest size the terrain actuallysupports -static func get_adjusted_map_size(width: int, height: int) -> int: - var width_po2 = HT_Util.next_power_of_two(width - 1) + 1 - var height_po2 = HT_Util.next_power_of_two(height - 1) + 1 - var size_po2 = mini(width_po2, height_po2) - size_po2 = clampi(size_po2, MIN_RESOLUTION, MAX_RESOLUTION) - return size_po2 - - -func _import_heightmap(fpath: String, min_y: float, max_y: float, big_endian: bool, - bit_depth: int) -> bool: - - var ext := fpath.get_extension().to_lower() - - if ext == "png": - # Godot can only load 8-bit PNG, - # so we have to bring it back to float in the wanted range - - var src_image := Image.load_from_file(ProjectSettings.globalize_path(fpath)) - # TODO No way to access the error code? - if src_image == null: - return false - - var res := get_adjusted_map_size(src_image.get_width(), src_image.get_height()) - if res != src_image.get_width(): - src_image.crop(res, res) - - _locked = true - - _logger.debug(str("Resizing terrain to ", res, "x", res, "...")) - resize(src_image.get_width(), false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - var hrange := max_y - min_y - - var width := mini(im.get_width(), src_image.get_width()) - var height := mini(im.get_height(), src_image.get_height()) - - _logger.debug("Converting to internal format...") - - # Convert to internal format with range scaling - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - for y in width: - for x in height: - var gs := src_image.get_pixel(x, y).r - var h := min_y + hrange * gs - im.set_pixel(x, y, Color(h, h, h)) - Image.FORMAT_RGB8: - for y in width: - for x in height: - var gs := src_image.get_pixel(x, y).r - var h := min_y + hrange * gs - im.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - elif ext == "exr": - var src_image := Image.load_from_file(ProjectSettings.globalize_path(fpath)) - # TODO No way to access the error code? - if src_image == null: - return false - - var res := get_adjusted_map_size(src_image.get_width(), src_image.get_height()) - if res != src_image.get_width(): - src_image.crop(res, res) - - _locked = true - - _logger.debug(str("Resizing terrain to ", res, "x", res, "...")) - resize(src_image.get_width(), false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - _logger.debug("Converting to internal format...") - - match im.get_format(): - Image.FORMAT_RF: - # See https://github.com/Zylann/godot_heightmap_plugin/issues/34 - # Godot can load EXR but it always makes them have at least 3-channels. - # Heightmaps need only one, so we have to get rid of 2. - var height_format : int = _map_types[CHANNEL_HEIGHT].texture_format - src_image.convert(height_format) - im.blit_rect(src_image, Rect2i(0, 0, res, res), Vector2i()) - - # Legacy format? - Image.FORMAT_RH: - var height_format : int = _map_types[CHANNEL_HEIGHT].texture_format - src_image.convert(height_format) - # Exception: instead of keeping the old format, - # convert to use the preferred format to allow upgrading old maps - im.convert(height_format) - im.blit_rect(src_image, Rect2i(0, 0, res, res), Vector2i()) - - Image.FORMAT_RGB8: - convert_float_heightmap_to_rgb8(src_image, im) - - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - elif ext == "raw": - # RAW files don't contain size, so we take the user's bit depth import choice. - # We also need to bring it back to float in the wanted range. - - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - return false - - var file_len := f.get_length() - var file_res := HT_Util.integer_square_root(file_len / (bit_depth/8)) - if file_res == -1: - # Can't deduce size - return false - - # TODO Need a way to know which endianess our system has! - # For now we have to make an assumption... - # This function is most supposed to execute in the editor. - # The editor officially runs on desktop architectures, which are - # generally little-endian. - if big_endian: - f.big_endian = true - - var res := get_adjusted_map_size(file_res, file_res) - - var width := res - var height := res - - _locked = true - - _logger.debug(str("Resizing terrain to ", width, "x", height, "...")) - resize(res, false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - var hrange := max_y - min_y - - _logger.debug("Converting to internal format...") - - var rw := mini(res, file_res) - var rh := mini(res, file_res) - - # Convert to internal format - var h := 0.0 - if bit_depth == BIT_DEPTH_32: - for y in rh: - for x in rw: - var gs := float(f.get_32()) / 4294967295.0 - h = min_y + hrange * float(gs) - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - im.set_pixel(x, y, Color(h, 0, 0)) - Image.FORMAT_RGB8: - im.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - return false - - # Skip next pixels if the file is bigger than the accepted resolution - for x in range(rw, file_res): - f.get_32() - else: - # Assuming 16-bit - for y in rh: - for x in rw: - var gs := float(f.get_16()) / 65535.0 - h = min_y + hrange * float(gs) - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - im.set_pixel(x, y, Color(h, 0, 0)) - Image.FORMAT_RGB8: - im.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - return false - - # Skip next pixels if the file is bigger than the accepted resolution - for x in range(rw, file_res): - f.get_16() - - elif ext == "xyz": - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - return false - - var bounds := HT_XYZFormat.load_bounds(f) - var res := get_adjusted_map_size(bounds.image_width, bounds.image_height) - - var width := res - var height := res - - _locked = true - - _logger.debug(str("Resizing terrain to ", width, "x", height, "...")) - resize(res, false, Vector2()) - - var im := get_image(CHANNEL_HEIGHT) - assert(im != null) - - im.fill(Color(0,0,0)) - - _logger.debug(str("Parsing XYZ file (this can take a while)...")) - f.seek(0) - var src_format := Image.FORMAT_RF - if im.get_format() == Image.FORMAT_RH: - src_format = im.get_format() - var float_heightmap := Image.create(im.get_width(), im.get_height(), false, src_format) - HT_XYZFormat.load_heightmap(f, float_heightmap, bounds) - - # Flipping because in Godot, for X to mean "east"/"right", Z must be backward, - # and we are using Z to map the Y axis of the heightmap image. - float_heightmap.flip_y() - - match im.get_format(): - Image.FORMAT_RF, \ - Image.FORMAT_RH: - im.blit_rect(float_heightmap, Rect2i(0, 0, res, res), Vector2i()) - Image.FORMAT_RGB8: - convert_float_heightmap_to_rgb8(float_heightmap, im) - _: - _logger.error(str("Invalid heightmap format ", im.get_format())) - - # Note: when importing maps with non-compliant sizes and flipping, - # the result might not be aligned to global coordinates. - # If this is a problem, we could just offset the terrain to compensate? - - else: - # File extension not recognized - return false - - _locked = false - - _logger.debug("Notify region change...") - notify_region_change(Rect2(0, 0, get_resolution(), get_resolution()), CHANNEL_HEIGHT) - - return true - - -func _import_map(map_type: int, path: String) -> bool: - # Heightmap requires special treatment - assert(map_type != CHANNEL_HEIGHT) - - var im := Image.load_from_file(ProjectSettings.globalize_path(path)) - # TODO No way to get the error code? - if im == null: - return false - - var res := get_resolution() - if im.get_width() != res or im.get_height() != res: - im.crop(res, res) - - if im.get_format() != get_channel_format(map_type): - im.convert(get_channel_format(map_type)) - - var map : HT_Map = _maps[map_type][0] - map.image = im - - notify_region_change(Rect2(0, 0, im.get_width(), im.get_height()), map_type) - return true - - -# TODO Workaround for https://github.com/Zylann/godot_heightmap_plugin/issues/101 -func _dummy_function(): - pass - - -static func _get_xz(v: Vector3) -> Vector2: - return Vector2(v.x, v.z) - - -class HT_CellRaycastContext: - var begin_pos := Vector3() - var _cell_begin_pos_y := 0.0 - var _cell_begin_pos_2d := Vector2() - var dir := Vector3() - var dir_2d := Vector2() - var vertical_bounds : Image - var hit = null # Vector3 - var heightmap : Image - var broad_param_2d_to_3d := 1.0 - var cell_param_2d_to_3d := 1.0 - # TODO Can't call static functions of the enclosing class..................... - var decode_height_func : Callable - #var dbg - - func broad_cb(cx: int, cz: int, enter_param: float, exit_param: float) -> bool: - if cx < 0 or cz < 0 or cz >= vertical_bounds.get_height() \ - or cx >= vertical_bounds.get_width(): - # The function may occasionally be called at boundary values - return false - var vb := vertical_bounds.get_pixel(cx, cz) - var begin := begin_pos + dir * (enter_param * broad_param_2d_to_3d) - var exit_y := begin_pos.y + dir.y * exit_param * broad_param_2d_to_3d - #_spawn_box(Vector3(cx * VERTICAL_BOUNDS_CHUNK_SIZE, \ - # begin.y, cz * VERTICAL_BOUNDS_CHUNK_SIZE), 2.0) - if begin.y < vb.r or exit_y > vb.g: - # Not hitting this chunk - return false - # We may be hitting something in this chunk, perform a narrow phase - # through terrain cells - var distance_in_chunk_2d := (exit_param - enter_param) * VERTICAL_BOUNDS_CHUNK_SIZE - var cell_ray_origin_2d := Vector2(begin.x, begin.z) - _cell_begin_pos_y = begin.y - _cell_begin_pos_2d = cell_ray_origin_2d - var rhit = HT_Util.grid_raytrace_2d( - cell_ray_origin_2d, dir_2d, cell_cb, distance_in_chunk_2d) - return rhit != null - - func cell_cb(cx: int, cz: int, enter_param: float, exit_param: float) -> bool: - var enter_pos := _cell_begin_pos_2d + dir_2d * enter_param - #var exit_pos := _cell_begin_pos_2d + dir_2d * exit_param - - var enter_y := _cell_begin_pos_y + dir.y * enter_param * cell_param_2d_to_3d - var exit_y := _cell_begin_pos_y + dir.y * exit_param * cell_param_2d_to_3d - - hit = _intersect_cell(heightmap, cx, cz, Vector3(enter_pos.x, enter_y, enter_pos.y), dir, - decode_height_func) - - return hit != null - - static func _intersect_cell(heightmap: Image, cx: int, cz: int, - begin_pos: Vector3, dir: Vector3, decode_func : Callable): - - var c00 := HT_Util.get_pixel_clamped(heightmap, cx, cz) - var c10 := HT_Util.get_pixel_clamped(heightmap, cx + 1, cz) - var c01 := HT_Util.get_pixel_clamped(heightmap, cx, cz + 1) - var c11 := HT_Util.get_pixel_clamped(heightmap, cx + 1, cz + 1) - - var h00 : float = decode_func.call(c00) - var h10 : float = decode_func.call(c10) - var h01 : float = decode_func.call(c01) - var h11 : float = decode_func.call(c11) - - var p00 := Vector3(cx, h00, cz) - var p10 := Vector3(cx + 1, h10, cz) - var p01 := Vector3(cx, h01, cz + 1) - var p11 := Vector3(cx + 1, h11, cz + 1) - - var th0 = Geometry3D.ray_intersects_triangle(begin_pos, dir, p00, p10, p11) - var th1 = Geometry3D.ray_intersects_triangle(begin_pos, dir, p00, p11, p01) - - if th0 != null: - return th0 - return th1 - -# func _spawn_box(pos: Vector3, r: float): -# if not Input.is_key_pressed(KEY_CONTROL): -# return -# var mi = MeshInstance.new() -# mi.mesh = CubeMesh.new() -# mi.translation = pos * dbg.map_scale -# mi.scale = Vector3(r, r, r) -# dbg.add_child(mi) -# mi.owner = dbg.get_tree().edited_scene_root - - -# Raycasts heightmap image directly without using a collider. -# The coordinate system is such that Y is up, terrain minimum corner is at (0, 0), -# and one heightmap pixel is one space unit. -# TODO Cannot hint as `-> Vector2` because it can be null if there is no hit -func cell_raycast(ray_origin: Vector3, ray_direction: Vector3, max_distance: float): - var heightmap := get_image(CHANNEL_HEIGHT) - if heightmap == null: - return null - - var terrain_rect := Rect2(Vector2(), Vector2(_resolution, _resolution)) - - # Project and clip into 2D - var ray_origin_2d := _get_xz(ray_origin) - var ray_end_2d := _get_xz(ray_origin + ray_direction * max_distance) - var clipped_segment_2d := HT_Util.get_segment_clipped_by_rect(terrain_rect, - ray_origin_2d, ray_end_2d) - # TODO We could clip along Y too if we had total AABB cached somewhere - - if len(clipped_segment_2d) == 0: - # Not hitting the terrain area - return null - - var max_distance_2d := ray_origin_2d.distance_to(ray_end_2d) - if max_distance_2d < 0.001: - # TODO Direct vertical hit? - return null - - # Get ratio along the segment where the first point was clipped - var begin_clip_param := ray_origin_2d.distance_to(clipped_segment_2d[0]) / max_distance_2d - - var ray_direction_2d := _get_xz(ray_direction).normalized() - - var ctx := HT_CellRaycastContext.new() - ctx.begin_pos = ray_origin + ray_direction * (begin_clip_param * max_distance) - ctx.dir = ray_direction - ctx.dir_2d = ray_direction_2d - ctx.vertical_bounds = _chunked_vertical_bounds - ctx.heightmap = heightmap - ctx.cell_param_2d_to_3d = max_distance / max_distance_2d - ctx.broad_param_2d_to_3d = ctx.cell_param_2d_to_3d * VERTICAL_BOUNDS_CHUNK_SIZE - - match heightmap.get_format(): - Image.FORMAT_RH, \ - Image.FORMAT_RF: - ctx.decode_height_func = decode_height_from_f - Image.FORMAT_RGB8: - ctx.decode_height_func = decode_height_from_rgb8_unorm - _: - _logger.error(str("Invalid heightmap format ", heightmap.get_format())) - return null - - #ctx.dbg = dbg - - # Broad phase through cached vertical bound chunks - var broad_ray_origin = clipped_segment_2d[0] / VERTICAL_BOUNDS_CHUNK_SIZE - var broad_max_distance = \ - clipped_segment_2d[0].distance_to(clipped_segment_2d[1]) / VERTICAL_BOUNDS_CHUNK_SIZE - var hit_bp = HT_Util.grid_raytrace_2d(broad_ray_origin, ray_direction_2d, ctx.broad_cb, - broad_max_distance) - - if hit_bp == null: - # No hit - return null - - return Vector2(ctx.hit.x, ctx.hit.z) - - -static func encode_normal(n: Vector3) -> Color: - n = 0.5 * (n + Vector3.ONE) - return Color(n.x, n.z, n.y) - - -static func get_channel_format(channel: int) -> int: - return _map_types[channel].texture_format as int - - -# Note: PNG supports 16-bit channels, unfortunately Godot doesn't -static func _channel_can_be_saved_as_png(channel: int) -> bool: - return _map_types[channel].can_be_saved_as_png - - -static func get_channel_name(c: int) -> String: - return _map_types[c].name as String - - -static func get_map_debug_name(map_type: int, index: int) -> String: - return str(get_channel_name(map_type), "[", index, "]") - - -func _get_map_filename(map_type: int, index: int) -> String: - var name = get_channel_name(map_type) - var id = _maps[map_type][index].id - if id > 0: - name += str(id + 1) - return name - - -static func get_map_shader_param_name(map_type: int, index: int) -> String: - var param_name = _map_types[map_type].shader_param_name - if typeof(param_name) == TYPE_STRING: - return param_name - return param_name[index] - - -# TODO Can't type hint because it returns a nullable array -#static func get_map_type_and_index_from_shader_param_name(p_name: String): -# for map_type in _map_types: -# var pn = _map_types[map_type].shader_param_name -# if typeof(pn) == TYPE_STRING: -# if pn == p_name: -# return [map_type, 0] -# else: -# for i in len(pn): -# if pn[i] == p_name: -# return [map_type, i] -# return null - - -static func decode_height_from_f(c: Color) -> float: - return c.r - - -const _V2_UNIT_STEPS = 1024.0 -const _V2_MIN = -8192.0 -const _V2_MAX = 8191.0 -const _V2_DF = 255.0 / _V2_UNIT_STEPS - -# This RGB8 encoding implementation is specific to this plugin. -# It was used in the port to Godot 4.0 for a time, until it was found float -# textures could be used. - -static func decode_height_from_rgb8_unorm(c: Color) -> float: - return (c.r * 0.25 + c.g * 64.0 + c.b * 16384.0) * (4.0 * _V2_DF) + _V2_MIN - - -static func encode_height_to_rgb8_unorm(h: float) -> Color: - h -= _V2_MIN - var i := int(h * _V2_UNIT_STEPS) - var r := i % 256 - var g := (i / 256) % 256 - var b := i / 65536 - return Color(r, g, b, 255.0) / 255.0 - - -static func convert_heightmap_to_float(src: Image, logger: HT_Logger.HT_LoggerBase) -> Image: - var src_format := src.get_format() - - if src_format == Image.FORMAT_RH: - var im : Image = src.duplicate() - im.convert(Image.FORMAT_RF) - return im - - if src_format == Image.FORMAT_RF: - return src.duplicate() as Image - - if src_format == Image.FORMAT_RGB8: - var im := Image.create(src.get_width(), src.get_height(), false, Image.FORMAT_RF) - for y in src.get_height(): - for x in src.get_width(): - var c := src.get_pixel(x, y) - var h := decode_height_from_rgb8_unorm(c) - im.set_pixel(x, y, Color(h, h, h, 1.0)) - return im - - logger.error("Unknown source heightmap format!") - return null - - -static func convert_float_heightmap_to_rgb8(src: Image, dst: Image): - assert(dst.get_format() == Image.FORMAT_RGB8) - assert(dst.get_size() == src.get_size()) - - for y in src.get_height(): - for x in src.get_width(): - var h = src.get_pixel(x, y).r - dst.set_pixel(x, y, encode_height_to_rgb8_unorm(h)) diff --git a/godot/addons/zylann.hterrain/hterrain_data.gd.uid b/godot/addons/zylann.hterrain/hterrain_data.gd.uid deleted file mode 100644 index 1cb763d..0000000 --- a/godot/addons/zylann.hterrain/hterrain_data.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vihj6hb616t3 diff --git a/godot/addons/zylann.hterrain/hterrain_detail_layer.gd b/godot/addons/zylann.hterrain/hterrain_detail_layer.gd deleted file mode 100644 index 9a79427..0000000 --- a/godot/addons/zylann.hterrain/hterrain_detail_layer.gd +++ /dev/null @@ -1,914 +0,0 @@ -@tool -extends Node3D - -# Child node of the terrain, used to render numerous small objects on the ground -# such as grass or rocks. They do so by using a texture covering the terrain -# (a "detail map"), which is found in the terrain data itself. -# A terrain can have multiple detail maps, and you can choose which one will be -# used with `layer_index`. -# Details use instanced rendering within their own chunk grid, scattered around -# the player. Importantly, the position and rotation of this node don't matter, -# and they also do NOT scale with map scale. Indeed, scaling the heightmap -# doesn't mean we want to scale grass blades (which is not a use case I know of). - -const HTerrainData = preload("./hterrain_data.gd") -const HT_DirectMultiMeshInstance = preload("./util/direct_multimesh_instance.gd") -const HT_DirectMeshInstance = preload("./util/direct_mesh_instance.gd") -const HT_Util = preload("./util/util.gd") -const HT_Logger = preload("./util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const DEFAULT_MESH_PATH = "res://addons/zylann.hterrain/models/grass_quad.obj" - -# Cannot use `const` because `HTerrain` depends on the current script -var HTerrain = load("res://addons/zylann.hterrain/hterrain.gd") - -const CHUNK_SIZE = 32 -const DEFAULT_SHADER_PATH = "res://addons/zylann.hterrain/shaders/detail.gdshader" -const DEBUG = false - -# These parameters are considered built-in, -# they are managed internally so they are not directly exposed -const _API_SHADER_PARAMS = { - "u_terrain_heightmap": true, - "u_terrain_detailmap": true, - "u_terrain_normalmap": true, - "u_terrain_globalmap": true, - "u_terrain_inverse_transform": true, - "u_terrain_normal_basis": true, - "u_albedo_alpha": true, - "u_view_distance": true, - "u_ambient_wind": true -} - -# TODO Should be renamed `map_index` -# Which detail map this layer will use -@export var layer_index := 0: - get: - return layer_index - set(v): - if layer_index == v: - return - layer_index = v - if is_inside_tree(): - _update_material() - HT_Util.update_configuration_warning(self, false) - - -# Texture to render on the detail meshes. -@export var texture : Texture: - get: - return texture - set(tex): - texture = tex - _material.set_shader_parameter("u_albedo_alpha", tex) - - -# How far detail meshes can be seen. -# TODO Improve speed of _get_chunk_aabb() so we can increase the limit -# See https://github.com/Zylann/godot_heightmap_plugin/issues/155 -@export_range(1.0, 500.0) var view_distance := 100.0: - get: - return view_distance - set(v): - if view_distance == v: - return - view_distance = maxf(v, 1.0) - if is_inside_tree(): - _update_material() - - -# Custom shader to replace the default one. -@export var custom_shader : Shader: - get: - return custom_shader - - set(shader): - if custom_shader == shader: - return - - if custom_shader != null: - if Engine.is_editor_hint(): - custom_shader.changed.disconnect(_on_custom_shader_changed) - - custom_shader = shader - - if custom_shader == null: - _material.shader = load(DEFAULT_SHADER_PATH) - else: - _material.shader = custom_shader - - if Engine.is_editor_hint(): - # Ability to fork default shader - if shader.code == "": - shader.code = _default_shader.code - - custom_shader.changed.connect(_on_custom_shader_changed) - - notify_property_list_changed() - - -# Density modifier, to make more or less detail meshes appear overall. -@export_range(0, 10) var density := 4.0: - get: - return density - set(v): - v = clampf(v, 0, 10) - if v == density: - return - density = v - _multimesh_need_regen = true - - -# Sets the seed of the random number generator that populates the multimesh -@export var fixed_seed := 0: - get: - return fixed_seed - set(v): - if v == fixed_seed: - return - fixed_seed = v - _multimesh_need_regen = true - - -# If false, the multimesh seed will be picked from current time. -# Otherwise, `fixed_seed` will be used. -# Defaults to `false` because that was the behavior on old versions. -@export var fixed_seed_enabled := false: - get: - return fixed_seed_enabled - set(v): - if v == fixed_seed_enabled: - return - fixed_seed_enabled = v - _multimesh_need_regen = true - - -# Mesh used for every detail instance (for example, every grass patch). -# If not assigned, an internal quad mesh will be used. -# I would have called it `mesh` but that's too broad and conflicts with local vars ._. -@export var instance_mesh : Mesh: - get: - return instance_mesh - set(p_mesh): - if p_mesh == instance_mesh: - return - instance_mesh = p_mesh - _multimesh.mesh = _get_used_mesh() - - -# Exposes rendering layers, similar to `VisualInstance.layers` -# (IMO this annotation is not specific enough, something might be off...) -@export_flags_3d_render var render_layers := 1: - get: - return render_layers - set(mask): - render_layers = mask - for k in _chunks: - var chunk : Chunk = _chunks[k] - chunk.mmi.set_layer_mask(mask) - - -# Exposes shadow casting setting. -# Possible values are the same as the enum `GeometryInstance.SHADOW_CASTING_SETTING_*`. -# TODO Casting to `int` should not be necessary! Had to do it otherwise GDScript complains... -@export_enum("Off", "On", "DoubleSided", "ShadowsOnly") \ - var cast_shadow := int(GeometryInstance3D.SHADOW_CASTING_SETTING_ON): - get: - return cast_shadow - set(option): - if option == cast_shadow: - return - cast_shadow = option - for k in _chunks: - var chunk : Chunk = _chunks[k] - chunk.mmi.set_cast_shadow(option) - - -class Chunk: - var mmi: HT_DirectMultiMeshInstance - var pending_update: bool = false - var pending_aabb_update: bool = false - - -var _material: ShaderMaterial = null -var _default_shader: Shader = null - -# Vector2i => Chunk -var _chunks := {} - -var _multimesh: MultiMesh -var _multimesh_need_regen = true -var _multimesh_instance_pool : Array[HT_DirectMultiMeshInstance] = [] -var _ambient_wind_time := 0.0 -#var _auto_pick_index_on_enter_tree := Engine.is_editor_hint() -var _debug_wirecube_mesh: Mesh = null -var _debug_cubes := [] -var _logger := HT_Logger.get_for(self) -var _prev_frame_cmin := Vector3i() -var _prev_frame_cmax := Vector3i() -var _pending_chunk_updates : Array[Vector2i] = [] -var _force_chunk_updates_next_frame : bool = false - - -func _init(): - _default_shader = load(DEFAULT_SHADER_PATH) - _material = ShaderMaterial.new() - _material.shader = _default_shader - - _multimesh = MultiMesh.new() - _multimesh.transform_format = MultiMesh.TRANSFORM_3D - # TODO Godot 3 had the option to specify color format, but Godot 4 no longer does... - # I only need 8-bit, but Godot 4 uses 32-bit components colors... - #_multimesh.color_format = MultiMesh.COLOR_8BIT - _multimesh.use_colors = true - - -func _enter_tree(): - var terrain = _get_terrain() - if terrain != null: - terrain.transform_changed.connect(_on_terrain_transform_changed) - - #if _auto_pick_index_on_enter_tree: - # _auto_pick_index_on_enter_tree = false - # _auto_pick_index() - - # Register this detail layer in the terrain node (this does not create a new layer) - terrain._internal_add_detail_layer(self) - - _update_material() - - -func _exit_tree(): - var terrain = _get_terrain() - if terrain != null: - terrain.transform_changed.disconnect(_on_terrain_transform_changed) - # Unregister from terrain - terrain._internal_remove_detail_layer(self) - _update_material() - for k in _chunks.keys(): - _recycle_chunk(k) - _chunks.clear() - - -#func _auto_pick_index(): -# # Automatically pick an unused layer -# -# var terrain = _get_terrain() -# if terrain == null: -# return -# -# var terrain_data = terrain.get_data() -# if terrain_data == null or terrain_data.is_locked(): -# return -# -# var auto_index := layer_index -# var others = terrain.get_detail_layers() -# -# if len(others) > 0: -# var used_layers := [] -# for other in others: -# used_layers.append(other.layer_index) -# used_layers.sort() -# -# auto_index = used_layers[-1] -# for i in range(1, len(used_layers)): -# if used_layers[i - 1] - used_layers[i] > 1: -# # Found a hole, take it instead -# auto_index = used_layers[i] - 1 -# break -# -# print("Auto picked ", auto_index, " ") -# layer_index = auto_index - - -func _get_property_list() -> Array: - # Dynamic properties coming from the shader - var props := [] - if _material != null: - var shader_params = _material.shader.get_shader_uniform_list(true) - for p in shader_params: - if _API_SHADER_PARAMS.has(p.name): - continue - var cp := {} - for k in p: - cp[k] = p[k] - # See HTerrain._get_property_list for more information about this - if cp.usage == PROPERTY_USAGE_GROUP: - cp.hint_string = "shader_params/" - else: - cp.name = str("shader_params/", p.name) - props.append(cp) - return props - - -func _get(key: StringName): - var key_str := String(key) - if key_str.begins_with("shader_params/"): - var param_name = key_str.substr(len("shader_params/")) - return get_shader_param(param_name) - - -func _set(key: StringName, v): - var key_str := String(key) - if key_str.begins_with("shader_params/"): - var param_name = key_str.substr(len("shader_params/")) - set_shader_param(param_name, v) - - -func get_shader_param(param_name: String): - return HT_Util.get_shader_material_parameter(_material, param_name) - - -func set_shader_param(param_name: String, v): - _material.set_shader_parameter(param_name, v) - - -func _get_terrain(): - if is_inside_tree(): - return get_parent() - return null - - -# Compat -func set_texture(tex: Texture): - texture = tex - - -# Compat -func get_texture() -> Texture: - return texture - - -# Compat -func set_layer_index(v: int): - layer_index = v - - -# Compat -func get_layer_index() -> int: - return layer_index - - -# Compat -func set_view_distance(v: float): - return view_distance - - -# Compat -func get_view_distance() -> float: - return view_distance - - -# Compat -func set_custom_shader(shader: Shader): - custom_shader = shader - - -# Compat -func get_custom_shader() -> Shader: - return custom_shader - - -# Compat -func set_instance_mesh(p_mesh: Mesh): - instance_mesh = p_mesh - - -# Compat -func get_instance_mesh() -> Mesh: - return instance_mesh - - -# Compat -func set_render_layer_mask(mask: int): - render_layers = mask - - -# Compat -func get_render_layer_mask() -> int: - return render_layers - - -func _get_used_mesh() -> Mesh: - if instance_mesh == null: - var mesh := load(DEFAULT_MESH_PATH) as Mesh - if mesh == null: - _logger.error(str("Failed to load default mesh: ", DEFAULT_MESH_PATH)) - return mesh - return instance_mesh - - -# Compat -func set_density(v: float): - density = v - - -# Compat -func get_density() -> float: - return density - - -# Updates texture references and values that come from the terrain itself. -# This is typically used when maps are being swapped around in terrain data, -# so we can restore texture references that may break. -func update_material(): - _update_material() - # Formerly update_ambient_wind, reset - - -func _notification(what: int): - match what: - NOTIFICATION_ENTER_WORLD: - _set_world(get_world_3d()) - - NOTIFICATION_EXIT_WORLD: - _set_world(null) - - NOTIFICATION_VISIBILITY_CHANGED: - _set_visible(is_visible_in_tree()) - - NOTIFICATION_PREDELETE: - # Force DirectMeshInstances to be destroyed before the material. - # Otherwise it causes RenderingServer errors... - _chunks.clear() - _multimesh_instance_pool.clear() - - -func _set_visible(v: bool): - for k in _chunks: - var chunk : Chunk = _chunks[k] - chunk.mmi.set_visible(v) - - -func _set_world(w: World3D): - for k in _chunks: - var chunk : Chunk = _chunks[k] - chunk.mmi.set_world(w) - - -func _on_terrain_transform_changed(gt: Transform3D): - _update_material() - - var terrain = _get_terrain() - if terrain == null: - _logger.error("Detail layer is not child of a terrain!") - return - - var terrain_transform : Transform3D = terrain.get_internal_transform_unscaled() - - # Update AABBs and transforms, because scale might have changed - for k in _chunks: - var chunk : Chunk = _chunks[k] - var mmi := chunk.mmi - var aabb := _get_chunk_aabb(terrain, Vector3(k.x * CHUNK_SIZE, 0, k.y * CHUNK_SIZE)) - # Nullify XZ translation because that's done by transform already - aabb.position.x = 0 - aabb.position.z = 0 - mmi.set_aabb(aabb) - mmi.set_transform(_get_chunk_transform(terrain_transform, k.x, k.y)) - - -func process(delta: float, viewer_pos: Vector3): - var terrain = _get_terrain() - if terrain == null: - _logger.error("DetailLayer processing while terrain is null!") - return - - if _multimesh_need_regen: - print("Regen multimesh") - _regen_multimesh() - _multimesh_need_regen = false - # Crash workaround for Godot 3.1 - # See https://github.com/godotengine/godot/issues/32500 - for k in _chunks: - var chunk : Chunk = _chunks[k] - chunk.mmi.set_multimesh(_multimesh) - - # Detail layers are unaffected by ground map_scale - var terrain_transform_without_map_scale : Transform3D = \ - terrain.get_internal_transform_unscaled() - var local_viewer_pos : Vector3 = \ - terrain_transform_without_map_scale.affine_inverse() * viewer_pos - - var viewer_cpos := Vector3i(local_viewer_pos / CHUNK_SIZE) - - var cr := int(view_distance) / CHUNK_SIZE + 1 - - var cmin := viewer_cpos - Vector3i(cr, cr, cr) - var cmax := viewer_cpos + Vector3i(cr, cr, cr) - - var terrain_data : HTerrainData = terrain.get_data() - var map_res := terrain_data.get_resolution() - var map_scale : Vector3 = terrain.map_scale - - var terrain_size_v2i := Vector2i(map_res * map_scale.x, map_res * map_scale.z) - var terrain_num_chunks_v2i := terrain_size_v2i / CHUNK_SIZE - - cmin.x = clampi(cmin.x, 0, terrain_num_chunks_v2i.x) - cmin.z = clampi(cmin.z, 0, terrain_num_chunks_v2i.y) - - cmax.x = clampi(cmax.x, 0, terrain_num_chunks_v2i.x) - cmax.z = clampi(cmax.z, 0, terrain_num_chunks_v2i.y) - - # This algorithm isn't the most efficient ever. - # Maybe we could switch to a clipbox algorithm eventually, and updating only when the viewer - # changes chunk position? - - if DEBUG and visible: - _debug_cubes.clear() - #for cz in range(cmin_z, cmax_z): - #for cx in range(cmin_x, cmax_x): - #_add_debug_cube(terrain, _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE), - #terrain_transform_without_map_scale) - for k in _chunks: - var aabb := _get_chunk_aabb(terrain, Vector3(k.x, 0, k.y) * CHUNK_SIZE) - _add_debug_cube(terrain, aabb, terrain_transform_without_map_scale) - - _add_debug_cube(terrain, - AABB(local_viewer_pos - Vector3(1,1,1), Vector3(2,2,2)), - terrain_transform_without_map_scale) - - var time_enter := 0 - var time_exit := 0 - - # Only update when the camera moves across chunks - if cmin != _prev_frame_cmin or cmax != _prev_frame_cmax or _force_chunk_updates_next_frame: - _force_chunk_updates_next_frame = false - - for cz in range(cmin.z, cmax.z): - for cx in range(cmin.x, cmax.x): - - var cpos2d := Vector2i(cx, cz) - if _chunks.has(cpos2d): - continue - - var aabb := _get_chunk_aabb(terrain, Vector3(cx, 0, cz) * CHUNK_SIZE) - var d := _get_approx_distance_to_chunk_aabb(aabb, local_viewer_pos) - - if d < view_distance: - _load_chunk(terrain_transform_without_map_scale, cx, cz, aabb) - - for k in _chunks: - var chunk : Chunk = _chunks[k] - # TODO Maybe we shouldn't include chunks that were just loaded above? - if not chunk.pending_update: - chunk.pending_update = true - _pending_chunk_updates.append(k) - - _process_pending_updates(terrain, local_viewer_pos) - - # Update time manually, so we can accelerate the animation when strength is increased, - # without causing phase jumps (which would be the case if we just scaled TIME) - var ambient_wind_frequency = 1.0 + 3.0 * terrain.ambient_wind - _ambient_wind_time += delta * ambient_wind_frequency - var awp = _get_ambient_wind_params() - _material.set_shader_parameter("u_ambient_wind", awp) - - _prev_frame_cmin = cmin - _prev_frame_cmax = cmax - - -func on_heightmap_region_changed(rect: Rect2i) -> void: - # Whether chunks should be loaded or not and their AABB may change, - # even if the camera didn't move - _force_chunk_updates_next_frame = true - - # The AABB of existing chunks may change - var cmin : Vector2i = rect.position / CHUNK_SIZE - var cmax : Vector2i = ceildiv_vec2i_int(rect.end, CHUNK_SIZE) - for cz in range(cmin.y, cmax.y): - for cx in range(cmin.x, cmax.x): - var cpos := Vector2i(cx, cz) - var chunk : Chunk = _chunks.get(cpos) - if chunk != null and not chunk.pending_update: - chunk.pending_update = true - chunk.pending_aabb_update = true - _pending_chunk_updates.append(cpos) - - -func on_heightmap_resolution_changed() -> void: - _reset_chunks() - - -func _reset_chunks() -> void: - for k in _chunks.keys(): - _recycle_chunk(k) - _prev_frame_cmin = Vector3i() - _prev_frame_cmax = Vector3i() - _pending_chunk_updates.clear() - - -static func ceildiv(x: int, d: int) -> int: - assert(d > 0); - if x < 0: - return (x - d + 1) / d - return x / d - - -static func ceildiv_vec2i_int(v: Vector2i, d: int) -> Vector2i: - return Vector2i(ceildiv(v.x, d), ceildiv(v.y, d)) - - -func _process_pending_updates(terrain, local_viewer_pos: Vector3): - # Defer this over multiple frames - var budget_us := 1000 - var time_before := Time.get_ticks_usec() - - while _pending_chunk_updates.size() > 0: - var cpos : Vector2i = _pending_chunk_updates.pop_back() - var chunk : Chunk = _chunks[cpos] - chunk.pending_update = false - - var aabb := _get_chunk_aabb(terrain, Vector3(cpos.x, 0, cpos.y) * CHUNK_SIZE) - var d := _get_approx_distance_to_chunk_aabb(aabb, local_viewer_pos) - if d > view_distance: - _recycle_chunk(cpos) - elif chunk.pending_aabb_update: - chunk.pending_aabb_update = false - chunk.mmi.set_aabb(aabb) - - if Time.get_ticks_usec() - time_before > budget_us: - break - - -# It would be nice if Godot had "AABB.distance_squared_to(vec3)"... -# Using an approximation here cuz GDScript is slow. -static func _get_approx_distance_to_chunk_aabb(aabb: AABB, pos: Vector3) -> float: - # Distance to center is faster but has issues with very large map scale. - # Detail chunks are based on cached vertical bounds. - # Usually it works fine on moderate scales, but on huge map scales, - # vertical bound chunks cover such large areas that detail chunks often - # stay exceedingly tall, in turn causing their centers to be randomly - # far from the ground, and then getting unloaded because assumed too far away - #return aabb.get_center().distance_to(pos) - - if aabb.has_point(pos): - return 0.0 - var delta := (pos - aabb.get_center()).abs() - aabb.size * 0.5 - return maxf(delta.x, maxf(delta.y, delta.z)) - - -# Gets local-space AABB of a detail chunk. -# This only apply map_scale in Y, because details are not affected by X and Z map scale. -func _get_chunk_aabb(terrain, lpos: Vector3) -> AABB: - var terrain_scale = terrain.map_scale - var terrain_data = terrain.get_data() - var origin_cells_x := int(lpos.x / terrain_scale.x) - var origin_cells_z := int(lpos.z / terrain_scale.z) - # We must at least sample 1 cell, in cases where map_scale is greater than the size of our - # chunks. This is quite an extreme situation though - var size_cells_x := int(ceilf(CHUNK_SIZE / terrain_scale.x)) - var size_cells_z := int(ceilf(CHUNK_SIZE / terrain_scale.z)) - - var aabb = terrain_data.get_region_aabb( - origin_cells_x, origin_cells_z, size_cells_x, size_cells_z) - - aabb.position = Vector3(lpos.x, lpos.y + aabb.position.y * terrain_scale.y, lpos.z) - aabb.size = Vector3(CHUNK_SIZE, aabb.size.y * terrain_scale.y, CHUNK_SIZE) - return aabb - - -func _get_chunk_transform(terrain_transform: Transform3D, cx: int, cz: int) -> Transform3D: - var lpos := Vector3(cx, 0, cz) * CHUNK_SIZE - # `terrain_transform` should be the terrain's internal transform, without `map_scale`. - var trans := Transform3D( - terrain_transform.basis, - terrain_transform.origin + terrain_transform.basis * lpos) - return trans - - -func _load_chunk(terrain_transform_without_map_scale: Transform3D, cx: int, cz: int, aabb: AABB): - aabb.position.x = 0 - aabb.position.z = 0 - - var mmi : HT_DirectMultiMeshInstance = null - if len(_multimesh_instance_pool) != 0: - mmi = _multimesh_instance_pool[-1] - _multimesh_instance_pool.pop_back() - else: - mmi = HT_DirectMultiMeshInstance.new() - mmi.set_world(get_world_3d()) - mmi.set_multimesh(_multimesh) - - var trans := _get_chunk_transform(terrain_transform_without_map_scale, cx, cz) - - mmi.set_material_override(_material) - mmi.set_transform(trans) - mmi.set_aabb(aabb) - mmi.set_layer_mask(render_layers) - mmi.set_cast_shadow(cast_shadow) - mmi.set_visible(visible) - - var chunk := Chunk.new() - chunk.mmi = mmi - _chunks[Vector2i(cx, cz)] = chunk - - -func _recycle_chunk(cpos2d: Vector2i): - var chunk : Chunk = _chunks[cpos2d] - _chunks.erase(cpos2d) - chunk.mmi.set_visible(false) - _multimesh_instance_pool.append(chunk.mmi) - - -func _get_ambient_wind_params() -> Vector2: - var aw := 0.0 - var terrain = _get_terrain() - if terrain != null: - aw = terrain.ambient_wind - # amplitude, time - return Vector2(aw, _ambient_wind_time) - - -func _update_material(): - # Sets API shader properties. Custom properties are assumed to be set already - _logger.debug("Updating detail layer material") - - var terrain_data : HTerrainData = null - var terrain = _get_terrain() - var it := Transform3D() - var normal_basis := Basis() - - if terrain != null: - var gt : Transform3D = terrain.get_internal_transform() - it = gt.affine_inverse() - terrain_data = terrain.get_data() - # This is needed to properly transform normals if the terrain is scaled. - # However we don't want to pick up rotation because it's already factored in the instance - #normal_basis = gt.basis.inverse().transposed() - normal_basis = Basis().scaled(terrain.map_scale).inverse().transposed() - - var mat := _material - - mat.set_shader_parameter("u_terrain_inverse_transform", it) - mat.set_shader_parameter("u_terrain_normal_basis", normal_basis) - mat.set_shader_parameter("u_albedo_alpha", texture) - mat.set_shader_parameter("u_view_distance", view_distance) - mat.set_shader_parameter("u_ambient_wind", _get_ambient_wind_params()) - - var heightmap_texture : Texture = null - var normalmap_texture : Texture = null - var detailmap_texture : Texture = null - var globalmap_texture : Texture = null - - if terrain_data != null: - if terrain_data.is_locked(): - _logger.error("Terrain data locked, can't update detail layer now") - return - - heightmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - normalmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_NORMAL) - - if layer_index < terrain_data.get_map_count(HTerrainData.CHANNEL_DETAIL): - detailmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_DETAIL, layer_index) - - if terrain_data.get_map_count(HTerrainData.CHANNEL_GLOBAL_ALBEDO) > 0: - globalmap_texture = terrain_data.get_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - else: - _logger.error("Terrain data is null, can't update detail layer completely") - - mat.set_shader_parameter("u_terrain_heightmap", heightmap_texture) - mat.set_shader_parameter("u_terrain_detailmap", detailmap_texture) - mat.set_shader_parameter("u_terrain_normalmap", normalmap_texture) - mat.set_shader_parameter("u_terrain_globalmap", globalmap_texture) - - -func _add_debug_cube(terrain: Node3D, aabb: AABB, terrain_transform_without_scale: Transform3D): - var world : World3D = terrain.get_world_3d() - - if _debug_wirecube_mesh == null: - _debug_wirecube_mesh = HT_Util.create_wirecube_mesh() - var mat := StandardMaterial3D.new() - mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - _debug_wirecube_mesh.surface_set_material(0, mat) - - # Flat terrain makes cubes invisible - aabb.size.y = maxf(aabb.size.y, 1.0) - - var debug_cube := HT_DirectMeshInstance.new() - debug_cube.set_mesh(_debug_wirecube_mesh) - debug_cube.set_world(world) - #aabb.position.y += 0.2*randf() - debug_cube.set_transform(terrain_transform_without_scale \ - * Transform3D(Basis().scaled(aabb.size), aabb.position)) - - _debug_cubes.append(debug_cube) - - -func _regen_multimesh(): - # We modify the existing multimesh instead of replacing it. - # DirectMultiMeshInstance does not keep a strong reference to them, - # so replacing would break pooled instances. - - var rng := RandomNumberGenerator.new() - if fixed_seed_enabled: - rng.seed = fixed_seed - else: - rng.randomize() - - _generate_multimesh(CHUNK_SIZE, density, _get_used_mesh(), _multimesh, rng) - - -func is_layer_index_valid() -> bool: - var terrain = _get_terrain() - if terrain == null: - return false - var data = terrain.get_data() - if data == null: - return false - return layer_index >= 0 and layer_index < data.get_map_count(HTerrainData.CHANNEL_DETAIL) - - -func _get_configuration_warnings() -> PackedStringArray: - var warnings := PackedStringArray() - - var terrain = _get_terrain() - if not (is_instance_of(terrain, HTerrain)): - warnings.append("This node must be child of an HTerrain node") - return warnings - - var data = terrain.get_data() - if data == null: - warnings.append("The terrain has no data") - return warnings - - if data.get_map_count(HTerrainData.CHANNEL_DETAIL) == 0: - warnings.append("The terrain does not have any detail map") - return warnings - - if layer_index < 0 or layer_index >= data.get_map_count(HTerrainData.CHANNEL_DETAIL): - warnings.append("Layer index is out of bounds") - return warnings - - var tex = data.get_texture(HTerrainData.CHANNEL_DETAIL, layer_index) - if tex == null: - warnings.append("The terrain does not have a map assigned in slot {0}" \ - .format([layer_index])) - - return warnings - - -# Compat -func set_cast_shadow(option: int): - cast_shadow = option - - -# Compat -func get_cast_shadow() -> int: - return cast_shadow - - -func _on_custom_shader_changed(): - notify_property_list_changed() - - -static func _generate_multimesh( - resolution: int, density: float, mesh: Mesh, multimesh: MultiMesh, - rng: RandomNumberGenerator): - - assert(multimesh != null) - - var position_randomness := 0.5 - var scale_randomness := 0.0 - #var color_randomness = 0.5 - - var cell_count := resolution * resolution - var idensity := int(density) - var random_instance_count := int(cell_count * (density - floorf(density))) - var total_instance_count := cell_count * idensity + random_instance_count - - multimesh.instance_count = total_instance_count - multimesh.mesh = mesh - - # First pass ensures uniform spread - var i := 0 - for z in resolution: - for x in resolution: - for j in idensity: - var pos := Vector3(x, 0, z) - pos.x += rng.randf_range(-position_randomness, position_randomness) - pos.z += rng.randf_range(-position_randomness, position_randomness) - - multimesh.set_instance_color(i, Color(1, 1, 1)) - multimesh.set_instance_transform(i, \ - Transform3D(_get_random_instance_basis(scale_randomness, rng), pos)) - i += 1 - - # Second pass adds the rest - for j in random_instance_count: - var pos = Vector3(rng.randf_range(0, resolution), 0, rng.randf_range(0, resolution)) - multimesh.set_instance_color(i, Color(1, 1, 1)) - multimesh.set_instance_transform(i, \ - Transform3D(_get_random_instance_basis(scale_randomness, rng), pos)) - i += 1 - - -static func _get_random_instance_basis(scale_randomness: float, rng: RandomNumberGenerator) -> Basis: - var sr := rng.randf_range(0, scale_randomness) - var s := 1.0 + (sr * sr * sr * sr * sr) * 50.0 - - var basis := Basis() - basis = basis.scaled(Vector3(1, s, 1)) - basis = basis.rotated(Vector3(0, 1, 0), rng.randf_range(0, PI)) - - return basis diff --git a/godot/addons/zylann.hterrain/hterrain_detail_layer.gd.uid b/godot/addons/zylann.hterrain/hterrain_detail_layer.gd.uid deleted file mode 100644 index 6dda847..0000000 --- a/godot/addons/zylann.hterrain/hterrain_detail_layer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://gjgg1j4u0si7 diff --git a/godot/addons/zylann.hterrain/hterrain_mesher.gd b/godot/addons/zylann.hterrain/hterrain_mesher.gd deleted file mode 100644 index 0b371e1..0000000 --- a/godot/addons/zylann.hterrain/hterrain_mesher.gd +++ /dev/null @@ -1,358 +0,0 @@ -@tool - -#const HT_Logger = preload("./util/logger.gd") -const HTerrainData = preload("./hterrain_data.gd") - -const SEAM_LEFT = 1 -const SEAM_RIGHT = 2 -const SEAM_BOTTOM = 4 -const SEAM_TOP = 8 -const SEAM_CONFIG_COUNT = 16 - - -# [seams_mask][lod] -var _mesh_cache := [] -var _chunk_size_x := 16 -var _chunk_size_y := 16 - - -func configure(chunk_size_x: int, chunk_size_y: int, lod_count: int): - assert(typeof(chunk_size_x) == TYPE_INT) - assert(typeof(chunk_size_y) == TYPE_INT) - assert(typeof(lod_count) == TYPE_INT) - - assert(chunk_size_x >= 2 or chunk_size_y >= 2) - - _mesh_cache.resize(SEAM_CONFIG_COUNT) - - if chunk_size_x == _chunk_size_x \ - and chunk_size_y == _chunk_size_y and lod_count == len(_mesh_cache): - return - - _chunk_size_x = chunk_size_x - _chunk_size_y = chunk_size_y - - # TODO Will reduce the size of this cache, but need index buffer swap feature - for seams in SEAM_CONFIG_COUNT: - var slot := [] - slot.resize(lod_count) - _mesh_cache[seams] = slot - - for lod in lod_count: - slot[lod] = make_flat_chunk(_chunk_size_x, _chunk_size_y, 1 << lod, seams) - - -func get_chunk(lod: int, seams: int) -> Mesh: - return _mesh_cache[seams][lod] as Mesh - - -static func make_flat_chunk(quad_count_x: int, quad_count_y: int, stride: int, seams: int) -> Mesh: - var positions = PackedVector3Array() - positions.resize((quad_count_x + 1) * (quad_count_y + 1)) - - var i = 0 - for y in quad_count_y + 1: - for x in quad_count_x + 1: - positions[i] = Vector3(x * stride, 0, y * stride) - i += 1 - - var indices := make_indices(quad_count_x, quad_count_y, seams) - - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX); - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_INDEX] = indices - - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) - - return mesh - - -# size: chunk size in quads (there are N+1 vertices) -# seams: Bitfield for which seams are present -static func make_indices(chunk_size_x: int, chunk_size_y: int, seams: int) -> PackedInt32Array: - var output_indices := PackedInt32Array() - - if seams != 0: - # LOD seams can't be made properly on uneven chunk sizes - assert(chunk_size_x % 2 == 0 and chunk_size_y % 2 == 0) - - var reg_origin_x := 0 - var reg_origin_y := 0 - var reg_size_x := chunk_size_x - var reg_size_y := chunk_size_y - var reg_hstride := 1 - - if seams & SEAM_LEFT: - reg_origin_x += 1; - reg_size_x -= 1; - reg_hstride += 1 - - if seams & SEAM_BOTTOM: - reg_origin_y += 1 - reg_size_y -= 1 - - if seams & SEAM_RIGHT: - reg_size_x -= 1 - reg_hstride += 1 - - if seams & SEAM_TOP: - reg_size_y -= 1 - - # Regular triangles - var ii := reg_origin_x + reg_origin_y * (chunk_size_x + 1) - - for y in reg_size_y: - for x in reg_size_x: - var i00 := ii - var i10 := ii + 1 - var i01 := ii + chunk_size_x + 1 - var i11 := i01 + 1 - - # 01---11 - # | /| - # | / | - # |/ | - # 00---10 - - # This flips the pattern to make the geometry orientation-free. - # Not sure if it helps in any way though - var flip = ((x + reg_origin_x) + (y + reg_origin_y) % 2) % 2 != 0 - - if flip: - output_indices.push_back( i00 ) - output_indices.push_back( i10 ) - output_indices.push_back( i01 ) - - output_indices.push_back( i10 ) - output_indices.push_back( i11 ) - output_indices.push_back( i01 ) - - else: - output_indices.push_back( i00 ) - output_indices.push_back( i11 ) - output_indices.push_back( i01 ) - - output_indices.push_back( i00 ) - output_indices.push_back( i10 ) - output_indices.push_back( i11 ) - - ii += 1 - ii += reg_hstride - - # Left seam - if seams & SEAM_LEFT: - - # 4 . 5 - # |\ . - # | \ . - # | \. - # (2)| 3 - # | /. - # | / . - # |/ . - # 0 . 1 - - var i := 0 - var n := chunk_size_y / 2 - - for j in n: - var i0 := i - var i1 := i + 1 - var i3 := i + chunk_size_x + 2 - var i4 := i + 2 * (chunk_size_x + 1) - var i5 := i4 + 1 - - output_indices.push_back( i0 ) - output_indices.push_back( i3 ) - output_indices.push_back( i4 ) - - if j != 0 or (seams & SEAM_BOTTOM) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_TOP) == 0: - output_indices.push_back( i3 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i4 - - if seams & SEAM_RIGHT: - - # 4 . 5 - # . /| - # . / | - # ./ | - # 2 |(3) - # .\ | - # . \ | - # . \| - # 0 . 1 - - var i := chunk_size_x - 1 - var n := chunk_size_y / 2 - - for j in n: - - var i0 := i - var i1 := i + 1 - var i2 := i + chunk_size_x + 1 - var i4 := i + 2 * (chunk_size_x + 1) - var i5 := i4 + 1 - - output_indices.push_back( i1 ) - output_indices.push_back( i5 ) - output_indices.push_back( i2 ) - - if j != 0 or (seams & SEAM_BOTTOM) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i2 ) - - if j != n - 1 or (seams & SEAM_TOP) == 0: - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i4; - - if seams & SEAM_BOTTOM: - - # 3 . 4 . 5 - # . / \ . - # . / \ . - # ./ \. - # 0-------2 - # (1) - - var i := 0; - var n := chunk_size_x / 2; - - for j in n: - - var i0 := i - var i2 := i + 2 - var i3 := i + chunk_size_x + 1 - var i4 := i3 + 1 - var i5 := i4 + 1 - - output_indices.push_back( i0 ) - output_indices.push_back( i2 ) - output_indices.push_back( i4 ) - - if j != 0 or (seams & SEAM_LEFT) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i4 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_RIGHT) == 0: - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - output_indices.push_back( i4 ) - - i = i2 - - if seams & SEAM_TOP: - - # (4) - # 3-------5 - # .\ /. - # . \ / . - # . \ / . - # 0 . 1 . 2 - - var i := (chunk_size_y - 1) * (chunk_size_x + 1) - var n := chunk_size_x / 2 - - for j in n: - - var i0 := i - var i1 := i + 1 - var i2 := i + 2 - var i3 := i + chunk_size_x + 1 - var i5 := i3 + 2 - - output_indices.push_back( i3 ) - output_indices.push_back( i1 ) - output_indices.push_back( i5 ) - - if j != 0 or (seams & SEAM_LEFT) == 0: - output_indices.push_back( i0 ) - output_indices.push_back( i1 ) - output_indices.push_back( i3 ) - - if j != n - 1 or (seams & SEAM_RIGHT) == 0: - output_indices.push_back( i1 ) - output_indices.push_back( i2 ) - output_indices.push_back( i5 ) - - i = i2 - - return output_indices - - -static func get_mesh_size(width: int, height: int) -> Dictionary: - return { - "vertices": width * height, - "triangles": (width - 1) * (height - 1) * 2 - } - - -# Makes a full mesh from a heightmap, without any LOD considerations. -# Using this mesh for rendering is very expensive on large terrains. -# Initially used as a workaround for Godot to use for navmesh generation. -static func make_heightmap_mesh(heightmap: Image, stride: int, scale: Vector3, - logger = null) -> Mesh: - - var size_x := heightmap.get_width() / stride - var size_z := heightmap.get_height() / stride - - assert(size_x >= 2) - assert(size_z >= 2) - - var positions := PackedVector3Array() - positions.resize(size_x * size_z) - - var i := 0 - - if heightmap.get_format() == Image.FORMAT_RH or heightmap.get_format() == Image.FORMAT_RF: - for mz in size_z: - for mx in size_x: - var x := mx * stride - var z := mz * stride - var y := heightmap.get_pixel(x, z).r - positions[i] = Vector3(x, y, z) * scale - i += 1 - - elif heightmap.get_format() == Image.FORMAT_RGB8: - for mz in size_z: - for mx in size_x: - var x := mx * stride - var z := mz * stride - var c := heightmap.get_pixel(x, z) - var y := HTerrainData.decode_height_from_rgb8_unorm(c) - positions[i] = Vector3(x, y, z) * scale - i += 1 - - else: - logger.error("Unknown heightmap format!") - return null - - var indices := make_indices(size_x - 1, size_z - 1, 0) - - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX); - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_INDEX] = indices - - if logger != null: - logger.debug(str("Generated mesh has ", len(positions), - " vertices and ", len(indices) / 3, " triangles")) - - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays) - - return mesh diff --git a/godot/addons/zylann.hterrain/hterrain_mesher.gd.uid b/godot/addons/zylann.hterrain/hterrain_mesher.gd.uid deleted file mode 100644 index c88ea2b..0000000 --- a/godot/addons/zylann.hterrain/hterrain_mesher.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dbi4eeois601s diff --git a/godot/addons/zylann.hterrain/hterrain_resource_loader.gd b/godot/addons/zylann.hterrain/hterrain_resource_loader.gd deleted file mode 100644 index ccc176b..0000000 --- a/godot/addons/zylann.hterrain/hterrain_resource_loader.gd +++ /dev/null @@ -1,35 +0,0 @@ -@tool -class_name HTerrainDataLoader -extends ResourceFormatLoader - - -const HTerrainData = preload("./hterrain_data.gd") - - -func _get_recognized_extensions() -> PackedStringArray: - return PackedStringArray([HTerrainData.META_EXTENSION]) - - -func _get_resource_type(path: String) -> String: - var ext := path.get_extension().to_lower() - if ext == HTerrainData.META_EXTENSION: - return "Resource" - return "" - - -# TODO Handle UIDs? -# By default Godot will return INVALID_ID, -# which makes this resource only tracked by path, like scripts -# -# func _get_resource_uid(path: String) -> int: -# return ??? - - -func _handles_type(typename: StringName) -> bool: - return typename == &"Resource" - - -func _load(path: String, original_path: String, use_sub_threads: bool, cache_mode: int): - var res = HTerrainData.new() - res.load_data(path.get_base_dir()) - return res diff --git a/godot/addons/zylann.hterrain/hterrain_resource_loader.gd.uid b/godot/addons/zylann.hterrain/hterrain_resource_loader.gd.uid deleted file mode 100644 index 400570a..0000000 --- a/godot/addons/zylann.hterrain/hterrain_resource_loader.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://e17rvnejpxey diff --git a/godot/addons/zylann.hterrain/hterrain_resource_saver.gd b/godot/addons/zylann.hterrain/hterrain_resource_saver.gd deleted file mode 100644 index be757e8..0000000 --- a/godot/addons/zylann.hterrain/hterrain_resource_saver.gd +++ /dev/null @@ -1,29 +0,0 @@ -@tool -class_name HTerrainDataSaver -extends ResourceFormatSaver - - -const HTerrainData = preload("./hterrain_data.gd") - - -func _get_recognized_extensions(res: Resource) -> PackedStringArray: - if res != null and res is HTerrainData: - return PackedStringArray([HTerrainData.META_EXTENSION]) - return PackedStringArray() - - -func _recognize(res: Resource) -> bool: - return res is HTerrainData - - -func _save(resource: Resource, path: String, flags: int) -> Error: - if resource.save_data(path.get_base_dir()): - return OK - # This can occur if at least one map of the terrain fails to save. - # It doesnt necessarily mean the entire terrain failed to save. - return FAILED - - -# TODO Handle UIDs -# func _set_uid(path: String, uid: int) -> int: -# ??? diff --git a/godot/addons/zylann.hterrain/hterrain_resource_saver.gd.uid b/godot/addons/zylann.hterrain/hterrain_resource_saver.gd.uid deleted file mode 100644 index edfe7ce..0000000 --- a/godot/addons/zylann.hterrain/hterrain_resource_saver.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://clwa21bdmmjnt diff --git a/godot/addons/zylann.hterrain/hterrain_texture_set.gd b/godot/addons/zylann.hterrain/hterrain_texture_set.gd deleted file mode 100644 index 4f9fb01..0000000 --- a/godot/addons/zylann.hterrain/hterrain_texture_set.gd +++ /dev/null @@ -1,253 +0,0 @@ -@tool -extends Resource - -const MODE_TEXTURES = 0 -const MODE_TEXTURE_ARRAYS = 1 -const MODE_COUNT = 2 - -const _mode_names = ["Textures", "TextureArrays"] - -const SRC_TYPE_ALBEDO = 0 -const SRC_TYPE_BUMP = 1 -const SRC_TYPE_NORMAL = 2 -const SRC_TYPE_ROUGHNESS = 3 -const SRC_TYPE_COUNT = 4 - -const _src_texture_type_names = ["albedo", "bump", "normal", "roughness"] - -# Ground texture types (used by the terrain system) -const TYPE_ALBEDO_BUMP = 0 -const TYPE_NORMAL_ROUGHNESS = 1 -const TYPE_COUNT = 2 - -const _texture_type_names = ["albedo_bump", "normal_roughness"] - -const _type_to_src_types = [ - [SRC_TYPE_ALBEDO, SRC_TYPE_BUMP], - [SRC_TYPE_NORMAL, SRC_TYPE_ROUGHNESS] -] - -const _src_default_color_codes = [ - "#ff000000", - "#ff888888", - "#ff8888ff", - "#ffffffff" -] - -# TODO We may get rid of modes in the future, and only use TextureArrays. -# It exists for now for backward compatibility, but it makes the API a bit confusing -var _mode := MODE_TEXTURES -# [type][slot] -> StreamTexture or TextureArray -var _textures := [[], []] - - -static func get_texture_type_name(tt: int) -> String: - return _texture_type_names[tt] - - -static func get_source_texture_type_name(tt: int) -> String: - return _src_texture_type_names[tt] - - -static func get_source_texture_default_color_code(tt: int) -> String: - return _src_default_color_codes[tt] - - -static func get_import_mode_name(mode: int) -> String: - return _mode_names[mode] - - -static func get_src_types_from_type(t: int) -> Array: - return _type_to_src_types[t] - - -static func get_max_slots_for_mode(mode: int) -> int: - match mode: - MODE_TEXTURES: - # This is a legacy mode, where shaders can only have up to 4 - return 4 - MODE_TEXTURE_ARRAYS: - # Will probably be lifted some day - return 16 - return 0 - - -func _get_property_list() -> Array: - return [ - { - "name": "mode", - "type": TYPE_INT, - "usage": PROPERTY_USAGE_STORAGE - }, - { - "name": "textures", - "type": TYPE_ARRAY, - "usage": PROPERTY_USAGE_STORAGE - } - ] - - -func _get(key: StringName): - if key == &"mode": - return _mode - if key == &"textures": - return _textures - - -func _set(key: StringName, value): - if key == &"mode": - # Not using set_mode() here because otherwise it could reset stuff set before... - _mode = value - if key == &"textures": - _textures = value - - -func get_slots_count() -> int: - if _mode == MODE_TEXTURES: - return get_texture_count() - - elif _mode == MODE_TEXTURE_ARRAYS: - # TODO What if there are two texture arrays of different size? - var texarray : TextureLayered = _textures[TYPE_ALBEDO_BUMP][0] - if texarray == null: - texarray = _textures[TYPE_NORMAL_ROUGHNESS][0] - if texarray == null: - return 0 - return texarray.get_layers() - - else: - assert(false) - return 0 - - -func get_texture_count() -> int: - var texs = _textures[TYPE_ALBEDO_BUMP] - return len(texs) - - -func get_texture(slot_index: int, ground_texture_type: int) -> Texture2D: - if _mode == MODE_TEXTURE_ARRAYS: - # Can't get a single texture at once - return null - - elif _mode == MODE_TEXTURES: - var texs = _textures[ground_texture_type] - if slot_index >= len(texs): - return null - return texs[slot_index] - - else: - assert(false) - return null - - -func set_texture(slot_index: int, ground_texture_type: int, texture: Texture2D): - assert(_mode == MODE_TEXTURES) - var texs = _textures[ground_texture_type] - if texs[slot_index] != texture: - texs[slot_index] = texture - emit_changed() - - -func get_texture_array(ground_texture_type: int) -> TextureLayered: - if _mode != MODE_TEXTURE_ARRAYS: - return null - var texs = _textures[ground_texture_type] - return texs[0] - - -func set_texture_array(ground_texture_type: int, texarray: TextureLayered): - assert(_mode == MODE_TEXTURE_ARRAYS) - var texs = _textures[ground_texture_type] - if texs[0] != texarray: - texs[0] = texarray - emit_changed() - - -# TODO This function only exists because of a flaw in UndoRedo -# See https://github.com/godotengine/godot/issues/36895 -func set_texture_null(slot_index: int, ground_texture_type: int): - set_texture(slot_index, ground_texture_type, null) - - -# TODO This function only exists because of a flaw in UndoRedo -# See https://github.com/godotengine/godot/issues/36895 -func set_texture_array_null(ground_texture_type: int): - set_texture_array(ground_texture_type, null) - - -func get_mode() -> int: - return _mode - - -func set_mode(mode: int): - # This effectively clears slots - _mode = mode - clear() - - -func clear(): - match _mode: - MODE_TEXTURES: - for type in TYPE_COUNT: - _textures[type] = [] - MODE_TEXTURE_ARRAYS: - for type in TYPE_COUNT: - _textures[type] = [null] - _: - assert(false) - emit_changed() - - -func insert_slot(i: int) -> int: - assert(_mode == MODE_TEXTURES) - if i == -1: - i = get_texture_count() - for type in TYPE_COUNT: - _textures[type].insert(i, null) - emit_changed() - return i - - -func remove_slot(i: int): - assert(_mode == MODE_TEXTURES) - if i == -1: - i = get_slots_count() - 1 - for type in TYPE_COUNT: - _textures[type].remove_at(i) - emit_changed() - - -func has_any_textures() -> bool: - for type in len(_textures): - var texs = _textures[type] - for i in len(texs): - if texs[i] != null: - return true - return false - - -#func set_textures(textures: Array): -# _textures = textures - - -# Cannot type hint because it would cause circular dependency -#func migrate_from_1_4(terrain): -# var textures := [] -# for type in TYPE_COUNT: -# textures.append([]) -# -# if terrain.is_using_texture_array(): -# for type in TYPE_COUNT: -# var tex : TextureArray = terrain.get_ground_texture_array(type) -# textures[type] = [tex] -# _mode = MODE_TEXTURE_ARRAYS -# -# else: -# for index in terrain.get_max_ground_texture_slot_count(): -# for type in TYPE_COUNT: -# var tex : Texture = terrain.get_ground_texture(type, index) -# textures[type].append(tex) -# _mode = MODE_TEXTURES -# -# _textures = textures diff --git a/godot/addons/zylann.hterrain/hterrain_texture_set.gd.uid b/godot/addons/zylann.hterrain/hterrain_texture_set.gd.uid deleted file mode 100644 index e6c173e..0000000 --- a/godot/addons/zylann.hterrain/hterrain_texture_set.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtmnslm2nar2i diff --git a/godot/addons/zylann.hterrain/models/grass_quad.obj b/godot/addons/zylann.hterrain/models/grass_quad.obj deleted file mode 100644 index 2215279..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad.obj +++ /dev/null @@ -1,14 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 diff --git a/godot/addons/zylann.hterrain/models/grass_quad.obj.import b/godot/addons/zylann.hterrain/models/grass_quad.obj.import deleted file mode 100644 index a726f51..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad.obj.import +++ /dev/null @@ -1,25 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://c1k6wgnjlvxpm" -path="res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad.obj" -dest_files=["res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh", "res://.godot/imported/grass_quad.obj-da067750350fe98ec466261b2aeaf486.mesh"] - -[params] - -generate_tangents=true -generate_lods=true -generate_shadow_mesh=true -generate_lightmap_uv2=false -generate_lightmap_uv2_texel_size=0.2 -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -force_disable_mesh_compression=false diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x2.obj b/godot/addons/zylann.hterrain/models/grass_quad_x2.obj deleted file mode 100644 index 37c4707..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x2.obj +++ /dev/null @@ -1,24 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x2.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -v -0.500000 1.000000 0.000000 -v -0.500000 0.000000 0.000000 -v 0.500000 1.000000 0.000000 -v 0.500000 0.000000 0.000000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 6/5/2 5/6/2 7/7/2 8/8/2 diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x2.obj.import b/godot/addons/zylann.hterrain/models/grass_quad_x2.obj.import deleted file mode 100644 index a09182c..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x2.obj.import +++ /dev/null @@ -1,25 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://dpef2d0qcn5d4" -path="res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x2.obj" -dest_files=["res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh", "res://.godot/imported/grass_quad_x2.obj-2054c140f543f2a80e2eb921f865ea49.mesh"] - -[params] - -generate_tangents=true -generate_lods=true -generate_shadow_mesh=true -generate_lightmap_uv2=false -generate_lightmap_uv2_texel_size=0.2 -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -force_disable_mesh_compression=false diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x3.obj b/godot/addons/zylann.hterrain/models/grass_quad_x3.obj deleted file mode 100644 index a373832..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x3.obj +++ /dev/null @@ -1,34 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x3.blend' -# www.blender.org -o Cube -v 0.000000 1.000000 -0.500000 -v 0.000000 0.000000 -0.500000 -v 0.000000 1.000000 0.500000 -v 0.000000 0.000000 0.500000 -v -0.433013 1.000000 -0.250000 -v -0.433013 0.000000 -0.250000 -v 0.433013 1.000000 0.250000 -v 0.433013 0.000000 0.250000 -v -0.433013 1.000000 0.250000 -v -0.433013 0.000000 0.250000 -v 0.433013 1.000000 -0.250000 -v 0.433013 0.000000 -0.250000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.5000 0.0000 -0.8660 -vn -0.5000 0.0000 -0.8660 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 6/5/2 5/6/2 7/7/2 8/8/2 -f 10/9/3 9/10/3 11/11/3 12/12/3 diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x3.obj.import b/godot/addons/zylann.hterrain/models/grass_quad_x3.obj.import deleted file mode 100644 index f7b405d..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x3.obj.import +++ /dev/null @@ -1,25 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://bhjb8bijf1ql3" -path="res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x3.obj" -dest_files=["res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh", "res://.godot/imported/grass_quad_x3.obj-8691724bc5006b6f65d4e8742ffc84dc.mesh"] - -[params] - -generate_tangents=true -generate_lods=true -generate_shadow_mesh=true -generate_lightmap_uv2=false -generate_lightmap_uv2_texel_size=0.2 -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -force_disable_mesh_compression=false diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x4.obj b/godot/addons/zylann.hterrain/models/grass_quad_x4.obj deleted file mode 100644 index b182be6..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x4.obj +++ /dev/null @@ -1,42 +0,0 @@ -# Blender v2.80 (sub 75) OBJ File: 'grass_x4.blend' -# www.blender.org -o Cube -v 0.250000 1.000000 -0.500000 -v 0.250000 0.000000 -0.500000 -v 0.250000 1.000000 0.500000 -v 0.250000 0.000000 0.500000 -v 0.500000 0.000000 -0.250000 -v 0.500000 1.000000 -0.250000 -v -0.500000 0.000000 -0.250000 -v -0.500000 1.000000 -0.250000 -v -0.250000 0.000000 0.500000 -v -0.250000 1.000000 0.500000 -v -0.250000 0.000000 -0.500000 -v -0.250000 1.000000 -0.500000 -v 0.500000 0.000000 0.250000 -v 0.500000 1.000000 0.250000 -v -0.500000 0.000000 0.250000 -v -0.500000 1.000000 0.250000 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vt 0.999900 0.000100 -vt 0.999900 0.999900 -vt 0.000100 0.999900 -vt 0.000100 0.000100 -vn 1.0000 0.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -s off -f 2/1/1 1/2/1 3/3/1 4/4/1 -f 7/5/2 8/6/2 6/7/2 5/8/2 -f 11/9/1 12/10/1 10/11/1 9/12/1 -f 15/13/2 16/14/2 14/15/2 13/16/2 diff --git a/godot/addons/zylann.hterrain/models/grass_quad_x4.obj.import b/godot/addons/zylann.hterrain/models/grass_quad_x4.obj.import deleted file mode 100644 index 0628d17..0000000 --- a/godot/addons/zylann.hterrain/models/grass_quad_x4.obj.import +++ /dev/null @@ -1,25 +0,0 @@ -[remap] - -importer="wavefront_obj" -importer_version=1 -type="Mesh" -uid="uid://cism8qe63t4tk" -path="res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh" - -[deps] - -files=["res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh"] - -source_file="res://addons/zylann.hterrain/models/grass_quad_x4.obj" -dest_files=["res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh", "res://.godot/imported/grass_quad_x4.obj-c449a7d6c810ba1595ed30df9fbf3d28.mesh"] - -[params] - -generate_tangents=true -generate_lods=true -generate_shadow_mesh=true -generate_lightmap_uv2=false -generate_lightmap_uv2_texel_size=0.2 -scale_mesh=Vector3(1, 1, 1) -offset_mesh=Vector3(0, 0, 0) -force_disable_mesh_compression=false diff --git a/godot/addons/zylann.hterrain/native/.clang-format b/godot/addons/zylann.hterrain/native/.clang-format deleted file mode 100644 index 237fd9c..0000000 --- a/godot/addons/zylann.hterrain/native/.clang-format +++ /dev/null @@ -1,127 +0,0 @@ -# Commented out parameters are those with the same value as base LLVM style -# We can uncomment them if we want to change their value, or enforce the -# chosen value in case the base style changes (last sync: Clang 6.0.1). ---- -### General config, applies to all languages ### -BasedOnStyle: LLVM -AccessModifierOffset: -4 -AlignAfterOpenBracket: DontAlign -# AlignConsecutiveAssignments: false -# AlignConsecutiveDeclarations: false -# AlignEscapedNewlines: Right -# AlignOperands: true -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: false -# AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: true -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: true -# AllowShortLoopsOnASingleLine: false -# AlwaysBreakAfterDefinitionReturnType: None -# AlwaysBreakAfterReturnType: None -# AlwaysBreakBeforeMultilineStrings: false -# AlwaysBreakTemplateDeclarations: false -# BinPackArguments: true -# BinPackParameters: true -# BraceWrapping: -# AfterClass: false -# AfterControlStatement: false -# AfterEnum: false -# AfterFunction: false -# AfterNamespace: false -# AfterObjCDeclaration: false -# AfterStruct: false -# AfterUnion: false -# AfterExternBlock: false -# BeforeCatch: false -# BeforeElse: false -# IndentBraces: false -# SplitEmptyFunction: true -# SplitEmptyRecord: true -# SplitEmptyNamespace: true -# BreakBeforeBinaryOperators: None -# BreakBeforeBraces: Attach -# BreakBeforeInheritanceComma: false -BreakBeforeTernaryOperators: false -# BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: AfterColon -# BreakStringLiterals: true -ColumnLimit: 0 -# CommentPragmas: '^ IWYU pragma:' -# CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 8 -ContinuationIndentWidth: 8 -Cpp11BracedListStyle: false -# DerivePointerAlignment: false -# DisableFormat: false -# ExperimentalAutoDetectBinPacking: false -# FixNamespaceComments: true -# ForEachMacros: -# - foreach -# - Q_FOREACH -# - BOOST_FOREACH -# IncludeBlocks: Preserve -IncludeCategories: - - Regex: '".*"' - Priority: 1 - - Regex: '^<.*\.h>' - Priority: 2 - - Regex: '^<.*' - Priority: 3 -# IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: true -# IndentPPDirectives: None -IndentWidth: 4 -# IndentWrappedFunctionNames: false -# JavaScriptQuotes: Leave -# JavaScriptWrapImports: true -# KeepEmptyLinesAtTheStartOfBlocks: true -# MacroBlockBegin: '' -# MacroBlockEnd: '' -# MaxEmptyLinesToKeep: 1 -# NamespaceIndentation: None -# PenaltyBreakAssignment: 2 -# PenaltyBreakBeforeFirstCallParameter: 19 -# PenaltyBreakComment: 300 -# PenaltyBreakFirstLessLess: 120 -# PenaltyBreakString: 1000 -# PenaltyExcessCharacter: 1000000 -# PenaltyReturnTypeOnItsOwnLine: 60 -# PointerAlignment: Right -# RawStringFormats: -# - Delimiter: pb -# Language: TextProto -# BasedOnStyle: google -# ReflowComments: true -# SortIncludes: true -# SortUsingDeclarations: true -# SpaceAfterCStyleCast: false -# SpaceAfterTemplateKeyword: true -# SpaceBeforeAssignmentOperators: true -# SpaceBeforeParens: ControlStatements -# SpaceInEmptyParentheses: false -# SpacesBeforeTrailingComments: 1 -# SpacesInAngles: false -# SpacesInContainerLiterals: true -# SpacesInCStyleCastParentheses: false -# SpacesInParentheses: false -# SpacesInSquareBrackets: false -TabWidth: 4 -UseTab: Always ---- -### C++ specific config ### -Language: Cpp -Standard: Cpp03 ---- -### ObjC specific config ### -Language: ObjC -Standard: Cpp03 -ObjCBlockIndentWidth: 4 -# ObjCSpaceAfterProperty: false -# ObjCSpaceBeforeProtocolList: true ---- -### Java specific config ### -Language: Java -# BreakAfterJavaFieldAnnotations: false -... diff --git a/godot/addons/zylann.hterrain/native/.gitignore b/godot/addons/zylann.hterrain/native/.gitignore deleted file mode 100644 index ec67d10..0000000 --- a/godot/addons/zylann.hterrain/native/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Build -# Ignored locally because there are other folders in which we want to version OBJ files -*.obj - diff --git a/godot/addons/zylann.hterrain/native/SConstruct b/godot/addons/zylann.hterrain/native/SConstruct deleted file mode 100644 index e36eb55..0000000 --- a/godot/addons/zylann.hterrain/native/SConstruct +++ /dev/null @@ -1,119 +0,0 @@ -#!python -import os - -opts = Variables([], ARGUMENTS) - -# Gets the standard flags CC, CCX, etc. -env = Environment(ENV = os.environ) - -# Define our options -opts.Add(EnumVariable('target', "Compilation target", 'debug', ['debug', 'release'])) -opts.Add(EnumVariable('platform', "Compilation platform", '', ['', 'windows', 'linux', 'osx'])) -opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) -opts.Add(EnumVariable('macos_arch', "Target macOS architecture", 'universal', ['universal', 'x86_64', 'arm64'])) - -# Hardcoded ones -target_path = "bin/" -TARGET_NAME = "hterrain_native" - -# Local dependency paths -godot_headers_path = "godot-cpp/godot-headers/" -cpp_bindings_path = "godot-cpp/" -cpp_bindings_library = "libgodot-cpp" - -# only support 64 at this time -bits = 64 - -# Updates the environment with the option variables. -opts.Update(env) - -# Process some arguments -if env['use_llvm']: - env['CC'] = 'clang' - env['CXX'] = 'clang++' - -if env['platform'] == '': - print("No valid target platform selected.") - quit() - -# For the reference: -# - CCFLAGS are compilation flags shared between C and C++ -# - CFLAGS are for C-specific compilation flags -# - CXXFLAGS are for C++-specific compilation flags -# - CPPFLAGS are for pre-processor flags -# - CPPDEFINES are for pre-processor defines -# - LINKFLAGS are for linking flags - -# Check our platform specifics -if env['platform'] == "osx": - target_path += 'osx/' - cpp_bindings_library += '.osx' - if env['target'] == 'debug': - env.Append(CCFLAGS = ['-g', '-O2', '-arch', 'x86_64']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-arch', 'x86_64']) - else: - env.Append(CCFLAGS = ['-g', '-O3', '-arch', 'x86_64']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-arch', 'x86_64']) - -elif env['platform'] == "linux": - target_path += 'linux/' - cpp_bindings_library += '.linux' - if env['target'] == 'debug': - # -g3 means we want plenty of debug info, more than default - env.Append(CCFLAGS = ['-fPIC', '-g3', '-Og']) - env.Append(CXXFLAGS = ['-std=c++17']) - else: - env.Append(CCFLAGS = ['-fPIC', '-O3']) - env.Append(CXXFLAGS = ['-std=c++17']) - env.Append(LINKFLAGS = ['-s']) - -elif env['platform'] == "windows": - target_path += 'win64/' - cpp_bindings_library += '.windows' - # This makes sure to keep the session environment variables on windows, - # that way you can run scons in a vs 2017 prompt and it will find all the required tools - #env.Append(ENV = os.environ) - - env.Append(CPPDEFINES = ['WIN32', '_WIN32', '_WINDOWS', '_CRT_SECURE_NO_WARNINGS']) - env.Append(CCFLAGS = ['-W3', '-GR']) - if env['target'] == 'debug': - env.Append(CPPDEFINES = ['_DEBUG']) - env.Append(CCFLAGS = ['-EHsc', '-MDd', '-ZI']) - env.Append(LINKFLAGS = ['-DEBUG']) - else: - env.Append(CPPDEFINES = ['NDEBUG']) - env.Append(CCFLAGS = ['-O2', '-EHsc', '-MD']) - -if env['target'] == 'debug': - cpp_bindings_library += '.debug' -else: - cpp_bindings_library += '.release' - -if env['macos_arch'] == 'universal': - cpp_bindings_library += '.' + str(bits) -else: - cpp_bindings_library += '.' + env['macos_arch'] - -# make sure our binding library is properly included -env.Append(CPPPATH = [ - '.', - godot_headers_path, - cpp_bindings_path + 'include/', - cpp_bindings_path + 'include/core/', - cpp_bindings_path + 'include/gen/' -]) -env.Append(LIBPATH = [cpp_bindings_path + 'bin/']) -env.Append(LIBS = [cpp_bindings_library]) - -# Add source files of our library -env.Append(CPPPATH = ['src/']) -sources = Glob('src/*.cpp') - -library = env.SharedLibrary(target = target_path + TARGET_NAME , source = sources) - -Default(library) - -# Generates help for the -h scons option. -Help(opts.GenerateHelpText(env)) diff --git a/godot/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so b/godot/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so deleted file mode 100644 index b562edd..0000000 Binary files a/godot/addons/zylann.hterrain/native/bin/linux/libhterrain_native.so and /dev/null differ diff --git a/godot/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib b/godot/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib deleted file mode 100755 index bba68dd..0000000 Binary files a/godot/addons/zylann.hterrain/native/bin/osx/libhterrain_native.dylib and /dev/null differ diff --git a/godot/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll b/godot/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll deleted file mode 100644 index 4f2af10..0000000 Binary files a/godot/addons/zylann.hterrain/native/bin/win64/hterrain_native.dll and /dev/null differ diff --git a/godot/addons/zylann.hterrain/native/factory.gd b/godot/addons/zylann.hterrain/native/factory.gd deleted file mode 100644 index d2dfe56..0000000 --- a/godot/addons/zylann.hterrain/native/factory.gd +++ /dev/null @@ -1,55 +0,0 @@ -@tool - -const NATIVE_PATH = "res://addons/zylann.hterrain/native/" - -const HT_ImageUtilsGeneric = preload("./image_utils_generic.gd") -const HT_QuadTreeLodGeneric = preload("./quad_tree_lod_generic.gd") - -# No native code was ported when moving to Godot 4. -# It may be changed too using GDExtension. - -# See https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-get-name -const _supported_os = { - # "Windows": true, - # "X11": true, - # "OSX": true -} -# See https://docs.godotengine.org/en/stable/tutorials/export/feature_tags.html -const _supported_archs = ["x86_64"] - - -static func _supports_current_arch() -> bool: - for arch in _supported_archs: - # This is misleading, we are querying features of the ENGINE, not the OS - if OS.has_feature(arch): - return true - return false - - -static func is_native_available() -> bool: - if not _supports_current_arch(): - return false - var os = OS.get_name() - if not _supported_os.has(os): - return false - # API changes can cause binary incompatibility - var v = Engine.get_version_info() - return v.major == 4 and v.minor == 0 - - -static func get_image_utils(): - if is_native_available(): - var HT_ImageUtilsNative = load(NATIVE_PATH + "image_utils.gdns") - # TODO Godot doesn't always return `null` when it fails so that `if` doesn't always help... - # See https://github.com/Zylann/godot_heightmap_plugin/issues/331 - if HT_ImageUtilsNative != null: - return HT_ImageUtilsNative.new() - return HT_ImageUtilsGeneric.new() - - -static func get_quad_tree_lod(): - if is_native_available(): - var HT_QuadTreeLod = load(NATIVE_PATH + "quad_tree_lod.gdns") - if HT_QuadTreeLod != null: - return HT_QuadTreeLod.new() - return HT_QuadTreeLodGeneric.new() diff --git a/godot/addons/zylann.hterrain/native/factory.gd.uid b/godot/addons/zylann.hterrain/native/factory.gd.uid deleted file mode 100644 index 4e87377..0000000 --- a/godot/addons/zylann.hterrain/native/factory.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vrsd12c1sh8r diff --git a/godot/addons/zylann.hterrain/native/image_utils_generic.gd b/godot/addons/zylann.hterrain/native/image_utils_generic.gd deleted file mode 100644 index 2a8aed8..0000000 --- a/godot/addons/zylann.hterrain/native/image_utils_generic.gd +++ /dev/null @@ -1,316 +0,0 @@ -@tool - -# These functions are the same as the ones found in the GDNative library. -# They are used if the user's platform is not supported. - -const HT_Util = preload("../util/util.gd") - -var _blur_buffer : Image - - -func get_red_range(im: Image, rect: Rect2) -> Vector2: - rect = rect.intersection(Rect2(0, 0, im.get_width(), im.get_height())) - var min_x := int(rect.position.x) - var min_y := int(rect.position.y) - var max_x := min_x + int(rect.size.x) - var max_y := min_y + int(rect.size.y) - - var min_height := im.get_pixel(min_x, min_y).r - var max_height := min_height - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var h = im.get_pixel(x, y).r - if h < min_height: - min_height = h - elif h > max_height: - max_height = h - - return Vector2(min_height, max_height) - - -func get_red_sum(im: Image, rect: Rect2) -> float: - rect = rect.intersection(Rect2(0, 0, im.get_width(), im.get_height())) - var min_x := int(rect.position.x) - var min_y := int(rect.position.y) - var max_x := min_x + int(rect.size.x) - var max_y := min_y + int(rect.size.y) - - var sum := 0.0 - - for y in range(min_y, max_y): - for x in range(min_x, max_x): - sum += im.get_pixel(x, y).r - - return sum - - -func get_red_sum_weighted(im: Image, brush: Image, pos: Vector2, factor: float) -> float: - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - var sum = 0.0 - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - sum += im.get_pixel(x, y).r * shape_value * factor - - return sum - - -func add_red_brush(im: Image, brush: Image, pos: Vector2, factor: float): - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var r = im.get_pixel(x, y).r + shape_value * factor - im.set_pixel(x, y, Color(r, r, r)) - - -func lerp_channel_brush(im: Image, brush: Image, pos: Vector2, - factor: float, target_value: float, channel: int): - - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var c = im.get_pixel(x, y) - c[channel] = lerp(c[channel], target_value, shape_value * factor) - im.set_pixel(x, y, c) - - -func lerp_color_brush(im: Image, brush: Image, pos: Vector2, - factor: float, target_value: Color): - - var min_x = int(pos.x) - var min_y = int(pos.y) - var max_x = min_x + brush.get_width() - var max_y = min_y + brush.get_height() - var min_noclamp_x = min_x - var min_noclamp_y = min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - for y in range(min_y, max_y): - var by = y - min_noclamp_y - - for x in range(min_x, max_x): - var bx = x - min_noclamp_x - - var shape_value = brush.get_pixel(bx, by).r - var c = im.get_pixel(x, y).lerp(target_value, factor * shape_value) - im.set_pixel(x, y, c) - - -func generate_gaussian_brush(im: Image) -> float: - var sum := 0.0 - var center := Vector2(im.get_width() / 2, im.get_height() / 2) - var radius := minf(im.get_width(), im.get_height()) / 2.0 - - for y in im.get_height(): - for x in im.get_width(): - var d := Vector2(x, y).distance_to(center) / radius - var v := clampf(1.0 - d * d * d, 0.0, 1.0) - im.set_pixel(x, y, Color(v, v, v)) - sum += v; - - return sum - - -func blur_red_brush(im: Image, brush: Image, pos: Vector2, factor: float): - factor = clampf(factor, 0.0, 1.0) - - if _blur_buffer == null: - _blur_buffer = Image.new() - var buffer := _blur_buffer - - var buffer_width := brush.get_width() + 2 - var buffer_height := brush.get_height() + 2 - - if buffer_width != buffer.get_width() or buffer_height != buffer.get_height(): - buffer.create(buffer_width, buffer_height, false, Image.FORMAT_RF) - - var min_x := int(pos.x) - 1 - var min_y := int(pos.y) - 1 - var max_x := min_x + buffer.get_width() - var max_y := min_y + buffer.get_height() - - var im_clamp_w = im.get_width() - 1 - var im_clamp_h = im.get_height() - 1 - - # Copy pixels to temporary buffer - for y in range(min_y, max_y): - for x in range(min_x, max_x): - var ix := clampi(x, 0, im_clamp_w) - var iy := clampi(y, 0, im_clamp_h) - var c = im.get_pixel(ix, iy) - buffer.set_pixel(x - min_x, y - min_y, c) - - min_x = int(pos.x) - min_y = int(pos.y) - max_x = min_x + brush.get_width() - max_y = min_y + brush.get_height() - var min_noclamp_x := min_x - var min_noclamp_y := min_y - - min_x = clampi(min_x, 0, im.get_width()) - min_y = clampi(min_y, 0, im.get_height()) - max_x = clampi(max_x, 0, im.get_width()) - max_y = clampi(max_y, 0, im.get_height()) - - # Apply blur - for y in range(min_y, max_y): - var by := y - min_noclamp_y - - for x in range(min_x, max_x): - var bx := x - min_noclamp_x - - var shape_value := brush.get_pixel(bx, by).r * factor - - var p10 = buffer.get_pixel(bx + 1, by ).r - var p01 = buffer.get_pixel(bx, by + 1).r - var p11 = buffer.get_pixel(bx + 1, by + 1).r - var p21 = buffer.get_pixel(bx + 2, by + 1).r - var p12 = buffer.get_pixel(bx + 1, by + 2).r - - var m = (p10 + p01 + p11 + p21 + p12) * 0.2 - var p = lerpf(p11, m, shape_value * factor) - - im.set_pixel(x, y, Color(p, p, p)) - - -func paint_indexed_splat(index_map: Image, weight_map: Image, brush: Image, pos: Vector2, \ - texture_index: int, factor: float): - - var min_x := pos.x - var min_y := pos.y - var max_x := min_x + brush.get_width() - var max_y := min_y + brush.get_height() - var min_noclamp_x := min_x - var min_noclamp_y := min_y - - min_x = clampi(min_x, 0, index_map.get_width()) - min_y = clampi(min_y, 0, index_map.get_height()) - max_x = clampi(max_x, 0, index_map.get_width()) - max_y = clampi(max_y, 0, index_map.get_height()) - - var texture_index_f := float(texture_index) / 255.0 - var all_texture_index_f := Color(texture_index_f, texture_index_f, texture_index_f) - var ci := texture_index % 3 - var cm := Color(-1, -1, -1) - cm[ci] = 1 - - for y in range(min_y, max_y): - var by := y - min_noclamp_y - - for x in range(min_x, max_x): - var bx := x - min_noclamp_x - - var shape_value := brush.get_pixel(bx, by).r * factor - if shape_value == 0.0: - continue - - var i := index_map.get_pixel(x, y) - var w := weight_map.get_pixel(x, y) - - # Decompress third weight to make computations easier - w[2] = 1.0 - w[0] - w[1] - - # The index map tells which textures to blend. - # The weight map tells their blending amounts. - # This brings the limitation that up to 3 textures can blend at a time in a given pixel. - # Painting this in real time can be a challenge. - - # The approach here is a compromise for simplicity. - # Each texture is associated a fixed component of the index map (R, G or B), - # so two neighbor pixels having the same component won't be guaranteed to blend. - # In other words, texture T will not be able to blend with T + N * k, - # where k is an integer, and N is the number of components in the index map (up to 4). - # It might still be able to blend due to a special case when an area is uniform, - # but not otherwise. - - # Dynamic component assignment sounds like the alternative, however I wasn't able - # to find a painting algorithm that wasn't confusing, at least the current one is - # predictable. - - # Need to use approximation because Color is float but GDScript uses doubles... - if abs(i[ci] - texture_index_f) > 0.001: - # Pixel does not have our texture index, - # transfer its weight to other components first - if w[ci] > shape_value: - w -= cm * shape_value - - elif w[ci] >= 0.0: - w[ci] = 0.0 - i[ci] = texture_index_f - - else: - # Pixel has our texture index, increase its weight - if w[ci] + shape_value < 1.0: - w += cm * shape_value - - else: - # Pixel weight is full, we can set all components to the same index. - # Need to nullify other weights because they would otherwise never reach - # zero due to normalization - w = Color(0, 0, 0) - w[ci] = 1.0 - i = all_texture_index_f - - # No `saturate` function in Color?? - w[0] = clampf(w[0], 0.0, 1.0) - w[1] = clampf(w[1], 0.0, 1.0) - w[2] = clampf(w[2], 0.0, 1.0) - - # Renormalize - w /= w[0] + w[1] + w[2] - - index_map.set_pixel(x, y, i) - weight_map.set_pixel(x, y, w) diff --git a/godot/addons/zylann.hterrain/native/image_utils_generic.gd.uid b/godot/addons/zylann.hterrain/native/image_utils_generic.gd.uid deleted file mode 100644 index d12dce2..0000000 --- a/godot/addons/zylann.hterrain/native/image_utils_generic.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dlvv43m6trgbx diff --git a/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd b/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd deleted file mode 100644 index 8518965..0000000 --- a/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd +++ /dev/null @@ -1,188 +0,0 @@ -@tool -# Independent quad tree designed to handle LOD - -class HT_QTLQuad: - # Optional array of 4 HT_QTLQuad - var children = null - - # TODO Use Vector2i - var origin_x : int = 0 - var origin_y : int = 0 - - var data = null - - func _init(): - pass - - func clear(): - clear_children() - data = null - - func clear_children(): - children = null - - func has_children() -> bool: - return children != null - - -var _tree := HT_QTLQuad.new() -var _max_depth : int = 0 -var _base_size : int = 16 -var _split_scale : float = 2.0 - -var _make_func : Callable -var _recycle_func : Callable -var _vertical_bounds_func : Callable - - -func set_callbacks(make_cb: Callable, recycle_cb: Callable, vbounds_cb: Callable): - _make_func = make_cb - _recycle_func = recycle_cb - _vertical_bounds_func = vbounds_cb - - -func clear(): - _join_all_recursively(_tree, _max_depth) - _max_depth = 0 - _base_size = 0 - - -static func compute_lod_count(base_size: int, full_size: int) -> int: - var po : int = 0 - while full_size > base_size: - full_size = full_size >> 1 - po += 1 - return po - - -func create_from_sizes(base_size: int, full_size: int): - clear() - _base_size = base_size - _max_depth = compute_lod_count(base_size, full_size) - - -func get_lod_count() -> int: - # TODO _max_depth is a maximum, not a count. Would be better for it to be a count (+1) - return _max_depth + 1 - - -# The higher, the longer LODs will spread and higher the quality. -# The lower, the shorter LODs will spread and lower the quality. -func set_split_scale(p_split_scale: float): - var MIN := 2.0 - var MAX := 5.0 - - # Split scale must be greater than a threshold, - # otherwise lods will decimate too fast and it will look messy - _split_scale = clampf(p_split_scale, MIN, MAX) - - -func get_split_scale() -> float: - return _split_scale - - -func update(view_pos: Vector3): - _update(_tree, _max_depth, view_pos) - - # This makes sure we keep seeing the lowest LOD, - # if the tree is cleared while we are far away - if not _tree.has_children() and _tree.data == null: - _tree.data = _make_chunk(_max_depth, 0, 0) - - -func get_lod_factor(lod: int) -> int: - return 1 << lod - - -func _update(quad: HT_QTLQuad, lod: int, view_pos: Vector3): - # This function should be called regularly over frames. - - var lod_factor : int = get_lod_factor(lod) - var chunk_size : int = _base_size * lod_factor - var world_center := \ - chunk_size * (Vector3(quad.origin_x, 0, quad.origin_y) + Vector3(0.5, 0, 0.5)) - - if _vertical_bounds_func.is_valid(): - var vbounds : Vector2 = _vertical_bounds_func.call(quad.origin_x, quad.origin_y, lod) - world_center.y = (vbounds.x + vbounds.y) / 2.0 - - var split_distance := _base_size * lod_factor * _split_scale - - if not quad.has_children(): - if lod > 0 and world_center.distance_to(view_pos) < split_distance: - # Split - quad.children = [null, null, null, null] - - for i in 4: - var child := HT_QTLQuad.new() - child.origin_x = quad.origin_x * 2 + (i & 1) - child.origin_y = quad.origin_y * 2 + ((i & 2) >> 1) - quad.children[i] = child - child.data = _make_chunk(lod - 1, child.origin_x, child.origin_y) - # If the quad needs to split more, we'll ask more recycling... - - if quad.data != null: - _recycle_chunk(quad.data, quad.origin_x, quad.origin_y, lod) - quad.data = null - - else: - var no_split_child := true - - for child in quad.children: - _update(child, lod - 1, view_pos) - if child.has_children(): - no_split_child = false - - if no_split_child and world_center.distance_to(view_pos) > split_distance: - # Join - for i in 4: - var child : HT_QTLQuad = quad.children[i] - _recycle_chunk(child.data, child.origin_x, child.origin_y, lod - 1) - quad.clear_children() - quad.data = _make_chunk(lod, quad.origin_x, quad.origin_y) - - -func _join_all_recursively(quad: HT_QTLQuad, lod: int): - if quad.has_children(): - for i in 4: - _join_all_recursively(quad.children[i], lod - 1) - - quad.clear_children() - - elif quad.data != null: - _recycle_chunk(quad.data, quad.origin_x, quad.origin_y, lod) - quad.data = null - - -func _make_chunk(lod: int, origin_x: int, origin_y: int): - var chunk = null - if _make_func.is_valid(): - chunk = _make_func.call(origin_x, origin_y, lod) - return chunk - - -func _recycle_chunk(chunk, origin_x: int, origin_y: int, lod: int): - if _recycle_func.is_valid(): - _recycle_func.call(chunk, origin_x, origin_y, lod) - - -func debug_draw_tree(ci: CanvasItem): - var quad := _tree - _debug_draw_tree_recursive(ci, quad, _max_depth, 0) - - -func _debug_draw_tree_recursive(ci: CanvasItem, quad: HT_QTLQuad, lod_index: int, child_index: int): - if quad.has_children(): - for i in 4: - _debug_draw_tree_recursive(ci, quad.children[i], lod_index - 1, i) - else: - var size : int = get_lod_factor(lod_index) - var checker : int = 0 - if child_index == 1 or child_index == 2: - checker = 1 - var chunk_indicator : int = 0 - if quad.data != null: - chunk_indicator = 1 - var r := Rect2(Vector2(quad.origin_x, quad.origin_y) * size, Vector2(size, size)) - ci.draw_rect(r, Color(1.0 - lod_index * 0.2, 0.2 * checker, chunk_indicator, 1)) - diff --git a/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd.uid b/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd.uid deleted file mode 100644 index 8a1732e..0000000 --- a/godot/addons/zylann.hterrain/native/quad_tree_lod_generic.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cnx6d4p5mlrma diff --git a/godot/addons/zylann.hterrain/native/src/.gdignore b/godot/addons/zylann.hterrain/native/src/.gdignore deleted file mode 100644 index e69de29..0000000 diff --git a/godot/addons/zylann.hterrain/native/src/gd_library.cpp b/godot/addons/zylann.hterrain/native/src/gd_library.cpp deleted file mode 100644 index 2836ecd..0000000 --- a/godot/addons/zylann.hterrain/native/src/gd_library.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "image_utils.h" -#include "quad_tree_lod.h" - -extern "C" { - -void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { -#ifdef _DEBUG - printf("godot_gdnative_init hterrain_native\n"); -#endif - godot::Godot::gdnative_init(o); -} - -void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { -#ifdef _DEBUG - printf("godot_gdnative_terminate hterrain_native\n"); -#endif - godot::Godot::gdnative_terminate(o); -} - -void GDN_EXPORT godot_nativescript_init(void *handle) { -#ifdef _DEBUG - printf("godot_nativescript_init hterrain_native\n"); -#endif - godot::Godot::nativescript_init(handle); - - godot::register_tool_class(); - godot::register_tool_class(); -} - -} // extern "C" diff --git a/godot/addons/zylann.hterrain/native/src/image_utils.cpp b/godot/addons/zylann.hterrain/native/src/image_utils.cpp deleted file mode 100644 index b82beff..0000000 --- a/godot/addons/zylann.hterrain/native/src/image_utils.cpp +++ /dev/null @@ -1,364 +0,0 @@ -#include "image_utils.h" -#include "int_range_2d.h" -#include "math_funcs.h" - -namespace godot { - -template -inline void generic_brush_op(Image &image, Image &brush, Vector2 p_pos, float factor, F op) { - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - int min_x_noclamp = range.min_x; - int min_y_noclamp = range.min_y; - range.clip(Vector2i(image.get_size())); - - image.lock(); - brush.lock(); - - for (int y = range.min_y; y < range.max_y; ++y) { - int by = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - int bx = x - min_x_noclamp; - - float b = brush.get_pixel(bx, by).r * factor; - op(image, x, y, b); - } - } - - image.unlock(); - brush.unlock(); -} - -ImageUtils::ImageUtils() { -#ifdef _DEBUG - Godot::print("Constructing ImageUtils"); -#endif -} - -ImageUtils::~ImageUtils() { -#ifdef _DEBUG - // TODO Cannot print shit here, see https://github.com/godotengine/godot/issues/37417 - // Means only the console will print this - //Godot::print("Destructing ImageUtils"); - printf("Destructing ImageUtils\n"); -#endif -} - -void ImageUtils::_init() { -} - -Vector2 ImageUtils::get_red_range(Ref image_ref, Rect2 rect) const { - ERR_FAIL_COND_V(image_ref.is_null(), Vector2()); - Image &image = **image_ref; - - IntRange2D range(rect); - range.clip(Vector2i(image.get_size())); - - image.lock(); - - float min_value = image.get_pixel(range.min_x, range.min_y).r; - float max_value = min_value; - - for (int y = range.min_y; y < range.max_y; ++y) { - for (int x = range.min_x; x < range.max_x; ++x) { - float v = image.get_pixel(x, y).r; - - if (v > max_value) { - max_value = v; - } else if (v < min_value) { - min_value = v; - } - } - } - - image.unlock(); - - return Vector2(min_value, max_value); -} - -float ImageUtils::get_red_sum(Ref image_ref, Rect2 rect) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - Image &image = **image_ref; - - IntRange2D range(rect); - range.clip(Vector2i(image.get_size())); - - image.lock(); - - float sum = 0.f; - - for (int y = range.min_y; y < range.max_y; ++y) { - for (int x = range.min_x; x < range.max_x; ++x) { - sum += image.get_pixel(x, y).r; - } - } - - image.unlock(); - - return sum; -} - -float ImageUtils::get_red_sum_weighted(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - ERR_FAIL_COND_V(brush_ref.is_null(), 0.f); - Image &image = **image_ref; - Image &brush = **brush_ref; - - float sum = 0.f; - generic_brush_op(image, brush, p_pos, factor, [&sum](Image &image, int x, int y, float b) { - sum += image.get_pixel(x, y).r * b; - }); - - return sum; -} - -void ImageUtils::add_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [](Image &image, int x, int y, float b) { - float r = image.get_pixel(x, y).r + b; - image.set_pixel(x, y, Color(r, r, r)); - }); -} - -void ImageUtils::lerp_channel_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, float target_value, int channel) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [target_value, channel](Image &image, int x, int y, float b) { - Color c = image.get_pixel(x, y); - c[channel] = Math::lerp(c[channel], target_value, b); - image.set_pixel(x, y, c); - }); -} - -void ImageUtils::lerp_color_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, Color target_value) const { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - generic_brush_op(image, brush, p_pos, factor, [target_value](Image &image, int x, int y, float b) { - const Color c = image.get_pixel(x, y).linear_interpolate(target_value, b); - image.set_pixel(x, y, c); - }); -} - -// TODO Smooth (each pixel being box-filtered, contrary to the existing smooth) - -float ImageUtils::generate_gaussian_brush(Ref image_ref) const { - ERR_FAIL_COND_V(image_ref.is_null(), 0.f); - Image &image = **image_ref; - - int w = static_cast(image.get_width()); - int h = static_cast(image.get_height()); - Vector2 center(w / 2, h / 2); - float radius = Math::min(w, h) / 2; - - ERR_FAIL_COND_V(radius <= 0.1f, 0.f); - - float sum = 0.f; - image.lock(); - - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - float d = Vector2(x, y).distance_to(center) / radius; - float v = Math::clamp(1.f - d * d * d, 0.f, 1.f); - image.set_pixel(x, y, Color(v, v, v)); - sum += v; - } - } - - image.unlock(); - return sum; -} - -void ImageUtils::blur_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) { - ERR_FAIL_COND(image_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &image = **image_ref; - Image &brush = **brush_ref; - - factor = Math::clamp(factor, 0.f, 1.f); - - // Relative to the image - IntRange2D buffer_range = IntRange2D::from_pos_size(p_pos, brush.get_size()); - buffer_range.pad(1); - - const int image_width = static_cast(image.get_width()); - const int image_height = static_cast(image.get_height()); - - const int buffer_width = static_cast(buffer_range.get_width()); - const int buffer_height = static_cast(buffer_range.get_height()); - _blur_buffer.resize(buffer_width * buffer_height); - - image.lock(); - - // Cache pixels, because they will be queried more than once and written to later - int buffer_i = 0; - for (int y = buffer_range.min_y; y < buffer_range.max_y; ++y) { - for (int x = buffer_range.min_x; x < buffer_range.max_x; ++x) { - const int ix = Math::clamp(x, 0, image_width - 1); - const int iy = Math::clamp(y, 0, image_height - 1); - _blur_buffer[buffer_i] = image.get_pixel(ix, iy).r; - ++buffer_i; - } - } - - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - const int min_x_noclamp = range.min_x; - const int min_y_noclamp = range.min_y; - range.clip(Vector2i(image.get_size())); - - const int buffer_offset_left = -1; - const int buffer_offset_right = 1; - const int buffer_offset_top = -buffer_width; - const int buffer_offset_bottom = buffer_width; - - brush.lock(); - - // Apply blur - for (int y = range.min_y; y < range.max_y; ++y) { - const int brush_y = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - const int brush_x = x - min_x_noclamp; - - const float brush_value = brush.get_pixel(brush_x, brush_y).r * factor; - - buffer_i = (brush_x + 1) + (brush_y + 1) * buffer_width; - - const float p10 = _blur_buffer[buffer_i + buffer_offset_top]; - const float p01 = _blur_buffer[buffer_i + buffer_offset_left]; - const float p11 = _blur_buffer[buffer_i]; - const float p21 = _blur_buffer[buffer_i + buffer_offset_right]; - const float p12 = _blur_buffer[buffer_i + buffer_offset_bottom]; - - // Average - float m = (p10 + p01 + p11 + p21 + p12) * 0.2f; - float p = Math::lerp(p11, m, brush_value); - - image.set_pixel(x, y, Color(p, p, p)); - } - } - - image.unlock(); - brush.unlock(); -} - -void ImageUtils::paint_indexed_splat(Ref index_map_ref, Ref weight_map_ref, - Ref brush_ref, Vector2 p_pos, int texture_index, float factor) { - - ERR_FAIL_COND(index_map_ref.is_null()); - ERR_FAIL_COND(weight_map_ref.is_null()); - ERR_FAIL_COND(brush_ref.is_null()); - Image &index_map = **index_map_ref; - Image &weight_map = **weight_map_ref; - Image &brush = **brush_ref; - - ERR_FAIL_COND(index_map.get_size() != weight_map.get_size()); - - factor = Math::clamp(factor, 0.f, 1.f); - - IntRange2D range = IntRange2D::from_min_max(p_pos, brush.get_size()); - const int min_x_noclamp = range.min_x; - const int min_y_noclamp = range.min_y; - range.clip(Vector2i(index_map.get_size())); - - const float texture_index_f = float(texture_index) / 255.f; - const Color all_texture_index_f(texture_index_f, texture_index_f, texture_index_f); - const int ci = texture_index % 3; - Color cm(-1, -1, -1); - cm[ci] = 1; - - brush.lock(); - index_map.lock(); - weight_map.lock(); - - for (int y = range.min_y; y < range.max_y; ++y) { - const int brush_y = y - min_y_noclamp; - - for (int x = range.min_x; x < range.max_x; ++x) { - const int brush_x = x - min_x_noclamp; - - const float brush_value = brush.get_pixel(brush_x, brush_y).r * factor; - - if (brush_value == 0.f) { - continue; - } - - Color i = index_map.get_pixel(x, y); - Color w = weight_map.get_pixel(x, y); - - // Decompress third weight to make computations easier - w[2] = 1.f - w[0] - w[1]; - - if (std::abs(i[ci] - texture_index_f) > 0.001f) { - // Pixel does not have our texture index, - // transfer its weight to other components first - if (w[ci] > brush_value) { - w[0] -= cm[0] * brush_value; - w[1] -= cm[1] * brush_value; - w[2] -= cm[2] * brush_value; - - } else if (w[ci] >= 0.f) { - w[ci] = 0.f; - i[ci] = texture_index_f; - } - - } else { - // Pixel has our texture index, increase its weight - if (w[ci] + brush_value < 1.f) { - w[0] += cm[0] * brush_value; - w[1] += cm[1] * brush_value; - w[2] += cm[2] * brush_value; - - } else { - // Pixel weight is full, we can set all components to the same index. - // Need to nullify other weights because they would otherwise never reach - // zero due to normalization - w = Color(0, 0, 0); - w[ci] = 1.0; - i = all_texture_index_f; - } - } - - // No `saturate` function in Color?? - w[0] = Math::clamp(w[0], 0.f, 1.f); - w[1] = Math::clamp(w[1], 0.f, 1.f); - w[2] = Math::clamp(w[2], 0.f, 1.f); - - // Renormalize - const float sum = w[0] + w[1] + w[2]; - w[0] /= sum; - w[1] /= sum; - w[2] /= sum; - - index_map.set_pixel(x, y, i); - weight_map.set_pixel(x, y, w); - } - } - - brush.lock(); - index_map.unlock(); - weight_map.unlock(); -} - -void ImageUtils::_register_methods() { - register_method("get_red_range", &ImageUtils::get_red_range); - register_method("get_red_sum", &ImageUtils::get_red_sum); - register_method("get_red_sum_weighted", &ImageUtils::get_red_sum_weighted); - register_method("add_red_brush", &ImageUtils::add_red_brush); - register_method("lerp_channel_brush", &ImageUtils::lerp_channel_brush); - register_method("lerp_color_brush", &ImageUtils::lerp_color_brush); - register_method("generate_gaussian_brush", &ImageUtils::generate_gaussian_brush); - register_method("blur_red_brush", &ImageUtils::blur_red_brush); - register_method("paint_indexed_splat", &ImageUtils::paint_indexed_splat); -} - -} // namespace godot diff --git a/godot/addons/zylann.hterrain/native/src/image_utils.h b/godot/addons/zylann.hterrain/native/src/image_utils.h deleted file mode 100644 index bff0178..0000000 --- a/godot/addons/zylann.hterrain/native/src/image_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef IMAGE_UTILS_H -#define IMAGE_UTILS_H - -#include -#include -#include -#include - -namespace godot { - -class ImageUtils : public Reference { - GODOT_CLASS(ImageUtils, Reference) -public: - static void _register_methods(); - - ImageUtils(); - ~ImageUtils(); - - void _init(); - - Vector2 get_red_range(Ref image_ref, Rect2 rect) const; - float get_red_sum(Ref image_ref, Rect2 rect) const; - float get_red_sum_weighted(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const; - void add_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor) const; - void lerp_channel_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, float target_value, int channel) const; - void lerp_color_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor, Color target_value) const; - float generate_gaussian_brush(Ref image_ref) const; - void blur_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor); - void paint_indexed_splat(Ref index_map_ref, Ref weight_map_ref, Ref brush_ref, Vector2 p_pos, int texture_index, float factor); - //void erode_red_brush(Ref image_ref, Ref brush_ref, Vector2 p_pos, float factor); - -private: - std::vector _blur_buffer; -}; - -} // namespace godot - -#endif // IMAGE_UTILS_H diff --git a/godot/addons/zylann.hterrain/native/src/int_range_2d.h b/godot/addons/zylann.hterrain/native/src/int_range_2d.h deleted file mode 100644 index 1c73f32..0000000 --- a/godot/addons/zylann.hterrain/native/src/int_range_2d.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef INT_RANGE_2D_H -#define INT_RANGE_2D_H - -#include "math_funcs.h" -#include "vector2i.h" -#include - -struct IntRange2D { - int min_x; - int min_y; - int max_x; - int max_y; - - static inline IntRange2D from_min_max(godot::Vector2 min_pos, godot::Vector2 max_pos) { - return IntRange2D(godot::Rect2(min_pos, max_pos)); - } - - static inline IntRange2D from_pos_size(godot::Vector2 min_pos, godot::Vector2 size) { - return IntRange2D(godot::Rect2(min_pos, size)); - } - - IntRange2D(godot::Rect2 rect) { - min_x = static_cast(rect.position.x); - min_y = static_cast(rect.position.y); - max_x = static_cast(rect.position.x + rect.size.x); - max_y = static_cast(rect.position.y + rect.size.y); - } - - inline bool is_inside(Vector2i size) const { - return min_x >= size.x && - min_y >= size.y && - max_x <= size.x && - max_y <= size.y; - } - - inline void clip(Vector2i size) { - min_x = Math::clamp(min_x, 0, size.x); - min_y = Math::clamp(min_y, 0, size.y); - max_x = Math::clamp(max_x, 0, size.x); - max_y = Math::clamp(max_y, 0, size.y); - } - - inline void pad(int p) { - min_x -= p; - min_y -= p; - max_x += p; - max_y += p; - } - - inline int get_width() const { - return max_x - min_x; - } - - inline int get_height() const { - return max_y - min_y; - } -}; - -#endif // INT_RANGE_2D_H diff --git a/godot/addons/zylann.hterrain/native/src/math_funcs.h b/godot/addons/zylann.hterrain/native/src/math_funcs.h deleted file mode 100644 index daff418..0000000 --- a/godot/addons/zylann.hterrain/native/src/math_funcs.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MATH_FUNCS_H -#define MATH_FUNCS_H - -namespace Math { - -inline float lerp(float minv, float maxv, float t) { - return minv + t * (maxv - minv); -} - -template -inline T clamp(T x, T minv, T maxv) { - if (x < minv) { - return minv; - } - if (x > maxv) { - return maxv; - } - return x; -} - -template -inline T min(T a, T b) { - return a < b ? a : b; -} - -} // namespace Math - -#endif // MATH_FUNCS_H diff --git a/godot/addons/zylann.hterrain/native/src/quad_tree_lod.cpp b/godot/addons/zylann.hterrain/native/src/quad_tree_lod.cpp deleted file mode 100644 index 592375e..0000000 --- a/godot/addons/zylann.hterrain/native/src/quad_tree_lod.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "quad_tree_lod.h" - -namespace godot { - -void QuadTreeLod::set_callbacks(Ref make_cb, Ref recycle_cb, Ref vbounds_cb) { - _make_func = make_cb; - _recycle_func = recycle_cb; - _vertical_bounds_func = vbounds_cb; -} - -int QuadTreeLod::get_lod_count() { - // TODO make this a count, not max - return _max_depth + 1; -} - -int QuadTreeLod::get_lod_factor(int lod) { - return 1 << lod; -} - -int QuadTreeLod::compute_lod_count(int base_size, int full_size) { - int po = 0; - while (full_size > base_size) { - full_size = full_size >> 1; - po += 1; - } - return po; -} - -// The higher, the longer LODs will spread and higher the quality. -// The lower, the shorter LODs will spread and lower the quality. -void QuadTreeLod::set_split_scale(real_t p_split_scale) { - real_t MIN = 2.0f; - real_t MAX = 5.0f; - - // Split scale must be greater than a threshold, - // otherwise lods will decimate too fast and it will look messy - if (p_split_scale < MIN) - p_split_scale = MIN; - if (p_split_scale > MAX) - p_split_scale = MAX; - - _split_scale = p_split_scale; -} - -real_t QuadTreeLod::get_split_scale() { - return _split_scale; -} - -void QuadTreeLod::clear() { - _join_all_recursively(ROOT, _max_depth); - _max_depth = 0; - _base_size = 0; -} - -void QuadTreeLod::create_from_sizes(int base_size, int full_size) { - clear(); - _base_size = base_size; - _max_depth = compute_lod_count(base_size, full_size); - - // Total qty of nodes is (N^L - 1) / (N - 1). -1 for root, where N=num children, L=levels including the root - int node_count = ((static_cast(pow(4, _max_depth+1)) - 1) / (4 - 1)) - 1; - _node_pool.resize(node_count); // e.g. ((4^6 -1) / 3 ) - 1 = 1364 excluding root - - _free_indices.resize((node_count / 4)); // 1364 / 4 = 341 - for (int i = 0; i < _free_indices.size(); i++) // i = 0 to 340, *4 = 0 to 1360 - _free_indices[i] = 4 * i; // _node_pool[4*0 + i0] is first child, [4*340 + i3] is last -} - -void QuadTreeLod::update(Vector3 view_pos) { - _update(ROOT, _max_depth, view_pos); - - // This makes sure we keep seeing the lowest LOD, - // if the tree is cleared while we are far away - Quad *root = _get_root(); - if (!root->has_children() && root->is_null()) - root->set_data(_make_chunk(_max_depth, 0, 0)); -} - -void QuadTreeLod::debug_draw_tree(CanvasItem *ci) { - if (ci != nullptr) - _debug_draw_tree_recursive(ci, ROOT, _max_depth, 0); -} - -// Intention is to only clear references to children -void QuadTreeLod::_clear_children(unsigned int index) { - Quad *quad = _get_node(index); - if (quad->has_children()) { - _recycle_children(quad->first_child); - quad->first_child = NO_CHILDREN; - } -} - -// Returns the index of the first_child. Allocates from _free_indices. -unsigned int QuadTreeLod::_allocate_children() { - if (_free_indices.size() == 0) { - return NO_CHILDREN; - } - - unsigned int i0 = _free_indices[_free_indices.size() - 1]; - _free_indices.pop_back(); - return i0; -} - -// Pass the first_child index, not the parent index. Stores back in _free_indices. -void QuadTreeLod::_recycle_children(unsigned int i0) { - // Debug check, there is no use case in recycling a node which is not a first child - CRASH_COND(i0 % 4 != 0); - - for (int i = 0; i < 4; ++i) { - _node_pool[i0 + i].init(); - } - - _free_indices.push_back(i0); -} - -Variant QuadTreeLod::_make_chunk(int lod, int origin_x, int origin_y) { - if (_make_func.is_valid()) { - return _make_func->call_func(origin_x, origin_y, lod); - } else { - return Variant(); - } -} - -void QuadTreeLod::_recycle_chunk(unsigned int quad_index, int lod) { - Quad *quad = _get_node(quad_index); - if (_recycle_func.is_valid()) { - _recycle_func->call_func(quad->get_data(), quad->origin_x, quad->origin_y, lod); - } -} - -void QuadTreeLod::_join_all_recursively(unsigned int quad_index, int lod) { - Quad *quad = _get_node(quad_index); - - if (quad->has_children()) { - for (int i = 0; i < 4; i++) { - _join_all_recursively(quad->first_child + i, lod - 1); - } - _clear_children(quad_index); - - } else if (quad->is_valid()) { - _recycle_chunk(quad_index, lod); - quad->clear_data(); - } -} - -void QuadTreeLod::_update(unsigned int quad_index, int lod, Vector3 view_pos) { - // This function should be called regularly over frames. - Quad *quad = _get_node(quad_index); - int lod_factor = get_lod_factor(lod); - int chunk_size = _base_size * lod_factor; - Vector3 world_center = static_cast(chunk_size) * (Vector3(static_cast(quad->origin_x), 0.f, static_cast(quad->origin_y)) + Vector3(0.5f, 0.f, 0.5f)); - - if (_vertical_bounds_func.is_valid()) { - Variant result = _vertical_bounds_func->call_func(quad->origin_x, quad->origin_y, lod); - ERR_FAIL_COND(result.get_type() != Variant::VECTOR2); - Vector2 vbounds = static_cast(result); - world_center.y = (vbounds.x + vbounds.y) / 2.0f; - } - - int split_distance = _base_size * lod_factor * static_cast(_split_scale); - - if (!quad->has_children()) { - if (lod > 0 && world_center.distance_to(view_pos) < split_distance) { - // Split - unsigned int new_idx = _allocate_children(); - ERR_FAIL_COND(new_idx == NO_CHILDREN); - quad->first_child = new_idx; - - for (int i = 0; i < 4; i++) { - Quad *child = _get_node(quad->first_child + i); - child->origin_x = quad->origin_x * 2 + (i & 1); - child->origin_y = quad->origin_y * 2 + ((i & 2) >> 1); - child->set_data(_make_chunk(lod - 1, child->origin_x, child->origin_y)); - // If the quad needs to split more, we'll ask more recycling... - } - - if (quad->is_valid()) { - _recycle_chunk(quad_index, lod); - quad->clear_data(); - } - } - } else { - bool no_split_child = true; - - for (int i = 0; i < 4; i++) { - _update(quad->first_child + i, lod - 1, view_pos); - - if (_get_node(quad->first_child + i)->has_children()) - no_split_child = false; - } - - if (no_split_child && world_center.distance_to(view_pos) > split_distance) { - // Join - for (int i = 0; i < 4; i++) { - _recycle_chunk(quad->first_child + i, lod - 1); - } - _clear_children(quad_index); - quad->set_data(_make_chunk(lod, quad->origin_x, quad->origin_y)); - } - } -} // _update - -void QuadTreeLod::_debug_draw_tree_recursive(CanvasItem *ci, unsigned int quad_index, int lod_index, int child_index) { - Quad *quad = _get_node(quad_index); - - if (quad->has_children()) { - int ch_index = quad->first_child; - for (int i = 0; i < 4; i++) { - _debug_draw_tree_recursive(ci, ch_index + i, lod_index - 1, i); - } - - } else { - real_t size = static_cast(get_lod_factor(lod_index)); - int checker = 0; - if (child_index == 1 || child_index == 2) - checker = 1; - - int chunk_indicator = 0; - if (quad->is_valid()) - chunk_indicator = 1; - - Rect2 rect2(Vector2(static_cast(quad->origin_x), static_cast(quad->origin_y)) * size, - Vector2(size, size)); - Color color(1.0f - static_cast(lod_index) * 0.2f, 0.2f * static_cast(checker), static_cast(chunk_indicator), 1.0f); - ci->draw_rect(rect2, color); - } -} - -void QuadTreeLod::_register_methods() { - register_method("set_callbacks", &QuadTreeLod::set_callbacks); - register_method("get_lod_count", &QuadTreeLod::get_lod_count); - register_method("get_lod_factor", &QuadTreeLod::get_lod_factor); - register_method("compute_lod_count", &QuadTreeLod::compute_lod_count); - register_method("set_split_scale", &QuadTreeLod::set_split_scale); - register_method("get_split_scale", &QuadTreeLod::get_split_scale); - register_method("clear", &QuadTreeLod::clear); - register_method("create_from_sizes", &QuadTreeLod::create_from_sizes); - register_method("update", &QuadTreeLod::update); - register_method("debug_draw_tree", &QuadTreeLod::debug_draw_tree); -} - -} // namespace godot diff --git a/godot/addons/zylann.hterrain/native/src/quad_tree_lod.h b/godot/addons/zylann.hterrain/native/src/quad_tree_lod.h deleted file mode 100644 index a4132ec..0000000 --- a/godot/addons/zylann.hterrain/native/src/quad_tree_lod.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef QUAD_TREE_LOD_H -#define QUAD_TREE_LOD_H - -#include -#include -#include - -#include - -namespace godot { - -class QuadTreeLod : public Reference { - GODOT_CLASS(QuadTreeLod, Reference) -public: - static void _register_methods(); - - QuadTreeLod() {} - ~QuadTreeLod() {} - - void _init() {} - - void set_callbacks(Ref make_cb, Ref recycle_cb, Ref vbounds_cb); - int get_lod_count(); - int get_lod_factor(int lod); - int compute_lod_count(int base_size, int full_size); - void set_split_scale(real_t p_split_scale); - real_t get_split_scale(); - void clear(); - void create_from_sizes(int base_size, int full_size); - void update(Vector3 view_pos); - void debug_draw_tree(CanvasItem *ci); - -private: - static const unsigned int NO_CHILDREN = -1; - static const unsigned int ROOT = -1; - - class Quad { - public: - unsigned int first_child = NO_CHILDREN; - int origin_x = 0; - int origin_y = 0; - - Quad() { - init(); - } - - ~Quad() { - } - - inline void init() { - first_child = NO_CHILDREN; - origin_x = 0; - origin_y = 0; - clear_data(); - } - - inline void clear_data() { - _data = Variant(); - } - - inline bool has_children() { - return first_child != NO_CHILDREN; - } - - inline bool is_null() { - return _data.get_type() == Variant::NIL; - } - - inline bool is_valid() { - return _data.get_type() != Variant::NIL; - } - - inline Variant get_data() { - return _data; - } - - inline void set_data(Variant p_data) { - _data = p_data; - } - - private: - Variant _data; // Type is HTerrainChunk.gd : Object - }; - - Quad _root; - std::vector _node_pool; - std::vector _free_indices; - - int _max_depth = 0; - int _base_size = 16; - real_t _split_scale = 2.0f; - - Ref _make_func; - Ref _recycle_func; - Ref _vertical_bounds_func; - - inline Quad *_get_root() { - return &_root; - } - - inline Quad *_get_node(unsigned int index) { - if (index == ROOT) { - return &_root; - } else { - return &_node_pool[index]; - } - } - - void _clear_children(unsigned int index); - unsigned int _allocate_children(); - void _recycle_children(unsigned int i0); - Variant _make_chunk(int lod, int origin_x, int origin_y); - void _recycle_chunk(unsigned int quad_index, int lod); - void _join_all_recursively(unsigned int quad_index, int lod); - void _update(unsigned int quad_index, int lod, Vector3 view_pos); - void _debug_draw_tree_recursive(CanvasItem *ci, unsigned int quad_index, int lod_index, int child_index); -}; // class QuadTreeLod - -} // namespace godot - -#endif // QUAD_TREE_LOD_H diff --git a/godot/addons/zylann.hterrain/native/src/vector2i.h b/godot/addons/zylann.hterrain/native/src/vector2i.h deleted file mode 100644 index 014d4d8..0000000 --- a/godot/addons/zylann.hterrain/native/src/vector2i.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef VECTOR2I_H -#define VECTOR2I_H - -#include - -struct Vector2i { - int x; - int y; - - Vector2i(godot::Vector2 v) : - x(static_cast(v.x)), - y(static_cast(v.y)) {} - - bool any_zero() const { - return x == 0 || y == 0; - } -}; - -#endif // VECTOR2I_H diff --git a/godot/addons/zylann.hterrain/plugin.cfg b/godot/addons/zylann.hterrain/plugin.cfg deleted file mode 100644 index da9c3ca..0000000 --- a/godot/addons/zylann.hterrain/plugin.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[plugin] - -name="Heightmap Terrain" -description="Heightmap-based terrain" -author="Marc Gilleron" -version="1.7.3 dev" -script="tools/plugin.gd" diff --git a/godot/addons/zylann.hterrain/shaders/array.gdshader b/godot/addons/zylann.hterrain/shaders/array.gdshader deleted file mode 100644 index 21f80a5..0000000 --- a/godot/addons/zylann.hterrain/shaders/array.gdshader +++ /dev/null @@ -1,170 +0,0 @@ -shader_type spatial; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splat_index_map; -uniform sampler2D u_terrain_splat_weight_map; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; -uniform sampler2DArray u_ground_normal_roughness_array; - -// TODO Have UV scales for each texture in an array? -uniform float u_ground_uv_scale; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; -uniform bool u_depth_blending = true; - -varying float v_hole; -varying vec3 v_tint; -varying vec2 v_ground_uv; -varying float v_distance_to_camera; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec3 get_depth_blended_weights(vec3 splat, vec3 bumps) { - float dh = 0.2; - - vec3 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec3 d = h + dh; - d.r -= max(h.g, h.b); - d.g -= max(h.r, h.b); - d.b -= max(h.g, h.r); - - vec3 w = clamp(d, 0, 1); - // Had to normalize, since this approach does not preserve components summing to 1 - return w / (w.x + w.y + w.z); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv.xz / u_ground_uv_scale; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = - clamp((v_distance_to_camera - u_globalmap_blend_start) * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 tex_splat_indexes = texture(u_terrain_splat_index_map, UV); - vec4 tex_splat_weights = texture(u_terrain_splat_weight_map, UV); - // TODO Can't use texelFetch! - // https://github.com/godotengine/godot/issues/31732 - - vec3 splat_indexes = tex_splat_indexes.rgb * 255.0; - vec3 splat_weights = vec3( - tex_splat_weights.r, - tex_splat_weights.g, - 1.0 - tex_splat_weights.r - tex_splat_weights.g - ); - - vec4 ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.x)); - vec4 ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.y)); - vec4 ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv, splat_indexes.z)); - - vec4 nr0 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.x)); - vec4 nr1 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.y)); - vec4 nr2 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv, splat_indexes.z)); - - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - splat_weights = get_depth_blended_weights(splat_weights, vec3(ab0.a, ab1.a, ab2.a)); - } - - ALBEDO = v_tint * ( - ab0.rgb * splat_weights.x - + ab1.rgb * splat_weights.y - + ab2.rgb * splat_weights.z - ); - - ROUGHNESS = - nr0.a * splat_weights.x - + nr1.a * splat_weights.y - + nr2.a * splat_weights.z; - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - - vec3 ground_normal = - normal0 * splat_weights.x - + normal1 * splat_weights.y - + normal2 * splat_weights.z; - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - //ALBEDO = vec3(splat_weight0, splat_weight1, splat_weight2); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/godot/addons/zylann.hterrain/shaders/array.gdshader.uid b/godot/addons/zylann.hterrain/shaders/array.gdshader.uid deleted file mode 100644 index c9fc484..0000000 --- a/godot/addons/zylann.hterrain/shaders/array.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://6vtipymy0i25 diff --git a/godot/addons/zylann.hterrain/shaders/array_global.gdshader b/godot/addons/zylann.hterrain/shaders/array_global.gdshader deleted file mode 100644 index 2c737f1..0000000 --- a/godot/addons/zylann.hterrain/shaders/array_global.gdshader +++ /dev/null @@ -1,87 +0,0 @@ -// This shader is used to bake the global albedo map. -// It exposes a subset of the main shader API, so uniform names were not modified. - -shader_type spatial; - -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splat_index_map; -uniform sampler2D u_terrain_splat_weight_map; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -// TODO Have UV scales for each texture in an array? -uniform float u_ground_uv_scale; -// Keep depth blending because it has a high effect on the final result -uniform bool u_depth_blending = true; - - -vec3 get_depth_blended_weights(vec3 splat, vec3 bumps) { - float dh = 0.2; - - vec3 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec3 d = h + dh; - d.r -= max(h.g, h.b); - d.g -= max(h.r, h.b); - d.b -= max(h.g, h.r); - - vec3 w = clamp(d, 0, 1); - // Had to normalize, since this approach does not preserve components summing to 1 - return w / (w.x + w.y + w.z); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = (cell_coords / vec2(textureSize(u_terrain_splat_index_map, 0))); -} - -void fragment() { - vec4 tint = texture(u_terrain_colormap, UV); - vec4 tex_splat_indexes = texture(u_terrain_splat_index_map, UV); - vec4 tex_splat_weights = texture(u_terrain_splat_weight_map, UV); - // TODO Can't use texelFetch! - // https://github.com/godotengine/godot/issues/31732 - - vec3 splat_indexes = tex_splat_indexes.rgb * 255.0; - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.x)).a; - float b1 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.y)).a; - float b2 = texture(u_ground_albedo_bump_array, vec3(ground_uv, splat_indexes.z)).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 a0 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.x), 10.0).rgb; - vec3 a1 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.y), 10.0).rgb; - vec3 a2 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, splat_indexes.z), 10.0).rgb; - - vec3 splat_weights = vec3( - tex_splat_weights.r, - tex_splat_weights.g, - 1.0 - tex_splat_weights.r - tex_splat_weights.g - ); - - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - splat_weights = get_depth_blended_weights(splat_weights, vec3(b0, b1, b2)); - } - - ALBEDO = tint.rgb * ( - a0 * splat_weights.x - + a1 * splat_weights.y - + a2 * splat_weights.z - ); -} diff --git a/godot/addons/zylann.hterrain/shaders/array_global.gdshader.uid b/godot/addons/zylann.hterrain/shaders/array_global.gdshader.uid deleted file mode 100644 index 291a50a..0000000 --- a/godot/addons/zylann.hterrain/shaders/array_global.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ct011aka1fqcl diff --git a/godot/addons/zylann.hterrain/shaders/detail.gdshader b/godot/addons/zylann.hterrain/shaders/detail.gdshader deleted file mode 100644 index f148d67..0000000 --- a/godot/addons/zylann.hterrain/shaders/detail.gdshader +++ /dev/null @@ -1,116 +0,0 @@ -shader_type spatial; -render_mode cull_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_detailmap; -uniform sampler2D u_terrain_normalmap; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -// We need to disable repetition, otherwise it can cause "lines" to appear on top of grass quads -// due to filtering, especially when MSAA is enabled -uniform sampler2D u_albedo_alpha : source_color, repeat_disable; - -uniform float u_view_distance = 100.0; -uniform float u_globalmap_tint_bottom : hint_range(0.0, 1.0); -uniform float u_globalmap_tint_top : hint_range(0.0, 1.0); -uniform float u_bottom_ao : hint_range(0.0, 1.0); -uniform vec2 u_ambient_wind; // x: amplitude, y: time -uniform vec3 u_instance_scale = vec3(1.0, 1.0, 1.0); -uniform float u_roughness = 0.9; - -varying vec3 v_normal; -varying vec2 v_map_uv; - -float get_hash(vec2 c) { - return fract(sin(dot(c.xy, vec2(12.9898,78.233))) * 43758.5453); -} - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - n.z *= -1.0; - return n; -} - -vec3 get_ambient_wind_displacement(vec2 uv, float hash) { - // TODO This is an initial basic implementation. It may be improved in the future, especially for strong wind. - float t = u_ambient_wind.y; - float amp = u_ambient_wind.x * (1.0 - uv.y); - // Main displacement - vec3 disp = amp * vec3(cos(t), 0, sin(t * 1.2)); - // Fine displacement - float fine_disp_frequency = 2.0; - disp += 0.2 * amp * vec3(cos(t * (fine_disp_frequency + hash)), 0, sin(t * (fine_disp_frequency + hash) * 1.2)); - return disp; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void vertex() { - vec4 obj_pos = MODEL_MATRIX * vec4(0, 1, 0, 1); - vec3 cell_coords = (u_terrain_inverse_transform * obj_pos).xyz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords.xz += vec2(0.5); - - vec2 map_uv = cell_coords.xz / vec2(textureSize(u_terrain_heightmap, 0)); - v_map_uv = map_uv; - - //float density = 0.5 + 0.5 * sin(4.0*TIME); // test - float density = 0.0; - // Force density to be 0 outside of bounds. This can be necessary when terrain is scaled, - // as detail chunks will keep their size and may partially overlap outside bounds at the edges - // of the terrain. - if (map_uv.x >= 0.0 && map_uv.y >= 0.0 && map_uv.x < 1.0 && map_uv.y < 1.0) { - density = texture(u_terrain_detailmap, map_uv).r; - } - float hash = get_hash(obj_pos.xz); - - if (density > hash) { - vec3 normal = normalize( - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, map_uv))); - - // Snap model to the terrain - float height = get_height(u_terrain_heightmap, map_uv) / cell_coords.y; - VERTEX *= u_instance_scale; - VERTEX.y += height; - - VERTEX += get_ambient_wind_displacement(UV, hash); - - // Fade alpha with distance - vec3 wpos = (MODEL_MATRIX * vec4(VERTEX, 1)).xyz; - float dr = distance(wpos, CAMERA_POSITION_WORLD) / u_view_distance; - COLOR.a = clamp(1.0 - dr * dr * dr, 0.0, 1.0); - - // When using billboards, - // the normal is the same as the terrain regardless of face orientation - v_normal = normal; - - } else { - // Discard, output degenerate triangles - VERTEX = vec3(0, 0, 0); - } -} - -void fragment() { - NORMAL = (VIEW_MATRIX * (MODEL_MATRIX * vec4(v_normal, 0.0))).xyz; - ALPHA_SCISSOR_THRESHOLD = 0.5; - ROUGHNESS = u_roughness; - - vec4 col = texture(u_albedo_alpha, UV); - ALPHA = col.a * COLOR.a;// - clamp(1.4 - UV.y, 0.0, 1.0);//* 0.5 + 0.5*cos(2.0*TIME); - - ALBEDO = COLOR.rgb * col.rgb; - - // Blend with ground color - float nh = sqrt(max(1.0 - UV.y, 0.0)); - ALBEDO = mix(ALBEDO, texture(u_terrain_globalmap, v_map_uv).rgb, mix(u_globalmap_tint_bottom, u_globalmap_tint_top, nh)); - - // Fake bottom AO - ALBEDO = ALBEDO * mix(1.0, 1.0 - u_bottom_ao, UV.y * UV.y); -} diff --git a/godot/addons/zylann.hterrain/shaders/detail.gdshader.uid b/godot/addons/zylann.hterrain/shaders/detail.gdshader.uid deleted file mode 100644 index 0fd2538..0000000 --- a/godot/addons/zylann.hterrain/shaders/detail.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dq756fsiq30qf diff --git a/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc b/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc deleted file mode 100644 index c023e52..0000000 --- a/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc +++ /dev/null @@ -1,66 +0,0 @@ - -// Use functions from this file everywhere a heightmap is used, -// so it is easy to track and change the format - -float sample_heightmap(sampler2D spl, vec2 pos) { - // RF - return texture(spl, pos).r; -} - -vec4 encode_height_to_viewport(float h) { - //return vec4(encode_height_to_rgb8_unorm(h), 1.0); - - // Encode regular floats into an assumed RGBA8 output color. - // This is used because Godot 4.0 doesn't support RF viewports, - // and the irony is, even if float viewports get supported, it's likely it will end up RGBAF, - // which is wasting bandwidth because we are only interested in R... - uint u = floatBitsToUint(h); - return vec4( - float((u >> 0u) & 255u), - float((u >> 8u) & 255u), - float((u >> 16u) & 255u), - float((u >> 24u) & 255u) - ) / vec4(255.0); -} - -float decode_height_from_viewport(vec4 c) { - uint u = uint(c.r * 255.0) - | (uint(c.g * 255.0) << 8u) - | (uint(c.b * 255.0) << 16u) - | (uint(c.a * 255.0) << 24u); - return uintBitsToFloat(u); -} - -float sample_height_from_viewport(sampler2D screen, vec2 uv) { - ivec2 ts = textureSize(screen, 0); - vec2 norm_to_px = vec2(ts); - - // Convert to pixels and apply a small offset so we interpolate from pixel centers - vec2 uv_px_f = uv * norm_to_px - vec2(0.5); - - ivec2 uv_px = ivec2(uv_px_f); - - // Get interpolation pixel positions - ivec2 p00 = uv_px; - ivec2 p10 = uv_px + ivec2(1, 0); - ivec2 p01 = uv_px + ivec2(0, 1); - ivec2 p11 = uv_px + ivec2(1, 1); - - // Get pixels - vec4 c00 = texelFetch(screen, p00, 0); - vec4 c10 = texelFetch(screen, p10, 0); - vec4 c01 = texelFetch(screen, p01, 0); - vec4 c11 = texelFetch(screen, p11, 0); - - // Decode heights - float h00 = decode_height_from_viewport(c00); - float h10 = decode_height_from_viewport(c10); - float h01 = decode_height_from_viewport(c01); - float h11 = decode_height_from_viewport(c11); - - // Linear filter - vec2 f = fract(uv_px_f); - float h = mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y); - - return h; -} diff --git a/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc.uid b/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc.uid deleted file mode 100644 index 261a104..0000000 --- a/godot/addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://3ciacq3mppl diff --git a/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc b/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc deleted file mode 100644 index bb30ebe..0000000 --- a/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc +++ /dev/null @@ -1,57 +0,0 @@ - -const float V2_UNIT_STEPS = 1024.0; -const float V2_MIN = -8192.0; -const float V2_MAX = 8191.0; -const float V2_DF = 255.0 / V2_UNIT_STEPS; - -float decode_height_from_rgb8_unorm_2(vec3 c) { - return (c.r * 0.25 + c.g * 64.0 + c.b * 16384.0) * (4.0 * V2_DF) + V2_MIN; -} - -vec3 encode_height_to_rgb8_unorm_2(float h) { - // TODO Check if this has float precision issues - // TODO Modulo operator might be a performance/compatibility issue - h -= V2_MIN; - int i = int(h * V2_UNIT_STEPS); - int r = i % 256; - int g = (i / 256) % 256; - int b = i / 65536; - return vec3(float(r), float(g), float(b)) / 255.0; -} - -float decode_height_from_rgb8_unorm(vec3 c) { - return decode_height_from_rgb8_unorm_2(c); -} - -vec3 encode_height_to_rgb8_unorm(float h) { - return encode_height_to_rgb8_unorm_2(h); -} - -// TODO Remove for now? -// Bilinear filtering appears to work well enough without doing this. -// There are some artifacts, but we could easily live with them, -// and I suspect they could be easy to patch somehow in the encoding/decoding. -// -// In case bilinear filtering is required. -// This is slower than if we had a native float format. -// Unfortunately, Godot 4 removed support for 2D HDR viewports. They were used -// to edit this format natively. Using compute shaders would force users to -// have Vulkan. So we had to downgrade performance a bit using a technique from the GLES2 era... -float sample_height_bilinear_rgb8_unorm(sampler2D heightmap, vec2 uv) { - vec2 ts = vec2(textureSize(heightmap, 0)); - vec2 p00f = uv * ts; - ivec2 p00 = ivec2(p00f); - - vec3 s00 = texelFetch(heightmap, p00, 0).rgb; - vec3 s10 = texelFetch(heightmap, p00 + ivec2(1, 0), 0).rgb; - vec3 s01 = texelFetch(heightmap, p00 + ivec2(0, 1), 0).rgb; - vec3 s11 = texelFetch(heightmap, p00 + ivec2(1, 1), 0).rgb; - - float h00 = decode_height_from_rgb8_unorm(s00); - float h10 = decode_height_from_rgb8_unorm(s10); - float h01 = decode_height_from_rgb8_unorm(s01); - float h11 = decode_height_from_rgb8_unorm(s11); - - vec2 f = p00f - vec2(p00); - return mix(mix(h00, h10, f.x), mix(h01, h11, f.x), f.y); -} diff --git a/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc.uid b/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc.uid deleted file mode 100644 index f9b46ca..0000000 --- a/godot/addons/zylann.hterrain/shaders/include/heightmap_rgb8_encoding.gdshaderinc.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bb67gkibbu4ri diff --git a/godot/addons/zylann.hterrain/shaders/lookdev.gdshader b/godot/addons/zylann.hterrain/shaders/lookdev.gdshader deleted file mode 100644 index 0945419..0000000 --- a/godot/addons/zylann.hterrain/shaders/lookdev.gdshader +++ /dev/null @@ -1,71 +0,0 @@ -shader_type spatial; - -// Development shader used to debug or help authoring. - -#include "include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_map; // This map will control color -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -varying float v_hole; - - -vec3 unpack_normal(vec4 rgba) { - // If we consider texture space starts from top-left corner and Y goes down, - // then Y+ in pixel space corresponds to Z+ in terrain space, - // while X+ also corresponds to X+ in terrain space. - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - vec4 value = texture(u_map, UV); - // TODO Blend toward checker pattern to show the alpha channel - - ALBEDO = value.rgb; - ROUGHNESS = 0.5; - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; -} diff --git a/godot/addons/zylann.hterrain/shaders/lookdev.gdshader.uid b/godot/addons/zylann.hterrain/shaders/lookdev.gdshader.uid deleted file mode 100644 index 0cf9a53..0000000 --- a/godot/addons/zylann.hterrain/shaders/lookdev.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://r2rbuxl40oj4 diff --git a/godot/addons/zylann.hterrain/shaders/low_poly.gdshader b/godot/addons/zylann.hterrain/shaders/low_poly.gdshader deleted file mode 100644 index ef824d7..0000000 --- a/godot/addons/zylann.hterrain/shaders/low_poly.gdshader +++ /dev/null @@ -1,65 +0,0 @@ -shader_type spatial; - -// This is a very simple shader for a low-poly coloured visual, without textures - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform float u_specular = 0.5; - -varying flat vec4 v_tint; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - v_tint = texture(u_terrain_colormap, UV); - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { - if (v_tint.a < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - ALBEDO = v_tint.rgb; - ROUGHNESS = 1.0; - NORMAL = normalize(cross(dFdy(VERTEX), dFdx(VERTEX))); - SPECULAR = u_specular; -} diff --git a/godot/addons/zylann.hterrain/shaders/low_poly.gdshader.uid b/godot/addons/zylann.hterrain/shaders/low_poly.gdshader.uid deleted file mode 100644 index 3337eda..0000000 --- a/godot/addons/zylann.hterrain/shaders/low_poly.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b1dq12xpegaen diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader b/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader deleted file mode 100644 index 66aaecf..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader +++ /dev/null @@ -1,391 +0,0 @@ -shader_type spatial; - -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -// TODO Figure out why sampling colormap or splatmap in vertex shader leads to artifacts. -// At extremely shallow angles (such as horizon), some pixels start to flash. -// It appears to be caused by interpolation between the vertex and fragment shaders, leading to -// color values going largely outside of 0..1. -// See https://github.com/Zylann/godot_heightmap_plugin/issues/469 -//#define COLORMAP_PER_VERTEX - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; -uniform sampler2DArray u_ground_normal_roughness_array; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; -uniform bool u_tile_reduction = false; -uniform float u_specular = 0.5; - -#ifdef COLORMAP_PER_VERTEX -varying float v_hole; -varying vec3 v_tint; -#endif -varying vec2 v_terrain_uv; -varying vec3 v_ground_uv; -varying float v_distance_to_camera; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -vec3 unpack_normal(vec4 rgba) { - // If we consider texture space starts from top-left corner and Y goes down, - // then Y+ in pixel space corresponds to Z+ in terrain space, - // while X+ also corresponds to X+ in terrain space. - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec4 pack_normal(vec3 n, float a) { - n.z *= -1.0; - return vec4((n.xzy + vec3(1.0)) * 0.5, a); -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a_bump + (1.0 - t), b_bump + t) - d; - float ba = max(a_bump + (1.0 - t) - ma, 0.0); - float bb = max(b_bump + t - ma, 0.0); - return (a_value * ba + b_value * bb) / (ba + bb); -} - -vec2 rotate(vec2 v, float cosa, float sina) { - return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); -} - -vec4 texture_array_antitile(sampler2DArray albedo_tex, sampler2DArray normal_tex, vec3 uv, - out vec4 out_normal) { - - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec3 uv2 = vec3(rotate(uv.xy, cosa, sina) * scale, uv.z); - - vec4 col0 = texture(albedo_tex, uv); - vec4 col1 = texture(albedo_tex, uv2); - vec4 nrm0 = texture(normal_tex, uv); - vec4 nrm1 = texture(normal_tex, uv2); - //col0 = vec4(0.0, 0.5, 0.5, 1.0); // Highlights variations - - // Normals have to be rotated too since we are rotating the texture... - // TODO Probably not the most efficient but understandable for now - vec3 n = unpack_normal(nrm1); - // Had to negate the Y axis for some reason. I never remember the myriad of conventions around - n.xz = rotate(n.xz, cosa, -sina); - nrm1 = pack_normal(n, nrm1.a); - - // Periodically alternate between the two versions using a warped checker pattern - float t = 1.1 + 0.5 - * sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); // Result in [0..2] - t = smoothstep(sharpness, 2.0 - sharpness, t); - - // Using depth blend because classic alpha blending smoothes out details. - out_normal = depth_blend2(nrm0, col0.a, nrm1, col1.a, t); - return depth_blend2(col0, col0.a, col1, col1.a, t); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv / u_ground_uv_scale; - -#ifdef COLORMAP_PER_VERTEX - // Putting this in vertex saves a fetch from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate it, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; -#endif - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { -#ifndef COLORMAP_PER_VERTEX - vec4 tint = texture(u_terrain_colormap, UV); - float v_hole = tint.a; - vec3 v_tint = tint.rgb; -#endif - - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * (unpack_normal(texture(u_terrain_normalmap, UV))); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - vec4 ab0, ab1, ab2, ab3; - vec4 nr0, nr1, nr2, nr3; - - if (u_tile_reduction) { - ab0 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.x), nr0); - ab1 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.y), nr1); - ab2 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.z), nr2); - ab3 = texture_array_antitile( - u_ground_albedo_bump_array, u_ground_normal_roughness_array, - vec3(v_ground_uv.xz, high_indices.w), nr3); - - } else { - ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.x)); - ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.y)); - ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.z)); - ab3 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.w)); - - nr0 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.x)); - nr1 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.y)); - nr2 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.z)); - nr3 = texture(u_ground_normal_roughness_array, vec3(v_ground_uv.xz, high_indices.w)); - } - - vec3 col0 = ab0.rgb * v_tint; - vec3 col1 = ab1.rgb * v_tint; - vec3 col2 = ab2.rgb * v_tint; - vec3 col3 = ab3.rgb * v_tint; - - vec4 rough = vec4(nr0.a, nr1.a, nr2.a, nr3.a); - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - vec3 normal3 = unpack_normal(nr3); - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = ( - w.r * rough.r + - w.g * rough.g + - w.b * rough.b + - w.a * rough.a) / w_sum; - - vec3 ground_normal = /*u_terrain_normal_basis **/ ( - w.r * normal0 + - w.g * normal1 + - w.b * normal2 + - w.a * normal3) / w_sum; - // If no splat textures are defined, normal vectors will default to (1,1,1), - // which is incorrect, and causes the terrain to be shaded wrongly in some directions. - // However, this should not be a problem to fix in the shader, - // because there MUST be at least one splat texture set. - //ground_normal = normalize(ground_normal); - // TODO Make the plugin insert a default normalmap if it's empty - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - -// if(count < 3) { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; - SPECULAR = u_specular; -} diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader.uid b/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader.uid deleted file mode 100644 index 2f4756d..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bjfd7mwktvebi diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader b/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader deleted file mode 100644 index 96964b7..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader +++ /dev/null @@ -1,173 +0,0 @@ -shader_type spatial; - -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_splatmap, 0)); -} - -void fragment() { - // These were moved from vertex to fragment, - // so we can generate part of the global map with just one quad and we get full quality - vec3 tint = texture(u_terrain_colormap, UV).rgb; - vec4 splat = texture(u_terrain_splatmap, UV); - - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.x)).a; - float b1 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.y)).a; - float b2 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.z)).a; - float b3 = texture(u_ground_albedo_bump_array, vec3(ground_uv, high_indices.w)).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 a0 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.x), 10.0).rgb; - vec3 a1 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.y), 10.0).rgb; - vec3 a2 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.z), 10.0).rgb; - vec3 a3 = textureLod(u_ground_albedo_bump_array, vec3(ndc_center, high_indices.w), 10.0).rgb; - - vec3 col0 = a0 * tint; - vec3 col1 = a1 * tint; - vec3 col2 = a2 * tint; - vec3 col3 = a3 * tint; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(b0, b1, b2, b3)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; -} diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader.uid b/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader.uid deleted file mode 100644 index e76a9ff..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16_global.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dani0mjpea5ii diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader b/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader deleted file mode 100644 index 32306ea..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader +++ /dev/null @@ -1,271 +0,0 @@ -shader_type spatial; - -// This shader uses a texture array with multiple splatmaps, allowing up to 16 textures. -// Only the 4 textures having highest blending weight are sampled. - -// TODO Figure out why sampling colormap or splatmap in vertex shader leads to artifacts. -// At extremely shallow angles (such as horizon), some pixels start to flash. -// It appears to be caused by interpolation between the vertex and fragment shaders, leading to -// color values going largely outside of 0..1. -// See https://github.com/Zylann/godot_heightmap_plugin/issues/469 -//#define COLORMAP_PER_VERTEX - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove source_color` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_splatmap_1; -uniform sampler2D u_terrain_splatmap_2; -uniform sampler2D u_terrain_splatmap_3; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2DArray u_ground_albedo_bump_array : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; -uniform float u_specular = 0.5; - -#ifdef COLORMAP_PER_VERTEX -varying float v_hole; -varying vec3 v_tint; -#endif -varying vec2 v_terrain_uv; -varying vec3 v_ground_uv; -varying float v_distance_to_camera; - -// TODO Can't put this in a constant: https://github.com/godotengine/godot/issues/44145 -//const int TEXTURE_COUNT = 16; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -void get_splat_weights(vec2 uv, out vec4 out_high_indices, out vec4 out_high_weights) { - vec4 ew0 = texture(u_terrain_splatmap, uv); - vec4 ew1 = texture(u_terrain_splatmap_1, uv); - vec4 ew2 = texture(u_terrain_splatmap_2, uv); - vec4 ew3 = texture(u_terrain_splatmap_3, uv); - - float weights[16] = { - ew0.r, ew0.g, ew0.b, ew0.a, - ew1.r, ew1.g, ew1.b, ew1.a, - ew2.r, ew2.g, ew2.b, ew2.a, - ew3.r, ew3.g, ew3.b, ew3.a - }; - -// float weights_sum = 0.0; -// for (int i = 0; i < 16; ++i) { -// weights_sum += weights[i]; -// } -// for (int i = 0; i < 16; ++i) { -// weights_sum /= weights_sum; -// } -// weights_sum=1.1; - - // Now we have to pick the 4 highest weights and use them to blend textures. - - // Using arrays because Godot's shader version doesn't support dynamic indexing of vectors - // TODO We should not need to initialize, but apparently we don't always find 4 weights - int high_indices_array[4] = {0, 0, 0, 0}; - float high_weights_array[4] = {0.0, 0.0, 0.0, 0.0}; - int count = 0; - // We know weights are supposed to be normalized. - // That means the highest value of the pivot above which we can find 4 results - // is 1.0 / 4.0. However that would mean exactly 4 textures have exactly that weight, - // which is very unlikely. If we consider 1.0 / 5.0, we are a bit more likely to find - // 4 results, and finding 5 results remains almost impossible. - float pivot = /*weights_sum*/1.0 / 5.0; - - for (int i = 0; i < 16; ++i) { - if (weights[i] > pivot) { - high_weights_array[count] = weights[i]; - high_indices_array[count] = i; - weights[i] = 0.0; - ++count; - } - } - - while (count < 4 && pivot > 0.0) { - float max_weight = 0.0; - int max_index = 0; - - for (int i = 0; i < 16; ++i) { - if (/*weights[i] <= pivot && */weights[i] > max_weight) { - max_weight = weights[i]; - max_index = i; - weights[i] = 0.0; - } - } - - high_indices_array[count] = max_index; - high_weights_array[count] = max_weight; - ++count; - pivot = max_weight; - } - - out_high_weights = vec4( - high_weights_array[0], high_weights_array[1], - high_weights_array[2], high_weights_array[3]); - - out_high_indices = vec4( - float(high_indices_array[0]), float(high_indices_array[1]), - float(high_indices_array[2]), float(high_indices_array[3])); - - out_high_weights /= - out_high_weights.r + out_high_weights.g + out_high_weights.b + out_high_weights.a; -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv = base_ground_uv / u_ground_uv_scale; - -#ifdef COLORMAP_PER_VERTEX - // Putting this in vertex saves a fetch from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate it, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint = tint.rgb; -#endif - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { -#ifndef COLORMAP_PER_VERTEX - vec4 tint = texture(u_terrain_colormap, UV); - float v_hole = tint.a; - vec3 v_tint = tint.rgb; -#endif - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 high_indices; - vec4 high_weights; - get_splat_weights(UV, high_indices, high_weights); - - vec4 ab0 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.x)); - vec4 ab1 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.y)); - vec4 ab2 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.z)); - vec4 ab3 = texture(u_ground_albedo_bump_array, vec3(v_ground_uv.xz, high_indices.w)); - - vec3 col0 = ab0.rgb * v_tint; - vec3 col1 = ab1.rgb * v_tint; - vec3 col2 = ab2.rgb * v_tint; - vec3 col3 = ab3.rgb * v_tint; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(high_weights, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = high_weights; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - -// if(count < 3) { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(terrain_normal_world, 0.0))).xyz; - SPECULAR = u_specular; -} diff --git a/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader.uid b/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader.uid deleted file mode 100644 index a6560f4..0000000 --- a/godot/addons/zylann.hterrain/shaders/multisplat16_lite.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://vv8o0jpa5s17 diff --git a/godot/addons/zylann.hterrain/shaders/simple4.gdshader b/godot/addons/zylann.hterrain/shaders/simple4.gdshader deleted file mode 100644 index ef326df..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4.gdshader +++ /dev/null @@ -1,361 +0,0 @@ -shader_type spatial; - -// This is the reference shader of the plugin, and has the most features. -// it should be preferred for high-end graphics cards. -// For less features but lower-end targets, see the lite version. - -// TODO Figure out why sampling colormap or splatmap in vertex shader leads to artifacts. -// At extremely shallow angles (such as horizon), some pixels start to flash. -// It appears to be caused by interpolation between the vertex and fragment shaders, leading to -// color values going largely outside of 0..1. -// See https://github.com/Zylann/godot_heightmap_plugin/issues/469 -//#define COLORMAP_PER_VERTEX -//#define SPLATMAP_PER_VERTEX - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap; -uniform sampler2D u_terrain_splatmap; -uniform sampler2D u_terrain_globalmap : source_color; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -// the reason bump is preferred with albedo is, roughness looks better with normal maps. -// If we want no normal mapping, roughness would only give flat mirror surfaces, -// while bump still allows to do depth-blending for free. -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -uniform sampler2D u_ground_normal_roughness_0; -uniform sampler2D u_ground_normal_roughness_1; -uniform sampler2D u_ground_normal_roughness_2; -uniform sampler2D u_ground_normal_roughness_3; - -// Had to give this uniform a suffix, because it's declared as a simple float -// in other shaders, and its type cannot be inferred by the plugin. -// See https://github.com/godotengine/godot/issues/24488 -uniform vec4 u_ground_uv_scale_per_texture = vec4(20.0, 20.0, 20.0, 20.0); - -uniform bool u_depth_blending = true; -uniform bool u_triplanar = false; -// Each component corresponds to a ground texture. Set greater than zero to enable. -uniform vec4 u_tile_reduction = vec4(0.0, 0.0, 0.0, 0.0); - -uniform float u_globalmap_blend_start; -uniform float u_globalmap_blend_distance; - -uniform vec4 u_colormap_opacity_per_texture = vec4(1.0, 1.0, 1.0, 1.0); - -uniform float u_specular = 0.5; - -#ifdef COLORMAP_PER_VERTEX -varying float v_hole; -varying vec3 v_tint0; -varying vec3 v_tint1; -varying vec3 v_tint2; -varying vec3 v_tint3; -#endif -#ifdef SPLATMAP_PER_VERTEX -varying vec4 v_splat; -#endif -varying vec2 v_ground_uv0; -varying vec2 v_ground_uv1; -varying vec2 v_ground_uv2; -varying vec3 v_ground_uv3; -varying float v_distance_to_camera; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec4 pack_normal(vec3 n, float a) { - n.z *= -1.0; - return vec4((n.xzy + vec3(1.0)) * 0.5, a); -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -vec4 depth_blend2(vec4 a_value, float a_bump, vec4 b_value, float b_bump, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a_bump + (1.0 - t), b_bump + t) - d; - float ba = max(a_bump + (1.0 - t) - ma, 0.0); - float bb = max(b_bump + t - ma, 0.0); - return (a_value * ba + b_value * bb) / (ba + bb); -} - -vec2 rotate(vec2 v, float cosa, float sina) { - return vec2(cosa * v.x - sina * v.y, sina * v.x + cosa * v.y); -} - -vec4 texture_antitile(sampler2D albedo_tex, sampler2D normal_tex, vec2 uv, out vec4 out_normal) { - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec2 uv2 = rotate(uv, cosa, sina) * scale; - - vec4 col0 = texture(albedo_tex, uv); - vec4 col1 = texture(albedo_tex, uv2); - vec4 nrm0 = texture(normal_tex, uv); - vec4 nrm1 = texture(normal_tex, uv2); - //col0 = vec4(0.0, 0.5, 0.5, 1.0); // Highlights variations - - // Normals have to be rotated too since we are rotating the texture... - // TODO Probably not the most efficient but understandable for now - vec3 n = unpack_normal(nrm1); - // Had to negate the Y axis for some reason. I never remember the myriad of conventions around - n.xz = rotate(n.xz, cosa, -sina); - nrm1 = pack_normal(n, nrm1.a); - - // Periodically alternate between the two versions using a warped checker pattern - float t = 1.2 + - sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); // Result in [0..2] - t = smoothstep(sharpness, 2.0 - sharpness, t); - - // Using depth blend because classic alpha blending smoothes out details. - out_normal = depth_blend2(nrm0, col0.a, nrm1, col1.a, t); - return depth_blend2(col0, col0.a, col1, col1.a, t); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = (u_terrain_inverse_transform * wpos).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - wpos.y = h; - - vec3 base_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y); - v_ground_uv0 = base_ground_uv.xz / u_ground_uv_scale_per_texture.x; - v_ground_uv1 = base_ground_uv.xz / u_ground_uv_scale_per_texture.y; - v_ground_uv2 = base_ground_uv.xz / u_ground_uv_scale_per_texture.z; - v_ground_uv3 = base_ground_uv / u_ground_uv_scale_per_texture.w; - -#ifdef COLORMAP_PER_VERTEX - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - vec4 tint = texture(u_terrain_colormap, UV); - v_hole = tint.a; - v_tint0 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.x); - v_tint1 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.y); - v_tint2 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.z); - v_tint3 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.w); -#endif -#ifdef SPLATMAP_PER_VERTEX - v_splat = texture(u_terrain_splatmap, UV); -#endif - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - - v_distance_to_camera = distance(wpos.xyz, CAMERA_POSITION_WORLD); -} - -void fragment() { -#ifndef COLORMAP_PER_VERTEX - vec4 tint = texture(u_terrain_colormap, UV); - float v_hole = tint.a; - vec3 v_tint0 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.x); - vec3 v_tint1 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.y); - vec3 v_tint2 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.z); - vec3 v_tint3 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.w); -#endif - - if (v_hole < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - -#ifndef SPLATMAP_PER_VERTEX - vec4 v_splat = texture(u_terrain_splatmap, UV); -#endif - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - vec3 normal = terrain_normal_world; - - float globalmap_factor = clamp((v_distance_to_camera - u_globalmap_blend_start) - * u_globalmap_blend_distance, 0.0, 1.0); - globalmap_factor *= globalmap_factor; // slower start, faster transition but far away - vec3 global_albedo = texture(u_terrain_globalmap, UV).rgb; - ALBEDO = global_albedo; - - // Doing this branch allows to spare a bunch of texture fetches for distant pixels. - // Eventually, there could be a split between near and far shaders in the future, - // if relevant on high-end GPUs - if (globalmap_factor < 1.0) { - vec4 ab0, ab1, ab2, ab3; - vec4 nr0, nr1, nr2, nr3; - - if (u_triplanar) { - // Only do triplanar on one texture slot, - // because otherwise it would be very expensive and cost many more ifs. - // I chose the last slot because first slot is the default on new splatmaps, - // and that's a feature used for cliffs, which are usually designed later. - - vec3 blending = get_triplanar_blend(terrain_normal_world); - - ab3 = texture_triplanar(u_ground_albedo_bump_3, v_ground_uv3, blending); - nr3 = texture_triplanar(u_ground_normal_roughness_3, v_ground_uv3, blending); - - } else { - if (u_tile_reduction[3] > 0.0) { - ab3 = texture_antitile( - u_ground_albedo_bump_3, u_ground_normal_roughness_3, v_ground_uv3.xz, nr3); - } else { - ab3 = texture(u_ground_albedo_bump_3, v_ground_uv3.xz); - nr3 = texture(u_ground_normal_roughness_3, v_ground_uv3.xz); - } - } - - if (u_tile_reduction[0] > 0.0) { - ab0 = texture_antitile( - u_ground_albedo_bump_0, u_ground_normal_roughness_0, v_ground_uv0, nr0); - } else { - ab0 = texture(u_ground_albedo_bump_0, v_ground_uv0); - nr0 = texture(u_ground_normal_roughness_0, v_ground_uv0); - } - if (u_tile_reduction[1] > 0.0) { - ab1 = texture_antitile( - u_ground_albedo_bump_1, u_ground_normal_roughness_1, v_ground_uv1, nr1); - } else { - ab1 = texture(u_ground_albedo_bump_1, v_ground_uv1); - nr1 = texture(u_ground_normal_roughness_1, v_ground_uv1); - } - if (u_tile_reduction[2] > 0.0) { - ab2 = texture_antitile( - u_ground_albedo_bump_2, u_ground_normal_roughness_2, v_ground_uv2, nr2); - } else { - ab2 = texture(u_ground_albedo_bump_2, v_ground_uv2); - nr2 = texture(u_ground_normal_roughness_2, v_ground_uv2); - } - - vec3 col0 = ab0.rgb * v_tint0; - vec3 col1 = ab1.rgb * v_tint1; - vec3 col2 = ab2.rgb * v_tint2; - vec3 col3 = ab3.rgb * v_tint3; - - vec4 rough = vec4(nr0.a, nr1.a, nr2.a, nr3.a); - - vec3 normal0 = unpack_normal(nr0); - vec3 normal1 = unpack_normal(nr1); - vec3 normal2 = unpack_normal(nr2); - vec3 normal3 = unpack_normal(nr3); - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(v_splat, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = v_splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = ( - w.r * rough.r + - w.g * rough.g + - w.b * rough.b + - w.a * rough.a) / w_sum; - - vec3 ground_normal = /*u_terrain_normal_basis **/ ( - w.r * normal0 + - w.g * normal1 + - w.b * normal2 + - w.a * normal3) / w_sum; - // If no splat textures are defined, normal vectors will default to (1,1,1), - // which is incorrect, and causes the terrain to be shaded wrongly in some directions. - // However, this should not be a problem to fix in the shader, - // because there MUST be at least one splat texture set. - //ground_normal = normalize(ground_normal); - // TODO Make the plugin insert a default normalmap if it's empty - - // Combine terrain normals with detail normals (not sure if correct but looks ok) - normal = normalize(vec3( - terrain_normal_world.x + ground_normal.x, - terrain_normal_world.y, - terrain_normal_world.z + ground_normal.z)); - - normal = mix(normal, terrain_normal_world, globalmap_factor); - - ALBEDO = mix(ALBEDO, global_albedo, globalmap_factor); - ROUGHNESS = mix(ROUGHNESS, 1.0, globalmap_factor); - - // Show splatmap weights - //ALBEDO = w.rgb; - } - // Highlight all pixels undergoing no splatmap at all -// else { -// ALBEDO = vec3(1.0, 0.0, 0.0); -// } - - NORMAL = (VIEW_MATRIX * (vec4(normal, 0.0))).xyz; - SPECULAR = u_specular; -} diff --git a/godot/addons/zylann.hterrain/shaders/simple4.gdshader.uid b/godot/addons/zylann.hterrain/shaders/simple4.gdshader.uid deleted file mode 100644 index de1cde1..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://divt160ypdqmv diff --git a/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader b/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader deleted file mode 100644 index db3dcdd..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader +++ /dev/null @@ -1,82 +0,0 @@ -shader_type spatial; - -// This shader is used to bake the global albedo map. -// It exposes a subset of the main shader API, so uniform names were not modified. - -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform sampler2D u_terrain_splatmap; - -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -// Keep depth blending because it has a high effect on the final result -uniform bool u_depth_blending = true; -uniform float u_ground_uv_scale = 20.0; - - -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -void vertex() { - vec4 wpos = MODEL_MATRIX * vec4(VERTEX, 1); - vec2 cell_coords = wpos.xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - // Normalized UV - UV = (cell_coords / vec2(textureSize(u_terrain_splatmap, 0))); -} - -void fragment() { - // These were moved from vertex to fragment, - // so we can generate part of the global map with just one quad and we get full quality - vec4 tint = texture(u_terrain_colormap, UV); - vec4 splat = texture(u_terrain_splatmap, UV); - - // Get bump at normal resolution so depth blending is accurate - vec2 ground_uv = UV / u_ground_uv_scale; - float b0 = texture(u_ground_albedo_bump_0, ground_uv).a; - float b1 = texture(u_ground_albedo_bump_1, ground_uv).a; - float b2 = texture(u_ground_albedo_bump_2, ground_uv).a; - float b3 = texture(u_ground_albedo_bump_3, ground_uv).a; - - // Take the center of the highest mip as color, because we can't see details from far away. - vec2 ndc_center = vec2(0.5, 0.5); - vec3 col0 = textureLod(u_ground_albedo_bump_0, ndc_center, 10.0).rgb; - vec3 col1 = textureLod(u_ground_albedo_bump_1, ndc_center, 10.0).rgb; - vec3 col2 = textureLod(u_ground_albedo_bump_2, ndc_center, 10.0).rgb; - vec3 col3 = textureLod(u_ground_albedo_bump_3, ndc_center, 10.0).rgb; - - vec4 w; - if (u_depth_blending) { - w = get_depth_blended_weights(splat, vec4(b0, b1, b2, b3)); - } else { - w = splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = tint.rgb * ( - w.r * col0 + - w.g * col1 + - w.b * col2 + - w.a * col3) / w_sum; -} diff --git a/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader.uid b/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader.uid deleted file mode 100644 index 00905d3..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4_global.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bvj2mowr5i6id diff --git a/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader b/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader deleted file mode 100644 index 893a5c5..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader +++ /dev/null @@ -1,236 +0,0 @@ -shader_type spatial; - -// This is a shader with less textures, in case the main one doesn't run on your GPU. -// It's mostly a big copy/paste, because Godot doesn't support #include or #ifdef... - -// TODO Figure out why sampling colormap or splatmap in vertex shader leads to artifacts. -// At extremely shallow angles (such as horizon), some pixels start to flash. -// It appears to be caused by interpolation between the vertex and fragment shaders, leading to -// color values going largely outside of 0..1. -// See https://github.com/Zylann/godot_heightmap_plugin/issues/469 -//#define COLORMAP_PER_VERTEX -//#define SPLATMAP_PER_VERTEX - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform sampler2D u_terrain_normalmap; -// I had to remove `hint_albedo` from colormap in Godot 3 because it makes sRGB conversion kick in, -// which snowballs to black when doing GPU painting on that texture... -uniform sampler2D u_terrain_colormap;// : hint_albedo; -uniform sampler2D u_terrain_splatmap; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; - -uniform sampler2D u_ground_albedo_bump_0 : source_color; -uniform sampler2D u_ground_albedo_bump_1 : source_color; -uniform sampler2D u_ground_albedo_bump_2 : source_color; -uniform sampler2D u_ground_albedo_bump_3 : source_color; - -uniform float u_ground_uv_scale = 20.0; -uniform bool u_depth_blending = true; -uniform bool u_triplanar = false; -// Each component corresponds to a ground texture. Set greater than zero to enable. -uniform vec4 u_tile_reduction = vec4(0.0, 0.0, 0.0, 0.0); -uniform float u_specular = 0.5; - -#ifdef COLORMAP_PER_VERTEX -varying vec4 v_tint; -#endif -#ifdef SPLATMAP_PER_VERTEX -varying vec4 v_splat; -#endif -varying vec3 v_ground_uv; - - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -// Blends weights according to the bump of detail textures, -// so for example it allows to have sand fill the gaps between pebbles -vec4 get_depth_blended_weights(vec4 splat, vec4 bumps) { - float dh = 0.2; - - vec4 h = bumps + splat; - - // TODO Keep improving multilayer blending, there are still some edge cases... - // Mitigation: nullify layers with near-zero splat - h *= smoothstep(0, 0.05, splat); - - vec4 d = h + dh; - d.r -= max(h.g, max(h.b, h.a)); - d.g -= max(h.r, max(h.b, h.a)); - d.b -= max(h.g, max(h.r, h.a)); - d.a -= max(h.g, max(h.b, h.r)); - - return clamp(d, 0, 1); -} - -vec3 get_triplanar_blend(vec3 world_normal) { - vec3 blending = abs(world_normal); - blending = normalize(max(blending, vec3(0.00001))); // Force weights to sum to 1.0 - float b = blending.x + blending.y + blending.z; - return blending / vec3(b, b, b); -} - -vec4 texture_triplanar(sampler2D tex, vec3 world_pos, vec3 blend) { - vec4 xaxis = texture(tex, world_pos.yz); - vec4 yaxis = texture(tex, world_pos.xz); - vec4 zaxis = texture(tex, world_pos.xy); - // blend the results of the 3 planar projections. - return xaxis * blend.x + yaxis * blend.y + zaxis * blend.z; -} - -vec4 depth_blend2(vec4 a, vec4 b, float t) { - // https://www.gamasutra.com - // /blogs/AndreyMishkinis/20130716/196339/Advanced_Terrain_Texture_Splatting.php - float d = 0.1; - float ma = max(a.a + (1.0 - t), b.a + t) - d; - float ba = max(a.a + (1.0 - t) - ma, 0.0); - float bb = max(b.a + t - ma, 0.0); - return (a * ba + b * bb) / (ba + bb); -} - -vec4 texture_antitile(sampler2D tex, vec2 uv) { - float frequency = 2.0; - float scale = 1.3; - float sharpness = 0.7; - - // Rotate and scale UV - float rot = 3.14 * 0.6; - float cosa = cos(rot); - float sina = sin(rot); - vec2 uv2 = vec2(cosa * uv.x - sina * uv.y, sina * uv.x + cosa * uv.y) * scale; - - vec4 col0 = texture(tex, uv); - vec4 col1 = texture(tex, uv2); - //col0 = vec4(0.0, 0.0, 1.0, 1.0); - // Periodically alternate between the two versions using a warped checker pattern - float t = 0.5 + 0.5 - * sin(uv2.x * frequency + sin(uv.x) * 2.0) - * cos(uv2.y * frequency + sin(uv.y) * 2.0); - // Using depth blend because classic alpha blending smoothes out details - return depth_blend2(col0, col1, smoothstep(0.5 * sharpness, 1.0 - 0.5 * sharpness, t)); -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results. - cell_coords += vec2(0.5); - - // Normalized UV - UV = cell_coords / vec2(textureSize(u_terrain_heightmap, 0)); - - // Height displacement - float h = sample_heightmap(u_terrain_heightmap, UV); - VERTEX.y = h; - - v_ground_uv = vec3(cell_coords.x, h * MODEL_MATRIX[1][1], cell_coords.y) / u_ground_uv_scale; - -#ifdef COLORMAP_PER_VERTEX - // Putting this in vertex saves 2 fetches from the fragment shader, - // which is good for performance at a negligible quality cost, - // provided that geometry is a regular grid that decimates with LOD. - // (downside is LOD will also decimate tint and splat, but it's not bad overall) - v_tint = texture(u_terrain_colormap, UV); -#endif -#ifdef SPLATMAP_PER_VERTEX - v_splat = texture(u_terrain_splatmap, UV); -#endif - - // Need to use u_terrain_normal_basis to handle scaling. - NORMAL = u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); -} - -void fragment() { -#ifndef COLORMAP_PER_VERTEX - vec4 v_tint = texture(u_terrain_colormap, UV); -#endif - - if (v_tint.a < 0.5) { - // TODO Add option to use vertex discarding instead, using NaNs - discard; - } - -#ifndef SPLATMAP_PER_VERTEX - vec4 v_splat = texture(u_terrain_splatmap, UV); -#endif - - vec3 terrain_normal_world = - u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, UV)); - terrain_normal_world = normalize(terrain_normal_world); - - // TODO Detail should only be rasterized on nearby chunks (needs proximity management to switch shaders) - - vec2 ground_uv = v_ground_uv.xz; - - vec4 ab0, ab1, ab2, ab3; - if (u_triplanar) { - // Only do triplanar on one texture slot, - // because otherwise it would be very expensive and cost many more ifs. - // I chose the last slot because first slot is the default on new splatmaps, - // and that's a feature used for cliffs, which are usually designed later. - - vec3 blending = get_triplanar_blend(terrain_normal_world); - - ab3 = texture_triplanar(u_ground_albedo_bump_3, v_ground_uv, blending); - - } else { - if (u_tile_reduction[3] > 0.0) { - ab3 = texture(u_ground_albedo_bump_3, ground_uv); - } else { - ab3 = texture_antitile(u_ground_albedo_bump_3, ground_uv); - } - } - - if (u_tile_reduction[0] > 0.0) { - ab0 = texture_antitile(u_ground_albedo_bump_0, ground_uv); - } else { - ab0 = texture(u_ground_albedo_bump_0, ground_uv); - } - if (u_tile_reduction[1] > 0.0) { - ab1 = texture_antitile(u_ground_albedo_bump_1, ground_uv); - } else { - ab1 = texture(u_ground_albedo_bump_1, ground_uv); - } - if (u_tile_reduction[2] > 0.0) { - ab2 = texture_antitile(u_ground_albedo_bump_2, ground_uv); - } else { - ab2 = texture(u_ground_albedo_bump_2, ground_uv); - } - - vec3 col0 = ab0.rgb; - vec3 col1 = ab1.rgb; - vec3 col2 = ab2.rgb; - vec3 col3 = ab3.rgb; - - vec4 w; - // TODO An #ifdef macro would be nice! Or copy/paste everything in a different shader... - if (u_depth_blending) { - w = get_depth_blended_weights(v_splat, vec4(ab0.a, ab1.a, ab2.a, ab3.a)); - } else { - w = v_splat.rgba; - } - - float w_sum = (w.r + w.g + w.b + w.a); - - ALBEDO = v_tint.rgb * ( - w.r * col0.rgb + - w.g * col1.rgb + - w.b * col2.rgb + - w.a * col3.rgb) / w_sum; - - ROUGHNESS = 1.0; - - NORMAL = (VIEW_MATRIX * (vec4(terrain_normal_world, 0.0))).xyz; - SPECULAR = u_specular; - - //ALBEDO = w.rgb; - //ALBEDO = v_ground_uv.xyz; -} diff --git a/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader.uid b/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader.uid deleted file mode 100644 index 49eefb6..0000000 --- a/godot/addons/zylann.hterrain/shaders/simple4_lite.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ci2beywfvyen0 diff --git a/godot/addons/zylann.hterrain/tools/about/about_dialog.gd b/godot/addons/zylann.hterrain/tools/about/about_dialog.gd deleted file mode 100644 index 20ec8f8..0000000 --- a/godot/addons/zylann.hterrain/tools/about/about_dialog.gd +++ /dev/null @@ -1,28 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_Errors = preload("../../util/errors.gd") - -const PLUGIN_CFG_PATH = "res://addons/zylann.hterrain/plugin.cfg" - - -@onready var _about_rich_text_label : RichTextLabel = $VB/HB2/TC/About - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - var plugin_cfg = ConfigFile.new() - var err := plugin_cfg.load(PLUGIN_CFG_PATH) - if err != OK: - _logger.error("Could not load {0}: {1}" \ - .format([PLUGIN_CFG_PATH, HT_Errors.get_message(err)])) - return - var version = plugin_cfg.get_value("plugin", "version", "--.--.--") - - _about_rich_text_label.text = _about_rich_text_label.text.format({"version": version}) diff --git a/godot/addons/zylann.hterrain/tools/about/about_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/about/about_dialog.gd.uid deleted file mode 100644 index 39b4233..0000000 --- a/godot/addons/zylann.hterrain/tools/about/about_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dglux3u0y5f5t diff --git a/godot/addons/zylann.hterrain/tools/about/about_dialog.tscn b/godot/addons/zylann.hterrain/tools/about/about_dialog.tscn deleted file mode 100644 index efeda7a..0000000 --- a/godot/addons/zylann.hterrain/tools/about/about_dialog.tscn +++ /dev/null @@ -1,85 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://cvuubd08805oa"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/about/about_dialog.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://sdaddk8wxjin" path="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd" id="3"] - -[node name="AboutDialog" type="AcceptDialog"] -size = Vector2i(516, 357) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -custom_minimum_size = Vector2(500, 300) -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -49.0 - -[node name="HB2" type="HBoxContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="TextureRect" type="TextureRect" parent="VB/HB2"] -layout_mode = 2 -texture = ExtResource("2") -stretch_mode = 2 - -[node name="TC" type="TabContainer" parent="VB/HB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="About" type="RichTextLabel" parent="VB/HB2/TC"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -bbcode_enabled = true -text = "Version: {version} -Author: Marc Gilleron -Repository: https://github.com/Zylann/godot_heightmap_plugin -Issue tracker: https://github.com/Zylann/godot_heightmap_plugin/issues - -Gold supporters: - -Aaron Franke (aaronfranke) - -Silver supporters: - -TheConceptBoy -Chris Bolton (yochrisbolton) -Gamerfiend (Snowminx) -greenlion (Justin Swanhart) -segfault-god (jp.owo.Manda) -RonanZe -Phyronnaz -NoFr1ends (Lynx) - -Bronze supporters: - -rcorre (Ryan Roden-Corrent) -duchainer (Raphaël Duchaîne) -MadMartian -stackdump (stackdump.eth) -Treer -MrGreaterThan -lenis0012 -" -script = ExtResource("3") - -[node name="License" type="RichTextLabel" parent="VB/HB2/TC"] -visible = false -layout_mode = 2 -text = "Copyright (c) 2016-2023 Marc Gilleron - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -" - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 diff --git a/godot/addons/zylann.hterrain/tools/brush/brush.gd b/godot/addons/zylann.hterrain/tools/brush/brush.gd deleted file mode 100644 index dd23e21..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush.gd +++ /dev/null @@ -1,224 +0,0 @@ -@tool - -# Brush properties (shape, transform, timing and opacity). -# Other attributes like color, height or texture index are tool-specific, -# while brush properties apply to all of them. -# This is separate from Painter because it could apply to multiple Painters at once. - -const HT_Errors = preload("../../util/errors.gd") -const HT_Painter = preload("./painter.gd") - -const SHAPES_DIR = "addons/zylann.hterrain/tools/brush/shapes" -const DEFAULT_BRUSH_TEXTURE_PATH = SHAPES_DIR + "/round2.exr" - -# Reasonable size for sliders to be usable -const MIN_SIZE_FOR_SLIDERS = 2 -const MAX_SIZE_FOR_SLIDERS = 500 -const MIN_OPACITY_FOR_SLIDERS = 0 -const MAX_OPACITY_FOR_SLIDERS = 100 -# Absolute size limit. Terrains can't be larger than that, and it will be very slow to paint -const MAX_SIZE = 4000 - -signal size_changed(new_size) -signal opacity_changed(new_opacity) -signal shapes_changed -signal shape_index_changed - -var _size := 32 -var _opacity := 1.0 -var _random_rotation := false -var _pressure_enabled := false -var _pressure_over_scale := 0.5 -var _pressure_over_opacity := 0.5 -# TODO Rename stamp_*? -var _frequency_distance := 0.0 -var _frequency_time_ms := 0 -# Array of greyscale textures -var _shapes : Array[Texture2D] = [] - -var _shape_index := 0 -var _shape_cycling_enabled := false -var _prev_position := Vector2(-999, -999) -var _prev_time_ms := 0 - - -func set_size(size: int): - if size < 1: - size = 1 - if size != _size: - _size = size - size_changed.emit(_size) - - -func get_size() -> int: - return _size - - -func set_opacity(opacity: float): - var new_opacity := clampf(opacity, 0.0, 1.0) - - if new_opacity != _opacity: - _opacity = new_opacity - opacity_changed.emit(_opacity) - - -func get_opacity() -> float: - return _opacity - - -func set_random_rotation_enabled(enabled: bool): - _random_rotation = enabled - - -func is_random_rotation_enabled() -> bool: - return _random_rotation - - -func set_pressure_enabled(enabled: bool): - _pressure_enabled = enabled - - -func is_pressure_enabled() -> bool: - return _pressure_enabled - - -func set_pressure_over_scale(amount: float): - _pressure_over_scale = clampf(amount, 0.0, 1.0) - - -func get_pressure_over_scale() -> float: - return _pressure_over_scale - - -func set_pressure_over_opacity(amount: float): - _pressure_over_opacity = clampf(amount, 0.0, 1.0) - - -func get_pressure_over_opacity() -> float: - return _pressure_over_opacity - - -func set_frequency_distance(d: float): - _frequency_distance = maxf(d, 0.0) - - -func get_frequency_distance() -> float: - return _frequency_distance - - -func set_frequency_time_ms(t: int): - if t < 0: - t = 0 - _frequency_time_ms = t - - -func get_frequency_time_ms() -> int: - return _frequency_time_ms - - -func set_shapes(shapes: Array[Texture2D]): - assert(len(shapes) >= 1) - for s in shapes: - assert(s != null) - assert(s is Texture2D) - _shapes = shapes.duplicate(false) - if _shape_index >= len(_shapes): - _shape_index = len(_shapes) - 1 - shapes_changed.emit() - - -func get_shapes() -> Array[Texture2D]: - return _shapes.duplicate(false) - - -func get_shape(i: int) -> Texture2D: - return _shapes[i] - - -func get_shape_index() -> int: - return _shape_index - - -func set_shape_index(i: int): - assert(i >= 0) - assert(i < len(_shapes)) - _shape_index = i - shape_index_changed.emit() - - -func set_shape_cycling_enabled(enable: bool): - _shape_cycling_enabled = enable - - -func is_shape_cycling_enabled() -> bool: - return _shape_cycling_enabled - - -static func load_shape_from_image_file(fpath: String, logger, retries := 1) -> Texture2D: - var im := Image.new() - var err := im.load(ProjectSettings.globalize_path(fpath)) - if err != OK: - if retries > 0: - # TODO There is a bug with Godot randomly being unable to load images. - # See https://github.com/Zylann/godot_heightmap_plugin/issues/219 - # Attempting to workaround this by retrying (I suspect it's because of non-initialized - # variable in Godot's C++ code...) - logger.error("Could not load image at '{0}', error {1}. Retrying..." \ - .format([fpath, HT_Errors.get_message(err)])) - return load_shape_from_image_file(fpath, logger, retries - 1) - else: - logger.error("Could not load image at '{0}', error {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return null - var tex := ImageTexture.create_from_image(im) - return tex - - -# Call this while handling mouse or pen input. -# If it returns false, painting should not run. -func configure_paint_input(painters: Array[HT_Painter], position: Vector2, pressure: float) -> bool: - assert(len(_shapes) != 0) - - # DEBUG - #pressure = 0.5 + 0.5 * sin(OS.get_ticks_msec() / 200.0) - - if position.distance_to(_prev_position) < _frequency_distance: - return false - var now := Time.get_ticks_msec() - if (now - _prev_time_ms) < _frequency_time_ms: - return false - _prev_position = position - _prev_time_ms = now - - for painter_index in len(painters): - var painter : HT_Painter = painters[painter_index] - - if _random_rotation: - painter.set_brush_rotation(randf_range(-PI, PI)) - else: - painter.set_brush_rotation(0.0) - - painter.set_brush_texture(_shapes[_shape_index]) - painter.set_brush_size(_size) - - if _pressure_enabled: - painter.set_brush_scale(lerpf(1.0, pressure, _pressure_over_scale)) - painter.set_brush_opacity(_opacity * lerpf(1.0, pressure, _pressure_over_opacity)) - else: - painter.set_brush_scale(1.0) - painter.set_brush_opacity(_opacity) - - #painter.paint_input(position) - - if _shape_cycling_enabled: - _shape_index += 1 - if _shape_index >= len(_shapes): - _shape_index = 0 - - return true - - -# Call this when the user releases the pen or mouse button -func on_paint_end(): - _prev_position = Vector2(-999, -999) - _prev_time_ms = 0 diff --git a/godot/addons/zylann.hterrain/tools/brush/brush.gd.uid b/godot/addons/zylann.hterrain/tools/brush/brush.gd.uid deleted file mode 100644 index 086d7d3..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b6x1t1di1t7s0 diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd b/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd deleted file mode 100644 index 2a06a87..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd +++ /dev/null @@ -1,259 +0,0 @@ -@tool -extends Control - -const HT_TerrainPainter = preload("./terrain_painter.gd") -const HT_Brush = preload("./brush.gd") -const HT_Errors = preload("../../util/errors.gd") -#const NativeFactory = preload("../../native/factory.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_IntervalSlider = preload("../util/interval_slider.gd") - -const HT_BrushSettingsDialogScene = preload("./settings_dialog/brush_settings_dialog.tscn") -const HT_BrushSettingsDialog = preload("./settings_dialog/brush_settings_dialog.gd") - - -@onready var _size_slider : Slider = $GridContainer/BrushSizeControl/Slider -@onready var _size_spin_box : SpinBox = $GridContainer/BrushSizeControl/SpinBox -#onready var _size_label = _params_container.get_node("BrushSizeLabel") - -@onready var _opacity_slider : Slider = $GridContainer/BrushOpacityControl/Slider -@onready var _opacity_control : Control = $GridContainer/BrushOpacityControl -@onready var _opacity_spin_box : SpinBox = $GridContainer/BrushOpacityControl/SpinBox -@onready var _opacity_label : Label = $GridContainer/BrushOpacityLabel - -@onready var _flatten_height_container : Control = $GridContainer/HB -@onready var _flatten_height_box : SpinBox = $GridContainer/HB/FlattenHeightControl -@onready var _flatten_height_label : Label = $GridContainer/FlattenHeightLabel -@onready var _flatten_height_pick_button : Button = $GridContainer/HB/FlattenHeightPickButton - -@onready var _color_picker : ColorPickerButton = $GridContainer/ColorPickerButton -@onready var _color_label : Label = $GridContainer/ColorLabel - -@onready var _density_slider : Slider = $GridContainer/DensitySlider -@onready var _density_label : Label = $GridContainer/DensityLabel - -@onready var _holes_label : Label = $GridContainer/HoleLabel -@onready var _holes_checkbox : CheckBox = $GridContainer/HoleCheckbox - -@onready var _slope_limit_label : Label = $GridContainer/SlopeLimitLabel -@onready var _slope_limit_control : HT_IntervalSlider = $GridContainer/SlopeLimit - -@onready var _shape_texture_rect : TextureRect = get_node("BrushShapeButton/TextureRect") - -var _terrain_painter : HT_TerrainPainter -var _brush_settings_dialog : HT_BrushSettingsDialog = null -var _logger = HT_Logger.get_for(self) - -# TODO This is an ugly workaround for https://github.com/godotengine/godot/issues/19479 -@onready var _temp_node = get_node("Temp") -@onready var _grid_container = get_node("GridContainer") -func _set_visibility_of(node: Control, v: bool): - node.get_parent().remove_child(node) - if v: - _grid_container.add_child(node) - else: - _temp_node.add_child(node) - node.visible = v - - -func _ready(): - _size_slider.value_changed.connect(_on_size_slider_value_changed) - _size_slider.share(_size_spin_box) - _opacity_slider.value_changed.connect(_on_opacity_slider_value_changed) - _opacity_slider.share(_opacity_spin_box) - _flatten_height_box.value_changed.connect(_on_flatten_height_box_value_changed) - _color_picker.color_changed.connect(_on_color_picker_color_changed) - _density_slider.value_changed.connect(_on_density_slider_changed) - _holes_checkbox.toggled.connect(_on_holes_checkbox_toggled) - _slope_limit_control.changed.connect(_on_slope_limit_changed) - - _size_slider.max_value = HT_Brush.MAX_SIZE_FOR_SLIDERS - _size_slider.min_value = HT_Brush.MIN_SIZE_FOR_SLIDERS - _opacity_slider.max_value = HT_Brush.MAX_OPACITY_FOR_SLIDERS - _opacity_slider.min_value = HT_Brush.MIN_OPACITY_FOR_SLIDERS - #if NativeFactory.is_native_available(): - # _size_slider.max_value = 200 - #else: - # _size_slider.max_value = 50 - - -func setup_dialogs(base_control: Node): - assert(_brush_settings_dialog == null) - _brush_settings_dialog = HT_BrushSettingsDialogScene.instantiate() - base_control.add_child(_brush_settings_dialog) - - # That dialog has sub-dialogs - _brush_settings_dialog.setup_dialogs(base_control) - _brush_settings_dialog.set_brush(_terrain_painter.get_brush()) - - -func _exit_tree(): - if _brush_settings_dialog != null: - _brush_settings_dialog.queue_free() - _brush_settings_dialog = null - -# Testing display modes -#var mode = 0 -#func _input(event): -# if event is InputEventKey: -# if event.pressed: -# set_display_mode(mode) -# mode += 1 -# if mode >= Brush.MODE_COUNT: -# mode = 0 - -func set_terrain_painter(terrain_painter: HT_TerrainPainter): - if _terrain_painter != null: - _terrain_painter.flatten_height_changed.disconnect(_on_flatten_height_changed) - _terrain_painter.get_brush().shapes_changed.disconnect(_on_brush_shapes_changed) - _terrain_painter.get_brush().shape_index_changed.disconnect(_on_brush_shape_index_changed) - _terrain_painter.get_brush().size_changed.disconnect(_on_brush_size_changed) - _terrain_painter.get_brush().opacity_changed.disconnect(_on_brush_opacity_changed) - - _terrain_painter = terrain_painter - - if _terrain_painter != null: - # TODO Had an issue in Godot 3.2.3 where mismatching type would silently cast to null... - # It happens if the argument went through a Variant (for example if call_deferred is used) - assert(_terrain_painter != null) - - if _terrain_painter != null: - # Initial brush params - _size_slider.value = _terrain_painter.get_brush().get_size() - _opacity_slider.ratio = _terrain_painter.get_brush().get_opacity() - # Initial specific params - _flatten_height_box.value = _terrain_painter.get_flatten_height() - _color_picker.get_picker().color = _terrain_painter.get_color() - _density_slider.value = _terrain_painter.get_detail_density() - _holes_checkbox.button_pressed = not _terrain_painter.get_mask_flag() - - var low := rad_to_deg(_terrain_painter.get_slope_limit_low_angle()) - var high := rad_to_deg(_terrain_painter.get_slope_limit_high_angle()) - _slope_limit_control.set_values(low, high) - - set_display_mode(_terrain_painter.get_mode()) - - # Load default brush - var brush := _terrain_painter.get_brush() - var default_shape_fpath := HT_Brush.DEFAULT_BRUSH_TEXTURE_PATH - var default_shape := HT_Brush.load_shape_from_image_file(default_shape_fpath, _logger) - brush.set_shapes([default_shape]) - _update_shape_preview() - - _terrain_painter.flatten_height_changed.connect(_on_flatten_height_changed) - brush.shapes_changed.connect(_on_brush_shapes_changed) - brush.shape_index_changed.connect(_on_brush_shape_index_changed) - brush.size_changed.connect(_on_brush_size_changed) - brush.opacity_changed.connect(_on_brush_opacity_changed) - - -func _on_flatten_height_changed(): - _flatten_height_box.value = _terrain_painter.get_flatten_height() - _flatten_height_pick_button.button_pressed = false - - -func _on_brush_shapes_changed(): - _update_shape_preview() - - -func _on_brush_size_changed(new_size): - _update_brush_size(new_size) - - -func _on_brush_opacity_changed(new_opacity): - _update_brush_opacity(new_opacity) - - -func _on_brush_shape_index_changed(): - _update_shape_preview() - - -func _update_shape_preview(): - var brush := _terrain_painter.get_brush() - var i := brush.get_shape_index() - _shape_texture_rect.texture = brush.get_shape(i) - - -func _update_brush_size(new_size): - if _terrain_painter != null: - _size_slider.set_value_no_signal(new_size) - - -func _update_brush_opacity(new_opacity): - if _terrain_painter != null: - _opacity_slider.set_value_no_signal(new_opacity * _opacity_slider.max_value) - - -func set_display_mode(mode: int): - var show_flatten := mode == HT_TerrainPainter.MODE_FLATTEN - var show_color := mode == HT_TerrainPainter.MODE_COLOR - var show_density := mode == HT_TerrainPainter.MODE_DETAIL - var show_opacity := mode != HT_TerrainPainter.MODE_MASK - var show_holes := mode == HT_TerrainPainter.MODE_MASK - var show_slope_limit := \ - mode == HT_TerrainPainter.MODE_SPLAT or mode == HT_TerrainPainter.MODE_DETAIL - - _set_visibility_of(_opacity_label, show_opacity) - _set_visibility_of(_opacity_control, show_opacity) - - _set_visibility_of(_color_label, show_color) - _set_visibility_of(_color_picker, show_color) - - _set_visibility_of(_flatten_height_label, show_flatten) - _set_visibility_of(_flatten_height_container, show_flatten) - - _set_visibility_of(_density_label, show_density) - _set_visibility_of(_density_slider, show_density) - - _set_visibility_of(_holes_label, show_holes) - _set_visibility_of(_holes_checkbox, show_holes) - - _set_visibility_of(_slope_limit_label, show_slope_limit) - _set_visibility_of(_slope_limit_control, show_slope_limit) - - _flatten_height_pick_button.button_pressed = false - - -func _on_size_slider_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_brush_size(int(v)) - - -func _on_opacity_slider_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_opacity(_opacity_slider.ratio) - - -func _on_flatten_height_box_value_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_flatten_height(v) - - -func _on_color_picker_color_changed(v: Color): - if _terrain_painter != null: - _terrain_painter.set_color(v) - - -func _on_density_slider_changed(v: float): - if _terrain_painter != null: - _terrain_painter.set_detail_density(v) - - -func _on_holes_checkbox_toggled(v: bool): - if _terrain_painter != null: - # When checked, we draw holes. When unchecked, we clear holes - _terrain_painter.set_mask_flag(not v) - - -func _on_BrushShapeButton_pressed(): - _brush_settings_dialog.popup_centered() - - -func _on_FlattenHeightPickButton_pressed(): - _terrain_painter.set_meta("pick_height", true) - - -func _on_slope_limit_changed(): - var low = deg_to_rad(_slope_limit_control.get_low_value()) - var high = deg_to_rad(_slope_limit_control.get_high_value()) - _terrain_painter.set_slope_limit_angles(low, high) diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd.uid b/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd.uid deleted file mode 100644 index cd31241..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dxk7y0ndb1i6v diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor.tscn b/godot/addons/zylann.hterrain/tools/brush/brush_editor.tscn deleted file mode 100644 index 584ac3f..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor.tscn +++ /dev/null @@ -1,132 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://bd42ig216p216"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/brush_editor.gd" id="1"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/util/interval_slider.gd" id="3"] - -[sub_resource type="CanvasItemMaterial" id="1"] -blend_mode = 1 - -[node name="BrushEditor" type="HBoxContainer"] -custom_minimum_size = Vector2(200, 0) -offset_right = 293.0 -offset_bottom = 211.0 -script = ExtResource("1") - -[node name="BrushShapeButton" type="Button" parent="."] -custom_minimum_size = Vector2(50, 0) -layout_mode = 2 - -[node name="TextureRect" type="TextureRect" parent="BrushShapeButton"] -material = SubResource("1") -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 -expand_mode = 1 -stretch_mode = 5 - -[node name="GridContainer" type="GridContainer" parent="."] -layout_mode = 2 -size_flags_horizontal = 3 -columns = 2 - -[node name="BrushSizeLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Brush size" - -[node name="BrushSizeControl" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -mouse_filter = 0 - -[node name="Slider" type="HSlider" parent="GridContainer/BrushSizeControl"] -custom_minimum_size = Vector2(60, 0) -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 1 -min_value = 2.0 -max_value = 500.0 -value = 2.0 -exp_edit = true -rounded = true - -[node name="SpinBox" type="SpinBox" parent="GridContainer/BrushSizeControl"] -layout_mode = 2 -min_value = 2.0 -max_value = 500.0 -value = 2.0 - -[node name="BrushOpacityLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Brush opacity" - -[node name="BrushOpacityControl" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Slider" type="HSlider" parent="GridContainer/BrushOpacityControl"] -layout_mode = 2 -size_flags_horizontal = 3 -size_flags_vertical = 1 - -[node name="SpinBox" type="SpinBox" parent="GridContainer/BrushOpacityControl"] -layout_mode = 2 -value = 1.0 - -[node name="FlattenHeightLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Flatten height" - -[node name="HB" type="HBoxContainer" parent="GridContainer"] -layout_mode = 2 - -[node name="FlattenHeightControl" type="SpinBox" parent="GridContainer/HB"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = -500.0 -max_value = 500.0 -step = 0.01 - -[node name="FlattenHeightPickButton" type="Button" parent="GridContainer/HB"] -layout_mode = 2 -toggle_mode = true -text = "Pick" - -[node name="ColorLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Color" - -[node name="ColorPickerButton" type="ColorPickerButton" parent="GridContainer"] -layout_mode = 2 -toggle_mode = false -color = Color(1, 1, 1, 1) - -[node name="DensityLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Detail density" - -[node name="DensitySlider" type="HSlider" parent="GridContainer"] -layout_mode = 2 -max_value = 1.0 -step = 0.1 - -[node name="HoleLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Draw holes" - -[node name="HoleCheckbox" type="CheckBox" parent="GridContainer"] -layout_mode = 2 - -[node name="SlopeLimitLabel" type="Label" parent="GridContainer"] -layout_mode = 2 -text = "Slope limit" - -[node name="SlopeLimit" type="Control" parent="GridContainer"] -layout_mode = 2 -script = ExtResource("3") -range = Vector2(0, 90) - -[node name="Temp" type="Node" parent="."] - -[connection signal="pressed" from="BrushShapeButton" to="." method="_on_BrushShapeButton_pressed"] -[connection signal="pressed" from="GridContainer/HB/FlattenHeightPickButton" to="." method="_on_FlattenHeightPickButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd b/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd deleted file mode 100644 index 6838efa..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd +++ /dev/null @@ -1,99 +0,0 @@ -@tool -extends Control - -const MIN_UI_CIRCLE_SIZE = 40 -const MAX_UI_CIRCLE_SIZE = 500 - -@onready var _brush_size_background: TextureRect = %BrushSizeBackground -@onready var _brush_size_preview: TextureRect = %BrushSizePreview -@onready var _value_label: Label = %ValueLabel -@onready var _overlay_name_label: Label = %OverlayNameLabel -@onready var _exponential_slider: HSlider = %ExponentialSlider - -@export var brush_size_factor: float = 2.5 -@export var min_value: float = -1 -@export var max_value: float = -1 -var _brush_preview_color: Color = Color.LIGHT_GREEN -var _dpi_scale: float = 1.0 -var _value: float = 0.0 - -signal on_value_selected(new_value: int) -signal on_cancel - -var background_margin: int = 10 - - -func _physics_process(delta: float) -> void: - _update_size(_get_mouse_distance()) - - -func _input(event: InputEvent) -> void: - if event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: - on_value_selected.emit(_value) - else: - on_cancel.emit() - if event is InputEventKey: - if event.keycode == KEY_ESCAPE and event.pressed: - on_cancel.emit() - - -func set_brush_preview_color(brush_color: Color) -> void: - _brush_preview_color = brush_color - _update_brush_preview_color() - - -func _update_brush_preview_color() -> void: - _brush_size_preview.modulate = _brush_preview_color - - -func set_overlay_name(overlay_label_name: String) -> void: - _overlay_name_label.text = overlay_label_name - - -func _update_size(value: float) -> void: - var dist := clampi(value * brush_size_factor, MIN_UI_CIRCLE_SIZE*_dpi_scale, MAX_UI_CIRCLE_SIZE*_dpi_scale ) - var ui_size := clampi(dist, MIN_UI_CIRCLE_SIZE*_dpi_scale, MAX_UI_CIRCLE_SIZE*_dpi_scale) - _brush_size_background.size = Vector2(ui_size + background_margin, ui_size + background_margin) - _brush_size_background.position = Vector2(-( (ui_size/2) + (background_margin/2)) , -( (ui_size/2) + (background_margin/2))) - _brush_size_preview.size = Vector2(ui_size, ui_size) - _brush_size_preview.position = Vector2(-(ui_size/2) , -(ui_size/2)) - - _exponential_slider.min_value = MIN_UI_CIRCLE_SIZE*_dpi_scale - _exponential_slider.max_value = MAX_UI_CIRCLE_SIZE*_dpi_scale - _exponential_slider.value = (_exponential_slider.min_value+_exponential_slider.max_value)-ui_size - - var re_value: float = absf(1.0-_exponential_slider.get_as_ratio()) * (max_value-min_value) - re_value += min_value - - _value = roundi(re_value) - _value_label.text = str(_value) - - -func apply_dpi_scale(dpi_scale: float) -> void: - _dpi_scale = dpi_scale - - -func setup_start_position(start_pos: Vector2, initial_value: float) -> void: - position = start_pos - - _exponential_slider.min_value = MIN_UI_CIRCLE_SIZE*_dpi_scale - _exponential_slider.max_value = MAX_UI_CIRCLE_SIZE*_dpi_scale - - var reverse: float = (initial_value - min_value) / (max_value-min_value) - reverse = absf(1-reverse) - _exponential_slider.set_as_ratio(reverse) - - var ui_size: float = (_exponential_slider.min_value+_exponential_slider.max_value) - _exponential_slider.value - - position.x -= (ui_size/brush_size_factor) - - -func _get_mouse_distance() -> float: - var global_mouse_pos: Vector2 = get_global_mouse_position() - - var distance: float = position.distance_to(global_mouse_pos) - if position.x > global_mouse_pos.x: - distance = 0 - - return distance; diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd.uid b/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd.uid deleted file mode 100644 index 2f88de0..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://djxrmp1pkrvyy diff --git a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.tscn b/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.tscn deleted file mode 100644 index d75f6a8..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/brush_editor_overlay.tscn +++ /dev/null @@ -1,91 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://d324kwgdf7e6l"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/brush_editor_overlay.gd" id="1_grgos"] -[ext_resource type="Texture2D" uid="uid://fk2rcx7lsbam" path="res://addons/zylann.hterrain/tools/icons/brush_circle_background.svg" id="2_jeqe2"] -[ext_resource type="Texture2D" uid="uid://c4ma6f4217y48" path="res://addons/zylann.hterrain/tools/icons/brush_circle.svg" id="3_sw64o"] - -[sub_resource type="LabelSettings" id="LabelSettings_0d2ij"] -font_size = 32 - -[node name="BrushEditorOverlay" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_grgos") -min_value = 2.0 -max_value = 500.0 - -[node name="BrushSizeBackground" type="TextureRect" parent="."] -unique_name_in_owner = true -modulate = Color(0.478431, 0.478431, 0.478431, 0.423529) -layout_mode = 0 -offset_left = -209.0 -offset_top = -209.0 -offset_right = 210.0 -offset_bottom = 210.0 -texture = ExtResource("2_jeqe2") -expand_mode = 1 -metadata/_edit_use_anchors_ = true - -[node name="BrushSizePreview" type="TextureRect" parent="."] -unique_name_in_owner = true -modulate = Color(1, 0, 0, 1) -layout_mode = 1 -offset_left = -204.0 -offset_top = -204.0 -offset_right = 205.0 -offset_bottom = 205.0 -texture = ExtResource("3_sw64o") -expand_mode = 1 -metadata/_edit_use_anchors_ = true - -[node name="ValueLabel" type="Label" parent="."] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = -1 -anchor_top = 0.001 -anchor_bottom = 0.001 -offset_left = -35.0 -offset_top = -22.648 -offset_right = 38.0 -offset_bottom = 22.352 -grow_horizontal = 2 -grow_vertical = 2 -scale = Vector2(0.7, 0.7) -pivot_offset = Vector2(33, 22) -text = "266" -label_settings = SubResource("LabelSettings_0d2ij") -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="OverlayNameLabel" type="Label" parent="."] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = -1 -offset_left = -211.0 -offset_top = -62.0 -offset_right = 400.0 -offset_bottom = 19.0 -scale = Vector2(0.7, 0.7) -text = "Brush size" -label_settings = SubResource("LabelSettings_0d2ij") -horizontal_alignment = 1 -vertical_alignment = 1 - -[node name="ExponentialSlider" type="HSlider" parent="."] -unique_name_in_owner = true -visible = false -layout_mode = 0 -offset_left = -132.0 -offset_top = 50.0 -offset_right = 140.0 -offset_bottom = 66.0 -focus_mode = 0 -mouse_filter = 2 -min_value = 40.0 -max_value = 500.0 -value = 131.0 -exp_edit = true diff --git a/godot/addons/zylann.hterrain/tools/brush/decal.gd b/godot/addons/zylann.hterrain/tools/brush/decal.gd deleted file mode 100644 index 27203bd..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/decal.gd +++ /dev/null @@ -1,130 +0,0 @@ -@tool -# Shows a cursor on top of the terrain to preview where the brush will paint - -# TODO Use an actual decal node, it wasn't available in Godot 3 - -const HT_DirectMeshInstance = preload("../../util/direct_mesh_instance.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Util = preload("../../util/util.gd") - -var _mesh_instance : HT_DirectMeshInstance -var _mesh : PlaneMesh -var _material := ShaderMaterial.new() -#var _debug_mesh := BoxMesh.new() -#var _debug_mesh_instance : HT_DirectMeshInstance = null - -var _terrain : HTerrain = null - - -func _init(): - _material.shader = load("res://addons/zylann.hterrain/tools/brush/decal.gdshader") - _mesh_instance = HT_DirectMeshInstance.new() - _mesh_instance.set_material(_material) - - _mesh = PlaneMesh.new() - _mesh_instance.set_mesh(_mesh) - -# _debug_mesh_instance = HT_DirectMeshInstance.new() -# _debug_mesh_instance.set_mesh(_debug_mesh) - - -func set_size(size: float): - _mesh.size = Vector2(size, size) - # Must line up to terrain vertex policy, so must apply an off-by-one. - # If I don't do that, the brush will appear to wobble above the ground - var ss := size - 1 - - # Adding extra subdivisions, notably for small brush sizes - ss *= 4 - - # Don't subdivide too much - while ss > 50: - ss /= 2 - _mesh.subdivide_width = ss - _mesh.subdivide_depth = ss - - # Move decal closer to ground at small sizes, otherwise it looks off. - # At larger sizes it needs to be further away because of Z-fighting and LOD imprecision. - var distance := clampf(size / 50.0, 0.1, 1.0) - _material.set_shader_parameter(&"u_distance_from_ground", distance) - - -#func set_shape(shape_image): -# set_size(shape_image.get_width()) - - -func _on_terrain_transform_changed(terrain_global_trans: Transform3D): - var inv = terrain_global_trans.affine_inverse() - _material.set_shader_parameter("u_terrain_inverse_transform", inv) - - var normal_basis = terrain_global_trans.basis.inverse().transposed() - _material.set_shader_parameter("u_terrain_normal_basis", normal_basis) - - -func set_terrain(terrain: HTerrain): - if _terrain == terrain: - return - - if _terrain != null: - _terrain.transform_changed.disconnect(_on_terrain_transform_changed) - _mesh_instance.exit_world() -# _debug_mesh_instance.exit_world() - - _terrain = terrain - - if _terrain != null: - _terrain.transform_changed.connect(_on_terrain_transform_changed) - _on_terrain_transform_changed(_terrain.get_internal_transform()) - _mesh_instance.enter_world(terrain.get_world_3d()) -# _debug_mesh_instance.enter_world(terrain.get_world_3d()) - - update_visibility() - - -func set_position(p_local_pos: Vector3): - assert(_terrain != null) - assert(typeof(p_local_pos) == TYPE_VECTOR3) - - # Set custom AABB (in local cells) because the decal is displaced by shader - var data := _terrain.get_data() - if data != null: - var r := _mesh.size / 2 - var aabb := data.get_region_aabb( \ - int(p_local_pos.x - r.x), \ - int(p_local_pos.z - r.y), \ - int(2 * r.x), \ - int(2 * r.y)) - aabb.position = Vector3(-r.x, aabb.position.y, -r.y) - _mesh.custom_aabb = aabb - #_debug_mesh.size = aabb.size - - var trans := Transform3D(Basis(), p_local_pos) - var terrain_gt := _terrain.get_internal_transform() - trans = terrain_gt * trans - _mesh_instance.set_transform(trans) -# _debug_mesh_instance.set_transform(trans) - - -# This is called very often so it should be cheap -func update_visibility(): - var heightmap = _get_heightmap(_terrain) - if heightmap == null: - # I do this for refcounting because heightmaps are large resources - _material.set_shader_parameter("u_terrain_heightmap", null) - _mesh_instance.set_visible(false) -# _debug_mesh_instance.set_visible(false) - else: - _material.set_shader_parameter("u_terrain_heightmap", heightmap) - _mesh_instance.set_visible(true) -# _debug_mesh_instance.set_visible(true) - - -func _get_heightmap(terrain): - if terrain == null: - return null - var data = terrain.get_data() - if data == null: - return null - return data.get_texture(HTerrainData.CHANNEL_HEIGHT) - diff --git a/godot/addons/zylann.hterrain/tools/brush/decal.gd.uid b/godot/addons/zylann.hterrain/tools/brush/decal.gd.uid deleted file mode 100644 index 636027b..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/decal.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bppvcdiplaac1 diff --git a/godot/addons/zylann.hterrain/tools/brush/decal.gdshader b/godot/addons/zylann.hterrain/tools/brush/decal.gdshader deleted file mode 100644 index fc9a4ba..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/decal.gdshader +++ /dev/null @@ -1,49 +0,0 @@ -shader_type spatial; -render_mode unshaded;//, depth_test_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_terrain_heightmap; -uniform mat4 u_terrain_inverse_transform; -uniform mat3 u_terrain_normal_basis; -uniform float u_distance_from_ground = 0.1; - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void vertex() { - vec2 cell_coords = (u_terrain_inverse_transform * MODEL_MATRIX * vec4(VERTEX, 1)).xz; - - // Must add a half-offset so that we sample the center of pixels, - // otherwise bilinear filtering of the textures will give us mixed results (#183) - cell_coords += vec2(0.5); - - vec2 ps = vec2(1.0) / vec2(textureSize(u_terrain_heightmap, 0)); - vec2 uv = ps * cell_coords; - - // Get terrain normal - float k = 1.0; - float left = get_height(u_terrain_heightmap, uv + vec2(-ps.x, 0)) * k; - float right = get_height(u_terrain_heightmap, uv + vec2(ps.x, 0)) * k; - float back = get_height(u_terrain_heightmap, uv + vec2(0, -ps.y)) * k; - float fore = get_height(u_terrain_heightmap, uv + vec2(0, ps.y)) * k; - vec3 n = normalize(vec3(left - right, 2.0, back - fore)); - - n = u_terrain_normal_basis * n; - - float h = get_height(u_terrain_heightmap, uv); - VERTEX.y = h; - - // Offset the decal a little above terrain so it doesn't Z-fight with it - VERTEX += u_distance_from_ground * n; - - NORMAL = n;//vec3(0.0, 1.0, 0.0); -} - -void fragment() { - float len = length(2.0 * UV - 1.0); - float g = clamp(1.0 - 15.0 * abs(0.9 - len), 0.0, 1.0); - ALBEDO = vec3(1.0, 0.1, 0.1); - ALPHA = g; -} diff --git a/godot/addons/zylann.hterrain/tools/brush/decal.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/decal.gdshader.uid deleted file mode 100644 index 2465f3c..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/decal.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dq0ky7sr4w4v0 diff --git a/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader b/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader deleted file mode 100644 index 8ae0f84..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader +++ /dev/null @@ -1,6 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -void fragment() { - COLOR = texture(TEXTURE, UV); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader.uid deleted file mode 100644 index 71bc236..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/no_blend.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bqdbf2ltnqn6j diff --git a/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader b/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader deleted file mode 100644 index d0460de..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -void fragment() { - float h = sample_heightmap(TEXTURE, UV); - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader.uid deleted file mode 100644 index e5520ee..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/no_blend_rf.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://5pgruu6tpc2j diff --git a/godot/addons/zylann.hterrain/tools/brush/painter.gd b/godot/addons/zylann.hterrain/tools/brush/painter.gd deleted file mode 100644 index 6e9f7a6..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/painter.gd +++ /dev/null @@ -1,413 +0,0 @@ - -# Core logic to paint a texture using shaders, with undo/redo support. -# Operations are delayed so results are only available the next frame. -# This doesn't implement UI or brush behavior, only rendering logic. -# -# Note: due to the absence of channel separation function in Image, -# you may need to use multiple painters at once if your application exploits multiple channels. -# Example: when painting a heightmap, it would be doable to output height in R, normalmap in GB, and -# then separate channels in two images at the end. - -@tool -extends Node - -const HT_Logger = preload("../../util/logger.gd") -const HT_Util = preload("../../util/util.gd") -const HT_NoBlendShader = preload("./no_blend.gdshader") -const HT_NoBlendRFShader = preload("./no_blend_rf.gdshader") - -const UNDO_CHUNK_SIZE = 64 - -# All painting shaders can use these common parameters -const SHADER_PARAM_SRC_TEXTURE = "u_src_texture" -const SHADER_PARAM_SRC_RECT = "u_src_rect" -const SHADER_PARAM_OPACITY = "u_opacity" - -const _API_SHADER_PARAMS = [ - SHADER_PARAM_SRC_TEXTURE, - SHADER_PARAM_SRC_RECT, - SHADER_PARAM_OPACITY -] - -# Emitted when a region of the painted texture actually changed. -# Note 1: the image might not have changed yet at this point. -# Note 2: the user could still be in the middle of dragging the brush. -signal texture_region_changed(rect) - -# Godot doesn't support 32-bit float rendering, so painting is limited to 16-bit depth. -# We should get this in Godot 4.0, either as Compute or renderer improvement -const _hdr_formats = [ - Image.FORMAT_RH, - Image.FORMAT_RGH, - Image.FORMAT_RGBH, - Image.FORMAT_RGBAH -] - -const _supported_formats = [ - Image.FORMAT_R8, - Image.FORMAT_RG8, - Image.FORMAT_RGB8, - Image.FORMAT_RGBA8, - Image.FORMAT_L8 - # No longer supported since Godot 4 removed support for it in 2D viewports... -# Image.FORMAT_RH, -# Image.FORMAT_RGH, -# Image.FORMAT_RGBH, -# Image.FORMAT_RGBAH -] - -# - SubViewport (size of edited region + margin to allow quad rotation) -# |- Background -# | Fills pixels with unmodified source image. -# |- Brush sprite -# Size of actual brush, scaled/rotated, modifies source image. -# Assigned texture is the brush texture, src image is a shader param - -var _viewport : SubViewport -var _viewport_bg_sprite : Sprite2D -var _viewport_brush_sprite : Sprite2D -var _brush_size := 32 -var _brush_scale := 1.0 -var _brush_position := Vector2() -var _brush_opacity := 1.0 -var _brush_texture : Texture -var _last_brush_position := Vector2() -var _brush_material := ShaderMaterial.new() -var _no_blend_material : ShaderMaterial -var _image : Image -var _texture : ImageTexture -var _cmd_paint := false -var _pending_paint_render := false -var _modified_chunks := {} -var _modified_shader_params := {} - -var _debug_display : TextureRect -var _logger = HT_Logger.get_for(self) - - -func _init(): - _viewport = SubViewport.new() - _viewport.size = Vector2(_brush_size, _brush_size) - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - #_viewport.hdr = false - # Require 4 components (RGBA) - _viewport.transparent_bg = true - # Apparently HDR doesn't work if this is set to 2D... so let's waste a depth buffer :/ - #_viewport.usage = Viewport.USAGE_2D - #_viewport.keep_3d_linear - - # There is no "blend_disabled" option on standard CanvasItemMaterial... - _no_blend_material = ShaderMaterial.new() - _no_blend_material.shader = HT_NoBlendShader - _viewport_bg_sprite = Sprite2D.new() - _viewport_bg_sprite.centered = false - _viewport_bg_sprite.material = _no_blend_material - _viewport.add_child(_viewport_bg_sprite) - - _viewport_brush_sprite = Sprite2D.new() - _viewport_brush_sprite.centered = true - _viewport_brush_sprite.material = _brush_material - _viewport_brush_sprite.position = _viewport.size / 2.0 - _viewport.add_child(_viewport_brush_sprite) - - add_child(_viewport) - - -func set_debug_display(dd: TextureRect): - _debug_display = dd - _debug_display.texture = _viewport.get_texture() - - -func set_image(image: Image, texture: ImageTexture): - assert((image == null and texture == null) or (image != null and texture != null)) - _image = image - _texture = texture - _viewport_bg_sprite.texture = _texture - _brush_material.set_shader_parameter(SHADER_PARAM_SRC_TEXTURE, _texture) - if image != null: - if image.get_format() == Image.FORMAT_RF \ - or image.get_format() == Image.FORMAT_RH: - # In case of RF all shaders must encode their fragment outputs in RGBA8, - # including the unmodified background, as Godot 4.0 does not support RF viewports - _no_blend_material.shader = HT_NoBlendRFShader - else: - _no_blend_material.shader = HT_NoBlendShader - # TODO HDR is required in order to paint heightmaps. - # Seems Godot 4.0 does not support it, so we have to wait for Godot 4.1... - #_viewport.hdr = image.get_format() in _hdr_formats - if (image.get_format() in _hdr_formats) and image.get_format() != Image.FORMAT_RF: - push_error("Godot 4.0 does not support HDR viewports for GPU-editing heightmaps! " + - "Only RF is supported using a bit packing hack.") - #print("PAINTER VIEWPORT HDR: ", _viewport.hdr) - - -# Sets the size of the brush in pixels. -# This will cause the internal viewport to resize, which is expensive. -# If you need to frequently change brush size during a paint stroke, prefer using scale instead. -func set_brush_size(new_size: int): - _brush_size = new_size - - -func get_brush_size() -> int: - return _brush_size - - -func set_brush_rotation(rotation: float): - _viewport_brush_sprite.rotation = rotation - - -func get_brush_rotation() -> float: - return _viewport_bg_sprite.rotation - - -# The difference between size and scale, is that size is in pixels, while scale is a multiplier. -# Scale is also a lot cheaper to change, so you may prefer changing it instead of size if that -# happens often during a painting stroke. -func set_brush_scale(s: float): - _brush_scale = clampf(s, 0.0, 1.0) - #_viewport_brush_sprite.scale = Vector2(s, s) - - -func get_brush_scale() -> float: - return _viewport_bg_sprite.scale.x - - -func set_brush_opacity(opacity: float): - _brush_opacity = clampf(opacity, 0.0, 1.0) - - -func get_brush_opacity() -> float: - return _brush_opacity - - -func set_brush_texture(texture: Texture): - _viewport_brush_sprite.texture = texture - - -func set_brush_shader(shader: Shader): - if _brush_material.shader != shader: - _brush_material.shader = shader - - -func set_brush_shader_param(p: String, v): - assert(not _API_SHADER_PARAMS.has(p)) - _modified_shader_params[p] = true - _brush_material.set_shader_parameter(p, v) - - -func clear_brush_shader_params(): - for key in _modified_shader_params: - _brush_material.set_shader_parameter(key, null) - _modified_shader_params.clear() - - -# If we want to be able to rotate the brush quad every frame, -# we must prepare a bigger viewport otherwise the quad will not fit inside -static func _get_size_fit_for_rotation(src_size: Vector2) -> Vector2i: - var d = int(ceilf(src_size.length())) - return Vector2i(d, d) - - -# You must call this from an `_input` function or similar. -func paint_input(center_pos: Vector2): - var vp_size := _get_size_fit_for_rotation(Vector2(_brush_size, _brush_size)) - if _viewport.size != vp_size: - # Do this lazily so the brush slider won't lag while adjusting it - # TODO An "sliding_ended" handling might produce better user experience - _viewport.size = vp_size - _viewport_brush_sprite.position = _viewport.size / 2.0 - - # Need to floor the position in case the brush has an odd size - var brush_pos := (center_pos - _viewport.size * 0.5).round() - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - _viewport_bg_sprite.position = -brush_pos - _brush_position = brush_pos - _cmd_paint = true - - # We want this quad to have a specific size, regardless of the texture assigned to it - _viewport_brush_sprite.scale = \ - _brush_scale * Vector2(_brush_size, _brush_size) \ - / Vector2(_viewport_brush_sprite.texture.get_size()) - - # Using a Color because Godot doesn't understand vec4 - var rect := Color() - rect.r = brush_pos.x / _texture.get_width() - rect.g = brush_pos.y / _texture.get_height() - rect.b = float(_viewport.size.x) / float(_texture.get_width()) - rect.a = float(_viewport.size.y) / float(_texture.get_height()) - # In order to make sure that u_brush_rect is never bigger than the brush: - # 1. we ceil() the result of lower-left corner - # 2. we floor() the result of upper-right corner - # and then rederive width and height from the result -# var half_brush:Vector2 = Vector2(_brush_size, _brush_size) / 2 -# var brush_LL := (center_pos - half_brush).ceil() -# var brush_UR := (center_pos + half_brush).floor() -# rect.r = brush_LL.x / _texture.get_width() -# rect.g = brush_LL.y / _texture.get_height() -# rect.b = (brush_UR.x - brush_LL.x) / _texture.get_width() -# rect.a = (brush_UR.y - brush_LL.y) / _texture.get_height() - _brush_material.set_shader_parameter(SHADER_PARAM_SRC_RECT, rect) - _brush_material.set_shader_parameter(SHADER_PARAM_OPACITY, _brush_opacity) - - -# Don't commit until this is false -func is_operation_pending() -> bool: - return _pending_paint_render or _cmd_paint - - -# Applies changes to the Image, and returns modified chunks for UndoRedo. -func commit() -> Dictionary: - if is_operation_pending(): - _logger.error("Painter commit() was called while an operation is still pending") - return _commit_modified_chunks() - - -func has_modified_chunks() -> bool: - return len(_modified_chunks) > 0 - - -func _process(delta: float): - if _pending_paint_render: - _pending_paint_render = false - - #print("Paint result at frame ", Engine.get_frames_drawn()) - var viewport_image := _viewport.get_texture().get_image() - - if _image.get_format() == Image.FORMAT_RF: - # Reinterpret RGBA8 as RF. This assumes painting shaders encode the output properly. - assert(viewport_image.get_format() == Image.FORMAT_RGBA8) - viewport_image = Image.create_from_data( - viewport_image.get_width(), viewport_image.get_height(), false, Image.FORMAT_RF, - viewport_image.get_data()) - - elif _image.get_format() == Image.FORMAT_RH: - # Reinterpret RGBA8 as RF then convert to RH. - # This assumes painting shaders encode the output properly. - # This is slower and only meant as legacy compatibility. It may be preferable to - # upgrade such heightmaps to RF at least for edition. - assert(viewport_image.get_format() == Image.FORMAT_RGBA8) - viewport_image = Image.create_from_data( - viewport_image.get_width(), viewport_image.get_height(), false, Image.FORMAT_RF, - viewport_image.get_data()) - viewport_image.convert(Image.FORMAT_RH) - - else: - viewport_image.convert(_image.get_format()) - - var brush_pos := _last_brush_position - - var dst_x : int = clamp(brush_pos.x, 0, _texture.get_width()) - var dst_y : int = clamp(brush_pos.y, 0, _texture.get_height()) - - var src_x : int = maxf(-brush_pos.x, 0) - var src_y : int = maxf(-brush_pos.y, 0) - var src_w : int = minf(maxf(_viewport.size.x - src_x, 0), _texture.get_width() - dst_x) - var src_h : int = minf(maxf(_viewport.size.y - src_y, 0), _texture.get_height() - dst_y) - - if src_w != 0 and src_h != 0: - _mark_modified_chunks(dst_x, dst_y, src_w, src_h) - HT_Util.update_texture_partial(_texture, viewport_image, - Rect2i(src_x, src_y, src_w, src_h), Vector2i(dst_x, dst_y)) - texture_region_changed.emit(Rect2(dst_x, dst_y, src_w, src_h)) - - # Input is handled just before process, so we still have to wait till next frame - if _cmd_paint: - _pending_paint_render = true - _last_brush_position = _brush_position - # Consume input - _cmd_paint = false - - -func _mark_modified_chunks(bx: int, by: int, bw: int, bh: int): - var cs := UNDO_CHUNK_SIZE - - var cmin_x := bx / cs - var cmin_y := by / cs - var cmax_x := (bx + bw - 1) / cs + 1 - var cmax_y := (by + bh - 1) / cs + 1 - - for cy in range(cmin_y, cmax_y): - for cx in range(cmin_x, cmax_x): - #print("Marking chunk ", Vector2(cx, cy)) - _modified_chunks[Vector2(cx, cy)] = true - - -func _commit_modified_chunks() -> Dictionary: - var time_before := Time.get_ticks_msec() - - var cs := UNDO_CHUNK_SIZE - var chunks_positions := [] - var chunks_initial_data := [] - var chunks_final_data := [] - - #_logger.debug("About to commit ", len(_modified_chunks), " chunks") - - # TODO get_data_partial() would be nice... - var final_image := _texture.get_image() - for cpos in _modified_chunks: - var cx : int = cpos.x - var cy : int = cpos.y - - var x := cx * cs - var y := cy * cs - var w : int = mini(cs, _image.get_width() - x) - var h : int = mini(cs, _image.get_height() - y) - - var rect := Rect2i(x, y, w, h) - var initial_data := _image.get_region(rect) - var final_data := final_image.get_region(rect) - - chunks_positions.append(cpos) - chunks_initial_data.append(initial_data) - chunks_final_data.append(final_data) - #_image_equals(initial_data, final_data) - - # TODO We could also just replace the image with `final_image`... - # TODO Use `final_data` instead? - _image.blit_rect(final_image, rect, rect.position) - - _modified_chunks.clear() - - var time_spent := Time.get_ticks_msec() - time_before - _logger.debug("Spent {0} ms to commit paint operation".format([time_spent])) - - return { - "chunk_positions": chunks_positions, - "chunk_initial_datas": chunks_initial_data, - "chunk_final_datas": chunks_final_data - } - - -# DEBUG -#func _input(event): -# if event is InputEventKey: -# if event.pressed: -# if event.control and event.scancode == KEY_SPACE: -# print("Saving painter viewport ", name) -# var im = _viewport.get_texture().get_data() -# im.convert(Image.FORMAT_RGBA8) -# im.save_png(str("test_painter_viewport_", name, ".png")) - - -#static func _image_equals(im_a: Image, im_b: Image) -> bool: -# if im_a.get_size() != im_b.get_size(): -# print("Diff size: ", im_a.get_size, ", ", im_b.get_size()) -# return false -# if im_a.get_format() != im_b.get_format(): -# print("Diff format: ", im_a.get_format(), ", ", im_b.get_format()) -# return false -# im_a.lock() -# im_b.lock() -# for y in im_a.get_height(): -# for x in im_a.get_width(): -# var ca = im_a.get_pixel(x, y) -# var cb = im_b.get_pixel(x, y) -# if ca != cb: -# print("Diff pixel ", x, ", ", y) -# return false -# im_a.unlock() -# im_b.unlock() -# print("SAME") -# return true diff --git a/godot/addons/zylann.hterrain/tools/brush/painter.gd.uid b/godot/addons/zylann.hterrain/tools/brush/painter.gd.uid deleted file mode 100644 index d609c71..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/painter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bp5gimsstjt4j diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd deleted file mode 100644 index 3aa4771..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd +++ /dev/null @@ -1,282 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../../util/util.gd") -const HT_Brush = preload("../brush.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_SpinSlider = preload("../../util/spin_slider.gd") -const HT_Scratchpad = preload("./preview_scratchpad.gd") - -@onready var _scratchpad : HT_Scratchpad = $VB/HB/VB3/PreviewScratchpad - -@onready var _shape_list : ItemList = $VB/HB/VB/ShapeList -@onready var _remove_shape_button : Button = $VB/HB/VB/HBoxContainer/RemoveShape -@onready var _change_shape_button : Button = $VB/HB/VB/ChangeShape - -@onready var _size_slider : HT_SpinSlider = $VB/HB/VB2/Settings/Size -@onready var _opacity_slider : HT_SpinSlider = $VB/HB/VB2/Settings/Opacity -@onready var _pressure_enabled_checkbox : CheckBox = $VB/HB/VB2/Settings/PressureEnabled -@onready var _pressure_over_size_slider : HT_SpinSlider = $VB/HB/VB2/Settings/PressureOverSize -@onready var _pressure_over_opacity_slider : HT_SpinSlider = $VB/HB/VB2/Settings/PressureOverOpacity -@onready var _frequency_distance_slider : HT_SpinSlider = $VB/HB/VB2/Settings/FrequencyDistance -@onready var _frequency_time_slider : HT_SpinSlider = $VB/HB/VB2/Settings/FrequencyTime -@onready var _random_rotation_checkbox : CheckBox = $VB/HB/VB2/Settings/RandomRotation -@onready var _shape_cycling_checkbox : CheckBox = $VB/HB/VB2/Settings/ShapeCycling - -var _brush : HT_Brush -# This is a `EditorFileDialog`, -# but cannot type it because I want to be able to test it by running the scene. -# And when I run it, Godot does not allow to use `EditorFileDialog`. -var _load_image_dialog -# -1 means add, otherwise replace -var _load_image_index := -1 -var _logger = HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - _size_slider.set_max_value(HT_Brush.MAX_SIZE_FOR_SLIDERS) - _size_slider.set_min_value(HT_Brush.MIN_SIZE_FOR_SLIDERS) - _opacity_slider.set_max_value(HT_Brush.MAX_OPACITY_FOR_SLIDERS) - _opacity_slider.set_min_value(HT_Brush.MIN_OPACITY_FOR_SLIDERS) - _size_slider.set_greater_max_value(HT_Brush.MAX_SIZE) - - # TESTING - if not Engine.is_editor_hint(): - setup_dialogs(self) - call_deferred("popup") - - -func set_brush(brush : HT_Brush): - assert(brush != null) - _brush = brush - _update_controls_from_brush() - - -# `base_control` can no longer be hinted as a `Control` because in Godot 4 it could be a -# window or dialog, which are no longer controls... -func setup_dialogs(base_control: Node): - assert(_load_image_dialog == null) - _load_image_dialog = HT_EditorUtil.create_open_file_dialog() - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - _load_image_dialog.add_filter("*.exr ; EXR files") - _load_image_dialog.unresizable = false - _load_image_dialog.access = EditorFileDialog.ACCESS_FILESYSTEM - _load_image_dialog.current_dir = HT_Brush.SHAPES_DIR - _load_image_dialog.file_selected.connect(_on_LoadImageDialog_file_selected) - _load_image_dialog.files_selected.connect(_on_LoadImageDialog_files_selected) - #base_control.add_child(_load_image_dialog) - # When a dialog opens another dialog, we get this error: - # "Transient parent has another exclusive child." - # Which is worked around by making the other dialog a child of the first one (I don't know why) - add_child(_load_image_dialog) - - -func _exit_tree(): - if _load_image_dialog != null: - _load_image_dialog.queue_free() - _load_image_dialog = null - - -func _get_shapes_from_gui() -> Array[Texture2D]: - var shapes : Array[Texture2D] = [] - for i in _shape_list.get_item_count(): - var icon : Texture2D = _shape_list.get_item_icon(i) - assert(icon != null) - shapes.append(icon) - return shapes - - -func _update_shapes_gui(shapes: Array[Texture2D]): - _shape_list.clear() - for shape in shapes: - assert(shape != null) - assert(shape is Texture2D) - _shape_list.add_icon_item(shape) - _update_shape_list_buttons() - - -func _on_AddShape_pressed(): - _load_image_index = -1 - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILES - _load_image_dialog.popup_centered_ratio(0.7) - - -func _on_RemoveShape_pressed(): - var selected_indices := _shape_list.get_selected_items() - if len(selected_indices) == 0: - return - - var index : int = selected_indices[0] - _shape_list.remove_item(index) - - var shapes := _get_shapes_from_gui() - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shape_list_buttons() - - -func _on_ShapeList_item_activated(index: int): - _request_modify_shape(index) - - -func _on_ChangeShape_pressed(): - var selected = _shape_list.get_selected_items() - if len(selected) == 0: - return - _request_modify_shape(selected[0]) - - -func _request_modify_shape(index: int): - _load_image_index = index - _load_image_dialog.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - _load_image_dialog.popup_centered_ratio(0.7) - - -func _on_LoadImageDialog_files_selected(fpaths: PackedStringArray): - var shapes := _get_shapes_from_gui() - - for fpath in fpaths: - var tex := HT_Brush.load_shape_from_image_file(fpath, _logger) - if tex == null: - # Failed - continue - shapes.append(tex) - - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shapes_gui(shapes) - - -func _on_LoadImageDialog_file_selected(fpath: String): - var tex := HT_Brush.load_shape_from_image_file(fpath, _logger) - if tex == null: - # Failed - return - - var shapes := _get_shapes_from_gui() - if _load_image_index == -1 or _load_image_index >= len(shapes): - # Add - shapes.append(tex) - else: - # Replace - assert(_load_image_index >= 0) - shapes[_load_image_index] = tex - - for brush in _get_brushes(): - brush.set_shapes(shapes) - - _update_shapes_gui(shapes) - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - # Testing the scratchpad because visibility can not only change before entering the tree - # since Godot 4 port, it can also change between entering the tree and being _ready... - if visible and _scratchpad != null: - _update_controls_from_brush() - - -func _update_controls_from_brush(): - var brush := _brush - - if brush == null: - # To allow testing - brush = _scratchpad.get_painter().get_brush() - - _update_shapes_gui(brush.get_shapes()) - - _size_slider.set_value(brush.get_size(), false) - _opacity_slider.set_value(brush.get_opacity() * 100.0, false) - _pressure_enabled_checkbox.button_pressed = brush.is_pressure_enabled() - _pressure_over_size_slider.set_value(brush.get_pressure_over_scale() * 100.0, false) - _pressure_over_opacity_slider.set_value(brush.get_pressure_over_opacity() * 100.0, false) - _frequency_distance_slider.set_value(brush.get_frequency_distance(), false) - _frequency_time_slider.set_value( - 1000.0 / maxf(0.1, float(brush.get_frequency_time_ms())), false) - _random_rotation_checkbox.button_pressed = brush.is_random_rotation_enabled() - _shape_cycling_checkbox.button_pressed = brush.is_shape_cycling_enabled() - - -func _on_ClearScratchpad_pressed(): - _scratchpad.reset_image() - - -func _on_Size_value_changed(value: float): - for brush in _get_brushes(): - brush.set_size(value) - - -func _on_Opacity_value_changed(value): - for brush in _get_brushes(): - brush.set_opacity(value / 100.0) - - -func _on_PressureEnabled_toggled(button_pressed): - for brush in _get_brushes(): - brush.set_pressure_enabled(button_pressed) - - -func _on_PressureOverSize_value_changed(value): - for brush in _get_brushes(): - brush.set_pressure_over_scale(value / 100.0) - - -func _on_PressureOverOpacity_value_changed(value): - for brush in _get_brushes(): - brush.set_pressure_over_opacity(value / 100.0) - - -func _on_FrequencyDistance_value_changed(value): - for brush in _get_brushes(): - brush.set_frequency_distance(value) - - -func _on_FrequencyTime_value_changed(fps): - fps = max(1.0, fps) - var ms = 1000.0 / fps - if is_equal_approx(fps, 60.0): - ms = 0 - for brush in _get_brushes(): - brush.set_frequency_time_ms(ms) - - -func _on_RandomRotation_toggled(button_pressed: bool): - for brush in _get_brushes(): - brush.set_random_rotation_enabled(button_pressed) - - -func _on_shape_cycling_toggled(button_pressed: bool): - for brush in _get_brushes(): - brush.set_shape_cycling_enabled(button_pressed) - - -func _get_brushes() -> Array[HT_Brush]: - if _brush != null: - # We edit both the preview brush and the terrain brush - # TODO Could we simply share the brush? - return [_brush, _scratchpad.get_painter().get_brush()] - # When testing the dialog in isolation, the edited brush might be null - return [_scratchpad.get_painter().get_brush()] - - -func _on_ShapeList_item_selected(index): - _update_shape_list_buttons() - for brush in _get_brushes(): - brush.set_shape_index(index) - - -func _update_shape_list_buttons(): - var selected_count := len(_shape_list.get_selected_items()) - # There must be at least one shape - _remove_shape_button.disabled = _shape_list.get_item_count() == 1 or selected_count == 0 - _change_shape_button.disabled = selected_count == 0 - - -func _on_shape_list_empty_clicked(at_position, mouse_button_index): - _update_shape_list_buttons() diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd.uid deleted file mode 100644 index defc9cf..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dwsnk6il4s27m diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn deleted file mode 100644 index 7d7e07d..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.tscn +++ /dev/null @@ -1,211 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://d2rt3wj8xkhp2"] - -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/spin_slider.tscn" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/brush_settings_dialog.gd" id="3"] -[ext_resource type="PackedScene" uid="uid://ng00jipfeucy" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn" id="4"] - -[node name="BrushSettingsDialog" type="AcceptDialog"] -title = "Brush settings" -size = Vector2i(700, 422) -min_size = Vector2i(700, 400) -script = ExtResource("3") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -49.0 - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="VB/HB/VB"] -layout_mode = 2 -text = "Shapes" - -[node name="ShapeList" type="ItemList" parent="VB/HB/VB"] -layout_mode = 2 -size_flags_vertical = 3 -fixed_icon_size = Vector2i(100, 100) - -[node name="ChangeShape" type="Button" parent="VB/HB/VB"] -layout_mode = 2 -disabled = true -text = "Change..." - -[node name="HBoxContainer" type="HBoxContainer" parent="VB/HB/VB"] -layout_mode = 2 - -[node name="AddShape" type="Button" parent="VB/HB/VB/HBoxContainer"] -layout_mode = 2 -text = "Add..." - -[node name="RemoveShape" type="Button" parent="VB/HB/VB/HBoxContainer"] -layout_mode = 2 -disabled = true -text = "Remove" - -[node name="VB2" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="VB/HB/VB2"] -layout_mode = 2 - -[node name="Settings" type="VBoxContainer" parent="VB/HB/VB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Size" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -size_flags_horizontal = 3 -value = 32.0 -min_value = 2.0 -max_value = 500.0 -prefix = "Size:" -suffix = "px" -rounded = true -centered = true -allow_greater = true -greater_max_value = 4000.0 - -[node name="Opacity" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -size_flags_horizontal = 3 -value = 100.0 -max_value = 100.0 -prefix = "Opacity" -suffix = "%" -rounded = true -centered = true -greater_max_value = 10000.0 - -[node name="PressureEnabled" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Enable pressure (pen tablets)" - -[node name="PressureOverSize" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 50.0 -max_value = 100.0 -prefix = "Pressure affects size:" -suffix = "%" -centered = true -greater_max_value = 10000.0 - -[node name="PressureOverOpacity" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 50.0 -max_value = 100.0 -prefix = "Pressure affects opacity:" -suffix = "%" -centered = true -greater_max_value = 10000.0 - -[node name="FrequencyTime" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -value = 60.0 -min_value = 1.0 -max_value = 60.0 -prefix = "Frequency time:" -suffix = "fps" -centered = true -greater_max_value = 10000.0 - -[node name="FrequencyDistance" parent="VB/HB/VB2/Settings" instance=ExtResource("2")] -custom_minimum_size = Vector2(32, 28) -layout_mode = 2 -max_value = 100.0 -prefix = "Frequency distance:" -suffix = "px" -centered = true -greater_max_value = 4000.0 - -[node name="RandomRotation" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Random rotation" - -[node name="ShapeCycling" type="CheckBox" parent="VB/HB/VB2/Settings"] -layout_mode = 2 -text = "Shape cycling" - -[node name="HSeparator" type="HSeparator" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="SizeLimitHB" type="HBoxContainer" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HB/VB2/Settings/SizeLimitHB"] -layout_mode = 2 -mouse_filter = 0 -text = "Size limit:" - -[node name="SizeLimit" type="SpinBox" parent="VB/HB/VB2/Settings/SizeLimitHB"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = 1.0 -max_value = 1000.0 -value = 200.0 - -[node name="HSeparator2" type="HSeparator" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="VB/HB/VB2/Settings"] -visible = false -layout_mode = 2 - -[node name="Button" type="Button" parent="VB/HB/VB2/Settings/HB"] -layout_mode = 2 -text = "Load preset..." - -[node name="Button2" type="Button" parent="VB/HB/VB2/Settings/HB"] -layout_mode = 2 -text = "Save preset..." - -[node name="VB3" type="VBoxContainer" parent="VB/HB"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HB/VB3"] -layout_mode = 2 -text = "Scratchpad" - -[node name="PreviewScratchpad" parent="VB/HB/VB3" instance=ExtResource("4")] -custom_minimum_size = Vector2(200, 300) -layout_mode = 2 - -[node name="ClearScratchpad" type="Button" parent="VB/HB/VB3"] -layout_mode = 2 -text = "Clear" - -[connection signal="empty_clicked" from="VB/HB/VB/ShapeList" to="." method="_on_shape_list_empty_clicked"] -[connection signal="item_activated" from="VB/HB/VB/ShapeList" to="." method="_on_ShapeList_item_activated"] -[connection signal="item_selected" from="VB/HB/VB/ShapeList" to="." method="_on_ShapeList_item_selected"] -[connection signal="pressed" from="VB/HB/VB/ChangeShape" to="." method="_on_ChangeShape_pressed"] -[connection signal="pressed" from="VB/HB/VB/HBoxContainer/AddShape" to="." method="_on_AddShape_pressed"] -[connection signal="pressed" from="VB/HB/VB/HBoxContainer/RemoveShape" to="." method="_on_RemoveShape_pressed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/Size" to="." method="_on_Size_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/Opacity" to="." method="_on_Opacity_value_changed"] -[connection signal="toggled" from="VB/HB/VB2/Settings/PressureEnabled" to="." method="_on_PressureEnabled_toggled"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/PressureOverSize" to="." method="_on_PressureOverSize_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/PressureOverOpacity" to="." method="_on_PressureOverOpacity_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/FrequencyTime" to="." method="_on_FrequencyTime_value_changed"] -[connection signal="value_changed" from="VB/HB/VB2/Settings/FrequencyDistance" to="." method="_on_FrequencyDistance_value_changed"] -[connection signal="toggled" from="VB/HB/VB2/Settings/RandomRotation" to="." method="_on_RandomRotation_toggled"] -[connection signal="toggled" from="VB/HB/VB2/Settings/ShapeCycling" to="." method="_on_shape_cycling_toggled"] -[connection signal="pressed" from="VB/HB/VB3/ClearScratchpad" to="." method="_on_ClearScratchpad_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd deleted file mode 100644 index be52072..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -extends Node - -const HT_Painter = preload("./../painter.gd") -const HT_Brush = preload("./../brush.gd") - -const HT_ColorShader = preload("../shaders/color.gdshader") - -var _painter : HT_Painter -var _brush : HT_Brush - - -func _init(): - var p = HT_Painter.new() - # The name is just for debugging - p.set_name("Painter") - add_child(p) - _painter = p - - _brush = HT_Brush.new() - - -func set_image_texture(image: Image, texture: ImageTexture): - _painter.set_image(image, texture) - - -func get_brush() -> HT_Brush: - return _brush - - -# This may be called from an `_input` callback -func paint_input(position: Vector2, pressure: float): - var p : HT_Painter = _painter - - if not _brush.configure_paint_input([p], position, pressure): - return - - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", Color(0,0,0,1)) - #p.set_image(_image, _texture) - p.paint_input(position) diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd.uid b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd.uid deleted file mode 100644 index d304636..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bcopyjfnkgovm diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd deleted file mode 100644 index cec0728..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd +++ /dev/null @@ -1,70 +0,0 @@ -@tool -extends Control - -const HT_PreviewPainter = preload("./preview_painter.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_DefaultBrushTexture = preload("../shapes/round2.exr") -const HT_Brush = preload("../brush.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Util = preload("../../../util/util.gd") - -@onready var _texture_rect : TextureRect = $TextureRect -@onready var _painter : HT_PreviewPainter = $Painter - -var _logger := HT_Logger.get_for(self) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - # If it runs in the edited scene, - # saving the scene would also save the ImageTexture in it... - return - reset_image() - # Default so it doesn't crash when painting and can be tested - var default_brush_texture = \ - HT_EditorUtil.load_texture(HT_Brush.DEFAULT_BRUSH_TEXTURE_PATH, _logger) - _painter.get_brush().set_shapes([default_brush_texture]) - - -func reset_image(): - var image = Image.create(_texture_rect.size.x, _texture_rect.size.y, false, Image.FORMAT_RGB8) - image.fill(Color(1,1,1)) - - # TEST -# var fnl = FastNoiseLite.new() -# for y in image.get_height(): -# for x in image.get_width(): -# var g = 0.5 + 0.5 * fnl.get_noise_2d(x, y) -# image.set_pixel(x, y, Color(g, g, g, 1.0)) - - var texture = ImageTexture.create_from_image(image) - _texture_rect.texture = texture - _painter.set_image_texture(image, texture) - - -func get_painter() -> HT_PreviewPainter: - return _painter - - -func _gui_input(event): - if event is InputEventMouseMotion: - if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): - _painter.paint_input(event.position, event.pressure) - queue_redraw() - - elif event is InputEventMouseButton: - if event.button_index == MOUSE_BUTTON_LEFT: - if event.pressed: - # TODO `pressure` is not available on button events - # So I have to assume zero... which means clicks do not paint anything? - _painter.paint_input(event.position, 0.0) - else: - _painter.get_brush().on_paint_end() - - -func _draw(): - var mpos = get_local_mouse_position() - var brush = _painter.get_brush() - draw_arc(mpos, 0.5 * brush.get_size(), -PI, PI, 32, Color(1, 0.2, 0.2), 2.0, true) - diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd.uid b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd.uid deleted file mode 100644 index bd05d79..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c28shbo15cs74 diff --git a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn b/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn deleted file mode 100644 index 0b50c91..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://ng00jipfeucy"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_scratchpad.gd" id="1"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/brush/settings_dialog/preview_painter.gd" id="2"] - -[node name="PreviewScratchpad" type="Control"] -clip_contents = true -layout_mode = 3 -anchors_preset = 0 -offset_right = 200.0 -offset_bottom = 274.0 -script = ExtResource("1") - -[node name="Painter" type="Node" parent="."] -script = ExtResource("2") - -[node name="TextureRect" type="TextureRect" parent="."] -show_behind_parent = true -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -stretch_mode = 5 diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader deleted file mode 100644 index f8a05c5..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader +++ /dev/null @@ -1,19 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_value = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec4 src = texture(u_src_texture, get_src_uv(SCREEN_UV)); - COLOR = vec4(src.rgb, mix(src.a, u_value, brush_value)); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader.uid deleted file mode 100644 index 415780c..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/alpha.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b23362qo0re0h diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader deleted file mode 100644 index eec65f5..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader +++ /dev/null @@ -1,68 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_color = vec4(1.0); -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - vec4 src = texture(u_src_texture, src_uv); - - // Despite hints, albedo textures render darker. - // Trying to undo sRGB does not work because of 8-bit precision loss - // that would occur either in texture, or on the source image. - // So it's not possible to use viewports to paint albedo... - //src.rgb = pow(src.rgb, vec3(0.4545)); - - vec4 col = vec4(mix(src.rgb, u_color.rgb, brush_value), src.a); - COLOR = col; -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader.uid deleted file mode 100644 index 9660ffa..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/color.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://s3axpm0hyidc diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader deleted file mode 100644 index 669f4d7..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader +++ /dev/null @@ -1,64 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_color = vec4(1.0); - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -// float get_noise(vec2 pos) { -// return fract(sin(dot(pos.xy ,vec2(12.9898,78.233))) * 43758.5453); -// } - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -float erode(sampler2D heightmap, vec2 uv, vec2 pixel_size, float weight) { - float r = 3.0; - - // Divide so the shader stays neighbor dependent 1 pixel across. - // For this to work, filtering must be enabled. - vec2 eps = pixel_size / (0.99 * r); - - float h = get_height(heightmap, uv); - float eh = h; - //float dh = h; - - // Morphology with circular structuring element - for (float y = -r; y <= r; ++y) { - for (float x = -r; x <= r; ++x) { - - vec2 p = vec2(x, y); - float nh = get_height(heightmap, uv + p * eps); - - float s = max(length(p) - r, 0); - eh = min(eh, nh + s); - - //s = min(r - length(p), 0); - //dh = max(dh, nh + s); - } - } - - eh = mix(h, eh, weight); - //dh = mix(h, dh, u_weight); - - float ph = eh;//mix(eh, dh, u_dilation); - - return ph; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - vec2 src_pixel_size = 1.0 / vec2(textureSize(u_src_texture, 0)); - float ph = erode(u_src_texture, get_src_uv(SCREEN_UV), src_pixel_size, brush_value); - //ph += brush_value * 0.35; - COLOR = encode_height_to_viewport(ph); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader.uid deleted file mode 100644 index 80749d6..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/erode.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d168f1vgarcal diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader deleted file mode 100644 index c51f03a..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_flatten_value; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - float src_h = sample_heightmap(u_src_texture, get_src_uv(SCREEN_UV)); - float h = mix(src_h, u_flatten_value, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader.uid deleted file mode 100644 index 419ac50..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/flatten.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://djdtklja6ui2i diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader deleted file mode 100644 index 4721b43..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader +++ /dev/null @@ -1,45 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -// TODO Could actually level to whatever height the brush was at the beginning of the stroke? - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - // The heightmap does not have mipmaps, - // so we need to use an approximation of average. - // This is not a very good one though... - float dst_h = 0.0; - vec2 uv_min = vec2(u_src_rect.xy); - vec2 uv_max = vec2(u_src_rect.xy + u_src_rect.zw); - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 5; ++j) { - float x = mix(uv_min.x, uv_max.x, float(i) / 4.0); - float y = mix(uv_min.y, uv_max.y, float(j) / 4.0); - float h = get_height(u_src_texture, vec2(x, y)); - dst_h += h; - } - } - dst_h /= (5.0 * 5.0); - - // TODO I have no idea if this will check out - float src_h = get_height(u_src_texture, get_src_uv(SCREEN_UV)); - float h = mix(src_h, dst_h, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader.uid deleted file mode 100644 index 2773896..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/level.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://hnycc801ybug diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader deleted file mode 100644 index 50fbc75..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader +++ /dev/null @@ -1,22 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - float src_h = sample_heightmap(u_src_texture, get_src_uv(SCREEN_UV)); - float h = src_h + brush_value; - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader.uid deleted file mode 100644 index 2b10026..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/raise.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://7mdfeo7ax88g diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader deleted file mode 100644 index 27123e4..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader +++ /dev/null @@ -1,34 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform float u_factor = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -void fragment() { - float brush_value = u_factor * u_opacity * texture(TEXTURE, UV).r; - - vec2 src_pixel_size = 1.0 / vec2(textureSize(u_src_texture, 0)); - vec2 src_uv = get_src_uv(SCREEN_UV); - vec2 offset = src_pixel_size; - float src_nx = get_height(u_src_texture, src_uv - vec2(offset.x, 0.0)); - float src_px = get_height(u_src_texture, src_uv + vec2(offset.x, 0.0)); - float src_ny = get_height(u_src_texture, src_uv - vec2(0.0, offset.y)); - float src_py = get_height(u_src_texture, src_uv + vec2(0.0, offset.y)); - float src_h = get_height(u_src_texture, src_uv); - float dst_h = (src_h + src_nx + src_px + src_ny + src_py) * 0.2; - float h = mix(src_h, dst_h, brush_value); - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader.uid deleted file mode 100644 index e699a41..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/smooth.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://be3de36aupe61 diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader deleted file mode 100644 index 68ebaa8..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader +++ /dev/null @@ -1,81 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_splat = vec4(1.0, 0.0, 0.0, 0.0); -uniform sampler2D u_other_splatmap_1; -uniform sampler2D u_other_splatmap_2; -uniform sampler2D u_other_splatmap_3; -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float sum(vec4 v) { - return v.x + v.y + v.z + v.w; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - // It is assumed 3 other renders are done the same with the other 3 - vec4 src0 = texture(u_src_texture, src_uv); - vec4 src1 = texture(u_other_splatmap_1, src_uv); - vec4 src2 = texture(u_other_splatmap_2, src_uv); - vec4 src3 = texture(u_other_splatmap_3, src_uv); - float t = brush_value; - vec4 s0 = mix(src0, u_splat, t); - vec4 s1 = mix(src1, vec4(0.0), t); - vec4 s2 = mix(src2, vec4(0.0), t); - vec4 s3 = mix(src3, vec4(0.0), t); - float sum = sum(s0) + sum(s1) + sum(s2) + sum(s3); - s0 /= sum; - s1 /= sum; - s2 /= sum; - s3 /= sum; - COLOR = s0; -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader.uid deleted file mode 100644 index d96ad66..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat16.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d3e56vrynmj8h diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader deleted file mode 100644 index 1291dbd..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader +++ /dev/null @@ -1,63 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform vec4 u_splat = vec4(1.0, 0.0, 0.0, 0.0); -uniform sampler2D u_heightmap; -uniform float u_normal_min_y = 0.0; -uniform float u_normal_max_y = 1.0; -//uniform float u_normal_falloff = 0.0; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -float get_height(sampler2D heightmap, vec2 uv) { - return sample_heightmap(heightmap, uv); -} - -vec3 get_normal(sampler2D heightmap, vec2 pos) { - vec2 ps = vec2(1.0) / vec2(textureSize(heightmap, 0)); - float hnx = get_height(heightmap, pos + vec2(-ps.x, 0.0)); - float hpx = get_height(heightmap, pos + vec2(ps.x, 0.0)); - float hny = get_height(heightmap, pos + vec2(0.0, -ps.y)); - float hpy = get_height(heightmap, pos + vec2(0.0, ps.y)); - return normalize(vec3(hnx - hpx, 2.0, hpy - hny)); -} - -// Limits painting based on the slope, with a bit of falloff -float apply_slope_limit(float brush_value, vec3 normal, float normal_min_y, float normal_max_y) { - float normal_falloff = 0.2; - - // If an edge is at min/max, make sure it won't be affected by falloff - normal_min_y = normal_min_y <= 0.0 ? -2.0 : normal_min_y; - normal_max_y = normal_max_y >= 1.0 ? 2.0 : normal_max_y; - - brush_value *= 1.0 - smoothstep( - normal_max_y - normal_falloff, - normal_max_y + normal_falloff, normal.y); - - brush_value *= smoothstep( - normal_min_y - normal_falloff, - normal_min_y + normal_falloff, normal.y); - - return brush_value; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec3 normal = get_normal(u_heightmap, src_uv); - brush_value = apply_slope_limit(brush_value, normal, u_normal_min_y, u_normal_max_y); - - vec4 src_splat = texture(u_src_texture, src_uv); - vec4 s = mix(src_splat, u_splat, brush_value); - s = s / (s.r + s.g + s.b + s.a); - COLOR = s; -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader.uid deleted file mode 100644 index 70277a9..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat4.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cidfwn26tiaw diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader b/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader deleted file mode 100644 index 9828068..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader +++ /dev/null @@ -1,89 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -uniform sampler2D u_src_texture; -uniform vec4 u_src_rect; -uniform float u_opacity = 1.0; -uniform int u_texture_index; -uniform int u_mode; // 0: output index, 1: output weight -uniform sampler2D u_index_map; -uniform sampler2D u_weight_map; - -vec2 get_src_uv(vec2 screen_uv) { - vec2 uv = u_src_rect.xy + screen_uv * u_src_rect.zw; - return uv; -} - -void fragment() { - float brush_value = u_opacity * texture(TEXTURE, UV).r; - - vec2 src_uv = get_src_uv(SCREEN_UV); - vec4 iv = texture(u_index_map, src_uv); - vec4 wv = texture(u_weight_map, src_uv); - - float i[3] = {iv.r, iv.g, iv.b}; - float w[3] = {wv.r, wv.g, wv.b}; - - if (brush_value > 0.0) { - float texture_index_f = float(u_texture_index) / 255.0; - int ci = u_texture_index % 3; - - float cm[3] = {-1.0, -1.0, -1.0}; - cm[ci] = 1.0; - - // Decompress third weight to make computations easier - w[2] = 1.0 - w[0] - w[1]; - - if (abs(i[ci] - texture_index_f) > 0.001) { - // Pixel does not have our texture index, - // transfer its weight to other components first - if (w[ci] > brush_value) { - w[0] -= cm[0] * brush_value; - w[1] -= cm[1] * brush_value; - w[2] -= cm[2] * brush_value; - - } else if (w[ci] >= 0.f) { - w[ci] = 0.f; - i[ci] = texture_index_f; - } - - } else { - // Pixel has our texture index, increase its weight - if (w[ci] + brush_value < 1.f) { - w[0] += cm[0] * brush_value; - w[1] += cm[1] * brush_value; - w[2] += cm[2] * brush_value; - - } else { - // Pixel weight is full, we can set all components to the same index. - // Need to nullify other weights because they would otherwise never reach - // zero due to normalization - w[0] = 0.0; - w[1] = 0.0; - w[2] = 0.0; - - w[ci] = 1.0; - - i[0] = texture_index_f; - i[1] = texture_index_f; - i[2] = texture_index_f; - } - } - - w[0] = clamp(w[0], 0.0, 1.0); - w[1] = clamp(w[1], 0.0, 1.0); - w[2] = clamp(w[2], 0.0, 1.0); - - // Renormalize - float sum = w[0] + w[1] + w[2]; - w[0] /= sum; - w[1] /= sum; - w[2] /= sum; - } - - if (u_mode == 0) { - COLOR = vec4(i[0], i[1], i[2], 1.0); - } else { - COLOR = vec4(w[0], w[1], w[2], 1.0); - } -} diff --git a/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader.uid b/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader.uid deleted file mode 100644 index bfaedc6..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shaders/splat_indexed.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dcuxrd4yybfc diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr deleted file mode 100644 index 14b66d6..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import deleted file mode 100644 index 48b0d76..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cua2gxgj2pum5" -path="res://.godot/imported/acrylic1.exr-8a4b622f104c607118d296791ee118f3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/acrylic1.exr" -dest_files=["res://.godot/imported/acrylic1.exr-8a4b622f104c607118d296791ee118f3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr deleted file mode 100644 index e91d97e..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import deleted file mode 100644 index 05c17d5..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/round0.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dekau2j7fx14d" -path="res://.godot/imported/round0.exr-fc6d691e8892911b1b4496769ee75dbb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round0.exr" -dest_files=["res://.godot/imported/round0.exr-fc6d691e8892911b1b4496769ee75dbb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr deleted file mode 100644 index f6931ba..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import deleted file mode 100644 index 06e282f..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/round1.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bbo5hotdg6mg7" -path="res://.godot/imported/round1.exr-8050cfbed31968e6ce8bd055fbaa6897.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round1.exr" -dest_files=["res://.godot/imported/round1.exr-8050cfbed31968e6ce8bd055fbaa6897.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr deleted file mode 100644 index 477ab7e..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import deleted file mode 100644 index 5058f27..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/round2.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://tn1ww3c47pwy" -path="res://.godot/imported/round2.exr-2a843db3bf131f2b2f5964ce65600f42.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round2.exr" -dest_files=["res://.godot/imported/round2.exr-2a843db3bf131f2b2f5964ce65600f42.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr deleted file mode 100644 index b466f92..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import deleted file mode 100644 index bf5a8cd..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/round3.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://baim7e27k13r4" -path="res://.godot/imported/round3.exr-77a9cdd9a592eb6010dc1db702d42c3a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/round3.exr" -dest_files=["res://.godot/imported/round3.exr-77a9cdd9a592eb6010dc1db702d42c3a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr deleted file mode 100644 index 021947b..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import deleted file mode 100644 index cebc58b..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/smoke.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cl6pxk6wr4hem" -path="res://.godot/imported/smoke.exr-0061a0a2acdf1ca295ec547e4b8c920d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/smoke.exr" -dest_files=["res://.godot/imported/smoke.exr-0061a0a2acdf1ca295ec547e4b8c920d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr deleted file mode 100644 index f456b77..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import deleted file mode 100644 index d2ffe91..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/texture1.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqdkxiq52oo0j" -path="res://.godot/imported/texture1.exr-0fac1840855f814972ea5666743101fc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/texture1.exr" -dest_files=["res://.godot/imported/texture1.exr-0fac1840855f814972ea5666743101fc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr deleted file mode 100644 index 49d341e..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import deleted file mode 100644 index dc5631f..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/thing.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://blljfgdlwdae5" -path="res://.godot/imported/thing.exr-8e88d861fe83e5e870fa01faee694c73.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/thing.exr" -dest_files=["res://.godot/imported/thing.exr-8e88d861fe83e5e870fa01faee694c73.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr b/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr deleted file mode 100644 index d65bc6e..0000000 Binary files a/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import b/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import deleted file mode 100644 index 6ad04d4..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ca5nk2h4ukm0g" -path="res://.godot/imported/vegetation1.exr-0573f4c73944e2dd8f3202b8930ac625.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/brush/shapes/vegetation1.exr" -dest_files=["res://.godot/imported/vegetation1.exr-0573f4c73944e2dd8f3202b8930ac625.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd b/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd deleted file mode 100644 index 81891b6..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd +++ /dev/null @@ -1,573 +0,0 @@ -@tool -extends Node - -const HT_Painter = preload("./painter.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_Brush = preload("./brush.gd") - -const HT_RaiseShader = preload("./shaders/raise.gdshader") -const HT_SmoothShader = preload("./shaders/smooth.gdshader") -const HT_LevelShader = preload("./shaders/level.gdshader") -const HT_FlattenShader = preload("./shaders/flatten.gdshader") -const HT_ErodeShader = preload("./shaders/erode.gdshader") -const HT_Splat4Shader = preload("./shaders/splat4.gdshader") -const HT_Splat16Shader = preload("./shaders/splat16.gdshader") -const HT_SplatIndexedShader = preload("./shaders/splat_indexed.gdshader") -const HT_ColorShader = preload("./shaders/color.gdshader") -const HT_AlphaShader = preload("./shaders/alpha.gdshader") - -const MODE_RAISE = 0 -const MODE_LOWER = 1 -const MODE_SMOOTH = 2 -const MODE_FLATTEN = 3 -const MODE_SPLAT = 4 -const MODE_COLOR = 5 -const MODE_MASK = 6 -const MODE_DETAIL = 7 -const MODE_LEVEL = 8 -const MODE_ERODE = 9 -const MODE_COUNT = 10 - -class HT_ModifiedMap: - var map_type := 0 - var map_index := 0 - var painter_index := 0 - -signal flatten_height_changed - -var _painters : Array[HT_Painter] = [] - -var _brush := HT_Brush.new() - -var _color := Color(1, 0, 0, 1) -var _mask_flag := false -var _mode := MODE_RAISE -var _flatten_height := 0.0 -var _detail_index := 0 -var _detail_density := 1.0 -var _texture_index := 0 -var _slope_limit_low_angle := 0.0 -var _slope_limit_high_angle := PI / 2.0 - -var _modified_maps := [] -var _terrain : HTerrain -var _logger = HT_Logger.get_for(self) - - -func _init(): - for i in 4: - var p := HT_Painter.new() - # The name is just for debugging - p.set_name(str("Painter", i)) - #p.set_brush_size(_brush_size) - p.texture_region_changed.connect(_on_painter_texture_region_changed.bind(i)) - add_child(p) - _painters.append(p) - - -func get_brush() -> HT_Brush: - return _brush - - -func get_brush_size() -> int: - return _brush.get_size() - - -func set_brush_size(s: int): - _brush.set_size(s) -# for p in _painters: -# p.set_brush_size(_brush_size) - - -func set_brush_texture(texture: Texture2D): - _brush.set_shapes([texture]) -# for p in _painters: -# p.set_brush_texture(texture) - - -func get_opacity() -> float: - return _brush.get_opacity() - - -func set_opacity(opacity: float): - _brush.set_opacity(opacity) - - -func set_flatten_height(h: float): - if h == _flatten_height: - return - _flatten_height = h - flatten_height_changed.emit() - - -func get_flatten_height() -> float: - return _flatten_height - - -func set_color(c: Color): - _color = c - - -func get_color() -> Color: - return _color - - -func set_mask_flag(m: bool): - _mask_flag = m - - -func get_mask_flag() -> bool: - return _mask_flag - - -func set_detail_density(d: float): - _detail_density = clampf(d, 0.0, 1.0) - - -func get_detail_density() -> float: - return _detail_density - - -func set_detail_index(di: int): - _detail_index = di - - -func set_texture_index(i: int): - _texture_index = i - - -func get_texture_index() -> int: - return _texture_index - - -func get_slope_limit_low_angle() -> float: - return _slope_limit_low_angle - - -func get_slope_limit_high_angle() -> float: - return _slope_limit_high_angle - - -func set_slope_limit_angles(low: float, high: float): - _slope_limit_low_angle = low - _slope_limit_high_angle = high - - -func is_operation_pending() -> bool: - for p in _painters: - if p.is_operation_pending(): - return true - return false - - -func has_modified_chunks() -> bool: - for p in _painters: - if p.has_modified_chunks(): - return true - return false - - -func get_undo_chunk_size() -> int: - return HT_Painter.UNDO_CHUNK_SIZE - - -func commit() -> Dictionary: - assert(_terrain.get_data() != null) - var terrain_data = _terrain.get_data() - assert(not terrain_data.is_locked()) - - var changes := [] - var chunk_positions : Array - - assert(len(_modified_maps) > 0) - - for mm in _modified_maps: - #print("Flushing painter ", mm.painter_index) - var painter : HT_Painter = _painters[mm.painter_index] - var info := painter.commit() - - # Note, positions are always the same for each map - chunk_positions = info.chunk_positions - - changes.append({ - "map_type": mm.map_type, - "map_index": mm.map_index, - "chunk_initial_datas": info.chunk_initial_datas, - "chunk_final_datas": info.chunk_final_datas - }) - - var cs := get_undo_chunk_size() - for pos in info.chunk_positions: - var rect = Rect2(pos * cs, Vector2(cs, cs)) - # This will update vertical bounds and notify normal map baker, - # since the latter updates out of order for preview - terrain_data.notify_region_change(rect, mm.map_type, mm.map_index, false, true) - -# for i in len(_painters): -# var p = _painters[i] -# if p.has_modified_chunks(): -# print("Painter ", i, " has modified chunks") - - # `commit()` is supposed to consume these chunks, there should be none left - assert(not has_modified_chunks()) - - return { - "chunk_positions": chunk_positions, - "maps": changes - } - - -func set_mode(mode: int): - assert(mode >= 0 and mode < MODE_COUNT) - _mode = mode - - -func get_mode() -> int: - return _mode - - -func set_terrain(terrain: HTerrain): - if terrain == _terrain: - return - _terrain = terrain - # It's important to release resources here, - # otherwise Godot keeps modified terrain maps in memory and "reloads" them like that - # next time we reopen the scene, even if we didn't save it - for p in _painters: - p.set_image(null, null) - p.clear_brush_shader_params() - - -# This may be called from an `_input` callback. -# Returns `true` if any change was performed. -func paint_input(position: Vector2, pressure: float) -> bool: - assert(_terrain.get_data() != null) - var data := _terrain.get_data() - assert(not data.is_locked()) - - if not _brush.configure_paint_input(_painters, position, pressure): - # Sometimes painting may not happen due to frequency options - return false - - _modified_maps.clear() - - match _mode: - MODE_RAISE: - _paint_height(data, position, 1.0) - - MODE_LOWER: - _paint_height(data, position, -1.0) - - MODE_SMOOTH: - _paint_smooth(data, position) - - MODE_FLATTEN: - _paint_flatten(data, position) - - MODE_LEVEL: - _paint_level(data, position) - - MODE_ERODE: - _paint_erode(data, position) - - MODE_SPLAT: - # TODO Properly support what happens when painting outside of supported index - # var supported_slots_count := terrain.get_cached_ground_texture_slot_count() - # if _texture_index >= supported_slots_count: - # _logger.debug("Painting out of range of supported texture slots: {0}/{1}" \ - # .format([_texture_index, supported_slots_count])) - # return - if _terrain.is_using_indexed_splatmap(): - _paint_splat_indexed(data, position) - else: - var splatmap_count := _terrain.get_used_splatmaps_count() - match splatmap_count: - 1: - _paint_splat4(data, position) - 4: - _paint_splat16(data, position) - - MODE_COLOR: - _paint_color(data, position) - - MODE_MASK: - _paint_mask(data, position) - - MODE_DETAIL: - _paint_detail(data, position) - - _: - _logger.error("Unknown mode {0}".format([_mode])) - - assert(len(_modified_maps) > 0) - return true - - -func _on_painter_texture_region_changed(rect: Rect2, painter_index: int): - var data := _terrain.get_data() - if data == null: - return - for mm in _modified_maps: - if mm.painter_index == painter_index: - # This will tell auto-baked maps to update (like normals). - data.notify_region_change(rect, mm.map_type, mm.map_index, false, false) - break - - -func _paint_height(data: HTerrainData, position: Vector2, factor: float): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - # When using sculpting tools, make it dependent on brush size - var raise_strength := 10.0 + float(_brush.get_size()) - var delta := factor * (2.0 / 60.0) * raise_strength - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_RaiseShader) - p.set_brush_shader_param("u_factor", delta) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_smooth(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_SmoothShader) - p.set_brush_shader_param("u_factor", 1.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_flatten(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_FlattenShader) - p.set_brush_shader_param("u_flatten_value", _flatten_height) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_level(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_LevelShader) - p.set_brush_shader_param("u_factor", (10.0 / 60.0)) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_erode(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_HEIGHT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_ErodeShader) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_splat4(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_SPLAT) - var texture := data.get_texture(HTerrainData.CHANNEL_SPLAT, 0, true) - var heightmap_texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_SPLAT - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - var splat := Color(0.0, 0.0, 0.0, 0.0) - splat[_texture_index] = 1.0; - p.set_brush_shader(HT_Splat4Shader) - p.set_brush_shader_param("u_splat", splat) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_splat_indexed(data: HTerrainData, position: Vector2): - var map_types := [ - HTerrainData.CHANNEL_SPLAT_INDEX, - HTerrainData.CHANNEL_SPLAT_WEIGHT - ] - _modified_maps = [] - - var textures := [] - for mode in 2: - textures.append(data.get_texture(map_types[mode], 0, true)) - - for mode in 2: - var image := data.get_image(map_types[mode]) - - var mm := HT_ModifiedMap.new() - mm.map_type = map_types[mode] - mm.map_index = 0 - mm.painter_index = mode - _modified_maps.append(mm) - - var p : HT_Painter = _painters[mode] - - p.set_brush_shader(HT_SplatIndexedShader) - p.set_brush_shader_param("u_mode", mode) - p.set_brush_shader_param("u_index_map", textures[0]) - p.set_brush_shader_param("u_weight_map", textures[1]) - p.set_brush_shader_param("u_texture_index", _texture_index) - p.set_image(image, textures[mode]) - p.paint_input(position) - - -func _paint_splat16(data: HTerrainData, position: Vector2): - # Make sure required maps are present - while data.get_map_count(HTerrainData.CHANNEL_SPLAT) < 4: - data._edit_add_map(HTerrainData.CHANNEL_SPLAT) - - var splats := [] - for i in 4: - splats.append(Color(0.0, 0.0, 0.0, 0.0)) - splats[_texture_index / 4][_texture_index % 4] = 1.0 - - var textures := [] - for i in 4: - textures.append(data.get_texture(HTerrainData.CHANNEL_SPLAT, i, true)) - - var heightmap_texture := data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - for i in 4: - var image : Image = data.get_image(HTerrainData.CHANNEL_SPLAT, i) - var texture : Texture = textures[i] - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_SPLAT - mm.map_index = i - mm.painter_index = i - _modified_maps.append(mm) - - var p : HT_Painter = _painters[i] - - var other_splatmaps := [] - for tex in textures: - if tex != texture: - other_splatmaps.append(tex) - - p.set_brush_shader(HT_Splat16Shader) - p.set_brush_shader_param("u_splat", splats[i]) - p.set_brush_shader_param("u_other_splatmap_1", other_splatmaps[0]) - p.set_brush_shader_param("u_other_splatmap_2", other_splatmaps[1]) - p.set_brush_shader_param("u_other_splatmap_3", other_splatmaps[2]) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_color(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_COLOR) - var texture := data.get_texture(HTerrainData.CHANNEL_COLOR, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_COLOR - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - # There was a problem with painting colors because of sRGB - # https://github.com/Zylann/godot_heightmap_plugin/issues/17#issuecomment-734001879 - - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", _color) - p.set_brush_shader_param("u_normal_min_y", 0.0) - p.set_brush_shader_param("u_normal_max_y", 1.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_mask(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_COLOR) - var texture := data.get_texture(HTerrainData.CHANNEL_COLOR, 0, true) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_COLOR - mm.map_index = 0 - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - - p.set_brush_shader(HT_AlphaShader) - p.set_brush_shader_param("u_value", 1.0 if _mask_flag else 0.0) - p.set_image(image, texture) - p.paint_input(position) - - -func _paint_detail(data: HTerrainData, position: Vector2): - var image := data.get_image(HTerrainData.CHANNEL_DETAIL, _detail_index) - var texture := data.get_texture(HTerrainData.CHANNEL_DETAIL, _detail_index, true) - var heightmap_texture = data.get_texture(HTerrainData.CHANNEL_HEIGHT, 0) - - var mm := HT_ModifiedMap.new() - mm.map_type = HTerrainData.CHANNEL_DETAIL - mm.map_index = _detail_index - mm.painter_index = 0 - _modified_maps = [mm] - - var p : HT_Painter = _painters[0] - var c := Color(_detail_density, _detail_density, _detail_density, 1.0) - - # TODO Don't use this shader (why?) - p.set_brush_shader(HT_ColorShader) - p.set_brush_shader_param("u_color", c) - _set_slope_limit_shader_params(p, heightmap_texture) - p.set_image(image, texture) - p.paint_input(position) - - -func _set_slope_limit_shader_params(p: HT_Painter, heightmap_texture: Texture): - p.set_brush_shader_param("u_normal_min_y", cos(_slope_limit_high_angle)) - p.set_brush_shader_param("u_normal_max_y", cos(_slope_limit_low_angle) + 0.001) - p.set_brush_shader_param("u_heightmap", heightmap_texture) diff --git a/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd.uid b/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd.uid deleted file mode 100644 index fbca307..0000000 --- a/godot/addons/zylann.hterrain/tools/brush/terrain_painter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dymrcrrcji2od diff --git a/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader b/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader deleted file mode 100644 index b0c97da..0000000 --- a/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader +++ /dev/null @@ -1,25 +0,0 @@ -shader_type canvas_item; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -vec4 pack_normal(vec3 n) { - return vec4((0.5 * (n + 1.0)).xzy, 1.0); -} - -float get_height(sampler2D tex, vec2 uv) { - return sample_heightmap(tex, uv); -} - -void fragment() { - vec2 uv = UV; - vec2 ps = TEXTURE_PIXEL_SIZE; - float left = get_height(TEXTURE, uv + vec2(-ps.x, 0)); - float right = get_height(TEXTURE, uv + vec2(ps.x, 0)); - float back = get_height(TEXTURE, uv + vec2(0, -ps.y)); - float fore = get_height(TEXTURE, uv + vec2(0, ps.y)); - vec3 n = normalize(vec3(left - right, 2.0, fore - back)); - COLOR = pack_normal(n); - // DEBUG - //COLOR.r = fract(TIME * 100.0); -} - diff --git a/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader.uid b/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader.uid deleted file mode 100644 index bd7c1ad..0000000 --- a/godot/addons/zylann.hterrain/tools/bump2normal_tex.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://ctymss7mxhrmh diff --git a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd b/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd deleted file mode 100644 index b462768..0000000 --- a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd +++ /dev/null @@ -1,202 +0,0 @@ -@tool -extends Control - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HTerrainDetailLayer = preload("../../hterrain_detail_layer.gd") -const HT_ImageFileCache = preload("../../util/image_file_cache.gd") -const HT_EditorUtil = preload("../util/editor_util.gd") -const HT_Logger = preload("../../util/logger.gd") - -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const PLACEHOLDER_ICON_TEXTURE = "res://addons/zylann.hterrain/tools/icons/icon_grass.svg" -const DETAIL_LAYER_ICON_TEXTURE = \ - "res://addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg" - -signal detail_selected(index) -# Emitted when the tool added or removed a detail map -signal detail_list_changed - -@onready var _item_list: ItemList = $ItemList -@onready var _confirmation_dialog: ConfirmationDialog = $ConfirmationDialog - -var _terrain: HTerrain = null -var _dialog_target := -1 -var _undo_redo_manager: EditorUndoRedoManager -var _image_cache: HT_ImageFileCache -var _logger = HT_Logger.get_for(self) - - -func set_terrain(terrain): - if _terrain == terrain: - return - _terrain = terrain - _update_list() - - -func set_undo_redo(ur: EditorUndoRedoManager): - assert(ur != null) - _undo_redo_manager = ur - - -func set_image_cache(image_cache: HT_ImageFileCache): - _image_cache = image_cache - - -func set_layer_index(i: int): - _item_list.select(i, true) - - -func _update_list(): - _item_list.clear() - - if _terrain == null: - return - - var layer_nodes = _terrain.get_detail_layers() - var layer_nodes_by_index := {} - for layer in layer_nodes: - if not layer_nodes_by_index.has(layer.layer_index): - layer_nodes_by_index[layer.layer_index] = [] - layer_nodes_by_index[layer.layer_index].append(layer.name) - - var data = _terrain.get_data() - if data != null: - # Display layers from what terrain data actually contains, - # because layer nodes are just what makes them rendered and aren't much restricted. - var layer_count = data.get_map_count(HTerrainData.CHANNEL_DETAIL) - var placeholder_icon = HT_EditorUtil.load_texture(PLACEHOLDER_ICON_TEXTURE, _logger) - - for i in layer_count: - # TODO Show a preview icon - _item_list.add_item(str("Map ", i), placeholder_icon) - - if layer_nodes_by_index.has(i): - # TODO How to keep names updated with node names? - var names := ", ".join(PackedStringArray(layer_nodes_by_index[i])) - if len(names) == 1: - _item_list.set_item_tooltip(i, "Used by " + names) - else: - _item_list.set_item_tooltip(i, "Used by " + names) - # Remove custom color - # TODO Use fg version when available in Godot 3.1, I want to only highlight text - _item_list.set_item_custom_bg_color(i, Color(0, 0, 0, 0)) - else: - # TODO Use fg version when available in Godot 3.1, I want to only highlight text - _item_list.set_item_custom_bg_color(i, Color(1.0, 0.2, 0.2, 0.3)) - _item_list.set_item_tooltip(i, "This map isn't used by any layer. " \ - +"Add a HTerrainDetailLayer node as child of the terrain.") - - -func _on_Add_pressed(): - _add_layer() - - -func _on_Remove_pressed(): - var selected = _item_list.get_selected_items() - if len(selected) == 0: - return - _dialog_target = _item_list.get_selected_items()[0] - _confirmation_dialog.title = "Removing detail map {0}".format([_dialog_target]) - _confirmation_dialog.popup_centered() - - -func _on_ConfirmationDialog_confirmed(): - _remove_layer(_dialog_target) - - -func _add_layer(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - assert(_undo_redo_manager != null) - var terrain_data: HTerrainData = _terrain.get_data() - - # First, create node and map image - var node := HTerrainDetailLayer.new() - # TODO Workarounds for https://github.com/godotengine/godot/issues/21410 - var detail_layer_icon := HT_EditorUtil.load_texture(DETAIL_LAYER_ICON_TEXTURE, _logger) - node.set_meta("_editor_icon", detail_layer_icon) - node.name = "HTerrainDetailLayer" - var map_index := terrain_data._edit_add_map(HTerrainData.CHANNEL_DETAIL) - var map_image := terrain_data.get_image(HTerrainData.CHANNEL_DETAIL, map_index) - var map_image_cache_id := _image_cache.save_image(map_image) - node.layer_index = map_index - - # var max_seed := 0 - # for dl in _terrain.get_detail_layers(): - # max_seed = maxi(dl.fixed_seed, max_seed) - # node.fixed_seed = max_seed + 1 - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_terrain)) - - # Then, create an action - undo_redo.create_action("Add Detail Layer {0}".format([map_index])) - - undo_redo.add_do_method(terrain_data._edit_insert_map_from_image_cache.bind( - HTerrainData.CHANNEL_DETAIL, map_index, _image_cache, map_image_cache_id)) - undo_redo.add_do_method(_terrain.add_child.bind(node, true)) - undo_redo.add_do_property(node, "owner", get_tree().edited_scene_root) - undo_redo.add_do_method(self._update_list) - undo_redo.add_do_reference(node) - - undo_redo.add_undo_method(_terrain.remove_child.bind(node)) - undo_redo.add_undo_method( - terrain_data._edit_remove_map.bind(HTerrainData.CHANNEL_DETAIL, map_index)) - undo_redo.add_undo_method(self._update_list) - - # Yet another instance of this hack, to prevent UndoRedo from running some of the functions, - # which we had to run already - terrain_data._edit_set_disable_apply_undo(true) - undo_redo.commit_action() - terrain_data._edit_set_disable_apply_undo(false) - - #_update_list() - detail_list_changed.emit() - - var index := node.layer_index - _item_list.select(index) - # select() doesn't trigger the signal - detail_selected.emit(index) - - -func _remove_layer(map_index: int): - var terrain_data: HTerrainData = _terrain.get_data() - - # First, cache image data - var image := terrain_data.get_image(HTerrainData.CHANNEL_DETAIL, map_index) - var image_id := _image_cache.save_image(image) - var nodes = _terrain.get_detail_layers() - var using_nodes := [] - # Nodes using this map will be removed from the tree - for node in nodes: - if node.layer_index == map_index: - using_nodes.append(node) - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_terrain)) - - undo_redo.create_action("Remove Detail Layer {0}".format([map_index])) - - undo_redo.add_do_method( - terrain_data._edit_remove_map.bind(HTerrainData.CHANNEL_DETAIL, map_index)) - for node in using_nodes: - undo_redo.add_do_method(_terrain.remove_child.bind(node)) - undo_redo.add_do_method(self._update_list) - - undo_redo.add_undo_method(terrain_data._edit_insert_map_from_image_cache.bind( - HTerrainData.CHANNEL_DETAIL, map_index, _image_cache, image_id)) - for node in using_nodes: - undo_redo.add_undo_method(_terrain.add_child.bind(node)) - undo_redo.add_undo_property(node, "owner", get_tree().edited_scene_root) - undo_redo.add_undo_reference(node) - undo_redo.add_undo_method(self._update_list) - - undo_redo.commit_action() - - #_update_list() - detail_list_changed.emit() - - -func _on_ItemList_item_selected(index): - detail_selected.emit(index) diff --git a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd.uid b/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd.uid deleted file mode 100644 index aef4f7e..0000000 --- a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://rw56r85jyb6b diff --git a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn b/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn deleted file mode 100644 index cc5b995..0000000 --- a/godot/addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn +++ /dev/null @@ -1,48 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://do3c3jse5p7hx"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/detail_editor/detail_editor.gd" id="1"] - -[node name="DetailEditor" type="Control"] -custom_minimum_size = Vector2(200, 0) -layout_mode = 3 -anchors_preset = 0 -offset_right = 189.0 -offset_bottom = 109.0 -script = ExtResource("1") - -[node name="ItemList" type="ItemList" parent="."] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_bottom = -26.0 -max_columns = 0 -same_column_width = true -icon_mode = 0 -fixed_icon_size = Vector2i(32, 32) - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 0 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -24.0 - -[node name="Add" type="Button" parent="HBoxContainer"] -layout_mode = 2 -text = "Add" - -[node name="Remove" type="Button" parent="HBoxContainer"] -layout_mode = 2 -text = "Remove" - -[node name="Label" type="Label" parent="HBoxContainer"] -layout_mode = 2 -text = "Details" - -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] -dialog_text = "Are you sure you want to remove this detail map?" - -[connection signal="item_selected" from="ItemList" to="." method="_on_ItemList_item_selected"] -[connection signal="pressed" from="HBoxContainer/Add" to="." method="_on_Add_pressed"] -[connection signal="pressed" from="HBoxContainer/Remove" to="." method="_on_Remove_pressed"] -[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"] diff --git a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd b/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd deleted file mode 100644 index 1ebc177..0000000 --- a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd +++ /dev/null @@ -1,228 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") - -const FORMAT_RH = 0 -const FORMAT_RF = 1 -const FORMAT_R16 = 2 -const FORMAT_R32 = 3 -const FORMAT_PNG8 = 4 -const FORMAT_EXRH = 5 -const FORMAT_EXRF = 6 -const FORMAT_COUNT = 7 - -@onready var _output_path_line_edit := $VB/Grid/OutputPath/HeightmapPathLineEdit as LineEdit -@onready var _format_selector := $VB/Grid/FormatSelector as OptionButton -@onready var _height_range_min_spinbox := $VB/Grid/HeightRange/HeightRangeMin as SpinBox -@onready var _height_range_max_spinbox := $VB/Grid/HeightRange/HeightRangeMax as SpinBox -@onready var _export_button := $VB/Buttons/ExportButton as Button -@onready var _show_in_explorer_checkbox := $VB/ShowInExplorerCheckbox as CheckBox - -var _terrain : HTerrain = null -var _file_dialog : EditorFileDialog = null -var _format_names := [] -var _format_extensions := [] -var _logger = HT_Logger.get_for(self) - - -func _init(): - # Godot 4 decided to not have a plain WindowDialog class... - # there is Window but it's way too unfriendly... - get_ok_button().hide() - - -func _ready(): - _format_names.resize(FORMAT_COUNT) - _format_extensions.resize(FORMAT_COUNT) - - _format_names[FORMAT_RH] = "16-bit RAW float" - _format_names[FORMAT_RF] = "32-bit RAW float" - _format_names[FORMAT_R16] = "16-bit RAW int unsigned (little endian)" - _format_names[FORMAT_R32] = "32-bit RAW int unsigned (little endian)" - _format_names[FORMAT_PNG8] = "8-bit PNG greyscale" - _format_names[FORMAT_EXRH] = "16-bit float greyscale EXR" - _format_names[FORMAT_EXRF] = "32-bit float greyscale EXR" - - _format_extensions[FORMAT_RH] = "raw" - _format_extensions[FORMAT_RF] = "raw" - _format_extensions[FORMAT_R16] = "raw" - _format_extensions[FORMAT_R32] = "raw" - _format_extensions[FORMAT_PNG8] = "png" - _format_extensions[FORMAT_EXRH] = "exr" - _format_extensions[FORMAT_EXRF] = "exr" - - if not HT_Util.is_in_edited_scene(self): - for i in len(_format_names): - _format_selector.get_popup().add_item(_format_names[i], i) - - -func setup_dialogs(base_control: Control): - assert(_file_dialog == null) - var fd := EditorFileDialog.new() - fd.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE - fd.unresizable = false - fd.access = EditorFileDialog.ACCESS_FILESYSTEM - fd.file_selected.connect(_on_FileDialog_file_selected) - add_child(fd) - _file_dialog = fd - - _update_file_extension() - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _exit_tree(): - if _file_dialog != null: - _file_dialog.queue_free() - _file_dialog = null - - -func _on_FileDialog_file_selected(fpath: String): - _output_path_line_edit.text = fpath - - -func _auto_adjust_height_range(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - var aabb := _terrain.get_data().get_aabb() - _height_range_min_spinbox.value = aabb.position.y - _height_range_max_spinbox.value = aabb.position.y + aabb.size.y - - -func _export() -> bool: - assert(_terrain != null) - assert(_terrain.get_data() != null) - var src_heightmap: Image = _terrain.get_data().get_image(HTerrainData.CHANNEL_HEIGHT) - var fpath := _output_path_line_edit.text.strip_edges() - - # TODO Is `selected` an ID or an index? I need an ID, it works by chance for now. - var format := _format_selector.selected - - var height_min := _height_range_min_spinbox.value - var height_max := _height_range_max_spinbox.value - - if height_min == height_max: - _logger.error("Cannot export, height range is zero") - return false - - if height_min > height_max: - _logger.error("Cannot export, height min is greater than max") - return false - - var save_error := OK - - var float_heightmap := HTerrainData.convert_heightmap_to_float(src_heightmap, _logger) - - if format == FORMAT_PNG8: - var hscale := 1.0 / (height_max - height_min) - var im := Image.create( - src_heightmap.get_width(), src_heightmap.get_height(), false, - # Using L8 because when using R8 Godot saves as 24-bit per pixel (RGB8) - # which is wasteful - Image.FORMAT_L8) - - for y in src_heightmap.get_height(): - for x in src_heightmap.get_width(): - var h := clampf((float_heightmap.get_pixel(x, y).r - height_min) * hscale, 0.0, 1.0) - im.set_pixel(x, y, Color(h, h, h)) - - save_error = im.save_png(fpath) - - elif format == FORMAT_EXRH: - float_heightmap.convert(Image.FORMAT_RH) - save_error = float_heightmap.save_exr(fpath, true) - - elif format == FORMAT_EXRF: - save_error = float_heightmap.save_exr(fpath, true) - - else: # RAW - var f := FileAccess.open(fpath, FileAccess.WRITE) - if f == null: - var err := FileAccess.get_open_error() - _print_file_error(fpath, err) - return false - - if format == FORMAT_RH: - float_heightmap.convert(Image.FORMAT_RH) - f.store_buffer(float_heightmap.get_data()) - - elif format == FORMAT_RF: - f.store_buffer(float_heightmap.get_data()) - - elif format == FORMAT_R16: - var hscale := 65535.0 / (height_max - height_min) - for y in float_heightmap.get_height(): - for x in float_heightmap.get_width(): - var h := int((float_heightmap.get_pixel(x, y).r - height_min) * hscale) - f.store_16(clampi(h, 0, 65535)) - - elif format == FORMAT_R32: - var hscale := 4294967295.0 / (height_max - height_min) - for y in float_heightmap.get_height(): - for x in float_heightmap.get_width(): - var h := int((float_heightmap.get_pixel(x, y).r - height_min) * hscale) - f.store_32(clampi(h, 0, 4294967295)) - - if save_error == OK: - _logger.debug("Exported heightmap as \"{0}\"".format([fpath])) - return true - else: - _print_file_error(fpath, save_error) - return false - - -func _update_file_extension(): - if _format_selector.selected == -1: - _format_selector.selected = 0 - # This recursively calls the current function - return - - # TODO Is `selected` an ID or an index? I need an ID, it works by chance for now. - var format = _format_selector.selected - - var ext : String = _format_extensions[format] - _file_dialog.clear_filters() - _file_dialog.add_filter(str("*.", ext, " ; ", ext.to_upper(), " files")) - - var fpath := _output_path_line_edit.text.strip_edges() - if fpath != "": - _output_path_line_edit.text = str(fpath.get_basename(), ".", ext) - - -func _print_file_error(fpath: String, err: int): - _logger.error("Could not save path {0}, error: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - - -func _on_CancelButton_pressed(): - hide() - - -func _on_ExportButton_pressed(): - if _export(): - hide() - if _show_in_explorer_checkbox.button_pressed: - OS.shell_open(_output_path_line_edit.text.strip_edges().get_base_dir()) - - -func _on_HeightmapPathLineEdit_text_changed(new_text: String): - _export_button.disabled = (new_text.strip_edges() == "") - - -func _on_HeightmapPathBrowseButton_pressed(): - _file_dialog.popup_centered_ratio() - - -func _on_FormatSelector_item_selected(id): - _update_file_extension() - - -func _on_HeightRangeAutoButton_pressed(): - _auto_adjust_height_range() diff --git a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd.uid deleted file mode 100644 index 0ad010d..0000000 --- a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://co4m27d6vjsl5 diff --git a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn b/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn deleted file mode 100644 index a702181..0000000 --- a/godot/addons/zylann.hterrain/tools/exporter/export_image_dialog.tscn +++ /dev/null @@ -1,125 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bcocysgmum5ag"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/exporter/export_image_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="2"] - -[node name="ExportImageDialog" type="AcceptDialog"] -size = Vector2i(500, 340) -min_size = Vector2i(500, 250) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Grid" type="GridContainer" parent="VB"] -layout_mode = 2 -columns = 2 - -[node name="OutputPathLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Output path:" - -[node name="OutputPath" type="HBoxContainer" parent="VB/Grid"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HeightmapPathLineEdit" type="LineEdit" parent="VB/Grid/OutputPath"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="HeightmapPathBrowseButton" type="Button" parent="VB/Grid/OutputPath"] -layout_mode = 2 -text = "..." - -[node name="FormatLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Format:" - -[node name="FormatSelector" type="OptionButton" parent="VB/Grid"] -layout_mode = 2 - -[node name="HeightRangeLabel" type="Label" parent="VB/Grid"] -layout_mode = 2 -text = "Height range:" - -[node name="HeightRange" type="HBoxContainer" parent="VB/Grid"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/Grid/HeightRange"] -layout_mode = 2 -text = "Min" - -[node name="HeightRangeMin" type="SpinBox" parent="VB/Grid/HeightRange"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -min_value = -10000.0 -max_value = 10000.0 -step = 0.0 -value = -2000.0 - -[node name="Label2" type="Label" parent="VB/Grid/HeightRange"] -layout_mode = 2 -text = "Max" - -[node name="HeightRangeMax" type="SpinBox" parent="VB/Grid/HeightRange"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -min_value = -10000.0 -max_value = 10000.0 -step = 0.0 -value = 2000.0 - -[node name="HeightRangeAutoButton" type="Button" parent="VB/Grid/HeightRange"] -layout_mode = 2 -size_flags_horizontal = 3 -text = "Auto" - -[node name="ShowInExplorerCheckbox" type="CheckBox" parent="VB"] -layout_mode = 2 -text = "Show in explorer after export" - -[node name="Spacer" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Label" type="Label" parent="VB"] -layout_mode = 2 -text = "Note: height range is needed for integer image formats, as they can't directly represent the real height. 8-bit formats may cause precision loss." -autowrap_mode = 2 - -[node name="Spacer2" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Buttons" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 - -[node name="ExportButton" type="Button" parent="VB/Buttons"] -layout_mode = 2 -text = "Export" - -[node name="CancelButton" type="Button" parent="VB/Buttons"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("2")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 492.0 -offset_bottom = 322.0 - -[connection signal="text_changed" from="VB/Grid/OutputPath/HeightmapPathLineEdit" to="." method="_on_HeightmapPathLineEdit_text_changed"] -[connection signal="pressed" from="VB/Grid/OutputPath/HeightmapPathBrowseButton" to="." method="_on_HeightmapPathBrowseButton_pressed"] -[connection signal="item_selected" from="VB/Grid/FormatSelector" to="." method="_on_FormatSelector_item_selected"] -[connection signal="pressed" from="VB/Grid/HeightRange/HeightRangeAutoButton" to="." method="_on_HeightRangeAutoButton_pressed"] -[connection signal="pressed" from="VB/Buttons/ExportButton" to="." method="_on_ExportButton_pressed"] -[connection signal="pressed" from="VB/Buttons/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd b/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd deleted file mode 100644 index f567e02..0000000 --- a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd +++ /dev/null @@ -1,54 +0,0 @@ -@tool -extends AcceptDialog - -signal generate_selected(lod) - -const HTerrain = preload("../hterrain.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HT_Util = preload("../util/util.gd") - -@onready var _preview_label : Label = $VBoxContainer/PreviewLabel -@onready var _lod_spinbox : SpinBox = $VBoxContainer/HBoxContainer/LODSpinBox - -var _terrain : HTerrain = null - - -func _init(): - get_ok_button().hide() - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - if visible and _terrain != null: - _update_preview() - - -func _on_LODSpinBox_value_changed(value): - _update_preview() - - -func _update_preview(): - assert(_terrain != null) - assert(_terrain.get_data() != null) - var resolution := _terrain.get_data().get_resolution() - var stride := int(_lod_spinbox.value) - resolution /= stride - var s := HTerrainMesher.get_mesh_size(resolution, resolution) - _preview_label.text = str( \ - HT_Util.format_integer(s.vertices), " vertices, ", \ - HT_Util.format_integer(s.triangles), " triangles") - - -func _on_Generate_pressed(): - var stride := int(_lod_spinbox.value) - generate_selected.emit(stride) - hide() - - -func _on_Cancel_pressed(): - hide() - diff --git a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd.uid deleted file mode 100644 index 1e19eec..0000000 --- a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2ofo34bml3us diff --git a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn b/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn deleted file mode 100644 index 12f3d4a..0000000 --- a/godot/addons/zylann.hterrain/tools/generate_mesh_dialog.tscn +++ /dev/null @@ -1,69 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://ci0da54goyo5o"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/generate_mesh_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="2"] - -[node name="GenerateMeshDialog" type="AcceptDialog"] -title = "Generate full mesh" -size = Vector2i(448, 234) -min_size = Vector2i(448, 186) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "LOD" - -[node name="LODSpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -min_value = 1.0 -max_value = 16.0 -value = 1.0 - -[node name="PreviewLabel" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "9999 vertices, 9999 triangles" - -[node name="Spacer" type="Control" parent="VBoxContainer"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "Note: generating a full mesh from the terrain may result in a huge amount of vertices for a single object. It is preferred to do this for small terrains, or as a temporary workaround to generate a navmesh." -autowrap_mode = 2 - -[node name="Buttons" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="Generate" type="Button" parent="VBoxContainer/Buttons"] -layout_mode = 2 -text = "Generate" - -[node name="Cancel" type="Button" parent="VBoxContainer/Buttons"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("2")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 440.0 -offset_bottom = 216.0 - -[connection signal="value_changed" from="VBoxContainer/HBoxContainer/LODSpinBox" to="." method="_on_LODSpinBox_value_changed"] -[connection signal="pressed" from="VBoxContainer/Buttons/Generate" to="." method="_on_Generate_pressed"] -[connection signal="pressed" from="VBoxContainer/Buttons/Cancel" to="." method="_on_Cancel_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd b/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd deleted file mode 100644 index bbb7069..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd +++ /dev/null @@ -1,562 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HTerrainMesher = preload("../../hterrain_mesher.gd") -const HT_Util = preload("../../util/util.gd") -const HT_TextureGenerator = preload("./texture_generator.gd") -const HT_TextureGeneratorPass = preload("./texture_generator_pass.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_ImageFileCache = preload("../../util/image_file_cache.gd") -const HT_Inspector = preload("../inspector/inspector.gd") -const HT_TerrainPreview = preload("../terrain_preview.gd") -const HT_ProgressWindow = preload("../progress_window.gd") - -const HT_ProgressWindowScene = preload("../progress_window.tscn") - -# TODO Power of two is assumed here. -# I wonder why it doesn't have the off by one terrain textures usually have -const MAX_VIEWPORT_RESOLUTION = 512 - -#signal progress_notified(info) # { "progress": real, "message": string, "finished": bool } - -@onready var _inspector_container : Control = $VBoxContainer/Editor/Settings -@onready var _inspector : HT_Inspector = $VBoxContainer/Editor/Settings/Inspector -@onready var _preview : HT_TerrainPreview = $VBoxContainer/Editor/Preview/TerrainPreview -@onready var _progress_bar : ProgressBar = $VBoxContainer/Editor/Preview/ProgressBar - -var _dummy_texture = load("res://addons/zylann.hterrain/tools/icons/empty.png") -var _terrain : HTerrain = null -var _applying := false -var _generator : HT_TextureGenerator -var _generated_textures := [null, null] -var _dialog_visible := false -var _undo_map_ids := {} -var _image_cache : HT_ImageFileCache = null -var _undo_redo_manager : EditorUndoRedoManager -var _logger := HT_Logger.get_for(self) -var _viewport_resolution := MAX_VIEWPORT_RESOLUTION -var _progress_window : HT_ProgressWindow - - -static func get_shader(shader_name: String) -> Shader: - var path := "res://addons/zylann.hterrain/tools/generator/shaders"\ - .path_join(str(shader_name, ".gdshader")) - return load(path) as Shader - - -func _init(): - # Godot 4 does not have a plain WindowDialog class... there is Window but it's too unfriendly... - get_ok_button().hide() - - _progress_window = HT_ProgressWindowScene.instantiate() - add_child(_progress_window) - - -func _ready(): - _inspector.set_prototype({ - "seed": { - "type": TYPE_INT, - "randomizable": true, - "range": { "min": -100, "max": 100 }, - "slidable": false - }, - "offset": { - "type": TYPE_VECTOR2 - }, - "base_height": { - "type": TYPE_FLOAT, - "range": {"min": -500.0, "max": 500.0, "step": 0.1 }, - "default_value": -50.0 - }, - "height_range": { - "type": TYPE_FLOAT, - "range": {"min": 0.0, "max": 2000.0, "step": 0.1 }, - "default_value": 150.0 - }, - "scale": { - "type": TYPE_FLOAT, - "range": {"min": 1.0, "max": 1000.0, "step": 1.0}, - "default_value": 100.0 - }, - "roughness": { - "type": TYPE_FLOAT, - "range": {"min": 0.0, "max": 1.0, "step": 0.01}, - "default_value": 0.4 - }, - "curve": { - "type": TYPE_FLOAT, - "range": {"min": 1.0, "max": 10.0, "step": 0.1}, - "default_value": 1.0 - }, - "octaves": { - "type": TYPE_INT, - "range": {"min": 1, "max": 10, "step": 1}, - "default_value": 6 - }, - "erosion_steps": { - "type": TYPE_INT, - "range": {"min": 0, "max": 100, "step": 1}, - "default_value": 0 - }, - "erosion_weight": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.5 - }, - "erosion_slope_factor": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.0 - }, - "erosion_slope_direction": { - "type": TYPE_VECTOR2, - "default_value": Vector2(0, 0) - }, - "erosion_slope_invert": { - "type": TYPE_BOOL, - "default_value": false - }, - "dilation": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0 }, - "default_value": 0.0 - }, - "island_weight": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "island_sharpness": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "island_height_ratio": { - "type": TYPE_FLOAT, - "range": { "min": -1.0, "max": 1.0, "step": 0.01 }, - "default_value": -1.0 - }, - "island_shape": { - "type": TYPE_FLOAT, - "range": { "min": 0.0, "max": 1.0, "step": 0.01 }, - "default_value": 0.0 - }, - "additive_heightmap": { - "type": TYPE_BOOL, - "default_value": false - }, - "show_sea": { - "type": TYPE_BOOL, - "default_value": true - }, - "shadows": { - "type": TYPE_BOOL, - "default_value": true - } - }) - - _generator = HT_TextureGenerator.new() - _generator.set_resolution(Vector2i(_viewport_resolution, _viewport_resolution)) - # Setup the extra pixels we want on max edges for terrain - # TODO I wonder if it's not better to let the generator shaders work in pixels - # instead of NDC, rather than putting a padding system there - _generator.set_output_padding([0, 1, 0, 1]) - _generator.output_generated.connect(_on_TextureGenerator_output_generated) - _generator.completed.connect(_on_TextureGenerator_completed) - _generator.progress_reported.connect(_on_TextureGenerator_progress_reported) - add_child(_generator) - - # TEST - if not Engine.is_editor_hint(): - call_deferred("popup_centered") - - -func apply_dpi_scale(dpi_scale: float): - min_size *= dpi_scale - _inspector_container.custom_minimum_size *= dpi_scale - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - _adjust_viewport_resolution() - - -func _adjust_viewport_resolution(): - if _terrain == null: - return - var data = _terrain.get_data() - if data == null: - return - var terrain_resolution := data.get_resolution() - - # By default we want to work with a large enough viewport to generate tiles, - # but we should pick a smaller size if the terrain is smaller than that... - var vp_res := MAX_VIEWPORT_RESOLUTION - while vp_res > terrain_resolution: - vp_res /= 2 - - _generator.set_resolution(Vector2(vp_res, vp_res)) - _viewport_resolution = vp_res - - -func set_image_cache(image_cache: HT_ImageFileCache): - _image_cache = image_cache - - -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func _notification(what: int): - match what: - NOTIFICATION_VISIBILITY_CHANGED: - # We don't want any of this to run in an edited scene - if HT_Util.is_in_edited_scene(self): - return - # Since Godot 4 visibility can be changed even between _enter_tree and _ready - if _preview == null: - return - - if visible: - # TODO https://github.com/godotengine/godot/issues/18160 - if _dialog_visible: - return - _dialog_visible = true - - _adjust_viewport_resolution() - - _preview.set_sea_visible(_inspector.get_value("show_sea")) - _preview.set_shadows_enabled(_inspector.get_value("shadows")) - - _update_generator(true) - - else: -# if not _applying: -# _destroy_viewport() - _preview.cleanup() - for i in len(_generated_textures): - _generated_textures[i] = null - _dialog_visible = false - - -func _update_generator(preview: bool): - var scale : float = _inspector.get_value("scale") - # Scale is inverted in the shader - if absf(scale) < 0.01: - scale = 0.0 - else: - scale = 1.0 / scale - scale *= _viewport_resolution - - var preview_scale := 4.0 # As if 2049x2049 - var sectors := [] - var terrain_size := 513 - - var additive_heightmap : Texture2D = null - - # For testing - if not Engine.is_editor_hint() and _terrain == null: - sectors.append(Vector2(0, 0)) - - # Get preview scale and sectors to generate. - # Allowing null terrain to make it testable. - if _terrain != null and _terrain.get_data() != null: - var terrain_data := _terrain.get_data() - terrain_size = terrain_data.get_resolution() - - if _inspector.get_value("additive_heightmap"): - additive_heightmap = terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - if preview: - # When previewing the resolution does not span the entire terrain, - # so we apply a scale to some of the passes to make it cover it all. - preview_scale = float(terrain_size) / float(_viewport_resolution) - sectors.append(Vector2(0, 0)) - - else: - if additive_heightmap != null: - # We have to duplicate the heightmap because we are going to write - # into it during the generation process. - # It would be fine when we don't read outside of a generated tile, - # but we actually do that for erosion: neighboring pixels are read - # again, and if they were modified by a previous tile it will - # disrupt generation, so we need to use a copy of the original. - additive_heightmap = additive_heightmap.duplicate() - - # When we get to generate it fully, sectors are used, - # so the size or shape of the terrain doesn't matter - preview_scale = 1.0 - - var cw := terrain_size / _viewport_resolution - var ch := terrain_size / _viewport_resolution - - for y in ch: - for x in cw: - sectors.append(Vector2(x, y)) - - var erosion_iterations := int(_inspector.get_value("erosion_steps")) - erosion_iterations /= int(preview_scale) - - _generator.clear_passes() - - # Terrain textures need to have an off-by-one on their max edge, - # which is shared with the other sectors. - var base_offset_ndc = _inspector.get_value("offset") - #var sector_size_offby1_ndc = float(VIEWPORT_RESOLUTION - 1) / padded_viewport_resolution - - for i in len(sectors): - var sector = sectors[i] - #var offset = sector * sector_size_offby1_ndc - Vector2(pad_offset_ndc, pad_offset_ndc) - -# var offset_px = sector * (VIEWPORT_RESOLUTION - 1) - Vector2(pad_offset_px, pad_offset_px) -# var offset_ndc = offset_px / padded_viewport_resolution - var progress := float(i) / len(sectors) - var p := HT_TextureGeneratorPass.new() - p.clear = true - p.shader = get_shader("perlin_noise") - # This pass generates the shapes of the terrain so will have to account for offset - p.tile_pos = sector - p.params = { - "u_octaves": _inspector.get_value("octaves"), - "u_seed": _inspector.get_value("seed"), - "u_scale": scale, - "u_offset": base_offset_ndc, - "u_base_height": _inspector.get_value("base_height") / preview_scale, - "u_height_range": _inspector.get_value("height_range") / preview_scale, - "u_roughness": _inspector.get_value("roughness"), - "u_curve": _inspector.get_value("curve"), - "u_island_weight": _inspector.get_value("island_weight"), - "u_island_sharpness": _inspector.get_value("island_sharpness"), - "u_island_height_ratio": _inspector.get_value("island_height_ratio"), - "u_island_shape": _inspector.get_value("island_shape"), - "u_additive_heightmap": additive_heightmap, - "u_additive_heightmap_factor": \ - (1.0 if additive_heightmap != null else 0.0) / preview_scale, - "u_terrain_size": terrain_size / preview_scale, - "u_tile_size": _viewport_resolution - } - _generator.add_pass(p) - - if erosion_iterations > 0: - p = HT_TextureGeneratorPass.new() - p.shader = get_shader("erode") - # TODO More erosion config - p.params = { - "u_slope_factor": _inspector.get_value("erosion_slope_factor"), - "u_slope_invert": _inspector.get_value("erosion_slope_invert"), - "u_slope_up": _inspector.get_value("erosion_slope_direction"), - "u_weight": _inspector.get_value("erosion_weight"), - "u_dilation": _inspector.get_value("dilation") - } - p.iterations = erosion_iterations - p.padding = p.iterations - _generator.add_pass(p) - - _generator.add_output({ - "maptype": HTerrainData.CHANNEL_HEIGHT, - "sector": sector, - "progress": progress - }) - - p = HT_TextureGeneratorPass.new() - p.shader = get_shader("bump2normal") - p.padding = 1 - _generator.add_pass(p) - - _generator.add_output({ - "maptype": HTerrainData.CHANNEL_NORMAL, - "sector": sector, - "progress": progress - }) - - # TODO AO generation - # TODO Splat generation - _generator.run() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_ApplyButton_pressed(): - # We used to hide the dialog when the Apply button is clicked, and then texture generation took - # place in an offscreen viewport in multiple tiled stages, with a progress window being shown. - # But in Godot 4, it turns out SubViewports never update if they are child of a hidden Window, - # even if they are set to UPDATE_ALWAYS... - #hide() - - _apply() - - -func _on_Inspector_property_changed(key, value): - match key: - "show_sea": - _preview.set_sea_visible(value) - "shadows": - _preview.set_shadows_enabled(value) - _: - _update_generator(true) - - -func _on_TerrainPreview_dragged(relative: Vector2, button_mask: int): - if button_mask & MOUSE_BUTTON_MASK_LEFT: - var offset : Vector2 = _inspector.get_value("offset") - offset += relative - _inspector.set_value("offset", offset) - - -func _apply(): - if _terrain == null: - _logger.error("cannot apply, terrain is null") - return - - var data := _terrain.get_data() - if data == null: - _logger.error("cannot apply, terrain data is null") - return - - var dst_heights := data.get_image(HTerrainData.CHANNEL_HEIGHT) - if dst_heights == null: - _logger.error("terrain heightmap image isn't loaded") - return - - var dst_normals := data.get_image(HTerrainData.CHANNEL_NORMAL) - if dst_normals == null: - _logger.error("terrain normal image isn't loaded") - return - - _applying = true - - _undo_map_ids[HTerrainData.CHANNEL_HEIGHT] = _image_cache.save_image(dst_heights) - _undo_map_ids[HTerrainData.CHANNEL_NORMAL] = _image_cache.save_image(dst_normals) - - _update_generator(false) - - -func _on_TextureGenerator_progress_reported(info: Dictionary): - if _applying: - return - var p := 0.0 - if info.pass_index == 1: - p = float(info.iteration) / float(info.iteration_count) - _progress_bar.show() - _progress_bar.ratio = p - - -func _on_TextureGenerator_output_generated(image: Image, info: Dictionary): - # TODO We should check the terrain's image format, - # but that would prevent from testing in isolation... - if info.maptype == HTerrainData.CHANNEL_HEIGHT: - # Hack to workaround Godot 4.0 not supporting RF viewports. Heights are packed as floats - # into RGBA8 components. - assert(image.get_format() == Image.FORMAT_RGBA8) - image = Image.create_from_data(image.get_width(), image.get_height(), false, - Image.FORMAT_RF, image.get_data()) - - if not _applying: - # Update preview - # TODO Improve TextureGenerator so we can get a ViewportTexture per output? - var tex = _generated_textures[info.maptype] - if tex == null: - tex = ImageTexture.create_from_image(image) - _generated_textures[info.maptype] = tex - else: - tex.update(image) - - var num_set := 0 - for v in _generated_textures: - if v != null: - num_set += 1 - if num_set == len(_generated_textures): - _preview.setup( \ - _generated_textures[HTerrainData.CHANNEL_HEIGHT], - _generated_textures[HTerrainData.CHANNEL_NORMAL]) - else: - assert(_terrain != null) - var data := _terrain.get_data() - assert(data != null) - var dst := data.get_image(info.maptype) - assert(dst != null) -# print("Tile ", info.sector) -# image.save_png(str("debug_generator_tile_", -# info.sector.x, "_", info.sector.y, "_map", info.maptype, ".png")) - - # Converting in case Viewport texture isn't the format we expect for this map. - # Note, in Godot 4 it seems the chosen renderer also influences what you get. - # Forward+ non-transparent viewport gives RGB8, but Compatibility gives RGBA8. - # I don't know if it's expected or is a bug... - # Also, since RF heightmaps we use RGBA8 so we can pack floats in pixels, because - # Godot 4.0 does not support RF viewports. But that also means the same viewport may be - # re-used for other maps that don't need to be RGBA8. - if image.get_format() != dst.get_format(): - image.convert(dst.get_format()) - - dst.blit_rect(image, \ - Rect2i(0, 0, image.get_width(), image.get_height()), \ - info.sector * _viewport_resolution) - - _notify_progress({ - "progress": info.progress, - "message": "Calculating sector (" - + str(info.sector.x) + ", " + str(info.sector.y) + ")" - }) - -# if info.maptype == HTerrainData.CHANNEL_NORMAL: -# image.save_png(str("normal_sector_", info.sector.x, "_", info.sector.y, ".png")) - - -func _on_TextureGenerator_completed(): - _progress_bar.hide() - - if not _applying: - return - _applying = false - - assert(_terrain != null) - var data : HTerrainData = _terrain.get_data() - var resolution := data.get_resolution() - data.notify_region_change(Rect2(0, 0, resolution, resolution), HTerrainData.CHANNEL_HEIGHT) - - var redo_map_ids := {} - for map_type in _undo_map_ids: - redo_map_ids[map_type] = _image_cache.save_image(data.get_image(map_type)) - - var undo_redo := _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(data)) - - data._edit_set_disable_apply_undo(true) - undo_redo.create_action("Generate terrain") - undo_redo.add_do_method(data._edit_apply_maps_from_file_cache.bind(_image_cache, redo_map_ids)) - undo_redo.add_undo_method( - data._edit_apply_maps_from_file_cache.bind(_image_cache, _undo_map_ids)) - undo_redo.commit_action() - data._edit_set_disable_apply_undo(false) - - _notify_progress({ "finished": true }) - _logger.debug("Done") - - hide() - - -func _notify_progress(info: Dictionary): - _progress_window.handle_progress(info) - - -func _process(delta): - if _applying: - # HACK to workaround a peculiar behavior of Viewports in Godot 4. - # Apparently Godot 4 will not update Viewports set to UPDATE_ALWAYS when the editor decides - # it doesn't need to redraw ("low processor mode", what makes the editor redraw only with - # changes). That wasn't the case in Godot 3, but I guess it is now. - # That means when we click Apply, the viewport will not update in particular when doing - # erosion passes, because the action of clicking Apply doesn't lead to as many redraws as - # changing preview parameters in the UI (those cause redraws for different reasons). - # So let's poke the renderer by redrawing something... - # - # This also piles on top of the workaround in which we keep the window visible when - # applying! So the window has one more reason to stay visible... - # - _preview.queue_redraw() - diff --git a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd.uid deleted file mode 100644 index 8df58bb..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://baen0bshbeqqh diff --git a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.tscn b/godot/addons/zylann.hterrain/tools/generator/generator_dialog.tscn deleted file mode 100644 index 5d911e3..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/generator_dialog.tscn +++ /dev/null @@ -1,84 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://cgfo1ocbdi1ug"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/generator/generator_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/inspector/inspector.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/terrain_preview.tscn" id="3"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="4"] - -[node name="GeneratorDialog" type="AcceptDialog"] -title = "Generate terrain" -size = Vector2i(1100, 780) -min_size = Vector2i(1100, 620) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Editor" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Settings" type="VBoxContainer" parent="VBoxContainer/Editor"] -custom_minimum_size = Vector2(420, 0) -layout_mode = 2 - -[node name="Inspector" parent="VBoxContainer/Editor/Settings" instance=ExtResource("2")] -layout_mode = 2 - -[node name="Preview" type="Control" parent="VBoxContainer/Editor"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="TerrainPreview" parent="VBoxContainer/Editor/Preview" instance=ExtResource("3")] -layout_mode = 1 -anchors_preset = 15 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="Label" type="Label" parent="VBoxContainer/Editor/Preview"] -layout_mode = 0 -offset_left = 5.0 -offset_top = 4.0 -offset_right = 207.0 -offset_bottom = 18.0 -text = "LMB: offset, MMB: rotate" - -[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer/Editor/Preview"] -layout_mode = 1 -anchors_preset = -1 -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -35.0 -step = 1.0 - -[node name="Choices" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="ApplyButton" type="Button" parent="VBoxContainer/Choices"] -layout_mode = 2 -text = "Apply" - -[node name="CancelButton" type="Button" parent="VBoxContainer/Choices"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("4")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 1092.0 -offset_bottom = 762.0 - -[connection signal="property_changed" from="VBoxContainer/Editor/Settings/Inspector" to="." method="_on_Inspector_property_changed"] -[connection signal="dragged" from="VBoxContainer/Editor/Preview/TerrainPreview" to="." method="_on_TerrainPreview_dragged"] -[connection signal="pressed" from="VBoxContainer/Choices/ApplyButton" to="." method="_on_ApplyButton_pressed"] -[connection signal="pressed" from="VBoxContainer/Choices/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader b/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader deleted file mode 100644 index 7dd9714..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader +++ /dev/null @@ -1,27 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -//uniform sampler2D u_screen_texture : hint_screen_texture; -uniform sampler2D u_previous_pass; - -vec4 pack_normal(vec3 n) { - return vec4((0.5 * (n + 1.0)).xzy, 1.0); -} - -float get_height(sampler2D tex, vec2 uv) { - return sample_height_from_viewport(tex, uv); -} - -void fragment() { - vec2 uv = SCREEN_UV; - vec2 ps = SCREEN_PIXEL_SIZE; - float left = get_height(u_previous_pass, uv + vec2(-ps.x, 0)); - float right = get_height(u_previous_pass, uv + vec2(ps.x, 0)); - float back = get_height(u_previous_pass, uv + vec2(0, -ps.y)); - float fore = get_height(u_previous_pass, uv + vec2(0, ps.y)); - vec3 n = normalize(vec3(left - right, 2.0, fore - back)); - COLOR = pack_normal(n); -} - diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader.uid b/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader.uid deleted file mode 100644 index e5b6ed6..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/bump2normal.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://i06ibr7o4lit diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader b/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader deleted file mode 100644 index 6f45e1c..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader +++ /dev/null @@ -1,76 +0,0 @@ -shader_type canvas_item; -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform vec2 u_slope_up = vec2(0, 0); -uniform float u_slope_factor = 1.0; -uniform bool u_slope_invert = false; -uniform float u_weight = 0.5; -uniform float u_dilation = 0.0; -//uniform sampler2D u_screen_texture : hint_screen_texture; -uniform sampler2D u_previous_pass; - -float get_height(sampler2D tex, vec2 uv) { - return sample_height_from_viewport(tex, uv); -} - -void fragment() { - float r = 3.0; - - // Divide so the shader stays neighbor dependent 1 pixel across. - // For this to work, filtering must be enabled. - vec2 eps = SCREEN_PIXEL_SIZE / (0.99 * r); - - vec2 uv = SCREEN_UV; - float h = get_height(u_previous_pass, uv); - float eh = h; - float dh = h; - - // Morphology with circular structuring element - for (float y = -r; y <= r; ++y) { - for (float x = -r; x <= r; ++x) { - - vec2 p = vec2(float(x), float(y)); - float nh = get_height(u_previous_pass, uv + p * eps); - - float s = max(length(p) - r, 0); - eh = min(eh, nh + s); - - s = min(r - length(p), 0); - dh = max(dh, nh + s); - } - } - - eh = mix(h, eh, u_weight); - dh = mix(h, dh, u_weight); - - float ph = mix(eh, dh, u_dilation); - - if (u_slope_factor > 0.0) { - vec2 ps = SCREEN_PIXEL_SIZE; - - float left = get_height(u_previous_pass, uv + vec2(-ps.x, 0.0)); - float right = get_height(u_previous_pass, uv + vec2(ps.x, 0.0)); - float top = get_height(u_previous_pass, uv + vec2(0.0, ps.y)); - float bottom = get_height(u_previous_pass, uv + vec2(0.0, -ps.y)); - - vec3 normal = normalize(vec3(left - right, ps.x + ps.y, bottom - top)); - vec3 up = normalize(vec3(u_slope_up.x, 1.0, u_slope_up.y)); - - float f = max(dot(normal, up), 0); - if (u_slope_invert) { - f = 1.0 - f; - } - - ph = mix(h, ph, mix(1.0, f, u_slope_factor)); - //COLOR = vec4(f, f, f, 1.0); - } - - //COLOR = vec4(0.5 * normal + 0.5, 1.0); - - //eh = 0.5 * (eh + texture(SCREEN_TEXTURE, uv + mp * ps * k).r); - //eh = mix(h, eh, (1.0 - h) / r); - - COLOR = encode_height_to_viewport(ph); -} diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader.uid b/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader.uid deleted file mode 100644 index 5f61880..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/erode.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cjoutj03v6ywx diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader b/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader deleted file mode 100644 index 32c6d55..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader +++ /dev/null @@ -1,211 +0,0 @@ -shader_type canvas_item; -// Required only because we use all 4 channels to encode floats into RGBA8 -render_mode blend_disabled; - -#include "res://addons/zylann.hterrain/shaders/include/heightmap.gdshaderinc" - -uniform vec2 u_offset; -uniform float u_scale = 0.02; -uniform float u_base_height = 0.0; -uniform float u_height_range = 100.0; -uniform int u_seed; -uniform int u_octaves = 5; -uniform float u_roughness = 0.5; -uniform float u_curve = 1.0; -uniform float u_terrain_size = 513.0; -uniform float u_tile_size = 513.0; -uniform sampler2D u_additive_heightmap; -uniform float u_additive_heightmap_factor = 0.0; -uniform vec2 u_uv_offset; -uniform vec2 u_uv_scale = vec2(1.0, 1.0); - -uniform float u_island_weight = 0.0; -// 0: smooth transition, 1: sharp transition -uniform float u_island_sharpness = 0.0; -// 0: edge is min height (island), 1: edge is max height (canyon) -uniform float u_island_height_ratio = 0.0; -// 0: round, 1: square -uniform float u_island_shape = 0.0; - -//////////////////////////////////////////////////////////////////////////////// -// Perlin noise source: -// https://github.com/curly-brace/Godot-3.0-Noise-Shaders -// -// GLSL textureless classic 2D noise \"cnoise\", -// with an RSL-style periodic variant \"pnoise\". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/stegu/webgl-noise -// - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) { - return mod289(((x * 34.0) + 1.0) * x); -} - -vec4 taylorInvSqrt(vec4 r) { - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec2 fade(vec2 t) { - return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); -} - -// Classic Perlin noise -float cnoise(vec2 P) { - vec4 Pi = floor(vec4(P, P)) + vec4(0.0, 0.0, 1.0, 1.0); - vec4 Pf = fract(vec4(P, P)) - vec4(0.0, 0.0, 1.0, 1.0); - Pi = mod289(Pi); // To avoid truncation effects in permutation - vec4 ix = Pi.xzxz; - vec4 iy = Pi.yyww; - vec4 fx = Pf.xzxz; - vec4 fy = Pf.yyww; - - vec4 i = permute(permute(ix) + iy); - - vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ; - vec4 gy = abs(gx) - 0.5 ; - vec4 tx = floor(gx + 0.5); - gx = gx - tx; - - vec2 g00 = vec2(gx.x,gy.x); - vec2 g10 = vec2(gx.y,gy.y); - vec2 g01 = vec2(gx.z,gy.z); - vec2 g11 = vec2(gx.w,gy.w); - - vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - - float n00 = dot(g00, vec2(fx.x, fy.x)); - float n10 = dot(g10, vec2(fx.y, fy.y)); - float n01 = dot(g01, vec2(fx.z, fy.z)); - float n11 = dot(g11, vec2(fx.w, fy.w)); - - vec2 fade_xy = fade(Pf.xy); - vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); - float n_xy = mix(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} -//////////////////////////////////////////////////////////////////////////////// - -float get_fractal_noise(vec2 uv) { - float scale = 1.0; - float sum = 0.0; - float amp = 0.0; - int octaves = u_octaves; - float p = 1.0; - uv.x += float(u_seed) * 61.0; - - for (int i = 0; i < octaves; ++i) { - sum += p * cnoise(uv * scale); - amp += p; - scale *= 2.0; - p *= u_roughness; - } - - float gs = sum / amp; - return gs; -} - -// x is a ratio in 0..1 -float get_island_curve(float x) { - return smoothstep(min(0.999, u_island_sharpness), 1.0, x); -// float exponent = 1.0 + 10.0 * u_island_sharpness; -// return pow(abs(x), exponent); -} - -float smooth_union(float a, float b, float k) { - float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); - return mix(b, a, h) - k * h * (1.0 - h); -} - -float squareish_distance(vec2 a, vec2 b, float r, float s) { - vec2 v = b - a; - // TODO This is brute force but this is the first attempt that gave me a "rounded square" distance, - // where the "roundings" remained constant over distance (not the case with standard box SDF) - float da = -smooth_union(v.x+s, v.y+s, r)+s; - float db = -smooth_union(s-v.x, s-v.y, r)+s; - float dc = -smooth_union(s-v.x, v.y+s, r)+s; - float dd = -smooth_union(v.x+s, s-v.y, r)+s; - return max(max(da, db), max(dc, dd)); -} - -// This is too sharp -//float squareish_distance(vec2 a, vec2 b) { -// vec2 v = b - a; -// // Manhattan distance would produce a "diamond-shaped distance". -// // This gives "square-shaped" distance. -// return max(abs(v.x), abs(v.y)); -//} - -float get_island_distance(vec2 pos, vec2 center, float terrain_size) { - float rd = distance(pos, center); - float sd = squareish_distance(pos, center, terrain_size * 0.1, terrain_size); - return mix(rd, sd, u_island_shape); -} - -// pos is in terrain space -float get_height(vec2 pos) { - float h = 0.0; - - { - // Noise (0..1) - // Offset and scale for the noise itself - vec2 uv_noise = (pos / u_terrain_size + u_offset) * u_scale; - h = 0.5 + 0.5 * get_fractal_noise(uv_noise); - } - - // Curve - { - h = pow(h, u_curve); - } - - // Island - { - float terrain_size = u_terrain_size; - vec2 island_center = vec2(0.5 * terrain_size); - float island_height_ratio = 0.5 + 0.5 * u_island_height_ratio; - float island_distance = get_island_distance(pos, island_center, terrain_size); - float distance_ratio = clamp(island_distance / (0.5 * terrain_size), 0.0, 1.0); - float island_ratio = u_island_weight * get_island_curve(distance_ratio); - h = mix(h, island_height_ratio, island_ratio); - } - - // Height remapping - { - h = u_base_height + h * u_height_range; - } - - // Additive heightmap - { - vec2 uv = pos / u_terrain_size; - float ah = sample_heightmap(u_additive_heightmap, uv); - h += u_additive_heightmap_factor * ah; - } - - return h; -} - -void fragment() { - // Handle screen padding: transform UV back into generation space. - // This is in tile space actually...? it spans 1 unit across the viewport, - // and starts from 0 when tile (0,0) is generated. - // Maybe we could change this into world units instead? - vec2 uv_tile = (SCREEN_UV + u_uv_offset) * u_uv_scale; - - float h = get_height(uv_tile * u_tile_size); - - COLOR = encode_height_to_viewport(h); -} diff --git a/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader.uid b/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader.uid deleted file mode 100644 index 3a005ea..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/shaders/perlin_noise.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2q8pujbi2cd diff --git a/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd b/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd deleted file mode 100644 index 0caaf7c..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd +++ /dev/null @@ -1,331 +0,0 @@ -# Holds a viewport on which several passes may run to generate a final image. -# Passes can have different shaders and re-use what was drawn by a previous pass. -# TODO I'd like to make such a system working as a graph of passes for more possibilities. - -@tool -extends Node - -const HT_Util = preload("res://addons/zylann.hterrain/util/util.gd") -const HT_TextureGeneratorPass = preload("./texture_generator_pass.gd") -const HT_Logger = preload("../../util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const DUMMY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal progress_reported(info) -# Emitted when an output is generated. -signal output_generated(image, metadata) -# Emitted when all passes are complete -signal completed - -class HT_TextureGeneratorViewport: - var viewport : SubViewport - var ci : TextureRect - -var _passes := [] -var _resolution := Vector2i(512, 512) -var _output_padding := [0, 0, 0, 0] - -# Since Godot 4.0, we use ping-pong viewports because `hint_screen_texture` always returns `1.0` -# for transparent pixels, which is wrong, but sadly appears to be intented... -# https://github.com/godotengine/godot/issues/78207 -var _viewports : Array[HT_TextureGeneratorViewport] = [null, null] -var _viewport_index := 0 - -var _dummy_texture : Texture2D -var _running := false -var _rerun := false -#var _tiles = PoolVector2Array([Vector2()]) - -var _running_passes := [] -var _running_pass_index := 0 -var _running_iteration := 0 -var _shader_material : ShaderMaterial = null -#var _uv_offset = 0 # Offset de to padding - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - _dummy_texture = load(DUMMY_TEXTURE_PATH) - if _dummy_texture == null: - _logger.error(str("Failed to load dummy texture ", DUMMY_TEXTURE_PATH)) - - for viewport_index in len(_viewports): - var viewport = SubViewport.new() - # We render with 2D shaders, but we don't want the parent world to interfere - viewport.own_world_3d = true - viewport.world_3d = World3D.new() - viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - # Require RGBA8 so we can pack heightmap floats into pixels - viewport.transparent_bg = true - add_child(viewport) - - var ci := TextureRect.new() - ci.stretch_mode = TextureRect.STRETCH_SCALE - ci.texture = _dummy_texture - viewport.add_child(ci) - - var vp := HT_TextureGeneratorViewport.new() - vp.viewport = viewport - vp.ci = ci - _viewports[viewport_index] = vp - - _shader_material = ShaderMaterial.new() - - set_process(false) - - -func is_running() -> bool: - return _running - - -func clear_passes(): - _passes.clear() - - -func add_pass(p: HT_TextureGeneratorPass): - assert(_passes.find(p) == -1) - assert(p.iterations > 0) - _passes.append(p) - - -func add_output(meta): - assert(len(_passes) > 0) - var p = _passes[-1] - p.output = true - p.metadata = meta - - -# Sets at which base resolution the generator will work on. -# In tiled rendering, this is the resolution of one tile. -# The internal viewport may be larger if some passes need more room, -# and the resulting images might include some of these pixels if output padding is used. -func set_resolution(res: Vector2i): - assert(not _running) - _resolution = res - - -# Tell image outputs to include extra pixels on the edges. -# This extends the resolution of images compared to the base resolution. -# The initial use case for this is to generate terrain tiles where edge pixels are -# shared with the neighor tiles. -func set_output_padding(p: Array): - assert(typeof(p) == TYPE_ARRAY) - assert(len(p) == 4) - for v in p: - assert(typeof(v) == TYPE_INT) - _output_padding = p - - -func run(): - assert(len(_passes) > 0) - - if _running: - _rerun = true - return - - for vp in _viewports: - assert(vp.viewport != null) - assert(vp.ci != null) - - # Copy passes - var passes := [] - passes.resize(len(_passes)) - for i in len(_passes): - passes[i] = _passes[i].duplicate() - _running_passes = passes - - # Pad pixels according to largest padding - var largest_padding := 0 - for p in passes: - if p.padding > largest_padding: - largest_padding = p.padding - for v in _output_padding: - if v > largest_padding: - largest_padding = v - var padded_size := _resolution + 2 * Vector2i(largest_padding, largest_padding) - -# _uv_offset = Vector2( \ -# float(largest_padding) / padded_size.x, -# float(largest_padding) / padded_size.y) - - for vp in _viewports: - vp.ci.size = padded_size - vp.viewport.size = padded_size - - # First viewport index doesn't matter. - # Maybe one issue of resetting it to zero would be that the previous run - # could have ended with the same viewport that will be sent as a texture as - # one of the uniforms of the shader material, which causes an error in the - # renderer because it's not allowed to use a viewport texture while - # rendering on the same viewport -# _viewport_index = 0 - - var first_vp := _viewports[_viewport_index] - first_vp.viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - # I don't trust `UPDATE_ONCE`, it also doesn't reset so we never know if it actually works... - # https://github.com/godotengine/godot/issues/33351 - first_vp.viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - - for vp in _viewports: - if vp != first_vp: - vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - - _running_pass_index = 0 - _running_iteration = 0 - _running = true - set_process(true) - - -func _process(delta: float): - # TODO because of https://github.com/godotengine/godot/issues/7894 - if not is_processing(): - return - - var prev_vpi := 0 if _viewport_index == 1 else 1 - var prev_vp := _viewports[prev_vpi] - - if _running_pass_index > 0: - var prev_pass : HT_TextureGeneratorPass = _running_passes[_running_pass_index - 1] - if prev_pass.output: - _create_output_image(prev_pass.metadata, prev_vp) - - if _running_pass_index >= len(_running_passes): - _running = false - - completed.emit() - - if _rerun: - # run() was requested again before we complete... - # this will happen very frequently because we are forced to wait multiple frames - # before getting a result - _rerun = false - run() - else: - # Done - for vp in _viewports: - vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - set_process(false) - return - - var p : HT_TextureGeneratorPass = _running_passes[_running_pass_index] - - var vp := _viewports[_viewport_index] - vp.viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - prev_vp.viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - - if _running_iteration == 0: - _setup_pass(p, vp) - - _setup_iteration(vp, prev_vp) - - _report_progress(_running_passes, _running_pass_index, _running_iteration) - # Wait one frame for render, and this for EVERY iteration and every pass, - # because Godot doesn't provide any way to run multiple feedback render passes in one go. - _running_iteration += 1 - - if _running_iteration == p.iterations: - _running_iteration = 0 - _running_pass_index += 1 - - # Swap viewport for next pass - _viewport_index = (_viewport_index + 1) % 2 - - # The viewport should render after the tree was processed - - -# Called at the beginning of each pass -func _setup_pass(p: HT_TextureGeneratorPass, vp: HT_TextureGeneratorViewport): - if p.texture != null: - vp.ci.texture = p.texture - else: - vp.ci.texture = _dummy_texture - - if p.shader != null: - if _shader_material == null: - _shader_material = ShaderMaterial.new() - _shader_material.shader = p.shader - - vp.ci.material = _shader_material - - if p.params != null: - for param_name in p.params: - _shader_material.set_shader_parameter(param_name, p.params[param_name]) - - var vp_size_f := Vector2(vp.viewport.size) - var res_f := Vector2(_resolution) - var scale_ndc := vp_size_f / res_f - var pad_offset_ndc := ((vp_size_f - res_f) / 2.0) / vp_size_f - var offset_ndc := -pad_offset_ndc + p.tile_pos / scale_ndc - - # Because padding may be used around the generated area, - # the shader can use these predefined parameters, - # and apply the following to SCREEN_UV to adjust its calculations: - # vec2 uv = (SCREEN_UV + u_uv_offset) * u_uv_scale; - - if p.params == null or not p.params.has("u_uv_scale"): - _shader_material.set_shader_parameter("u_uv_scale", scale_ndc) - - if p.params == null or not p.params.has("u_uv_offset"): - _shader_material.set_shader_parameter("u_uv_offset", offset_ndc) - - else: - vp.ci.material = null - - if p.clear: - vp.viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ONCE - - -# Called for every iteration of every pass -func _setup_iteration(vp: HT_TextureGeneratorViewport, prev_vp: HT_TextureGeneratorViewport): - assert(vp != prev_vp) - if _shader_material != null: - _shader_material.set_shader_parameter("u_previous_pass", prev_vp.viewport.get_texture()) - - -func _create_output_image(metadata, vp: HT_TextureGeneratorViewport): - var tex := vp.viewport.get_texture() - var src := tex.get_image() -# src.save_png(str("ddd_tgen_output", metadata.maptype, ".png")) - - # Pick the center of the image - var subrect := Rect2i( \ - (src.get_width() - _resolution.x) / 2, \ - (src.get_height() - _resolution.y) / 2, \ - _resolution.x, _resolution.y) - - # Make sure we are pixel-perfect. If not, padding is odd -# assert(int(subrect.position.x) == subrect.position.x) -# assert(int(subrect.position.y) == subrect.position.y) - - subrect.position.x -= _output_padding[0] - subrect.position.y -= _output_padding[2] - subrect.size.x += _output_padding[0] + _output_padding[1] - subrect.size.y += _output_padding[2] + _output_padding[3] - - var dst : Image - if subrect == Rect2i(0, 0, src.get_width(), src.get_height()): - dst = src - else: - # Note: size MUST match at this point. - # If it doesn't, the viewport has not been configured properly, - # or padding has been modified while the generator was running - dst = Image.create( \ - _resolution.x + _output_padding[0] + _output_padding[1], \ - _resolution.y + _output_padding[2] + _output_padding[3], \ - false, src.get_format()) - dst.blit_rect(src, subrect, Vector2i()) - - output_generated.emit(dst, metadata) - - -func _report_progress(passes: Array, pass_index: int, iteration: int): - var p = passes[pass_index] - progress_reported.emit({ - "name": p.debug_name, - "pass_index": pass_index, - "pass_count": len(passes), - "iteration": iteration, - "iteration_count": p.iterations - }) - diff --git a/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd.uid b/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd.uid deleted file mode 100644 index a611fdb..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/texture_generator.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bxdmk1e84s8rd diff --git a/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd b/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd deleted file mode 100644 index 76745f1..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd +++ /dev/null @@ -1,43 +0,0 @@ - -# Name of the pass, for debug purposes -var debug_name := "" -# The viewport will be cleared at this pass -var clear := false -# Which main texture should be drawn. -# If not set, a default texture will be drawn. -# Note that it won't matter if the shader disregards it, -# and will only serve to provide UVs, due to https://github.com/godotengine/godot/issues/7298. -var texture : Texture = null -# Which shader to use -var shader : Shader = null -# Parameters for the shader -# TODO Use explicit Dictionary, dont allow null -var params = null -# How many pixels to pad the viewport on all edges, in case neighboring matters. -# Outputs won't have that padding, but can pick part of it in case output padding is used. -var padding := 0 -# How many times this pass must be run -var iterations := 1 -# If not empty, the viewport will be downloaded as an image before the next pass -var output := false -# Sent along the output -var metadata = null -# Used for tiled rendering, where each tile has the base resolution, -# in case the viewport cannot be made big enough to cover the final image, -# of if you are generating a pseudo-infinite terrain. -# TODO Have an API for this? -var tile_pos := Vector2() - -func duplicate(): - var p = get_script().new() - p.debug_name = debug_name - p.clear = clear - p.texture = texture - p.shader = shader - p.params = params - p.padding = padding - p.iterations = iterations - p.output = output - p.metadata = metadata - p.tile_pos = tile_pos - return p diff --git a/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd.uid b/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd.uid deleted file mode 100644 index a00bf73..0000000 --- a/godot/addons/zylann.hterrain/tools/generator/texture_generator_pass.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://fq1rgml455is diff --git a/godot/addons/zylann.hterrain/tools/globalmap_baker.gd b/godot/addons/zylann.hterrain/tools/globalmap_baker.gd deleted file mode 100644 index 6faa0eb..0000000 --- a/godot/addons/zylann.hterrain/tools/globalmap_baker.gd +++ /dev/null @@ -1,168 +0,0 @@ - -# Bakes a global albedo map using the same shader the terrain uses, -# but renders top-down in orthographic mode. - -@tool -extends Node - -const HTerrain = preload("../hterrain.gd") -const HTerrainData = preload("../hterrain_data.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") - -# Must be power of two -const DEFAULT_VIEWPORT_SIZE = 512 - -signal progress_notified(info) -signal permanent_change_performed(message) - -var _terrain : HTerrain = null -var _viewport : SubViewport = null -var _viewport_size := DEFAULT_VIEWPORT_SIZE -var _plane : MeshInstance3D = null -var _camera : Camera3D = null -var _sectors := [] -var _sector_index := 0 - - -func _ready(): - set_process(false) - - -func bake(terrain: HTerrain): - assert(terrain != null) - var data := terrain.get_data() - assert(data != null) - _terrain = terrain - - var splatmap := data.get_texture(HTerrainData.CHANNEL_SPLAT) - var colormap := data.get_texture(HTerrainData.CHANNEL_COLOR) - - var terrain_size := data.get_resolution() - - if _viewport == null: - _setup_scene(terrain_size) - - var cw := terrain_size / _viewport_size - var ch := terrain_size / _viewport_size - for y in ch: - for x in cw: - _sectors.append(Vector2(x, y)) - - var mat := _plane.material_override - _terrain.setup_globalmap_material(mat) - - _sector_index = 0 - set_process(true) - - -func _setup_scene(terrain_size: int): - assert(_viewport == null) - - _viewport_size = DEFAULT_VIEWPORT_SIZE - while _viewport_size > terrain_size: - _viewport_size /= 2 - - _viewport = SubViewport.new() - _viewport.size = Vector2(_viewport_size + 1, _viewport_size + 1) - _viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS - # _viewport.render_target_v_flip = true - _viewport.world_3d = World3D.new() - _viewport.own_world_3d = true - _viewport.debug_draw = Viewport.DEBUG_DRAW_UNSHADED - - var mat := ShaderMaterial.new() - - _plane = MeshInstance3D.new() - # Make a very small mesh, vertex precision isn't required - var plane_res := 4 - _plane.mesh = \ - HTerrainMesher.make_flat_chunk(plane_res, plane_res, _viewport_size / plane_res, 0) - _plane.material_override = mat - _viewport.add_child(_plane) - - _camera = Camera3D.new() - _camera.projection = Camera3D.PROJECTION_ORTHOGONAL - _camera.size = _viewport.size.x - _camera.near = 0.1 - _camera.far = 10.0 - _camera.current = true - _camera.rotation = Vector3(deg_to_rad(-90), 0, 0) - _viewport.add_child(_camera) - - add_child(_viewport) - - -func _cleanup_scene(): - _viewport.queue_free() - _viewport = null - _plane = null - _camera = null - - -func _process(delta): - if not is_processing(): - return - - if _sector_index > 0: - _grab_image(_sectors[_sector_index - 1]) - - if _sector_index >= len(_sectors): - set_process(false) - _finish() - progress_notified.emit({ "finished": true }) - else: - _setup_pass(_sectors[_sector_index]) - _report_progress() - _sector_index += 1 - - -func _report_progress(): - var sector = _sectors[_sector_index] - progress_notified.emit({ - "progress": float(_sector_index) / len(_sectors), - "message": "Calculating sector (" + str(sector.x) + ", " + str(sector.y) + ")" - }) - - -func _setup_pass(sector: Vector2): - # Note: we implicitely take off-by-one pixels into account - var origin := sector * _viewport_size - var center := origin + 0.5 * Vector2(_viewport.size) - - # The heightmap is left empty, so will default to white, which is a height of 1. - # The camera must be placed above the terrain to see it. - _camera.position = Vector3(center.x, 2.0, center.y) - _plane.position = Vector3(origin.x, 0.0, origin.y) - - -func _grab_image(sector: Vector2): - var tex := _viewport.get_texture() - var src := tex.get_image() - - assert(_terrain != null) - var data := _terrain.get_data() - assert(data != null) - - if data.get_map_count(HTerrainData.CHANNEL_GLOBAL_ALBEDO) == 0: - data._edit_add_map(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - var dst := data.get_image(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - src.convert(dst.get_format()) - var origin = sector * _viewport_size - dst.blit_rect(src, Rect2i(0, 0, src.get_width(), src.get_height()), origin) - - -func _finish(): - assert(_terrain != null) - var data := _terrain.get_data() as HTerrainData - assert(data != null) - var dst := data.get_image(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - - data.notify_region_change(Rect2(0, 0, dst.get_width(), dst.get_height()), - HTerrainData.CHANNEL_GLOBAL_ALBEDO) - permanent_change_performed.emit("Bake globalmap") - - _cleanup_scene() - _terrain = null diff --git a/godot/addons/zylann.hterrain/tools/globalmap_baker.gd.uid b/godot/addons/zylann.hterrain/tools/globalmap_baker.gd.uid deleted file mode 100644 index 8d4d464..0000000 --- a/godot/addons/zylann.hterrain/tools/globalmap_baker.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://d2ukdke3mfhd3 diff --git a/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg b/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg deleted file mode 100644 index d0e3a26..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg.import b/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg.import deleted file mode 100644 index 5297924..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/brush_circle.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bcowfpqv56xs3" -path="res://.godot/imported/brush_circle.svg-339556430f66037867afbdbb3ea049fb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/brush_circle.svg" -dest_files=["res://.godot/imported/brush_circle.svg-339556430f66037867afbdbb3ea049fb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg b/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg deleted file mode 100644 index e8638e0..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg.import b/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg.import deleted file mode 100644 index 3187331..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/brush_circle_background.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dqw1x056gf148" -path="res://.godot/imported/brush_circle_background.svg-4acbd4cce1fa780db9f389c7a5f8301a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/brush_circle_background.svg" -dest_files=["res://.godot/imported/brush_circle_background.svg-4acbd4cce1fa780db9f389c7a5f8301a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/empty.png b/godot/addons/zylann.hterrain/tools/icons/empty.png deleted file mode 100644 index 0a59813..0000000 Binary files a/godot/addons/zylann.hterrain/tools/icons/empty.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/icons/empty.png.import b/godot/addons/zylann.hterrain/tools/icons/empty.png.import deleted file mode 100644 index 6c9030f..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/empty.png.import +++ /dev/null @@ -1,40 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://vo2brkj3udel" -path="res://.godot/imported/empty.png-31363f083c9c4e2e8e54cf64f3716737.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/empty.png" -dest_files=["res://.godot/imported/empty.png-31363f083c9c4e2e8e54cf64f3716737.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg deleted file mode 100644 index f490172..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import deleted file mode 100644 index 2aee2d9..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://l16qrsohg7jj" -path="res://.godot/imported/icon_anchor_bottom.svg-963f115d31a41c38349ab03453cf2ef5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom.svg-963f115d31a41c38349ab03453cf2ef5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg deleted file mode 100644 index 05f255a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import deleted file mode 100644 index d061ea3..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://30wsjmeemngg" -path="res://.godot/imported/icon_anchor_bottom_left.svg-c59f20ff71f725e47b5fc556b5ef93c4.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom_left.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom_left.svg-c59f20ff71f725e47b5fc556b5ef93c4.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg deleted file mode 100644 index 33e97ef..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import deleted file mode 100644 index 97a851f..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cwb02kd3gr5v1" -path="res://.godot/imported/icon_anchor_bottom_right.svg-23dd5f1d1c7021fe105f8bde603dcc4d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_bottom_right.svg" -dest_files=["res://.godot/imported/icon_anchor_bottom_right.svg-23dd5f1d1c7021fe105f8bde603dcc4d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg deleted file mode 100644 index 8ab613a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import deleted file mode 100644 index a84d82d..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_center.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bkphpwgf3vlqy" -path="res://.godot/imported/icon_anchor_center.svg-d48605c4035ec4a02ae8159aea6db85f.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_center.svg" -dest_files=["res://.godot/imported/icon_anchor_center.svg-d48605c4035ec4a02ae8159aea6db85f.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg deleted file mode 100644 index 7fd1a68..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import deleted file mode 100644 index 67984e1..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_left.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cmydngdawudhq" -path="res://.godot/imported/icon_anchor_left.svg-77f3e03e6fbadfd7e4dc1ab3661e6e7c.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_left.svg" -dest_files=["res://.godot/imported/icon_anchor_left.svg-77f3e03e6fbadfd7e4dc1ab3661e6e7c.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg deleted file mode 100644 index 8ad32f1..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import deleted file mode 100644 index 104cb3c..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_right.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cut3xadorcxqt" -path="res://.godot/imported/icon_anchor_right.svg-90e3a37e8d38587bac01703849f8b9f7.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_right.svg" -dest_files=["res://.godot/imported/icon_anchor_right.svg-90e3a37e8d38587bac01703849f8b9f7.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg deleted file mode 100644 index e15ed1a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import deleted file mode 100644 index d30eb17..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cprd188dc3fc7" -path="res://.godot/imported/icon_anchor_top.svg-f1dcf93e569fe43b280b5dc072ee78e5.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top.svg" -dest_files=["res://.godot/imported/icon_anchor_top.svg-f1dcf93e569fe43b280b5dc072ee78e5.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg deleted file mode 100644 index cd82a6f..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import deleted file mode 100644 index d94a724..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bugm51ryp0urq" -path="res://.godot/imported/icon_anchor_top_left.svg-aea4438056394f9967bf74b13799fedc.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top_left.svg" -dest_files=["res://.godot/imported/icon_anchor_top_left.svg-aea4438056394f9967bf74b13799fedc.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg deleted file mode 100644 index 4619493..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import deleted file mode 100644 index 0a760ff..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bebc1xsqguspq" -path="res://.godot/imported/icon_anchor_top_right.svg-e9f520f41c9c20cc5e64aca56427ca01.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_anchor_top_right.svg" -dest_files=["res://.godot/imported/icon_anchor_top_right.svg-e9f520f41c9c20cc5e64aca56427ca01.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg b/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg deleted file mode 100644 index f5d8156..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import deleted file mode 100644 index 0fa1bad..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6jmdwj3vn6m0" -path="res://.godot/imported/icon_detail_layer_node.svg-70daba484432569847b1d2fe22768af3.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_detail_layer_node.svg" -dest_files=["res://.godot/imported/icon_detail_layer_node.svg-70daba484432569847b1d2fe22768af3.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg b/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg deleted file mode 100644 index 7866628..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg.import deleted file mode 100644 index b741ca5..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_grass.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://coicfqoi4spg0" -path="res://.godot/imported/icon_grass.svg-6a20eb11bc23d46b8a4c0f365f95554b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_grass.svg" -dest_files=["res://.godot/imported/icon_grass.svg-6a20eb11bc23d46b8a4c0f365f95554b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg deleted file mode 100644 index 2b20f6a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import deleted file mode 100644 index 95625e9..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://t1m58v6iitwb" -path="res://.godot/imported/icon_heightmap_color.svg-2b3375697cab4a6c7b8d933fc7f2b982.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_color.svg" -dest_files=["res://.godot/imported/icon_heightmap_color.svg-2b3375697cab4a6c7b8d933fc7f2b982.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg deleted file mode 100644 index 03c0caf..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import deleted file mode 100644 index 580da2b..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cd13q0qxqt8cd" -path="res://.godot/imported/icon_heightmap_data.svg-00236b6035ce13dd687a19d98237bdbd.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_data.svg" -dest_files=["res://.godot/imported/icon_heightmap_data.svg-00236b6035ce13dd687a19d98237bdbd.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg deleted file mode 100644 index 22824a2..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import deleted file mode 100644 index 88172f8..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ci3jif8wx2tig" -path="res://.godot/imported/icon_heightmap_erode.svg-fad285f0810d69bec16027ac0257c223.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_erode.svg" -dest_files=["res://.godot/imported/icon_heightmap_erode.svg-fad285f0810d69bec16027ac0257c223.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg deleted file mode 100644 index c4d3268..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import deleted file mode 100644 index 3968dd1..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://6bnt8lvvabf1" -path="res://.godot/imported/icon_heightmap_flatten.svg-3d183c33fce9f34c419c53418ef26264.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_flatten.svg" -dest_files=["res://.godot/imported/icon_heightmap_flatten.svg-3d183c33fce9f34c419c53418ef26264.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg deleted file mode 100644 index d7c27e9..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import deleted file mode 100644 index 15e6322..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c6trw4wyo86x4" -path="res://.godot/imported/icon_heightmap_level.svg-0abbb78afcf28f4da15188c85861a768.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_level.svg" -dest_files=["res://.godot/imported/icon_heightmap_level.svg-0abbb78afcf28f4da15188c85861a768.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg deleted file mode 100644 index 87101c3..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import deleted file mode 100644 index c99f3f1..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://da02ckrgusaoe" -path="res://.godot/imported/icon_heightmap_lower.svg-5bb5cae46ea03f9d65d6c497a65882db.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_lower.svg" -dest_files=["res://.godot/imported/icon_heightmap_lower.svg-5bb5cae46ea03f9d65d6c497a65882db.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg deleted file mode 100644 index 751b683..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import deleted file mode 100644 index 9ae25c3..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://btb4kkafvn67j" -path="res://.godot/imported/icon_heightmap_mask.svg-3fad663c59a229c1c6c17c4e8d5bad09.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_mask.svg" -dest_files=["res://.godot/imported/icon_heightmap_mask.svg-3fad663c59a229c1c6c17c4e8d5bad09.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg deleted file mode 100644 index 00fb889..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import deleted file mode 100644 index 21c4213..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ofs3osrmxfi" -path="res://.godot/imported/icon_heightmap_node.svg-0b776ad0015c7d9d9553b161b36e70fe.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node.svg" -dest_files=["res://.godot/imported/icon_heightmap_node.svg-0b776ad0015c7d9d9553b161b36e70fe.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg deleted file mode 100644 index 00fb889..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import deleted file mode 100644 index 24c8d27..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://sdaddk8wxjin" -path="res://.godot/imported/icon_heightmap_node_large.svg-4b8ff9077cb0d8dc06efcf638cce1edb.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_node_large.svg" -dest_files=["res://.godot/imported/icon_heightmap_node_large.svg-4b8ff9077cb0d8dc06efcf638cce1edb.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=8.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg deleted file mode 100644 index 72503fa..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import deleted file mode 100644 index 00656eb..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cgw6r4eg1msvn" -path="res://.godot/imported/icon_heightmap_paint.svg-ad4c1d13ab344959f8e60b793d52d80d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_paint.svg" -dest_files=["res://.godot/imported/icon_heightmap_paint.svg-ad4c1d13ab344959f8e60b793d52d80d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg deleted file mode 100644 index 0e3033f..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import deleted file mode 100644 index 4746ae5..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://0polw88tpkl4" -path="res://.godot/imported/icon_heightmap_raise.svg-16ae516b9460ce83d04d965ed6b9989a.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_raise.svg" -dest_files=["res://.godot/imported/icon_heightmap_raise.svg-16ae516b9460ce83d04d965ed6b9989a.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg deleted file mode 100644 index c9d586a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import deleted file mode 100644 index fc7a652..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b6hlgjb4fa31c" -path="res://.godot/imported/icon_heightmap_smooth.svg-1216ccdd3a408b8769b0a0964b7bd3f9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_smooth.svg" -dest_files=["res://.godot/imported/icon_heightmap_smooth.svg-1216ccdd3a408b8769b0a0964b7bd3f9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg deleted file mode 100644 index 24f39a4..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import deleted file mode 100644 index f972559..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b4ya0po3a4nqa" -path="res://.godot/imported/icon_heightmap_unmask.svg-f88c0addb6f444beecc364dd218d67e9.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg" -dest_files=["res://.godot/imported/icon_heightmap_unmask.svg-f88c0addb6f444beecc364dd218d67e9.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg b/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg deleted file mode 100644 index 0cc022a..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import deleted file mode 100644 index 3d6bac4..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://b6l5dys0awbwd" -path="res://.godot/imported/icon_long_arrow_down.svg-baa34c94eaf2f9f3533b079350dd260b.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg" -dest_files=["res://.godot/imported/icon_long_arrow_down.svg-baa34c94eaf2f9f3533b079350dd260b.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg b/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg deleted file mode 100644 index d4e8c2b..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import deleted file mode 100644 index bfc6b8b..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://d3vie0tj3ry6k" -path="res://.godot/imported/icon_long_arrow_right.svg-2e9c5428ca49af0df04372d4de12fdd2.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg" -dest_files=["res://.godot/imported/icon_long_arrow_right.svg-2e9c5428ca49af0df04372d4de12fdd2.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg b/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg deleted file mode 100644 index 34e2ab7..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import deleted file mode 100644 index 79c9677..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://cc47smy24m368" -path="res://.godot/imported/icon_minimap_out_of_range_position.svg-be0d8e592b6594137b0f40434b64f771.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg" -dest_files=["res://.godot/imported/icon_minimap_out_of_range_position.svg-be0d8e592b6594137b0f40434b64f771.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg b/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg deleted file mode 100644 index 468c52d..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import deleted file mode 100644 index 2f605b8..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_minimap_position.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://c1el0dmyvaaij" -path="res://.godot/imported/icon_minimap_position.svg-09c3263e8852c7010dcfa0a85245403d.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_minimap_position.svg" -dest_files=["res://.godot/imported/icon_minimap_position.svg-09c3263e8852c7010dcfa0a85245403d.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg b/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg deleted file mode 100644 index b5a004d..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import b/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import deleted file mode 100644 index 9b2a7af..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/icon_small_circle.svg.import +++ /dev/null @@ -1,43 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://bdkcgtv1r5j31" -path="res://.godot/imported/icon_small_circle.svg-758362406034e77f78350899f9b2cf34.ctex" -metadata={ -"vram_texture": false -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/icon_small_circle.svg" -dest_files=["res://.godot/imported/icon_small_circle.svg-758362406034e77f78350899f9b2cf34.ctex"] - -[params] - -compress/mode=0 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=false -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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=1 -svg/scale=1.0 -editor/scale_with_editor_scale=false -editor/convert_colors_with_editor_theme=false diff --git a/godot/addons/zylann.hterrain/tools/icons/white.png b/godot/addons/zylann.hterrain/tools/icons/white.png deleted file mode 100644 index dee54f4..0000000 Binary files a/godot/addons/zylann.hterrain/tools/icons/white.png and /dev/null differ diff --git a/godot/addons/zylann.hterrain/tools/icons/white.png.import b/godot/addons/zylann.hterrain/tools/icons/white.png.import deleted file mode 100644 index 095a846..0000000 --- a/godot/addons/zylann.hterrain/tools/icons/white.png.import +++ /dev/null @@ -1,41 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://dnee27oabcvy2" -path.s3tc="res://.godot/imported/white.png-06b7d7f95e74cd7f8357ec25a73870fb.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} - -[deps] - -source_file="res://addons/zylann.hterrain/tools/icons/white.png" -dest_files=["res://.godot/imported/white.png-06b7d7f95e74cd7f8357ec25a73870fb.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -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/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -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/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd b/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd deleted file mode 100644 index 0c622cb..0000000 --- a/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd +++ /dev/null @@ -1,347 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Logger = preload("../../util/logger.gd") -const HT_XYZFormat = preload("../../util/xyz_format.gd") -const HT_Inspector = preload("../inspector/inspector.gd") - -signal permanent_change_performed(message) - -@onready var _inspector : HT_Inspector = $VBoxContainer/Inspector -@onready var _errors_label : Label = $VBoxContainer/ColorRect/ScrollContainer/VBoxContainer/Errors -@onready var _warnings_label : Label = \ - $VBoxContainer/ColorRect/ScrollContainer/VBoxContainer/Warnings - - -enum { - RAW_LITTLE_ENDIAN, - RAW_BIG_ENDIAN -} - -var _terrain : HTerrain = null -var _logger = HT_Logger.get_for(self) - - -func _init(): - get_ok_button().hide() - - -func _ready(): - _inspector.set_prototype({ - "heightmap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["raw", "png", "exr", "xyz"] - }, - "raw_endianess": { - "type": TYPE_INT, - "usage": "enum", - "enum_items": [[RAW_LITTLE_ENDIAN, "Little Endian"], [RAW_BIG_ENDIAN, "Big Endian"]], - "enabled": false - }, - "bit_depth": { - "type": TYPE_INT, - "usage": "enum", - "enum_items": [[HTerrainData.BIT_DEPTH_16, "16-bit"], [HTerrainData.BIT_DEPTH_32, "32-bit"]], - "enabled": false - }, - "min_height": { - "type": TYPE_FLOAT, - "range": {"min": -2000.0, "max": 2000.0, "step": 0.01}, - "default_value": 0.0 - }, - "max_height": { - "type": TYPE_FLOAT, - "range": {"min": -2000.0, "max": 2000.0, "step": 0.01}, - "default_value": 400.0 - }, - "splatmap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["png"] - }, - "colormap": { - "type": TYPE_STRING, - "usage": "file", - "exts": ["png"] - } - }) - - # Testing -# _errors_label.text = "- Hello World!" -# _warnings_label.text = "- Yolo Jesus!" - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - # Checking a node set in _ready, - # because visibility can also change between _enter_tree and _ready... - if visible and _inspector != null: - _clear_feedback() - - -static func _format_feedbacks(feed): - var a := [] - for s in feed: - a.append("- " + s) - return "\n".join(PackedStringArray(a)) - - -func _clear_feedback(): - _errors_label.text = "" - _warnings_label.text = "" - - -class HT_ErrorCheckReport: - var errors := [] - var warnings := [] - - -func _show_feedback(res: HT_ErrorCheckReport): - for e in res.errors: - _logger.error(e) - - for w in res.warnings: - _logger.warn(w) - - _clear_feedback() - - if len(res.errors) > 0: - _errors_label.text = _format_feedbacks(res.errors) - - if len(res.warnings) > 0: - _warnings_label.text = _format_feedbacks(res.warnings) - - -func _on_CheckButton_pressed(): - var res := _validate_form() - _show_feedback(res) - - -func _on_ImportButton_pressed(): - assert(_terrain != null and _terrain.get_data() != null) - - # Verify input to inform the user of potential issues - var res := _validate_form() - _show_feedback(res) - - if len(res.errors) != 0: - _logger.debug("Cannot import due to errors, aborting") - return - - var params := {} - - var heightmap_path = _inspector.get_value("heightmap") - if heightmap_path != "": - var endianess = _inspector.get_value("raw_endianess") - params[HTerrainData.CHANNEL_HEIGHT] = { - "path": heightmap_path, - "min_height": _inspector.get_value("min_height"), - "max_height": _inspector.get_value("max_height"), - "big_endian": endianess == RAW_BIG_ENDIAN, - "bit_depth": _inspector.get_value("bit_depth"), - } - - var colormap_path = _inspector.get_value("colormap") - if colormap_path != "": - params[HTerrainData.CHANNEL_COLOR] = { - "path": colormap_path - } - - var splatmap_path = _inspector.get_value("splatmap") - if splatmap_path != "": - params[HTerrainData.CHANNEL_SPLAT] = { - "path": splatmap_path - } - - var data = _terrain.get_data() - data._edit_import_maps(params) - emit_signal("permanent_change_performed", "Import maps") - - _logger.debug("Terrain import finished") - hide() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_Inspector_property_changed(key: String, value): - if key == "heightmap": - var is_raw = value.get_extension().to_lower() == "raw" - _inspector.set_property_enabled("raw_endianess", is_raw) - _inspector.set_property_enabled("bit_depth", is_raw) - if is_raw: - var bit_depth:int = _estimate_bit_depth_for_raw_file(value) - if bit_depth == HTerrainData.BIT_DEPTH_UNDEFINED: - bit_depth = HTerrainData.BIT_DEPTH_16 # fallback depth value - _inspector.set_value("bit_depth", bit_depth) - - -# _estimate_bit_depth_for_raw_file returns the file's identified bit depth, or 0. -static func _estimate_bit_depth_for_raw_file(path: String) -> int: - var ext := path.get_extension().to_lower() - if ext == "raw": - var f := FileAccess.open(path, FileAccess.READ) - if f == null: - return HTerrainData.BIT_DEPTH_UNDEFINED - - var file_len := f.get_length() - f = null # close file - - for bit_depth in [HTerrainData.BIT_DEPTH_16, HTerrainData.BIT_DEPTH_32]: - var file_res := HT_Util.integer_square_root(file_len / (bit_depth/8)) - if file_res > 0: - return bit_depth - - return HTerrainData.BIT_DEPTH_UNDEFINED - - -func _validate_form() -> HT_ErrorCheckReport: - var res := HT_ErrorCheckReport.new() - - var heightmap_path : String = _inspector.get_value("heightmap") - var splatmap_path : String = _inspector.get_value("splatmap") - var colormap_path : String = _inspector.get_value("colormap") - var bit_depth = _inspector.get_value("bit_depth") - - if colormap_path == "" and heightmap_path == "" and splatmap_path == "": - res.errors.append("No maps specified.") - return res - - # If a heightmap is specified, it will override the size of the existing terrain. - # If not specified, maps will have to match the resolution of the existing terrain. - var heightmap_size := _terrain.get_data().get_resolution() - - if heightmap_path != "": - var min_height = _inspector.get_value("min_height") - var max_height = _inspector.get_value("max_height") - - if min_height >= max_height: - res.errors.append("Minimum height must be lower than maximum height") - # Returning early because min and max can be slided, - # so we avoid loading other maps every time to do further checks. - return res - - var image_size_result = _load_image_size(heightmap_path, _logger, bit_depth) - if image_size_result.error_code != OK: - res.errors.append(str("Cannot open heightmap file: ", image_size_result.to_string())) - return res - - var adjusted_size = HTerrainData.get_adjusted_map_size( - image_size_result.width, image_size_result.height) - - if adjusted_size != image_size_result.width: - res.warnings.append( - "The square resolution deduced from heightmap file size is not power of two + 1.\n" + \ - "The heightmap will be cropped.") - - heightmap_size = adjusted_size - - if splatmap_path != "": - _check_map_size(splatmap_path, "splatmap", heightmap_size, bit_depth, res, _logger) - - if colormap_path != "": - _check_map_size(colormap_path, "colormap", heightmap_size, bit_depth, res, _logger) - - return res - - -static func _check_map_size(path: String, map_name: String, heightmap_size: int, bit_depth: int, - res: HT_ErrorCheckReport, logger): - - var size_result := _load_image_size(path, logger, bit_depth) - if size_result.error_code != OK: - res.errors.append(str("Cannot open splatmap file: ", size_result.to_string())) - return - var adjusted_size := HTerrainData.get_adjusted_map_size(size_result.width, size_result.height) - if adjusted_size != heightmap_size: - res.errors.append(str( - "The ", map_name, - " must have the same resolution as the heightmap (", heightmap_size, ")")) - else: - if adjusted_size != size_result.width: - res.warnings.append(str( - "The square resolution deduced from ", map_name, - " file size is not power of two + 1.\nThe ", - map_name, " will be cropped.")) - - -class HT_ImageSizeResult: - var width := 0 - var height := 0 - var error_code := OK - var error_message := "" - - func to_string() -> String: - if error_message != "": - return error_message - return HT_Errors.get_message(error_code) - - -static func _load_image_size(path: String, logger, bit_depth: int) -> HT_ImageSizeResult: - var ext := path.get_extension().to_lower() - var result := HT_ImageSizeResult.new() - - if ext == "png" or ext == "exr": - # Godot can load these formats natively - var im := Image.new() - var err := im.load(ProjectSettings.globalize_path(path)) - if err != OK: - logger.error("An error occurred loading image '{0}', code {1}".format([path, err])) - result.error_code = err - return result - - result.width = im.get_width() - result.height = im.get_height() - return result - - elif ext == "raw": - var f := FileAccess.open(path, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - logger.error("Error opening file {0}".format([path])) - result.error_code = err - return result - - # Assume the raw data is square, so its size is function of file length - var flen := f.get_length() - f = null - var size_px = HT_Util.integer_square_root(flen / (bit_depth/8)) - if size_px == -1: - result.error_code = ERR_INVALID_DATA - result.error_message = "RAW image is not square or your bit depth choice is incorrect…" - return result - - logger.debug("Deduced RAW heightmap resolution: {0}*{1}, for a length of {2}" \ - .format([size_px, size_px, flen])) - - result.width = size_px - result.height = size_px - return result - - elif ext == "xyz": - var f := FileAccess.open(path, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - logger.error("Error opening file {0}".format([path])) - result.error_code = err - return result - - var bounds := HT_XYZFormat.load_bounds(f) - - result.width = bounds.image_width - result.height = bounds.image_height - return result - - else: - result.error_code = ERR_FILE_UNRECOGNIZED - return result diff --git a/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd.uid deleted file mode 100644 index b9f1353..0000000 --- a/godot/addons/zylann.hterrain/tools/importer/importer_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bn813omf284q3 diff --git a/godot/addons/zylann.hterrain/tools/importer/importer_dialog.tscn b/godot/addons/zylann.hterrain/tools/importer/importer_dialog.tscn deleted file mode 100644 index 0c2d267..0000000 --- a/godot/addons/zylann.hterrain/tools/importer/importer_dialog.tscn +++ /dev/null @@ -1,87 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://on7x7xkovsc8"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/importer/importer_dialog.gd" id="1"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/inspector/inspector.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="3"] - -[node name="WindowDialog" type="AcceptDialog"] -title = "Import maps" -size = Vector2i(500, 433) -min_size = Vector2i(500, 380) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="Label" type="Label" parent="VBoxContainer"] -layout_mode = 2 -text = "Select maps to import. Leave empty if you don't need some." - -[node name="Spacer" type="Control" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 16) -layout_mode = 2 - -[node name="Inspector" parent="VBoxContainer" instance=ExtResource("2")] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="ColorRect" type="ColorRect" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 100) -layout_mode = 2 -color = Color(0, 0, 0, 0.417529) - -[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/ColorRect"] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 - -[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/ColorRect/ScrollContainer"] -layout_mode = 2 - -[node name="Errors" type="Label" parent="VBoxContainer/ColorRect/ScrollContainer/VBoxContainer"] -self_modulate = Color(1, 0.203125, 0.203125, 1) -layout_mode = 2 - -[node name="Warnings" type="Label" parent="VBoxContainer/ColorRect/ScrollContainer/VBoxContainer"] -self_modulate = Color(1, 0.901428, 0.257813, 1) -layout_mode = 2 - -[node name="Spacer2" type="Control" parent="VBoxContainer"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="ButtonsArea" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -mouse_filter = 0 -alignment = 1 - -[node name="CheckButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Check" - -[node name="ImportButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Import" - -[node name="CancelButton" type="Button" parent="VBoxContainer/ButtonsArea"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("3")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 492.0 -offset_bottom = 415.0 - -[connection signal="property_changed" from="VBoxContainer/Inspector" to="." method="_on_Inspector_property_changed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/CheckButton" to="." method="_on_CheckButton_pressed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="VBoxContainer/ButtonsArea/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/inspector/inspector.gd b/godot/addons/zylann.hterrain/tools/inspector/inspector.gd deleted file mode 100644 index be14635..0000000 --- a/godot/addons/zylann.hterrain/tools/inspector/inspector.gd +++ /dev/null @@ -1,484 +0,0 @@ - -# GDScript implementation of an inspector. -# It generates controls for a provided list of properties, -# which is easier to maintain than placing them by hand and connecting things in the editor. - -@tool -extends Control - -const USAGE_FILE = "file" -const USAGE_ENUM = "enum" - -signal property_changed(key, value) - -# Used for most simple types -class HT_InspectorEditor: - var control = null - var getter := Callable() - var setter := Callable() - var key_label : Label - - -# Used when the control cannot hold the actual value -class HT_InspectorResourceEditor extends HT_InspectorEditor: - var value = null - var label = null - - func get_value(): - return value - - func set_value(v): - value = v - label.text = "null" if v == null else v.resource_path - - -class HT_InspectorVectorEditor extends HT_InspectorEditor: - signal value_changed(v) - - var value := Vector2() - var xed = null - var yed = null - - func get_value(): - return value - - func set_value(v): - xed.value = v.x - yed.value = v.y - value = v - - func _component_changed(v, i): - value[i] = v - value_changed.emit(value) - - -# TODO Rename _schema -var _prototype = null -var _edit_signal := true -# name => editor -var _editors := {} - -# Had to separate the container because otherwise I can't open dialogs properly... -@onready var _grid_container = get_node("GridContainer") -@onready var _file_dialog = get_node("OpenFileDialog") - - -func _ready(): - _file_dialog.visibility_changed.connect( - call_deferred.bind("_on_file_dialog_visibility_changed")) -# Test -# set_prototype({ -# "seed": { -# "type": TYPE_INT, -# "randomizable": true -# }, -# "base_height": { -# "type": TYPE_REAL, -# "range": {"min": -1000.0, "max": 1000.0, "step": 0.1} -# }, -# "height_range": { -# "type": TYPE_REAL, -# "range": {"min": -1000.0, "max": 1000.0, "step": 0.1 }, -# "default_value": 500.0 -# }, -# "streamed": { -# "type": TYPE_BOOL -# }, -# "texture": { -# "type": TYPE_OBJECT, -# "object_type": Resource -# } -# }) - - -# TODO Rename clear_schema -func clear_prototype(): - _editors.clear() - var i = _grid_container.get_child_count() - 1 - while i >= 0: - var child = _grid_container.get_child(i) - _grid_container.remove_child(child) - child.call_deferred("free") - i -= 1 - _prototype = null - - -func get_value(key: String): - var editor = _editors[key] - return editor.getter.call() - - -func get_values(): - var values = {} - for key in _editors: - var editor = _editors[key] - values[key] = editor.getter.call() - return values - - -func set_value(key: String, value): - var editor = _editors[key] - editor.setter.call(value) - - -func set_values(values: Dictionary): - for key in values: - if _editors.has(key): - var editor = _editors[key] - var v = values[key] - editor.setter.call(v) - - -# TODO Rename set_schema -func set_prototype(proto: Dictionary): - clear_prototype() - - for key in proto: - var prop = proto[key] - - var label := Label.new() - label.text = str(key).capitalize() - _grid_container.add_child(label) - - var editor := _make_editor(key, prop) - editor.key_label = label - - if prop.has("default_value"): - editor.setter.call(prop.default_value) - - _editors[key] = editor - - if prop.has("enabled"): - set_property_enabled(key, prop.enabled) - - _grid_container.add_child(editor.control) - - _prototype = proto - - -func trigger_all_modified(): - for key in _prototype: - var value = _editors[key].getter.call_func() - property_changed.emit(key, value) - - -func set_property_enabled(prop_name: String, enabled: bool): - var ed = _editors[prop_name] - - if ed.control is BaseButton: - ed.control.disabled = not enabled - - elif ed.control is SpinBox: - ed.control.editable = enabled - - elif ed.control is LineEdit: - ed.control.editable = enabled - - # TODO Support more editors - - var col = ed.key_label.modulate - if enabled: - col.a = 1.0 - else: - col.a = 0.5 - ed.key_label.modulate = col - - -func _make_editor(key: String, prop: Dictionary) -> HT_InspectorEditor: - var ed : HT_InspectorEditor = null - - var editor : Control = null - var getter : Callable - var setter : Callable - var extra = null - - match prop.type: - TYPE_INT, \ - TYPE_FLOAT: - var pre = null - if prop.has("randomizable") and prop.randomizable: - editor = HBoxContainer.new() - pre = Button.new() - pre.pressed.connect(_randomize_property_pressed.bind(key)) - pre.text = "Randomize" - editor.add_child(pre) - - if prop.type == TYPE_INT and prop.has("usage") and prop.usage == USAGE_ENUM: - # Enumerated value - assert(prop.has("enum_items")) - var option_button := OptionButton.new() - - for i in len(prop.enum_items): - var item:Array = prop.enum_items[i] - var value:int = item[0] - var text:String = item[1] - option_button.add_item(text, value) - - getter = option_button.get_selected_id - setter = func select_id(id: int): - var index:int = option_button.get_item_index(id) - assert(index >= 0) - option_button.select(index) - - option_button.item_selected.connect(_property_edited.bind(key)) - - editor = option_button - - else: - # Numeric value - var spinbox := SpinBox.new() - # Spinboxes have shit UX when not expanded... - spinbox.custom_minimum_size = Vector2(120, 16) - _setup_range_control(spinbox, prop) - spinbox.value_changed.connect(_property_edited.bind(key)) - - # TODO In case the type is INT, the getter should return an integer! - getter = spinbox.get_value - setter = spinbox.set_value - - var show_slider = prop.has("range") \ - and not (prop.has("slidable") \ - and prop.slidable == false) - - if show_slider: - if editor == null: - editor = HBoxContainer.new() - var slider := HSlider.new() - # Need to give some size because otherwise the slider is hard to click... - slider.custom_minimum_size = Vector2(32, 16) - _setup_range_control(slider, prop) - slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL - spinbox.share(slider) - editor.add_child(slider) - editor.add_child(spinbox) - else: - spinbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL - if editor == null: - editor = spinbox - else: - editor.add_child(spinbox) - - TYPE_STRING: - if prop.has("usage") and prop.usage == USAGE_FILE: - editor = HBoxContainer.new() - - var line_edit := LineEdit.new() - line_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL - editor.add_child(line_edit) - - var exts = [] - if prop.has("exts"): - exts = prop.exts - - var load_button := Button.new() - load_button.text = "..." - load_button.pressed.connect(_on_ask_load_file.bind(key, exts)) - editor.add_child(load_button) - - line_edit.text_submitted.connect(_property_edited.bind(key)) - getter = line_edit.get_text - setter = line_edit.set_text - - else: - editor = LineEdit.new() - editor.text_submitted.connect(_property_edited.bind(key)) - getter = editor.get_text - setter = editor.set_text - - TYPE_COLOR: - editor = ColorPickerButton.new() - editor.color_changed.connect(_property_edited.bind(key)) - getter = editor.get_pick_color - setter = editor.set_pick_color - - TYPE_BOOL: - editor = CheckBox.new() - editor.toggled.connect(_property_edited.bind(key)) - getter = editor.is_pressed - setter = editor.set_pressed - - TYPE_OBJECT: - # TODO How do I even check inheritance if I work on the class themselves, not instances? - if prop.object_type == Resource: - editor = HBoxContainer.new() - - var label := Label.new() - label.text = "null" - label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - label.clip_text = true - label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - editor.add_child(label) - - var load_button := Button.new() - load_button.text = "Load..." - load_button.pressed.connect(_on_ask_load_texture.bind(key)) - editor.add_child(load_button) - - var clear_button := Button.new() - clear_button.text = "Clear" - clear_button.pressed.connect(_on_ask_clear_texture.bind(key)) - editor.add_child(clear_button) - - ed = HT_InspectorResourceEditor.new() - ed.label = label - getter = ed.get_value - setter = ed.set_value - - TYPE_VECTOR2: - editor = HBoxContainer.new() - - ed = HT_InspectorVectorEditor.new() - - var xlabel := Label.new() - xlabel.text = "x" - editor.add_child(xlabel) - var xed := SpinBox.new() - xed.size_flags_horizontal = Control.SIZE_EXPAND_FILL - xed.step = 0.01 - xed.min_value = -10000 - xed.max_value = 10000 - # TODO This will fire twice (for each coordinate), hmmm... - xed.value_changed.connect(ed._component_changed.bind(0)) - editor.add_child(xed) - - var ylabel := Label.new() - ylabel.text = "y" - editor.add_child(ylabel) - var yed = SpinBox.new() - yed.size_flags_horizontal = Control.SIZE_EXPAND_FILL - yed.step = 0.01 - yed.min_value = -10000 - yed.max_value = 10000 - yed.value_changed.connect(ed._component_changed.bind(1)) - editor.add_child(yed) - - ed.xed = xed - ed.yed = yed - ed.value_changed.connect(_property_edited.bind(key)) - getter = ed.get_value - setter = ed.set_value - - _: - editor = Label.new() - editor.text = "" - getter = _dummy_getter - setter = _dummy_setter - - if not(editor is CheckButton): - editor.size_flags_horizontal = Control.SIZE_EXPAND_FILL - - if ed == null: - # Default - ed = HT_InspectorEditor.new() - ed.control = editor - ed.getter = getter - ed.setter = setter - - return ed - - -static func _setup_range_control(range_control: Range, prop): - if prop.type == TYPE_INT: - range_control.step = 1 - range_control.rounded = true - else: - range_control.step = 0.1 - if prop.has("range"): - range_control.min_value = prop.range.min - range_control.max_value = prop.range.max - if prop.range.has("step"): - range_control.step = prop.range.step - else: - # Where is INT_MAX?? - range_control.min_value = -0x7fffffff - range_control.max_value = 0x7fffffff - - -func _property_edited(value, key): - if _edit_signal: - property_changed.emit(key, value) - - -func _randomize_property_pressed(key): - var prop = _prototype[key] - var v = 0 - - # TODO Support range step - match prop.type: - TYPE_INT: - if prop.has("range"): - v = randi() % (prop.range.max - prop.range.min) + prop.range.min - else: - v = randi() - 0x7fffffff - TYPE_FLOAT: - if prop.has("range"): - v = randf_range(prop.range.min, prop.range.max) - else: - v = randf() - - _editors[key].setter.call(v) - - -func _dummy_getter(): - pass - - -func _dummy_setter(v): - # TODO Could use extra data to store the value anyways? - pass - - -func _on_ask_load_texture(key): - _open_file_dialog(["*.png ; PNG files"], _on_texture_selected.bind(key), - FileDialog.ACCESS_RESOURCES) - - -func _open_file_dialog(filters: Array, callback: Callable, access: int): - _file_dialog.access = access - _file_dialog.clear_filters() - for filter in filters: - _file_dialog.add_filter(filter) - - # Can't just use one-shot signals because the dialog could be closed without choosing a file... -# if not _file_dialog.file_selected.is_connected(callback): -# _file_dialog.file_selected.connect(callback, Object.CONNECT_ONE_SHOT) - _file_dialog.file_selected.connect(callback) - - _file_dialog.popup_centered_ratio(0.7) - - -func _on_file_dialog_visibility_changed(): - if _file_dialog.visible == false: - # Disconnect listeners automatically, - # so we can re-use the same dialog with different listeners - var cons = _file_dialog.get_signal_connection_list("file_selected") - for con in cons: - _file_dialog.file_selected.disconnect(con.callable) - - -func _on_texture_selected(path: String, key): - var tex = load(path) - if tex == null: - return - var ed = _editors[key] - ed.setter.call(tex) - _property_edited(tex, key) - - -func _on_ask_clear_texture(key): - var ed = _editors[key] - ed.setter.call(null) - _property_edited(null, key) - - -func _on_ask_load_file(key, exts): - var filters := [] - for ext in exts: - filters.append(str("*.", ext, " ; ", ext.to_upper(), " files")) - _open_file_dialog(filters, _on_file_selected.bind(key), FileDialog.ACCESS_FILESYSTEM) - - -func _on_file_selected(path, key): - var ed = _editors[key] - ed.setter.call(path) - _property_edited(path, key) diff --git a/godot/addons/zylann.hterrain/tools/inspector/inspector.gd.uid b/godot/addons/zylann.hterrain/tools/inspector/inspector.gd.uid deleted file mode 100644 index 643731d..0000000 --- a/godot/addons/zylann.hterrain/tools/inspector/inspector.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b5pq00j5ejcx1 diff --git a/godot/addons/zylann.hterrain/tools/inspector/inspector.tscn b/godot/addons/zylann.hterrain/tools/inspector/inspector.tscn deleted file mode 100644 index 4bd1395..0000000 --- a/godot/addons/zylann.hterrain/tools/inspector/inspector.tscn +++ /dev/null @@ -1,15 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dfjip6c4olemn"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/inspector/inspector.gd" id="1"] - -[node name="Inspector" type="VBoxContainer"] -script = ExtResource("1") - -[node name="GridContainer" type="GridContainer" parent="."] -layout_mode = 2 -columns = 2 - -[node name="OpenFileDialog" type="FileDialog" parent="."] -title = "Open a File" -ok_button_text = "Open" -file_mode = 0 diff --git a/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd b/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd deleted file mode 100644 index 6d1e874..0000000 --- a/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd +++ /dev/null @@ -1,22 +0,0 @@ -@tool -extends EditorFileDialog - - -func _init(): - #access = EditorFileDialog.ACCESS_RESOURCES - file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - # TODO I actually want a dialog to load a texture, not specifically a PNG... - add_filter("*.png ; PNG files") - add_filter("*.jpg ; JPG files") - unresizable = false - access = EditorFileDialog.ACCESS_RESOURCES - close_requested.connect(call_deferred.bind("_on_close")) - - -func _on_close(): - # Disconnect listeners automatically, - # so we can re-use the same dialog with different listeners - var cons = get_signal_connection_list("file_selected") - for con in cons: - file_selected.disconnect(con.callable) - diff --git a/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd.uid deleted file mode 100644 index 653a8d5..0000000 --- a/godot/addons/zylann.hterrain/tools/load_texture_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://h1lt75pocf7h diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap.gd b/godot/addons/zylann.hterrain/tools/minimap/minimap.gd deleted file mode 100644 index f71295a..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap.gd +++ /dev/null @@ -1,140 +0,0 @@ -@tool -extends Control - -const HT_Util = preload("../../util/util.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") -const HT_MinimapOverlay = preload("./minimap_overlay.gd") - -const HT_MinimapShader = preload("./minimap_normal.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_WhiteTexture = preload("../icons/white.png") -const WHITE_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/white.png" - -const MODE_QUADTREE = 0 -const MODE_NORMAL = 1 - -@onready var _popup_menu : PopupMenu = $PopupMenu -@onready var _color_rect : ColorRect = $ColorRect -@onready var _overlay : HT_MinimapOverlay = $Overlay - -var _terrain : HTerrain = null -var _mode := MODE_NORMAL -var _camera_transform := Transform3D() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - _set_mode(_mode) - - _popup_menu.add_item("Quadtree mode", MODE_QUADTREE) - _popup_menu.add_item("Normal mode", MODE_NORMAL) - - -func set_terrain(node: HTerrain): - if _terrain != node: - _terrain = node - set_process(_terrain != null) - - -func set_camera_transform(ct: Transform3D): - if _camera_transform == ct: - return - if _terrain == null: - return - var data = _terrain.get_data() - if data == null: - return - var to_local := _terrain.get_internal_transform().affine_inverse() - var pos := _get_xz(to_local * _camera_transform.origin) - var size := Vector2(data.get_resolution(), data.get_resolution()) - pos /= size - var dir := _get_xz(to_local.basis * (-_camera_transform.basis.z)).normalized() - _overlay.set_cursor_position_normalized(pos, dir) - _camera_transform = ct - - -static func _get_xz(v: Vector3) -> Vector2: - return Vector2(v.x, v.z) - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - match event.button_index: - MOUSE_BUTTON_RIGHT: - _popup_menu.position = get_screen_position() + event.position - _popup_menu.popup() - MOUSE_BUTTON_LEFT: - # Teleport there? - pass - - -func _process(delta): - if _terrain != null: - if _mode == MODE_QUADTREE: - queue_redraw() - else: - _update_normal_material() - - -func _set_mode(mode: int): - if mode == MODE_QUADTREE: - _color_rect.hide() - else: - var mat := ShaderMaterial.new() - mat.shader = HT_MinimapShader - _color_rect.material = mat - _color_rect.show() - _update_normal_material() - _mode = mode - queue_redraw() - - -func _update_normal_material(): - if _terrain == null: - return - var data : HTerrainData = _terrain.get_data() - if data == null: - return - - var normalmap = data.get_texture(HTerrainData.CHANNEL_NORMAL) - _set_if_changed(_color_rect.material, "u_normalmap", normalmap) - - var globalmap : Texture - if data.has_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO, 0): - globalmap = data.get_texture(HTerrainData.CHANNEL_GLOBAL_ALBEDO) - if globalmap == null: - globalmap = load(WHITE_TEXTURE_PATH) - _set_if_changed(_color_rect.material, "u_globalmap", globalmap) - - -# Need to check if it has changed, otherwise Godot's update spinner -# indicates that the editor keeps redrawing every frame, -# which is not intended and consumes more power. -static func _set_if_changed(sm: ShaderMaterial, param: String, v): - if sm.get_shader_parameter(param) != v: - sm.set_shader_parameter(param, v) - - -func _draw(): - if _terrain == null: - return - - if _mode == MODE_QUADTREE: - var lod_count := _terrain.get_lod_count() - - if lod_count > 0: - # Fit drawing to rect - - var qsize = 1 << (lod_count - 1) - var vsize := size - draw_set_transform(Vector2(0, 0), 0, Vector2(vsize.x / qsize, vsize.y / qsize)) - - _terrain._edit_debug_draw(self) - - -func _on_PopupMenu_id_pressed(id: int): - _set_mode(id) diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap.gd.uid b/godot/addons/zylann.hterrain/tools/minimap/minimap.gd.uid deleted file mode 100644 index dc45b88..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://g7hw225c3sei diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap.tscn b/godot/addons/zylann.hterrain/tools/minimap/minimap.tscn deleted file mode 100644 index b2a7ef5..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap.tscn +++ /dev/null @@ -1,56 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://cba6k3hrwhrke"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/minimap.gd" id="1"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader" id="2"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/minimap_overlay.gd" id="3"] -[ext_resource type="Texture2D" uid="uid://c1el0dmyvaaij" path="res://addons/zylann.hterrain/tools/icons/icon_minimap_position.svg" id="4"] -[ext_resource type="Texture2D" uid="uid://cc47smy24m368" path="res://addons/zylann.hterrain/tools/icons/icon_minimap_out_of_range_position.svg" id="5"] - -[sub_resource type="ShaderMaterial" id="1"] -shader = ExtResource("2") -shader_parameter/u_light_direction = Vector3(0.5, -0.7, 0.2) - -[node name="Minimap" type="Control"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 3 -anchors_preset = 0 -offset_right = 100.0 -offset_bottom = 100.0 -script = ExtResource("1") - -[node name="PopupMenu" type="PopupMenu" parent="."] - -[node name="ColorRect" type="ColorRect" parent="."] -material = SubResource("1") -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 - -[node name="X" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.929412, 0.290196, 0.290196, 0.627451) - -[node name="Z" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.0784314, 0.501961, 1, 0.627451) - -[node name="Y" type="ColorRect" parent="."] -layout_mode = 0 -mouse_filter = 2 -color = Color(0.207843, 0.835294, 0.152941, 0.627451) - -[node name="Overlay" type="Control" parent="."] -anchors_preset = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 2 -script = ExtResource("3") -cursor_texture = ExtResource("4") -out_of_range_texture = ExtResource("5") - -[node name="Cursor" type="Sprite2D" parent="Overlay"] - -[connection signal="id_pressed" from="PopupMenu" to="." method="_on_PopupMenu_id_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader b/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader deleted file mode 100644 index 0ea3120..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader +++ /dev/null @@ -1,24 +0,0 @@ -shader_type canvas_item; - -uniform sampler2D u_normalmap; -uniform sampler2D u_globalmap; -uniform vec3 u_light_direction = vec3(0.5, -0.7, 0.2); - -vec3 unpack_normal(vec4 rgba) { - return rgba.xzy * 2.0 - vec3(1.0); -} - -void fragment() { - vec3 albedo = texture(u_globalmap, UV).rgb; - // Undo sRGB - // TODO I don't know what is correct tbh, this didn't work well - //albedo *= pow(albedo, vec3(0.4545)); - //albedo *= pow(albedo, vec3(1.0 / 0.4545)); - albedo = sqrt(albedo); - - vec3 normal = unpack_normal(texture(u_normalmap, UV)); - float g = max(-dot(u_light_direction, normal), 0.0); - - COLOR = vec4(albedo * g, 1.0); -} - diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader.uid b/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader.uid deleted file mode 100644 index 1f4ea10..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap_normal.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cxkvkj2f5s5d2 diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd b/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd deleted file mode 100644 index 93c6695..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd +++ /dev/null @@ -1,24 +0,0 @@ -@tool -extends Control - - -@export var cursor_texture : Texture -@export var out_of_range_texture : Texture - -@onready var _sprite : Sprite2D = $Cursor - -var _pos := Vector2() -var _rot := 0.0 - - -func set_cursor_position_normalized(pos_norm: Vector2, dir: Vector2): - if Rect2(0, 0, 1, 1).has_point(pos_norm): - _sprite.texture = cursor_texture - else: - pos_norm.x = clampf(pos_norm.x, 0.0, 1.0) - pos_norm.y = clampf(pos_norm.y, 0.0, 1.0) - _sprite.texture = out_of_range_texture - - _sprite.position = pos_norm * size - _sprite.rotation = dir.angle() - diff --git a/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd.uid b/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd.uid deleted file mode 100644 index 40244c0..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/minimap_overlay.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0lsikyx6fmy1 diff --git a/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd b/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd deleted file mode 100644 index 1bd6aca..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd +++ /dev/null @@ -1,32 +0,0 @@ -# Simple container keeping its children under the same aspect ratio - -@tool -extends Container - - -@export var ratio := 1.0 - - -func _notification(what: int): - if what == NOTIFICATION_SORT_CHILDREN: - _sort_children2() - - -# TODO Function with ugly name to workaround a Godot 3.1 issue -# See https://github.com/godotengine/godot/pull/38396 -func _sort_children2(): - for i in get_child_count(): - var child = get_child(i) - if not (child is Control): - continue - var w := size.x - var h := size.x / ratio - - if h > size.y: - h = size.y - w = h * ratio - - var rect := Rect2(0, 0, w, h) - - fit_child_in_rect(child, rect) - diff --git a/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd.uid b/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd.uid deleted file mode 100644 index 73811c0..0000000 --- a/godot/addons/zylann.hterrain/tools/minimap/ratio_container.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://blr7b3muu5600 diff --git a/godot/addons/zylann.hterrain/tools/normalmap_baker.gd b/godot/addons/zylann.hterrain/tools/normalmap_baker.gd deleted file mode 100644 index e5af37d..0000000 --- a/godot/addons/zylann.hterrain/tools/normalmap_baker.gd +++ /dev/null @@ -1,148 +0,0 @@ - -# Bakes normals asynchronously in the editor as the heightmap gets modified. -# It uses the heightmap texture to change the normalmap image, which is then uploaded like an edit. -# This is probably not a nice method GPU-wise, but it's way faster than GDScript. - -@tool -extends Node - -const HTerrainData = preload("../hterrain_data.gd") - -const VIEWPORT_SIZE = 64 - -const STATE_PENDING = 0 -const STATE_PROCESSING = 1 - -var _viewport : SubViewport = null -var _ci : Sprite2D = null -var _pending_tiles_grid := {} -var _pending_tiles_queue := [] -var _processing_tile = null -var _terrain_data : HTerrainData = null - - -func _init(): - assert(VIEWPORT_SIZE <= HTerrainData.MIN_RESOLUTION) - _viewport = SubViewport.new() - _viewport.size = Vector2(VIEWPORT_SIZE + 2, VIEWPORT_SIZE + 2) - _viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED - _viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS - # We only render 2D, but we don't want the parent world to interfere - _viewport.world_3d = World3D.new() - _viewport.own_world_3d = true - add_child(_viewport) - - var mat = ShaderMaterial.new() - mat.shader = load("res://addons/zylann.hterrain/tools/bump2normal_tex.gdshader") - - _ci = Sprite2D.new() - _ci.centered = false - _ci.material = mat - _viewport.add_child(_ci) - - set_process(false) - - -func set_terrain_data(data: HTerrainData): - if data == _terrain_data: - return - - _pending_tiles_grid.clear() - _pending_tiles_queue.clear() - _processing_tile = null - _ci.texture = null - set_process(false) - - if data == null: - _terrain_data.map_changed.disconnect(_on_terrain_data_map_changed) - _terrain_data.resolution_changed.disconnect(_on_terrain_data_resolution_changed) - - _terrain_data = data - - if _terrain_data != null: - _terrain_data.map_changed.connect(_on_terrain_data_map_changed) - _terrain_data.resolution_changed.connect(_on_terrain_data_resolution_changed) - _ci.texture = data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - -func _on_terrain_data_map_changed(maptype: int, index: int): - if maptype == HTerrainData.CHANNEL_HEIGHT: - _ci.texture = _terrain_data.get_texture(HTerrainData.CHANNEL_HEIGHT) - - -func _on_terrain_data_resolution_changed(): - # TODO Workaround issue https://github.com/godotengine/godot/issues/24463 - _ci.queue_redraw() - - -# TODO Use Vector2i -func request_tiles_in_region(min_pos: Vector2, size: Vector2): - assert(is_inside_tree()) - assert(_terrain_data != null) - var res = _terrain_data.get_resolution() - - min_pos -= Vector2(1, 1) - var max_pos = min_pos + size + Vector2(1, 1) - var tmin = (min_pos / VIEWPORT_SIZE).floor() - var tmax = (max_pos / VIEWPORT_SIZE).ceil() - var ntx = res / VIEWPORT_SIZE - var nty = res / VIEWPORT_SIZE - tmin.x = clamp(tmin.x, 0, ntx) - tmin.y = clamp(tmin.y, 0, nty) - tmax.x = clamp(tmax.x, 0, ntx) - tmax.y = clamp(tmax.y, 0, nty) - - for y in range(tmin.y, tmax.y): - for x in range(tmin.x, tmax.x): - request_tile(Vector2(x, y)) - - -# TODO Use Vector2i -func request_tile(tpos: Vector2): - assert(tpos == tpos.round()) - if _pending_tiles_grid.has(tpos): - var state = _pending_tiles_grid[tpos] - if state == STATE_PENDING: - return - _pending_tiles_grid[tpos] = STATE_PENDING - _pending_tiles_queue.push_front(tpos) - set_process(true) - - -func _process(delta): - if not is_processing(): - return - - if _processing_tile != null and _terrain_data != null: - var src = _viewport.get_texture().get_image() - var dst = _terrain_data.get_image(HTerrainData.CHANNEL_NORMAL) - - src.convert(dst.get_format()) - #src.save_png(str("test_", _processing_tile.x, "_", _processing_tile.y, ".png")) - var pos = _processing_tile * VIEWPORT_SIZE - var w = src.get_width() - 1 - var h = src.get_height() - 1 - dst.blit_rect(src, Rect2i(1, 1, w, h), pos) - _terrain_data.notify_region_change(Rect2(pos.x, pos.y, w, h), HTerrainData.CHANNEL_NORMAL) - - if _pending_tiles_grid[_processing_tile] == STATE_PROCESSING: - _pending_tiles_grid.erase(_processing_tile) - _processing_tile = null - - if _has_pending_tiles(): - var tpos = _pending_tiles_queue[-1] - _pending_tiles_queue.pop_back() - # The sprite will be much larger than the viewport due to the size of the heightmap. - # We move it around so the part inside the viewport will correspond to the tile. - _ci.position = -VIEWPORT_SIZE * tpos + Vector2(1, 1) - _viewport.render_target_update_mode = SubViewport.UPDATE_ONCE - _processing_tile = tpos - _pending_tiles_grid[tpos] = STATE_PROCESSING - else: - set_process(false) - - -func _has_pending_tiles(): - return len(_pending_tiles_queue) > 0 - - diff --git a/godot/addons/zylann.hterrain/tools/normalmap_baker.gd.uid b/godot/addons/zylann.hterrain/tools/normalmap_baker.gd.uid deleted file mode 100644 index 2ecd156..0000000 --- a/godot/addons/zylann.hterrain/tools/normalmap_baker.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dc5exqyxq7hlx diff --git a/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd b/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd deleted file mode 100644 index 35455d6..0000000 --- a/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd +++ /dev/null @@ -1,86 +0,0 @@ -@tool - -const HT_Logger = preload("../../util/logger.gd") -const HT_Errors = preload("../../util/errors.gd") -const HT_Result = preload("../util/result.gd") - -const _transform_params = [ - "normalmap_flip_y" -] - - -# sources: { -# "a": "path_to_image_where_red_channel_will_be_stored_in_alpha.png", -# "rgb": "path_to_image_where_rgb_channels_will_be_stored.png" -# "rgba": "path_to_image.png", -# "rgb": "#hexcolor" -# } -static func generate_image(sources: Dictionary, resolution: int, logger) -> HT_Result: - var image := Image.create(resolution, resolution, true, Image.FORMAT_RGBA8) - - var flip_normalmap_y := false - - # TODO Accelerate with GDNative - for key in sources: - if key in _transform_params: - continue - - var src_path : String = sources[key] - - logger.debug(str("Processing source \"", src_path, "\"")) - - var src_image : Image - if src_path.begins_with("#"): - # Plain color - var col = Color(src_path) - src_image = Image.create(resolution, resolution, false, Image.FORMAT_RGBA8) - src_image.fill(col) - - else: - # File - src_image = Image.new() - var err := src_image.load(ProjectSettings.globalize_path(src_path)) - if err != OK: - return HT_Result.new(false, "Could not open file \"{0}\": {1}" \ - .format([src_path, HT_Errors.get_message(err)])) \ - .with_value(err) - src_image.decompress() - - src_image.resize(image.get_width(), image.get_height()) - - # TODO Support more channel configurations - if key == "rgb": - for y in image.get_height(): - for x in image.get_width(): - var dst_col := image.get_pixel(x, y) - var a := dst_col.a - dst_col = src_image.get_pixel(x, y) - dst_col.a = a - image.set_pixel(x, y, dst_col) - - elif key == "a": - for y in image.get_height(): - for x in image.get_width(): - var dst_col := image.get_pixel(x, y) - dst_col.a = src_image.get_pixel(x, y).r - image.set_pixel(x, y, dst_col) - - elif key == "rgba": - # Meh - image.blit_rect(src_image, - Rect2i(0, 0, image.get_width(), image.get_height()), Vector2i()) - - if sources.has("normalmap_flip_y") and sources.normalmap_flip_y: - _flip_normalmap_y(image) - - return HT_Result.new(true).with_value(image) - - -static func _flip_normalmap_y(image: Image): - for y in image.get_height(): - for x in image.get_width(): - var col := image.get_pixel(x, y) - col.g = 1.0 - col.g - image.set_pixel(x, y, col) - - diff --git a/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd.uid b/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd.uid deleted file mode 100644 index 4218b74..0000000 --- a/godot/addons/zylann.hterrain/tools/packed_textures/packed_texture_util.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dnwv4ni5c44lh diff --git a/godot/addons/zylann.hterrain/tools/panel.gd b/godot/addons/zylann.hterrain/tools/panel.gd deleted file mode 100644 index 307e008..0000000 --- a/godot/addons/zylann.hterrain/tools/panel.gd +++ /dev/null @@ -1,75 +0,0 @@ -@tool -extends Control - -const HT_DetailEditor = preload("./detail_editor/detail_editor.gd") - - -# Emitted when a texture item is selected -signal texture_selected(index) -signal edit_texture_pressed(index) -signal import_textures_pressed - -# Emitted when a detail item is selected (grass painting) -signal detail_selected(index) -signal detail_list_changed - - -@onready var _minimap = $HSplitContainer/HSplitContainer/MinimapContainer/Minimap -@onready var _brush_editor = $HSplitContainer/BrushEditor -@onready var _texture_editor = $HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor -@onready var _detail_editor : HT_DetailEditor = \ - $HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor - - -func setup_dialogs(base_control: Control): - _brush_editor.setup_dialogs(base_control) - - -func set_terrain(terrain): - _minimap.set_terrain(terrain) - _texture_editor.set_terrain(terrain) - _detail_editor.set_terrain(terrain) - - -func set_undo_redo(undo_manager: EditorUndoRedoManager): - _detail_editor.set_undo_redo(undo_manager) - - -func set_image_cache(image_cache): - _detail_editor.set_image_cache(image_cache) - - -func set_camera_transform(cam_transform: Transform3D): - _minimap.set_camera_transform(cam_transform) - - -func set_terrain_painter(terrain_painter): - _brush_editor.set_terrain_painter(terrain_painter) - - -func _on_TextureEditor_texture_selected(index): - texture_selected.emit(index) - - -func _on_DetailEditor_detail_selected(index): - detail_selected.emit(index) - - -func set_brush_editor_display_mode(mode): - _brush_editor.set_display_mode(mode) - - -func set_detail_layer_index(index): - _detail_editor.set_layer_index(index) - - -func _on_DetailEditor_detail_list_changed(): - detail_list_changed.emit() - - -func _on_TextureEditor_import_pressed(): - import_textures_pressed.emit() - - -func _on_TextureEditor_edit_pressed(index: int): - edit_texture_pressed.emit(index) diff --git a/godot/addons/zylann.hterrain/tools/panel.gd.uid b/godot/addons/zylann.hterrain/tools/panel.gd.uid deleted file mode 100644 index c53e79b..0000000 --- a/godot/addons/zylann.hterrain/tools/panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://caeya7yehhhuo diff --git a/godot/addons/zylann.hterrain/tools/panel.tscn b/godot/addons/zylann.hterrain/tools/panel.tscn deleted file mode 100644 index 33e856f..0000000 --- a/godot/addons/zylann.hterrain/tools/panel.tscn +++ /dev/null @@ -1,58 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://dtdgawtpwfaft"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/panel.gd" id="1"] -[ext_resource type="PackedScene" uid="uid://bd42ig216p216" path="res://addons/zylann.hterrain/tools/brush/brush_editor.tscn" id="2"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn" id="3"] -[ext_resource type="PackedScene" uid="uid://do3c3jse5p7hx" path="res://addons/zylann.hterrain/tools/detail_editor/detail_editor.tscn" id="4"] -[ext_resource type="PackedScene" uid="uid://cba6k3hrwhrke" path="res://addons/zylann.hterrain/tools/minimap/minimap.tscn" id="5"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/minimap/ratio_container.gd" id="6"] - -[node name="Panel" type="Control"] -custom_minimum_size = Vector2(400, 120) -layout_mode = 3 -anchors_preset = 0 -offset_right = 1012.0 -offset_bottom = 120.0 -script = ExtResource("1") - -[node name="HSplitContainer" type="HSplitContainer" parent="."] -layout_mode = 0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 4.0 -offset_top = 4.0 -offset_right = -6.0 -offset_bottom = -4.0 -split_offset = 60 - -[node name="BrushEditor" parent="HSplitContainer" instance=ExtResource("2")] -layout_mode = 2 - -[node name="HSplitContainer" type="HSplitContainer" parent="HSplitContainer"] -layout_mode = 2 - -[node name="HSplitContainer" type="HSplitContainer" parent="HSplitContainer/HSplitContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -split_offset = 300 - -[node name="TextureEditor" parent="HSplitContainer/HSplitContainer/HSplitContainer" instance=ExtResource("3")] -layout_mode = 2 -size_flags_horizontal = 1 - -[node name="DetailEditor" parent="HSplitContainer/HSplitContainer/HSplitContainer" instance=ExtResource("4")] -layout_mode = 2 - -[node name="MinimapContainer" type="Container" parent="HSplitContainer/HSplitContainer"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -script = ExtResource("6") - -[node name="Minimap" parent="HSplitContainer/HSplitContainer/MinimapContainer" instance=ExtResource("5")] -layout_mode = 2 - -[connection signal="edit_pressed" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_edit_pressed"] -[connection signal="import_pressed" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_import_pressed"] -[connection signal="texture_selected" from="HSplitContainer/HSplitContainer/HSplitContainer/TextureEditor" to="." method="_on_TextureEditor_texture_selected"] -[connection signal="detail_list_changed" from="HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor" to="." method="_on_DetailEditor_detail_list_changed"] -[connection signal="detail_selected" from="HSplitContainer/HSplitContainer/HSplitContainer/DetailEditor" to="." method="_on_DetailEditor_detail_selected"] diff --git a/godot/addons/zylann.hterrain/tools/plugin.gd b/godot/addons/zylann.hterrain/tools/plugin.gd deleted file mode 100644 index 0fe645f..0000000 --- a/godot/addons/zylann.hterrain/tools/plugin.gd +++ /dev/null @@ -1,963 +0,0 @@ -@tool # https://www.youtube.com/watch?v=Y7JG63IuaWs - -extends EditorPlugin - -const HTerrain = preload("../hterrain.gd") -const HTerrainDetailLayer = preload("../hterrain_detail_layer.gd") -const HTerrainData = preload("../hterrain_data.gd") -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HTerrainTextureSet = preload("../hterrain_texture_set.gd") -const HT_PreviewGenerator = preload("./preview_generator.gd") -const HT_TerrainPainter = preload("./brush/terrain_painter.gd") -const HT_Brush = preload("./brush/brush.gd") -const HT_BrushDecal = preload("./brush/decal.gd") -const HT_Util = preload("../util/util.gd") -const HT_EditorUtil = preload("./util/editor_util.gd") -const HT_LoadTextureDialog = preload("./load_texture_dialog.gd") -const HT_GlobalMapBaker = preload("./globalmap_baker.gd") -const HT_ImageFileCache = preload("../util/image_file_cache.gd") -const HT_Logger = preload("../util/logger.gd") -const HT_EditPanel = preload("./panel.gd") -const HT_GeneratorDialog = preload("./generator/generator_dialog.gd") -const HT_TextureSetEditor = preload("./texture_editor/set_editor/texture_set_editor.gd") -const HT_TextureSetImportEditor = \ - preload("./texture_editor/set_editor/texture_set_import_editor.gd") -const HT_ProgressWindow = preload("./progress_window.gd") -const HT_BrushEditorOverlay = preload("./brush/brush_editor_overlay.gd") -const HT_BrushEditorOverlayScene = preload("./brush/brush_editor_overlay.tscn") - -const HT_EditPanelScene = preload("./panel.tscn") -const HT_ProgressWindowScene = preload("./progress_window.tscn") -const HT_GeneratorDialogScene = preload("./generator/generator_dialog.tscn") -const HT_ImportDialogScene = preload("./importer/importer_dialog.tscn") -const HT_GenerateMeshDialogScene = preload("./generate_mesh_dialog.tscn") -const HT_ResizeDialogScene = preload("./resize_dialog/resize_dialog.tscn") -const HT_ExportImageDialogScene = preload("./exporter/export_image_dialog.tscn") -const HT_TextureSetEditorScene = preload("./texture_editor/set_editor/texture_set_editor.tscn") -const HT_TextureSetImportEditorScene = \ - preload("./texture_editor/set_editor/texture_set_import_editor.tscn") -const HT_AboutDialogScene = preload("./about/about_dialog.tscn") - -const DOCUMENTATION_URL = "https://hterrain-plugin.readthedocs.io/en/latest" - -const MENU_IMPORT_MAPS = 0 -const MENU_GENERATE = 1 -const MENU_BAKE_GLOBALMAP = 2 -const MENU_RESIZE = 3 -const MENU_UPDATE_EDITOR_COLLIDER = 4 -const MENU_GENERATE_MESH = 5 -const MENU_EXPORT_HEIGHTMAP = 6 -const MENU_LOOKDEV = 7 -const MENU_DOCUMENTATION = 8 -const MENU_ABOUT = 9 - - -# TODO Rename _terrain -var _node : HTerrain = null - -# GUI -var _panel : HT_EditPanel = null -var _toolbar : Container = null -var _toolbar_brush_buttons := {} -var _generator_dialog : HT_GeneratorDialog = null -# TODO Rename _import_terrain_dialog -var _import_dialog = null -var _export_image_dialog = null - -# This window is only used for operations not triggered by an existing dialog. -# In Godot it has been solved by automatically reparenting the dialog: -# https://github.com/godotengine/godot/pull/71209 -# But `get_exclusive_child()` is not exposed. So dialogs triggering a progress -# dialog may need their own child instance... -var _progress_window : HT_ProgressWindow = null - -var _generate_mesh_dialog = null -var _preview_generator : HT_PreviewGenerator = null -var _resize_dialog = null -var _about_dialog = null -var _menu_button : MenuButton -var _lookdev_menu : PopupMenu -var _texture_set_editor : HT_TextureSetEditor = null -var _texture_set_import_editor : HT_TextureSetImportEditor = null - -var _globalmap_baker : HT_GlobalMapBaker = null -var _terrain_had_data_previous_frame := false -var _image_cache : HT_ImageFileCache -var _terrain_painter : HT_TerrainPainter = null -var _brush_decal : HT_BrushDecal = null -var _mouse_pressed := false -#var _pending_paint_action = null -var _pending_paint_commit := false - -var _overlay_selector : HT_BrushEditorOverlay = null -var _editor_viewport : SubViewportContainer - -var _logger := HT_Logger.get_for(self) - - -func get_icon(icon_name: String) -> Texture2D: - return HT_EditorUtil.load_texture( - "res://addons/zylann.hterrain/tools/icons/icon_" + icon_name + ".svg", _logger) - - -func _enter_tree(): - _logger.debug("HTerrain plugin Enter tree") - - var dpi_scale = get_editor_interface().get_editor_scale() - _logger.debug(str("DPI scale: ", dpi_scale)) - - add_custom_type("HTerrain", "Node3D", HTerrain, get_icon("heightmap_node")) - add_custom_type("HTerrainDetailLayer", "Node3D", HTerrainDetailLayer, - get_icon("detail_layer_node")) - add_custom_type("HTerrainData", "Resource", HTerrainData, get_icon("heightmap_data")) - # TODO Proper texture - add_custom_type("HTerrainTextureSet", "Resource", HTerrainTextureSet, null) - - _preview_generator = HT_PreviewGenerator.new() - get_editor_interface().get_resource_previewer().add_preview_generator(_preview_generator) - - _terrain_painter = HT_TerrainPainter.new() - _terrain_painter.set_brush_size(5) - _terrain_painter.get_brush().size_changed.connect(_on_brush_size_changed) - add_child(_terrain_painter) - - _brush_decal = HT_BrushDecal.new() - _brush_decal.set_size(_terrain_painter.get_brush_size()) - - _image_cache = HT_ImageFileCache.new("user://temp_hterrain_image_cache") - - var editor_interface := get_editor_interface() - var base_control := editor_interface.get_base_control() - - _panel = HT_EditPanelScene.instantiate() - HT_Util.apply_dpi_scale(_panel, dpi_scale) - _panel.hide() - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_BOTTOM, _panel) - # Apparently _ready() still isn't called at this point... - _panel.call_deferred("set_terrain_painter", _terrain_painter) - _panel.call_deferred("setup_dialogs", base_control) - _panel.set_undo_redo(get_undo_redo()) - _panel.set_image_cache(_image_cache) - _panel.detail_selected.connect(_on_detail_selected) - _panel.texture_selected.connect(_on_texture_selected) - _panel.detail_list_changed.connect(_update_brush_buttons_availability) - _panel.edit_texture_pressed.connect(_on_Panel_edit_texture_pressed) - _panel.import_textures_pressed.connect(_on_Panel_import_textures_pressed) - - _toolbar = HBoxContainer.new() - add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, _toolbar) - _toolbar.hide() - - var menu := MenuButton.new() - menu.set_text("Terrain") - menu.get_popup().add_item("Import maps...", MENU_IMPORT_MAPS) - menu.get_popup().add_item("Generate...", MENU_GENERATE) - menu.get_popup().add_item("Resize...", MENU_RESIZE) - menu.get_popup().add_item("Bake global map", MENU_BAKE_GLOBALMAP) - menu.get_popup().add_separator() - menu.get_popup().add_item("Update Editor Collider", MENU_UPDATE_EDITOR_COLLIDER) - menu.get_popup().add_separator() - menu.get_popup().add_item("Generate mesh (heavy)", MENU_GENERATE_MESH) - menu.get_popup().add_separator() - menu.get_popup().add_item("Export heightmap", MENU_EXPORT_HEIGHTMAP) - menu.get_popup().add_separator() - _lookdev_menu = PopupMenu.new() - _lookdev_menu.name = "LookdevMenu" - _lookdev_menu.about_to_popup.connect(_on_lookdev_menu_about_to_show) - _lookdev_menu.id_pressed.connect(_on_lookdev_menu_id_pressed) - menu.get_popup().add_child(_lookdev_menu) - menu.get_popup().add_submenu_item("Lookdev", _lookdev_menu.name, MENU_LOOKDEV) - menu.get_popup().id_pressed.connect(_menu_item_selected) - menu.get_popup().add_separator() - menu.get_popup().add_item("Documentation", MENU_DOCUMENTATION) - menu.get_popup().add_item("About HTerrain...", MENU_ABOUT) - _toolbar.add_child(menu) - _menu_button = menu - - var mode_icons := {} - mode_icons[HT_TerrainPainter.MODE_RAISE] = get_icon("heightmap_raise") - mode_icons[HT_TerrainPainter.MODE_LOWER] = get_icon("heightmap_lower") - mode_icons[HT_TerrainPainter.MODE_SMOOTH] = get_icon("heightmap_smooth") - mode_icons[HT_TerrainPainter.MODE_FLATTEN] = get_icon("heightmap_flatten") - mode_icons[HT_TerrainPainter.MODE_SPLAT] = get_icon("heightmap_paint") - mode_icons[HT_TerrainPainter.MODE_COLOR] = get_icon("heightmap_color") - mode_icons[HT_TerrainPainter.MODE_DETAIL] = get_icon("grass") - mode_icons[HT_TerrainPainter.MODE_MASK] = get_icon("heightmap_mask") - mode_icons[HT_TerrainPainter.MODE_LEVEL] = get_icon("heightmap_level") - mode_icons[HT_TerrainPainter.MODE_ERODE] = get_icon("heightmap_erode") - - var mode_tooltips := {} - mode_tooltips[HT_TerrainPainter.MODE_RAISE] = "Raise height" - mode_tooltips[HT_TerrainPainter.MODE_LOWER] = "Lower height" - mode_tooltips[HT_TerrainPainter.MODE_SMOOTH] = "Smooth height" - mode_tooltips[HT_TerrainPainter.MODE_FLATTEN] = "Flatten (flatten to a specific height)" - mode_tooltips[HT_TerrainPainter.MODE_SPLAT] = "Texture paint" - mode_tooltips[HT_TerrainPainter.MODE_COLOR] = "Color paint" - mode_tooltips[HT_TerrainPainter.MODE_DETAIL] = "Grass paint" - mode_tooltips[HT_TerrainPainter.MODE_MASK] = "Cut holes" - mode_tooltips[HT_TerrainPainter.MODE_LEVEL] = "Level (smoothly flattens to average)" - mode_tooltips[HT_TerrainPainter.MODE_ERODE] = "Erode" - - _toolbar.add_child(VSeparator.new()) - - # I want modes to be in that order in the GUI - var ordered_brush_modes := [ - HT_TerrainPainter.MODE_RAISE, - HT_TerrainPainter.MODE_LOWER, - HT_TerrainPainter.MODE_SMOOTH, - HT_TerrainPainter.MODE_LEVEL, - HT_TerrainPainter.MODE_FLATTEN, - HT_TerrainPainter.MODE_ERODE, - HT_TerrainPainter.MODE_SPLAT, - HT_TerrainPainter.MODE_COLOR, - HT_TerrainPainter.MODE_DETAIL, - HT_TerrainPainter.MODE_MASK - ] - - var mode_group := ButtonGroup.new() - - for mode in ordered_brush_modes: - var button := Button.new() - button.flat = true - button.icon = mode_icons[mode] - button.tooltip_text = mode_tooltips[mode] - button.set_toggle_mode(true) - button.set_button_group(mode_group) - - if mode == _terrain_painter.get_mode(): - button.button_pressed = true - - button.pressed.connect(_on_mode_selected.bind(mode)) - _toolbar.add_child(button) - - _toolbar_brush_buttons[mode] = button - - _generator_dialog = HT_GeneratorDialogScene.instantiate() - _generator_dialog.set_image_cache(_image_cache) - _generator_dialog.set_undo_redo(get_undo_redo()) - base_control.add_child(_generator_dialog) - _generator_dialog.apply_dpi_scale(dpi_scale) - - _import_dialog = HT_ImportDialogScene.instantiate() - _import_dialog.permanent_change_performed.connect(_on_permanent_change_performed) - HT_Util.apply_dpi_scale(_import_dialog, dpi_scale) - base_control.add_child(_import_dialog) - - _progress_window = HT_ProgressWindowScene.instantiate() - base_control.add_child(_progress_window) - - _generate_mesh_dialog = HT_GenerateMeshDialogScene.instantiate() - _generate_mesh_dialog.generate_selected.connect(_on_GenerateMeshDialog_generate_selected) - HT_Util.apply_dpi_scale(_generate_mesh_dialog, dpi_scale) - base_control.add_child(_generate_mesh_dialog) - - _resize_dialog = HT_ResizeDialogScene.instantiate() - _resize_dialog.permanent_change_performed.connect(_on_permanent_change_performed) - HT_Util.apply_dpi_scale(_resize_dialog, dpi_scale) - base_control.add_child(_resize_dialog) - - _globalmap_baker = HT_GlobalMapBaker.new() - _globalmap_baker.progress_notified.connect(_progress_window.handle_progress) - _globalmap_baker.permanent_change_performed.connect(_on_permanent_change_performed) - add_child(_globalmap_baker) - - _export_image_dialog = HT_ExportImageDialogScene.instantiate() - HT_Util.apply_dpi_scale(_export_image_dialog, dpi_scale) - base_control.add_child(_export_image_dialog) - # Need to call deferred because in the specific case where you start the editor - # with the plugin enabled, _ready won't be called at this point - _export_image_dialog.call_deferred("setup_dialogs", base_control) - - _about_dialog = HT_AboutDialogScene.instantiate() - HT_Util.apply_dpi_scale(_about_dialog, dpi_scale) - base_control.add_child(_about_dialog) - - _texture_set_editor = HT_TextureSetEditorScene.instantiate() - _texture_set_editor.set_undo_redo(get_undo_redo()) - HT_Util.apply_dpi_scale(_texture_set_editor, dpi_scale) - base_control.add_child(_texture_set_editor) - _texture_set_editor.call_deferred("setup_dialogs", base_control) - - _texture_set_import_editor = HT_TextureSetImportEditorScene.instantiate() - _texture_set_import_editor.set_undo_redo(get_undo_redo()) - _texture_set_import_editor.set_editor_file_system( - get_editor_interface().get_resource_filesystem()) - HT_Util.apply_dpi_scale(_texture_set_import_editor, dpi_scale) - base_control.add_child(_texture_set_import_editor) - _texture_set_import_editor.call_deferred("setup_dialogs", base_control) - - _texture_set_editor.import_selected.connect(_on_TextureSetEditor_import_selected) - - _editor_viewport = _get_editor_viewport_container() - -func _exit_tree(): - _logger.debug("HTerrain plugin Exit tree") - - _remove_overlay_selector() - - # Make sure we release all references to edited stuff - _edit(null) - - _panel.queue_free() - _panel = null - - _toolbar.queue_free() - _toolbar = null - - _generator_dialog.queue_free() - _generator_dialog = null - - _import_dialog.queue_free() - _import_dialog = null - - _progress_window.queue_free() - _progress_window = null - - _generate_mesh_dialog.queue_free() - _generate_mesh_dialog = null - - _resize_dialog.queue_free() - _resize_dialog = null - - _export_image_dialog.queue_free() - _export_image_dialog = null - - _about_dialog.queue_free() - _about_dialog = null - - _texture_set_editor.queue_free() - _texture_set_editor = null - - _texture_set_import_editor.queue_free() - _texture_set_import_editor = null - - get_editor_interface().get_resource_previewer().remove_preview_generator(_preview_generator) - _preview_generator = null - - # TODO Manual clear cuz it can't do it automatically due to a Godot bug - _image_cache.clear() - - # TODO https://github.com/godotengine/godot/issues/6254#issuecomment-246139694 - # This was supposed to be automatic, but was never implemented it seems... - remove_custom_type("HTerrain") - remove_custom_type("HTerrainDetailLayer") - remove_custom_type("HTerrainData") - remove_custom_type("HTerrainTextureSet") - - -func _handles(object): - return _get_terrain_from_object(object) != null - - -func _edit(object): - _logger.debug(str("Edit ", object)) - - var node = _get_terrain_from_object(object) - - if _node != null: - _node.tree_exited.disconnect(_terrain_exited_scene) - - _node = node - - if _node != null: - _node.tree_exited.connect(_terrain_exited_scene) - - _update_brush_buttons_availability() - - _panel.set_terrain(_node) - _generator_dialog.set_terrain(_node) - _import_dialog.set_terrain(_node) - _terrain_painter.set_terrain(_node) - _brush_decal.set_terrain(_node) - _generate_mesh_dialog.set_terrain(_node) - _resize_dialog.set_terrain(_node) - _export_image_dialog.set_terrain(_node) - - if object is HTerrainDetailLayer: - # Auto-select layer for painting - if object.is_layer_index_valid(): - _panel.set_detail_layer_index(object.get_layer_index()) - _on_detail_selected(object.get_layer_index()) - - _update_toolbar_menu_availability() - - -static func _get_terrain_from_object(object): - if object != null and object is Node3D: - if not object.is_inside_tree(): - return null - if object is HTerrain: - return object - if object is HTerrainDetailLayer and object.get_parent() is HTerrain: - return object.get_parent() - return null - - -func _update_brush_buttons_availability(): - if _node == null: - return - if _node.get_data() != null: - var data = _node.get_data() - var has_details = (data.get_map_count(HTerrainData.CHANNEL_DETAIL) > 0) - - if has_details: - var button = _toolbar_brush_buttons[HT_TerrainPainter.MODE_DETAIL] - button.disabled = false - else: - var button = _toolbar_brush_buttons[HT_TerrainPainter.MODE_DETAIL] - if button.button_pressed: - _select_brush_mode(HT_TerrainPainter.MODE_RAISE) - button.disabled = true - - -func _update_toolbar_menu_availability(): - var data_available := false - if _node != null and _node.get_data() != null: - data_available = true - var popup : PopupMenu = _menu_button.get_popup() - for i in popup.get_item_count(): - #var id = popup.get_item_id(i) - # Turn off items if there is no data for them to work on - if data_available: - popup.set_item_disabled(i, false) - popup.set_item_tooltip(i, "") - else: - popup.set_item_disabled(i, true) - popup.set_item_tooltip(i, "Terrain has no data") - - -func _make_visible(visible: bool): - _panel.set_visible(visible) - _toolbar.set_visible(visible) - _brush_decal.update_visibility() - - # TODO Workaround https://github.com/godotengine/godot/issues/6459 - # When the user selects another node, - # I want the plugin to release its references to the terrain. - # This is important because if we don't do that, some modified resources will still be - # loaded in memory, so if the user closes the scene and reopens it later, the changes will - # still be partially present, and this is not expected. - if not visible: - _edit(null) - - -# TODO Can't hint return as `Vector2?` because it's nullable -func _get_pointed_cell_position(mouse_position: Vector2, p_camera: Camera3D):# -> Vector2: - # Need to do an extra conversion in case the editor viewport is in half-resolution mode - var viewport := p_camera.get_viewport() - var viewport_container : Control = viewport.get_parent() - var screen_pos = mouse_position * Vector2(viewport.size) / viewport_container.size - - var origin = p_camera.project_ray_origin(screen_pos) - var dir = p_camera.project_ray_normal(screen_pos) - - var ray_distance := p_camera.far * 1.2 - return _node.cell_raycast(origin, dir, ray_distance) - - -func _forward_3d_gui_input(p_camera: Camera3D, p_event: InputEvent) -> int: - if _node == null || _node.get_data() == null: - return AFTER_GUI_INPUT_PASS - - _node._edit_update_viewer_position(p_camera) - _panel.set_camera_transform(p_camera.global_transform) - - var captured_event = false - - if p_event is InputEventKey: - if p_event.keycode == KEY_G and p_event.is_echo() == false and p_event.pressed: - captured_event = true - _show_brush_editor_overlay( - HT_Brush.MIN_SIZE_FOR_SLIDERS, - HT_Brush.MAX_SIZE_FOR_SLIDERS, - Color.LIGHT_GREEN, _terrain_painter.get_brush_size(), - "Brush Size", - func on_value_changed(value): - _terrain_painter.set_brush_size(value)\ - ) - elif p_event.keycode == KEY_H and p_event.is_echo() == false and p_event.pressed: - captured_event = true - _show_brush_editor_overlay( - HT_Brush.MIN_OPACITY_FOR_SLIDERS, - HT_Brush.MAX_OPACITY_FOR_SLIDERS, - Color.LIGHT_CORAL, _terrain_painter.get_opacity()*100, - "Brush Opacity", - func on_value_changed(value): - _terrain_painter.set_opacity(value/100.0)\ - ) - - if p_event is InputEventMouseButton: - var mb = p_event - - if mb.button_index == MOUSE_BUTTON_LEFT or mb.button_index == MOUSE_BUTTON_RIGHT: - if mb.pressed == false: - _mouse_pressed = false - - # Need to check modifiers before capturing the event, - # because they are used in navigation schemes - if (not mb.ctrl_pressed) and (not mb.alt_pressed) and mb.button_index == MOUSE_BUTTON_LEFT: - if mb.pressed: - # TODO Allow to paint on click - # TODO `pressure` is not available in button press events - # So I have to assume zero to avoid discontinuities with move events - #_terrain_painter.paint_input(hit_pos_in_cells, 0.0) - _mouse_pressed = true - - captured_event = true - - if not _mouse_pressed: - # Just finished painting - _pending_paint_commit = true - _terrain_painter.get_brush().on_paint_end() - - if _terrain_painter.get_mode() == HT_TerrainPainter.MODE_FLATTEN \ - and _terrain_painter.has_meta("pick_height") \ - and _terrain_painter.get_meta("pick_height"): - _terrain_painter.set_meta("pick_height", false) - # Pick height - var hit_pos_in_cells = _get_pointed_cell_position(mb.position, p_camera) - if hit_pos_in_cells != null: - var h = _node.get_data().get_height_at( - int(hit_pos_in_cells.x), int(hit_pos_in_cells.y)) - _logger.debug("Picking height {0}".format([h])) - _terrain_painter.set_flatten_height(h) - - elif p_event is InputEventMouseMotion: - var mm = p_event - var hit_pos_in_cells = _get_pointed_cell_position(mm.position, p_camera) - if hit_pos_in_cells != null: - _brush_decal.set_position(Vector3(hit_pos_in_cells.x, 0, hit_pos_in_cells.y)) - - if _mouse_pressed: - if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): - _terrain_painter.paint_input(hit_pos_in_cells, mm.pressure) - captured_event = true - - # This is in case the data or textures change as the user edits the terrain, - # to keep the decal working without having to noodle around with nested signals - _brush_decal.update_visibility() - - if captured_event: - return AFTER_GUI_INPUT_STOP - return AFTER_GUI_INPUT_PASS - - -func _process(delta: float): - if _node == null: - return - - var has_data = (_node.get_data() != null) - - if _pending_paint_commit: - if has_data: - if not _terrain_painter.is_operation_pending(): - _pending_paint_commit = false - if _terrain_painter.has_modified_chunks(): - _logger.debug("Paint completed") - var changes : Dictionary = _terrain_painter.commit() - _paint_completed(changes) - else: - _pending_paint_commit = false - - # Poll presence of data resource - if has_data != _terrain_had_data_previous_frame: - _terrain_had_data_previous_frame = has_data - _update_toolbar_menu_availability() - - -func _paint_completed(changes: Dictionary): - var time_before = Time.get_ticks_msec() - - var heightmap_data = _node.get_data() - assert(heightmap_data != null) - - var chunk_positions : Array = changes.chunk_positions - # Should not create an UndoRedo action if nothing changed - assert(len(chunk_positions) > 0) - var changed_maps : Array = changes.maps - - var action_name := "Modify HTerrainData " - for i in len(changed_maps): - var mm = changed_maps[i] - var map_debug_name := HTerrainData.get_map_debug_name(mm.map_type, mm.map_index) - if i > 0: - action_name += " and " - action_name += map_debug_name - - var redo_maps := [] - var undo_maps := [] - var chunk_size := _terrain_painter.get_undo_chunk_size() - - for map in changed_maps: - # Cache images to disk so RAM does not continuously go up (or at least much slower) - for chunks in [map.chunk_initial_datas, map.chunk_final_datas]: - for i in len(chunks): - var im : Image = chunks[i] - chunks[i] = _image_cache.save_image(im) - - redo_maps.append({ - "map_type": map.map_type, - "map_index": map.map_index, - "chunks": map.chunk_final_datas - }) - undo_maps.append({ - "map_type": map.map_type, - "map_index": map.map_index, - "chunks": map.chunk_initial_datas - }) - - var undo_data := { - "chunk_positions": chunk_positions, - "chunk_size": chunk_size, - "maps": undo_maps - } - var redo_data := { - "chunk_positions": chunk_positions, - "chunk_size": chunk_size, - "maps": redo_maps - } - -# { -# chunk_positions: [Vector2, Vector2, ...] -# chunk_size: int -# maps: [ -# { -# map_type: int -# map_index: int -# chunks: [ -# int, int, ... -# ] -# }, -# ... -# ] -# } - - var ur := get_undo_redo() - - ur.create_action(action_name) - ur.add_do_method(heightmap_data, "_edit_apply_undo", redo_data, _image_cache) - ur.add_undo_method(heightmap_data, "_edit_apply_undo", undo_data, _image_cache) - - # Small hack here: - # commit_actions executes the do method, however terrain modifications are heavy ones, - # so we don't really want to re-run an update in every chunk that was modified during painting. - # The data is already in its final state, - # so we just prevent the resource from applying changes here. - heightmap_data._edit_set_disable_apply_undo(true) - ur.commit_action() - heightmap_data._edit_set_disable_apply_undo(false) - - var time_spent = Time.get_ticks_msec() - time_before - _logger.debug(str(action_name, " | ", len(chunk_positions), " chunks | ", time_spent, " ms")) - - -func _terrain_exited_scene(): - _logger.debug("HTerrain exited the scene") - _edit(null) - - -func _menu_item_selected(id: int): - _logger.debug(str("Menu item selected ", id)) - - match id: - MENU_IMPORT_MAPS: - _import_dialog.popup_centered() - - MENU_GENERATE: - _generator_dialog.popup_centered() - - MENU_BAKE_GLOBALMAP: - var data = _node.get_data() - if data != null: - _globalmap_baker.bake(_node) - - MENU_RESIZE: - _resize_dialog.popup_centered() - - MENU_UPDATE_EDITOR_COLLIDER: - # This is for editor tools to be able to use terrain collision. - # It's not automatic because keeping this collider up to date is - # expensive, but not too bad IMO because that feature is not often - # used in editor for now. - # If users complain too much about this, there are ways to improve it: - # - # 1) When the terrain gets deselected, update the terrain collider - # in a thread automatically. This is still expensive but should - # be easy to do. - # - # 2) Bullet actually support modifying the heights dynamically, - # as long as we stay within min and max bounds, - # so PR a change to the Godot heightmap collider to support passing - # a Float Image directly, and make it so the data is in sync - # (no CoW plz!!). It's trickier than 1) but almost free. - # - _node.update_collider() - - MENU_GENERATE_MESH: - if _node != null and _node.get_data() != null: - _generate_mesh_dialog.popup_centered() - - MENU_EXPORT_HEIGHTMAP: - if _node != null and _node.get_data() != null: - _export_image_dialog.popup_centered() - - MENU_LOOKDEV: - # No actions here, it's a submenu - pass - - MENU_DOCUMENTATION: - OS.shell_open(DOCUMENTATION_URL) - - MENU_ABOUT: - _about_dialog.popup_centered() - - -func _on_lookdev_menu_about_to_show(): - _lookdev_menu.clear() - _lookdev_menu.add_check_item("Disabled") - _lookdev_menu.set_item_checked(0, not _node.is_lookdev_enabled()) - _lookdev_menu.add_separator() - var terrain_data : HTerrainData = _node.get_data() - if terrain_data == null: - _lookdev_menu.add_item("No terrain data") - _lookdev_menu.set_item_disabled(0, true) - else: - for map_type in HTerrainData.CHANNEL_COUNT: - var count := terrain_data.get_map_count(map_type) - for map_index in count: - var map_name := HTerrainData.get_map_debug_name(map_type, map_index) - var lookdev_item_index := _lookdev_menu.get_item_count() - _lookdev_menu.add_item(map_name, lookdev_item_index) - _lookdev_menu.set_item_metadata(lookdev_item_index, { - "map_type": map_type, - "map_index": map_index - }) - - -func _on_lookdev_menu_id_pressed(id: int): - var meta = _lookdev_menu.get_item_metadata(id) - if meta == null: - _node.set_lookdev_enabled(false) - else: - _node.set_lookdev_enabled(true) - var data : HTerrainData = _node.get_data() - var map_texture = data.get_texture(meta.map_type, meta.map_index) - _node.set_lookdev_shader_param("u_map", map_texture) - _lookdev_menu.set_item_checked(0, not _node.is_lookdev_enabled()) - - -func _on_mode_selected(mode: int): - _logger.debug(str("On mode selected ", mode)) - _terrain_painter.set_mode(mode) - _panel.set_brush_editor_display_mode(mode) - - -func _on_texture_selected(index: int): - # Switch to texture paint mode when a texture is selected - _select_brush_mode(HT_TerrainPainter.MODE_SPLAT) - _terrain_painter.set_texture_index(index) - - -func _on_detail_selected(index: int): - # Switch to detail paint mode when a detail item is selected - _select_brush_mode(HT_TerrainPainter.MODE_DETAIL) - _terrain_painter.set_detail_index(index) - - -func _select_brush_mode(mode: int): - _toolbar_brush_buttons[mode].button_pressed = true - _on_mode_selected(mode) - - -static func get_size_from_raw_length(flen: int): - var side_len = roundf(sqrt(float(flen/2))) - return int(side_len) - - -func _on_GenerateMeshDialog_generate_selected(lod: int): - var data := _node.get_data() - if data == null: - _logger.error("Terrain has no data, cannot generate mesh") - return - var heightmap := data.get_image(HTerrainData.CHANNEL_HEIGHT) - var scale := _node.map_scale - var mesh := HTerrainMesher.make_heightmap_mesh(heightmap, lod, scale, _logger) - var mi := MeshInstance3D.new() - mi.name = str(_node.name, "_FullMesh") - mi.mesh = mesh - mi.transform = _node.transform - _node.get_parent().add_child(mi) - mi.set_owner(get_editor_interface().get_edited_scene_root()) - - -# TODO Workaround for https://github.com/Zylann/godot_heightmap_plugin/issues/101 -func _on_permanent_change_performed(message: String): - var data := _node.get_data() - if data == null: - _logger.error("Terrain has no data, cannot mark it as changed") - return - var ur := get_undo_redo() - ur.create_action(message) - ur.add_do_method(data, "_dummy_function") - #ur.add_undo_method(data, "_dummy_function") - ur.commit_action() - - -func _on_brush_size_changed(size): - _brush_decal.set_size(size) - - -func _on_Panel_edit_texture_pressed(index: int): - var ts := _node.get_texture_set() - _texture_set_editor.set_texture_set(ts) - _texture_set_editor.select_slot(index) - _texture_set_editor.popup_centered() - - -func _on_TextureSetEditor_import_selected(): - _open_texture_set_import_editor() - - -func _on_Panel_import_textures_pressed(): - _open_texture_set_import_editor() - - -func _open_texture_set_import_editor(): - var ts := _node.get_texture_set() - _texture_set_import_editor.set_texture_set(ts) - _texture_set_import_editor.popup_centered() - - -################ -# DEBUG LAND - -# TEST -#func _physics_process(delta): -# if Input.is_key_pressed(KEY_KP_0): -# _debug_spawn_collider_indicators() - - -func _debug_spawn_collider_indicators(): - var root = get_editor_interface().get_edited_scene_root() - var terrain := HT_Util.find_first_node(root, HTerrain) as HTerrain - if terrain == null: - return - - var test_root : Node3D - if not terrain.has_node("__DEBUG"): - test_root = Node3D.new() - test_root.name = "__DEBUG" - terrain.add_child(test_root) - else: - test_root = terrain.get_node("__DEBUG") - - var space_state := terrain.get_world_3d().direct_space_state - var hit_material := StandardMaterial3D.new() - hit_material.albedo_color = Color(0, 1, 1) - var cube := BoxMesh.new() - - for zi in 16: - for xi in 16: - var hit_name := str(xi, "_", zi) - var pos := Vector3(xi * 16, 1000, zi * 16) - - var query := PhysicsRayQueryParameters3D.new() - query.from = pos - query.to = pos + Vector3(0, -2000, 0) - - var hit := space_state.intersect_ray(query) - - var mi : MeshInstance3D - if not test_root.has_node(hit_name): - mi = MeshInstance3D.new() - mi.name = hit_name - mi.material_override = hit_material - mi.mesh = cube - test_root.add_child(mi) - else: - mi = test_root.get_node(hit_name) - if hit.is_empty(): - mi.hide() - else: - mi.show() - mi.position = hit.position - - -func _show_brush_editor_overlay(min_size: float, max_size: float, widget_color: Color, - initial_value: float, action_name: String, - on_value_selected: Callable): - _remove_overlay_selector() - - if _editor_viewport == null: - # something went wrong - return - - var selector: HT_BrushEditorOverlay = HT_BrushEditorOverlayScene.instantiate() - EditorInterface.get_base_control().add_child(selector) - - selector.min_value = min_size - selector.max_value = max_size - selector.set_overlay_name(action_name) - selector.set_brush_preview_color(widget_color) - selector.apply_dpi_scale(get_editor_interface().get_editor_scale()) - selector.setup_start_position(_editor_viewport.get_global_mouse_position(), initial_value) - - _overlay_selector = selector - - - selector.on_value_selected.connect(func f(value): - on_value_selected.call(value) - _remove_overlay_selector() - ) - selector.on_cancel.connect(func f(): - _remove_overlay_selector() - ) - - -func _remove_overlay_selector(): - if _overlay_selector != null: - _overlay_selector.queue_free() - _overlay_selector = null - - -func _get_editor_viewport_container() -> SubViewportContainer: - # Returns the Node3DEditorViewportContainer - var viewport_container: Control = EditorInterface.get_editor_viewport_3d().get_parent().get_parent() - var editor_viewport_container: Array[Node] = viewport_container.find_children("*","SubViewportContainer", false,false) - - if editor_viewport_container.is_empty(): - return null - - return editor_viewport_container[0] - - -func _spawn_vertical_bound_boxes(): - var data := _node.get_data() -# var sy = data._chunked_vertical_bounds_size_y -# var sx = data._chunked_vertical_bounds_size_x - var mat := StandardMaterial3D.new() - mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA - mat.albedo_color = Color(1,1,1,0.2) - for cy in range(30, 60): - for cx in range(30, 60): - var vb := data._chunked_vertical_bounds.get_pixel(cx, cy) - var minv := vb.r - var maxv := vb.g - var mi := MeshInstance3D.new() - mi.mesh = BoxMesh.new() - var cs := HTerrainData.VERTICAL_BOUNDS_CHUNK_SIZE - mi.mesh.size = Vector3(cs, maxv - minv, cs) - mi.position = Vector3( - (float(cx) + 0.5) * cs, - minv + mi.mesh.size.y * 0.5, - (float(cy) + 0.5) * cs) - mi.position *= _node.map_scale - mi.scale = _node.map_scale - mi.material_override = mat - _node.add_child(mi) - mi.owner = get_editor_interface().get_edited_scene_root() - -# if p_event is InputEventKey: -# if p_event.pressed == false: -# if p_event.scancode == KEY_SPACE and p_event.control: -# _spawn_vertical_bound_boxes() diff --git a/godot/addons/zylann.hterrain/tools/plugin.gd.uid b/godot/addons/zylann.hterrain/tools/plugin.gd.uid deleted file mode 100644 index 21c4e9b..0000000 --- a/godot/addons/zylann.hterrain/tools/plugin.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dwtu2adbuq6ws diff --git a/godot/addons/zylann.hterrain/tools/preview_generator.gd b/godot/addons/zylann.hterrain/tools/preview_generator.gd deleted file mode 100644 index 3eb0362..0000000 --- a/godot/addons/zylann.hterrain/tools/preview_generator.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool -extends EditorResourcePreviewGenerator - -const HTerrainData = preload("../hterrain_data.gd") -const HT_Errors = preload("../util/errors.gd") -const HT_Logger = preload("../util/logger.gd") - -var _logger = HT_Logger.get_for(self) - - -func _generate(res: Resource, size: Vector2i, metadata: Dictionary) -> Texture2D: - if res == null or not (res is HTerrainData): - return null - var normalmap = res.get_image(HTerrainData.CHANNEL_NORMAL) - if normalmap == null: - return null - return _generate_internal(normalmap, size) - - -func _generate_from_path(path: String, size: Vector2i, metadata: Dictionary) -> Texture2D: - if not path.ends_with("." + HTerrainData.META_EXTENSION): - return null - var data_dir := path.get_base_dir() - var normals_fname := str(HTerrainData.get_channel_name(HTerrainData.CHANNEL_NORMAL), ".png") - var normals_path := data_dir.path_join(normals_fname) - var normals := Image.new() - var err := normals.load(ProjectSettings.globalize_path(normals_path)) - if err != OK: - _logger.error("Could not load '{0}', error {1}" \ - .format([normals_path, HT_Errors.get_message(err)])) - return null - return _generate_internal(normals, size) - - -func _handles(type: String) -> bool: - return type == "Resource" - - -static func _generate_internal(normals: Image, size: Vector2) -> Texture2D: - var im := Image.create(size.x, size.y, false, Image.FORMAT_RGB8) - - var light_dir := Vector3(-1, -0.5, -1).normalized() - - for y in im.get_height(): - for x in im.get_width(): - - var fx := float(x) / float(im.get_width()) - var fy := float(im.get_height() - y - 1) / float(im.get_height()) - var mx := int(fx * normals.get_width()) - var my := int(fy * normals.get_height()) - - var n := _decode_normal(normals.get_pixel(mx, my)) - - var ndot := -n.dot(light_dir) - var gs := clampf(0.5 * ndot + 0.5, 0.0, 1.0) - var col := Color(gs, gs, gs, 1.0) - - im.set_pixel(x, y, col) - - var tex := ImageTexture.create_from_image(im) - return tex - - -static func _decode_normal(c: Color) -> Vector3: - return Vector3(2.0 * c.r - 1.0, 2.0 * c.b - 1.0, 2.0 * c.g - 1.0) diff --git a/godot/addons/zylann.hterrain/tools/preview_generator.gd.uid b/godot/addons/zylann.hterrain/tools/preview_generator.gd.uid deleted file mode 100644 index f7b3111..0000000 --- a/godot/addons/zylann.hterrain/tools/preview_generator.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://urnowxupw7o5 diff --git a/godot/addons/zylann.hterrain/tools/progress_window.gd b/godot/addons/zylann.hterrain/tools/progress_window.gd deleted file mode 100644 index 791717f..0000000 --- a/godot/addons/zylann.hterrain/tools/progress_window.gd +++ /dev/null @@ -1,32 +0,0 @@ -@tool -extends AcceptDialog - - -#onready var _label = get_node("VBoxContainer/Label") -@onready var _progress_bar : ProgressBar = $VBoxContainer/ProgressBar - - -func _init(): - get_ok_button().hide() - - -func _show_progress(message, progress): - self.title = message - _progress_bar.ratio = progress - - -func handle_progress(info: Dictionary): - if info.has("finished") and info.finished: - hide() - - else: - if not visible: - popup_centered() - - var message = "" - if info.has("message"): - message = info.message - - _show_progress(info.message, info.progress) - # TODO Have builtin modal progress bar - # https://github.com/godotengine/godot/issues/17763 diff --git a/godot/addons/zylann.hterrain/tools/progress_window.gd.uid b/godot/addons/zylann.hterrain/tools/progress_window.gd.uid deleted file mode 100644 index e7ba4d9..0000000 --- a/godot/addons/zylann.hterrain/tools/progress_window.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://coghg4mby2shi diff --git a/godot/addons/zylann.hterrain/tools/progress_window.tscn b/godot/addons/zylann.hterrain/tools/progress_window.tscn deleted file mode 100644 index e6d7d19..0000000 --- a/godot/addons/zylann.hterrain/tools/progress_window.tscn +++ /dev/null @@ -1,22 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://b0f3h46ugtni6"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/progress_window.gd" id="1"] - -[node name="WindowDialog" type="AcceptDialog"] -title = "" -size = Vector2i(400, 100) -min_size = Vector2i(400, 40) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -8.0 - -[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer"] -layout_mode = 2 -step = 1.0 diff --git a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd b/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd deleted file mode 100644 index 617e457..0000000 --- a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd +++ /dev/null @@ -1,174 +0,0 @@ -@tool -extends AcceptDialog - -const HT_Util = preload("../../util/util.gd") -const HT_Logger = preload("../../util/logger.gd") -const HTerrain = preload("../../hterrain.gd") -const HTerrainData = preload("../../hterrain_data.gd") - -const ANCHOR_TOP_LEFT = 0 -const ANCHOR_TOP = 1 -const ANCHOR_TOP_RIGHT = 2 -const ANCHOR_LEFT = 3 -const ANCHOR_CENTER = 4 -const ANCHOR_RIGHT = 5 -const ANCHOR_BOTTOM_LEFT = 6 -const ANCHOR_BOTTOM = 7 -const ANCHOR_BOTTOM_RIGHT = 8 -const ANCHOR_COUNT = 9 - -const _anchor_dirs = [ - [-1, -1], - [0, -1], - [1, -1], - [-1, 0], - [0, 0], - [1, 0], - [-1, 1], - [0, 1], - [1, 1] -] - -const _anchor_icon_names = [ - "anchor_top_left", - "anchor_top", - "anchor_top_right", - "anchor_left", - "anchor_center", - "anchor_right", - "anchor_bottom_left", - "anchor_bottom", - "anchor_bottom_right" -] - -signal permanent_change_performed(message) - -@onready var _resolution_dropdown : OptionButton = $VBoxContainer/GridContainer/ResolutionDropdown -@onready var _stretch_checkbox : CheckBox = $VBoxContainer/GridContainer/StretchCheckBox -@onready var _anchor_control : Control = $VBoxContainer/GridContainer/HBoxContainer/AnchorControl - -const _resolutions = HTerrainData.SUPPORTED_RESOLUTIONS - -var _anchor_buttons := [] -var _anchor_buttons_grid := {} -var _anchor_button_group : ButtonGroup = null -var _selected_anchor = ANCHOR_TOP_LEFT -var _logger = HT_Logger.get_for(self) - -var _terrain : HTerrain = null - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -static func _get_icon(name) -> Texture2D: - return load("res://addons/zylann.hterrain/tools/icons/icon_" + name + ".svg") - - -func _init(): - get_ok_button().hide() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - # TEST - #show() - - for i in len(_resolutions): - _resolution_dropdown.add_item(str(_resolutions[i]), i) - - _anchor_button_group = ButtonGroup.new() - _anchor_buttons.resize(ANCHOR_COUNT) - var x := 0 - var y := 0 - for i in _anchor_control.get_child_count(): - var child_node = _anchor_control.get_child(i) - assert(child_node is Button) - var child := child_node as Button - child.toggle_mode = true - child.custom_minimum_size = child.size - child.icon = null - child.pressed.connect(_on_AnchorButton_pressed.bind(i, x, y)) - child.button_group = _anchor_button_group - _anchor_buttons[i] = child - _anchor_buttons_grid[Vector2(x, y)] = child - x += 1 - if x >= 3: - x = 0 - y += 1 - - _anchor_buttons[_selected_anchor].button_pressed = true - # The signal apparently doesn't trigger in this case - _on_AnchorButton_pressed(_selected_anchor, 0, 0) - - -func _notification(what: int): - if what == NOTIFICATION_VISIBILITY_CHANGED: - if visible: - # Select current resolution - if _terrain != null and _terrain.get_data() != null: - var res := _terrain.get_data().get_resolution() - for i in len(_resolutions): - if res == _resolutions[i]: - _resolution_dropdown.select(i) - break - - -func _on_AnchorButton_pressed(anchor0: int, x0: int, y0: int): - _selected_anchor = anchor0 - - for button in _anchor_buttons: - button.icon = null - - for anchor in ANCHOR_COUNT: - var d = _anchor_dirs[anchor] - var nx = x0 + d[0] - var ny = y0 + d[1] - var k = Vector2(nx, ny) - if not _anchor_buttons_grid.has(k): - continue - var button : Button = _anchor_buttons_grid[k] - var icon := _get_icon(_anchor_icon_names[anchor]) - button.icon = icon - - -func _set_anchor_control_active(active: bool): - for button in _anchor_buttons: - button.disabled = not active - - -func _on_ResolutionDropdown_item_selected(id): - pass - - -func _on_StretchCheckBox_toggled(button_pressed: bool): - _set_anchor_control_active(not button_pressed) - - -func _on_ApplyButton_pressed(): - var stretch = _stretch_checkbox.button_pressed - var res = _resolutions[_resolution_dropdown.get_selected_id()] - var dir = _anchor_dirs[_selected_anchor] - _apply(res, stretch, Vector2(dir[0], dir[1])) - hide() - - -func _on_CancelButton_pressed(): - hide() - - -func _apply(p_resolution: int, p_stretch: bool, p_anchor: Vector2): - if _terrain == null: - _logger.error("Cannot apply resize, terrain is not set") - return - - var data = _terrain.get_data() - if data == null: - _logger.error("Cannot apply resize, terrain has no data") - return - - data.resize(p_resolution, p_stretch, p_anchor) - data.notify_full_change() - permanent_change_performed.emit("Resize terrain") diff --git a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd.uid b/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd.uid deleted file mode 100644 index 1543cae..0000000 --- a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2nb6nn5kliq1 diff --git a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn b/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn deleted file mode 100644 index c0678ae..0000000 --- a/godot/addons/zylann.hterrain/tools/resize_dialog/resize_dialog.tscn +++ /dev/null @@ -1,159 +0,0 @@ -[gd_scene load_steps=7 format=3 uid="uid://gt402qqhab7j"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/resize_dialog/resize_dialog.gd" id="1"] -[ext_resource type="Texture2D" uid="uid://b4ya0po3a4nqa" path="res://addons/zylann.hterrain/tools/icons/icon_heightmap_unmask.svg" id="2"] -[ext_resource type="Texture2D" uid="uid://d3vie0tj3ry6k" path="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_right.svg" id="3"] -[ext_resource type="Texture2D" uid="uid://b6l5dys0awbwd" path="res://addons/zylann.hterrain/tools/icons/icon_long_arrow_down.svg" id="4"] -[ext_resource type="Texture2D" uid="uid://bdkcgtv1r5j31" path="res://addons/zylann.hterrain/tools/icons/icon_small_circle.svg" id="5"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="6"] - -[node name="ResizeDialog" type="AcceptDialog"] -title = "Resize terrain" -size = Vector2i(300, 201) -min_size = Vector2i(300, 200) -script = ExtResource("1") - -[node name="VBoxContainer" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="GridContainer" type="GridContainer" parent="VBoxContainer"] -layout_mode = 2 -columns = 2 - -[node name="Label" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Resolution" - -[node name="ResolutionDropdown" type="OptionButton" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -size_flags_horizontal = 3 -toggle_mode = false - -[node name="Label3" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Stretch" - -[node name="StretchCheckBox" type="CheckBox" parent="VBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="Label2" type="Label" parent="VBoxContainer/GridContainer"] -layout_mode = 2 -text = "Direction" - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/GridContainer"] -layout_mode = 2 - -[node name="AnchorControl" type="GridContainer" parent="VBoxContainer/GridContainer/HBoxContainer"] -layout_mode = 2 -columns = 3 - -[node name="TopLeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="TopButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="TopRightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="LeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="CenterButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="RightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="ButtomLeftButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="ButtomButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="BottomRightButton" type="Button" parent="VBoxContainer/GridContainer/HBoxContainer/AnchorControl"] -layout_mode = 2 -icon = ExtResource("2") - -[node name="Reference" type="Control" parent="VBoxContainer/GridContainer/HBoxContainer"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 - -[node name="XArrow" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -modulate = Color(1, 0.292969, 0.292969, 1) -layout_mode = 0 -anchor_right = 1.0 -offset_left = 9.0 -offset_bottom = 16.0 -texture = ExtResource("3") - -[node name="ZArrow" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -modulate = Color(0.292969, 0.602295, 1, 1) -layout_mode = 0 -anchor_bottom = 1.0 -offset_top = 10.0 -offset_right = 16.0 -texture = ExtResource("4") - -[node name="ZLabel" type="Label" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 14.0 -offset_top = 54.0 -offset_right = 22.0 -offset_bottom = 68.0 -text = "Z" - -[node name="XLabel" type="Label" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 52.0 -offset_top = 14.0 -offset_right = 60.0 -offset_bottom = 28.0 -text = "X" - -[node name="Origin" type="TextureRect" parent="VBoxContainer/GridContainer/HBoxContainer/Reference"] -layout_mode = 0 -offset_left = 3.0 -offset_top = 4.0 -offset_right = 11.0 -offset_bottom = 12.0 -texture = ExtResource("5") - -[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -alignment = 1 - -[node name="ApplyButton" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Apply (no undo)" - -[node name="CancelButton" type="Button" parent="VBoxContainer/HBoxContainer"] -layout_mode = 2 -text = "Cancel" - -[node name="DialogFitter" parent="." instance=ExtResource("6")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 292.0 -offset_bottom = 183.0 - -[connection signal="item_selected" from="VBoxContainer/GridContainer/ResolutionDropdown" to="." method="_on_ResolutionDropdown_item_selected"] -[connection signal="toggled" from="VBoxContainer/GridContainer/StretchCheckBox" to="." method="_on_StretchCheckBox_toggled"] -[connection signal="pressed" from="VBoxContainer/HBoxContainer/ApplyButton" to="." method="_on_ApplyButton_pressed"] -[connection signal="pressed" from="VBoxContainer/HBoxContainer/CancelButton" to="." method="_on_CancelButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/terrain_preview.gd b/godot/addons/zylann.hterrain/tools/terrain_preview.gd deleted file mode 100644 index 1c64b6d..0000000 --- a/godot/addons/zylann.hterrain/tools/terrain_preview.gd +++ /dev/null @@ -1,143 +0,0 @@ -@tool -extends SubViewportContainer - -const PREVIEW_MESH_LOD = 2 - -const HTerrainMesher = preload("../hterrain_mesher.gd") -const HT_Util = preload("../util/util.gd") - -signal dragged(relative, button_mask) - -@onready var _viewport : SubViewport = $Viewport -@onready var _mesh_instance : MeshInstance3D = $Viewport/MeshInstance -@onready var _camera : Camera3D = $Viewport/Camera -@onready var _light : DirectionalLight3D = $Viewport/DirectionalLight - -# Use the simplest shader -var _shader : Shader = load("res://addons/zylann.hterrain/shaders/simple4_lite.gdshader") -var _yaw := 0.0 -var _pitch := -PI / 6.0 -var _distance := 0.0 -var _default_distance := 0.0 -var _sea_outline : MeshInstance3D = null -var _sea_plane : MeshInstance3D = null -var _mesh_resolution := 0 - - -func _ready(): - if _sea_outline == null: - var mesh := HT_Util.create_wirecube_mesh() - var mat2 := StandardMaterial3D.new() - mat2.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - mat2.albedo_color = Color(0, 0.5, 1) - mesh.surface_set_material(0, mat2) - _sea_outline = MeshInstance3D.new() - _sea_outline.mesh = mesh - _viewport.add_child(_sea_outline) - - if _sea_plane == null: - var mesh := PlaneMesh.new() - mesh.size = Vector2(1, 1) - var mat2 := StandardMaterial3D.new() - mat2.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - mat2.albedo_color = Color(0, 0.5, 1, 0.5) - mat2.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA - mesh.material = mat2 - _sea_plane = MeshInstance3D.new() - _sea_plane.mesh = mesh - _sea_plane.hide() - _viewport.add_child(_sea_plane) - - -func setup(heights_texture: Texture2D, normals_texture: Texture2D): - var terrain_size := heights_texture.get_width() - var mesh_resolution := terrain_size / PREVIEW_MESH_LOD - - if _mesh_resolution != mesh_resolution or not (_mesh_instance.mesh is ArrayMesh): - _mesh_resolution = mesh_resolution - var mesh := HTerrainMesher.make_flat_chunk( - _mesh_resolution, _mesh_resolution, PREVIEW_MESH_LOD, 0) - _mesh_instance.mesh = mesh - _default_distance = _mesh_instance.get_aabb().size.x - _distance = _default_distance - #_mesh_instance.translation -= 0.5 * Vector3(terrain_size, 0, terrain_size) - _update_camera() - - var mat : ShaderMaterial = _mesh_instance.mesh.surface_get_material(0) - - if mat == null: - mat = ShaderMaterial.new() - mat.shader = _shader - _mesh_instance.mesh.surface_set_material(0, mat) - - mat.set_shader_parameter("u_terrain_heightmap", heights_texture) - mat.set_shader_parameter("u_terrain_normalmap", normals_texture) - mat.set_shader_parameter("u_terrain_inverse_transform", Transform3D()) - mat.set_shader_parameter("u_terrain_normal_basis", Basis()) - - var aabb := _mesh_instance.get_aabb() - _sea_outline.scale = aabb.size - - aabb = _mesh_instance.get_aabb() - _sea_plane.scale = Vector3(aabb.size.x, 1, aabb.size.z) - _sea_plane.position = Vector3(aabb.size.x, 0, aabb.size.z) / 2.0 - - -func set_sea_visible(visible: bool): - _sea_plane.visible = visible - - -func set_shadows_enabled(enabled: bool): - _light.shadow_enabled = enabled - - -func _update_camera(): - var aabb := _mesh_instance.get_aabb() - var target := aabb.position + 0.5 * aabb.size - var trans := Transform3D() - trans.basis = Basis(Quaternion(Vector3(0, 1, 0), _yaw) * Quaternion(Vector3(1, 0, 0), _pitch)) - var back := trans.basis.z - trans.origin = target + back * _distance - _camera.transform = trans - - -func cleanup(): - if _mesh_instance != null: - var mat : ShaderMaterial = _mesh_instance.mesh.surface_get_material(0) - assert(mat != null) - mat.set_shader_parameter("u_terrain_heightmap", null) - mat.set_shader_parameter("u_terrain_normalmap", null) - - -func _gui_input(event: InputEvent): - if HT_Util.is_in_edited_scene(self): - return - - if event is InputEventMouseMotion: - if event.button_mask & MOUSE_BUTTON_MASK_MIDDLE: - var d : Vector2 = 0.01 * event.relative - _yaw -= d.x - _pitch -= d.y - _update_camera() - else: - var rel : Vector2 = 0.01 * event.relative - # Align dragging to view rotation - rel = -rel.rotated(-_yaw) - dragged.emit(rel, event.button_mask) - - elif event is InputEventMouseButton: - if event.pressed: - - var factor := 1.2 - var max_factor := 10.0 - var min_distance := _default_distance / max_factor - var max_distance := _default_distance - - # Zoom in/out - if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: - _distance = clampf(_distance * factor, min_distance, max_distance) - _update_camera() - - elif event.button_index == MOUSE_BUTTON_WHEEL_UP: - _distance = clampf(_distance / factor, min_distance, max_distance) - _update_camera() diff --git a/godot/addons/zylann.hterrain/tools/terrain_preview.gd.uid b/godot/addons/zylann.hterrain/tools/terrain_preview.gd.uid deleted file mode 100644 index 8341285..0000000 --- a/godot/addons/zylann.hterrain/tools/terrain_preview.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bglpxjkltdbef diff --git a/godot/addons/zylann.hterrain/tools/terrain_preview.tscn b/godot/addons/zylann.hterrain/tools/terrain_preview.tscn deleted file mode 100644 index 0b87a16..0000000 --- a/godot/addons/zylann.hterrain/tools/terrain_preview.tscn +++ /dev/null @@ -1,38 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://bue2flijnxa3p"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/terrain_preview.gd" id="1"] - -[sub_resource type="PlaneMesh" id="3"] -size = Vector2(256, 256) - -[node name="TerrainPreview" type="SubViewportContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -mouse_filter = 0 -stretch = true -script = ExtResource("1") - -[node name="Viewport" type="SubViewport" parent="."] -own_world_3d = true -handle_input_locally = false -size = Vector2i(1152, 648) -render_target_update_mode = 4 - -[node name="DirectionalLight" type="DirectionalLight3D" parent="Viewport"] -transform = Transform3D(-0.901211, 0.315056, -0.297588, 0, 0.686666, 0.726973, 0.433381, 0.655156, -0.618831, 0, 0, 0) -light_bake_mode = 1 -shadow_enabled = true -shadow_bias = 0.5 -directional_shadow_mode = 1 -directional_shadow_max_distance = 1000.0 - -[node name="MeshInstance" type="MeshInstance3D" parent="Viewport"] -mesh = SubResource("3") - -[node name="Camera" type="Camera3D" parent="Viewport"] -transform = Transform3D(-1, 3.31486e-08, -8.08945e-08, 0, 0.925325, 0.379176, 8.74228e-08, 0.379176, -0.925325, -2.25312e-05, 145.456, -348.286) -current = true -fov = 70.0 -near = 1.0 -far = 1000.0 diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader b/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader deleted file mode 100644 index 7ac1b98..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader +++ /dev/null @@ -1,6 +0,0 @@ -shader_type canvas_item; - -void fragment() { - float a = texture(TEXTURE, UV).a; - COLOR = vec4(a, a, a, 1.0); -} diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader.uid b/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader.uid deleted file mode 100644 index d7ad9d2..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://5j5edukdhjn5 diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres b/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres deleted file mode 100644 index 34ef863..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_material.tres +++ /dev/null @@ -1,9 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader" type="Shader" id=1] - -[resource] - -render_priority = 0 -shader = ExtResource( 1 ) - diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader b/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader deleted file mode 100644 index 384e1a2..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; - -uniform sampler2DArray u_texture_array; -uniform float u_index; - -void fragment() { - vec4 col = texture(u_texture_array, vec3(UV.x, UV.y, u_index)); - COLOR = vec4(col.a, col.a, col.a, 1.0); -} diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader.uid b/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader.uid deleted file mode 100644 index a0dcea5..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_alpha_slice.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://blt2fllts28g8 diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader b/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader deleted file mode 100644 index dcc1fda..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader +++ /dev/null @@ -1,7 +0,0 @@ -shader_type canvas_item; - -void fragment() { - // TODO Have an option to "undo" sRGB, for funzies? - vec4 col = texture(TEXTURE, UV); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader.uid b/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader.uid deleted file mode 100644 index 6b639b3..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_color.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c2rxvjof3utgs diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres b/godot/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres deleted file mode 100644 index 094400f..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_material.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="ShaderMaterial" load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/display_color.gdshader" type="Shader" id=1] - -[resource] -shader = ExtResource( 1 ) diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader b/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader deleted file mode 100644 index d2e4f5c..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader +++ /dev/null @@ -1,9 +0,0 @@ -shader_type canvas_item; - -uniform sampler2DArray u_texture_array; -uniform float u_index; - -void fragment() { - vec4 col = texture(u_texture_array, vec3(UV.x, UV.y, u_index)); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader.uid b/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader.uid deleted file mode 100644 index 0d2bb7c..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_color_slice.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bmbn4lvtknwfk diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader b/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader deleted file mode 100644 index 665af53..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader +++ /dev/null @@ -1,28 +0,0 @@ -shader_type canvas_item; - -uniform float u_strength = 1.0; -uniform bool u_flip_y = false; - -vec3 unpack_normal(vec4 rgba) { - vec3 n = rgba.xzy * 2.0 - vec3(1.0); - // Had to negate Z because it comes from Y in the normal map, - // and OpenGL-style normal maps are Y-up. - n.z *= -1.0; - return n; -} - -vec3 pack_normal(vec3 n) { - n.z *= -1.0; - return 0.5 * (n.xzy + vec3(1.0)); -} - -void fragment() { - vec4 col = texture(TEXTURE, UV); - vec3 n = unpack_normal(col); - n = normalize(mix(n, vec3(-n.x, n.y, -n.z), 0.5 - 0.5 * u_strength)); - if (u_flip_y) { - n.z = -n.z; - } - col.rgb = pack_normal(n); - COLOR = vec4(col.rgb, 1.0); -} diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader.uid b/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader.uid deleted file mode 100644 index f874e4f..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/display_normal.gdshader.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c44isyey67csr diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd b/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd deleted file mode 100644 index 4425134..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd +++ /dev/null @@ -1,41 +0,0 @@ -@tool -extends Container - -const SEPARATION = 2 - - -func _notification(what: int): - if what == NOTIFICATION_SORT_CHILDREN: - _sort_children2() - - -# TODO Function with ugly name to workaround a Godot 3.1 issue -# See https://github.com/godotengine/godot/pull/38396 -func _sort_children2(): - var max_x := size.x - SEPARATION - var pos := Vector2(SEPARATION, SEPARATION) - var line_height := 0 - - for i in get_child_count(): - var child_node = get_child(i) - if not child_node is Control: - continue - var child := child_node as Control - - var rect := child.get_rect() - - if rect.size.y > line_height: - line_height = rect.size.y - - if pos.x + rect.size.x > max_x: - pos.x = SEPARATION - pos.y += line_height + SEPARATION - line_height = rect.size.y - - rect.position = pos - fit_child_in_rect(child, rect) - - pos.x += rect.size.x + SEPARATION - - custom_minimum_size.y = pos.y + line_height - diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd.uid deleted file mode 100644 index c5ea086..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/flow_container.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://chpsas3p21wt5 diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd deleted file mode 100644 index 834accb..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd +++ /dev/null @@ -1,60 +0,0 @@ -@tool -extends Control - -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_EmptyTexture = preload("../../icons/empty.png") -const EMPTY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal load_pressed -signal clear_pressed - - -@onready var _label : Label = $Label -@onready var _texture_rect : TextureRect = $TextureRect - -@onready var _buttons = [ - $LoadButton, - $ClearButton -] - -var _material : Material -var _is_empty := true - - -func set_label(text: String): - _label.text = text - - -func set_texture(tex: Texture): - if tex == null: - _texture_rect.texture = load(EMPTY_TEXTURE_PATH) - _texture_rect.material = null - _is_empty = true - else: - _texture_rect.texture = tex - _texture_rect.material = _material - _is_empty = false - - -func set_texture_tooltip(msg: String): - _texture_rect.tooltip_text = msg - - -func _on_LoadButton_pressed(): - load_pressed.emit() - - -func _on_ClearButton_pressed(): - clear_pressed.emit() - - -func set_material(mat: Material): - _material = mat - if not _is_empty: - _texture_rect.material = _material - - -func set_enabled(enabled: bool): - for b in _buttons: - b.disabled = not enabled - diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd.uid deleted file mode 100644 index 0c2f279..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c1r8hav3fsxrk diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn deleted file mode 100644 index 9907e0c..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn +++ /dev/null @@ -1,29 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dqgaomu3tr1ym"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.gd" id="2"] - -[node name="SourceFileItem" type="VBoxContainer"] -offset_right = 128.0 -offset_bottom = 194.0 -script = ExtResource("2") - -[node name="Label" type="Label" parent="."] -layout_mode = 2 -text = "Albedo" - -[node name="TextureRect" type="TextureRect" parent="."] -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="LoadButton" type="Button" parent="."] -layout_mode = 2 -text = "Load..." - -[node name="ClearButton" type="Button" parent="."] -layout_mode = 2 -text = "Clear" - -[connection signal="pressed" from="LoadButton" to="." method="_on_LoadButton_pressed"] -[connection signal="pressed" from="ClearButton" to="." method="_on_ClearButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd deleted file mode 100644 index 03f0a30..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd +++ /dev/null @@ -1,529 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrainTextureSet = preload("../../../hterrain_texture_set.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Util = preload("../../../util/util.gd") -const HT_Logger = preload("../../../util/logger.gd") - -const HT_ColorShader = preload("../display_color.gdshader") -const HT_ColorSliceShader = preload("../display_color_slice.gdshader") -const HT_AlphaShader = preload("../display_alpha.gdshader") -const HT_AlphaSliceShader = preload("../display_alpha_slice.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_EmptyTexture = preload("../../icons/empty.png") -const EMPTY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal import_selected - -@onready var _slots_list : ItemList = $VB/HS/VB/SlotsList -@onready var _albedo_preview : TextureRect = $VB/HS/VB2/GC/AlbedoPreview -@onready var _bump_preview : TextureRect = $VB/HS/VB2/GC/BumpPreview -@onready var _normal_preview : TextureRect = $VB/HS/VB2/GC/NormalPreview -@onready var _roughness_preview : TextureRect = $VB/HS/VB2/GC/RoughnessPreview -@onready var _load_albedo_button : Button = $VB/HS/VB2/GC/LoadAlbedo -@onready var _load_normal_button : Button = $VB/HS/VB2/GC/LoadNormal -@onready var _clear_albedo_button : Button = $VB/HS/VB2/GC/ClearAlbedo -@onready var _clear_normal_button : Button = $VB/HS/VB2/GC/ClearNormal -@onready var _mode_selector : OptionButton = $VB/HS/VB2/GC2/ModeSelector -@onready var _add_slot_button : Button = $VB/HS/VB/HB/AddSlot -@onready var _remove_slot_button : Button = $VB/HS/VB/HB/RemoveSlot - -var _texture_set : HTerrainTextureSet -var _undo_redo_manager : EditorUndoRedoManager - -var _mode_confirmation_dialog : ConfirmationDialog -var _delete_slot_confirmation_dialog : ConfirmationDialog -var _load_texture_dialog : ConfirmationDialog -var _load_texture_array_dialog : ConfirmationDialog -var _load_texture_type := -1 - -var _logger = HT_Logger.get_for(self) - - -func _init(): - get_ok_button().hide() - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - for id in HTerrainTextureSet.MODE_COUNT: - var mode_name = HTerrainTextureSet.get_import_mode_name(id) - _mode_selector.add_item(mode_name, id) - - -func setup_dialogs(parent: Node): - var d = HT_EditorUtil.create_open_texture_dialog() - d.file_selected.connect(_on_LoadTextureDialog_file_selected) - _load_texture_dialog = d - add_child(d) - - d = HT_EditorUtil.create_open_texture_array_dialog() - d.file_selected.connect(_on_LoadTextureArrayDialog_file_selected) - _load_texture_array_dialog = d - add_child(d) - - d = ConfirmationDialog.new() - d.confirmed.connect(_on_ModeConfirmationDialog_confirmed) - # This is ridiculous. - # See https://github.com/godotengine/godot/issues/17460 -# d.connect("modal_closed", self, "_on_ModeConfirmationDialog_cancelled") -# d.get_close_button().connect("pressed", self, "_on_ModeConfirmationDialog_cancelled") -# d.get_cancel().connect("pressed", self, "_on_ModeConfirmationDialog_cancelled") - _mode_confirmation_dialog = d - add_child(d) - - -func _notification(what: int): - if HT_Util.is_in_edited_scene(self): - return - - if what == NOTIFICATION_EXIT_TREE: - # Have to check for null in all of them, - # because otherwise it breaks in the scene editor... - if _load_texture_dialog != null: - _load_texture_dialog.queue_free() - if _load_texture_array_dialog != null: - _load_texture_array_dialog.queue_free() - - if what == NOTIFICATION_VISIBILITY_CHANGED: - if not visible: - # Cleanup referenced resources - set_texture_set(null) - - -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func set_texture_set(texture_set: HTerrainTextureSet): - if _texture_set == texture_set: - return - - if _texture_set != null: - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = texture_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - _update_ui_from_data() - - -func _on_texture_set_changed(): - _update_ui_from_data() - - -func _update_ui_from_data(): - var prev_selected_items = _slots_list.get_selected_items() - - _slots_list.clear() - - var slots_count := _texture_set.get_slots_count() - for slot_index in slots_count: - _slots_list.add_item("Texture {0}".format([slot_index])) - - _set_selected_id(_mode_selector, _texture_set.get_mode()) - - if _slots_list.get_item_count() > 0: - if len(prev_selected_items) > 0: - var i : int = prev_selected_items[0] - if i >= _slots_list.get_item_count(): - i = _slots_list.get_item_count() - 1 - _select_slot(i) - else: - _select_slot(0) - else: - _clear_previews() - - var max_slots := HTerrainTextureSet.get_max_slots_for_mode(_texture_set.get_mode()) - _add_slot_button.disabled = slots_count >= max_slots - _remove_slot_button.disabled = slots_count == 0 - - var buttons := [ - _load_albedo_button, - _load_normal_button, - _clear_albedo_button, - _clear_normal_button - ] - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _add_slot_button.visible = true - _remove_slot_button.visible = true - _load_albedo_button.text = "Load..." - _load_normal_button.text = "Load..." - - for b in buttons: - b.disabled = (slots_count == 0) - - else: - _add_slot_button.visible = false - _remove_slot_button.visible = false - _load_albedo_button.text = "Load Array..." - _load_normal_button.text = "Load Array..." - - for b in buttons: - b.disabled = false - - -static func _set_selected_id(ob: OptionButton, id: int): - for i in ob.get_item_count(): - if ob.get_item_id(i) == id: - ob.selected = i - break - - -func select_slot(slot_index: int): - var count = _texture_set.get_slots_count() - if count > 0: - if slot_index >= count: - slot_index = count - 1 - _select_slot(slot_index) - - -func _clear_previews(): - var empty_texture : Texture2D = load(EMPTY_TEXTURE_PATH) - if empty_texture == null: - _logger.error(str("Failed to load empty texture ", EMPTY_TEXTURE_PATH)) - - _albedo_preview.texture = empty_texture - _bump_preview.texture = empty_texture - _normal_preview.texture = empty_texture - _roughness_preview.texture = empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(null) - _bump_preview.tooltip_text = _get_resource_path_or_empty(null) - _normal_preview.tooltip_text = _get_resource_path_or_empty(null) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(null) - - -func _select_slot(slot_index: int): - assert(slot_index >= 0) - assert(slot_index < _texture_set.get_slots_count()) - - var empty_texture : Texture2D = load(EMPTY_TEXTURE_PATH) - if empty_texture == null: - _logger.error(str("Failed to load empty texture ", EMPTY_TEXTURE_PATH)) - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - var albedo_tex := \ - _texture_set.get_texture(slot_index, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var normal_tex := \ - _texture_set.get_texture(slot_index, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - _albedo_preview.texture = albedo_tex if albedo_tex != null else empty_texture - _bump_preview.texture = albedo_tex if albedo_tex != null else empty_texture - _normal_preview.texture = normal_tex if normal_tex != null else empty_texture - _roughness_preview.texture = normal_tex if normal_tex != null else empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _bump_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _normal_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - - _albedo_preview.material.shader = HT_ColorShader - _bump_preview.material.shader = HT_AlphaShader - _normal_preview.material.shader = HT_ColorShader - _roughness_preview.material.shader = HT_AlphaShader - - _albedo_preview.material.set_shader_parameter("u_texture_array", null) - _bump_preview.material.set_shader_parameter("u_texture_array", null) - _normal_preview.material.set_shader_parameter("u_texture_array", null) - _roughness_preview.material.set_shader_parameter("u_texture_array", null) - - else: - var albedo_tex := _texture_set.get_texture_array(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var normal_tex := _texture_set.get_texture_array(HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - _albedo_preview.texture = empty_texture - _bump_preview.texture = empty_texture - _normal_preview.texture = empty_texture - _roughness_preview.texture = empty_texture - - _albedo_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _bump_preview.tooltip_text = _get_resource_path_or_empty(albedo_tex) - _normal_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - _roughness_preview.tooltip_text = _get_resource_path_or_empty(normal_tex) - - _albedo_preview.material.shader = HT_ColorSliceShader - _bump_preview.material.shader = HT_AlphaSliceShader - _normal_preview.material.shader = \ - HT_ColorSliceShader if normal_tex != null else HT_ColorShader - _roughness_preview.material.shader = \ - HT_AlphaSliceShader if normal_tex != null else HT_AlphaShader - - _albedo_preview.material.set_shader_parameter("u_texture_array", albedo_tex) - _bump_preview.material.set_shader_parameter("u_texture_array", albedo_tex) - _normal_preview.material.set_shader_parameter("u_texture_array", normal_tex) - _roughness_preview.material.set_shader_parameter("u_texture_array", normal_tex) - - _albedo_preview.material.set_shader_parameter("u_index", slot_index) - _bump_preview.material.set_shader_parameter("u_index", slot_index) - _normal_preview.material.set_shader_parameter("u_index", slot_index) - _roughness_preview.material.set_shader_parameter("u_index", slot_index) - - _slots_list.select(slot_index) - - -static func _get_resource_path_or_empty(res: Resource) -> String: - if res != null: - return res.resource_path - return "" - - -func _on_ImportButton_pressed(): - import_selected.emit() - - -func _on_CloseButton_pressed(): - hide() - - -func _get_undo_redo_for_texture_set() -> UndoRedo: - return _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_texture_set)) - - -func _on_AddSlot_pressed(): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - var slot_index = _texture_set.get_slots_count() - var ur := _get_undo_redo_for_texture_set() - ur.create_action("HTerrainTextureSet: add slot") - ur.add_do_method(_texture_set.insert_slot.bind(-1)) - ur.add_undo_method(_texture_set.remove_slot.bind(slot_index)) - ur.commit_action() - - -func _on_RemoveSlot_pressed(): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - - var slot_index = _slots_list.get_selected_items()[0] - var textures = [] - for type in HTerrainTextureSet.TYPE_COUNT: - textures.append(_texture_set.get_texture(slot_index, type)) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: remove slot") - - ur.add_do_method(_texture_set.remove_slot.bind(slot_index)) - - ur.add_undo_method(_texture_set.insert_slot.bind(slot_index)) - for type in len(textures): - var texture = textures[type] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_undo_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(_texture_set.set_texture.bind(slot_index, type, texture)) - - ur.commit_action() - - -func _on_SlotsList_item_selected(index: int): - _select_slot(index) - - -func _open_load_texture_dialog(type: int): - _load_texture_type = type - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _load_texture_dialog.popup_centered_ratio() - else: - _load_texture_array_dialog.popup_centered_ratio() - - -func _on_LoadAlbedo_pressed(): - _open_load_texture_dialog(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - - -func _on_LoadNormal_pressed(): - _open_load_texture_dialog(HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - -func _set_texture_action(slot_index: int, texture: Texture, type: int): - var prev_texture = _texture_set.get_texture(slot_index, type) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: load texture") - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_do_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_do_method(_texture_set.set_texture.bind(slot_index, type, texture)) - ur.add_do_method(self._select_slot.bind(slot_index)) - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if prev_texture == null: - ur.add_undo_method(_texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(_texture_set.set_texture.bind(slot_index, type, prev_texture)) - ur.add_undo_method(self._select_slot.bind(slot_index)) - - ur.commit_action() - - -func _set_texture_array_action(slot_index: int, texture_array: TextureLayered, type: int): - var prev_texture_array = _texture_set.get_texture_array(type) - - var ur := _get_undo_redo_for_texture_set() - - ur.create_action("HTerrainTextureSet: load texture array") - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture_array == null: - ur.add_do_method(_texture_set.set_texture_array_null.bind(type)) - # Can't select a slot after this because there won't be any after the array is removed - else: - ur.add_do_method(_texture_set.set_texture_array.bind(type, texture_array)) - ur.add_do_method(self._select_slot.bind(slot_index)) - - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if prev_texture_array == null: - ur.add_undo_method(_texture_set.set_texture_array_null.bind(type)) - # Can't select a slot after this because there won't be any after the array is removed - else: - ur.add_undo_method(_texture_set.set_texture_array.bind(type, prev_texture_array)) - ur.add_undo_method(self._select_slot.bind(slot_index)) - - ur.commit_action() - - -func _on_LoadTextureDialog_file_selected(fpath: String): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES) - var texture = load(fpath) - assert(texture != null) - var slot_index : int = _slots_list.get_selected_items()[0] - _set_texture_action(slot_index, texture, _load_texture_type) - - -func _on_LoadTextureArrayDialog_file_selected(fpath: String): - assert(_texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURE_ARRAYS) - var texture_array = load(fpath) - assert(texture_array != null) - # It's possible no slot exists at the moment, - # because there could be no texture array already set. - # The number of slots in the new array might also be different. - # So in this case we'll default to selecting the first slot. - var slot_index := 0 - _set_texture_array_action(slot_index, texture_array, _load_texture_type) - - -func _on_ClearAlbedo_pressed(): - var slot_index : int = _slots_list.get_selected_items()[0] - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _set_texture_action(slot_index, null, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - else: - _set_texture_array_action(slot_index, null, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - - -func _on_ClearNormal_pressed(): - var slot_index : int = _slots_list.get_selected_items()[0] - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _set_texture_action(slot_index, null, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - else: - _set_texture_array_action(slot_index, null, HTerrainTextureSet.TYPE_NORMAL_ROUGHNESS) - - -func _on_ModeSelector_item_selected(index: int): - var id := _mode_selector.get_selected_id() - if id == _texture_set.get_mode(): - return - - # Early-cancel the change in OptionButton, so we won't need to rely on - # the (inexistent) cancel signal from ConfirmationDialog - _set_selected_id(_mode_selector, _texture_set.get_mode()) - - if not _texture_set.has_any_textures(): - _switch_mode_action() - - else: - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - _mode_confirmation_dialog.title = "Switch to TextureArrays" - _mode_confirmation_dialog.dialog_text = \ - "This will unload all textures currently setup. Do you want to continue?" - _mode_confirmation_dialog.popup_centered() - - else: - _mode_confirmation_dialog.title = "Switch to Textures" - _mode_confirmation_dialog.dialog_text = \ - "This will unload all textures currently setup. Do you want to continue?" - _mode_confirmation_dialog.popup_centered() - - -func _on_ModeConfirmationDialog_confirmed(): - _switch_mode_action() - - -func _switch_mode_action(): - var mode := _texture_set.get_mode() - var ur := _get_undo_redo_for_texture_set() - - if mode == HTerrainTextureSet.MODE_TEXTURES: - ur.create_action("HTerrainTextureSet: switch to TextureArrays") - ur.add_do_method(_texture_set.set_mode.bind(HTerrainTextureSet.MODE_TEXTURE_ARRAYS)) - backup_for_undo(_texture_set, ur) - - else: - ur.create_action("HTerrainTextureSet: switch to Textures") - ur.add_do_method(_texture_set.set_mode.bind(HTerrainTextureSet.MODE_TEXTURES)) - backup_for_undo(_texture_set, ur) - - ur.commit_action() - - -static func backup_for_undo(texture_set: HTerrainTextureSet, ur: UndoRedo): - var mode := texture_set.get_mode() - - ur.add_undo_method(texture_set.clear) - ur.add_undo_method(texture_set.set_mode.bind(mode)) - - if mode == HTerrainTextureSet.MODE_TEXTURES: - # Backup slots - var slot_count := texture_set.get_slots_count() - var type_textures := [] - for type in HTerrainTextureSet.TYPE_COUNT: - var textures := [] - for slot_index in slot_count: - textures.append(texture_set.get_texture(slot_index, type)) - type_textures.append(textures) - - for type in len(type_textures): - var textures = type_textures[type] - for slot_index in len(textures): - ur.add_undo_method(texture_set.insert_slot.bind(slot_index)) - var texture = textures[slot_index] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture == null: - ur.add_undo_method(texture_set.set_texture_null.bind(slot_index, type)) - else: - ur.add_undo_method(texture_set.set_texture.bind(slot_index, type, texture)) - - else: - # Backup slots - var type_textures := [] - for type in HTerrainTextureSet.TYPE_COUNT: - type_textures.append(texture_set.get_texture_array(type)) - - for type in len(type_textures): - var texture_array = type_textures[type] - # TODO This branch only exists because of a flaw in UndoRedo - # See https://github.com/godotengine/godot/issues/36895 - if texture_array == null: - ur.add_undo_method(texture_set.set_texture_array_null.bind(type)) - else: - ur.add_undo_method(texture_set.set_texture_array.bind(type, texture_array)) - - -#func _on_ModeConfirmationDialog_cancelled(): -# print("Cancelled") -# _set_selected_id(_mode_selector, _texture_set.get_mode()) - diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd.uid deleted file mode 100644 index a875846..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://jq1uw21pp5ev diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn deleted file mode 100644 index f69c89a..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.tscn +++ /dev/null @@ -1,194 +0,0 @@ -[gd_scene load_steps=9 format=3 uid="uid://c0e7ifnoygvr6"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_editor.gd" id="1"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/texture_editor/display_alpha.gdshader" id="2"] -[ext_resource type="Shader" path="res://addons/zylann.hterrain/tools/texture_editor/display_color.gdshader" id="3"] -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="5"] - -[sub_resource type="ShaderMaterial" id="1"] -shader = ExtResource("3") - -[sub_resource type="ShaderMaterial" id="2"] -shader = ExtResource("2") - -[sub_resource type="ShaderMaterial" id="3"] -shader = ExtResource("3") - -[sub_resource type="ShaderMaterial" id="4"] -shader = ExtResource("2") - -[node name="TextureSetEditor" type="AcceptDialog"] -title = "TextureSet Editor" -size = Vector2i(666, 341) -min_size = Vector2i(652, 320) -script = ExtResource("1") - -[node name="VB" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HS" type="HSplitContainer" parent="VB"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="VB/HS"] -layout_mode = 2 - -[node name="SlotsList" type="ItemList" parent="VB/HS/VB"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -size_flags_vertical = 3 - -[node name="HB" type="HBoxContainer" parent="VB/HS/VB"] -layout_mode = 2 - -[node name="AddSlot" type="Button" parent="VB/HS/VB/HB"] -layout_mode = 2 -text = "+" - -[node name="Control" type="Control" parent="VB/HS/VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="RemoveSlot" type="Button" parent="VB/HS/VB/HB"] -layout_mode = 2 -text = "-" - -[node name="VB2" type="VBoxContainer" parent="VB/HS"] -layout_mode = 2 - -[node name="GC" type="GridContainer" parent="VB/HS/VB2"] -layout_mode = 2 -columns = 4 - -[node name="AlbedoLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Albedo" - -[node name="AlbedoExtraLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "+ alpha bump" - -[node name="NormalLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Normal" - -[node name="NormalExtraLabel" type="Label" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "+ alpha roughness" - -[node name="AlbedoPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("1") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="BumpPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("2") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="NormalPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("3") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="RoughnessPreview" type="TextureRect" parent="VB/HS/VB2/GC"] -material = SubResource("4") -custom_minimum_size = Vector2(128, 128) -layout_mode = 2 -expand_mode = 1 -stretch_mode = 1 - -[node name="LoadAlbedo" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Load..." - -[node name="Spacer" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="LoadNormal" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Load..." - -[node name="Spacer2" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="ClearAlbedo" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Clear" - -[node name="Spacer3" type="Control" parent="VB/HS/VB2/GC"] -layout_mode = 2 - -[node name="ClearNormal" type="Button" parent="VB/HS/VB2/GC"] -layout_mode = 2 -text = "Clear" - -[node name="HSeparator" type="Control" parent="VB/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="GC2" type="HBoxContainer" parent="VB/HS/VB2"] -layout_mode = 2 - -[node name="Label" type="Label" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -text = "Mode" - -[node name="ModeSelector" type="OptionButton" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Spacer" type="Control" parent="VB/HS/VB2/GC2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Spacer" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="VB"] -layout_mode = 2 -alignment = 1 - -[node name="ImportButton" type="Button" parent="VB/HB"] -layout_mode = 2 -text = "Import..." - -[node name="CloseButton" type="Button" parent="VB/HB"] -layout_mode = 2 -text = "Close" - -[node name="Spacer2" type="Control" parent="VB"] -custom_minimum_size = Vector2(0, 2) -layout_mode = 2 - -[node name="DialogFitter" parent="." instance=ExtResource("5")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 658.0 -offset_bottom = 323.0 - -[connection signal="item_selected" from="VB/HS/VB/SlotsList" to="." method="_on_SlotsList_item_selected"] -[connection signal="pressed" from="VB/HS/VB/HB/AddSlot" to="." method="_on_AddSlot_pressed"] -[connection signal="pressed" from="VB/HS/VB/HB/RemoveSlot" to="." method="_on_RemoveSlot_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/LoadAlbedo" to="." method="_on_LoadAlbedo_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/LoadNormal" to="." method="_on_LoadNormal_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/ClearAlbedo" to="." method="_on_ClearAlbedo_pressed"] -[connection signal="pressed" from="VB/HS/VB2/GC/ClearNormal" to="." method="_on_ClearNormal_pressed"] -[connection signal="item_selected" from="VB/HS/VB2/GC2/ModeSelector" to="." method="_on_ModeSelector_item_selected"] -[connection signal="pressed" from="VB/HB/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="VB/HB/CloseButton" to="." method="_on_CloseButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd deleted file mode 100644 index 9df98cf..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd +++ /dev/null @@ -1,909 +0,0 @@ -@tool -extends AcceptDialog - -const HTerrainTextureSet = preload("../../../hterrain_texture_set.gd") -const HT_Logger = preload("../../../util/logger.gd") -const HT_EditorUtil = preload("../../util/editor_util.gd") -const HT_Errors = preload("../../../util/errors.gd") -const HT_TextureSetEditor = preload("./texture_set_editor.gd") -const HT_Result = preload("../../util/result.gd") -const HT_Util = preload("../../../util/util.gd") -const HT_PackedTextureUtil = preload("../../packed_textures/packed_texture_util.gd") -const ResourceImporterTexture_Unexposed = preload("../../util/resource_importer_texture.gd") -const ResourceImporterTextureLayered_Unexposed = preload( - "../../util/resource_importer_texture_layered.gd") - -const HT_NormalMapPreviewShader = preload("../display_normal.gdshader") - -const COMPRESS_RAW = 0 -const COMPRESS_LOSSLESS = 1 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM = 2 -const COMPRESS_COUNT = 3 - -const _compress_names = ["Raw", "Lossless", "Lossy", "VRAM"] - -# Indexed by HTerrainTextureSet.SRC_TYPE_* constants -const _smart_pick_file_keywords = [ - ["albedo", "color", "col", "diffuse", "diff"], - ["bump", "height", "depth", "displacement", "disp"], - ["normal", "norm", "nrm", "normalgl", "nor_gl"], - ["roughness", "rough", "rgh"] -] - -signal import_finished - -@onready var _texture_editors = [ - $Import/HS/VB2/HB/Albedo, - $Import/HS/VB2/HB/Bump, - $Import/HS/VB2/HB/Normal, - $Import/HS/VB2/HB/Roughness -] - -@onready var _slots_list : ItemList = $Import/HS/VB/SlotsList - -# TODO Some shortcuts to import options were disabled in the GUI because of Godot issues. -# If users want to customize that, they need to do it on the files directly. -# -# There is no script API in Godot to choose the import settings of a generated file. -# They always start with the defaults, and the only implemented case is for the import dock. -# It appeared possible to reverse-engineer and write a .import file as done in HTerrainData, -# however when I tried this with custom importers, Godot stopped importing after scan(), -# and the resources could not load. However, selecting them each and clicking "Reimport" -# did import them fine. Unfortunately, this short-circuits the workflow. -# Since I have no idea what's going on with this reverse-engineering, I had to drop those options. -# Godot needs an API to import specific files and choose settings before the first import. -# -# Godot 4: now we'll really need it, let's enable and we'll see if it works -# when we can test the workflow... -const _WRITE_IMPORT_FILES = true - -@onready var _import_mode_selector : OptionButton = $Import/GC/ImportModeSelector -@onready var _compression_selector : OptionButton = $Import/GC/CompressionSelector -@onready var _resolution_spinbox : SpinBox = $Import/GC/ResolutionSpinBox -@onready var _mipmaps_checkbox : CheckBox = $Import/GC/MipmapsCheckbox -@onready var _add_slot_button : Button = $Import/HS/VB/HB/AddSlotButton -@onready var _remove_slot_button : Button = $Import/HS/VB/HB/RemoveSlotButton -@onready var _import_directory_line_edit : LineEdit = $Import/HB2/ImportDirectoryLineEdit -@onready var _normalmap_flip_checkbox : CheckBox = $Import/HS/VB2/HB/Normal/NormalMapFlipY - -var _texture_set : HTerrainTextureSet -var _undo_redo_manager : EditorUndoRedoManager -var _logger = HT_Logger.get_for(self) - -# This is normally an `EditorFileDialog`. I can't type-hint this one properly, -# because when I test this UI in isolation, I can't use `EditorFileDialog`. -var _load_texture_dialog : ConfirmationDialog -var _load_texture_type : int = -1 -var _error_popup : AcceptDialog -var _info_popup : AcceptDialog -var _delete_confirmation_popup : ConfirmationDialog -var _open_dir_dialog : ConfirmationDialog -var _editor_file_system : EditorFileSystem -var _normalmap_material : ShaderMaterial - -var _import_mode := HTerrainTextureSet.MODE_TEXTURES - -class HT_TextureSetImportEditorSlot: - # Array of strings. - # Can be either path to images, hexadecimal colors starting with #, or empty string for "null". - var texture_paths := [] - var flip_normalmap_y := false - - func _init(): - for i in HTerrainTextureSet.SRC_TYPE_COUNT: - texture_paths.append("") - -# Array of HT_TextureSetImportEditorSlot -var _slots_data := [] - -var _import_settings := { - "mipmaps": true, - "compression": COMPRESS_VRAM, - "resolution": 512 -} - - -func _init(): - get_ok_button().hide() - - # Default data - _slots_data.clear() - for i in 4: - _slots_data.append(HT_TextureSetImportEditorSlot.new()) - - -func _ready(): - if HT_Util.is_in_edited_scene(self): - return - - for src_type in len(_texture_editors): - var ed = _texture_editors[src_type] - var typename = HTerrainTextureSet.get_source_texture_type_name(src_type) - ed.set_label(typename.capitalize()) - ed.load_pressed.connect(_on_texture_load_pressed.bind(src_type)) - ed.clear_pressed.connect(_on_texture_clear_pressed.bind(src_type)) - - for import_mode in HTerrainTextureSet.MODE_COUNT: - var n = HTerrainTextureSet.get_import_mode_name(import_mode) - _import_mode_selector.add_item(n, import_mode) - - for compress_mode in COMPRESS_COUNT: - var n = _compress_names[compress_mode] - _compression_selector.add_item(n, compress_mode) - - _normalmap_material = ShaderMaterial.new() - _normalmap_material.shader = HT_NormalMapPreviewShader - _texture_editors[HTerrainTextureSet.SRC_TYPE_NORMAL].set_material(_normalmap_material) - - -func setup_dialogs(parent: Node): - var d = HT_EditorUtil.create_open_image_dialog() - d.file_selected.connect(_on_LoadTextureDialog_file_selected) - _load_texture_dialog = d - add_child(d) - - d = AcceptDialog.new() - d.title = "Import error" - _error_popup = d - add_child(_error_popup) - - d = AcceptDialog.new() - d.title = "Info" - _info_popup = d - add_child(_info_popup) - - d = ConfirmationDialog.new() - d.confirmed.connect(_on_delete_confirmation_popup_confirmed) - _delete_confirmation_popup = d - add_child(_delete_confirmation_popup) - - d = HT_EditorUtil.create_open_dir_dialog() - d.title = "Choose import directory" - d.dir_selected.connect(_on_OpenDirDialog_dir_selected) - _open_dir_dialog = d - add_child(_open_dir_dialog) - - _update_ui_from_data() - - -func _notification(what: int): - if what == NOTIFICATION_EXIT_TREE: - # Have to check for null in all of them, - # because otherwise it breaks in the scene editor... - if _load_texture_dialog != null: - _load_texture_dialog.queue_free() - if _error_popup != null: - _error_popup.queue_free() - if _delete_confirmation_popup != null: - _delete_confirmation_popup.queue_free() - if _open_dir_dialog != null: - _open_dir_dialog.queue_free() - if _info_popup != null: - _info_popup.queue_free() - - -# TODO Is it still necessary for an import tab? -func set_undo_redo(ur: EditorUndoRedoManager): - _undo_redo_manager = ur - - -func set_editor_file_system(efs: EditorFileSystem): - _editor_file_system = efs - - -func set_texture_set(texture_set: HTerrainTextureSet): - if _texture_set == texture_set: - # TODO What if the set was actually modified since? - return - _texture_set = texture_set - - _slots_data.clear() - - if _texture_set.get_mode() == HTerrainTextureSet.MODE_TEXTURES: - var slots_count = _texture_set.get_slots_count() - - for slot_index in slots_count: - var slot := HT_TextureSetImportEditorSlot.new() - - for type in HTerrainTextureSet.TYPE_COUNT: - var texture = _texture_set.get_texture(slot_index, type) - - if texture == null or texture.resource_path == "": - continue - - # In Godot 3 we used a custom format to store and composite source images - # with a custom importer. It was removed during the port to Godot 4 because it - # was too hard to maintain a custom texture importer (too much logic to replicate - # from Godot's builtin importer, which wasn't exposed). - # For now the import tool won't remember source images between editor sessions. - -# if not texture.resource_path.ends_with(".packed_tex"): -# continue -# -# var import_data := _parse_json_file(texture.resource_path) -# if import_data.is_empty() or not import_data.has("src"): -# continue -# -# var src_types = HTerrainTextureSet.get_src_types_from_type(type) -# -# var src_data = import_data["src"] -# if src_data.has("rgb"): -# slot.texture_paths[src_types[0]] = src_data["rgb"] -# if src_data.has("a"): -# slot.texture_paths[src_types[1]] = src_data["a"] - - _slots_data.append(slot) - - else: - var slots_count := _texture_set.get_slots_count() - - for type in HTerrainTextureSet.TYPE_COUNT: - var texture_array := _texture_set.get_texture_array(type) - - if texture_array == null or texture_array.resource_path == "": - continue - - # In Godot 3 we used a custom format to store and composite source images - # with a custom importer. It was removed during the port to Godot 4 because it - # was too hard to maintain a custom texture importer (too much logic to replicate - # from Godot's builtin importer, which wasn't exposed). - # For now the import tool won't remember source images between editor sessions. - -# if not texture_array.resource_path.ends_with(".packed_texarr"): -# continue -# -# var import_data := _parse_json_file(texture_array.resource_path) -# if import_data.is_empty() or not import_data.has("layers"): -# continue -# -# var layers_data = import_data["layers"] -# -# for slot_index in len(layers_data): -# var src_data = layers_data[slot_index] -# -# var src_types = HTerrainTextureSet.get_src_types_from_type(type) -# -# while slot_index >= len(_slots_data): -# var slot = HT_TextureSetImportEditorSlot.new() -# _slots_data.append(slot) -# -# var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] -# -# if src_data.has("rgb"): -# slot.texture_paths[src_types[0]] = src_data["rgb"] -# if src_data.has("a"): -# slot.texture_paths[src_types[1]] = src_data["a"] - - # TODO If the set doesn't have a file, use terrain path by default? - if texture_set.resource_path != "": - var dir = texture_set.resource_path.get_base_dir() - _import_directory_line_edit.text = dir - - _update_ui_from_data() - - -func _parse_json_file(fpath: String) -> Dictionary: - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - _logger.error("Could not load {0}: {1}".format([fpath, HT_Errors.get_message(err)])) - return {} - - var json_text := f.get_as_text() - var json := JSON.new() - var json_err := json.parse(json_text) - if json_err != OK: - _logger.error("Failed to parse {0}: {1}".format([fpath, json.get_error_message()])) - return {} - - return json.data - - -func _update_ui_from_data(): - var prev_selected_items := _slots_list.get_selected_items() - - _slots_list.clear() - - for slot_index in len(_slots_data): - _slots_list.add_item("Texture {0}".format([slot_index])) - - _resolution_spinbox.value = _import_settings.resolution - _mipmaps_checkbox.button_pressed = _import_settings.mipmaps - _set_selected_id(_compression_selector, _import_settings.compression) - _set_selected_id(_import_mode_selector, _import_mode) - - var has_slots : bool = _slots_list.get_item_count() > 0 - - for ed in _texture_editors: - ed.set_enabled(has_slots) - _normalmap_flip_checkbox.disabled = not has_slots - - if has_slots: - if len(prev_selected_items) > 0: - var i : int = prev_selected_items[0] - if i >= _slots_list.get_item_count(): - i = _slots_list.get_item_count() - 1 - _select_slot(i) - else: - _select_slot(0) - else: - for type in HTerrainTextureSet.SRC_TYPE_COUNT: - _set_ui_slot_texture_from_path("", type) - - var max_slots := HTerrainTextureSet.get_max_slots_for_mode(_import_mode) - _add_slot_button.disabled = (len(_slots_data) >= max_slots) - _remove_slot_button.disabled = (len(_slots_data) == 0) - - -static func _set_selected_id(ob: OptionButton, id: int): - for i in ob.get_item_count(): - if ob.get_item_id(i) == id: - ob.selected = i - break - - -func _select_slot(slot_index: int): - assert(slot_index >= 0) - assert(slot_index < len(_slots_data)) - var slot = _slots_data[slot_index] - - for type in HTerrainTextureSet.SRC_TYPE_COUNT: - var im_path : String = slot.texture_paths[type] - _set_ui_slot_texture_from_path(im_path, type) - - _slots_list.select(slot_index) - - _normalmap_flip_checkbox.button_pressed = slot.flip_normalmap_y - _normalmap_material.set_shader_parameter("u_flip_y", slot.flip_normalmap_y) - - -func _set_ui_slot_texture_from_path(im_path: String, type: int): - var ed = _texture_editors[type] - - if im_path == "": - ed.set_texture(null) - ed.set_texture_tooltip("") - return - - var im : Image - - if im_path.begins_with("#") and im_path.find(".") == -1: - # The path is actually a preset for a uniform color. - # This is a feature of packed texture descriptor files. - # Make a small placeholder image. - var color := Color(im_path) - im = Image.create(4, 4, false, Image.FORMAT_RGBA8) - im.fill(color) - - else: - # Regular path - im = Image.new() - var err := im.load(ProjectSettings.globalize_path(im_path)) - if err != OK: - _logger.error(str("Unable to load image from ", im_path)) - # TODO Different icon for images that can't load? - ed.set_texture(null) - ed.set_texture_tooltip("") - return - - var tex := ImageTexture.create_from_image(im) - ed.set_texture(tex) - ed.set_texture_tooltip(im_path) - - -func _set_source_image(fpath: String, type: int): - _set_ui_slot_texture_from_path(fpath, type) - - var slot_index : int = _slots_list.get_selected_items()[0] - #var prev_path = _texture_set.get_source_image_path(slot_index, type) - - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - slot.texture_paths[type] = fpath - - -func _set_import_property(key: String, value): - var prev_value = _import_settings[key] - # This is needed, notably because CheckBox emits a signal too when we set it from code... - if prev_value == value: - return - - _import_settings[key] = value - - -func _on_texture_load_pressed(type: int): - _load_texture_type = type - _load_texture_dialog.popup_centered_ratio() - - -func _on_LoadTextureDialog_file_selected(fpath: String): - _set_source_image(fpath, _load_texture_type) - - if _load_texture_type == HTerrainTextureSet.SRC_TYPE_ALBEDO: - _smart_pick_files(fpath) - - -# Attempts to load source images of other types by looking at how the albedo file was named -func _smart_pick_files(albedo_fpath: String): - var albedo_words = _smart_pick_file_keywords[HTerrainTextureSet.SRC_TYPE_ALBEDO] - - var albedo_fname := albedo_fpath.get_file() - var albedo_fname_lower = albedo_fname.to_lower() - var fname_pattern = "" - - for albedo_word in albedo_words: - var i = albedo_fname_lower.find(albedo_word, 0) - if i != -1: - fname_pattern = \ - albedo_fname.substr(0, i) + "{0}" + albedo_fname.substr(i + len(albedo_word)) - break - - if fname_pattern == "": - return - - var dirpath := albedo_fpath.get_base_dir() - var fnames := _get_files_in_directory(dirpath, _logger) - - var types := [ - HTerrainTextureSet.SRC_TYPE_BUMP, - HTerrainTextureSet.SRC_TYPE_NORMAL, - HTerrainTextureSet.SRC_TYPE_ROUGHNESS - ] - - var slot_index : int = _slots_list.get_selected_items()[0] - - for type in types: - var slot = _slots_data[slot_index] - if slot.texture_paths[type] != "": - # Already set, don't overwrite unwantedly - continue - - var keywords = _smart_pick_file_keywords[type] - - for key in keywords: - var expected_fname = fname_pattern.format([key]) - - var found := false - - for i in len(fnames): - var fname : String = fnames[i] - - # TODO We should probably ignore extensions? - if fname.to_lower() == expected_fname.to_lower(): - var fpath = dirpath.path_join(fname) - _set_source_image(fpath, type) - found = true - break - - if found: - break - - -static func _get_files_in_directory(dirpath: String, logger) -> Array: - var dir := DirAccess.open(dirpath) - var err := DirAccess.get_open_error() - if err != OK: - logger.error("Could not open directory {0}: {1}" \ - .format([dirpath, HT_Errors.get_message(err)])) - return [] - - dir.include_hidden = false - dir.include_navigational = false - - err = dir.list_dir_begin() - if err != OK: - logger.error("Could not probe directory {0}: {1}" \ - .format([dirpath, HT_Errors.get_message(err)])) - return [] - - var files := [] - var fname := dir.get_next() - while fname != "": - if not dir.current_is_dir(): - files.append(fname) - fname = dir.get_next() - - return files - - -func _on_texture_clear_pressed(type: int): - _set_source_image("", type) - - -func _on_SlotsList_item_selected(index: int): - _select_slot(index) - - -func _on_ImportModeSelector_item_selected(index: int): - var mode : int = _import_mode_selector.get_item_id(index) - if mode != _import_mode: - #_set_import_property("mode", mode) - _import_mode = mode - _update_ui_from_data() - - -func _on_CompressionSelector_item_selected(index: int): - var compression : int = _compression_selector.get_item_id(index) - _set_import_property("compression", compression) - - -func _on_MipmapsCheckbox_toggled(button_pressed: bool): - _set_import_property("mipmaps", button_pressed) - - -func _on_ResolutionSpinBox_value_changed(value): - _set_import_property("resolution", int(value)) - - -func _on_TextureArrayPrefixLineEdit_text_changed(new_text: String): - _set_import_property("output_prefix", new_text) - - -func _on_AddSlotButton_pressed(): - var i := len(_slots_data) - _slots_data.append(HT_TextureSetImportEditorSlot.new()) - _update_ui_from_data() - _select_slot(i) - - -func _on_RemoveSlotButton_pressed(): - if _slots_list.get_item_count() == 0: - return - var selected_item = _slots_list.get_selected_items()[0] - _delete_confirmation_popup.title = "Delete slot {0}".format([selected_item]) - _delete_confirmation_popup.dialog_text = "Delete import slot {0}?".format([selected_item]) - _delete_confirmation_popup.popup_centered() - - -func _on_delete_confirmation_popup_confirmed(): - var selected_item : int = _slots_list.get_selected_items()[0] - _slots_data.remove_at(selected_item) - _update_ui_from_data() - - -func _on_CancelButton_pressed(): - hide() - - -func _on_BrowseImportDirectory_pressed(): - _open_dir_dialog.popup_centered_ratio() - - -func _on_ImportDirectoryLineEdit_text_changed(new_text: String): - pass - - -func _on_OpenDirDialog_dir_selected(dir_path: String): - _import_directory_line_edit.text = dir_path - - -func _show_error(message: String): - _error_popup.dialog_text = message - _error_popup.popup_centered() - - -func _on_NormalMapFlipY_toggled(button_pressed: bool): - var slot_index : int = _slots_list.get_selected_items()[0] - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - slot.flip_normalmap_y = button_pressed - _normalmap_material.set_shader_parameter("u_flip_y", slot.flip_normalmap_y) - - -# class ButtonDisabler: -# var _button : Button - -# func _init(b: Button): -# _button = b -# _button.disabled = true - -# func _notification(what: int): -# if what == NOTIFICATION_PREDELETE: -# _button.disabled = false - - -func _get_undo_redo_for_texture_set() -> UndoRedo: - return _undo_redo_manager.get_history_undo_redo( - _undo_redo_manager.get_object_history_id(_texture_set)) - - -func _on_ImportButton_pressed(): - if _texture_set == null: - _show_error("No HTerrainTextureSet selected.") - return - - var import_dir := _import_directory_line_edit.text.strip_edges() - - var prefix := "" - if _texture_set.resource_path != "": - prefix = _texture_set.resource_path.get_file().get_basename() + "_" - - var files_data_result : HT_Result - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - files_data_result = _generate_packed_images(import_dir, prefix) - else: - files_data_result = _generate_packed_texarray_images(import_dir, prefix) - - if not files_data_result.success: - _show_error(files_data_result.get_message()) - return - - var files_data : Array = files_data_result.value - - if len(files_data) == 0: - _show_error("There are no files to save.\nYou must setup at least one slot of textures.") - return - - for fd in files_data: - var dir_path : String = fd.path.get_base_dir() - if not DirAccess.dir_exists_absolute(dir_path): - _show_error("The directory {0} could not be found.".format([dir_path])) - return - - if _WRITE_IMPORT_FILES: - for fd in files_data: - var import_fpath = fd.path + ".import" - if not HT_Util.write_import_file(fd.import_file_data, import_fpath, _logger): - _show_error("Failed to write file {0}: {1}".format([import_fpath])) - return - - if _editor_file_system == null: - _show_error("EditorFileSystem is not setup, can't trigger import system.") - return - - # Notify Godot's file system that new files were created - for fd in files_data: - _editor_file_system.update_file(fd.path) - - # Import new files - var files_paths := PackedStringArray() - for fd in files_data: - files_paths.append(fd.path) - _editor_file_system.reimport_files(files_paths) - - var failed_resource_paths := [] - - # Using UndoRedo is mandatory for Godot to consider the resource as modified... - # ...yet if files get deleted, that won't be undoable anyways, but whatever :shrug: - var ur := _get_undo_redo_for_texture_set() - - # Check imported textures - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - for fd in files_data: - var texture : Texture2D = load(fd.path) - if texture == null: - failed_resource_paths.append(fd.path) - continue - fd.texture = texture - - else: - for fd in files_data: - var texture_array : TextureLayered = load(fd.path) - if texture_array == null: - failed_resource_paths.append(fd.path) - continue - fd.texture_array = texture_array - - if len(failed_resource_paths) > 0: - var failed_list := "\n".join(PackedStringArray(failed_resource_paths)) - _show_error("Some resources failed to load:\n" + failed_list) - return - - # All is OK, commit action to modify the texture set with imported textures - - if _import_mode == HTerrainTextureSet.MODE_TEXTURES: - ur.create_action("HTerrainTextureSet: import textures") - - HT_TextureSetEditor.backup_for_undo(_texture_set, ur) - - ur.add_do_method(_texture_set.clear) - ur.add_do_method(_texture_set.set_mode.bind(_import_mode)) - - for i in len(_slots_data): - ur.add_do_method(_texture_set.insert_slot.bind(-1)) - for fd in files_data: - ur.add_do_method(_texture_set.set_texture.bind(fd.slot_index, fd.type, fd.texture)) - - else: - ur.create_action("HTerrainTextureSet: import texture arrays") - - HT_TextureSetEditor.backup_for_undo(_texture_set, ur) - - ur.add_do_method(_texture_set.clear) - ur.add_do_method(_texture_set.set_mode.bind(_import_mode)) - - for fd in files_data: - ur.add_do_method(_texture_set.set_texture_array.bind(fd.type, fd.texture_array)) - - ur.commit_action() - - _logger.debug("Done importing") - - _info_popup.dialog_text = "Importing complete!" - _info_popup.popup_centered() - - import_finished.emit() - - -class HT_PackedImageInfo: - var path := "" # Where the packed image is saved - var slot_index : int # Slot in texture set, when using individual textures - var type : int # 0:Albedo+Bump, 1:Normal+Roughness - var import_file_data := {} # Data to write into the .import file (when enabled...) - var image : Image - var is_default := false - var texture : Texture2D - var texture_array : TextureLayered - - -# Shared code between the two import modes -func _generate_packed_images2() -> HT_Result: - var resolution : int = _import_settings.resolution - var images_infos := [] - - for type in HTerrainTextureSet.TYPE_COUNT: - var src_types := HTerrainTextureSet.get_src_types_from_type(type) - - for slot_index in len(_slots_data): - var slot : HT_TextureSetImportEditorSlot = _slots_data[slot_index] - - # Albedo or Normal - var src0 : String = slot.texture_paths[src_types[0]] - # Bump or Roughness - var src1 : String = slot.texture_paths[src_types[1]] - - if src0 == "": - if src_types[0] == HTerrainTextureSet.SRC_TYPE_ALBEDO: - return HT_Result.new(false, - "Albedo texture is missing in slot {0}".format([slot_index])) - - var is_default := (src0 == "" and src1 == "") - - if src0 == "": - src0 = HTerrainTextureSet.get_source_texture_default_color_code(src_types[0]) - if src1 == "": - src1 = HTerrainTextureSet.get_source_texture_default_color_code(src_types[1]) - - var pack_sources := { - "rgb": src0, - "a": src1 - } - - if HTerrainTextureSet.SRC_TYPE_NORMAL in src_types and slot.flip_normalmap_y: - pack_sources["normalmap_flip_y"] = true - - var packed_image_result := HT_PackedTextureUtil.generate_image( - pack_sources, resolution, _logger) - if not packed_image_result.success: - return packed_image_result - var packed_image : Image = packed_image_result.value - - var fd := HT_PackedImageInfo.new() - fd.slot_index = slot_index - fd.type = type - fd.image = packed_image - fd.is_default = is_default - - images_infos.append(fd) - - return HT_Result.new(true).with_value(images_infos) - - -func _generate_packed_images(import_dir: String, prefix: String) -> HT_Result: - var images_infos_result := _generate_packed_images2() - if not images_infos_result.success: - return images_infos_result - var images_infos : Array = images_infos_result.value - - for info_index in len(images_infos): - var info : HT_PackedImageInfo = images_infos[info_index] - - var type_name := HTerrainTextureSet.get_texture_type_name(info.type) - var fpath := import_dir.path_join( - str(prefix, "slot", info.slot_index, "_", type_name, ".png")) - - var err := info.image.save_png(fpath) - if err != OK: - return HT_Result.new(false, - "Could not save image {0}, {1}".format([fpath, HT_Errors.get_message(err)])) - - info.path = fpath - info.import_file_data = { - "remap": { - "importer": "texture", - "type": "CompressedTexture2D" - }, - "deps": { - "source_file": fpath - }, - "params": { - "compress/mode": ResourceImporterTexture_Unexposed.COMPRESS_VRAM_COMPRESSED, - "compress/high_quality": false, - "compress/lossy_quality": 0.7, - "mipmaps/generate": true, - "mipmaps/limit": -1, - "roughness/mode": ResourceImporterTexture_Unexposed.ROUGHNESS_DISABLED, - "process/fix_alpha_border": false - } - } - - return HT_Result.new(true).with_value(images_infos) - - -static func _assemble_texarray_images(images: Array[Image], resolution: Vector2i) -> Image: - # Godot expects some kind of grid. Let's be lazy and do a grid with only one row. - var atlas := Image.create(resolution.x * len(images), resolution.y, false, Image.FORMAT_RGBA8) - for index in len(images): - var image : Image = images[index] - if image.get_size() != resolution: - image.resize(resolution.x, resolution.y, Image.INTERPOLATE_BILINEAR) - atlas.blit_rect(image, - Rect2i(0, 0, image.get_width(), image.get_height()), - Vector2i(index * resolution.x, 0)) - return atlas - - -func _generate_packed_texarray_images(import_dir: String, prefix: String) -> HT_Result: - var images_infos_result := _generate_packed_images2() - if not images_infos_result.success: - return images_infos_result - var individual_images_infos : Array = images_infos_result.value - - var resolution : int = _import_settings.resolution - - var texarray_images_infos := [] - var slot_count := len(_slots_data) - - for type in HTerrainTextureSet.TYPE_COUNT: - var texarray_images : Array[Image] = [] - texarray_images.resize(slot_count) - - var fully_defaulted_slots := 0 - - for i in slot_count: - var info : HT_PackedImageInfo = individual_images_infos[type * slot_count + i] - if info.type == type: - texarray_images[i] = info.image - if info.is_default: - fully_defaulted_slots += 1 - - if fully_defaulted_slots == len(texarray_images): - # No need to generate this file at all - continue - - var texarray_image := _assemble_texarray_images(texarray_images, - Vector2i(resolution, resolution)) - - var type_name := HTerrainTextureSet.get_texture_type_name(type) - var fpath := import_dir.path_join(str(prefix, type_name, "_array.png")) - - var err := texarray_image.save_png(fpath) - if err != OK: - return HT_Result.new(false, - "Could not save image {0}, {1}".format([fpath, HT_Errors.get_message(err)])) - - var texarray_image_info := HT_PackedImageInfo.new() - texarray_image_info.type = type - texarray_image_info.path = fpath - texarray_image_info.import_file_data = { - "remap": { - "importer": "2d_array_texture", - "type": "CompressedTexture2DArray" - }, - "deps": { - "source_file": fpath - }, - "params": { - "compress/mode": ResourceImporterTextureLayered_Unexposed.COMPRESS_VRAM_COMPRESSED, - "compress/high_quality": false, - "compress/lossy_quality": 0.7, - "mipmaps/generate": true, - "mipmaps/limit": -1, - "process/fix_alpha_border": false, - "slices/horizontal": len(texarray_images), - "slices/vertical": 1 - } - } - - texarray_images_infos.append(texarray_image_info) - - return HT_Result.new(true).with_value(texarray_images_infos) diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd.uid deleted file mode 100644 index c8a0d0d..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dm64ke6hfojrd diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn deleted file mode 100644 index 81bff88..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.tscn +++ /dev/null @@ -1,219 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://3indvrto5vd5"] - -[ext_resource type="PackedScene" path="res://addons/zylann.hterrain/tools/util/dialog_fitter.tscn" id="1"] -[ext_resource type="PackedScene" uid="uid://dqgaomu3tr1ym" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/source_file_item_editor.tscn" id="3"] -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/set_editor/texture_set_import_editor.gd" id="4"] - -[node name="TextureSetImportEditor" type="AcceptDialog"] -title = "Texture Set Import Tool" -size = Vector2i(652, 623) -min_size = Vector2i(652, 480) -script = ExtResource("4") - -[node name="Import" type="VBoxContainer" parent="."] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = -8.0 -offset_bottom = -18.0 - -[node name="HS" type="HSplitContainer" parent="Import"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="VB" type="VBoxContainer" parent="Import/HS"] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label" type="Label" parent="Import/HS/VB"] -visible = false -layout_mode = 2 -text = "Slots" - -[node name="SlotsList" type="ItemList" parent="Import/HS/VB"] -custom_minimum_size = Vector2(100, 0) -layout_mode = 2 -size_flags_vertical = 3 -item_count = 7 -item_0/text = "Item 0" -item_1/text = "Item 1" -item_2/text = "Item 2" -item_3/text = "Item 3" -item_4/text = "Item 4" -item_5/text = "Item 5" -item_6/text = "Item 6" - -[node name="HB" type="HBoxContainer" parent="Import/HS/VB"] -layout_mode = 2 - -[node name="AddSlotButton" type="Button" parent="Import/HS/VB/HB"] -layout_mode = 2 -text = "+" - -[node name="Control" type="Control" parent="Import/HS/VB/HB"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="RemoveSlotButton" type="Button" parent="Import/HS/VB/HB"] -layout_mode = 2 -text = "-" - -[node name="VB2" type="VBoxContainer" parent="Import/HS"] -layout_mode = 2 - -[node name="Label" type="Label" parent="Import/HS/VB2"] -visible = false -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="Import/HS/VB2"] -layout_mode = 2 - -[node name="Albedo" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Bump" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Normal" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="NormalMapFlipY" type="CheckBox" parent="Import/HS/VB2/HB/Normal"] -layout_mode = 2 -text = "Flip Y" - -[node name="Roughness" parent="Import/HS/VB2/HB" instance=ExtResource("3")] -layout_mode = 2 - -[node name="Control" type="Control" parent="Import/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 - -[node name="Control2" type="Control" parent="Import/HS/VB2"] -custom_minimum_size = Vector2(0, 4) -layout_mode = 2 -size_flags_vertical = 3 - -[node name="Label3" type="Label" parent="Import/HS/VB2"] -modulate = Color(0.564706, 0.564706, 0.564706, 1) -custom_minimum_size = Vector2(400, 80) -layout_mode = 2 -text = "These images should remain accessible for import to work. -Tip: you can place them in a folder with a `.gdignore` file, so they won't take space in your exported game." -autowrap_mode = 2 - -[node name="Spacer3" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="Import"] -layout_mode = 2 - -[node name="GC" type="GridContainer" parent="Import"] -layout_mode = 2 -columns = 4 - -[node name="Label2" type="Label" parent="Import/GC"] -layout_mode = 2 -text = "Import mode: " - -[node name="ImportModeSelector" type="OptionButton" parent="Import/GC"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="MipmapsCheckbox" type="CheckBox" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Mipmaps" - -[node name="Spacer2" type="Control" parent="Import/GC"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="Label" type="Label" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Compression:" - -[node name="CompressionSelector" type="OptionButton" parent="Import/GC"] -visible = false -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="FilterCheckBox" type="CheckBox" parent="Import/GC"] -visible = false -layout_mode = 2 -text = "Filter" - -[node name="Spacer" type="Control" parent="Import/GC"] -layout_mode = 2 - -[node name="Label3" type="Label" parent="Import/GC"] -layout_mode = 2 -text = "Resolution:" - -[node name="ResolutionSpinBox" type="SpinBox" parent="Import/GC"] -layout_mode = 2 -min_value = 1.0 -max_value = 4096.0 -value = 1.0 - -[node name="HB2" type="HBoxContainer" parent="Import"] -layout_mode = 2 - -[node name="Label2" type="Label" parent="Import/HB2"] -layout_mode = 2 -text = "Import directory" - -[node name="ImportDirectoryLineEdit" type="LineEdit" parent="Import/HB2"] -layout_mode = 2 -size_flags_horizontal = 3 - -[node name="BrowseImportDirectory" type="Button" parent="Import/HB2"] -layout_mode = 2 -text = "..." - -[node name="Spacer" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="HB" type="HBoxContainer" parent="Import"] -layout_mode = 2 -alignment = 1 - -[node name="ImportButton" type="Button" parent="Import/HB"] -layout_mode = 2 -text = "Import to TextureSet" - -[node name="CancelButton" type="Button" parent="Import/HB"] -layout_mode = 2 -text = "Close" - -[node name="Spacer2" type="Control" parent="Import"] -custom_minimum_size = Vector2(0, 8) -layout_mode = 2 - -[node name="DialogFitter" parent="." instance=ExtResource("1")] -layout_mode = 3 -anchors_preset = 0 -offset_left = 8.0 -offset_top = 8.0 -offset_right = 644.0 -offset_bottom = 605.0 - -[connection signal="item_selected" from="Import/HS/VB/SlotsList" to="." method="_on_SlotsList_item_selected"] -[connection signal="pressed" from="Import/HS/VB/HB/AddSlotButton" to="." method="_on_AddSlotButton_pressed"] -[connection signal="pressed" from="Import/HS/VB/HB/RemoveSlotButton" to="." method="_on_RemoveSlotButton_pressed"] -[connection signal="toggled" from="Import/HS/VB2/HB/Normal/NormalMapFlipY" to="." method="_on_NormalMapFlipY_toggled"] -[connection signal="item_selected" from="Import/GC/ImportModeSelector" to="." method="_on_ImportModeSelector_item_selected"] -[connection signal="toggled" from="Import/GC/MipmapsCheckbox" to="." method="_on_MipmapsCheckbox_toggled"] -[connection signal="item_selected" from="Import/GC/CompressionSelector" to="." method="_on_CompressionSelector_item_selected"] -[connection signal="toggled" from="Import/GC/FilterCheckBox" to="." method="_on_FilterCheckBox_toggled"] -[connection signal="value_changed" from="Import/GC/ResolutionSpinBox" to="." method="_on_ResolutionSpinBox_value_changed"] -[connection signal="text_changed" from="Import/HB2/ImportDirectoryLineEdit" to="." method="_on_ImportDirectoryLineEdit_text_changed"] -[connection signal="pressed" from="Import/HB2/BrowseImportDirectory" to="." method="_on_BrowseImportDirectory_pressed"] -[connection signal="pressed" from="Import/HB/ImportButton" to="." method="_on_ImportButton_pressed"] -[connection signal="pressed" from="Import/HB/CancelButton" to="." method="_on_CancelButton_pressed"] - -[editable path="Import/HS/VB2/HB/Normal"] diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd b/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd deleted file mode 100644 index e3e337f..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd +++ /dev/null @@ -1,134 +0,0 @@ -@tool -extends Control - -const HTerrain = preload("../../hterrain.gd") -const HTerrainTextureSet = preload("../../hterrain_texture_set.gd") -const HT_TextureList = preload("./texture_list.gd") -const HT_Logger = preload("../../util/logger.gd") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -const EMPTY_ICON_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -signal texture_selected(index) -signal edit_pressed(index) -signal import_pressed - -@onready var _textures_list: HT_TextureList = $TextureList -@onready var _buttons_container : HBoxContainer = $HBoxContainer - -var _terrain : HTerrain = null -var _texture_set : HTerrainTextureSet = null - -var _texture_list_need_update := false -var _empty_icon : Texture2D - -var _logger = HT_Logger.get_for(self) - - -func _ready(): - _empty_icon = load(EMPTY_ICON_TEXTURE_PATH) - if _empty_icon == null: - _logger.error(str("Failed to load empty icon ", EMPTY_ICON_TEXTURE_PATH)) - - # Default amount, will be updated when a terrain is assigned - _textures_list.clear() - for i in range(4): - _textures_list.add_item(str(i), _empty_icon) - - -func set_terrain(terrain: HTerrain): - _terrain = terrain - - -static func _get_slot_count(terrain: HTerrain) -> int: - var texture_set = terrain.get_texture_set() - if texture_set == null: - return 0 - return texture_set.get_slots_count() - - -func _process(delta: float): - var texture_set = null - if _terrain != null: - texture_set = _terrain.get_texture_set() - - if _texture_set != texture_set: - if _texture_set != null: - _texture_set.changed.disconnect(_on_texture_set_changed) - - _texture_set = texture_set - - if _texture_set != null: - _texture_set.changed.connect(_on_texture_set_changed) - - _update_texture_list() - - if _texture_list_need_update: - _update_texture_list() - _texture_list_need_update = false - - -func _on_texture_set_changed(): - _texture_list_need_update = true - - -func _update_texture_list(): - _textures_list.clear() - - if _terrain == null: - _set_buttons_active(false) - return - var texture_set := _terrain.get_texture_set() - if texture_set == null: - _set_buttons_active(false) - return - _set_buttons_active(true) - - var slots_count := texture_set.get_slots_count() - - match texture_set.get_mode(): - HTerrainTextureSet.MODE_TEXTURES: - for slot_index in slots_count: - var texture := texture_set.get_texture( - slot_index, HTerrainTextureSet.TYPE_ALBEDO_BUMP) - var hint := _get_slot_hint_name(slot_index, _terrain.get_shader_type()) - if texture == null: - texture = _empty_icon - _textures_list.add_item(hint, texture) - - HTerrainTextureSet.MODE_TEXTURE_ARRAYS: - var texture_array = texture_set.get_texture_array(HTerrainTextureSet.TYPE_ALBEDO_BUMP) - for slot_index in slots_count: - var hint := _get_slot_hint_name(slot_index, _terrain.get_shader_type()) - _textures_list.add_item(hint, texture_array, slot_index) - - -func _set_buttons_active(active: bool): - for i in _buttons_container.get_child_count(): - var child = _buttons_container.get_child(i) - if child is Button: - child.disabled = not active - - -static func _get_slot_hint_name(i: int, stype: String) -> String: - if i == 3 and (stype == HTerrain.SHADER_CLASSIC4 or stype == HTerrain.SHADER_CLASSIC4_LITE): - return "cliff" - return str(i) - - -func _on_TextureList_item_selected(index: int): - texture_selected.emit(index) - - -func _on_TextureList_item_activated(index: int): - edit_pressed.emit(index) - - -func _on_EditButton_pressed(): - var selected_slot := _textures_list.get_selected_item() - if selected_slot == -1: - selected_slot = 0 - edit_pressed.emit(selected_slot) - - -func _on_ImportButton_pressed(): - import_pressed.emit() diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd.uid deleted file mode 100644 index 51ab07f..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://20l1dtghutrk diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn deleted file mode 100644 index 885f344..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_editor.tscn +++ /dev/null @@ -1,48 +0,0 @@ -[gd_scene load_steps=3 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_editor.gd" type="Script" id=1] -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_list.tscn" type="PackedScene" id=2] - -[node name="TextureEditor" type="Control"] -offset_right = 352.0 -offset_bottom = 104.0 -custom_minimum_size = Vector2( 100, 0 ) -size_flags_horizontal = 3 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="TextureList" parent="." instance=ExtResource( 2 )] -offset_bottom = -26.0 - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -anchor_top = 1.0 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_top = -24.0 -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="EditButton" type="Button" parent="HBoxContainer"] -offset_right = 48.0 -offset_bottom = 24.0 -text = "Edit..." - -[node name="ImportButton" type="Button" parent="HBoxContainer"] -offset_left = 52.0 -offset_right = 120.0 -offset_bottom = 24.0 -text = "Import..." - -[node name="Label" type="Label" parent="HBoxContainer"] -offset_left = 124.0 -offset_top = 5.0 -offset_right = 179.0 -offset_bottom = 19.0 -text = "Textures" -[connection signal="item_activated" from="TextureList" to="." method="_on_TextureList_item_activated"] -[connection signal="item_selected" from="TextureList" to="." method="_on_TextureList_item_selected"] -[connection signal="pressed" from="HBoxContainer/EditButton" to="." method="_on_EditButton_pressed"] -[connection signal="pressed" from="HBoxContainer/ImportButton" to="." method="_on_ImportButton_pressed"] diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd deleted file mode 100644 index 7391f85..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd +++ /dev/null @@ -1,79 +0,0 @@ - -# I needed a custom container for this because textures edited by this plugin are often -# unfit to display in a GUI, they need to go through a shader (either discarding alpha, -# or picking layers of a TextureArray). Unfortunately, ItemList does not have custom item drawing, -# and items cannot have individual shaders. -# I could create new textures just for that but it would be expensive. - -@tool -extends ScrollContainer - -const HT_TextureListItemScene = preload("./texture_list_item.tscn") -const HT_TextureListItem = preload("./texture_list_item.gd") - -signal item_selected(index) -signal item_activated(index) - -@onready var _container : Container = $Container - - -var _selected_item := -1 - - -# TEST -#func _ready(): -# add_item("First", load("res://addons/zylann.hterrain_demo/textures/ground/bricks_albedo_bump.png"), 0) -# add_item("Second", load("res://addons/zylann.hterrain_demo/textures/ground/grass_albedo_bump.png"), 0) -# add_item("Third", load("res://addons/zylann.hterrain_demo/textures/ground/leaves_albedo_bump.png"), 0) -# add_item("Fourth", load("res://addons/zylann.hterrain_demo/textures/ground/sand_albedo_bump.png"), 0) -# var texture_array = load("res://tests/texarray/textures/array_albedo_atlas.png") -# add_item("Ninth", texture_array, 2) -# add_item("Sixth", texture_array, 3) - - -# Note: the texture can be a TextureArray, which does not inherit Texture -func add_item(text: String, texture: Texture, texture_layer: int = 0): - var item : HT_TextureListItem = HT_TextureListItemScene.instantiate() - _container.add_child(item) - item.set_text(text) - item.set_texture(texture, texture_layer) - - -func get_item_count() -> int: - return _container.get_child_count() - - -func set_item_texture(index: int, tex: Texture, layer: int = 0): - var child : HT_TextureListItem = _container.get_child(index) - child.set_texture(tex, layer) - - -func get_selected_item() -> int: - return _selected_item - - -func clear(): - for i in _container.get_child_count(): - var child = _container.get_child(i) - if child is Control: - child.queue_free() - _selected_item = -1 - - -func _on_item_selected(item: HT_TextureListItem): - _selected_item = item.get_index() - for i in _container.get_child_count(): - var child = _container.get_child(i) - if child is HT_TextureListItem and child != item: - child.set_selected(false, false) - item_selected.emit(_selected_item) - - -func _on_item_activated(item: HT_TextureListItem): - item_activated.emit(item.get_index()) - - -func _draw(): - # TODO Draw same background as Panel - # Draw a background - draw_rect(get_rect(), Color(0,0,0,0.3)) diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd.uid deleted file mode 100644 index 3997a74..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bwc1sm4jbmdk6 diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn deleted file mode 100644 index df5e1e2..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list.tscn +++ /dev/null @@ -1,20 +0,0 @@ -[gd_scene load_steps=3 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/texture_list.gd" type="Script" id=1] -[ext_resource path="res://addons/zylann.hterrain/tools/texture_editor/flow_container.gd" type="Script" id=2] - -[node name="TextureList" type="ScrollContainer"] -anchor_right = 1.0 -anchor_bottom = 1.0 -scroll_horizontal_enabled = false -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} - -[node name="Container" type="Container" parent="."] -offset_right = 800.0 -offset_bottom = 82.0 -custom_minimum_size = Vector2( 0, 82 ) -size_flags_horizontal = 3 -script = ExtResource( 2 ) diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd deleted file mode 100644 index 098f349..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd +++ /dev/null @@ -1,72 +0,0 @@ -@tool -extends PanelContainer -# Had to use PanelContainer, because due to variable font sizes in the editor, -# the contents of the VBoxContainer can vary in size, and so in height. -# Which means the entire item can have variable size, not just because of DPI. -# In such cases, the hierarchy must be made of containers that grow based on their children. - -const HT_ColorMaterial = preload("./display_color_material.tres") -const HT_ColorSliceShader = preload("./display_color_slice.gdshader") -# TODO Can't preload because it causes the plugin to fail loading if assets aren't imported -#const HT_DummyTexture = preload("../icons/empty.png") -const DUMMY_TEXTURE_PATH = "res://addons/zylann.hterrain/tools/icons/empty.png" - -@onready var _texture_rect : TextureRect = $VB/TextureRect -@onready var _label : Label = $VB/Label - - -var _selected := false - - -func set_text(text: String): - _label.text = text - - -func set_texture(texture: Texture, texture_layer: int): - if texture is TextureLayered: - var mat = _texture_rect.material - if mat == null or not (mat is ShaderMaterial): - mat = ShaderMaterial.new() - mat.shader = HT_ColorSliceShader - _texture_rect.material = mat - mat.set_shader_parameter("u_texture_array", texture) - mat.set_shader_parameter("u_index", texture_layer) - _texture_rect.texture = load(DUMMY_TEXTURE_PATH) - else: - _texture_rect.texture = texture - _texture_rect.material = HT_ColorMaterial - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - grab_focus() - set_selected(true, true) - if event.double_click: - # Don't do this at home. - # I do it here because this script is very related to its container anyways. - get_parent().get_parent()._on_item_activated(self) - - -func set_selected(selected: bool, notify: bool): - if selected == _selected: - return - _selected = selected - queue_redraw() - if _selected: - _label.modulate = Color(0,0,0) - else: - _label.modulate = Color(1,1,1) - if notify: - get_parent().get_parent()._on_item_selected(self) - - -func _draw(): - var color : Color - if _selected: - color = get_theme_color("accent_color", "Editor") - else: - color = Color(0.0, 0.0, 0.0, 0.5) - # Draw background - draw_rect(Rect2(Vector2(), size), color) diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd.uid b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd.uid deleted file mode 100644 index 41c9e79..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dqh4bepsafiin diff --git a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn b/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn deleted file mode 100644 index 4340f55..0000000 --- a/godot/addons/zylann.hterrain/tools/texture_editor/texture_list_item.tscn +++ /dev/null @@ -1,25 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://daugk4kdnx6vy"] - -[ext_resource type="Script" path="res://addons/zylann.hterrain/tools/texture_editor/texture_list_item.gd" id="2"] - -[node name="TextureListItem" type="PanelContainer"] -custom_minimum_size = Vector2(64, 80) -offset_right = 64.0 -offset_bottom = 80.0 -focus_mode = 1 -script = ExtResource("2") - -[node name="VB" type="VBoxContainer" parent="."] -layout_mode = 2 -mouse_filter = 2 - -[node name="TextureRect" type="TextureRect" parent="VB"] -custom_minimum_size = Vector2(60, 60) -layout_mode = 2 -size_flags_vertical = 3 -mouse_filter = 2 -expand_mode = 1 - -[node name="Label" type="Label" parent="VB"] -layout_mode = 2 -text = "Texture" diff --git a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd b/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd deleted file mode 100644 index 59bb194..0000000 --- a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd +++ /dev/null @@ -1,53 +0,0 @@ - -# If you make a container-based UI inside a WindowDialog, there is a chance it will overflow -# because WindowDialogs don't adjust by themselves. This happens when the user has a different -# font size than yours, and can cause controls to be unusable (like buttons at the bottom). -# This script adjusts the size of the parent WindowDialog based on the first Container it finds -# when the node becomes visible. - -@tool -# Needs to be a Control, otherwise we don't receive the notification... -extends Control - -const HT_Util = preload("../../util/util.gd") - - -func _notification(what: int): - if HT_Util.is_in_edited_scene(self): - return - if is_inside_tree() and what == Control.NOTIFICATION_VISIBILITY_CHANGED: - #print("Visible ", is_visible_in_tree(), ", ", visible) - call_deferred("_fit_to_contents") - - -func _fit_to_contents(): - var dialog : Window = get_parent() - for child in dialog.get_children(): - if child is Container: - var child_rect : Rect2 = child.get_global_rect() - var dialog_rect := Rect2(Vector2(), dialog.size) - #print("Dialog: ", dialog_rect, ", contents: ", child_rect, " ", child.get_path()) - if not dialog_rect.encloses(child_rect): - var margin : Vector2 = child.get_rect().position - #print("Fitting ", dialog.get_path(), " from ", dialog.rect_size, - # " to ", child_rect.size + margin * 2.0) - dialog.min_size = child_rect.size + margin * 2.0 - - -#func _process(delta): -# update() - -# DEBUG -#func _draw(): -# var self_global_pos = get_global_rect().position -# -# var dialog : Control = get_parent() -# var dialog_rect := dialog.get_global_rect() -# dialog_rect.position -= self_global_pos -# draw_rect(dialog_rect, Color(1,1,0), false) -# -# for child in dialog.get_children(): -# if child is Container: -# var child_rect : Rect2 = child.get_global_rect() -# child_rect.position -= self_global_pos -# draw_rect(child_rect, Color(1,1,0,0.1)) diff --git a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd.uid b/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd.uid deleted file mode 100644 index ed94525..0000000 --- a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://baibrqn06a8in diff --git a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.tscn b/godot/addons/zylann.hterrain/tools/util/dialog_fitter.tscn deleted file mode 100644 index 2e3b00c..0000000 --- a/godot/addons/zylann.hterrain/tools/util/dialog_fitter.tscn +++ /dev/null @@ -1,10 +0,0 @@ -[gd_scene load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/util/dialog_fitter.gd" type="Script" id=1] - -[node name="DialogFitter" type="Control"] -mouse_filter = 2 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} diff --git a/godot/addons/zylann.hterrain/tools/util/editor_util.gd b/godot/addons/zylann.hterrain/tools/util/editor_util.gd deleted file mode 100644 index b77b5dc..0000000 --- a/godot/addons/zylann.hterrain/tools/util/editor_util.gd +++ /dev/null @@ -1,104 +0,0 @@ - -# Editor-specific utilities. -# This script cannot be loaded in an exported game. - -@tool - - -# This is normally an `EditorFileDialog`. I can't type-hint this one properly, -# because when I test UI in isolation, I can't use `EditorFileDialog`. -static func create_open_file_dialog() -> ConfirmationDialog: - var d - if Engine.is_editor_hint(): - # TODO Workaround bug when editor-only classes are created in source code, even if not run - # https://github.com/godotengine/godot/issues/73525 -# d = EditorFileDialog.new() - d = ClassDB.instantiate(&"EditorFileDialog") - d.file_mode = EditorFileDialog.FILE_MODE_OPEN_FILE - d.access = EditorFileDialog.ACCESS_RESOURCES - else: - d = FileDialog.new() - d.file_mode = FileDialog.FILE_MODE_OPEN_FILE - d.access = FileDialog.ACCESS_RESOURCES - d.unresizable = false - return d - - -static func create_open_dir_dialog() -> ConfirmationDialog: - var d - if Engine.is_editor_hint(): - # TODO Workaround bug when editor-only classes are created in source code, even if not run - # https://github.com/godotengine/godot/issues/73525 -# d = EditorFileDialog.new() - d = ClassDB.instantiate(&"EditorFileDialog") - d.file_mode = EditorFileDialog.FILE_MODE_OPEN_DIR - d.access = EditorFileDialog.ACCESS_RESOURCES - else: - d = FileDialog.new() - d.file_mode = FileDialog.FILE_MODE_OPEN_DIR - d.access = FileDialog.ACCESS_RESOURCES - d.unresizable = false - return d - - -# If you want to open using Image.load() -static func create_open_image_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_image_filters(d) - return d - - -# If you want to open using load(), -# although it might still fail if the file is imported as Image... -static func create_open_texture_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_texture_filters(d) - return d - - -static func create_open_texture_array_dialog() -> ConfirmationDialog: - var d = create_open_file_dialog() - _add_texture_array_filters(d) - return d - -# TODO Post a proposal, we need a file dialog filtering on resource types, not on file extensions! - -static func _add_image_filters(file_dialog): - file_dialog.add_filter("*.png ; PNG files") - file_dialog.add_filter("*.jpg ; JPG files") - #file_dialog.add_filter("*.exr ; EXR files") - - -static func _add_texture_filters(file_dialog): - _add_image_filters(file_dialog) - # Godot - file_dialog.add_filter("*.ctex ; CompressedTexture files") - # Packed textures - # file_dialog.add_filter("*.packed_tex ; HTerrainPackedTexture files") - - -static func _add_texture_array_filters(file_dialog): - _add_image_filters(file_dialog) - # Godot - file_dialog.add_filter("*.ctexarray ; TextureArray files") - # Packed textures - # file_dialog.add_filter("*.packed_texarr ; HTerrainPackedTextureArray files") - - -# Tries to load a texture with the ResourceLoader, and if it fails, attempts -# to load it manually as an ImageTexture -static func load_texture(path: String, logger) -> Texture: - var tex : Texture = load(path) - if tex != null: - return tex - # This can unfortunately happen when the editor didn't import assets yet. - # See https://github.com/godotengine/godot/issues/17483 - logger.error(str("Failed to load texture ", path, ", attempting to load manually")) - var im := Image.new() - var err = im.load(ProjectSettings.globalize_path(path)) - if err != OK: - logger.error(str("Failed to load image ", path)) - return null - var itex := ImageTexture.create_from_image(im) - return itex - diff --git a/godot/addons/zylann.hterrain/tools/util/editor_util.gd.uid b/godot/addons/zylann.hterrain/tools/util/editor_util.gd.uid deleted file mode 100644 index 338f48f..0000000 --- a/godot/addons/zylann.hterrain/tools/util/editor_util.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://drri8ww1msxy8 diff --git a/godot/addons/zylann.hterrain/tools/util/interval_slider.gd b/godot/addons/zylann.hterrain/tools/util/interval_slider.gd deleted file mode 100644 index 481d08b..0000000 --- a/godot/addons/zylann.hterrain/tools/util/interval_slider.gd +++ /dev/null @@ -1,197 +0,0 @@ - -# Slider with two handles representing an interval. - -@tool -extends Control - -const VALUE_LOW = 0 -const VALUE_HIGH = 1 -const VALUE_COUNT = 2 - -const FG_MARGIN = 1 - -signal changed - -var _min_value := 0.0 -var _max_value := 1.0 -var _values = [0.2, 0.6] -var _grabbing := false - - -func _get_property_list(): - return [ - { - "name": "min_value", - "type": TYPE_FLOAT, - "usage": PROPERTY_USAGE_EDITOR - }, - { - "name": "max_value", - "type": TYPE_FLOAT, - "usage": PROPERTY_USAGE_EDITOR - }, - { - "name": "range", - "type": TYPE_VECTOR2, - "usage": PROPERTY_USAGE_STORAGE - } - ] - - -func _get(key: StringName): - match key: - &"min_value": - return _min_value - &"max_value": - return _max_value - &"range": - return Vector2(_min_value, _max_value) - - -func _set(key: StringName, value): - match key: - &"min_value": - _min_value = min(value, _max_value) - queue_redraw() - &"max_value": - _max_value = max(value, _min_value) - queue_redraw() - &"range": - _min_value = value.x - _max_value = value.y - - -func set_values(low: float, high: float): - if low > high: - low = high - if high < low: - high = low - _values[VALUE_LOW] = low - _values[VALUE_HIGH] = high - queue_redraw() - - -func set_value(i: int, v: float, notify_change: bool): - var min_value = _min_value - var max_value = _max_value - - match i: - VALUE_LOW: - max_value = _values[VALUE_HIGH] - VALUE_HIGH: - min_value = _values[VALUE_LOW] - _: - assert(false) - - v = clampf(v, min_value, max_value) - if v != _values[i]: - _values[i] = v - queue_redraw() - if notify_change: - changed.emit() - - -func get_value(i: int) -> float: - return _values[i] - - -func get_low_value() -> float: - return _values[VALUE_LOW] - - -func get_high_value() -> float: - return _values[VALUE_HIGH] - - -func get_ratio(i: int) -> float: - return _value_to_ratio(_values[i]) - - -func get_low_ratio() -> float: - return get_ratio(VALUE_LOW) - - -func get_high_ratio() -> float: - return get_ratio(VALUE_HIGH) - - -func _ratio_to_value(r: float) -> float: - return r * (_max_value - _min_value) + _min_value - - -func _value_to_ratio(v: float) -> float: - if absf(_max_value - _min_value) < 0.001: - return 0.0 - return (v - _min_value) / (_max_value - _min_value) - - -func _get_closest_index(ratio: float) -> int: - var distance_low := absf(ratio - get_low_ratio()) - var distance_high := absf(ratio - get_high_ratio()) - if distance_low < distance_high: - return VALUE_LOW - return VALUE_HIGH - - -func _set_from_pixel(px: float): - var r := (px - FG_MARGIN) / (size.x - FG_MARGIN * 2.0) - var i := _get_closest_index(r) - var v := _ratio_to_value(r) - set_value(i, v, true) - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - _grabbing = true - _set_from_pixel(event.position.x) - else: - if event.button_index == MOUSE_BUTTON_LEFT: - _grabbing = false - - elif event is InputEventMouseMotion: - if _grabbing: - _set_from_pixel(event.position.x) - - -func _draw(): - var grabber_width := 3 - var background_v_margin := 0 - var foreground_margin := FG_MARGIN - var grabber_color := Color(0.8, 0.8, 0.8) - var interval_color := Color(0.4,0.4,0.4) - var background_color := Color(0.1, 0.1, 0.1) - - var control_rect := Rect2(Vector2(), size) - - var bg_rect := Rect2( - control_rect.position.x, - control_rect.position.y + background_v_margin, - control_rect.size.x, - control_rect.size.y - 2 * background_v_margin) - draw_rect(bg_rect, background_color) - - var fg_rect := control_rect.grow(-foreground_margin) - - var low_ratio := get_low_ratio() - var high_ratio := get_high_ratio() - - var low_x := fg_rect.position.x + low_ratio * fg_rect.size.x - var high_x := fg_rect.position.x + high_ratio * fg_rect.size.x - - var interval_rect := Rect2( - low_x, fg_rect.position.y, high_x - low_x, fg_rect.size.y) - draw_rect(interval_rect, interval_color) - - low_x = fg_rect.position.x + low_ratio * (fg_rect.size.x - grabber_width) - high_x = fg_rect.position.x + high_ratio * (fg_rect.size.x - grabber_width) - - for x in [low_x, high_x]: - var grabber_rect := Rect2( - x, - fg_rect.position.y, - grabber_width, - fg_rect.size.y) - draw_rect(grabber_rect, grabber_color) - diff --git a/godot/addons/zylann.hterrain/tools/util/interval_slider.gd.uid b/godot/addons/zylann.hterrain/tools/util/interval_slider.gd.uid deleted file mode 100644 index 37fe657..0000000 --- a/godot/addons/zylann.hterrain/tools/util/interval_slider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cv6uulnsachc0 diff --git a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd b/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd deleted file mode 100644 index b24f0e2..0000000 --- a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd +++ /dev/null @@ -1,19 +0,0 @@ -@tool - -# Stuff not exposed by Godot for making .import files - -const COMPRESS_LOSSLESS = 0 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM_COMPRESSED = 2 -const COMPRESS_VRAM_UNCOMPRESSED = 3 -const COMPRESS_BASIS_UNIVERSAL = 4 - -const ROUGHNESS_DETECT = 0 -const ROUGHNESS_DISABLED = 1 -# Godot internally subtracts 2 to magically obtain a `Image.RoughnessChannel` enum -# (also not exposed) -const ROUGHNESS_RED = 2 -const ROUGHNESS_GREEN = 3 -const ROUGHNESS_BLUE = 4 -const ROUGHNESS_ALPHA = 5 -const ROUGHNESS_GRAY = 6 diff --git a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd.uid b/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd.uid deleted file mode 100644 index c70f41b..0000000 --- a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://caclak85pejtl diff --git a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd b/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd deleted file mode 100644 index ff77b1a..0000000 --- a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd +++ /dev/null @@ -1,9 +0,0 @@ -@tool - -# Stuff not exposed by Godot for making .import files - -const COMPRESS_LOSSLESS = 0 -const COMPRESS_LOSSY = 1 -const COMPRESS_VRAM_COMPRESSED = 2 -const COMPRESS_VRAM_UNCOMPRESSED = 3 -const COMPRESS_BASIS_UNIVERSAL = 4 diff --git a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd.uid b/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd.uid deleted file mode 100644 index 258dba3..0000000 --- a/godot/addons/zylann.hterrain/tools/util/resource_importer_texture_layered.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dtrmccku5d4rj diff --git a/godot/addons/zylann.hterrain/tools/util/result.gd b/godot/addons/zylann.hterrain/tools/util/result.gd deleted file mode 100644 index 5e897f1..0000000 --- a/godot/addons/zylann.hterrain/tools/util/result.gd +++ /dev/null @@ -1,36 +0,0 @@ -# Data structure to hold the result of a function that can be expected to fail. -# The use case is to report errors back to the GUI and act accordingly, -# instead of forgetting them to the console or having the script break on an assertion. -# This is a C-like way of things, where the result can bubble, and does not require globals. - -@tool - -# Replace `success` with `error : int`? -var success := false -var value = null -var message := "" -var inner_result = null - - -func _init(p_success: bool, p_message := "", p_inner = null): - success = p_success - message = p_message - inner_result = p_inner - - -# TODO Can't type-hint self return -func with_value(v): - value = v - return self - - -func get_message() -> String: - var msg := message - if inner_result != null: - msg += "\n" - msg += inner_result.get_message() - return msg - - -func is_ok() -> bool: - return success diff --git a/godot/addons/zylann.hterrain/tools/util/result.gd.uid b/godot/addons/zylann.hterrain/tools/util/result.gd.uid deleted file mode 100644 index 06e6888..0000000 --- a/godot/addons/zylann.hterrain/tools/util/result.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dyo8ajxidcicn diff --git a/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd b/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd deleted file mode 100644 index 242fe6e..0000000 --- a/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd +++ /dev/null @@ -1,11 +0,0 @@ -@tool -extends RichTextLabel - - -func _init(): - meta_clicked.connect(_on_meta_clicked) - - -func _on_meta_clicked(meta): - OS.shell_open(meta) - diff --git a/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd.uid b/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd.uid deleted file mode 100644 index f081523..0000000 --- a/godot/addons/zylann.hterrain/tools/util/rich_text_label_hyperlinks.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b4lrgbrxu3n3b diff --git a/godot/addons/zylann.hterrain/tools/util/spin_slider.gd b/godot/addons/zylann.hterrain/tools/util/spin_slider.gd deleted file mode 100644 index fa690d5..0000000 --- a/godot/addons/zylann.hterrain/tools/util/spin_slider.gd +++ /dev/null @@ -1,385 +0,0 @@ -@tool -extends Control - -const FG_MARGIN = 2 -const MAX_DECIMALS_VISUAL = 3 - -signal value_changed(value) - - -var _value := 0.0 -@export var value: float: - get: - return _value - set(v): - set_value_no_notify(v) - - -var _min_value := 0.0 -@export var min_value: float: - get: - return _min_value - set(v): - set_min_value(v) - - -var _max_value := 100.0 -@export var max_value: float: - get: - return _max_value - set(v): - set_max_value(v) - - -var _prefix := "" -@export var prefix: String: - get: - return _prefix - set(v): - set_prefix(v) - - -var _suffix := "" -@export var suffix: String: - get: - return _suffix - set(v): - set_suffix(v) - - -var _rounded := false -@export var rounded: bool: - get: - return _rounded - set(v): - set_rounded(v) - - -var _centered := true -@export var centered: bool: - get: - return _centered - set(v): - set_centered(v) - - -var _allow_greater := false -@export var allow_greater: bool: - get: - return _allow_greater - set(v): - set_allow_greater(v) - - -# There is still a limit when typing a larger value, but this one is to prevent software -# crashes or freezes. The regular min and max values are for slider UX. Exceeding it should be -# a corner case. -var _greater_max_value := 10000.0 -@export var greater_max_value: float: - get: - return _greater_max_value - set(v): - set_greater_max_value(v) - - -var _label : Label -var _label2 : Label -var _line_edit : LineEdit -var _ignore_line_edit := false -var _pressing := false -var _grabbing := false -var _press_pos := Vector2() - - -func _init(): - custom_minimum_size = Vector2(32, 28) - - _label = Label.new() - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - _label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _label.clip_text = true - #_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - _label.anchor_top = 0 - _label.anchor_left = 0 - _label.anchor_right = 1 - _label.anchor_bottom = 1 - _label.mouse_filter = Control.MOUSE_FILTER_IGNORE - _label.add_theme_color_override("font_color_shadow", Color(0,0,0,0.5)) - _label.add_theme_constant_override("shadow_offset_x", 1) - _label.add_theme_constant_override("shadow_offset_y", 1) - add_child(_label) - - _label2 = Label.new() - _label2.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT - _label2.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _label2.clip_text = true - #_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL - _label2.anchor_top = 0 - _label2.anchor_left = 0 - _label2.anchor_right = 1 - _label2.anchor_bottom = 1 - _label2.offset_left = 8 - _label2.mouse_filter = Control.MOUSE_FILTER_IGNORE - _label2.add_theme_color_override("font_color_shadow", Color(0,0,0,0.5)) - _label2.add_theme_constant_override("shadow_offset_x", 1) - _label2.add_theme_constant_override("shadow_offset_y", 1) - _label2.hide() - add_child(_label2) - - _line_edit = LineEdit.new() - _line_edit.alignment = HORIZONTAL_ALIGNMENT_CENTER - _line_edit.anchor_top = 0 - _line_edit.anchor_left = 0 - _line_edit.anchor_right = 1 - _line_edit.anchor_bottom = 1 - _line_edit.gui_input.connect(_on_LineEdit_gui_input) - _line_edit.focus_exited.connect(_on_LineEdit_focus_exited) - _line_edit.text_submitted.connect(_on_LineEdit_text_submitted) - _line_edit.hide() - add_child(_line_edit) - - mouse_default_cursor_shape = Control.CURSOR_HSIZE - - -func _ready(): - pass # Replace with function body. - - -func set_centered(p_centered: bool): - _centered = p_centered - if _centered: - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER - _label.offset_right = 0 - _label2.hide() - else: - _label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - _label.offset_right = -8 - _label2.show() - queue_redraw() - - -func is_centered() -> bool: - return _centered - - -func set_value_no_notify(v: float): - set_value(v, false, false) - - -func set_value(v: float, notify_change: bool, use_slider_maximum: bool = false): - if _allow_greater and not use_slider_maximum: - v = clampf(v, _min_value, _greater_max_value) - else: - v = clampf(v, _min_value, _max_value) - - if v != _value: - _value = v - - queue_redraw() - - if notify_change: - value_changed.emit(get_value()) - - -func get_value(): - if _rounded: - return int(roundf(_value)) - return _value - - -func set_min_value(minv: float): - _min_value = minv - #queue_redraw() - - -func get_min_value() -> float: - return _min_value - - -func set_max_value(maxv: float): - _max_value = maxv - #queue_redraw() - - -func get_max_value() -> float: - return _max_value - - -func set_greater_max_value(gmax: float): - _greater_max_value = gmax - - -func get_greater_max_value() -> float: - return _greater_max_value - - -func set_rounded(b: bool): - _rounded = b - queue_redraw() - - -func is_rounded() -> bool: - return _rounded - - -func set_prefix(p_prefix: String): - _prefix = p_prefix - queue_redraw() - - -func get_prefix() -> String: - return _prefix - - -func set_suffix(p_suffix: String): - _suffix = p_suffix - queue_redraw() - - -func get_suffix() -> String: - return _suffix - - -func set_allow_greater(allow: bool): - _allow_greater = allow - - -func is_allowing_greater() -> bool: - return _allow_greater - - -func _set_from_pixel(px: float): - var r := (px - FG_MARGIN) / (size.x - FG_MARGIN * 2.0) - var v := _ratio_to_value(r) - set_value(v, true, true) - - -func get_ratio() -> float: - return _value_to_ratio(get_value()) - - -func _ratio_to_value(r: float) -> float: - return r * (_max_value - _min_value) + _min_value - - -func _value_to_ratio(v: float) -> float: - if absf(_max_value - _min_value) < 0.001: - return 0.0 - return (v - _min_value) / (_max_value - _min_value) - - -func _on_LineEdit_gui_input(event: InputEvent): - if event is InputEventKey: - if event.pressed: - if event.keycode == KEY_ESCAPE: - _ignore_line_edit = true - _hide_line_edit() - grab_focus() - _ignore_line_edit = false - - -func _on_LineEdit_focus_exited(): - if _ignore_line_edit: - return - _enter_text() - - -func _on_LineEdit_text_submitted(text: String): - _enter_text() - - -func _enter_text(): - var s = _line_edit.text.strip_edges() - if s.is_valid_float(): - var v := s.to_float() - if not _allow_greater: - v = minf(v, _max_value) - set_value(v, true, false) - _hide_line_edit() - - -func _hide_line_edit(): - _line_edit.hide() - _label.show() - queue_redraw() - - -func _show_line_edit(): - _line_edit.show() - _line_edit.text = str(get_value()) - _line_edit.select_all() - _line_edit.grab_focus() - _label.hide() - queue_redraw() - - -func _gui_input(event: InputEvent): - if event is InputEventMouseButton: - if event.pressed: - if event.button_index == MOUSE_BUTTON_LEFT: - _press_pos = event.position - _pressing = true - else: - if event.button_index == MOUSE_BUTTON_LEFT: - _pressing = false - if _grabbing: - _grabbing = false - _set_from_pixel(event.position.x) - else: - _show_line_edit() - - elif event is InputEventMouseMotion: - if _pressing and _press_pos.distance_to(event.position) > 2.0: - _grabbing = true - if _grabbing: - _set_from_pixel(event.position.x) - - -func _draw(): - if _line_edit.visible: - return - - #var grabber_width := 3 - var background_v_margin := 0 - var foreground_margin := FG_MARGIN - #var grabber_color := Color(0.8, 0.8, 0.8) - var interval_color := Color(0.4,0.4,0.4) - var background_color := Color(0.1, 0.1, 0.1) - - var control_rect := Rect2(Vector2(), size) - - var bg_rect := Rect2( - control_rect.position.x, - control_rect.position.y + background_v_margin, - control_rect.size.x, - control_rect.size.y - 2 * background_v_margin) - draw_rect(bg_rect, background_color) - - var fg_rect := control_rect.grow(-foreground_margin) - # Clamping the ratio because the value can be allowed to exceed the slider's boundaries - var ratio := clampf(get_ratio(), 0.0, 1.0) - fg_rect.size.x *= ratio - draw_rect(fg_rect, interval_color) - - var value_text := str(get_value()) - - var dot_pos := value_text.find(".") - if dot_pos != -1: - var decimal_count := len(value_text) - dot_pos - if decimal_count > MAX_DECIMALS_VISUAL: - value_text = value_text.substr(0, dot_pos + MAX_DECIMALS_VISUAL + 1) - - if _centered: - var text := value_text - if _prefix != "": - text = str(_prefix, " ", text) - if _suffix != "": - text = str(text, " ", _suffix) - _label.text = text - - else: - _label2.text = _prefix - var text := value_text - if _suffix != "": - text = str(text, " ", _suffix) - _label.text = text diff --git a/godot/addons/zylann.hterrain/tools/util/spin_slider.gd.uid b/godot/addons/zylann.hterrain/tools/util/spin_slider.gd.uid deleted file mode 100644 index 0e3ab91..0000000 --- a/godot/addons/zylann.hterrain/tools/util/spin_slider.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dww32qcqrw63k diff --git a/godot/addons/zylann.hterrain/tools/util/spin_slider.tscn b/godot/addons/zylann.hterrain/tools/util/spin_slider.tscn deleted file mode 100644 index 70a0da8..0000000 --- a/godot/addons/zylann.hterrain/tools/util/spin_slider.tscn +++ /dev/null @@ -1,13 +0,0 @@ -[gd_scene load_steps=2 format=2] - -[ext_resource path="res://addons/zylann.hterrain/tools/util/spin_slider.gd" type="Script" id=1] - -[node name="SpinSlider" type="Control"] -anchor_right = 1.0 -anchor_bottom = 1.0 -rect_min_size = Vector2( 32, 28 ) -mouse_default_cursor_shape = 10 -script = ExtResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} diff --git a/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd b/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd deleted file mode 100644 index 17c89c9..0000000 --- a/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd +++ /dev/null @@ -1,65 +0,0 @@ -@tool - -# Implementation of MeshInstance which doesn't use the scene tree - -var _mesh_instance := RID() -# Need to keep a reference so that the mesh RID doesn't get freed -var _mesh : Mesh - - -func _init(): - var rs = RenderingServer - _mesh_instance = rs.instance_create() - rs.instance_set_visible(_mesh_instance, true) - - -func _notification(p_what: int): - if p_what == NOTIFICATION_PREDELETE: - if _mesh_instance != RID(): - RenderingServer.free_rid(_mesh_instance) - _mesh_instance = RID() - - -func enter_world(world: World3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, world.get_scenario()) - - -func exit_world(): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_scenario(_mesh_instance, RID()) - - -func set_world(world: World3D): - if world != null: - enter_world(world) - else: - exit_world() - - -func set_transform(world_transform: Transform3D): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_transform(_mesh_instance, world_transform) - - -func set_mesh(mesh: Mesh): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_base(_mesh_instance, mesh.get_rid() if mesh != null else RID()) - _mesh = mesh - - -func set_material(material: Material): - assert(_mesh_instance != RID()) - RenderingServer.instance_geometry_set_material_override( \ - _mesh_instance, material.get_rid() if material != null else RID()) - - -func set_visible(visible: bool): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_visible(_mesh_instance, visible) - - -func set_aabb(aabb: AABB): - assert(_mesh_instance != RID()) - RenderingServer.instance_set_custom_aabb(_mesh_instance, aabb) - diff --git a/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd.uid b/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd.uid deleted file mode 100644 index 0c85745..0000000 --- a/godot/addons/zylann.hterrain/util/direct_mesh_instance.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://6kljt18npflv diff --git a/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd b/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd deleted file mode 100644 index dbb899b..0000000 --- a/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd +++ /dev/null @@ -1,48 +0,0 @@ -@tool - -# Implementation of MultiMeshInstance which doesn't use the scene tree - -var _multimesh_instance := RID() - - -func _init(): - _multimesh_instance = RenderingServer.instance_create() - - -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - RenderingServer.free_rid(_multimesh_instance) - - -func set_world(world: World3D): - RenderingServer.instance_set_scenario( - _multimesh_instance, world.get_scenario() if world != null else RID()) - - -func set_visible(visible: bool): - RenderingServer.instance_set_visible(_multimesh_instance, visible) - - -func set_transform(trans: Transform3D): - RenderingServer.instance_set_transform(_multimesh_instance, trans) - - -func set_multimesh(mm: MultiMesh): - RenderingServer.instance_set_base(_multimesh_instance, mm.get_rid() if mm != null else RID()) - - -func set_material_override(material: Material): - RenderingServer.instance_geometry_set_material_override( \ - _multimesh_instance, material.get_rid() if material != null else RID()) - - -func set_aabb(aabb: AABB): - RenderingServer.instance_set_custom_aabb(_multimesh_instance, aabb) - - -func set_layer_mask(mask: int): - RenderingServer.instance_set_layer_mask(_multimesh_instance, mask) - - -func set_cast_shadow(cast_shadow: int): - RenderingServer.instance_geometry_set_cast_shadows_setting(_multimesh_instance, cast_shadow) diff --git a/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd.uid b/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd.uid deleted file mode 100644 index 84b3146..0000000 --- a/godot/addons/zylann.hterrain/util/direct_multimesh_instance.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://lo4e4jjt67f7 diff --git a/godot/addons/zylann.hterrain/util/errors.gd b/godot/addons/zylann.hterrain/util/errors.gd deleted file mode 100644 index c6a2c63..0000000 --- a/godot/addons/zylann.hterrain/util/errors.gd +++ /dev/null @@ -1,58 +0,0 @@ -@tool - -# Taken from https://docs.godotengine.org/en/3.0/classes/class_@globalscope.html#enum-globalscope-error -const _names = { - OK: "ok", - FAILED: "Generic error.", - ERR_UNAVAILABLE: "Unavailable error", - ERR_UNCONFIGURED: "Unconfigured error", - ERR_UNAUTHORIZED: "Unauthorized error", - ERR_PARAMETER_RANGE_ERROR: "Parameter range error", - ERR_OUT_OF_MEMORY: "Out of memory (OOM) error", - ERR_FILE_NOT_FOUND: "File Not found error", - ERR_FILE_BAD_DRIVE: "File Bad drive error", - ERR_FILE_BAD_PATH: "File Bad path error", - ERR_FILE_NO_PERMISSION: "File No permission error", - ERR_FILE_ALREADY_IN_USE: "File Already in use error", - ERR_FILE_CANT_OPEN: "File Can't open error", - ERR_FILE_CANT_WRITE: "File Can't write error", - ERR_FILE_CANT_READ: "File Can't read error", - ERR_FILE_UNRECOGNIZED: "File Unrecognized error", - ERR_FILE_CORRUPT: "File Corrupt error", - ERR_FILE_MISSING_DEPENDENCIES: "File Missing dependencies error", - ERR_FILE_EOF: "File End of file (EOF) error", - ERR_CANT_OPEN: "Can't open error", - ERR_CANT_CREATE: "Can't create error", - ERR_QUERY_FAILED: "Query failed error", - ERR_ALREADY_IN_USE: "Already in use error", - ERR_LOCKED: "Locked error", - ERR_TIMEOUT: "Timeout error", - ERR_CANT_CONNECT: "Can't connect", - ERR_CANT_RESOLVE: "Can't resolve", - ERR_CONNECTION_ERROR: "Connection error", - ERR_CANT_ACQUIRE_RESOURCE: "Can't acquire resource error", - ERR_CANT_FORK: "Can't fork", - ERR_INVALID_DATA: "Invalid data error", - ERR_INVALID_PARAMETER: "Invalid parameter error", - ERR_ALREADY_EXISTS: "Already exists error", - ERR_DOES_NOT_EXIST: "Does not exist error", - ERR_DATABASE_CANT_READ: "Database Read error", - ERR_DATABASE_CANT_WRITE: "Database Write error", - ERR_COMPILATION_FAILED: "Compilation failed error", - ERR_METHOD_NOT_FOUND: "Method not found error", - ERR_LINK_FAILED: "Linking failed error", - ERR_SCRIPT_FAILED: "Script failed error", - ERR_CYCLIC_LINK: "Cycling link (import cycle) error", - ERR_INVALID_DECLARATION: "Invalid declaration", - ERR_DUPLICATE_SYMBOL: "Duplicate symbol", - ERR_PARSE_ERROR: "Parse error", - ERR_BUSY: "Busy error", - ERR_SKIP: "Skip error", - ERR_HELP: "Help error", - ERR_BUG: "Bug error", - ERR_PRINTER_ON_FIRE: "The printer is on fire" -} - -static func get_message(err_code: int): - return str("[", err_code, "]: ", _names[err_code]) - diff --git a/godot/addons/zylann.hterrain/util/errors.gd.uid b/godot/addons/zylann.hterrain/util/errors.gd.uid deleted file mode 100644 index 1440fca..0000000 --- a/godot/addons/zylann.hterrain/util/errors.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b00usyemqhe76 diff --git a/godot/addons/zylann.hterrain/util/grid.gd b/godot/addons/zylann.hterrain/util/grid.gd deleted file mode 100644 index b28e83b..0000000 --- a/godot/addons/zylann.hterrain/util/grid.gd +++ /dev/null @@ -1,203 +0,0 @@ - -# Note: `tool` is optional but without it there are no error reporting in the editor -@tool - -# TODO Remove grid_ prefixes, context is already given by the script itself - - -# Performs a positive integer division rounded to upper (4/2 = 2, 5/3 = 2) -static func up_div(a: int, b: int): - if a % b != 0: - return a / b + 1 - return a / b - - -# Creates a 2D array as an array of arrays. -# if v is provided, all cells will contain the same value. -# if v is a funcref, it will be executed to fill the grid cell per cell. -static func create_grid(w: int, h: int, v=null): - var is_create_func = typeof(v) == TYPE_CALLABLE - var grid := [] - grid.resize(h) - for y in range(grid.size()): - var row := [] - row.resize(w) - if is_create_func: - for x in range(row.size()): - row[x] = v.call(x, y) - else: - for x in range(row.size()): - row[x] = v - grid[y] = row - return grid - - -# Creates a 2D array that is a copy of another 2D array -static func clone_grid(other_grid): - var grid := [] - grid.resize(other_grid.size()) - for y in range(0, grid.size()): - var row := [] - var other_row = other_grid[y] - row.resize(other_row.size()) - grid[y] = row - for x in range(0, row.size()): - row[x] = other_row[x] - return grid - - -# Resizes a 2D array and allows to set or call functions for each deleted and created cells. -# This is especially useful if cells contain objects and you don't want to loose existing data. -static func resize_grid(grid, new_width, new_height, create_func=null, delete_func=null): - # Check parameters - assert(new_width >= 0 and new_height >= 0) - assert(grid != null) - if delete_func != null: - assert(typeof(delete_func) == TYPE_CALLABLE) - # `create_func` can also be a default value - var is_create_func = typeof(create_func) == TYPE_CALLABLE - - # Get old size (supposed to be rectangular!) - var old_height = grid.size() - var old_width = 0 - if grid.size() != 0: - old_width = grid[0].size() - - # Delete old rows - if new_height < old_height: - if delete_func != null: - for y in range(new_height, grid.size()): - var row = grid[y] - for x in len(row): - var elem = row[x] - delete_func.call(elem) - grid.resize(new_height) - - # Delete old columns - if new_width < old_width: - for y in len(grid): - var row = grid[y] - if delete_func != null: - for x in range(new_width, row.size()): - var elem = row[x] - delete_func.call(elem) - row.resize(new_width) - - # Create new columns - if new_width > old_width: - for y in len(grid): - var row = grid[y] - row.resize(new_width) - if is_create_func: - for x in range(old_width, new_width): - row[x] = create_func.call(x,y) - else: - for x in range(old_width, new_width): - row[x] = create_func - - # Create new rows - if new_height > old_height: - grid.resize(new_height) - for y in range(old_height, new_height): - var row = [] - row.resize(new_width) - grid[y] = row - if is_create_func: - for x in new_width: - row[x] = create_func.call(x,y) - else: - for x in new_width: - row[x] = create_func - - # Debug test check - assert(grid.size() == new_height) - for y in len(grid): - assert(len(grid[y]) == new_width) - - -# Retrieves the minimum and maximum values from a grid -static func grid_min_max(grid): - if grid.size() == 0 or grid[0].size() == 0: - return [0,0] - var vmin = grid[0][0] - var vmax = vmin - for y in len(grid): - var row = grid[y] - for x in len(row): - var v = row[x] - if v > vmax: - vmax = v - elif v < vmin: - vmin = v - return [vmin, vmax] - - -# Copies a sub-region of a grid as a new grid. No boundary check! -static func grid_extract_area(src_grid, x0, y0, w, h): - var dst = create_grid(w, h) - for y in h: - var dst_row = dst[y] - var src_row = src_grid[y0+y] - for x in w: - dst_row[x] = src_row[x0+x] - return dst - - -# Extracts data and crops the result if the requested rect crosses the bounds -static func grid_extract_area_safe_crop(src_grid, x0, y0, w, h): - # Return empty is completely out of bounds - var gw = src_grid.size() - if gw == 0: - return [] - var gh = src_grid[0].size() - if x0 >= gw or y0 >= gh: - return [] - - # Crop min pos - if x0 < 0: - w += x0 - x0 = 0 - if y0 < 0: - h += y0 - y0 = 0 - - # Crop max pos - if x0 + w >= gw: - w = gw-x0 - if y0 + h >= gh: - h = gh-y0 - - return grid_extract_area(src_grid, x0, y0, w, h) - - -# Sets values from a grid inside another grid. No boundary check! -static func grid_paste(src_grid, dst_grid, x0, y0): - for y in range(0, src_grid.size()): - var src_row = src_grid[y] - var dst_row = dst_grid[y0+y] - for x in range(0, src_row.size()): - dst_row[x0+x] = src_row[x] - - -# Tests if two grids are the same size and contain the same values -static func grid_equals(a, b): - if a.size() != b.size(): - return false - for y in a.size(): - var a_row = a[y] - var b_row = b[y] - if a_row.size() != b_row.size(): - return false - for x in b_row.size(): - if a_row[x] != b_row[x]: - return false - return true - - -static func grid_get_or_default(grid, x, y, defval=null): - if y >= 0 and y < len(grid): - var row = grid[y] - if x >= 0 and x < len(row): - return row[x] - return defval - diff --git a/godot/addons/zylann.hterrain/util/grid.gd.uid b/godot/addons/zylann.hterrain/util/grid.gd.uid deleted file mode 100644 index 5acc2ca..0000000 --- a/godot/addons/zylann.hterrain/util/grid.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bgj37mvgl47gv diff --git a/godot/addons/zylann.hterrain/util/image_file_cache.gd b/godot/addons/zylann.hterrain/util/image_file_cache.gd deleted file mode 100644 index e39e4cd..0000000 --- a/godot/addons/zylann.hterrain/util/image_file_cache.gd +++ /dev/null @@ -1,291 +0,0 @@ -@tool - -# Used to store temporary images on disk. -# This is useful for undo/redo as image edition can quickly fill up memory. - -# Image data is stored in archive files together, -# because when dealing with many images it speeds up filesystem I/O on Windows. -# If the file exceeds a predefined size, a new one is created. -# Writing to disk is performed from a thread, to leave the main thread responsive. -# However if you want to obtain an image back while it didn't save yet, the main thread will block. -# When the application or plugin is closed, the files get cleared. - -const HT_Logger = preload("./logger.gd") -const HT_Errors = preload("./errors.gd") - -const CACHE_FILE_SIZE_THRESHOLD = 1048576 -# For debugging -const USE_THREAD = true - -var _cache_dir := "" -var _next_id := 0 -var _session_id := "" -var _cache_image_info := {} -var _logger = HT_Logger.get_for(self) -var _current_cache_file_index := 0 -var _cache_file_offset := 0 - -var _saving_thread := Thread.new() -var _save_queue := [] -var _save_queue_mutex := Mutex.new() -var _save_semaphore := Semaphore.new() -var _save_thread_running := false - - -func _init(cache_dir: String): - assert(cache_dir != "") - _cache_dir = cache_dir - var rng := RandomNumberGenerator.new() - rng.randomize() - for i in 16: - _session_id += str(rng.randi() % 10) - _logger.debug(str("Image cache session ID: ", _session_id)) - if not DirAccess.dir_exists_absolute(_cache_dir): - var err := DirAccess.make_dir_absolute(_cache_dir) - if err != OK: - _logger.error("Could not create directory {0}: {1}" \ - .format([_cache_dir, HT_Errors.get_message(err)])) - _save_thread_running = true - if USE_THREAD: - _saving_thread.start(_save_thread_func) - - -# TODO Cannot cleanup the cache in destructor! -# Godot doesn't allow me to call clear()... -# https://github.com/godotengine/godot/issues/31166 -func _notification(what: int): - if what == NOTIFICATION_PREDELETE: - #clear() - _save_thread_running = false - _save_semaphore.post() - if USE_THREAD: - _saving_thread.wait_to_finish() - - -func _create_new_cache_file(fpath: String): - var f := FileAccess.open(fpath, FileAccess.WRITE) - if f == null: - var err = FileAccess.get_open_error() - _logger.error("Failed to create new cache file {0}: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return - - -func _get_current_cache_file_name() -> String: - return _cache_dir.path_join(str(_session_id, "_", _current_cache_file_index, ".cache")) - - -func save_image(im: Image) -> int: - assert(im != null) - if im.has_mipmaps(): - # TODO Add support for this? Didn't need it so far - _logger.error("Caching an image with mipmaps, this isn't supported") - - var fpath := _get_current_cache_file_name() - if _next_id == 0: - # First file - _create_new_cache_file(fpath) - - var id := _next_id - _next_id += 1 - - var item := { - # Duplicate the image so we are sure nothing funny will happen to it - # while the thread saves it - "image": im.duplicate(), - "path": fpath, - "data_offset": _cache_file_offset, - "saved": false - } - - _cache_file_offset += _get_image_data_size(im) - if _cache_file_offset >= CACHE_FILE_SIZE_THRESHOLD: - _cache_file_offset = 0 - _current_cache_file_index += 1 - _create_new_cache_file(_get_current_cache_file_name()) - - _cache_image_info[id] = item - - _save_queue_mutex.lock() - _save_queue.append(item) - _save_queue_mutex.unlock() - - _save_semaphore.post() - - if not USE_THREAD: - var before = Time.get_ticks_msec() - while len(_save_queue) > 0: - _save_thread_func() - if Time.get_ticks_msec() - before > 10_000: - _logger.error("Taking to long to empty save queue in non-threaded mode!") - - return id - - -static func _get_image_data_size(im: Image) -> int: - return 1 + 4 + 4 + 4 + len(im.get_data()) - - -static func _write_image(f: FileAccess, im: Image): - f.store_8(im.get_format()) - f.store_32(im.get_width()) - f.store_32(im.get_height()) - var data : PackedByteArray = im.get_data() - f.store_32(len(data)) - f.store_buffer(data) - - -static func _read_image(f: FileAccess) -> Image: - var format := f.get_8() - var width := f.get_32() - var height := f.get_32() - var data_size := f.get_32() - var data := f.get_buffer(data_size) - var im := Image.create_from_data(width, height, false, format, data) - return im - - -func load_image(id: int) -> Image: - var info := _cache_image_info[id] as Dictionary - - var timeout := 5.0 - var time_before := Time.get_ticks_msec() - # We could just grab `image`, because the thread only reads it. - # However it's still not safe to do that if we write or even lock it, - # so we have to assume it still has ownership of it. - while not info.saved: - OS.delay_msec(8.0) - _logger.debug("Waiting for cached image {0}...".format([id])) - if Time.get_ticks_msec() - time_before > timeout: - _logger.error("Could not get image {0} from cache. Something went wrong.".format([id])) - return null - - var fpath := info.path as String - - var f := FileAccess.open(fpath, FileAccess.READ) - if f == null: - var err := FileAccess.get_open_error() - _logger.error("Could not load cached image from {0}: {1}" \ - .format([fpath, HT_Errors.get_message(err)])) - return null - - f.seek(info.data_offset) - var im = _read_image(f) - f = null # close file - - assert(im != null) - return im - - -func clear(): - _logger.debug("Clearing image cache") - - var dir := DirAccess.open(_cache_dir) - if dir == null: - #var err = DirAccess.get_open_error() - _logger.error("Could not open image file cache directory '{0}'" \ - .format([_cache_dir])) - return - - dir.include_hidden = false - dir.include_navigational = false - - var err := dir.list_dir_begin() - if err != OK: - _logger.error("Could not start list_dir_begin in '{0}'".format([_cache_dir])) - return - - # Delete all cache files - while true: - var fpath := dir.get_next() - if fpath == "": - break - if fpath.ends_with(".cache"): - _logger.debug(str("Deleting ", fpath)) - err = dir.remove(fpath) - if err != OK: - _logger.error("Failed to delete cache file '{0}': {1}" \ - .format([_cache_dir.path_join(fpath), HT_Errors.get_message(err)])) - - _cache_image_info.clear() - - -func _save_thread_func(): - # Threads keep a reference to the object of the function they run. - # So if the object is a Reference, and that reference owns the thread... we get a cycle. - # We can break the cycle by removing 1 to the count inside the thread. - # The thread's reference will never die unexpectedly because we stop and destroy the thread - # in the destructor of the reference. - # If that workaround explodes one day, another way could be to use an intermediary instance - # extending Object, and run a function on that instead. - # - # I added this in Godot 3, and it seems to still be relevant in Godot 4 because if I don't - # do it, objects are leaking. - # - # BUT it seems to end up triggering a crash in debug Godot builds due to unrefing RefCounted - # with refcount == 0, so I guess it's wrong now? - # So basically, either I do it and I risk a crash, - # or I don't do it and then it causes a leak... - # TODO Make this shit use `Object` - # - # if USE_THREAD: - # unreference() - - while _save_thread_running: - _save_queue_mutex.lock() - var to_save := _save_queue.duplicate(false) - _save_queue.clear() - _save_queue_mutex.unlock() - - if len(to_save) == 0: - if USE_THREAD: - _save_semaphore.wait() - continue - - var f : FileAccess - var path := "" - - for item in to_save: - # Keep re-using the same file if we did not change path. - # It makes I/Os faster. - if item.path != path: - # Close previous file - f = null - - path = item.path - - f = FileAccess.open(path, FileAccess.READ_WRITE) - if f == null: - var err := FileAccess.get_open_error() - call_deferred("_on_error", "Could not open file {0}: {1}" \ - .format([path, HT_Errors.get_message(err)])) - path = "" - continue - - f.seek(item.data_offset) - _write_image(f, item.image) - # Notify main thread. - # The thread does not modify data, only reads it. - call_deferred("_on_image_saved", item) - - # Workaround some weird behavior in Godot 4: - # when the next loop runs, `f` IS NOT CLEANED UP. A reference is still held before `var f` - # is reached, which means the file is still locked while the thread is waiting on the - # semaphore... so I have to explicitely "close" the file here. - f = null - - if not USE_THREAD: - break - - -func _on_error(msg: String): - _logger.error(msg) - - -func _on_image_saved(item: Dictionary): - _logger.debug(str("Saved ", item.path)) - item.saved = true - # Should remove image from memory (for usually being last reference) - item.image = null - - diff --git a/godot/addons/zylann.hterrain/util/image_file_cache.gd.uid b/godot/addons/zylann.hterrain/util/image_file_cache.gd.uid deleted file mode 100644 index b542713..0000000 --- a/godot/addons/zylann.hterrain/util/image_file_cache.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bvw3g87up6bv diff --git a/godot/addons/zylann.hterrain/util/logger.gd b/godot/addons/zylann.hterrain/util/logger.gd deleted file mode 100644 index fcc78a3..0000000 --- a/godot/addons/zylann.hterrain/util/logger.gd +++ /dev/null @@ -1,34 +0,0 @@ -@tool - -class HT_LoggerBase: - var _context := "" - - func _init(p_context): - _context = p_context - - func debug(msg: String): - pass - - func warn(msg: String): - push_warning("{0}: {1}".format([_context, msg])) - - func error(msg: String): - push_error("{0}: {1}".format([_context, msg])) - - -class HT_LoggerVerbose extends HT_LoggerBase: - func _init(p_context: String): - super(p_context) - - func debug(msg: String): - print(_context, ": ", msg) - - -static func get_for(owner: Object) -> HT_LoggerBase: - # Note: don't store the owner. If it's a Reference, it could create a cycle - var script : Script = owner.get_script() - var context := script.resource_path.get_file() - if OS.is_stdout_verbose(): - return HT_LoggerVerbose.new(context) - return HT_LoggerBase.new(context) - diff --git a/godot/addons/zylann.hterrain/util/logger.gd.uid b/godot/addons/zylann.hterrain/util/logger.gd.uid deleted file mode 100644 index 5ff95a7..0000000 --- a/godot/addons/zylann.hterrain/util/logger.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b6pgvie4diwlr diff --git a/godot/addons/zylann.hterrain/util/util.gd b/godot/addons/zylann.hterrain/util/util.gd deleted file mode 100644 index b3b93ca..0000000 --- a/godot/addons/zylann.hterrain/util/util.gd +++ /dev/null @@ -1,562 +0,0 @@ -@tool - -const HT_Errors = preload("./errors.gd") - - -# Godot has this internally but doesn't expose it -static func next_power_of_two(x: int) -> int: - x -= 1 - x |= x >> 1 - x |= x >> 2 - x |= x >> 4 - x |= x >> 8 - x |= x >> 16 - x += 1 - return x - - -# CubeMesh doesn't have a wireframe option -static func create_wirecube_mesh(color = Color(1,1,1)) -> Mesh: - var positions := PackedVector3Array([ - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 1, 0), - Vector3(1, 1, 1), - Vector3(0, 1, 1), - ]) - var colors := PackedColorArray([ - color, color, color, color, - color, color, color, color, - ]) - var indices := PackedInt32Array([ - 0, 1, - 1, 2, - 2, 3, - 3, 0, - - 4, 5, - 5, 6, - 6, 7, - 7, 4, - - 0, 4, - 1, 5, - 2, 6, - 3, 7 - ]) - var arrays := [] - arrays.resize(Mesh.ARRAY_MAX) - arrays[Mesh.ARRAY_VERTEX] = positions - arrays[Mesh.ARRAY_COLOR] = colors - arrays[Mesh.ARRAY_INDEX] = indices - var mesh := ArrayMesh.new() - mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINES, arrays) - return mesh - - -static func integer_square_root(x: int) -> int: - assert(typeof(x) == TYPE_INT) - var r := int(roundf(sqrt(x))) - if r * r == x: - return r - # Does not exist - return -1 - - -# Formats integer using a separator between each 3-digit group -static func format_integer(n: int, sep := ",") -> String: - assert(typeof(n) == TYPE_INT) - - var negative := false - if n < 0: - negative = true - n = -n - - var s = "" - while n >= 1000: - s = str(sep, str(n % 1000).pad_zeros(3), s) - n /= 1000 - - if negative: - return str("-", str(n), s) - else: - return str(str(n), s) - - -# Goes up all parents until a node of the given class is found -static func get_node_in_parents(node: Node, klass) -> Node: - while node != null: - node = node.get_parent() - if node != null and is_instance_of(node, klass): - return node - return null - - -# Goes down all children until a node of the given class is found -static func find_first_node(node: Node, klass) -> Node: - if is_instance_of(node, klass): - return node - for i in node.get_child_count(): - var child := node.get_child(i) - var found_node := find_first_node(child, klass) - if found_node != null: - return found_node - return null - - -static func is_in_edited_scene(node: Node) -> bool: - if not node.is_inside_tree(): - return false - var edited_scene := node.get_tree().edited_scene_root - if node == edited_scene: - return true - return edited_scene != null and edited_scene.is_ancestor_of(node) - - -# Get an extended or cropped version of an image, -# with optional anchoring to decide in which direction to extend or crop. -# New pixels are filled with the provided fill color. -static func get_cropped_image(src: Image, width: int, height: int, - fill_color=null, anchor=Vector2(-1, -1)) -> Image: - - width = int(width) - height = int(height) - if width == src.get_width() and height == src.get_height(): - return src - var im := Image.create(width, height, false, src.get_format()) - if fill_color != null: - im.fill(fill_color) - var p = get_cropped_image_params( - src.get_width(), src.get_height(), width, height, anchor) - im.blit_rect(src, p.src_rect, p.dst_pos) - return im - - -static func get_cropped_image_params(src_w: int, src_h: int, dst_w: int, dst_h: int, - anchor: Vector2) -> Dictionary: - - var rel_anchor := (anchor + Vector2(1, 1)) / 2.0 - - var dst_x := (dst_w - src_w) * rel_anchor.x - var dst_y := (dst_h - src_h) * rel_anchor.y - - var src_x := 0 - var src_y := 0 - - if dst_x < 0: - src_x -= dst_x - src_w -= dst_x - dst_x = 0 - - if dst_y < 0: - src_y -= dst_y - src_h -= dst_y - dst_y = 0 - - if dst_x + src_w >= dst_w: - src_w = dst_w - dst_x - - if dst_y + src_h >= dst_h: - src_h = dst_h - dst_y - - return { - "src_rect": Rect2i(src_x, src_y, src_w, src_h), - "dst_pos": Vector2i(dst_x, dst_y) - } - -# TODO Workaround for https://github.com/godotengine/godot/issues/24488 -# TODO Simplify in Godot 3.1 if that's still not fixed, -# using https://github.com/godotengine/godot/pull/21806 -# And actually that function does not even work. -#static func get_shader_param_or_default(mat: Material, name: String): -# assert(mat.shader != null) -# var v = mat.get_shader_param(name) -# if v != null: -# return v -# var params = VisualServer.shader_get_param_list(mat.shader) -# for p in params: -# if p.name == name: -# match p.type: -# TYPE_OBJECT: -# return null -# # I should normally check default values, -# # however they are not accessible -# TYPE_BOOL: -# return false -# TYPE_REAL: -# return 0.0 -# TYPE_VECTOR2: -# return Vector2() -# TYPE_VECTOR3: -# return Vector3() -# TYPE_COLOR: -# return Color() -# return null - - -# Generic way to apply editor scale to a plugin UI scene. -# It is slower than doing it manually on specific controls. -# Takes a node as root because since Godot 4 Window dialogs are no longer Controls. -static func apply_dpi_scale(root: Node, dpi_scale: float): - if dpi_scale == 1.0: - return - var to_process := [root] - while len(to_process) > 0: - var node : Node = to_process[-1] - to_process.pop_back() - if node is Window: - node.size = Vector2(node.size) * dpi_scale - elif node is Viewport or node is SubViewport: - continue - elif node is Control: - if node.custom_minimum_size != Vector2(0, 0): - node.custom_minimum_size = node.custom_minimum_size * dpi_scale - var parent = node.get_parent() - if parent != null: - if not (parent is Container): - node.offset_bottom *= dpi_scale - node.offset_left *= dpi_scale - node.offset_top *= dpi_scale - node.offset_right *= dpi_scale - for i in node.get_child_count(): - to_process.append(node.get_child(i)) - - -# TODO AABB has `intersects_segment` but doesn't provide the hit point -# So we have to rely on a less efficient method. -# Returns a list of intersections between an AABB and a segment, sorted -# by distance to the beginning of the segment. -static func get_aabb_intersection_with_segment(aabb: AABB, - segment_begin: Vector3, segment_end: Vector3) -> Array: - - var hits := [] - - if not aabb.intersects_segment(segment_begin, segment_end): - return hits - - var hit - - var x_rect := Rect2(aabb.position.y, aabb.position.z, aabb.size.y, aabb.size.z) - - hit = Plane(Vector3(1, 0, 0), aabb.position.x) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and x_rect.has_point(Vector2(hit.y, hit.z)): - hits.append(hit) - - hit = Plane(Vector3(1, 0, 0), aabb.end.x) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and x_rect.has_point(Vector2(hit.y, hit.z)): - hits.append(hit) - - var y_rect := Rect2(aabb.position.x, aabb.position.z, aabb.size.x, aabb.size.z) - - hit = Plane(Vector3(0, 1, 0), aabb.position.y) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and y_rect.has_point(Vector2(hit.x, hit.z)): - hits.append(hit) - - hit = Plane(Vector3(0, 1, 0), aabb.end.y) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and y_rect.has_point(Vector2(hit.x, hit.z)): - hits.append(hit) - - var z_rect := Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y) - - hit = Plane(Vector3(0, 0, 1), aabb.position.z) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and z_rect.has_point(Vector2(hit.x, hit.y)): - hits.append(hit) - - hit = Plane(Vector3(0, 0, 1), aabb.end.z) \ - .intersects_segment(segment_begin, segment_end) - if hit != null and z_rect.has_point(Vector2(hit.x, hit.y)): - hits.append(hit) - - if len(hits) == 2: - # The segment has two hit points. Sort them by distance - var d0 = hits[0].distance_squared_to(segment_begin) - var d1 = hits[1].distance_squared_to(segment_begin) - if d0 > d1: - var temp = hits[0] - hits[0] = hits[1] - hits[1] = temp - else: - assert(len(hits) < 2) - - return hits - - -class HT_GridRaytraceResult2D: - var hit_cell_pos: Vector2 - var prev_cell_pos: Vector2 - - -# Iterates through a virtual 2D grid of unit-sized square cells, -# and executes an action on each cell intersecting the given segment, -# ordered from begin to end. -# One of my most re-used pieces of code :) -# -# Initially inspired by http://www.cse.yorku.ca/~amana/research/grid.pdf -# -# Ported from https://github.com/bulletphysics/bullet3/blob/ -# 687780af6b491056700cfb22cab57e61aeec6ab8/src/BulletCollision/CollisionShapes/ -# btHeightfieldTerrainShape.cpp#L418 -# -static func grid_raytrace_2d(ray_origin: Vector2, ray_direction: Vector2, - quad_predicate: Callable, max_distance: float) -> HT_GridRaytraceResult2D: - - if max_distance < 0.0001: - # Consider the ray is too small to hit anything - return null - - var xi_step := 0 - if ray_direction.x > 0: - xi_step = 1 - elif ray_direction.x < 0: - xi_step = -1 - - var yi_step := 0 - if ray_direction.y > 0: - yi_step = 1 - elif ray_direction.y < 0: - yi_step = -1 - - var infinite := 9999999.0 - - var param_delta_x := infinite - if xi_step != 0: - param_delta_x = 1.0 / absf(ray_direction.x) - - var param_delta_y := infinite - if yi_step != 0: - param_delta_y = 1.0 / absf(ray_direction.y) - - # pos = param * dir - # At which value of `param` we will cross a x-axis lane? - var param_cross_x := infinite - # At which value of `param` we will cross a y-axis lane? - var param_cross_y := infinite - - # param_cross_x and param_cross_z are initialized as being the first cross - # X initialization - if xi_step != 0: - if xi_step == 1: - param_cross_x = (ceilf(ray_origin.x) - ray_origin.x) * param_delta_x - else: - param_cross_x = (ray_origin.x - floorf(ray_origin.x)) * param_delta_x - else: - # Will never cross on X - param_cross_x = infinite - - # Y initialization - if yi_step != 0: - if yi_step == 1: - param_cross_y = (ceilf(ray_origin.y) - ray_origin.y) * param_delta_y - else: - param_cross_y = (ray_origin.y - floorf(ray_origin.y)) * param_delta_y - else: - # Will never cross on Y - param_cross_y = infinite - - var x := int(floorf(ray_origin.x)) - var y := int(floorf(ray_origin.y)) - - # Workaround cases where the ray starts at an integer position - if param_cross_x == 0.0: - param_cross_x += param_delta_x - # If going backwards, we should ignore the position we would get by the above flooring, - # because the ray is not heading in that direction - if xi_step == -1: - x -= 1 - - if param_cross_y == 0.0: - param_cross_y += param_delta_y - if yi_step == -1: - y -= 1 - - var prev_x := x - var prev_y := y - var param := 0.0 - var prev_param := 0.0 - - while true: - prev_x = x - prev_y = y - prev_param = param - - if param_cross_x < param_cross_y: - # X lane - x += xi_step - # Assign before advancing the param, - # to be in sync with the initialization step - param = param_cross_x - param_cross_x += param_delta_x - - else: - # Y lane - y += yi_step - param = param_cross_y - param_cross_y += param_delta_y - - if param > max_distance: - param = max_distance - # quad coordinates, enter param, exit/end param - if quad_predicate.call(prev_x, prev_y, prev_param, param): - var res := HT_GridRaytraceResult2D.new() - res.hit_cell_pos = Vector2(x, y) - res.prev_cell_pos = Vector2(prev_x, prev_y) - return res - else: - break - - elif quad_predicate.call(prev_x, prev_y, prev_param, param): - var res := HT_GridRaytraceResult2D.new() - res.hit_cell_pos = Vector2(x, y) - res.prev_cell_pos = Vector2(prev_x, prev_y) - return res - - return null - - -static func get_segment_clipped_by_rect(rect: Rect2, - segment_begin: Vector2, segment_end: Vector2) -> Array: - - # / - # A-----/---B A-----+---B - # | / | => | / | - # | / | | / | - # C--/------D C--+------D - # / - - if rect.has_point(segment_begin) and rect.has_point(segment_end): - return [segment_begin, segment_end] - - var a := rect.position - var b := Vector2(rect.end.x, rect.position.y) - var c := Vector2(rect.position.x, rect.end.y) - var d := rect.end - - var ab = Geometry2D.segment_intersects_segment(segment_begin, segment_end, a, b) - var cd = Geometry2D.segment_intersects_segment(segment_begin, segment_end, c, d) - var ac = Geometry2D.segment_intersects_segment(segment_begin, segment_end, a, c) - var bd = Geometry2D.segment_intersects_segment(segment_begin, segment_end, b, d) - - var hits = [] - if ab != null: - hits.append(ab) - if cd != null: - hits.append(cd) - if ac != null: - hits.append(ac) - if bd != null: - hits.append(bd) - - # Now we need to order the hits from begin to end - if len(hits) == 1: - if rect.has_point(segment_begin): - hits = [segment_begin, hits[0]] - elif rect.has_point(segment_end): - hits = [hits[0], segment_end] - else: - # TODO This has a tendency to happen with integer coordinates... - # How can you get only 1 hit and have no end of the segment - # inside of the rectangle? Float precision shit? Assume no hit... - return [] - - elif len(hits) == 2: - var d0 = hits[0].distance_squared_to(segment_begin) - var d1 = hits[1].distance_squared_to(segment_begin) - if d0 > d1: - hits = [hits[1], hits[0]] - - return hits - - -static func get_pixel_clamped(im: Image, x: int, y: int) -> Color: - x = clampi(x, 0, im.get_width() - 1) - y = clampi(y, 0, im.get_height() - 1) - return im.get_pixel(x, y) - - -static func update_configuration_warning(node: Node, recursive: bool): - if not Engine.is_editor_hint(): - return - node.update_configuration_warnings() - if recursive: - for i in node.get_child_count(): - var child = node.get_child(i) - update_configuration_warning(child, true) - - -static func write_import_file(settings: Dictionary, imp_fpath: String, logger) -> bool: - # TODO Should use ConfigFile instead - var f := FileAccess.open(imp_fpath, FileAccess.WRITE) - if f == null: - var err = FileAccess.get_open_error() - logger.error("Could not open '{0}' for write, error {1}" \ - .format([imp_fpath, HT_Errors.get_message(err)])) - return false - - for section in settings: - f.store_line(str("[", section, "]")) - f.store_line("") - var params = settings[section] - for key in params: - var v = params[key] - var sv - match typeof(v): - TYPE_STRING: - sv = str('"', v.replace('"', '\"'), '"') - TYPE_BOOL: - sv = "true" if v else "false" - _: - sv = str(v) - f.store_line(str(key, "=", sv)) - f.store_line("") - - return true - - -static func update_texture_partial( - tex: ImageTexture, im: Image, src_rect: Rect2i, dst_pos: Vector2i): - - # ..ooo@@@XXX%%%xx.. - # .oo@@XXX%x%xxx.. ` . - # .o@XX%%xx.. ` . - # o@X%.. ..ooooooo - # .@X%x. ..o@@^^ ^^@@o - # .ooo@@@@@@ooo.. ..o@@^ @X% - # o@@^^^ ^^^@@@ooo.oo@@^ % - # xzI -*-- ^^^o^^ --*- % - # @@@o ooooooo^@@^o^@X^@oooooo .X%x - # I@@@@@@@@@XX%%xx ( o@o )X%x@ROMBASED@@@X%x - # I@@@@XX%%xx oo@@@@X% @@X%x ^^^@@@@@@@X%x - # @X%xx o@@@@@@@X% @@XX%%x ) ^^@X%x - # ^ xx o@@@@@@@@Xx ^ @XX%%x xxx - # o@@^^^ooo I^^ I^o ooo . x - # oo @^ IX I ^X @^ oo - # IX U . V IX - # V . . V - # - - # TODO Optimize: Godot 4 has lost the ability to update textures partially! - var fuck = tex.get_image() - fuck.blit_rect(im, src_rect, dst_pos) - tex.update(fuck) - - -# Should be used because if `set_shader_parameter` has never been called, `get_shader_parameter` -# will return null even if the shader's corresponding uniform has a default value. -# See https://github.com/godotengine/godot/issues/44454 -static func get_shader_material_parameter(material: ShaderMaterial, param_name: StringName): - var v = material.get_shader_parameter(param_name) - if v == null: - var shader : Shader = material.shader - if shader != null: - v = RenderingServer.shader_get_parameter_default(shader.get_rid(), param_name) - return v - - diff --git a/godot/addons/zylann.hterrain/util/util.gd.uid b/godot/addons/zylann.hterrain/util/util.gd.uid deleted file mode 100644 index 97cd5d5..0000000 --- a/godot/addons/zylann.hterrain/util/util.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dnr71g2sg2511 diff --git a/godot/addons/zylann.hterrain/util/xyz_format.gd b/godot/addons/zylann.hterrain/util/xyz_format.gd deleted file mode 100644 index 8f35190..0000000 --- a/godot/addons/zylann.hterrain/util/xyz_format.gd +++ /dev/null @@ -1,111 +0,0 @@ -@tool - -# XYZ files are text files containing a list of 3D points. -# They can be found in GIS software as an export format for heightmaps. -# In order to turn it into a heightmap we may calculate bounds first -# to find the origin and then set points in an image. - - -class HT_XYZBounds: - # Note: it is important for these to be double-precision floats, - # GIS data can have large coordinates - var min_x := 0.0 - var min_y := 0.0 - - var max_x := 0.0 - var max_y := 0.0 - - var line_count := 0 - - var image_width := 0 - var image_height := 0 - - -# TODO `split_float` returns 32-bit floats, despite internally parsing doubles... -# Despite that, I still use it here because it doesn't seem to cause issues and is faster. -# If it becomes an issue, we'll have to switch to `split` and casting to `float`. - -static func load_bounds(f: FileAccess) -> HT_XYZBounds: - # It is faster to get line and split floats than using CSV functions - var line := f.get_line() - var floats := line.split_floats(" ") - - # We only care about X and Y, it makes less operations to do in the loop. - # Z is the height and will remain as-is at the end. - var min_pos_x := floats[0] - var min_pos_y := floats[1] - - var max_pos_x := min_pos_x - var max_pos_y := min_pos_y - - # Start at 1 because we just read the first line - var line_count := 1 - - # We know the file is a series of float triplets - while not f.eof_reached(): - line = f.get_line() - - # The last line can be empty - if len(line) < 2: - break - - floats = line.split_floats(" ") - - var pos_x := floats[0] - var pos_y := floats[1] - - min_pos_x = minf(min_pos_x, pos_x) - min_pos_y = minf(min_pos_y, pos_y) - - max_pos_x = maxf(max_pos_x, pos_x) - max_pos_y = maxf(max_pos_y, pos_y) - - line_count += 1 - - var bounds := HT_XYZBounds.new() - bounds.min_x = min_pos_x - bounds.min_y = min_pos_y - bounds.max_x = max_pos_x - bounds.max_y = max_pos_y - bounds.line_count = line_count - bounds.image_width = int(max_pos_x - min_pos_x) + 1 - bounds.image_height = int(max_pos_y - min_pos_y) + 1 - return bounds - - -# Loads points into an image with existing dimensions and format. -# `f` must be positioned at the beginning of the series of points. -# If `bounds` is `null`, it will be computed. -static func load_heightmap(f: FileAccess, dst_image: Image, bounds: HT_XYZBounds): - # We are not going to read the entire file directly in memory, because it can be really big. - # Instead we'll parse it directly and the only thing we retain in memory is the heightmap. - # This can be really slow on big files. If we can assume the file is square and points - # separated by 1 unit each in a grid pattern, it could be a bit faster, but - # parsing points from text really is the main bottleneck (40 seconds to load a 2000x2000 file!). - - var dst_format := dst_image.get_format() - assert(dst_format == Image.FORMAT_RF or dst_format == Image.FORMAT_RH) - - # Bounds can be precalculated - if bounds == null: - var file_begin := f.get_position() - bounds = load_bounds(f) - f.seek(file_begin) - - # Put min coordinates on the GDScript stack so they are faster to access - var min_pos_x := bounds.min_x - var min_pos_y := bounds.min_y - var line_count := bounds.line_count - - for i in line_count: - var line := f.get_line() - var floats := line.split_floats(" ") - var x := int(floats[0] - min_pos_x) - var y := int(floats[1] - min_pos_y) - - # Make sure the coordinate is inside the image, - # due to float imprecision or potentially non-grid-aligned points. - # Could use `Rect2` to check faster but it uses floats. - # `Rect2i` would be better but is only available in Godot 4. - if x >= 0 and y >= 0 and x < dst_image.get_width() and y < dst_image.get_height(): - dst_image.set_pixel(x, y, Color(floats[2], 0, 0)) diff --git a/godot/addons/zylann.hterrain/util/xyz_format.gd.uid b/godot/addons/zylann.hterrain/util/xyz_format.gd.uid deleted file mode 100644 index 9c4fab4..0000000 --- a/godot/addons/zylann.hterrain/util/xyz_format.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bxfa0ybku8m5h diff --git a/godot/default_bus_layout.tres b/godot/default_bus_layout.tres deleted file mode 100644 index 2c0cd0e..0000000 --- a/godot/default_bus_layout.tres +++ /dev/null @@ -1,15 +0,0 @@ -[gd_resource type="AudioBusLayout" format=3 uid="uid://cc76fsdx1go5q"] - -[resource] -bus/1/name = &"Music" -bus/1/solo = false -bus/1/mute = false -bus/1/bypass_fx = false -bus/1/volume_db = 0.0 -bus/1/send = &"Master" -bus/2/name = &"SFX" -bus/2/solo = false -bus/2/mute = false -bus/2/bypass_fx = false -bus/2/volume_db = 0.0 -bus/2/send = &"Master" diff --git a/godot/project.godot b/godot/project.godot index 5ef86b5..eaf883d 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -73,13 +73,3 @@ move_down={ , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) ] } - -[internationalization] - -locale/translations=PackedStringArray("res://addons/maaacks_game_template/base/translations/menus_translations.en.translation", "res://addons/maaacks_game_template/base/translations/menus_translations.fr.translation") - -[maaacks_game_template] - -disable_install_audio_busses=true -disable_update_check=false -disable_install_wizard=true