diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 8b7dd9902..7add46a5d 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -3803,6 +3803,9 @@ insert = .xref-old-path-prefix = بادئة المسار القديم .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 3d88014b0..c7fb5e456 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = стар префикс на път .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 67aaf37cf..c585c046b 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -3788,6 +3788,9 @@ insert = .xref-old-path-prefix = stará předpona cesty .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index f32c9ba95..3b2fe629e 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -3789,6 +3789,9 @@ insert = .xref-old-path-prefix = alte Pfadpräfix .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 1729d534a..e3cb58071 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -3801,6 +3801,9 @@ insert = .xref-old-path-prefix = old path prefix .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 05e319474..8fba57187 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -3802,6 +3802,9 @@ insert = .xref-old-path-prefix = old path prefix .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 92fd93eff..6d5500dae 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -3791,6 +3791,9 @@ insert = .xref-old-path-prefix = prefijo de ruta antiguo .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 058b1a6a5..da2de7a81 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = vanha polun etuliite .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 7607d15b3..899c9b245 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -3791,6 +3791,9 @@ insert = .xref-old-path-prefix = ancien préfixe de chemin .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 4929071d4..ea5c4c076 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -3779,6 +3779,9 @@ insert = .xref-old-path-prefix = पुराना पथ उपसर्ग .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 08ce8b3d0..d59408b22 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = régi útvonal-előtag .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 1994c37d3..c66383d3f 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = vecchio prefisso percorso .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index d9daa920a..2cbbdba5b 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -3779,6 +3779,9 @@ insert = .xref-old-path-prefix = 古いパスプレフィックス .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 8a537142a..fcb1ba020 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = 이전 경로 접두어 .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 314a83d35..bbfb0bbb2 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -3789,6 +3789,9 @@ insert = .xref-old-path-prefix = oud padprefix .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index ef384bbc5..5f625c4de 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -3790,6 +3790,9 @@ insert = .xref-old-path-prefix = stary prefiks ścieżki .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index cb5ea8a3e..d6ecda397 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -3792,6 +3792,9 @@ insert = .xref-old-path-prefix = prefixo de caminho antigo .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 42a3d5334..9235e6a4d 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -3792,6 +3792,9 @@ insert = .xref-old-path-prefix = старый префикс пути .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index eb92c4bcb..49c6d8870 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -3758,6 +3758,9 @@ insert = .xref-old-path-prefix = eski yol öneki .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Görüntüleri seçin: + .transparency-mode-on = Saydamlık modunu girin [ON/OFF] : + .transparency-mode-off = Saydamlık modunu girin [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 828fc7429..6780264a2 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -3774,6 +3774,9 @@ insert = .xref-old-path-prefix = 旧路径前缀 .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index bbf1928ca..810b88978 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -3786,6 +3786,9 @@ insert = .xref-old-path-prefix = 舊路徑前綴 .xref-attach-dwg = Attach DWG .xref-attach-image = Attach Image + .select-images = Select image(s): + .transparency-mode-on = Enter transparency mode [ON/OFF] : + .transparency-mode-off = Enter transparency mode [ON/OFF] : .xref-attach-menu = Attach... .xref-change-path-type = Change Path Type .xref-find-and-replace-menu = Find and Replace... diff --git a/src/app/commands/display.rs b/src/app/commands/display.rs index 7fddf031d..2f00501d6 100644 --- a/src/app/commands/display.rs +++ b/src/app/commands/display.rs @@ -929,6 +929,55 @@ impl OpenCADStudio { } } } + // TRANSPARENCY — raster images show transparent pixels (ON) or + // draw every pixel in its colour (OFF). + "TRANSPARENCY" => { + let c = crate::modules::insert::image_transparency::TransparencyCommand::new(); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + } + "TRANSPARENCY MODE" | "TRANSPARENCY ON" | "TRANSPARENCY OFF" => { + use codec::entities::ImageDisplayFlags; + let images: Vec<(codec::Handle, bool)> = self.tabs[i] + .scene + .selected_entities() + .iter() + .filter(|(handle, _)| !self.tabs[i].scene.is_layer_locked(*handle)) + .filter_map(|(handle, _)| match self.tabs[i].scene.document.get_entity(*handle) { + Some(codec::EntityType::RasterImage(image)) => { + Some((*handle, image.flags.contains(ImageDisplayFlags::TRANSPARENCY_ON))) + } + _ => None, + }) + .collect(); + let Some(&(_, first_on)) = images.first() else { + return Some(Task::none()); + }; + let handles: Vec = images.iter().map(|(handle, _)| *handle).collect(); + if cmd == "TRANSPARENCY MODE" { + let c = crate::modules::insert::image_transparency::TransparencyCommand::mode( + handles, first_on, + ); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + } else { + let on = cmd == "TRANSPARENCY ON"; + self.push_undo_snapshot(i, "TRANSPARENCY"); + for handle in &handles { + if let Some(codec::EntityType::RasterImage(image)) = + self.tabs[i].scene.document.get_entity_mut(*handle) + { + image.flags.set(ImageDisplayFlags::TRANSPARENCY_ON, on); + } + } + let changes: Vec<_> = handles + .iter() + .map(|handle| (*handle, crate::scene::ChangeKind::Modified)) + .collect(); + self.tabs[i].scene.bump_entities(&changes); + self.tabs[i].dirty = true; + } + } // UNDERLAY — edit properties of selected PDF/DWF/DGN underlay entities. // Usage: // UNDERLAY FADE <0-80> diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index eb9a7a4b1..4f819ae37 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -714,6 +714,7 @@ inventory::submit!(crate::command::CommandRegistration { "IM", "IMAGE", "IMAGEATTACH", + "TRANSPARENCY", "IMAGEEMBED", "IMPORTOBJ", "ISOLATEOBJECTS", diff --git a/src/io/pdf_export.rs b/src/io/pdf_export.rs index 7e9d44269..3f1810a68 100644 --- a/src/io/pdf_export.rs +++ b/src/io/pdf_export.rs @@ -242,8 +242,10 @@ fn emit_image( { return Err("Cannot plot bitmap: invalid coordinates, clip boundary, or opacity.".into()); } + // The low bit (free: the pixel buffer is aligned) keeps the opaque copy + // of a picture apart from its transparent one. let key = ( - std::sync::Arc::as_ptr(&image.pixels) as usize, + std::sync::Arc::as_ptr(&image.pixels) as usize | usize::from(!image.use_alpha), image.width, image.height, ); @@ -255,7 +257,14 @@ fn emit_image( doc.resources.xobjects.map.insert( id.clone(), printpdf::XObject::Image(printpdf::RawImage { - pixels: printpdf::RawImageData::U8(image.pixels.as_ref().clone()), + pixels: printpdf::RawImageData::U8(if image.use_alpha { + image.pixels.as_ref().clone() + } else { + // Transparency off: every pixel opaque in its colour. + let mut opaque = image.pixels.as_ref().clone(); + opaque.chunks_exact_mut(4).for_each(|px| px[3] = 255); + opaque + }), width: image.width as usize, height: image.height as usize, data_format: printpdf::RawImageFormat::RGBA8, diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 92edc4613..d2150f076 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -3303,6 +3303,9 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "File References" => Some(("insert", "xref-file-references")), "Attach DWG" => Some(("insert", "xref-attach-dwg")), "Attach Image" => Some(("insert", "xref-attach-image")), + "Select image(s):" => Some(("insert", "select-images")), + "Enter transparency mode [ON/OFF] :" => Some(("insert", "transparency-mode-on")), + "Enter transparency mode [ON/OFF] :" => Some(("insert", "transparency-mode-off")), "Attach..." => Some(("insert", "xref-attach-menu")), "Change Path Type" => Some(("insert", "xref-change-path-type")), "Find and Replace..." => Some(("insert", "xref-find-and-replace-menu")), diff --git a/src/modules/insert/image_transparency.rs b/src/modules/insert/image_transparency.rs new file mode 100644 index 000000000..cdf22a30c --- /dev/null +++ b/src/modules/insert/image_transparency.rs @@ -0,0 +1,93 @@ +// TRANSPARENCY — whether raster images show their transparent pixels as +// transparent or draw every pixel in its stored colour. +// +// Select image(s): +// Enter transparency mode [ON/OFF] : (the default is the first +// image's current mode) + +use codec::Handle; +use glam::DVec3; + +use crate::command::{CadCommand, CmdOption, CmdResult}; + +pub struct TransparencyCommand { + handles: Vec, + /// `None` while images are being selected; then the default mode. + default_on: Option, +} + +impl TransparencyCommand { + pub fn new() -> Self { + Self { handles: Vec::new(), default_on: None } + } + + /// The mode prompt for images already chosen. + pub fn mode(handles: Vec, default_on: bool) -> Self { + Self { handles, default_on: Some(default_on) } + } + + fn apply(&mut self, on: bool) -> CmdResult { + let command = if on { "TRANSPARENCY ON" } else { "TRANSPARENCY OFF" }; + CmdResult::Relaunch(command.to_string(), std::mem::take(&mut self.handles)) + } +} + +impl CadCommand for TransparencyCommand { + fn name(&self) -> &'static str { + "TRANSPARENCY" + } + + fn prompt(&self) -> String { + match self.default_on { + None => crate::t!("Select image(s):").into_owned(), + Some(true) => crate::t!("Enter transparency mode [ON/OFF] :").into_owned(), + Some(false) => crate::t!("Enter transparency mode [ON/OFF] :").into_owned(), + } + } + + fn options(&self) -> Vec { + match self.default_on { + None => Vec::new(), + Some(_) => vec![CmdOption::new("ON", "ON"), CmdOption::new("OFF", "OFF")], + } + } + + fn is_selection_gathering(&self) -> bool { + self.default_on.is_none() + } + + fn wants_text_input(&self) -> bool { + self.default_on.is_some() + } + + fn on_selection_complete(&mut self, handles: Vec) -> CmdResult { + self.handles = handles; + CmdResult::NeedPoint + } + + fn on_text_input(&mut self, text: &str) -> Option { + let default_on = self.default_on?; + Some(match text.trim().to_uppercase().as_str() { + "" => self.apply(default_on), + "ON" => self.apply(true), + "OFF" => self.apply(false), + _ => CmdResult::ReportError("Invalid option keyword.".to_string()), + }) + } + + fn on_point(&mut self, _pt: DVec3) -> CmdResult { + CmdResult::NeedPoint + } + + fn on_enter(&mut self) -> CmdResult { + match self.default_on { + None if self.handles.is_empty() => CmdResult::Cancel, + // The app keeps only the images and asks for the mode. + None => CmdResult::Relaunch( + "TRANSPARENCY MODE".to_string(), + std::mem::take(&mut self.handles), + ), + Some(on) => self.apply(on), + } + } +} diff --git a/src/modules/insert/mod.rs b/src/modules/insert/mod.rs index e157971ca..0e3393464 100644 --- a/src/modules/insert/mod.rs +++ b/src/modules/insert/mod.rs @@ -9,6 +9,7 @@ mod content_browser; pub(crate) mod create_block; mod design_center; mod edit_block; +pub(crate) mod image_transparency; pub(crate) mod insert_block; mod landxml; pub(crate) mod picker; diff --git a/src/scene/model/image_model.rs b/src/scene/model/image_model.rs index 5fbd58802..1e312100e 100644 --- a/src/scene/model/image_model.rs +++ b/src/scene/model/image_model.rs @@ -94,6 +94,9 @@ pub struct ImageModel { /// Magnified pixels stay square (raster images); otherwise they blend /// (PDF pages, OLE pictures). pub pixelated: bool, + /// Pixel alpha applies. A raster image whose transparency is off draws + /// every pixel opaque in its stored colour. + pub use_alpha: bool, } impl ImageModel { @@ -165,6 +168,9 @@ impl ImageModel { draw_depth: 0.0, verts, pixelated: true, + use_alpha: img + .flags + .contains(codec::entities::ImageDisplayFlags::TRANSPARENCY_ON), }) } } @@ -274,6 +280,7 @@ impl ImageModel { draw_depth: 0.0, verts, pixelated: false, + use_alpha: true, }) } } @@ -355,6 +362,7 @@ impl ImageModel { draw_depth: 0.0, verts, pixelated: false, + use_alpha: true, }) } } diff --git a/src/scene/pipeline/image_gpu.rs b/src/scene/pipeline/image_gpu.rs index 196c3f830..4a6ecd3f3 100644 --- a/src/scene/pipeline/image_gpu.rs +++ b/src/scene/pipeline/image_gpu.rs @@ -79,7 +79,9 @@ struct ImageParams { /// Signed draw-order depth (-1,1); applied as a clip-z bias in the shader /// so the raster orders against other entity types. 0.0 = neutral. draw_depth: f32, - _pad: [f32; 2], + /// 1.0 when pixel alpha applies, 0.0 when pixels draw opaque. + use_alpha: f32, + _pad: f32, } // 16 bytes // ── Per-image GPU handle ────────────────────────────────────────────────── @@ -196,7 +198,8 @@ impl ImageGpu { let params = ImageParams { opacity: model.opacity.clamp(0.0, 1.0), draw_depth: 0.0, - _pad: [0.0; 2], + use_alpha: if model.use_alpha { 1.0 } else { 0.0 }, + _pad: 0.0, }; let params_buf = Arc::new(super::gpu_upload::upload_buffer( device, diff --git a/src/shaders/image.wgsl b/src/shaders/image.wgsl index ca7860aa7..b8af298c4 100644 --- a/src/shaders/image.wgsl +++ b/src/shaders/image.wgsl @@ -28,7 +28,7 @@ struct Uniforms { struct ImageParams { opacity: f32, draw_depth: f32, // signed (-1,1) draw-order bias; 0 = neutral - _pad1: f32, + use_alpha: f32, // 1 = pixel alpha applies, 0 = pixels draw opaque _pad2: f32, }; @group(1) @binding(2) var img_params: ImageParams; @@ -63,5 +63,11 @@ fn vs_main(in: VertIn) -> VertOut { @fragment fn fs_main(in: VertOut) -> @location(0) vec4 { let col = textureSample(img_texture, img_sampler, in.uv); - return vec4(col.rgb, col.a * img_params.opacity); + let alpha = select(1.0, col.a, img_params.use_alpha > 0.5); + // A fully transparent pixel leaves no depth behind, so what lies under + // the image (drawn before or after it) shows through. + if (alpha * img_params.opacity <= 0.0) { + discard; + } + return vec4(col.rgb, alpha * img_params.opacity); }