RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
palette_manager.gd
Go to the documentation of this file.
1extends RefCounted
2
3
11
12const DataCacheManager = preload("res://scripts/systems/dataCacheManager/data_cache_manager.gd")
13
14var palettes := {}
15var texture_cache := {}
16var data_cache_manager = DataCacheManager.new()
17
18
19
20func load_palettes(file_path:String) -> void:
21 var data = data_cache_manager.load_json(file_path)
22 if not data is Dictionary:
23 return
24 for palette_id in data.get("palettes", {}).keys():
25 palettes[str(palette_id)] = _parse_palette(data["palettes"][palette_id])
26
27
28
29func get_palette(palette_id:String) -> Array:
30 return palettes.get(palette_id, []).duplicate()
31
32
33
34func has_palette(palette_id:String) -> bool:
35 return palettes.has(palette_id)
36
37
38
39func recolor_image(source_image:Image, source_palette_id:String, target_palette_id:String) -> Image:
40 var source_palette = get_palette(source_palette_id)
41 var target_palette = get_palette(target_palette_id)
42 if source_image == null or source_palette.is_empty() or target_palette.is_empty():
43 return source_image
44 var limit = min(source_palette.size(), target_palette.size())
45 var image = source_image.duplicate()
46 for y in range(image.get_height()):
47 for x in range(image.get_width()):
48 var pixel = image.get_pixel(x, y)
49 if pixel.a <= 0.0:
50 continue
51 var index = _nearest_palette_index(pixel, source_palette, limit)
52 var replacement:Color = target_palette[index]
53 replacement.a = pixel.a
54 image.set_pixel(x, y, replacement)
55 return image
56
57
58
59func recolor_texture(texture:Texture2D, source_palette_id:String, target_palette_id:String):
60 if texture == null:
61 return null
62 var image = texture.get_image()
63 if image == null or image.is_empty():
64 return texture
65 return ImageTexture.create_from_image(recolor_image(image, source_palette_id, target_palette_id))
66
67
68
69func get_recolored_sprite_texture(sprite_manager, sprite_id:String, source_palette_id:String, target_palette_id:String, size:int = 0):
70 var cache_key = "%s|%s|%s|%d" % [sprite_id, source_palette_id, target_palette_id, size]
71 if texture_cache.has(cache_key):
72 return texture_cache[cache_key]
73 var texture = sprite_manager.get_scaled_texture(sprite_id, size) if size > 0 else sprite_manager.get_texture(sprite_id)
74 var recolored = recolor_texture(texture, source_palette_id, target_palette_id)
75 if recolored != null:
76 texture_cache[cache_key] = recolored
77 return recolored
78
79
80
81func get_cache_stats() -> Dictionary:
82 return {
83 "palettes": palettes.size(),
84 "recolored_textures": texture_cache.size(),
85 "data_cache_entries": int(data_cache_manager.get_cache_stats().get("entries", 0)),
86 "data_cache_hits": int(data_cache_manager.get_cache_stats().get("cache_hits", 0)),
87 "data_cache_misses": int(data_cache_manager.get_cache_stats().get("cache_misses", 0))
88 }
89
90
91
92func clear_cache() -> void:
93 texture_cache.clear()
94
95
96func _parse_palette(raw_palette) -> Array:
97 var parsed := []
98 if not raw_palette is Array:
99 return parsed
100 for value in raw_palette:
101 parsed.append(Color(str(value)))
102 return parsed
103
104
105func _nearest_palette_index(pixel:Color, palette:Array, limit:int) -> int:
106 var best_index := 0
107 var best_distance := INF
108 for i in range(limit):
109 var color:Color = palette[i]
110 var dr = pixel.r - color.r
111 var dg = pixel.g - color.g
112 var db = pixel.b - color.b
113 var distance = dr * dr + dg * dg + db * db
114 if distance < best_distance:
115 best_distance = distance
116 best_index = i
117 return best_index
int
Resolve a sprite id through spriteManager and return a recolored texture.