forked from 1b-agent/opencadstudio-upstream
DWF and DGN underlays: attach, display, snaps, frames and references
DWFATTACH / -DWFATTACH and DGNATTACH / -DGNATTACH attach a DWF / DWFx sheet or a DGN (V7 or V8) model with the reference's prompts; ATTACH routes the file types to them. The sheet or model is read into vector paths, drawn as a transparent underlay raster (contrast, fade, monochrome and background adjustment apply) and offers its geometry to object snaps. Definitions are kept in ACAD_DWFDEFINITIONS / ACAD_DGNDEFINITIONS, the External References palette lists and reloads them, and image textures get line-keeping mip levels so thin underlay lines stay visible when zoomed out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7f8f8457c7
commit
cb7860e50e
46 files changed
+2723
-129
No files matched your search
@@ -220,6 +220,7 @@ impl ImageGpu {
|
||||
"image.texture:{}:{}:{}",
|
||||
model.file_path, x.content_start, y.content_start
|
||||
);
|
||||
let levels = mip_chain(&model.pixels, model.width, x.data_start, y.data_start, width, height);
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some(&tex_label),
|
||||
size: wgpu::Extent3d {
|
||||
@@ -227,7 +228,7 @@ impl ImageGpu {
|
||||
height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
mip_level_count: levels.len() as u32,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
@@ -235,22 +236,27 @@ impl ImageGpu {
|
||||
| wgpu::TextureUsages::COPY_DST,
|
||||
view_formats: &[],
|
||||
});
|
||||
queue.write_texture(
|
||||
texture.as_image_copy(),
|
||||
&model.pixels[((y.data_start as usize * model.width as usize
|
||||
+ x.data_start as usize)
|
||||
* 4)..],
|
||||
wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(4 * model.width),
|
||||
rows_per_image: Some(model.height),
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width,
|
||||
height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
for (level, (w, h, data)) in levels.iter().enumerate() {
|
||||
queue.write_texture(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: &texture,
|
||||
mip_level: level as u32,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
data,
|
||||
wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(4 * w),
|
||||
rows_per_image: Some(*h),
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: *w,
|
||||
height: *h,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
}
|
||||
let tex_view =
|
||||
texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
@@ -302,6 +308,52 @@ struct TileRange {
|
||||
data_end: u32,
|
||||
}
|
||||
|
||||
/// A tile's pixels and its smaller levels down to 1×1, so a far view
|
||||
/// samples a level near its own size. A level keeps the most opaque of each
|
||||
/// 2×2 block unless all four are equally opaque (then their average): thin
|
||||
/// lines on a transparent page (PDF, DWF, DGN underlays) stay visible when
|
||||
/// zoomed out instead of falling between samples, and opaque images are
|
||||
/// averaged as usual.
|
||||
fn mip_chain(pixels: &[u8], stride: u32, x0: u32, y0: u32, w: u32, h: u32) -> Vec<(u32, u32, Vec<u8>)> {
|
||||
let (stride, x0, y0) = (stride as usize, x0 as usize, y0 as usize);
|
||||
let mut base = Vec::with_capacity(w as usize * h as usize * 4);
|
||||
for row in 0..h as usize {
|
||||
let start = ((y0 + row) * stride + x0) * 4;
|
||||
base.extend_from_slice(&pixels[start..start + w as usize * 4]);
|
||||
}
|
||||
let mut levels = vec![(w, h, base)];
|
||||
loop {
|
||||
let (pw, ph, prev) = levels.last().expect("base level");
|
||||
if *pw == 1 && *ph == 1 {
|
||||
break;
|
||||
}
|
||||
let (pw, ph) = (*pw as usize, *ph as usize);
|
||||
let (nw, nh) = ((pw / 2).max(1), (ph / 2).max(1));
|
||||
let mut next = Vec::with_capacity(nw * nh * 4);
|
||||
for y in 0..nh {
|
||||
for x in 0..nw {
|
||||
let block = [(0, 0), (1, 0), (0, 1), (1, 1)].map(|(dx, dy)| {
|
||||
let at = (((2 * y + dy).min(ph - 1)) * pw + (2 * x + dx).min(pw - 1)) * 4;
|
||||
[prev[at], prev[at + 1], prev[at + 2], prev[at + 3]]
|
||||
});
|
||||
if block.iter().all(|p| p[3] == block[0][3]) {
|
||||
let mut sum = [0u32; 4];
|
||||
for p in &block {
|
||||
for c in 0..4 {
|
||||
sum[c] += p[c] as u32;
|
||||
}
|
||||
}
|
||||
next.extend(sum.map(|v| ((v + 2) / 4) as u8));
|
||||
} else {
|
||||
next.extend(*block.iter().max_by_key(|p| p[3]).expect("four pixels"));
|
||||
}
|
||||
}
|
||||
}
|
||||
levels.push((nw as u32, nh as u32, next));
|
||||
}
|
||||
levels
|
||||
}
|
||||
|
||||
fn tile_ranges(size: u32, limit: u32) -> Vec<TileRange> {
|
||||
if size <= limit {
|
||||
return vec![TileRange {
|
||||
|
||||
Reference in new issue
Block a user