Skip to content

Commit fbfc451

Browse files
committed
add color remapping
1 parent 8fd7244 commit fbfc451

File tree

12 files changed

+119
-31
lines changed

12 files changed

+119
-31
lines changed

rct-graphics-helper/magick_command.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def as_montage(self, inputs):
1616
"\" \"".join(inputs) + \
1717
"\" +append -background none"
1818

19+
# Writes rbg or rbga data to output
20+
def pixel_data(self, image):
21+
self.full_command = '"'+ image + '" -format %c -depth 8 histogram:info:-'
22+
1923
# Writes the current result to the MPR for reuse in the same command. The cached result can be referenced using mpr:{id}
2024
def write_to_cache(self, id, delete_previous=False, next_file=""):
2125
delete_addition = ""
@@ -100,10 +104,10 @@ def clone(self):
100104

101105
# Gets the cli command to perform the ImageMagick operation
102106

103-
def get_command_string(self, magick_path, output):
107+
def get_command_string(self, magick_path, output = None):
104108
if self.use_repage:
105109
self.full_command = self.full_command + " +repage"
106-
final_command = magick_path + " " + self.full_command + " \"" + output + "\""
110+
final_command = magick_path + " " + self.full_command + (output and " \"" + output + "\"" or "")
107111
if os.name == "posix":
108112
final_command = final_command.replace("(", "\(").replace(")", "\)")
109113
return final_command

rct-graphics-helper/models/palette.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import subprocess
1111
import os
12+
import re
1213

1314
from ..magick_command import MagickCommand
1415
from ..res.res import res_path
@@ -176,9 +177,37 @@
176177
}
177178
}
178179

180+
palettes_for_recolor = [
181+
"black", "lavender_purple", "violet_purple","blue", "teal","yellow_green",
182+
"sea_green","light_olive_green","dark_olive_green","lime_green","yellow",
183+
"bright_yellow","orange","salmon","sandy_brown","bordeaux_red","bright_red",
184+
"magenta","recolor_1","recolor_1_orct2"
185+
]
186+
187+
def create_remap_tuple(paletteName):
188+
if not paletteName in palette_colors_details:
189+
return
190+
palette = palette_colors_details[paletteName]
191+
return tuple([paletteName, palette["title"], palette["Description"]])
192+
193+
def create_remap_enumlist(defaultSelection):
194+
myPaletteColors = palettes_for_recolor.copy()
195+
myPaletteColors.remove(defaultSelection)
196+
options = [create_remap_tuple(i) for i in myPaletteColors]
197+
options.insert(0,create_remap_tuple(defaultSelection))
198+
return options
199+
179200
palette_base_path = os.path.join(res_path, "palettes")
180201
palette_groups_path = os.path.join(palette_base_path, "groups")
181202

203+
class RGBA:
204+
def __init__(self, hexString, red, green, blue, alpha = 255):
205+
self.hex = hexString
206+
self.red = int(red)
207+
self.green = int(green)
208+
self.blue = int(blue)
209+
self.alpha = int(alpha)
210+
182211
# Collection of color groups to create a palette from
183212

184213

@@ -188,6 +217,7 @@ def __init__(self, path=None, colors=[]):
188217
self.generated = False
189218
self.invalidated = False
190219
self.path = ""
220+
self.shades = []
191221

192222
if path != None:
193223
self.path = path
@@ -242,3 +272,19 @@ def generate_output(self, renderer, output_path):
242272
self.path = output_path
243273
self.generated = True
244274
self.invalidated = False
275+
276+
# generates a list of hexadecimal colors usable in ImageMagick
277+
def get_shades(self, renderer):
278+
cmd = MagickCommand("")
279+
cmd.pixel_data(self.path)
280+
raw_output = subprocess.check_output(cmd.get_command_string(
281+
renderer.magick_path), shell = True)
282+
output = raw_output.decode("utf-8")
283+
data_rgb = re.findall(" \(([\d,]+)\)", output)
284+
data_hex = re.findall("#[\w]+", output)
285+
if (len(data_rgb) != len(data_hex)):
286+
print(len(data_rgb), data_rgb)
287+
print(len(data_hex), data_hex)
288+
assert(len(data_rgb) != len(data_hex))
289+
colors_present = [RGBA(data_hex[i], *(data_rgb[i].split(","))) for i in range(len(data_rgb))]
290+
self.shades = [shade.hex for shade in colors_present if shade.alpha == 255]

