diff --git a/index.pug b/index.pug index d161e67..be17ae4 100644 --- a/index.pug +++ b/index.pug @@ -62,6 +62,12 @@ html(lang="en-gb") | palette select#palette + #new-palette(style="display: none;") + .half + input#colour-background(type="color" value="#2f4ac9") + .half + input#colour-foreground(type="color" value="#8798fe") + label input#dither(type="checkbox" checked=true) | dither diff --git a/script.js b/script.js index 66d12b8..28c46e6 100644 --- a/script.js +++ b/script.js @@ -72,7 +72,10 @@ async function run() { const buttonNewGame = el("new"); const buttonReset = el("reset"); const checkboxDither = el("dither"); + const divNewPalette = el("new-palette"); const inputBrightness = el("brightness"); + const inputColourBackground = el("colour-background"); + const inputColourForeground = el("colour-foreground"); const inputRoomName = el("room-name"); const selectPalette = el("palette"); const textareaGameDataInput = el("game-data"); @@ -126,6 +129,11 @@ async function run() { selectPalette.innerHTML = ""; + palettes.push({ + id: "NEW_PALETTE", + name: "new palette" + }); + for (let palette of palettes) { let option = document.createElement("option"); @@ -174,10 +182,25 @@ async function run() { buttonImageProceed.addEventListener("touchend", handleImage); selectPalette.addEventListener("change", () => { - set_palette(selectPalette.value); + set_palette(selectPalette.value, inputColourBackground.value, inputColourForeground.value); + + if (selectPalette.value === "NEW_PALETTE") { + divNewPalette.style.display = "block"; + } else { + divNewPalette.style.display = "none"; + } + loadPreview(); }); + function updateCustomPalette() { + set_palette(selectPalette.value, inputColourBackground.value, inputColourForeground.value); + loadPreview(); + } + + inputColourForeground.addEventListener("change", updateCustomPalette); + inputColourBackground.addEventListener("change", updateCustomPalette); + checkboxDither.addEventListener("change", () => { set_dither(checkboxDither.checked); loadPreview(); diff --git a/src/lib.rs b/src/lib.rs index 9a6ceaf..5d42374 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,11 +16,22 @@ use colour_map::ColourMap; const SD: u32 = 8; +enum SelectedPalette { + None, + Existing { + id: String, + }, + New { + background: bitsy_parser::Colour, + foreground: bitsy_parser::Colour, + } +} + struct State { game: Option, image: Option, room_name: Option, - palette: Option, + palette: SelectedPalette, dither: bool, brightness: i32, } @@ -31,7 +42,7 @@ lazy_static! { game: None, image: None, room_name: None, - palette: None, + palette: SelectedPalette::None, dither: true, brightness: 0, } @@ -49,8 +60,13 @@ fn tile_name(prefix: &Option, index: &u32) -> Option { #[wasm_bindgen] pub fn load_default_game() { let mut state = STATE.lock().unwrap(); + state.game = Some(bitsy_parser::mock::game_default()); - state.palette = Some(bitsy_parser::mock::game_default().palette_ids()[0].clone()) + + // yes, this will probably always just be "0", but to be safeā€¦ + state.palette = SelectedPalette::Existing { + id: bitsy_parser::mock::game_default().palette_ids()[0].clone() + } } #[wasm_bindgen] @@ -63,12 +79,12 @@ pub fn load_game(game_data: String) -> String { Ok((game, _errs)) => { let palette_id = game.palette_ids()[0].clone(); state.game = Some(game); - state.palette = Some(palette_id); + state.palette = SelectedPalette::Existing { id: palette_id }; format!("Loaded game") }, _ => { state.game = None; - state.palette = None; + state.palette = SelectedPalette::None; format!("{}", result.err().unwrap()) } } @@ -110,12 +126,16 @@ pub fn set_dither(dither: bool) { } #[wasm_bindgen] -pub fn set_palette(palette_id: String) { +pub fn set_palette(palette_id: &str, background: String, foreground: String) { let mut state = STATE.lock().unwrap(); - match palette_id.is_empty() { - true => { state.palette = None }, - false => { state.palette = Some(palette_id) }, + state.palette = match palette_id { + "NEW_PALETTE" => SelectedPalette::New { + background: bitsy_parser::Colour::from_hex(&background).unwrap(), + foreground: bitsy_parser::Colour::from_hex(&foreground).unwrap(), + }, + "" => SelectedPalette::None, + _ => SelectedPalette::Existing { id: palette_id.to_string() }, } } @@ -166,10 +186,22 @@ fn image_to_base64(image: &DynamicImage) -> String { fn render_preview(state: &State) -> DynamicImage { let mut buffer = state.image.as_ref().unwrap().clone().into_rgba(); - let palette_id = state.palette.as_ref().unwrap(); - let palette = *&state.game.as_ref().unwrap().get_palette(palette_id).unwrap(); - let colour_map = crate::ColourMap::from(palette); + let palette = match &state.palette { + SelectedPalette::None => bitsy_parser::mock::game_default().palettes[0].clone(), + SelectedPalette::Existing { id } => state.game.as_ref().unwrap().get_palette(id).unwrap().clone(), + SelectedPalette::New { background, foreground } => Palette { + id: "0".to_string(), + name: None, + colours: vec![ + background.clone(), foreground.clone(), Colour { red: 0, green: 0, blue: 0 } + ], + }, + }; + + let colour_map = crate::ColourMap::from(&palette); + + // adjust brightness let mut buffer = image::imageops::brighten(&mut buffer, state.brightness); if state.dither {