mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
ifcviewer: move edge silhouette subsystem into ViewportCore (#84-s)
buildEdgePipeline, encodeEdgePass, releaseEdgeResources + the EDGE_WGSL shader source all move to ViewportCore. The edge_bind_group_ + the edges_enabled_ flag come along too (the latter aliased on VW so the edge-toggle keybind keeps compiling). The pass binds the now-core-side depth_view_ directly, so there's no remaining cross-side state dependency for edge rendering. render() still calls core_.encodeEdgePass(enc, surface_view) — once render() itself moves, the call collapses to a sibling method invocation.
This commit is contained in:
@@ -3447,3 +3447,179 @@ void ViewportCore::releaseMsaaColorTexture() {
|
||||
if (msaa_color_texture_) { wgpuTextureRelease(msaa_color_texture_); msaa_color_texture_ = nullptr; }
|
||||
msaa_w_ = msaa_h_ = 0;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Edge silhouette post-process (#84-s): buildEdgePipeline + encodeEdgePass +
|
||||
// releaseEdgeResources
|
||||
// ===========================================================================
|
||||
|
||||
namespace {
|
||||
|
||||
const char* EDGE_WGSL = R"(
|
||||
@group(0) @binding(0) var src_depth: texture_depth_multisampled_2d;
|
||||
|
||||
const NEAR: f32 = 0.1;
|
||||
const FAR: f32 = 10000.0;
|
||||
const EDGE_SCALE: f32 = 6.0;
|
||||
const EDGE_THRESHOLD: f32 = 0.004;
|
||||
|
||||
// Depth texture stores [0,1] z (we pre-multiply a z-remap onto Qt's GL-style
|
||||
// projection in the main pipeline). Convert back to GL-NDC then reverse-
|
||||
// project to view-space distance.
|
||||
fn linearise(z: f32) -> f32 {
|
||||
let ndc = z * 2.0 - 1.0;
|
||||
return (2.0 * NEAR * FAR) / (FAR + NEAR - ndc * (FAR - NEAR));
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4<f32> {
|
||||
let x = f32((vid << 1u) & 2u) * 2.0 - 1.0;
|
||||
let y = f32(vid & 2u) * 2.0 - 1.0;
|
||||
return vec4<f32>(x, y, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(@builtin(position) frag: vec4<f32>) -> @location(0) vec4<f32> {
|
||||
let p = vec2<i32>(i32(frag.x), i32(frag.y));
|
||||
let dim = vec2<i32>(textureDimensions(src_depth));
|
||||
|
||||
let dc_raw = textureLoad(src_depth, p, 0);
|
||||
// Background pixels: nothing was drawn here. Skip so we don't draw
|
||||
// edges on the void / sky.
|
||||
if (dc_raw >= 0.99999) { discard; }
|
||||
|
||||
let c = linearise(dc_raw);
|
||||
let n = linearise(textureLoad(src_depth, vec2<i32>(p.x, max(p.y - 1, 0)), 0));
|
||||
let s = linearise(textureLoad(src_depth, vec2<i32>(p.x, min(p.y + 1, dim.y - 1)), 0));
|
||||
let e = linearise(textureLoad(src_depth, vec2<i32>(min(p.x + 1, dim.x - 1), p.y), 0));
|
||||
let w = linearise(textureLoad(src_depth, vec2<i32>(max(p.x - 1, 0), p.y), 0));
|
||||
|
||||
let lap = abs(4.0 * c - n - s - e - w);
|
||||
let t = EDGE_THRESHOLD * c;
|
||||
let edge = clamp((lap - t) * EDGE_SCALE, 0.0, 0.6);
|
||||
|
||||
// Multiplicative blend (Dst, Zero): output rgb = (1 - edge), so the
|
||||
// existing surface colour is multiplied by (1 - edge) per channel.
|
||||
return vec4<f32>(vec3<f32>(1.0 - edge), 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ViewportCore::buildEdgePipeline() {
|
||||
WGPUBindGroupLayoutEntry entries[1] = {};
|
||||
entries[0].binding = 0;
|
||||
entries[0].visibility = WGPUShaderStage_Fragment;
|
||||
entries[0].texture.sampleType = WGPUTextureSampleType_Depth;
|
||||
entries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
|
||||
entries[0].texture.multisampled = 1;
|
||||
|
||||
WGPUBindGroupLayoutDescriptor bgl_desc = {};
|
||||
bgl_desc.entryCount = 1;
|
||||
bgl_desc.entries = entries;
|
||||
bgl_desc.label = svFromCStr("ifcviewer-wgpu.edge_bgl");
|
||||
edge_bgl_ = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc);
|
||||
|
||||
WGPUPipelineLayoutDescriptor pl_desc = {};
|
||||
pl_desc.bindGroupLayoutCount = 1;
|
||||
pl_desc.bindGroupLayouts = &edge_bgl_;
|
||||
pl_desc.label = svFromCStr("ifcviewer-wgpu.edge_pipeline_layout");
|
||||
edge_pipeline_layout_ = wgpuDeviceCreatePipelineLayout(device_, &pl_desc);
|
||||
|
||||
WGPUShaderSourceWGSL wgsl_src = {};
|
||||
wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL;
|
||||
wgsl_src.code = svFromCStr(EDGE_WGSL);
|
||||
WGPUShaderModuleDescriptor sm_desc = {};
|
||||
sm_desc.nextInChain = &wgsl_src.chain;
|
||||
sm_desc.label = svFromCStr("ifcviewer-wgpu.edge_wgsl");
|
||||
edge_shader_module_ = wgpuDeviceCreateShaderModule(device_, &sm_desc);
|
||||
|
||||
// Multiplicative blend (Dst, Zero): out.rgb = src.rgb * dst.rgb.
|
||||
// Fragment outputs (1 - edge, 1 - edge, 1 - edge) so the existing
|
||||
// surface colour is scaled per-channel — strictly darkens, never
|
||||
// brightens. Matches GL's renderEdgePass (GL_DST_COLOR, GL_ZERO).
|
||||
WGPUBlendState blend = {};
|
||||
blend.color.srcFactor = WGPUBlendFactor_Dst;
|
||||
blend.color.dstFactor = WGPUBlendFactor_Zero;
|
||||
blend.color.operation = WGPUBlendOperation_Add;
|
||||
blend.alpha.srcFactor = WGPUBlendFactor_Zero;
|
||||
blend.alpha.dstFactor = WGPUBlendFactor_One;
|
||||
blend.alpha.operation = WGPUBlendOperation_Add;
|
||||
|
||||
WGPUColorTargetState target = {};
|
||||
target.format = surface_format_;
|
||||
target.blend = &blend;
|
||||
target.writeMask = WGPUColorWriteMask_All;
|
||||
|
||||
WGPUFragmentState frag = {};
|
||||
frag.module = edge_shader_module_;
|
||||
frag.entryPoint = svFromCStr("fs_main");
|
||||
frag.targetCount = 1;
|
||||
frag.targets = ⌖
|
||||
|
||||
WGPURenderPipelineDescriptor rp_desc = {};
|
||||
rp_desc.layout = edge_pipeline_layout_;
|
||||
rp_desc.label = svFromCStr("ifcviewer-wgpu.edge_pipeline");
|
||||
rp_desc.vertex.module = edge_shader_module_;
|
||||
rp_desc.vertex.entryPoint = svFromCStr("vs_main");
|
||||
rp_desc.vertex.bufferCount = 0;
|
||||
rp_desc.fragment = &frag;
|
||||
rp_desc.depthStencil = nullptr; // no depth attachment
|
||||
rp_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||
rp_desc.primitive.cullMode = WGPUCullMode_None;
|
||||
rp_desc.multisample.count = 1;
|
||||
rp_desc.multisample.mask = 0xFFFFFFFFu;
|
||||
|
||||
edge_pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &rp_desc);
|
||||
if (!edge_pipeline_) {
|
||||
Log::warn() << "wgpu edge pipeline creation failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewportCore::encodeEdgePass(WGPUCommandEncoder enc,
|
||||
WGPUTextureView surface_view) {
|
||||
if (!edges_enabled_ || !edge_pipeline_ || !depth_view_ || !surface_view) return;
|
||||
|
||||
// Rebuild lazily when the underlying depth view was replaced (on
|
||||
// resize we proactively null this alongside the HiZ bind group).
|
||||
if (!edge_bind_group_) {
|
||||
WGPUBindGroupEntry entry = {};
|
||||
entry.binding = 0;
|
||||
entry.textureView = depth_view_;
|
||||
WGPUBindGroupDescriptor bg = {};
|
||||
bg.layout = edge_bgl_;
|
||||
bg.entryCount = 1;
|
||||
bg.entries = &entry;
|
||||
bg.label = svFromCStr("ifcviewer-wgpu.edge_bind_group");
|
||||
edge_bind_group_ = wgpuDeviceCreateBindGroup(device_, &bg);
|
||||
}
|
||||
|
||||
WGPURenderPassColorAttachment color = {};
|
||||
color.view = surface_view;
|
||||
color.loadOp = WGPULoadOp_Load;
|
||||
color.storeOp = WGPUStoreOp_Store;
|
||||
color.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
|
||||
|
||||
WGPURenderPassDescriptor pass_desc = {};
|
||||
pass_desc.colorAttachmentCount = 1;
|
||||
pass_desc.colorAttachments = &color;
|
||||
pass_desc.depthStencilAttachment = nullptr;
|
||||
pass_desc.label = svFromCStr("ifcviewer-wgpu.edge_pass");
|
||||
|
||||
WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(enc, &pass_desc);
|
||||
wgpuRenderPassEncoderSetPipeline(pass, edge_pipeline_);
|
||||
wgpuRenderPassEncoderSetBindGroup(pass, 0, edge_bind_group_, 0, nullptr);
|
||||
wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
|
||||
wgpuRenderPassEncoderEnd(pass);
|
||||
wgpuRenderPassEncoderRelease(pass);
|
||||
}
|
||||
|
||||
void ViewportCore::releaseEdgeResources() {
|
||||
if (edge_bind_group_) { wgpuBindGroupRelease(edge_bind_group_); edge_bind_group_ = nullptr; }
|
||||
if (edge_pipeline_) { wgpuRenderPipelineRelease(edge_pipeline_); edge_pipeline_ = nullptr; }
|
||||
if (edge_shader_module_) { wgpuShaderModuleRelease(edge_shader_module_);edge_shader_module_ = nullptr; }
|
||||
if (edge_pipeline_layout_) { wgpuPipelineLayoutRelease(edge_pipeline_layout_); edge_pipeline_layout_ = nullptr; }
|
||||
if (edge_bgl_) { wgpuBindGroupLayoutRelease(edge_bgl_); edge_bgl_ = nullptr; }
|
||||
}
|
||||
|
||||
@@ -375,6 +375,22 @@ public:
|
||||
void ensureMsaaColorTexture(int w, int h);
|
||||
void releaseMsaaColorTexture();
|
||||
|
||||
// ---- Edge silhouette post-process (#84-s) -----------------------------
|
||||
//
|
||||
// Build the edge pipeline + shader + BGL. Run after initWgpu's
|
||||
// device is up. Returns false on pipeline creation failure.
|
||||
bool buildEdgePipeline();
|
||||
|
||||
// Encode the edge silhouette fullscreen pass into the supplied
|
||||
// command encoder. No-op when edges_enabled_ is false or the
|
||||
// pipeline / depth view / surface view is null. Lazily builds the
|
||||
// bind group on first call after a surface resize.
|
||||
void encodeEdgePass(WGPUCommandEncoder enc, WGPUTextureView surface_view);
|
||||
|
||||
// Tear down the edge pipeline + bind group + supporting state.
|
||||
// Called from shutdown() before the device dies.
|
||||
void releaseEdgeResources();
|
||||
|
||||
// ---- Cull (#84-p) -----------------------------------------------------
|
||||
//
|
||||
// Per-instance occlusion test, supplied by the caller. Wired by
|
||||
@@ -535,6 +551,8 @@ private:
|
||||
WGPUBindGroupLayout edge_bgl_ = nullptr;
|
||||
WGPUPipelineLayout edge_pipeline_layout_ = nullptr;
|
||||
WGPURenderPipeline edge_pipeline_ = nullptr;
|
||||
WGPUBindGroup edge_bind_group_ = nullptr;
|
||||
bool edges_enabled_ = true;
|
||||
|
||||
// Pick pass. Reuses pipeline_layout_ — same set of bindings as the
|
||||
// main pass since the pick fragment also vertex-pulls instance data.
|
||||
|
||||
@@ -241,6 +241,8 @@ ViewportWindow::ViewportWindow(QWindow* parent)
|
||||
edge_bgl_ (core_.edge_bgl_),
|
||||
edge_pipeline_layout_ (core_.edge_pipeline_layout_),
|
||||
edge_pipeline_ (core_.edge_pipeline_),
|
||||
edge_bind_group_ (core_.edge_bind_group_),
|
||||
edges_enabled_ (core_.edges_enabled_),
|
||||
pick_pipeline_(core_.pick_pipeline_),
|
||||
pool_ (core_.pool_),
|
||||
streaming_thread_(core_.streaming_thread_),
|
||||
@@ -742,7 +744,7 @@ bool ViewportWindow::initWgpu() {
|
||||
// init haven't migrated yet) -------------------------------------
|
||||
if (!buildPipelines()) return false;
|
||||
if (!core_.buildHizPipeline()) return false;
|
||||
if (!buildEdgePipeline()) return false;
|
||||
if (!core_.buildEdgePipeline()) return false;
|
||||
if (!overlays_.init(instance_, device_, queue_, surface_format_, SAMPLE_COUNT)) {
|
||||
Log::warn() << "OverlayRenderer init failed";
|
||||
return false;
|
||||
@@ -999,164 +1001,11 @@ void ViewportWindow::configureSurface(int width_px, int height_px) {
|
||||
// camera near/far are hard-coded to the viewport defaults (0.1 / 10000).
|
||||
// They'll move to a small uniform when AppSettings ports over.
|
||||
|
||||
static const char* EDGE_WGSL = R"(
|
||||
@group(0) @binding(0) var src_depth: texture_depth_multisampled_2d;
|
||||
// EDGE_WGSL moved to ViewportCore.cpp anon namespace (#84-s).
|
||||
|
||||
const NEAR: f32 = 0.1;
|
||||
const FAR: f32 = 10000.0;
|
||||
const EDGE_SCALE: f32 = 6.0;
|
||||
const EDGE_THRESHOLD: f32 = 0.004;
|
||||
// buildEdgePipeline moved to ViewportCore (#84-s).
|
||||
|
||||
// Depth texture stores [0,1] z (we pre-multiply a z-remap onto Qt's GL-style
|
||||
// projection in the main pipeline). Convert back to GL-NDC then reverse-
|
||||
// project to view-space distance.
|
||||
fn linearise(z: f32) -> f32 {
|
||||
let ndc = z * 2.0 - 1.0;
|
||||
return (2.0 * NEAR * FAR) / (FAR + NEAR - ndc * (FAR - NEAR));
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4<f32> {
|
||||
let x = f32((vid << 1u) & 2u) * 2.0 - 1.0;
|
||||
let y = f32(vid & 2u) * 2.0 - 1.0;
|
||||
return vec4<f32>(x, y, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(@builtin(position) frag: vec4<f32>) -> @location(0) vec4<f32> {
|
||||
let p = vec2<i32>(i32(frag.x), i32(frag.y));
|
||||
let dim = vec2<i32>(textureDimensions(src_depth));
|
||||
|
||||
let dc_raw = textureLoad(src_depth, p, 0);
|
||||
// Background pixels: nothing was drawn here. Skip so we don't draw
|
||||
// edges on the void / sky.
|
||||
if (dc_raw >= 0.99999) { discard; }
|
||||
|
||||
let c = linearise(dc_raw);
|
||||
let n = linearise(textureLoad(src_depth, vec2<i32>(p.x, max(p.y - 1, 0)), 0));
|
||||
let s = linearise(textureLoad(src_depth, vec2<i32>(p.x, min(p.y + 1, dim.y - 1)), 0));
|
||||
let e = linearise(textureLoad(src_depth, vec2<i32>(min(p.x + 1, dim.x - 1), p.y), 0));
|
||||
let w = linearise(textureLoad(src_depth, vec2<i32>(max(p.x - 1, 0), p.y), 0));
|
||||
|
||||
let lap = abs(4.0 * c - n - s - e - w);
|
||||
let t = EDGE_THRESHOLD * c;
|
||||
let edge = clamp((lap - t) * EDGE_SCALE, 0.0, 0.6);
|
||||
|
||||
// Multiplicative blend (Dst, Zero): output rgb = (1 - edge), so the
|
||||
// existing surface colour is multiplied by (1 - edge) per channel.
|
||||
return vec4<f32>(vec3<f32>(1.0 - edge), 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
bool ViewportWindow::buildEdgePipeline() {
|
||||
WGPUBindGroupLayoutEntry entries[1] = {};
|
||||
entries[0].binding = 0;
|
||||
entries[0].visibility = WGPUShaderStage_Fragment;
|
||||
entries[0].texture.sampleType = WGPUTextureSampleType_Depth;
|
||||
entries[0].texture.viewDimension = WGPUTextureViewDimension_2D;
|
||||
entries[0].texture.multisampled = 1;
|
||||
|
||||
WGPUBindGroupLayoutDescriptor bgl_desc = {};
|
||||
bgl_desc.entryCount = 1;
|
||||
bgl_desc.entries = entries;
|
||||
bgl_desc.label = svFromCStr("ifcviewer-wgpu.edge_bgl");
|
||||
edge_bgl_ = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc);
|
||||
|
||||
WGPUPipelineLayoutDescriptor pl_desc = {};
|
||||
pl_desc.bindGroupLayoutCount = 1;
|
||||
pl_desc.bindGroupLayouts = &edge_bgl_;
|
||||
pl_desc.label = svFromCStr("ifcviewer-wgpu.edge_pipeline_layout");
|
||||
edge_pipeline_layout_ = wgpuDeviceCreatePipelineLayout(device_, &pl_desc);
|
||||
|
||||
WGPUShaderSourceWGSL wgsl_src = {};
|
||||
wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL;
|
||||
wgsl_src.code = svFromCStr(EDGE_WGSL);
|
||||
WGPUShaderModuleDescriptor sm_desc = {};
|
||||
sm_desc.nextInChain = &wgsl_src.chain;
|
||||
sm_desc.label = svFromCStr("ifcviewer-wgpu.edge_wgsl");
|
||||
edge_shader_module_ = wgpuDeviceCreateShaderModule(device_, &sm_desc);
|
||||
|
||||
// Multiplicative blend (Dst, Zero): out.rgb = src.rgb * dst.rgb.
|
||||
// Fragment outputs (1 - edge, 1 - edge, 1 - edge) so the existing
|
||||
// surface colour is scaled per-channel — strictly darkens, never
|
||||
// brightens. Matches GL's renderEdgePass (GL_DST_COLOR, GL_ZERO).
|
||||
WGPUBlendState blend = {};
|
||||
blend.color.srcFactor = WGPUBlendFactor_Dst;
|
||||
blend.color.dstFactor = WGPUBlendFactor_Zero;
|
||||
blend.color.operation = WGPUBlendOperation_Add;
|
||||
blend.alpha.srcFactor = WGPUBlendFactor_Zero;
|
||||
blend.alpha.dstFactor = WGPUBlendFactor_One;
|
||||
blend.alpha.operation = WGPUBlendOperation_Add;
|
||||
|
||||
WGPUColorTargetState target = {};
|
||||
target.format = surface_format_;
|
||||
target.blend = &blend;
|
||||
target.writeMask = WGPUColorWriteMask_All;
|
||||
|
||||
WGPUFragmentState frag = {};
|
||||
frag.module = edge_shader_module_;
|
||||
frag.entryPoint = svFromCStr("fs_main");
|
||||
frag.targetCount = 1;
|
||||
frag.targets = ⌖
|
||||
|
||||
WGPURenderPipelineDescriptor rp_desc = {};
|
||||
rp_desc.layout = edge_pipeline_layout_;
|
||||
rp_desc.label = svFromCStr("ifcviewer-wgpu.edge_pipeline");
|
||||
rp_desc.vertex.module = edge_shader_module_;
|
||||
rp_desc.vertex.entryPoint = svFromCStr("vs_main");
|
||||
rp_desc.vertex.bufferCount = 0;
|
||||
rp_desc.fragment = &frag;
|
||||
rp_desc.depthStencil = nullptr; // no depth attachment
|
||||
rp_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||
rp_desc.primitive.cullMode = WGPUCullMode_None;
|
||||
rp_desc.multisample.count = 1;
|
||||
rp_desc.multisample.mask = 0xFFFFFFFFu;
|
||||
|
||||
edge_pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &rp_desc);
|
||||
if (!edge_pipeline_) {
|
||||
Log::warn() << "wgpu edge pipeline creation failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewportWindow::encodeEdgePass(WGPUCommandEncoder enc,
|
||||
WGPUTextureView surface_view) {
|
||||
if (!edges_enabled_ || !edge_pipeline_ || !depth_view_ || !surface_view) return;
|
||||
|
||||
// Rebuild lazily when the underlying depth view was replaced (on resize
|
||||
// we proactively null this out alongside the HiZ bind group).
|
||||
if (!edge_bind_group_) {
|
||||
WGPUBindGroupEntry entry = {};
|
||||
entry.binding = 0;
|
||||
entry.textureView = depth_view_;
|
||||
WGPUBindGroupDescriptor bg = {};
|
||||
bg.layout = edge_bgl_;
|
||||
bg.entryCount = 1;
|
||||
bg.entries = &entry;
|
||||
bg.label = svFromCStr("ifcviewer-wgpu.edge_bind_group");
|
||||
edge_bind_group_ = wgpuDeviceCreateBindGroup(device_, &bg);
|
||||
}
|
||||
|
||||
WGPURenderPassColorAttachment color = {};
|
||||
color.view = surface_view;
|
||||
color.loadOp = WGPULoadOp_Load; // preserve resolved main-pass colour
|
||||
color.storeOp = WGPUStoreOp_Store;
|
||||
color.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
|
||||
|
||||
WGPURenderPassDescriptor pass_desc = {};
|
||||
pass_desc.colorAttachmentCount = 1;
|
||||
pass_desc.colorAttachments = &color;
|
||||
pass_desc.depthStencilAttachment = nullptr;
|
||||
pass_desc.label = svFromCStr("ifcviewer-wgpu.edge_pass");
|
||||
|
||||
WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(enc, &pass_desc);
|
||||
wgpuRenderPassEncoderSetPipeline(pass, edge_pipeline_);
|
||||
wgpuRenderPassEncoderSetBindGroup(pass, 0, edge_bind_group_, 0, nullptr);
|
||||
wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
|
||||
wgpuRenderPassEncoderEnd(pass);
|
||||
wgpuRenderPassEncoderRelease(pass);
|
||||
}
|
||||
// encodeEdgePass moved to ViewportCore (#84-s).
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void ViewportWindow::setPivotIndicatorVisible(bool visible, int hide_after_ms) {
|
||||
@@ -1177,13 +1026,7 @@ void ViewportWindow::setPivotIndicatorVisible(bool visible, int hide_after_ms) {
|
||||
}
|
||||
requestUpdate();
|
||||
}
|
||||
void ViewportWindow::releaseEdgeResources() {
|
||||
if (edge_bind_group_) { wgpuBindGroupRelease(edge_bind_group_); edge_bind_group_ = nullptr; }
|
||||
if (edge_pipeline_) { wgpuRenderPipelineRelease(edge_pipeline_); edge_pipeline_ = nullptr; }
|
||||
if (edge_shader_module_) { wgpuShaderModuleRelease(edge_shader_module_);edge_shader_module_ = nullptr; }
|
||||
if (edge_pipeline_layout_) { wgpuPipelineLayoutRelease(edge_pipeline_layout_); edge_pipeline_layout_ = nullptr; }
|
||||
if (edge_bgl_) { wgpuBindGroupLayoutRelease(edge_bgl_); edge_bgl_ = nullptr; }
|
||||
}
|
||||
// releaseEdgeResources moved to ViewportCore (#84-s).
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Pick pipeline (stage 4)
|
||||
@@ -2896,7 +2739,7 @@ void ViewportWindow::render() {
|
||||
// lines onto the resolved surface colour. Encoded before HiZ resolve
|
||||
// so HiZ uses the same MSAA depth that produced the edges.
|
||||
if (edges_enabled_) {
|
||||
encodeEdgePass(enc, view);
|
||||
core_.encodeEdgePass(enc, view);
|
||||
}
|
||||
|
||||
// Corner axis gizmo. Encoded after the edge pass on the resolved
|
||||
@@ -4453,7 +4296,7 @@ void ViewportWindow::shutdown() {
|
||||
core_.releaseDepthTexture();
|
||||
core_.releaseMsaaColorTexture();
|
||||
core_.releaseHizResources();
|
||||
releaseEdgeResources();
|
||||
core_.releaseEdgeResources();
|
||||
overlays_.destroy();
|
||||
releasePickResources();
|
||||
|
||||
|
||||
@@ -670,8 +670,8 @@ private:
|
||||
WGPUBindGroupLayout& edge_bgl_;
|
||||
WGPUPipelineLayout& edge_pipeline_layout_;
|
||||
WGPURenderPipeline& edge_pipeline_;
|
||||
WGPUBindGroup edge_bind_group_ = nullptr;
|
||||
bool edges_enabled_ = true;
|
||||
WGPUBindGroup& edge_bind_group_;
|
||||
bool& edges_enabled_;
|
||||
|
||||
// Pivot visibility state — the gizmo itself lives in overlays_.
|
||||
// The timer auto-hides the pivot after a wheel-zoom afterglow.
|
||||
|
||||
Reference in New Issue
Block a user