rct-graphics-helper/operators/render_tiles_operator.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ def create_task(self, context):
2222
scene = context.scene
2323
props = scene.rct_graphics_helper_static_properties
2424
general_props = scene.rct_graphics_helper_general_properties
25-
25+
26+
# Update the remap palettes with the ones we set. These colors will be recolored into OpenRCT2's remap 1, 2, 3
27+
# colors on materials with the appropriate index set
28+
self.palette_manager.set_recolor_palettes(general_props.primary_remap_input, general_props.secondary_remap_input,
29+
general_props.tertiary_remap_input)
2630
# Create the list of frames with our parameters
2731
self.task_builder.clear()
2832
self.task_builder.set_anti_aliasing_with_background(

rct-graphics-helper/palette_manager.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import bpy
1313
import math
1414

15-
from .models.palette import Palette, palette_base_path
15+
from .models.palette import Palette, palette_base_path, palette_groups_path
1616

1717
default_full_palette = Palette(os.path.join(
1818
palette_base_path, "default_full_palette.bmp"), [
@@ -52,12 +52,6 @@
5252
"transparent"
5353
])
5454

55-
recolor_1_palette = Palette(os.path.join(
56-
palette_base_path, "recolor_1_palette.bmp"), [
57-
"recolor_1",
58-
"transparent"
59-
])
60-
6155
recolor_1_orct2_palette = Palette(os.path.join(
6256
palette_base_path, "recolor_1_orct2_palette.bmp"), [
6357
"recolor_1_orct2",
@@ -86,18 +80,36 @@
8680

8781
class PaletteManager:
8882
def __init__(self):
89-
self.recolor_palettes = [
90-
recolor_1_palette,
91-
recolor_2_palette,
92-
recolor_3_palette
93-
]
83+
self.recolor_palettes = []
9484

9585
self.orct2_recolor_palettes = [
9686
recolor_1_orct2_palette,
9787
recolor_2_palette,
9888
recolor_3_palette
9989
]
10090

91+
def set_recolor_palettes(self, recolor1, recolor2, recolor3):
92+
self.recolor_palettes = [
93+
Palette(
94+
os.path.join(palette_groups_path, recolor1 + ".png"),
95+
[ recolor1 ]
96+
),
97+
Palette(
98+
os.path.join(palette_groups_path, recolor2 + ".png"),
99+
[ recolor2 ]
100+
),
101+
Palette(
102+
os.path.join(palette_groups_path, recolor3 + ".png"),
103+
[ recolor3 ]
104+
),
105+
]
106+
107+
def get_recolor_shades(self, renderer):
108+
for palette in self.recolor_palettes:
109+
palette.get_shades(renderer)
110+
for palette in self.orct2_recolor_palettes:
111+
palette.get_shades(renderer)
112+
101113
# Gets a base palette for the selected palette mode for the selected number of recolorables
102114
def get_base_palette(self, selected_palette_mode, recolors, preference="FULL"):
103115
if selected_palette_mode == "AUTO":

rct-graphics-helper/processors/sub_processes/frame_processors/post_processor.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ def process(self, frame, callback=None):
4343
magick_command.quantize(self.renderer.get_palette_path(
4444
frame.base_palette), self.renderer.floyd_steinberg_diffusion)
4545

46+
# this should be moved somewhere it can run once per palette change
47+
self.renderer.get_recolor_shades()
48+
4649
# Force the recolorables to a palette that only contains the recolorable color
4750
channels_to_exclude_for_mai = ["Green", "Blue"]
4851

@@ -58,21 +61,10 @@ def process(self, frame, callback=None):
5861
forced_color_render = MagickCommand("mpr:render")
5962
forced_color_render.quantize(self.renderer.get_palette_path(
6063
palette), self.renderer.floyd_steinberg_diffusion)
61-
62-
if i == 0:
63-
# Replace our clover green recolor 1 with the OpenRCT2 orange recolor 1
64-
forced_color_render.replace_color("#003F21", "#6F332F")
65-
forced_color_render.replace_color("#00672F", "#83372F")
66-
forced_color_render.replace_color("#0B7B41", "#973F33")
67-
forced_color_render.replace_color("#178F51", "#AB4333")
68-
forced_color_render.replace_color("#1FA35C", "#BF4B2F")
69-
forced_color_render.replace_color("#27B768", "#D34F2B")
70-
forced_color_render.replace_color("#3BDB7F", "#E75723")
71-
forced_color_render.replace_color("#5BEF98", "#FF5F1F")
72-
forced_color_render.replace_color("#77F3A9", "#FF7F27")
73-
forced_color_render.replace_color("#97F7BE", "#FF9B33")
74-
forced_color_render.replace_color("#B7FBD0", "#FFB73F")
75-
forced_color_render.replace_color("#D7FFE5", "#FFCF4B")
64+
65+
# Replace our input color with the appropriate orct2 remap color
66+
for i in range(min(len(palette.shades), len(orct2_palette.shades))):
67+
forced_color_render.replace_color(palette.shades[i],orct2_palette.shades[i])
7668

7769
magick_command.mask_mix(forced_color_render, mask)
7870

rct-graphics-helper/properties/general_properties.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import math
1212
import os
1313

14-
from ..models.palette import palette_colors, palette_colors_details
14+
from ..models.palette import palette_colors, palette_colors_details, create_remap_enumlist
1515

1616

1717
class GeneralProperties(bpy.types.PropertyGroup):
@@ -94,6 +94,21 @@ class GeneralProperties(bpy.types.PropertyGroup):
9494
description="Which color groups to dither to. Recolorables will be excluded from this palette when used to avoid conflicts.",
9595
size=len(defaults))
9696

97+
primary_remap_input = bpy.props.EnumProperty(
98+
name="Primary Color",
99+
items= create_remap_enumlist("recolor_1")
100+
)
101+
102+
secondary_remap_input = bpy.props.EnumProperty(
103+
name="Secondary Color",
104+
items= create_remap_enumlist("magenta")
105+
)
106+
107+
tertiary_remap_input = bpy.props.EnumProperty(
108+
name="Tertiary Color",
109+
items= create_remap_enumlist("yellow")
110+
)
111+
97112
render_mode = bpy.props.EnumProperty(
98113
name="Render Mode",
99114
items=(

rct-graphics-helper/rct_graphics_helper_panel.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ def draw(self, context):
8282
row = layout.row()
8383
row.separator()
8484

85+
row = layout.row()
86+
row.label("Remap Colors:")
87+
88+
row = layout.row()
89+
row.prop(properties,"primary_remap_input")
90+
91+
row = layout.row()
92+
row.prop(properties,"secondary_remap_input")
93+
94+
row = layout.row()
95+
row.prop(properties,"tertiary_remap_input")
96+
8597
row = layout.row()
8698
row.label("Dither Palette:")
8799

rct-graphics-helper/renderer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ def _render_finished_safe(self):
114114
if callback != None:
115115
callback()
116116

117+
def get_recolor_shades(self):
118+
self.palette_manager.get_recolor_shades(self)
119+
117120
def get_palette_path(self, palette):
118121
palette.prepare(self)
119122
return palette.path
-780 Bytes
Binary file not shown.
158 Bytes
Loading

0 commit comments

Comments
 (0)