mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 15:13:16 +00:00
use oklch instead of hsv for hue shifts
This commit is contained in:
parent
e4ea0213ef
commit
d235795efd
3 changed files with 100 additions and 58 deletions
25
noita-proxy/Cargo.lock
generated
25
noita-proxy/Cargo.lock
generated
|
@ -1271,9 +1271,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glam"
|
||||||
version = "0.29.0"
|
version = "0.29.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a"
|
checksum = "480c9417a5dc586fc0c0cb67891170e59cc11e9dc79ba1c11ddd2c56ca3f3b90"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
|
@ -1507,9 +1507,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.9"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
|
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
|
@ -2530,10 +2530,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn-udp"
|
name = "quinn-udp"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b"
|
checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
@ -2680,9 +2681,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.8"
|
version = "0.12.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
|
checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -2992,18 +2993,18 @@ checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.213"
|
version = "1.0.214"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1"
|
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.213"
|
version = "1.0.214"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5"
|
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -156,7 +156,7 @@ enum AppState {
|
||||||
struct PlayerAppearance {
|
struct PlayerAppearance {
|
||||||
player_color: PlayerColor,
|
player_color: PlayerColor,
|
||||||
player_picker: PlayerPicker,
|
player_picker: PlayerPicker,
|
||||||
hue: f32,
|
hue: f64,
|
||||||
cosmetics: (bool, bool, bool),
|
cosmetics: (bool, bool, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,23 +204,23 @@ impl Default for AppSavedState {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Decode, Encode, Copy, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Decode, Encode, Copy, Clone)]
|
||||||
pub struct PlayerColor {
|
pub struct PlayerColor {
|
||||||
player_main: [u8; 4],
|
player_main: [f64; 4],
|
||||||
player_alt: [u8; 4],
|
player_alt: [f64; 4],
|
||||||
player_arm: [u8; 4],
|
player_arm: [f64; 4],
|
||||||
player_cape: [u8; 4],
|
player_cape: [f64; 4],
|
||||||
player_cape_edge: [u8; 4],
|
player_cape_edge: [f64; 4],
|
||||||
player_forearm: [u8; 4],
|
player_forearm: [f64; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerColor {
|
impl Default for PlayerColor {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
player_main: [155, 111, 154, 255],
|
player_main: [155.0, 111.0, 154.0, 255.0],
|
||||||
player_alt: [127, 84, 118, 255],
|
player_alt: [127.0, 84.0, 118.0, 255.0],
|
||||||
player_arm: [89, 67, 84, 255],
|
player_arm: [89.0, 67.0, 84.0, 255.0],
|
||||||
player_cape: [118, 84, 127, 255],
|
player_cape: [118.0, 84.0, 127.0, 255.0],
|
||||||
player_cape_edge: [154, 111, 155, 255],
|
player_cape_edge: [154.0, 111.0, 155.0, 255.0],
|
||||||
player_forearm: [158, 115, 154, 255],
|
player_forearm: [158.0, 115.0, 154.0, 255.0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use bitcode::{Decode, Encode};
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use eframe::egui::color_picker::{color_picker_color32, Alpha};
|
use eframe::egui::color_picker::{color_picker_color32, Alpha};
|
||||||
use eframe::egui::{Color32, TextureHandle, TextureOptions, Ui};
|
use eframe::egui::{Color32, TextureHandle, TextureOptions, Ui};
|
||||||
use eframe::epaint::Hsva;
|
|
||||||
use image::{Rgba, RgbaImage};
|
use image::{Rgba, RgbaImage};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
@ -51,19 +50,23 @@ pub fn replace_color(image: &mut RgbaImage, main: Rgba<u8>, alt: Rgba<u8>, arm:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_u8(c: [f64; 4]) -> [u8; 4] {
|
||||||
|
[c[0] as u8, c[1] as u8, c[2] as u8, c[3] as u8]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn make_player_image(image: &mut RgbaImage, colors: PlayerColor) {
|
pub fn make_player_image(image: &mut RgbaImage, colors: PlayerColor) {
|
||||||
let target_main = Rgba::from([155, 111, 154, 255]);
|
let target_main = Rgba::from([155, 111, 154, 255]);
|
||||||
let target_alt = Rgba::from([127, 84, 118, 255]);
|
let target_alt = Rgba::from([127, 84, 118, 255]);
|
||||||
let target_arm = Rgba::from([89, 67, 84, 255]);
|
let target_arm = Rgba::from([89, 67, 84, 255]);
|
||||||
let main = Rgba::from(colors.player_main);
|
let main = Rgba::from(to_u8(colors.player_main));
|
||||||
let alt = Rgba::from(colors.player_alt);
|
let alt = Rgba::from(to_u8(colors.player_alt));
|
||||||
let arm = Rgba::from(colors.player_arm);
|
let arm = Rgba::from(to_u8(colors.player_arm));
|
||||||
let cape = Rgba::from(colors.player_cape);
|
let cape = Rgba::from(to_u8(colors.player_cape));
|
||||||
let cape_edge = Rgba::from(colors.player_cape_edge);
|
let cape_edge = Rgba::from(to_u8(colors.player_cape_edge));
|
||||||
let forearm = Rgba::from(colors.player_forearm);
|
let forearm = Rgba::from(to_u8(colors.player_forearm));
|
||||||
for (i, pixel) in image.pixels_mut().enumerate() {
|
for (i, pixel) in image.pixels_mut().enumerate() {
|
||||||
if *pixel == target_main {
|
if *pixel == target_main {
|
||||||
*pixel = main;
|
*pixel = main
|
||||||
} else if *pixel == target_alt {
|
} else if *pixel == target_alt {
|
||||||
*pixel = alt
|
*pixel = alt
|
||||||
} else if *pixel == target_arm {
|
} else if *pixel == target_arm {
|
||||||
|
@ -112,13 +115,51 @@ pub fn add_cosmetics(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shift_hue(diff: f32, color: &mut [u8; 4]) {
|
fn rgb_to_oklch(color: &mut [f64; 4]) {
|
||||||
let rgb = Color32::from_rgb(color[0], color[1], color[2]);
|
let mut l = 0.4122214708 * color[0] + 0.5363325363 * color[1] + 0.0514459929 * color[2];
|
||||||
let mut hsv = Hsva::from(rgb);
|
let mut m = 0.2119034982 * color[0] + 0.6806995451 * color[1] + 0.1073969566 * color[2];
|
||||||
hsv.h += diff / 360.0;
|
let mut s = 0.0883024619 * color[0] + 0.2817188376 * color[1] + 0.6299787005 * color[2];
|
||||||
hsv.h = hsv.h.fract();
|
|
||||||
let rgb = hsv.to_srgb();
|
l = l.cbrt();
|
||||||
*color = [rgb[0], rgb[1], rgb[2], 255];
|
m = m.cbrt();
|
||||||
|
s = s.cbrt();
|
||||||
|
|
||||||
|
color[0] = 0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s;
|
||||||
|
color[1] = 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s;
|
||||||
|
color[2] = 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oklch_to_rgb(color: &mut [f64; 4]) {
|
||||||
|
let mut l = color[0] + 0.3963377774 * color[1] + 0.2158037573 * color[2];
|
||||||
|
let mut m = color[0] - 0.1055613458 * color[1] - 0.0638541728 * color[2];
|
||||||
|
let mut s = color[0] - 0.0894841775 * color[1] - 1.2914855480 * color[2];
|
||||||
|
|
||||||
|
l = l.powi(3);
|
||||||
|
m = m.powi(3);
|
||||||
|
s = s.powi(3);
|
||||||
|
|
||||||
|
color[0] = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
|
||||||
|
color[1] = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
|
||||||
|
color[2] = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shift_hue_by(color: &mut [f64; 4], diff: f64) {
|
||||||
|
let tau = std::f64::consts::TAU;
|
||||||
|
let diff = tau * diff / 360.0;
|
||||||
|
let c = (color[1].powi(2) + color[2].powi(2)).sqrt();
|
||||||
|
let hue = color[2].atan2(color[1]);
|
||||||
|
let mut new_hue = (hue + diff) % tau;
|
||||||
|
if new_hue.is_sign_negative() {
|
||||||
|
new_hue += tau;
|
||||||
|
}
|
||||||
|
color[1] = c * new_hue.cos();
|
||||||
|
color[2] = c * new_hue.sin();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shift_hue(diff: f64, color: &mut [f64; 4]) {
|
||||||
|
rgb_to_oklch(color);
|
||||||
|
shift_hue_by(color, diff);
|
||||||
|
oklch_to_rgb(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn player_skin_display_color_picker(
|
pub fn player_skin_display_color_picker(
|
||||||
|
@ -149,10 +190,10 @@ pub fn player_skin_display_color_picker(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color_picker(ui: &mut Ui, color: &mut [u8; 4]) {
|
pub fn color_picker(ui: &mut Ui, color: &mut [f64; 4]) {
|
||||||
let mut rgb = Color32::from_rgb(color[0], color[1], color[2]);
|
let mut rgb = Color32::from_rgb(color[0] as u8, color[1] as u8, color[2] as u8);
|
||||||
color_picker_color32(ui, &mut rgb, Alpha::Opaque);
|
color_picker_color32(ui, &mut rgb, Alpha::Opaque);
|
||||||
*color = [rgb.r(), rgb.g(), rgb.b(), 255]
|
*color = [rgb.r() as f64, rgb.g() as f64, rgb.b() as f64, 255.0]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn player_select_current_color_slot(ui: &mut Ui, app: &mut App) {
|
pub fn player_select_current_color_slot(ui: &mut Ui, app: &mut App) {
|
||||||
|
@ -258,30 +299,30 @@ pub fn create_player_png(
|
||||||
let mut img = image::open(player_path).unwrap().into_rgba8();
|
let mut img = image::open(player_path).unwrap().into_rgba8();
|
||||||
replace_color(
|
replace_color(
|
||||||
&mut img,
|
&mut img,
|
||||||
Rgba::from(rgb.player_main),
|
Rgba::from(to_u8(rgb.player_main)),
|
||||||
Rgba::from(rgb.player_alt),
|
Rgba::from(to_u8(rgb.player_alt)),
|
||||||
Rgba::from(rgb.player_arm),
|
Rgba::from(to_u8(rgb.player_arm)),
|
||||||
);
|
);
|
||||||
let mut img_arrow = image::open(arrows_path).unwrap().into_rgba8();
|
let mut img_arrow = image::open(arrows_path).unwrap().into_rgba8();
|
||||||
replace_color(
|
replace_color(
|
||||||
&mut img_arrow,
|
&mut img_arrow,
|
||||||
Rgba::from(rgb.player_main),
|
Rgba::from(to_u8(rgb.player_main)),
|
||||||
Rgba::from(rgb.player_alt),
|
Rgba::from(to_u8(rgb.player_alt)),
|
||||||
Rgba::from(rgb.player_arm),
|
Rgba::from(to_u8(rgb.player_arm)),
|
||||||
);
|
);
|
||||||
let mut img_ping = image::open(ping_path).unwrap().into_rgba8();
|
let mut img_ping = image::open(ping_path).unwrap().into_rgba8();
|
||||||
replace_color(
|
replace_color(
|
||||||
&mut img_ping,
|
&mut img_ping,
|
||||||
Rgba::from(rgb.player_main),
|
Rgba::from(to_u8(rgb.player_main)),
|
||||||
Rgba::from(rgb.player_alt),
|
Rgba::from(to_u8(rgb.player_alt)),
|
||||||
Rgba::from(rgb.player_arm),
|
Rgba::from(to_u8(rgb.player_arm)),
|
||||||
);
|
);
|
||||||
let mut img_cursor = image::open(cursor_path).unwrap().into_rgba8();
|
let mut img_cursor = image::open(cursor_path).unwrap().into_rgba8();
|
||||||
replace_color(
|
replace_color(
|
||||||
&mut img_cursor,
|
&mut img_cursor,
|
||||||
Rgba::from(rgb.player_main),
|
Rgba::from(to_u8(rgb.player_main)),
|
||||||
Rgba::from(rgb.player_alt),
|
Rgba::from(to_u8(rgb.player_alt)),
|
||||||
Rgba::from(rgb.player_arm),
|
Rgba::from(to_u8(rgb.player_arm)),
|
||||||
);
|
);
|
||||||
let path = tmp_path.join(format!("tmp/{}.png", id));
|
let path = tmp_path.join(format!("tmp/{}.png", id));
|
||||||
img.save(path).unwrap();
|
img.save(path).unwrap();
|
||||||
|
@ -291,7 +332,7 @@ pub fn create_player_png(
|
||||||
img_ping.save(path).unwrap();
|
img_ping.save(path).unwrap();
|
||||||
let path = tmp_path.join(format!("tmp/{}_cursor.png", id));
|
let path = tmp_path.join(format!("tmp/{}_cursor.png", id));
|
||||||
img_cursor.save(path).unwrap();
|
img_cursor.save(path).unwrap();
|
||||||
let img = create_arm(Rgba::from(rgb.player_forearm));
|
let img = create_arm(Rgba::from(to_u8(rgb.player_forearm)));
|
||||||
let path = tmp_path.join(format!("tmp/{}_arm.png", id));
|
let path = tmp_path.join(format!("tmp/{}_arm.png", id));
|
||||||
img.save(path).unwrap();
|
img.save(path).unwrap();
|
||||||
edit_nth_line(
|
edit_nth_line(
|
||||||
|
@ -301,10 +342,10 @@ pub fn create_player_png(
|
||||||
.into_os_string(),
|
.into_os_string(),
|
||||||
vec![16, 16],
|
vec![16, 16],
|
||||||
vec![
|
vec![
|
||||||
format!("cloth_color=\"0xFF{}\"", rgb_to_hex(rgb.player_cape)),
|
format!("cloth_color=\"0xFF{}\"", rgb_to_hex(to_u8(rgb.player_cape))),
|
||||||
format!(
|
format!(
|
||||||
"cloth_color_edge=\"0xFF{}\"",
|
"cloth_color_edge=\"0xFF{}\"",
|
||||||
rgb_to_hex(rgb.player_cape_edge)
|
rgb_to_hex(to_u8(rgb.player_cape_edge))
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue