Skip to content

Commit ebf1511

Browse files
committed
Copy texture to clipboard from context menu
1 parent b365e67 commit ebf1511

File tree

6 files changed

+324
-44
lines changed

6 files changed

+324
-44
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ either = "1.10.0"
4545
tokio = { version = "1.37.0", features = ["rt", "macros"] }
4646
image = { version = "0.25.1", features = ["png"], default-features = false }
4747
regex = "1.10.4"
48+
clipboard-win = "5.3.1"
4849

4950
[profile.dev]
5051
opt-level = 3

src/gui/common.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@ use std::fs::File;
22

33
use destiny_pkg::{TagHash, TagHash64};
44
use eframe::egui;
5+
use image::ImageFormat;
6+
use lazy_static::lazy_static;
57
use log::{error, info, warn};
6-
use std::io::Write;
8+
use std::io::{Cursor, Write};
9+
use std::num::NonZeroU32;
710

811
use crate::{packages::package_manager, tagtypes::TagType};
912

10-
use super::texture::TextureCache;
13+
use super::texture::{Texture, TextureCache};
14+
15+
lazy_static! {
16+
static ref CF_PNG: NonZeroU32 = clipboard_win::register_format("PNG").unwrap();
17+
static ref CF_FILENAME: NonZeroU32 = clipboard_win::register_format("FileNameW").unwrap();
18+
}
1119

1220
pub trait ResponseExt {
1321
fn tag_context(&self, tag: TagHash, tag64: Option<TagHash64>) -> &Self;
@@ -34,7 +42,46 @@ impl ResponseExt for egui::Response {
3442
texture_cache: &TextureCache,
3543
is_texture: bool,
3644
) -> Self {
37-
self.context_menu(|ui| tag_context(ui, tag, tag64));
45+
self.context_menu(|ui| {
46+
if is_texture {
47+
if ui.selectable_label(false, "📷 Copy texture").clicked() {
48+
match Texture::load(&texture_cache.render_state, tag, false) {
49+
Ok(o) => {
50+
let image = o.to_image(&texture_cache.render_state).unwrap();
51+
let mut png_data = vec![];
52+
let mut png_writer = Cursor::new(&mut png_data);
53+
image.write_to(&mut png_writer, ImageFormat::Png).unwrap();
54+
55+
let _clipboard = clipboard_win::Clipboard::new();
56+
if let Err(e) = clipboard_win::raw::set(CF_PNG.get(), &png_data) {
57+
error!("Failed to copy texture to clipboard: {e}");
58+
}
59+
60+
// Save to temp
61+
let path = std::env::temp_dir().join(format!("{tag}.png"));
62+
let mut file = File::create(&path).unwrap();
63+
file.write_all(&png_data).unwrap();
64+
65+
let mut path_utf16 =
66+
path.to_string_lossy().encode_utf16().collect::<Vec<u16>>();
67+
path_utf16.push(0);
68+
69+
if let Err(e) = clipboard_win::raw::set_without_clear(
70+
CF_FILENAME.get(),
71+
bytemuck::cast_slice(&path_utf16),
72+
) {
73+
error!("Failed to copy texture path to clipboard: {e}");
74+
}
75+
}
76+
Err(e) => {
77+
error!("Failed to load texture: {e}");
78+
}
79+
}
80+
ui.close_menu();
81+
}
82+
}
83+
tag_context(ui, tag, tag64);
84+
});
3885
if is_texture {
3986
self.on_hover_ui(|ui| {
4087
texture_cache.texture_preview(tag, ui);

src/gui/shaders/copy.wgsl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
struct VertexOutput {
2+
@builtin(position) position: vec4<f32>,
3+
@location(0) uv: vec2<f32>,
4+
}
5+
6+
@group(0) @binding(0)
7+
var t: texture_2d<f32>;
8+
9+
@group(0) @binding(1)
10+
var s: sampler;
11+
12+
@vertex
13+
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput {
14+
var out: VertexOutput;
15+
out.uv = vec2<f32>(0.0);
16+
out.uv.x = select(0.0, 2.0, in_vertex_index == 1u);
17+
out.uv.y = select(0.0, 2.0, in_vertex_index == 2u);
18+
out.position = vec4<f32>(out.uv * vec2<f32>(2.0, -2.0) + vec2<f32>(-1.0, 1.0), 1.0, 1.0);
19+
return out;
20+
}
21+
22+
@fragment
23+
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
24+
return textureSample(t, s, in.uv);
25+
}

src/gui/tag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl TagView {
215215
let scan = ExtendedScanResult::from_scanresult(cache.hashes.get(&tag).cloned()?);
216216

217217
let texture = if tag_type.is_texture() && tag_type.is_header() {
218-
Texture::load(&render_state, tag).map(|t| {
218+
Texture::load(&render_state, tag, true).map(|t| {
219219
let egui_handle = render_state.renderer.write().register_native_texture(
220220
&render_state.device,
221221
&t.view,

0 commit comments

Comments
 (0)