From 1657188676ad1eb8d7218f112961ec73ef0bd828 Mon Sep 17 00:00:00 2001 From: Astrielle <77818664+shimenga@users.noreply.github.com> Date: Sat, 27 Jun 2026 23:31:14 +0800 Subject: [PATCH 1/2] Reformat glass rendering sources and undefine Windows min/max macros - backdrop.cpp / glass.cpp: expand compact single-line D3D11 state-creation blocks (buffer/sampler/blend/rasterizer/depth-stencil) into multi-line, properly indented braces for readability. - surfaces.cpp / glass.cpp: add `#undef max` / `#undef min` to prevent the Windows macros from interfering with std::numeric_limits and template uses. - surfaces.cpp: expand compact loops and inline branches in RoundedGrad, ImgOrGrad and SurfaceLaunchpad into clearer multi-line form. No runtime behavior changes; whitespace/brace reformatting plus the min/max undef guard. --- .../src/glass/backdrop.cpp | 513 ++++---- .../src/glass/glass.cpp | 1123 +++++++++-------- .../src/glass/surfaces.cpp | 761 +++++------ 3 files changed, 1217 insertions(+), 1180 deletions(-) diff --git a/examples/example_win32_directx11/src/glass/backdrop.cpp b/examples/example_win32_directx11/src/glass/backdrop.cpp index a04447d..746d3ba 100644 --- a/examples/example_win32_directx11/src/glass/backdrop.cpp +++ b/examples/example_win32_directx11/src/glass/backdrop.cpp @@ -15,280 +15,291 @@ namespace Glass { -bool Backdrop::Init(ID3D11Device* device, ID3D11DeviceContext* ctx, HWND hwnd) { - dev_ = device; ctx_ = ctx; hwnd_ = hwnd; - ::SetWindowDisplayAffinity(hwnd_, WDA_EXCLUDEFROMCAPTURE); - if (!CompileBlurShaders()) { Shutdown(); return false; } - { D3D11_BUFFER_DESC bd = {}; - bd.ByteWidth = 16; bd.Usage = D3D11_USAGE_DYNAMIC; - bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - if (FAILED(dev_->CreateBuffer(&bd, nullptr, &blur_cb_))) { Shutdown(); return false; } } - { D3D11_SAMPLER_DESC sd = {}; - sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.MaxLOD = D3D11_FLOAT32_MAX; - if (FAILED(dev_->CreateSamplerState(&sd, &sampler_))) { Shutdown(); return false; } } - { D3D11_BLEND_DESC bd = {}; - bd.RenderTarget[0].BlendEnable = FALSE; - bd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - if (FAILED(dev_->CreateBlendState(&bd, &blend_opaque_))) { Shutdown(); return false; } } - { D3D11_RASTERIZER_DESC rd = {}; - rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; rd.DepthClipEnable = TRUE; - if (FAILED(dev_->CreateRasterizerState(&rd, &raster_))) { Shutdown(); return false; } } - { D3D11_DEPTH_STENCIL_DESC dd = {}; - dd.DepthEnable = FALSE; dd.StencilEnable = FALSE; - if (FAILED(dev_->CreateDepthStencilState(&dd, &depth_off_))) { Shutdown(); return false; } } - CreateDuplication(); - if (!up_[0].srv) { - int W = ::GetSystemMetrics(SM_CXSCREEN); - int H = ::GetSystemMetrics(SM_CYSCREEN); - if (W <= 0) W = 1920; if (H <= 0) H = 1080; - out_x_ = 0; out_y_ = 0; - CreateChain(W, H); + bool Backdrop::Init(ID3D11Device* device, ID3D11DeviceContext* ctx, HWND hwnd) { + dev_ = device; ctx_ = ctx; hwnd_ = hwnd; + ::SetWindowDisplayAffinity(hwnd_, WDA_EXCLUDEFROMCAPTURE); + if (!CompileBlurShaders()) { Shutdown(); return false; } + { + D3D11_BUFFER_DESC bd = {}; + bd.ByteWidth = 16; bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (FAILED(dev_->CreateBuffer(&bd, nullptr, &blur_cb_))) { Shutdown(); return false; } + } + { + D3D11_SAMPLER_DESC sd = {}; + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.MaxLOD = D3D11_FLOAT32_MAX; + if (FAILED(dev_->CreateSamplerState(&sd, &sampler_))) { Shutdown(); return false; } + } + { + D3D11_BLEND_DESC bd = {}; + bd.RenderTarget[0].BlendEnable = FALSE; + bd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + if (FAILED(dev_->CreateBlendState(&bd, &blend_opaque_))) { Shutdown(); return false; } + } + { + D3D11_RASTERIZER_DESC rd = {}; + rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; rd.DepthClipEnable = TRUE; + if (FAILED(dev_->CreateRasterizerState(&rd, &raster_))) { Shutdown(); return false; } + } + { + D3D11_DEPTH_STENCIL_DESC dd = {}; + dd.DepthEnable = FALSE; dd.StencilEnable = FALSE; + if (FAILED(dev_->CreateDepthStencilState(&dd, &depth_off_))) { Shutdown(); return false; } + } + CreateDuplication(); + if (!up_[0].srv) { + int W = ::GetSystemMetrics(SM_CXSCREEN); + int H = ::GetSystemMetrics(SM_CYSCREEN); + if (W <= 0) W = 1920; if (H <= 0) H = 1080; + out_x_ = 0; out_y_ = 0; + CreateChain(W, H); + } + for (int i = 0; i < 8 && !have_first_; ++i) Capture(); + return true; } - for (int i = 0; i < 8 && !have_first_; ++i) Capture(); - return true; -} - -void Backdrop::Shutdown() { - ReleaseDuplication(); - ReleaseChain(); - if (depth_off_) { depth_off_->Release(); depth_off_ = nullptr; } - if (raster_) { raster_->Release(); raster_ = nullptr; } - if (blend_opaque_) { blend_opaque_->Release(); blend_opaque_ = nullptr; } - if (sampler_) { sampler_->Release(); sampler_ = nullptr; } - if (blur_cb_) { blur_cb_->Release(); blur_cb_ = nullptr; } - if (ps_up_) { ps_up_->Release(); ps_up_ = nullptr; } - if (ps_down_) { ps_down_->Release(); ps_down_ = nullptr; } - if (vs_full_) { vs_full_->Release(); vs_full_ = nullptr; } -} -bool Backdrop::CompileBlurShaders() { - ID3DBlob *vb = nullptr, *db = nullptr, *ub = nullptr, *err = nullptr; - HRESULT hr; size_t len = std::strlen(kBlurHLSL); - hr = D3DCompile(kBlurHLSL, len, "BlurVS", nullptr, nullptr, "VSFull", "vs_5_0", 0, 0, &vb, &err); - if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } return false; } - hr = D3DCompile(kBlurHLSL, len, "BlurDown", nullptr, nullptr, "PSDown", "ps_5_0", 0, 0, &db, &err); - if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); return false; } - hr = D3DCompile(kBlurHLSL, len, "BlurUp", nullptr, nullptr, "PSUp", "ps_5_0", 0, 0, &ub, &err); - if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); db->Release(); return false; } - bool ok = true; - ok &= SUCCEEDED(dev_->CreateVertexShader(vb->GetBufferPointer(), vb->GetBufferSize(), nullptr, &vs_full_)); - ok &= SUCCEEDED(dev_->CreatePixelShader (db->GetBufferPointer(), db->GetBufferSize(), nullptr, &ps_down_)); - ok &= SUCCEEDED(dev_->CreatePixelShader (ub->GetBufferPointer(), ub->GetBufferSize(), nullptr, &ps_up_)); - vb->Release(); db->Release(); ub->Release(); - return ok; -} + void Backdrop::Shutdown() { + ReleaseDuplication(); + ReleaseChain(); + if (depth_off_) { depth_off_->Release(); depth_off_ = nullptr; } + if (raster_) { raster_->Release(); raster_ = nullptr; } + if (blend_opaque_) { blend_opaque_->Release(); blend_opaque_ = nullptr; } + if (sampler_) { sampler_->Release(); sampler_ = nullptr; } + if (blur_cb_) { blur_cb_->Release(); blur_cb_ = nullptr; } + if (ps_up_) { ps_up_->Release(); ps_up_ = nullptr; } + if (ps_down_) { ps_down_->Release(); ps_down_ = nullptr; } + if (vs_full_) { vs_full_->Release(); vs_full_ = nullptr; } + } -bool Backdrop::CreateRT(RT& rt, int w, int h, DXGI_FORMAT fmt, bool want_rtv, bool want_srv) { - ReleaseRT(rt); - rt.w = w; rt.h = h; - D3D11_TEXTURE2D_DESC td = {}; - td.Width = w; td.Height = h; td.MipLevels = 1; td.ArraySize = 1; - td.Format = fmt; td.SampleDesc.Count = 1; td.Usage = D3D11_USAGE_DEFAULT; - td.BindFlags = (want_rtv ? D3D11_BIND_RENDER_TARGET : 0) | (want_srv ? D3D11_BIND_SHADER_RESOURCE : 0); - if (FAILED(dev_->CreateTexture2D(&td, nullptr, &rt.tex))) return false; - if (want_rtv && FAILED(dev_->CreateRenderTargetView(rt.tex, nullptr, &rt.rtv))) return false; - if (want_srv && FAILED(dev_->CreateShaderResourceView(rt.tex, nullptr, &rt.srv))) return false; - return true; -} + bool Backdrop::CompileBlurShaders() { + ID3DBlob* vb = nullptr, * db = nullptr, * ub = nullptr, * err = nullptr; + HRESULT hr; size_t len = std::strlen(kBlurHLSL); + hr = D3DCompile(kBlurHLSL, len, "BlurVS", nullptr, nullptr, "VSFull", "vs_5_0", 0, 0, &vb, &err); + if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } return false; } + hr = D3DCompile(kBlurHLSL, len, "BlurDown", nullptr, nullptr, "PSDown", "ps_5_0", 0, 0, &db, &err); + if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); return false; } + hr = D3DCompile(kBlurHLSL, len, "BlurUp", nullptr, nullptr, "PSUp", "ps_5_0", 0, 0, &ub, &err); + if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); db->Release(); return false; } + bool ok = true; + ok &= SUCCEEDED(dev_->CreateVertexShader(vb->GetBufferPointer(), vb->GetBufferSize(), nullptr, &vs_full_)); + ok &= SUCCEEDED(dev_->CreatePixelShader(db->GetBufferPointer(), db->GetBufferSize(), nullptr, &ps_down_)); + ok &= SUCCEEDED(dev_->CreatePixelShader(ub->GetBufferPointer(), ub->GetBufferSize(), nullptr, &ps_up_)); + vb->Release(); db->Release(); ub->Release(); + return ok; + } -void Backdrop::ReleaseRT(RT& rt) { - if (rt.srv) { rt.srv->Release(); rt.srv = nullptr; } - if (rt.rtv) { rt.rtv->Release(); rt.rtv = nullptr; } - if (rt.tex) { rt.tex->Release(); rt.tex = nullptr; } - rt.w = rt.h = 0; -} + bool Backdrop::CreateRT(RT& rt, int w, int h, DXGI_FORMAT fmt, bool want_rtv, bool want_srv) { + ReleaseRT(rt); + rt.w = w; rt.h = h; + D3D11_TEXTURE2D_DESC td = {}; + td.Width = w; td.Height = h; td.MipLevels = 1; td.ArraySize = 1; + td.Format = fmt; td.SampleDesc.Count = 1; td.Usage = D3D11_USAGE_DEFAULT; + td.BindFlags = (want_rtv ? D3D11_BIND_RENDER_TARGET : 0) | (want_srv ? D3D11_BIND_SHADER_RESOURCE : 0); + if (FAILED(dev_->CreateTexture2D(&td, nullptr, &rt.tex))) return false; + if (want_rtv && FAILED(dev_->CreateRenderTargetView(rt.tex, nullptr, &rt.rtv))) return false; + if (want_srv && FAILED(dev_->CreateShaderResourceView(rt.tex, nullptr, &rt.srv))) return false; + return true; + } -bool Backdrop::CreateChain(int W, int H) { - out_w_ = W; out_h_ = H; - const DXGI_FORMAT F = DXGI_FORMAT_R8G8B8A8_UNORM; - for (int k = 0; k < 6; ++k) { - int w = std::max(1, W >> (k + 1)); - int h = std::max(1, H >> (k + 1)); - if (!CreateRT(down_[k], w, h, F, true, true)) return false; + void Backdrop::ReleaseRT(RT& rt) { + if (rt.srv) { rt.srv->Release(); rt.srv = nullptr; } + if (rt.rtv) { rt.rtv->Release(); rt.rtv = nullptr; } + if (rt.tex) { rt.tex->Release(); rt.tex = nullptr; } + rt.w = rt.h = 0; } - for (int k = 0; k < 5; ++k) - if (!CreateRT(up_[k], down_[k].w, down_[k].h, F, true, true)) return false; - if (!CreateRT(soft_, W, H, F, true, true)) return false; - if (!CreateRT(heavy_, W, H, F, true, true)) return false; - const float grey[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; - ctx_->ClearRenderTargetView(up_[0].rtv, grey); - ctx_->ClearRenderTargetView(soft_.rtv, grey); - ctx_->ClearRenderTargetView(heavy_.rtv, grey); - return true; -} -void Backdrop::ReleaseChain() { - ReleaseRT(desktop_); - for (auto& r : down_) ReleaseRT(r); - for (auto& r : up_) ReleaseRT(r); - ReleaseRT(soft_); - ReleaseRT(heavy_); - ReleaseRT(ui_cap_); - for (auto& r : ui_down_) ReleaseRT(r); - for (auto& r : ui_up_) ReleaseRT(r); - ReleaseRT(ui_heavy_); -} + bool Backdrop::CreateChain(int W, int H) { + out_w_ = W; out_h_ = H; + const DXGI_FORMAT F = DXGI_FORMAT_R8G8B8A8_UNORM; + for (int k = 0; k < 6; ++k) { + int w = std::max(1, W >> (k + 1)); + int h = std::max(1, H >> (k + 1)); + if (!CreateRT(down_[k], w, h, F, true, true)) return false; + } + for (int k = 0; k < 5; ++k) + if (!CreateRT(up_[k], down_[k].w, down_[k].h, F, true, true)) return false; + if (!CreateRT(soft_, W, H, F, true, true)) return false; + if (!CreateRT(heavy_, W, H, F, true, true)) return false; + const float grey[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; + ctx_->ClearRenderTargetView(up_[0].rtv, grey); + ctx_->ClearRenderTargetView(soft_.rtv, grey); + ctx_->ClearRenderTargetView(heavy_.rtv, grey); + return true; + } -void Backdrop::BlurUI(ID3D11Texture2D* src, int w, int h) { - if (!src || w <= 0 || h <= 0 || !vs_full_ || !ps_down_ || !ps_up_) return; - if (ui_cap_.w != w || ui_cap_.h != h || !ui_heavy_.srv) { - D3D11_TEXTURE2D_DESC sd = {}; src->GetDesc(&sd); + void Backdrop::ReleaseChain() { + ReleaseRT(desktop_); + for (auto& r : down_) ReleaseRT(r); + for (auto& r : up_) ReleaseRT(r); + ReleaseRT(soft_); + ReleaseRT(heavy_); ReleaseRT(ui_cap_); for (auto& r : ui_down_) ReleaseRT(r); for (auto& r : ui_up_) ReleaseRT(r); ReleaseRT(ui_heavy_); - const DXGI_FORMAT F = DXGI_FORMAT_R8G8B8A8_UNORM; - if (!CreateRT(ui_cap_, w, h, sd.Format, false, true)) return; - for (int k = 0; k < 8; ++k) - if (!CreateRT(ui_down_[k], std::max(1, w >> (k + 1)), std::max(1, h >> (k + 1)), F, true, true)) return; - for (int k = 0; k < 7; ++k) - if (!CreateRT(ui_up_[k], ui_down_[k].w, ui_down_[k].h, F, true, true)) return; - if (!CreateRT(ui_heavy_, w, h, F, true, true)) return; } - if (!ui_cap_.tex || !ui_heavy_.rtv) return; - ctx_->CopyResource(ui_cap_.tex, src); - const float amt = ui_blur_amt_; - blur_spread_ = amt * 0.7f; - if (blur_spread_ < 0.25f) blur_spread_ = 0.25f; else if (blur_spread_ > 2.2f) blur_spread_ = 2.2f; - int extra = (int)((amt - 3.0f) / 2.0f); if (extra < 0) extra = 0; else if (extra > 2) extra = 2; - const int DOWN = 6 + extra; - ctx_->IASetInputLayout(nullptr); - ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - const float bf[4] = { 0, 0, 0, 0 }; - ctx_->OMSetBlendState(blend_opaque_, bf, 0xffffffff); - ctx_->OMSetDepthStencilState(depth_off_, 0); - ctx_->RSSetState(raster_); - BlurPass(ps_down_, ui_cap_.srv, ui_down_[0], ui_cap_.w, ui_cap_.h); - for (int k = 1; k < DOWN; ++k) - BlurPass(ps_down_, ui_down_[k - 1].srv, ui_down_[k], ui_down_[k - 1].w, ui_down_[k - 1].h); - BlurPass(ps_up_, ui_down_[DOWN - 1].srv, ui_up_[DOWN - 2], ui_down_[DOWN - 1].w, ui_down_[DOWN - 1].h); - for (int k = DOWN - 3; k >= 0; --k) - BlurPass(ps_up_, ui_up_[k + 1].srv, ui_up_[k], ui_up_[k + 1].w, ui_up_[k + 1].h); - BlurPass(ps_up_, ui_up_[0].srv, ui_heavy_, ui_up_[0].w, ui_up_[0].h); - ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; - ctx_->PSSetShaderResources(0, 2, nullsrv); - ID3D11RenderTargetView* nullrtv = nullptr; - ctx_->OMSetRenderTargets(1, &nullrtv, nullptr); -} -bool Backdrop::CreateDuplication() { - ReleaseDuplication(); - IDXGIDevice* dxgi = nullptr; - if (FAILED(dev_->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgi))) return false; - IDXGIAdapter* adapter = nullptr; - if (FAILED(dxgi->GetAdapter(&adapter))) { dxgi->Release(); return false; } - dxgi->Release(); - RECT wr = {}; ::GetWindowRect(hwnd_, &wr); - POINT c = { (wr.left + wr.right) / 2, (wr.top + wr.bottom) / 2 }; - IDXGIOutput* chosen = nullptr; - DXGI_OUTPUT_DESC chosen_desc = {}; - for (UINT i = 0; ; ++i) { - IDXGIOutput* o = nullptr; - if (adapter->EnumOutputs(i, &o) == DXGI_ERROR_NOT_FOUND) break; - DXGI_OUTPUT_DESC od = {}; o->GetDesc(&od); - const RECT& dc = od.DesktopCoordinates; - bool inside = c.x >= dc.left && c.x < dc.right && c.y >= dc.top && c.y < dc.bottom; - if (inside || chosen == nullptr) { - if (chosen) chosen->Release(); - chosen = o; chosen_desc = od; - if (inside) break; - } else { - o->Release(); + void Backdrop::BlurUI(ID3D11Texture2D* src, int w, int h) { + if (!src || w <= 0 || h <= 0 || !vs_full_ || !ps_down_ || !ps_up_) return; + if (ui_cap_.w != w || ui_cap_.h != h || !ui_heavy_.srv) { + D3D11_TEXTURE2D_DESC sd = {}; src->GetDesc(&sd); + ReleaseRT(ui_cap_); + for (auto& r : ui_down_) ReleaseRT(r); + for (auto& r : ui_up_) ReleaseRT(r); + ReleaseRT(ui_heavy_); + const DXGI_FORMAT F = DXGI_FORMAT_R8G8B8A8_UNORM; + if (!CreateRT(ui_cap_, w, h, sd.Format, false, true)) return; + for (int k = 0; k < 8; ++k) + if (!CreateRT(ui_down_[k], std::max(1, w >> (k + 1)), std::max(1, h >> (k + 1)), F, true, true)) return; + for (int k = 0; k < 7; ++k) + if (!CreateRT(ui_up_[k], ui_down_[k].w, ui_down_[k].h, F, true, true)) return; + if (!CreateRT(ui_heavy_, w, h, F, true, true)) return; } + if (!ui_cap_.tex || !ui_heavy_.rtv) return; + ctx_->CopyResource(ui_cap_.tex, src); + const float amt = ui_blur_amt_; + blur_spread_ = amt * 0.7f; + if (blur_spread_ < 0.25f) blur_spread_ = 0.25f; else if (blur_spread_ > 2.2f) blur_spread_ = 2.2f; + int extra = (int)((amt - 3.0f) / 2.0f); if (extra < 0) extra = 0; else if (extra > 2) extra = 2; + const int DOWN = 6 + extra; + ctx_->IASetInputLayout(nullptr); + ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + const float bf[4] = { 0, 0, 0, 0 }; + ctx_->OMSetBlendState(blend_opaque_, bf, 0xffffffff); + ctx_->OMSetDepthStencilState(depth_off_, 0); + ctx_->RSSetState(raster_); + BlurPass(ps_down_, ui_cap_.srv, ui_down_[0], ui_cap_.w, ui_cap_.h); + for (int k = 1; k < DOWN; ++k) + BlurPass(ps_down_, ui_down_[k - 1].srv, ui_down_[k], ui_down_[k - 1].w, ui_down_[k - 1].h); + BlurPass(ps_up_, ui_down_[DOWN - 1].srv, ui_up_[DOWN - 2], ui_down_[DOWN - 1].w, ui_down_[DOWN - 1].h); + for (int k = DOWN - 3; k >= 0; --k) + BlurPass(ps_up_, ui_up_[k + 1].srv, ui_up_[k], ui_up_[k + 1].w, ui_up_[k + 1].h); + BlurPass(ps_up_, ui_up_[0].srv, ui_heavy_, ui_up_[0].w, ui_up_[0].h); + ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; + ctx_->PSSetShaderResources(0, 2, nullsrv); + ID3D11RenderTargetView* nullrtv = nullptr; + ctx_->OMSetRenderTargets(1, &nullrtv, nullptr); } - adapter->Release(); - if (!chosen) return false; - const RECT& dc = chosen_desc.DesktopCoordinates; - out_x_ = dc.left; out_y_ = dc.top; - int W = dc.right - dc.left, H = dc.bottom - dc.top; - if (FAILED(chosen->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1_))) { chosen->Release(); return false; } - chosen->Release(); - if (FAILED(output1_->DuplicateOutput(dev_, &dupl_))) { return false; } - if (down_[0].tex == nullptr || W != down_[0].w * 2) - if (!CreateChain(W, H)) return false; - out_w_ = W; out_h_ = H; - return true; -} -void Backdrop::ReleaseDuplication() { - if (dupl_) { dupl_->Release(); dupl_ = nullptr; } - if (output1_) { output1_->Release(); output1_ = nullptr; } -} + bool Backdrop::CreateDuplication() { + ReleaseDuplication(); + IDXGIDevice* dxgi = nullptr; + if (FAILED(dev_->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgi))) return false; + IDXGIAdapter* adapter = nullptr; + if (FAILED(dxgi->GetAdapter(&adapter))) { dxgi->Release(); return false; } + dxgi->Release(); + RECT wr = {}; ::GetWindowRect(hwnd_, &wr); + POINT c = { (wr.left + wr.right) / 2, (wr.top + wr.bottom) / 2 }; + IDXGIOutput* chosen = nullptr; + DXGI_OUTPUT_DESC chosen_desc = {}; + for (UINT i = 0; ; ++i) { + IDXGIOutput* o = nullptr; + if (adapter->EnumOutputs(i, &o) == DXGI_ERROR_NOT_FOUND) break; + DXGI_OUTPUT_DESC od = {}; o->GetDesc(&od); + const RECT& dc = od.DesktopCoordinates; + bool inside = c.x >= dc.left && c.x < dc.right && c.y >= dc.top && c.y < dc.bottom; + if (inside || chosen == nullptr) { + if (chosen) chosen->Release(); + chosen = o; chosen_desc = od; + if (inside) break; + } + else { + o->Release(); + } + } + adapter->Release(); + if (!chosen) return false; + const RECT& dc = chosen_desc.DesktopCoordinates; + out_x_ = dc.left; out_y_ = dc.top; + int W = dc.right - dc.left, H = dc.bottom - dc.top; + if (FAILED(chosen->QueryInterface(__uuidof(IDXGIOutput1), (void**)&output1_))) { chosen->Release(); return false; } + chosen->Release(); + if (FAILED(output1_->DuplicateOutput(dev_, &dupl_))) { return false; } + if (down_[0].tex == nullptr || W != down_[0].w * 2) + if (!CreateChain(W, H)) return false; + out_w_ = W; out_h_ = H; + return true; + } -void Backdrop::BlurPass(ID3D11PixelShader* ps, ID3D11ShaderResourceView* src, - const RT& dst, int src_w, int src_h) { - ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; - ctx_->PSSetShaderResources(0, 2, nullsrv); - ctx_->OMSetRenderTargets(1, &dst.rtv, nullptr); - D3D11_VIEWPORT vp = {}; vp.Width = (float)dst.w; vp.Height = (float)dst.h; vp.MaxDepth = 1.0f; - ctx_->RSSetViewports(1, &vp); - D3D11_MAPPED_SUBRESOURCE m; - if (SUCCEEDED(ctx_->Map(blur_cb_, 0, D3D11_MAP_WRITE_DISCARD, 0, &m))) { - float* f = (float*)m.pData; - f[0] = 1.0f / (float)src_w; f[1] = 1.0f / (float)src_h; f[2] = blur_spread_; f[3] = 0.0f; - ctx_->Unmap(blur_cb_, 0); + void Backdrop::ReleaseDuplication() { + if (dupl_) { dupl_->Release(); dupl_ = nullptr; } + if (output1_) { output1_->Release(); output1_ = nullptr; } } - ctx_->VSSetShader(vs_full_, nullptr, 0); - ctx_->PSSetShader(ps, nullptr, 0); - ctx_->PSSetConstantBuffers(0, 1, &blur_cb_); - ctx_->PSSetSamplers(0, 1, &sampler_); - ctx_->PSSetShaderResources(0, 1, &src); - ctx_->Draw(3, 0); -} -void Backdrop::RunBlur() { - if (!desktop_.srv || !down_[0].rtv) return; - blur_spread_ = 1.0f; - ctx_->IASetInputLayout(nullptr); - ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - const float bf[4] = { 0, 0, 0, 0 }; - ctx_->OMSetBlendState(blend_opaque_, bf, 0xffffffff); - ctx_->OMSetDepthStencilState(depth_off_, 0); - ctx_->RSSetState(raster_); - BlurPass(ps_down_, desktop_.srv, down_[0], desktop_.w, desktop_.h); - for (int k = 1; k < 6; ++k) - BlurPass(ps_down_, down_[k - 1].srv, down_[k], down_[k - 1].w, down_[k - 1].h); - BlurPass(ps_up_, down_[5].srv, up_[4], down_[5].w, down_[5].h); - BlurPass(ps_up_, up_[4].srv, up_[3], up_[4].w, up_[4].h); - BlurPass(ps_up_, up_[3].srv, up_[2], up_[3].w, up_[3].h); - BlurPass(ps_up_, up_[2].srv, up_[1], up_[2].w, up_[2].h); - BlurPass(ps_up_, up_[1].srv, up_[0], up_[1].w, up_[1].h); - BlurPass(ps_up_, up_[0].srv, heavy_, up_[0].w, up_[0].h); - BlurPass(ps_up_, desktop_.srv, soft_, desktop_.w, desktop_.h); - ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; - ctx_->PSSetShaderResources(0, 2, nullsrv); - ID3D11RenderTargetView* nullrtv = nullptr; - ctx_->OMSetRenderTargets(1, &nullrtv, nullptr); -} + void Backdrop::BlurPass(ID3D11PixelShader* ps, ID3D11ShaderResourceView* src, + const RT& dst, int src_w, int src_h) { + ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; + ctx_->PSSetShaderResources(0, 2, nullsrv); + ctx_->OMSetRenderTargets(1, &dst.rtv, nullptr); + D3D11_VIEWPORT vp = {}; vp.Width = (float)dst.w; vp.Height = (float)dst.h; vp.MaxDepth = 1.0f; + ctx_->RSSetViewports(1, &vp); + D3D11_MAPPED_SUBRESOURCE m; + if (SUCCEEDED(ctx_->Map(blur_cb_, 0, D3D11_MAP_WRITE_DISCARD, 0, &m))) { + float* f = (float*)m.pData; + f[0] = 1.0f / (float)src_w; f[1] = 1.0f / (float)src_h; f[2] = blur_spread_; f[3] = 0.0f; + ctx_->Unmap(blur_cb_, 0); + } + ctx_->VSSetShader(vs_full_, nullptr, 0); + ctx_->PSSetShader(ps, nullptr, 0); + ctx_->PSSetConstantBuffers(0, 1, &blur_cb_); + ctx_->PSSetSamplers(0, 1, &sampler_); + ctx_->PSSetShaderResources(0, 1, &src); + ctx_->Draw(3, 0); + } + + void Backdrop::RunBlur() { + if (!desktop_.srv || !down_[0].rtv) return; + blur_spread_ = 1.0f; + ctx_->IASetInputLayout(nullptr); + ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + const float bf[4] = { 0, 0, 0, 0 }; + ctx_->OMSetBlendState(blend_opaque_, bf, 0xffffffff); + ctx_->OMSetDepthStencilState(depth_off_, 0); + ctx_->RSSetState(raster_); + BlurPass(ps_down_, desktop_.srv, down_[0], desktop_.w, desktop_.h); + for (int k = 1; k < 6; ++k) + BlurPass(ps_down_, down_[k - 1].srv, down_[k], down_[k - 1].w, down_[k - 1].h); + BlurPass(ps_up_, down_[5].srv, up_[4], down_[5].w, down_[5].h); + BlurPass(ps_up_, up_[4].srv, up_[3], up_[4].w, up_[4].h); + BlurPass(ps_up_, up_[3].srv, up_[2], up_[3].w, up_[3].h); + BlurPass(ps_up_, up_[2].srv, up_[1], up_[2].w, up_[2].h); + BlurPass(ps_up_, up_[1].srv, up_[0], up_[1].w, up_[1].h); + BlurPass(ps_up_, up_[0].srv, heavy_, up_[0].w, up_[0].h); + BlurPass(ps_up_, desktop_.srv, soft_, desktop_.w, desktop_.h); + ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; + ctx_->PSSetShaderResources(0, 2, nullsrv); + ID3D11RenderTargetView* nullrtv = nullptr; + ctx_->OMSetRenderTargets(1, &nullrtv, nullptr); + } -void Backdrop::Capture() { - if (!dupl_) { if (!CreateDuplication()) return; } - IDXGIResource* res = nullptr; - DXGI_OUTDUPL_FRAME_INFO info = {}; - HRESULT hr = dupl_->AcquireNextFrame(have_first_ ? 0 : 250, &info, &res); - if (hr == DXGI_ERROR_WAIT_TIMEOUT) return; - if (hr == DXGI_ERROR_ACCESS_LOST) { ReleaseDuplication(); return; } - if (FAILED(hr)) return; - bool new_image = (info.LastPresentTime.QuadPart != 0) || !have_first_; - if (new_image) { - ID3D11Texture2D* frame = nullptr; - if (SUCCEEDED(res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&frame))) { - D3D11_TEXTURE2D_DESC fd = {}; frame->GetDesc(&fd); - if (!desktop_.tex || (int)fd.Width != desktop_.w || - (int)fd.Height != desktop_.h || fd.Format != desktop_fmt_) { - desktop_fmt_ = fd.Format; - CreateRT(desktop_, (int)fd.Width, (int)fd.Height, fd.Format, false, true); + void Backdrop::Capture() { + if (!dupl_) { if (!CreateDuplication()) return; } + IDXGIResource* res = nullptr; + DXGI_OUTDUPL_FRAME_INFO info = {}; + HRESULT hr = dupl_->AcquireNextFrame(have_first_ ? 0 : 250, &info, &res); + if (hr == DXGI_ERROR_WAIT_TIMEOUT) return; + if (hr == DXGI_ERROR_ACCESS_LOST) { ReleaseDuplication(); return; } + if (FAILED(hr)) return; + bool new_image = (info.LastPresentTime.QuadPart != 0) || !have_first_; + if (new_image) { + ID3D11Texture2D* frame = nullptr; + if (SUCCEEDED(res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&frame))) { + D3D11_TEXTURE2D_DESC fd = {}; frame->GetDesc(&fd); + if (!desktop_.tex || (int)fd.Width != desktop_.w || + (int)fd.Height != desktop_.h || fd.Format != desktop_fmt_) { + desktop_fmt_ = fd.Format; + CreateRT(desktop_, (int)fd.Width, (int)fd.Height, fd.Format, false, true); + } + ctx_->CopyResource(desktop_.tex, frame); + frame->Release(); + RunBlur(); + have_first_ = true; } - ctx_->CopyResource(desktop_.tex, frame); - frame->Release(); - RunBlur(); - have_first_ = true; } + res->Release(); + dupl_->ReleaseFrame(); } - res->Release(); - dupl_->ReleaseFrame(); -} } diff --git a/examples/example_win32_directx11/src/glass/glass.cpp b/examples/example_win32_directx11/src/glass/glass.cpp index 268ae29..02d5c74 100644 --- a/examples/example_win32_directx11/src/glass/glass.cpp +++ b/examples/example_win32_directx11/src/glass/glass.cpp @@ -8,599 +8,614 @@ #include #include #include - +#undef max +#undef min #pragma comment(lib, "d3dcompiler.lib") #pragma comment(lib, "winmm.lib") namespace Glass { -Renderer* g = nullptr; + Renderer* g = nullptr; -ImTextureID g_uiBlurTex = 0; -ImVec2 g_uiBlurOrigin = ImVec2(0.0f, 0.0f); -ImVec2 g_uiBlurSize = ImVec2(1.0f, 1.0f); + ImTextureID g_uiBlurTex = 0; + ImVec2 g_uiBlurOrigin = ImVec2(0.0f, 0.0f); + ImVec2 g_uiBlurSize = ImVec2(1.0f, 1.0f); -bool DrawUIBlurPanel(ImDrawList* dl, ImVec2 pmin, ImVec2 pmax, float rounding, float alpha, ImU32 tint) { - if (!g_uiBlurTex) return false; - if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; - const float iw = g_uiBlurSize.x > 1.0f ? g_uiBlurSize.x : 1.0f; - const float ih = g_uiBlurSize.y > 1.0f ? g_uiBlurSize.y : 1.0f; - ImVec2 uv0((pmin.x - g_uiBlurOrigin.x) / iw, (pmin.y - g_uiBlurOrigin.y) / ih); - ImVec2 uv1((pmax.x - g_uiBlurOrigin.x) / iw, (pmax.y - g_uiBlurOrigin.y) / ih); - const int ia = (int)(alpha * 255.0f); - dl->AddImageRounded(g_uiBlurTex, pmin, pmax, uv0, uv1, IM_COL32(255, 255, 255, ia), rounding); - const int tA = (int)(((tint >> IM_COL32_A_SHIFT) & 0xFF) * alpha); - dl->AddRectFilled(pmin, pmax, (tint & ~IM_COL32_A_MASK) | ((ImU32)tA << IM_COL32_A_SHIFT), rounding); - return true; -} + bool DrawUIBlurPanel(ImDrawList* dl, ImVec2 pmin, ImVec2 pmax, float rounding, float alpha, ImU32 tint) { + if (!g_uiBlurTex) return false; + if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; + const float iw = g_uiBlurSize.x > 1.0f ? g_uiBlurSize.x : 1.0f; + const float ih = g_uiBlurSize.y > 1.0f ? g_uiBlurSize.y : 1.0f; + ImVec2 uv0((pmin.x - g_uiBlurOrigin.x) / iw, (pmin.y - g_uiBlurOrigin.y) / ih); + ImVec2 uv1((pmax.x - g_uiBlurOrigin.x) / iw, (pmax.y - g_uiBlurOrigin.y) / ih); + const int ia = (int)(alpha * 255.0f); + dl->AddImageRounded(g_uiBlurTex, pmin, pmax, uv0, uv1, IM_COL32(255, 255, 255, ia), rounding); + const int tA = (int)(((tint >> IM_COL32_A_SHIFT) & 0xFF) * alpha); + dl->AddRectFilled(pmin, pmax, (tint & ~IM_COL32_A_MASK) | ((ImU32)tA << IM_COL32_A_SHIFT), rounding); + return true; + } -static inline float Clampf(float x, float a, float b) { return x < a ? a : (x > b ? b : x); } -static ImU32 kInk = IM_COL32(236, 237, 243, 255); -static ImU32 kInkSoft = IM_COL32(151, 154, 168, 255); -static int g_appearance = 0; -ImU32 InkColor() { return kInk; } -ImU32 InkSoftColor() { return kInkSoft; } -void SetInk(ImU32 primary, ImU32 soft) { kInk = primary; kInkSoft = soft; } -static float g_density = 1.0f; -void SetDensity(float d) { g_density = d < 0.5f ? 0.5f : (d > 1.6f ? 1.6f : d); } -static float g_ui = 1.0f; -void SetWidgetScale(float s) { g_ui = s < 0.25f ? 0.25f : (s > 4.0f ? 4.0f : s); } -float WidgetScale() { return g_ui; } -static inline float US(float v) { return v * g_ui; } -static float g_flow = 0.0f; -void SetLiquidFlow(float f) { g_flow = f < 0.0f ? 0.0f : (f > 24.0f ? 24.0f : f); } -int Appearance() { return g_appearance; } -static bool g_use24 = false; -void Set24Hour(bool v) { g_use24 = v; } -bool Use24Hour() { return g_use24; } -static void* g_photoTex[64]; static int g_photoN = 0; -void SetPhotoTextures(void* const* t, int n) { if (n>64) n=64; for (int i=0;i b ? b : x); } + static ImU32 kInk = IM_COL32(236, 237, 243, 255); + static ImU32 kInkSoft = IM_COL32(151, 154, 168, 255); + static int g_appearance = 0; + ImU32 InkColor() { return kInk; } + ImU32 InkSoftColor() { return kInkSoft; } + void SetInk(ImU32 primary, ImU32 soft) { kInk = primary; kInkSoft = soft; } + static float g_density = 1.0f; + void SetDensity(float d) { g_density = d < 0.5f ? 0.5f : (d > 1.6f ? 1.6f : d); } + static float g_ui = 1.0f; + void SetWidgetScale(float s) { g_ui = s < 0.25f ? 0.25f : (s > 4.0f ? 4.0f : s); } + float WidgetScale() { return g_ui; } + static inline float US(float v) { return v * g_ui; } + static float g_flow = 0.0f; + void SetLiquidFlow(float f) { g_flow = f < 0.0f ? 0.0f : (f > 24.0f ? 24.0f : f); } + int Appearance() { return g_appearance; } + static bool g_use24 = false; + void Set24Hour(bool v) { g_use24 = v; } + bool Use24Hour() { return g_use24; } + static void* g_photoTex[64]; static int g_photoN = 0; + void SetPhotoTextures(void* const* t, int n) { if (n > 64) n = 64; for (int i = 0; i < n; i++) g_photoTex[i] = t[i]; g_photoN = n < 0 ? 0 : n; } + int PhotoCount() { return g_photoN; } + void* PhotoTex(int i) { if (g_photoN <= 0) return nullptr; int k = ((i % g_photoN) + g_photoN) % g_photoN; return g_photoTex[k]; } + static const float kPI = 3.14159265358979f; + static ImU32 AccentCol(); -static ImFont* g_icon_font = nullptr; -static ImFont* g_icon_font_brands = nullptr; -void SetIconFont(ImFont* f) { g_icon_font = f; } -void SetIconFontBrands(ImFont* f) { g_icon_font_brands = f; } + static ImFont* g_icon_font = nullptr; + static ImFont* g_icon_font_brands = nullptr; + void SetIconFont(ImFont* f) { g_icon_font = f; } + void SetIconFontBrands(ImFont* f) { g_icon_font_brands = f; } -static unsigned IconCodepoint(Icon ic) { - switch (ic) { - case Icon::Wifi: return 0xF1EB; - case Icon::Bluetooth: return 0xF293; - case Icon::Bolt: return 0xF0E7; - case Icon::Sun: return 0xF185; - case Icon::Speaker: return 0xF028; - case Icon::Bell: return 0xF0F3; - case Icon::Moon: return 0xF186; - case Icon::Display: return 0xF108; - case Icon::Palette: return 0xF53F; - case Icon::Person: return 0xF007; - case Icon::Lock: return 0xF023; - case Icon::Gear: return 0xF013; - case Icon::Search: return 0xF002; - case Icon::Star: return 0xF005; - case Icon::Cloud: return 0xF0C2; - case Icon::Heart: return 0xF004; - case Icon::Airplane: return 0xF072; - case Icon::Check: return 0xF00C; - case Icon::ChevronR: return 0xF054; - case Icon::Cube: return 0xF1B2; - case Icon::Eye: return 0xF06E; - case Icon::Globe: return 0xF0AC; - case Icon::Gauge: return 0xF625; - case Icon::Crosshairs:return 0xF05B; - case Icon::Box: return 0xF466; - case Icon::Wrench: return 0xF0AD; - case Icon::LocationDot:return 0xF3C5; - case Icon::Spark: return 0xF179; - case Icon::Music: return 0xF001; - case Icon::Play: return 0xF04B; - case Icon::Pause: return 0xF04C; - case Icon::Next: return 0xF051; - case Icon::Prev: return 0xF048; - case Icon::Forward: return 0xF04E; - case Icon::Backward: return 0xF04A; - case Icon::Shuffle: return 0xF074; - case Icon::Repeat: return 0xF363; - case Icon::VolumeLow: return 0xF027; - case Icon::VolumeMute:return 0xF6A9; - case Icon::Microphone:return 0xF130; - case Icon::Video: return 0xF03D; - case Icon::Camera: return 0xF030; - case Icon::Image: return 0xF03E; - case Icon::Images: return 0xF302; - case Icon::Film: return 0xF008; - case Icon::Headphones:return 0xF025; - case Icon::CalendarDays: return 0xF073; - case Icon::CalendarDay: return 0xF783; - case Icon::Clock: return 0xF017; - case Icon::Stopwatch: return 0xF2F2; - case Icon::Hourglass: return 0xF254; - case Icon::BellSlash: return 0xF1F6; - case Icon::Envelope: return 0xF0E0; - case Icon::Comment: return 0xF075; - case Icon::CommentDots:return 0xF4AD; - case Icon::Phone: return 0xF095; - case Icon::PaperPlane:return 0xF1D8; - case Icon::ShareNodes:return 0xF1E0; - case Icon::Map: return 0xF279; - case Icon::MapPin: return 0xF276; - case Icon::Compass: return 0xF14E; - case Icon::LocationArrow:return 0xF124; - case Icon::CloudSun: return 0xF6C4; - case Icon::CloudMoon: return 0xF6C3; - case Icon::CloudRain: return 0xF73D; - case Icon::CloudBolt: return 0xF76C; - case Icon::CloudShowers:return 0xF740; - case Icon::Snowflake: return 0xF2DC; - case Icon::Wind: return 0xF72E; - case Icon::Droplet: return 0xF043; - case Icon::Thermometer:return 0xF2C9; - case Icon::Umbrella: return 0xF0E9; - case Icon::Folder: return 0xF07B; - case Icon::FolderOpen:return 0xF07C; - case Icon::File: return 0xF15B; - case Icon::FileLines: return 0xF15C; - case Icon::Trash: return 0xF1F8; - case Icon::Download: return 0xF019; - case Icon::Upload: return 0xF093; - case Icon::Paperclip: return 0xF0C6; - case Icon::Copy: return 0xF0C5; - case Icon::ArrowUp: return 0xF062; - case Icon::ArrowDown: return 0xF063; - case Icon::ArrowLeft: return 0xF060; - case Icon::ArrowRight:return 0xF061; - case Icon::ChevronL: return 0xF053; - case Icon::ChevronU: return 0xF077; - case Icon::ChevronD: return 0xF078; - case Icon::Refresh: return 0xF021; - case Icon::Expand: return 0xF065; - case Icon::Compress: return 0xF066; - case Icon::Plus: return 0xF067; - case Icon::Minus: return 0xF068; - case Icon::Xmark: return 0xF00D; - case Icon::Sliders: return 0xF1DE; - case Icon::List: return 0xF03A; - case Icon::Grid: return 0xF00A; - case Icon::Bars: return 0xF0C9; - case Icon::Ellipsis: return 0xF141; - case Icon::House: return 0xF015; - case Icon::Users: return 0xF0C0; - case Icon::InfoCircle:return 0xF05A; - case Icon::WarnTriangle:return 0xF071; - case Icon::CheckCircle:return 0xF058; - case Icon::XCircle: return 0xF057; - case Icon::Lightbulb: return 0xF0EB; - case Icon::Paintbrush:return 0xF1FC; - case Icon::Font: return 0xF031; - case Icon::PenEdit: return 0xF044; - case Icon::Link: return 0xF0C1; - case Icon::BatteryFull: return 0xF240; - case Icon::BatteryHalf: return 0xF242; - case Icon::BatteryEmpty:return 0xF244; - case Icon::PowerOff: return 0xF011; - case Icon::Cart: return 0xF07A; - case Icon::CreditCard:return 0xF09D; - case Icon::Gift: return 0xF06B; - case Icon::Tag: return 0xF02B; - case Icon::Bookmark: return 0xF02E; - case Icon::Flag: return 0xF024; - case Icon::Wallet: return 0xF555; - case Icon::Bag: return 0xF290; - case Icon::Key: return 0xF084; - case Icon::Fingerprint:return 0xF577; - case Icon::ShieldHalf:return 0xF3ED; - case Icon::EyeSlash: return 0xF070; - case Icon::LockOpen: return 0xF09C; - case Icon::Code: return 0xF121; - case Icon::Terminal: return 0xF120; - case Icon::Database: return 0xF1C0; - case Icon::Server: return 0xF233; - case Icon::LayerGroup:return 0xF5FD; - case Icon::Signal: return 0xF012; - case Icon::Qrcode: return 0xF029; - case Icon::ToggleOn: return 0xF205; - case Icon::ToggleOff: return 0xF204; - case Icon::Gamepad: return 0xF11B; - case Icon::Keyboard: return 0xF11C; - case Icon::Rocket: return 0xF135; - case Icon::Fire: return 0xF06D; - case Icon::Leaf: return 0xF06C; - case Icon::MugHot: return 0xF7B6; - case Icon::Calculator:return 0xF1EC; - case Icon::ThumbsUp: return 0xF164; - case Icon::StarHalf: return 0xF5C0; - case Icon::Github: return 0xF09B; - case Icon::Spotify: return 0xF1BC; - case Icon::Youtube: return 0xF167; - case Icon::Xtwitter: return 0xE61B; - case Icon::Google: return 0xF1A0; - case Icon::Windows: return 0xF17A; - case Icon::Android: return 0xF17B; - case Icon::Discord: return 0xF392; - case Icon::Newspaper: return 0xF1EA; - case Icon::Book: return 0xF02D; - case Icon::BookOpen: return 0xF518; - case Icon::Tv: return 0xF26C; - case Icon::Trophy: return 0xF091; - case Icon::Medal: return 0xF5A2; - case Icon::Crown: return 0xF521; - case Icon::Gem: return 0xF3A5; - case Icon::Dumbbell: return 0xF44B; - case Icon::Running: return 0xF70C; - case Icon::Walking: return 0xF554; - case Icon::Bed: return 0xF236; - case Icon::Pills: return 0xF484; - case Icon::Stethoscope:return 0xF0F1; - case Icon::Car: return 0xF1B9; - case Icon::Train: return 0xF238; - case Icon::Bus: return 0xF207; - case Icon::Bicycle: return 0xF206; - case Icon::Utensils: return 0xF2E7; - case Icon::Pizza: return 0xF818; - case Icon::Fish: return 0xF578; - case Icon::Tree: return 0xF1BB; - case Icon::Mountain: return 0xF6FC; - case Icon::Dice: return 0xF522; - case Icon::Ticket: return 0xF3FF; - case Icon::Guitar: return 0xF7A6; - default: return 0; + static unsigned IconCodepoint(Icon ic) { + switch (ic) { + case Icon::Wifi: return 0xF1EB; + case Icon::Bluetooth: return 0xF293; + case Icon::Bolt: return 0xF0E7; + case Icon::Sun: return 0xF185; + case Icon::Speaker: return 0xF028; + case Icon::Bell: return 0xF0F3; + case Icon::Moon: return 0xF186; + case Icon::Display: return 0xF108; + case Icon::Palette: return 0xF53F; + case Icon::Person: return 0xF007; + case Icon::Lock: return 0xF023; + case Icon::Gear: return 0xF013; + case Icon::Search: return 0xF002; + case Icon::Star: return 0xF005; + case Icon::Cloud: return 0xF0C2; + case Icon::Heart: return 0xF004; + case Icon::Airplane: return 0xF072; + case Icon::Check: return 0xF00C; + case Icon::ChevronR: return 0xF054; + case Icon::Cube: return 0xF1B2; + case Icon::Eye: return 0xF06E; + case Icon::Globe: return 0xF0AC; + case Icon::Gauge: return 0xF625; + case Icon::Crosshairs:return 0xF05B; + case Icon::Box: return 0xF466; + case Icon::Wrench: return 0xF0AD; + case Icon::LocationDot:return 0xF3C5; + case Icon::Spark: return 0xF179; + case Icon::Music: return 0xF001; + case Icon::Play: return 0xF04B; + case Icon::Pause: return 0xF04C; + case Icon::Next: return 0xF051; + case Icon::Prev: return 0xF048; + case Icon::Forward: return 0xF04E; + case Icon::Backward: return 0xF04A; + case Icon::Shuffle: return 0xF074; + case Icon::Repeat: return 0xF363; + case Icon::VolumeLow: return 0xF027; + case Icon::VolumeMute:return 0xF6A9; + case Icon::Microphone:return 0xF130; + case Icon::Video: return 0xF03D; + case Icon::Camera: return 0xF030; + case Icon::Image: return 0xF03E; + case Icon::Images: return 0xF302; + case Icon::Film: return 0xF008; + case Icon::Headphones:return 0xF025; + case Icon::CalendarDays: return 0xF073; + case Icon::CalendarDay: return 0xF783; + case Icon::Clock: return 0xF017; + case Icon::Stopwatch: return 0xF2F2; + case Icon::Hourglass: return 0xF254; + case Icon::BellSlash: return 0xF1F6; + case Icon::Envelope: return 0xF0E0; + case Icon::Comment: return 0xF075; + case Icon::CommentDots:return 0xF4AD; + case Icon::Phone: return 0xF095; + case Icon::PaperPlane:return 0xF1D8; + case Icon::ShareNodes:return 0xF1E0; + case Icon::Map: return 0xF279; + case Icon::MapPin: return 0xF276; + case Icon::Compass: return 0xF14E; + case Icon::LocationArrow:return 0xF124; + case Icon::CloudSun: return 0xF6C4; + case Icon::CloudMoon: return 0xF6C3; + case Icon::CloudRain: return 0xF73D; + case Icon::CloudBolt: return 0xF76C; + case Icon::CloudShowers:return 0xF740; + case Icon::Snowflake: return 0xF2DC; + case Icon::Wind: return 0xF72E; + case Icon::Droplet: return 0xF043; + case Icon::Thermometer:return 0xF2C9; + case Icon::Umbrella: return 0xF0E9; + case Icon::Folder: return 0xF07B; + case Icon::FolderOpen:return 0xF07C; + case Icon::File: return 0xF15B; + case Icon::FileLines: return 0xF15C; + case Icon::Trash: return 0xF1F8; + case Icon::Download: return 0xF019; + case Icon::Upload: return 0xF093; + case Icon::Paperclip: return 0xF0C6; + case Icon::Copy: return 0xF0C5; + case Icon::ArrowUp: return 0xF062; + case Icon::ArrowDown: return 0xF063; + case Icon::ArrowLeft: return 0xF060; + case Icon::ArrowRight:return 0xF061; + case Icon::ChevronL: return 0xF053; + case Icon::ChevronU: return 0xF077; + case Icon::ChevronD: return 0xF078; + case Icon::Refresh: return 0xF021; + case Icon::Expand: return 0xF065; + case Icon::Compress: return 0xF066; + case Icon::Plus: return 0xF067; + case Icon::Minus: return 0xF068; + case Icon::Xmark: return 0xF00D; + case Icon::Sliders: return 0xF1DE; + case Icon::List: return 0xF03A; + case Icon::Grid: return 0xF00A; + case Icon::Bars: return 0xF0C9; + case Icon::Ellipsis: return 0xF141; + case Icon::House: return 0xF015; + case Icon::Users: return 0xF0C0; + case Icon::InfoCircle:return 0xF05A; + case Icon::WarnTriangle:return 0xF071; + case Icon::CheckCircle:return 0xF058; + case Icon::XCircle: return 0xF057; + case Icon::Lightbulb: return 0xF0EB; + case Icon::Paintbrush:return 0xF1FC; + case Icon::Font: return 0xF031; + case Icon::PenEdit: return 0xF044; + case Icon::Link: return 0xF0C1; + case Icon::BatteryFull: return 0xF240; + case Icon::BatteryHalf: return 0xF242; + case Icon::BatteryEmpty:return 0xF244; + case Icon::PowerOff: return 0xF011; + case Icon::Cart: return 0xF07A; + case Icon::CreditCard:return 0xF09D; + case Icon::Gift: return 0xF06B; + case Icon::Tag: return 0xF02B; + case Icon::Bookmark: return 0xF02E; + case Icon::Flag: return 0xF024; + case Icon::Wallet: return 0xF555; + case Icon::Bag: return 0xF290; + case Icon::Key: return 0xF084; + case Icon::Fingerprint:return 0xF577; + case Icon::ShieldHalf:return 0xF3ED; + case Icon::EyeSlash: return 0xF070; + case Icon::LockOpen: return 0xF09C; + case Icon::Code: return 0xF121; + case Icon::Terminal: return 0xF120; + case Icon::Database: return 0xF1C0; + case Icon::Server: return 0xF233; + case Icon::LayerGroup:return 0xF5FD; + case Icon::Signal: return 0xF012; + case Icon::Qrcode: return 0xF029; + case Icon::ToggleOn: return 0xF205; + case Icon::ToggleOff: return 0xF204; + case Icon::Gamepad: return 0xF11B; + case Icon::Keyboard: return 0xF11C; + case Icon::Rocket: return 0xF135; + case Icon::Fire: return 0xF06D; + case Icon::Leaf: return 0xF06C; + case Icon::MugHot: return 0xF7B6; + case Icon::Calculator:return 0xF1EC; + case Icon::ThumbsUp: return 0xF164; + case Icon::StarHalf: return 0xF5C0; + case Icon::Github: return 0xF09B; + case Icon::Spotify: return 0xF1BC; + case Icon::Youtube: return 0xF167; + case Icon::Xtwitter: return 0xE61B; + case Icon::Google: return 0xF1A0; + case Icon::Windows: return 0xF17A; + case Icon::Android: return 0xF17B; + case Icon::Discord: return 0xF392; + case Icon::Newspaper: return 0xF1EA; + case Icon::Book: return 0xF02D; + case Icon::BookOpen: return 0xF518; + case Icon::Tv: return 0xF26C; + case Icon::Trophy: return 0xF091; + case Icon::Medal: return 0xF5A2; + case Icon::Crown: return 0xF521; + case Icon::Gem: return 0xF3A5; + case Icon::Dumbbell: return 0xF44B; + case Icon::Running: return 0xF70C; + case Icon::Walking: return 0xF554; + case Icon::Bed: return 0xF236; + case Icon::Pills: return 0xF484; + case Icon::Stethoscope:return 0xF0F1; + case Icon::Car: return 0xF1B9; + case Icon::Train: return 0xF238; + case Icon::Bus: return 0xF207; + case Icon::Bicycle: return 0xF206; + case Icon::Utensils: return 0xF2E7; + case Icon::Pizza: return 0xF818; + case Icon::Fish: return 0xF578; + case Icon::Tree: return 0xF1BB; + case Icon::Mountain: return 0xF6FC; + case Icon::Dice: return 0xF522; + case Icon::Ticket: return 0xF3FF; + case Icon::Guitar: return 0xF7A6; + default: return 0; + } } -} -static bool IconIsBrand(Icon ic) { - switch (ic) { - case Icon::Bluetooth: case Icon::Spark: case Icon::Github: case Icon::Spotify: - case Icon::Youtube: case Icon::Xtwitter: case Icon::Google: case Icon::Windows: - case Icon::Android: case Icon::Discord: - return true; - default: - return false; + static bool IconIsBrand(Icon ic) { + switch (ic) { + case Icon::Bluetooth: case Icon::Spark: case Icon::Github: case Icon::Spotify: + case Icon::Youtube: case Icon::Xtwitter: case Icon::Google: case Icon::Windows: + case Icon::Android: case Icon::Discord: + return true; + default: + return false; + } } -} -static MaterialParams kMaterials[] = { - { 0.28f, 1.65f, 0.050f, 1.04f, {0.17f,0.17f,0.21f}, 0.30f, 0.012f, 16.f, 20.f, 0.42f,0.12f,0.18f,1.4f,0.08f,28.f,0.f, 9.f, 0.45f, 1.0f }, - { 0.00f, 0.50f, 0.050f, 1.04f, {0.16f,0.16f,0.20f}, 0.00f, 0.010f, 40.f, 40.f, 1.00f,0.14f,0.20f,1.4f,0.60f,46.f,0.f,16.f, 0.40f, 6.0f }, - { 0.58f, 1.65f, 0.040f, 1.04f, {0.14f,0.14f,0.18f}, 0.52f, 0.008f, 26.f, 28.f, 0.55f,0.16f,0.22f,1.4f,0.18f,52.f,0.f,20.f, 0.50f, 1.8f }, - { 0.85f, 1.40f, 0.050f, 1.00f, {0.04f,0.52f,1.0f}, 0.90f, 0.010f, 14.f, 18.f, 0.55f,0.18f,0.18f,1.2f,0.15f,24.f,0.f, 8.f, 0.80f, 0.0f }, - { 0.55f, 1.10f, 0.080f, 1.00f, {0.97f,0.97f,1.0f}, 0.94f, 0.000f, 12.f, 14.f, 0.72f,0.22f,0.24f,1.0f,0.22f,13.f,0.f, 4.f, 1.20f, 1.2f }, - { 0.00f, 1.00f, 0.000f, 1.00f, {0.00f,0.00f,0.00f}, 0.00f, 0.000f, 0.f, 1.f, 0.00f,0.00f,0.00f,0.0f,0.00f, 0.f,0.f, 0.f, 0.00f, 0.0f }, -}; + static MaterialParams kMaterials[] = { + { 0.28f, 1.65f, 0.050f, 1.04f, {0.17f,0.17f,0.21f}, 0.30f, 0.012f, 16.f, 20.f, 0.42f,0.12f,0.18f,1.4f,0.08f,28.f,0.f, 9.f, 0.45f, 1.0f }, + { 0.00f, 0.50f, 0.050f, 1.04f, {0.16f,0.16f,0.20f}, 0.00f, 0.010f, 40.f, 40.f, 1.00f,0.14f,0.20f,1.4f,0.60f,46.f,0.f,16.f, 0.40f, 6.0f }, + { 0.58f, 1.65f, 0.040f, 1.04f, {0.14f,0.14f,0.18f}, 0.52f, 0.008f, 26.f, 28.f, 0.55f,0.16f,0.22f,1.4f,0.18f,52.f,0.f,20.f, 0.50f, 1.8f }, + { 0.85f, 1.40f, 0.050f, 1.00f, {0.04f,0.52f,1.0f}, 0.90f, 0.010f, 14.f, 18.f, 0.55f,0.18f,0.18f,1.2f,0.15f,24.f,0.f, 8.f, 0.80f, 0.0f }, + { 0.55f, 1.10f, 0.080f, 1.00f, {0.97f,0.97f,1.0f}, 0.94f, 0.000f, 12.f, 14.f, 0.72f,0.22f,0.24f,1.0f,0.22f,13.f,0.f, 4.f, 1.20f, 1.2f }, + { 0.00f, 1.00f, 0.000f, 1.00f, {0.00f,0.00f,0.00f}, 0.00f, 0.000f, 0.f, 1.f, 0.00f,0.00f,0.00f,0.0f,0.00f, 0.f,0.f, 0.f, 0.00f, 0.0f }, + }; -const MaterialParams& Params(Material m) { - int i = (int)m; - if (i < 0 || i >= (int)(sizeof(kMaterials)/sizeof(kMaterials[0]))) i = (int)Material::Regular; - return kMaterials[i]; -} + const MaterialParams& Params(Material m) { + int i = (int)m; + if (i < 0 || i >= (int)(sizeof(kMaterials) / sizeof(kMaterials[0]))) i = (int)Material::Regular; + return kMaterials[i]; + } -MaterialParams& EditParams(Material m) { - int i = (int)m; - if (i < 0 || i >= (int)(sizeof(kMaterials)/sizeof(kMaterials[0]))) i = (int)Material::Regular; - return kMaterials[i]; -} + MaterialParams& EditParams(Material m) { + int i = (int)m; + if (i < 0 || i >= (int)(sizeof(kMaterials) / sizeof(kMaterials[0]))) i = (int)Material::Regular; + return kMaterials[i]; + } -void SetGlobalMaterial(float blur, float opacity, float sat, float refr, float chroma, float edge, float shadow) { - const Material ms[] = { Material::Thin, Material::Regular, Material::Thick }; - for (Material m : ms) { - MaterialParams& p = kMaterials[(int)m]; - p.blur_mix = blur; p.tint_opacity = opacity; p.saturation = sat; - p.refr_strength = refr; p.refr_band = refr > 8.0f ? refr : 8.0f; p.chroma = chroma; - p.highlight = edge; p.shadow_strength = shadow; + void SetGlobalMaterial(float blur, float opacity, float sat, float refr, float chroma, float edge, float shadow) { + const Material ms[] = { Material::Thin, Material::Regular, Material::Thick }; + for (Material m : ms) { + MaterialParams& p = kMaterials[(int)m]; + p.blur_mix = blur; p.tint_opacity = opacity; p.saturation = sat; + p.refr_strength = refr; p.refr_band = refr > 8.0f ? refr : 8.0f; p.chroma = chroma; + p.highlight = edge; p.shadow_strength = shadow; + } } -} -void SetAccent(float r, float gn, float b) { - kMaterials[(int)Material::Accent].tint_rgb[0] = r; - kMaterials[(int)Material::Accent].tint_rgb[1] = gn; - kMaterials[(int)Material::Accent].tint_rgb[2] = b; -} + void SetAccent(float r, float gn, float b) { + kMaterials[(int)Material::Accent].tint_rgb[0] = r; + kMaterials[(int)Material::Accent].tint_rgb[1] = gn; + kMaterials[(int)Material::Accent].tint_rgb[2] = b; + } -static MaterialParams g_matDefaults[8]; static bool g_matSaved = false; -void SetAppearance(int mode) { - int N = (int)(sizeof(kMaterials)/sizeof(kMaterials[0])); - if (!g_matSaved) { for (int i=0;iCreateBuffer(&bd, nullptr, &cb_))) return false; } - { D3D11_SAMPLER_DESC sd = {}; - sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.MaxLOD = D3D11_FLOAT32_MAX; - if (FAILED(device_->CreateSamplerState(&sd, &sampler_))) return false; } - { D3D11_BLEND_DESC bd = {}; - bd.RenderTarget[0].BlendEnable = TRUE; - bd.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - bd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - if (FAILED(device_->CreateBlendState(&bd, &blend_))) return false; } - { D3D11_RASTERIZER_DESC rd = {}; - rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; rd.DepthClipEnable = TRUE; - rd.ScissorEnable = TRUE; - if (FAILED(device_->CreateRasterizerState(&rd, &raster_))) return false; } - { D3D11_DEPTH_STENCIL_DESC dd = {}; - dd.DepthEnable = FALSE; dd.StencilEnable = FALSE; - if (FAILED(device_->CreateDepthStencilState(&dd, &depth_))) return false; } - return true; -} + bool Renderer::Init(ID3D11Device* device, ID3D11DeviceContext* ctx) { + device_ = device; ctx_ = ctx; + if (!CompileShaders()) return false; + { + D3D11_BUFFER_DESC bd = {}; + bd.ByteWidth = sizeof(GlassCB); bd.Usage = D3D11_USAGE_DYNAMIC; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (FAILED(device_->CreateBuffer(&bd, nullptr, &cb_))) return false; + } + { + D3D11_SAMPLER_DESC sd = {}; + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.MaxLOD = D3D11_FLOAT32_MAX; + if (FAILED(device_->CreateSamplerState(&sd, &sampler_))) return false; + } + { + D3D11_BLEND_DESC bd = {}; + bd.RenderTarget[0].BlendEnable = TRUE; + bd.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + bd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + if (FAILED(device_->CreateBlendState(&bd, &blend_))) return false; + } + { + D3D11_RASTERIZER_DESC rd = {}; + rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; rd.DepthClipEnable = TRUE; + rd.ScissorEnable = TRUE; + if (FAILED(device_->CreateRasterizerState(&rd, &raster_))) return false; + } + { + D3D11_DEPTH_STENCIL_DESC dd = {}; + dd.DepthEnable = FALSE; dd.StencilEnable = FALSE; + if (FAILED(device_->CreateDepthStencilState(&dd, &depth_))) return false; + } + return true; + } -void Renderer::Shutdown() { - if (depth_) { depth_->Release(); depth_ = nullptr; } - if (raster_) { raster_->Release(); raster_ = nullptr; } - if (blend_) { blend_->Release(); blend_ = nullptr; } - if (sampler_) { sampler_->Release(); sampler_ = nullptr; } - if (cb_) { cb_->Release(); cb_ = nullptr; } - if (ps_) { ps_->Release(); ps_ = nullptr; } - if (vs_) { vs_->Release(); vs_ = nullptr; } -} + void Renderer::Shutdown() { + if (depth_) { depth_->Release(); depth_ = nullptr; } + if (raster_) { raster_->Release(); raster_ = nullptr; } + if (blend_) { blend_->Release(); blend_ = nullptr; } + if (sampler_) { sampler_->Release(); sampler_ = nullptr; } + if (cb_) { cb_->Release(); cb_ = nullptr; } + if (ps_) { ps_->Release(); ps_ = nullptr; } + if (vs_) { vs_->Release(); vs_ = nullptr; } + } -bool Renderer::CompileShaders() { - ID3DBlob *vb = nullptr, *pb = nullptr, *err = nullptr; HRESULT hr; - size_t len = std::strlen(kGlassHLSL); - hr = D3DCompile(kGlassHLSL, len, "GlassVS", nullptr, nullptr, "VS_Glass", "vs_5_0", 0, 0, &vb, &err); - if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } return false; } - hr = D3DCompile(kGlassHLSL, len, "GlassPS", nullptr, nullptr, "PS_Glass", "ps_5_0", 0, 0, &pb, &err); - if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); return false; } - hr = device_->CreateVertexShader(vb->GetBufferPointer(), vb->GetBufferSize(), nullptr, &vs_); vb->Release(); - if (FAILED(hr)) { pb->Release(); return false; } - { - ID3D11ShaderReflection* refl = nullptr; - if (SUCCEEDED(D3DReflect(pb->GetBufferPointer(), pb->GetBufferSize(), - __uuidof(ID3D11ShaderReflection), (void**)&refl)) && refl) { - if (ID3D11ShaderReflectionConstantBuffer* rcb = refl->GetConstantBufferByName("GlassCB")) { - D3D11_SHADER_BUFFER_DESC sbd = {}; - if (SUCCEEDED(rcb->GetDesc(&sbd)) && sbd.Size != (UINT)sizeof(GlassCB)) { - char msg[160]; - std::snprintf(msg, sizeof(msg), - "[Glass] GlassCB size mismatch: HLSL cbuffer=%u bytes vs C++ struct=%u bytes\n", - sbd.Size, (unsigned)sizeof(GlassCB)); - OutputDebugStringA(msg); - IM_ASSERT(false && "GlassCB layout drift: shaders.h cbuffer != glass.cpp struct"); + bool Renderer::CompileShaders() { + ID3DBlob* vb = nullptr, * pb = nullptr, * err = nullptr; HRESULT hr; + size_t len = std::strlen(kGlassHLSL); + hr = D3DCompile(kGlassHLSL, len, "GlassVS", nullptr, nullptr, "VS_Glass", "vs_5_0", 0, 0, &vb, &err); + if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } return false; } + hr = D3DCompile(kGlassHLSL, len, "GlassPS", nullptr, nullptr, "PS_Glass", "ps_5_0", 0, 0, &pb, &err); + if (FAILED(hr)) { if (err) { OutputDebugStringA((char*)err->GetBufferPointer()); err->Release(); } vb->Release(); return false; } + hr = device_->CreateVertexShader(vb->GetBufferPointer(), vb->GetBufferSize(), nullptr, &vs_); vb->Release(); + if (FAILED(hr)) { pb->Release(); return false; } + { + ID3D11ShaderReflection* refl = nullptr; + if (SUCCEEDED(D3DReflect(pb->GetBufferPointer(), pb->GetBufferSize(), + __uuidof(ID3D11ShaderReflection), (void**)&refl)) && refl) { + if (ID3D11ShaderReflectionConstantBuffer* rcb = refl->GetConstantBufferByName("GlassCB")) { + D3D11_SHADER_BUFFER_DESC sbd = {}; + if (SUCCEEDED(rcb->GetDesc(&sbd)) && sbd.Size != (UINT)sizeof(GlassCB)) { + char msg[160]; + std::snprintf(msg, sizeof(msg), + "[Glass] GlassCB size mismatch: HLSL cbuffer=%u bytes vs C++ struct=%u bytes\n", + sbd.Size, (unsigned)sizeof(GlassCB)); + OutputDebugStringA(msg); + IM_ASSERT(false && "GlassCB layout drift: shaders.h cbuffer != glass.cpp struct"); + } } + refl->Release(); } - refl->Release(); } + hr = device_->CreatePixelShader(pb->GetBufferPointer(), pb->GetBufferSize(), nullptr, &ps_); pb->Release(); + return SUCCEEDED(hr); } - hr = device_->CreatePixelShader(pb->GetBufferPointer(), pb->GetBufferSize(), nullptr, &ps_); pb->Release(); - return SUCCEEDED(hr); -} -void Renderer::BeginFrame(int win_w, int win_h, int win_x, int win_y, - int desk_w, int desk_h, ImVec2 cursor) { - win_w_ = win_w; win_h_ = win_h; win_x_ = win_x; win_y_ = win_y; - desk_w_ = desk_w; desk_h_ = desk_h; - cursor_x_ = cursor.x; cursor_y_ = cursor.y; - queue_.clear(); - overlay_.clear(); - submit_fade_ = 1.0f; - ClearClipRect(); - float dt = ImGui::GetIO().DeltaTime; - time_ += dt; - Spring& e = springs_.Get(0xE0E0E0u, 0, SpringStyle::Bouncy, 0.0f); - e.target = 1.0f; e.Tick(dt); - entrance_ = e.x; - float th = light_angle_deg_ * (kPI / 180.0f); - float th2 = light2_angle_deg_ * (kPI / 180.0f); - light_x_ = std::sin(th); light_y_ = -std::cos(th); - light2_x_ = std::sin(th2); light2_y_ = -std::cos(th2); -} + void Renderer::BeginFrame(int win_w, int win_h, int win_x, int win_y, + int desk_w, int desk_h, ImVec2 cursor) { + win_w_ = win_w; win_h_ = win_h; win_x_ = win_x; win_y_ = win_y; + desk_w_ = desk_w; desk_h_ = desk_h; + cursor_x_ = cursor.x; cursor_y_ = cursor.y; + queue_.clear(); + overlay_.clear(); + submit_fade_ = 1.0f; + ClearClipRect(); + float dt = ImGui::GetIO().DeltaTime; + time_ += dt; + Spring& e = springs_.Get(0xE0E0E0u, 0, SpringStyle::Bouncy, 0.0f); + e.target = 1.0f; e.Tick(dt); + entrance_ = e.x; + float th = light_angle_deg_ * (kPI / 180.0f); + float th2 = light2_angle_deg_ * (kPI / 180.0f); + light_x_ = std::sin(th); light_y_ = -std::cos(th); + light2_x_ = std::sin(th2); light2_y_ = -std::cos(th2); + } -size_t Renderer::Submit(const Primitive& p) { - queue_.push_back(p); - Primitive& q = queue_.back(); q.fade *= submit_fade_; - q.clip[0] = clip_[0]; q.clip[1] = clip_[1]; q.clip[2] = clip_[2]; q.clip[3] = clip_[3]; - return queue_.size() - 1; -} -Primitive& Renderer::At(size_t i) { return queue_[i]; } -void Renderer::SubmitOverlay(const Primitive& p) { overlay_.push_back(p); } + size_t Renderer::Submit(const Primitive& p) { + queue_.push_back(p); + Primitive& q = queue_.back(); q.fade *= submit_fade_; + q.clip[0] = clip_[0]; q.clip[1] = clip_[1]; q.clip[2] = clip_[2]; q.clip[3] = clip_[3]; + return queue_.size() - 1; + } + Primitive& Renderer::At(size_t i) { return queue_[i]; } + void Renderer::SubmitOverlay(const Primitive& p) { overlay_.push_back(p); } -void Renderer::Render(ID3D11ShaderResourceView* heavy, ID3D11ShaderResourceView* soft) { - if (queue_.empty() && overlay_.empty()) return; - ctx_->OMSetDepthStencilState(depth_, 0); - const FLOAT bf[4] = { 0,0,0,0 }; - ctx_->OMSetBlendState(blend_, bf, 0xffffffff); - ctx_->RSSetState(raster_); - ctx_->VSSetShader(vs_, nullptr, 0); - ctx_->PSSetShader(ps_, nullptr, 0); - ctx_->IASetInputLayout(nullptr); - ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - ctx_->VSSetConstantBuffers(0, 1, &cb_); - ctx_->PSSetConstantBuffers(0, 1, &cb_); - ctx_->PSSetSamplers(0, 1, &sampler_); - ID3D11ShaderResourceView* srvs[2] = { heavy, soft }; - ctx_->PSSetShaderResources(0, 2, srvs); - const float ent = std::min(1.0f, std::max(0.0f, entrance_)); - const float rimA_ = edge_cfg_.panel_rim_angle * (kPI / 180.0f); - const float rimSin_ = std::sin(rimA_), rimNegCos_ = -std::cos(rimA_); - auto draw_one = [&](const Primitive& p) { - if (p.fade <= 0.0f || p.hw <= 0.0f || p.hh <= 0.0f) return; - D3D11_RECT sc; - sc.left = (LONG)(std::max(0.0f, p.clip[0]) * render_scale_); - sc.top = (LONG)(std::max(0.0f, p.clip[1]) * render_scale_); - sc.right = (LONG)(std::min((float)win_w_, p.clip[2]) * render_scale_); - sc.bottom = (LONG)(std::min((float)win_h_, p.clip[3]) * render_scale_); - if (sc.right < sc.left) sc.right = sc.left; - if (sc.bottom < sc.top) sc.bottom = sc.top; - ctx_->RSSetScissorRects(1, &sc); - const MaterialParams& m = Params(p.material); - D3D11_MAPPED_SUBRESOURCE map = {}; - if (FAILED(ctx_->Map(cb_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map))) return; - GlassCB* d = (GlassCB*)map.pData; - d->window_size[0] = (float)win_w_; d->window_size[1] = (float)win_h_; - d->desktop_size[0] = (float)desk_w_; d->desktop_size[1] = (float)desk_h_; - d->window_origin[0] = (float)win_x_; d->window_origin[1] = (float)win_y_; - d->light_dir[0] = light_x_; d->light_dir[1] = light_y_; - d->widget_center[0] = p.cx; d->widget_center[1] = p.cy; - d->widget_half_size[0] = std::max(0.5f, p.hw); - d->widget_half_size[1] = std::max(0.5f, p.hh); - d->corner_radius = std::min(p.corner_radius, std::min(p.hw, p.hh)); - d->fade = p.fade * ent; - d->blur_mix = m.blur_mix; - d->saturation = m.saturation; - d->tint_color[0] = m.tint_rgb[0]; d->tint_color[1] = m.tint_rgb[1]; - d->tint_color[2] = m.tint_rgb[2]; d->tint_color[3] = 1.0f; - d->tint_opacity = m.tint_opacity; - d->brightness = m.brightness; - d->contrast = m.contrast; - d->grain = m.grain; - d->refr_strength = m.refr_strength; - d->refr_band = m.refr_band; - d->highlight = m.highlight; - d->inner_shadow = m.inner_shadow; - float el = p.elevate; - d->border_intensity = m.border_intensity; - d->border_width = m.border_width; - d->shadow_strength = std::min(0.9f, m.shadow_strength * el); - d->shadow_radius = m.shadow_radius * el; - d->shadow_offset[0] = m.shadow_off_x * el; - d->shadow_offset[1] = m.shadow_off_y * el; - d->time = time_; - d->quad_pad = m.shadow_radius * el - + std::max(std::fabs(m.shadow_off_x), std::fabs(m.shadow_off_y)) * el - + m.border_width + 3.0f; - d->tilt[0] = tilt_x_; d->tilt[1] = tilt_y_; - d->sheen = m.sheen; - d->chroma = m.chroma; - d->cursor[0] = cursor_x_; d->cursor[1] = cursor_y_; - d->_pad_cur[0] = g_flow; - d->_pad_cur[1] = 0.0f; - d->blob1_center[0] = p.b1x; d->blob1_center[1] = p.b1y; - d->blob1_half[0] = p.b1w; d->blob1_half[1] = p.b1h; - d->blob2_center[0] = p.b2x; d->blob2_center[1] = p.b2y; - d->blob2_half[0] = p.b2w; d->blob2_half[1] = p.b2h; - d->blob_k = p.blob_k; - d->_pad_blob[0] = d->_pad_blob[1] = d->_pad_blob[2] = 0.0f; - d->edge0[0] = edge_cfg_.fresnel_exp; d->edge0[1] = edge_cfg_.bevel_scale; - d->edge0[2] = edge_cfg_.lip; d->edge0[3] = edge_cfg_.specular_exp; - d->edge1[0] = edge_cfg_.specular_amt; d->edge1[1] = edge_cfg_.front_amt; - d->edge1[2] = edge_cfg_.back_amt; d->edge1[3] = edge_cfg_.sat_pop; - d->edge2[0] = edge_cfg_.bevel_tilt; d->edge2[1] = edge_cfg_.light_height; - d->edge2[2] = edge_cfg_.edge_shadow; d->edge2[3] = edge_cfg_.cursor_size; - d->edge3[0] = edge_cfg_.cursor_glow; d->edge3[1] = edge_cfg_.sheen_amt; - d->edge3[2] = edge_cfg_.grain_amt; d->edge3[3] = edge_cfg_.ambient_rim; - d->edge4[0] = edge_cfg_.front_spread; d->edge4[1] = edge_cfg_.back_spread; - d->edge4[2] = edge_cfg_.panel_br_spread; d->edge4[3] = edge_cfg_.panel_br_smooth; - d->edge5[0] = light2_x_; d->edge5[1] = light2_y_; - d->edge5[2] = light1_amt_; d->edge5[3] = light2_amt_; - d->edge6[0] = rimSin_; d->edge6[1] = rimNegCos_; - d->edge6[2] = edge_cfg_.tbl_fill; - d->edge6[3] = 0.0f; - d->edge7[0] = edge_cfg_.adapt_strength; - d->edge7[1] = edge_cfg_.adapt_pivot; d->edge7[2] = edge_cfg_.adapt_soft; - d->edge7[3] = edge_cfg_.smooth_refraction; - d->edge8[0] = edge_cfg_.squircle_power; d->edge8[1] = edge_cfg_.lens_amount; - d->edge8[2] = edge_cfg_.lens_power; d->edge8[3] = edge_cfg_.lens_a; - d->edge9[0] = edge_cfg_.lens_b; d->edge9[1] = edge_cfg_.lens_c; d->edge9[2] = edge_cfg_.lens_d; - d->edge9[3] = edge_cfg_.glow_weight; - d->edge10[0] = edge_cfg_.glow_phase; d->edge10[1] = edge_cfg_.glow_edge0; - d->edge10[2] = edge_cfg_.glow_edge1; d->edge10[3] = edge_cfg_.glow_bias; - d->edge11[0] = edge_cfg_.glow_anim; d->edge11[1] = d->edge11[2] = d->edge11[3] = 0.0f; - ctx_->Unmap(cb_, 0); - ctx_->Draw(6, 0); - }; - for (const Primitive& p : queue_) draw_one(p); - for (const Primitive& p : overlay_) draw_one(p); - ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; - ctx_->PSSetShaderResources(0, 2, nullsrv); -} + void Renderer::Render(ID3D11ShaderResourceView* heavy, ID3D11ShaderResourceView* soft) { + if (queue_.empty() && overlay_.empty()) return; + ctx_->OMSetDepthStencilState(depth_, 0); + const FLOAT bf[4] = { 0,0,0,0 }; + ctx_->OMSetBlendState(blend_, bf, 0xffffffff); + ctx_->RSSetState(raster_); + ctx_->VSSetShader(vs_, nullptr, 0); + ctx_->PSSetShader(ps_, nullptr, 0); + ctx_->IASetInputLayout(nullptr); + ctx_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx_->VSSetConstantBuffers(0, 1, &cb_); + ctx_->PSSetConstantBuffers(0, 1, &cb_); + ctx_->PSSetSamplers(0, 1, &sampler_); + ID3D11ShaderResourceView* srvs[2] = { heavy, soft }; + ctx_->PSSetShaderResources(0, 2, srvs); + const float ent = std::min(1.0f, std::max(0.0f, entrance_)); + const float rimA_ = edge_cfg_.panel_rim_angle * (kPI / 180.0f); + const float rimSin_ = std::sin(rimA_), rimNegCos_ = -std::cos(rimA_); + auto draw_one = [&](const Primitive& p) { + if (p.fade <= 0.0f || p.hw <= 0.0f || p.hh <= 0.0f) return; + D3D11_RECT sc; + sc.left = (LONG)(std::max(0.0f, p.clip[0]) * render_scale_); + sc.top = (LONG)(std::max(0.0f, p.clip[1]) * render_scale_); + sc.right = (LONG)(std::min((float)win_w_, p.clip[2]) * render_scale_); + sc.bottom = (LONG)(std::min((float)win_h_, p.clip[3]) * render_scale_); + if (sc.right < sc.left) sc.right = sc.left; + if (sc.bottom < sc.top) sc.bottom = sc.top; + ctx_->RSSetScissorRects(1, &sc); + const MaterialParams& m = Params(p.material); + D3D11_MAPPED_SUBRESOURCE map = {}; + if (FAILED(ctx_->Map(cb_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map))) return; + GlassCB* d = (GlassCB*)map.pData; + d->window_size[0] = (float)win_w_; d->window_size[1] = (float)win_h_; + d->desktop_size[0] = (float)desk_w_; d->desktop_size[1] = (float)desk_h_; + d->window_origin[0] = (float)win_x_; d->window_origin[1] = (float)win_y_; + d->light_dir[0] = light_x_; d->light_dir[1] = light_y_; + d->widget_center[0] = p.cx; d->widget_center[1] = p.cy; + d->widget_half_size[0] = std::max(0.5f, p.hw); + d->widget_half_size[1] = std::max(0.5f, p.hh); + d->corner_radius = std::min(p.corner_radius, std::min(p.hw, p.hh)); + d->fade = p.fade * ent; + d->blur_mix = m.blur_mix; + d->saturation = m.saturation; + d->tint_color[0] = m.tint_rgb[0]; d->tint_color[1] = m.tint_rgb[1]; + d->tint_color[2] = m.tint_rgb[2]; d->tint_color[3] = 1.0f; + d->tint_opacity = m.tint_opacity; + d->brightness = m.brightness; + d->contrast = m.contrast; + d->grain = m.grain; + d->refr_strength = m.refr_strength; + d->refr_band = m.refr_band; + d->highlight = m.highlight; + d->inner_shadow = m.inner_shadow; + float el = p.elevate; + d->border_intensity = m.border_intensity; + d->border_width = m.border_width; + d->shadow_strength = std::min(0.9f, m.shadow_strength * el); + d->shadow_radius = m.shadow_radius * el; + d->shadow_offset[0] = m.shadow_off_x * el; + d->shadow_offset[1] = m.shadow_off_y * el; + d->time = time_; + d->quad_pad = m.shadow_radius * el + + std::max(std::fabs(m.shadow_off_x), std::fabs(m.shadow_off_y)) * el + + m.border_width + 3.0f; + d->tilt[0] = tilt_x_; d->tilt[1] = tilt_y_; + d->sheen = m.sheen; + d->chroma = m.chroma; + d->cursor[0] = cursor_x_; d->cursor[1] = cursor_y_; + d->_pad_cur[0] = g_flow; + d->_pad_cur[1] = 0.0f; + d->blob1_center[0] = p.b1x; d->blob1_center[1] = p.b1y; + d->blob1_half[0] = p.b1w; d->blob1_half[1] = p.b1h; + d->blob2_center[0] = p.b2x; d->blob2_center[1] = p.b2y; + d->blob2_half[0] = p.b2w; d->blob2_half[1] = p.b2h; + d->blob_k = p.blob_k; + d->_pad_blob[0] = d->_pad_blob[1] = d->_pad_blob[2] = 0.0f; + d->edge0[0] = edge_cfg_.fresnel_exp; d->edge0[1] = edge_cfg_.bevel_scale; + d->edge0[2] = edge_cfg_.lip; d->edge0[3] = edge_cfg_.specular_exp; + d->edge1[0] = edge_cfg_.specular_amt; d->edge1[1] = edge_cfg_.front_amt; + d->edge1[2] = edge_cfg_.back_amt; d->edge1[3] = edge_cfg_.sat_pop; + d->edge2[0] = edge_cfg_.bevel_tilt; d->edge2[1] = edge_cfg_.light_height; + d->edge2[2] = edge_cfg_.edge_shadow; d->edge2[3] = edge_cfg_.cursor_size; + d->edge3[0] = edge_cfg_.cursor_glow; d->edge3[1] = edge_cfg_.sheen_amt; + d->edge3[2] = edge_cfg_.grain_amt; d->edge3[3] = edge_cfg_.ambient_rim; + d->edge4[0] = edge_cfg_.front_spread; d->edge4[1] = edge_cfg_.back_spread; + d->edge4[2] = edge_cfg_.panel_br_spread; d->edge4[3] = edge_cfg_.panel_br_smooth; + d->edge5[0] = light2_x_; d->edge5[1] = light2_y_; + d->edge5[2] = light1_amt_; d->edge5[3] = light2_amt_; + d->edge6[0] = rimSin_; d->edge6[1] = rimNegCos_; + d->edge6[2] = edge_cfg_.tbl_fill; + d->edge6[3] = 0.0f; + d->edge7[0] = edge_cfg_.adapt_strength; + d->edge7[1] = edge_cfg_.adapt_pivot; d->edge7[2] = edge_cfg_.adapt_soft; + d->edge7[3] = edge_cfg_.smooth_refraction; + d->edge8[0] = edge_cfg_.squircle_power; d->edge8[1] = edge_cfg_.lens_amount; + d->edge8[2] = edge_cfg_.lens_power; d->edge8[3] = edge_cfg_.lens_a; + d->edge9[0] = edge_cfg_.lens_b; d->edge9[1] = edge_cfg_.lens_c; d->edge9[2] = edge_cfg_.lens_d; + d->edge9[3] = edge_cfg_.glow_weight; + d->edge10[0] = edge_cfg_.glow_phase; d->edge10[1] = edge_cfg_.glow_edge0; + d->edge10[2] = edge_cfg_.glow_edge1; d->edge10[3] = edge_cfg_.glow_bias; + d->edge11[0] = edge_cfg_.glow_anim; d->edge11[1] = d->edge11[2] = d->edge11[3] = 0.0f; + ctx_->Unmap(cb_, 0); + ctx_->Draw(6, 0); + }; + for (const Primitive& p : queue_) draw_one(p); + for (const Primitive& p : overlay_) draw_one(p); + ID3D11ShaderResourceView* nullsrv[2] = { nullptr, nullptr }; + ctx_->PSSetShaderResources(0, 2, nullsrv); + } -struct CardState { Material mat; size_t queue_index; float radius; }; -static std::vector g_card_stack; + struct CardState { Material mat; size_t queue_index; float radius; }; + static std::vector g_card_stack; -static inline float Dt() { return ImGui::GetIO().DeltaTime; } + static inline float Dt() { return ImGui::GetIO().DeltaTime; } -bool BeginCard(const char* id, Material m, ImVec2 size) { - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(US(22 * g_density), US(20 * g_density))); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(US(12 * g_density), US(11 * g_density))); - ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32(0,0,0,0)); - ImGuiWindowFlags fl = - ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | - ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize; - if (size.x != 0 && size.y != 0) { - ImGui::SetNextWindowSize(size, ImGuiCond_Always); - } else { - fl |= ImGuiWindowFlags_AlwaysAutoResize; - if (size.x != 0) - ImGui::SetNextWindowSizeConstraints(ImVec2(size.x, 0), ImVec2(size.x, 100000.0f)); + bool BeginCard(const char* id, Material m, ImVec2 size) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(US(22 * g_density), US(20 * g_density))); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(US(12 * g_density), US(11 * g_density))); + ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32(0, 0, 0, 0)); + ImGuiWindowFlags fl = + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize; + if (size.x != 0 && size.y != 0) { + ImGui::SetNextWindowSize(size, ImGuiCond_Always); + } + else { + fl |= ImGuiWindowFlags_AlwaysAutoResize; + if (size.x != 0) + ImGui::SetNextWindowSizeConstraints(ImVec2(size.x, 0), ImVec2(size.x, 100000.0f)); + } + bool open = ImGui::Begin(id, nullptr, fl); + size_t idx = 0; + if (g) idx = g->Submit(Primitive{}); + g_card_stack.push_back({ m, idx, US(26.0f) }); + return open; } - bool open = ImGui::Begin(id, nullptr, fl); - size_t idx = 0; - if (g) idx = g->Submit(Primitive{}); - g_card_stack.push_back({ m, idx, US(26.0f) }); - return open; -} -void EndCard() { - if (g_card_stack.empty()) { ImGui::End(); ImGui::PopStyleColor(); ImGui::PopStyleVar(2); return; } - CardState s = g_card_stack.back(); g_card_stack.pop_back(); - ImVec2 wp = ImGui::GetWindowPos(); - ImVec2 ws = ImGui::GetWindowSize(); - if (g) { - Primitive& p = g->At(s.queue_index); - p.cx = wp.x + ws.x * 0.5f; p.cy = wp.y + ws.y * 0.5f; - p.hw = ws.x * 0.5f; p.hh = ws.y * 0.5f; - p.corner_radius = s.radius; p.fade = 1.0f; p.material = s.mat; + void EndCard() { + if (g_card_stack.empty()) { ImGui::End(); ImGui::PopStyleColor(); ImGui::PopStyleVar(2); return; } + CardState s = g_card_stack.back(); g_card_stack.pop_back(); + ImVec2 wp = ImGui::GetWindowPos(); + ImVec2 ws = ImGui::GetWindowSize(); + if (g) { + Primitive& p = g->At(s.queue_index); + p.cx = wp.x + ws.x * 0.5f; p.cy = wp.y + ws.y * 0.5f; + p.hw = ws.x * 0.5f; p.hh = ws.y * 0.5f; + p.corner_radius = s.radius; p.fade = 1.0f; p.material = s.mat; + } + ImGui::End(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); } - ImGui::End(); - ImGui::PopStyleColor(); - ImGui::PopStyleVar(2); -} #include "widgets/audio.inc" #include "widgets/widgets_core.inc" diff --git a/examples/example_win32_directx11/src/glass/surfaces.cpp b/examples/example_win32_directx11/src/glass/surfaces.cpp index ec3f77c..eebac5a 100644 --- a/examples/example_win32_directx11/src/glass/surfaces.cpp +++ b/examples/example_win32_directx11/src/glass/surfaces.cpp @@ -5,409 +5,420 @@ #include #include #include - +#undef max +#undef min namespace Glass { -static inline float Clampf(float x, float a, float b){ return xb?b:x); } -static inline float Dt(){ return ImGui::GetIO().DeltaTime; } + static inline float Clampf(float x, float a, float b) { return x < a ? a : (x > b ? b : x); } + static inline float Dt() { return ImGui::GetIO().DeltaTime; } #define kInk (InkColor()) #define kInkSoft (InkSoftColor()) -static ImU32 Accent(){ const MaterialParams& p = Params(Material::Accent); - return IM_COL32((int)(p.tint_rgb[0]*255), (int)(p.tint_rgb[1]*255), (int)(p.tint_rgb[2]*255), 255); } -static inline ImU32 SA(ImU32 c, float a){ a=Clampf(a,0,1); ImU32 al=(ImU32)(((c>>24)&0xFF)*a); return (c&0x00FFFFFFu)|(al<<24); } + static ImU32 Accent() { + const MaterialParams& p = Params(Material::Accent); + return IM_COL32((int)(p.tint_rgb[0] * 255), (int)(p.tint_rgb[1] * 255), (int)(p.tint_rgb[2] * 255), 255); + } + static inline ImU32 SA(ImU32 c, float a) { a = Clampf(a, 0, 1); ImU32 al = (ImU32)(((c >> 24) & 0xFF) * a); return (c & 0x00FFFFFFu) | (al << 24); } -static void TextC(ImDrawList* dl, ImFont* f, float sz, ImVec2 center, ImU32 col, const char* s){ - sz *= Glass::WidgetScale(); - ImVec2 ts = f->CalcTextSizeA(sz, 99999.0f, 0.0f, s); - dl->AddText(f, sz, ImVec2(center.x - ts.x*0.5f, center.y - ts.y*0.5f), col, s); -} + static void TextC(ImDrawList* dl, ImFont* f, float sz, ImVec2 center, ImU32 col, const char* s) { + sz *= Glass::WidgetScale(); + ImVec2 ts = f->CalcTextSizeA(sz, 99999.0f, 0.0f, s); + dl->AddText(f, sz, ImVec2(center.x - ts.x * 0.5f, center.y - ts.y * 0.5f), col, s); + } -static void FmtClock(char* b, int n, int h24, int mn){ - if (Use24Hour()) snprintf(b, n, "%d:%02d", h24, mn); - else snprintf(b, n, "%d:%02d", (h24%12==0)?12:h24%12, mn); -} + static void FmtClock(char* b, int n, int h24, int mn) { + if (Use24Hour()) snprintf(b, n, "%d:%02d", h24, mn); + else snprintf(b, n, "%d:%02d", (h24 % 12 == 0) ? 12 : h24 % 12, mn); + } -static ImU32 Bilerp4(ImU32 ctl, ImU32 ctr, ImU32 cbr, ImU32 cbl, float u, float v){ - auto C=[&](ImU32 c,int s)->float{ return (float)((c>>s)&0xFFu); }; - float iu=1.0f-u, iv=1.0f-v; - float r =(C(ctl,0)*iu + C(ctr,0)*u)*iv + (C(cbl,0)*iu + C(cbr,0)*u)*v; - float gg=(C(ctl,8)*iu + C(ctr,8)*u)*iv + (C(cbl,8)*iu + C(cbr,8)*u)*v; - float bb=(C(ctl,16)*iu+ C(ctr,16)*u)*iv+ (C(cbl,16)*iu+ C(cbr,16)*u)*v; - float aa=(C(ctl,24)*iu+ C(ctr,24)*u)*iv+ (C(cbl,24)*iu+ C(cbr,24)*u)*v; - return IM_COL32((int)(r+0.5f),(int)(gg+0.5f),(int)(bb+0.5f),(int)(aa+0.5f)); -} + static ImU32 Bilerp4(ImU32 ctl, ImU32 ctr, ImU32 cbr, ImU32 cbl, float u, float v) { + auto C = [&](ImU32 c, int s)->float { return (float)((c >> s) & 0xFFu); }; + float iu = 1.0f - u, iv = 1.0f - v; + float r = (C(ctl, 0) * iu + C(ctr, 0) * u) * iv + (C(cbl, 0) * iu + C(cbr, 0) * u) * v; + float gg = (C(ctl, 8) * iu + C(ctr, 8) * u) * iv + (C(cbl, 8) * iu + C(cbr, 8) * u) * v; + float bb = (C(ctl, 16) * iu + C(ctr, 16) * u) * iv + (C(cbl, 16) * iu + C(cbr, 16) * u) * v; + float aa = (C(ctl, 24) * iu + C(ctr, 24) * u) * iv + (C(cbl, 24) * iu + C(cbr, 24) * u) * v; + return IM_COL32((int)(r + 0.5f), (int)(gg + 0.5f), (int)(bb + 0.5f), (int)(aa + 0.5f)); + } -static void RoundedGrad(ImDrawList* dl, ImVec2 a, ImVec2 b, ImU32 ctl, ImU32 ctr, ImU32 cbr, ImU32 cbl, float rnd, ImDrawFlags flags=ImDrawFlags_RoundCornersAll){ - if (b.x-a.x < 1.0f || b.y-a.y < 1.0f) return; - dl->PathRect(a, b, rnd, flags); - int n = dl->_Path.Size; - if (n < 3){ dl->_Path.Size = 0; dl->AddRectFilledMultiColor(a, b, ctl, ctr, cbr, cbl); return; } - float w = b.x-a.x, h = b.y-a.y; - ImVec2 ctrp((a.x+b.x)*0.5f,(a.y+b.y)*0.5f); - ImVec2 uv = ImGui::GetIO().Fonts->TexUvWhitePixel; - bool aa = (dl->Flags & ImDrawListFlags_AntiAliasedFill) != 0; - if (!aa){ - dl->PrimReserve(n*3, n+1); - unsigned int base = dl->_VtxCurrentIdx; - dl->PrimWriteVtx(ctrp, uv, Bilerp4(ctl,ctr,cbr,cbl,0.5f,0.5f)); - for (int i=0;i_Path[i]; dl->PrimWriteVtx(p, uv, Bilerp4(ctl,ctr,cbr,cbl,(p.x-a.x)/w,(p.y-a.y)/h)); } - for (int i=0;iPrimWriteIdx((ImDrawIdx)base); dl->PrimWriteIdx((ImDrawIdx)(base+1+i)); dl->PrimWriteIdx((ImDrawIdx)(base+1+((i+1)%n))); } - dl->_Path.Size = 0; return; + static void RoundedGrad(ImDrawList* dl, ImVec2 a, ImVec2 b, ImU32 ctl, ImU32 ctr, ImU32 cbr, ImU32 cbl, float rnd, ImDrawFlags flags = ImDrawFlags_RoundCornersAll) { + if (b.x - a.x < 1.0f || b.y - a.y < 1.0f) return; + dl->PathRect(a, b, rnd, flags); + int n = dl->_Path.Size; + if (n < 3) { dl->_Path.Size = 0; dl->AddRectFilledMultiColor(a, b, ctl, ctr, cbr, cbl); return; } + float w = b.x - a.x, h = b.y - a.y; + ImVec2 ctrp((a.x + b.x) * 0.5f, (a.y + b.y) * 0.5f); + ImVec2 uv = ImGui::GetIO().Fonts->TexUvWhitePixel; + bool aa = (dl->Flags & ImDrawListFlags_AntiAliasedFill) != 0; + if (!aa) { + dl->PrimReserve(n * 3, n + 1); + unsigned int base = dl->_VtxCurrentIdx; + dl->PrimWriteVtx(ctrp, uv, Bilerp4(ctl, ctr, cbr, cbl, 0.5f, 0.5f)); + for (int i = 0; i < n; i++) { ImVec2 p = dl->_Path[i]; dl->PrimWriteVtx(p, uv, Bilerp4(ctl, ctr, cbr, cbl, (p.x - a.x) / w, (p.y - a.y) / h)); } + for (int i = 0; i < n; i++) { dl->PrimWriteIdx((ImDrawIdx)base); dl->PrimWriteIdx((ImDrawIdx)(base + 1 + i)); dl->PrimWriteIdx((ImDrawIdx)(base + 1 + ((i + 1) % n))); } + dl->_Path.Size = 0; return; + } + const float AA = 1.30f; + dl->PrimReserve(n * 9, 2 * n + 1); + unsigned int base = dl->_VtxCurrentIdx, innerB = base + 1, outerB = base + 1 + (unsigned)n; + dl->PrimWriteVtx(ctrp, uv, Bilerp4(ctl, ctr, cbr, cbl, 0.5f, 0.5f)); + for (int i = 0; i < n; i++) { ImVec2 p = dl->_Path[i]; dl->PrimWriteVtx(p, uv, Bilerp4(ctl, ctr, cbr, cbl, (p.x - a.x) / w, (p.y - a.y) / h)); } + for (int i = 0; i < n; i++) { + ImVec2 p = dl->_Path[i]; float dx = p.x - ctrp.x, dy = p.y - ctrp.y; float l = sqrtf(dx * dx + dy * dy); if (l < 1e-4f)l = 1e-4f; + dl->PrimWriteVtx(ImVec2(p.x + dx / l * AA, p.y + dy / l * AA), uv, Bilerp4(ctl, ctr, cbr, cbl, (p.x - a.x) / w, (p.y - a.y) / h) & 0x00FFFFFFu); + } + for (int i = 0; i < n; i++) { int j = (i + 1) % n; dl->PrimWriteIdx((ImDrawIdx)base); dl->PrimWriteIdx((ImDrawIdx)(innerB + i)); dl->PrimWriteIdx((ImDrawIdx)(innerB + j)); } + for (int i = 0; i < n; i++) { + int j = (i + 1) % n; + dl->PrimWriteIdx((ImDrawIdx)(innerB + i)); dl->PrimWriteIdx((ImDrawIdx)(innerB + j)); dl->PrimWriteIdx((ImDrawIdx)(outerB + j)); + dl->PrimWriteIdx((ImDrawIdx)(innerB + i)); dl->PrimWriteIdx((ImDrawIdx)(outerB + j)); dl->PrimWriteIdx((ImDrawIdx)(outerB + i)); + } + dl->_Path.Size = 0; } - const float AA = 1.30f; - dl->PrimReserve(n*9, 2*n+1); - unsigned int base = dl->_VtxCurrentIdx, innerB = base+1, outerB = base+1+(unsigned)n; - dl->PrimWriteVtx(ctrp, uv, Bilerp4(ctl,ctr,cbr,cbl,0.5f,0.5f)); - for (int i=0;i_Path[i]; dl->PrimWriteVtx(p, uv, Bilerp4(ctl,ctr,cbr,cbl,(p.x-a.x)/w,(p.y-a.y)/h)); } - for (int i=0;i_Path[i]; float dx=p.x-ctrp.x, dy=p.y-ctrp.y; float l=sqrtf(dx*dx+dy*dy); if(l<1e-4f)l=1e-4f; - dl->PrimWriteVtx(ImVec2(p.x+dx/l*AA, p.y+dy/l*AA), uv, Bilerp4(ctl,ctr,cbr,cbl,(p.x-a.x)/w,(p.y-a.y)/h) & 0x00FFFFFFu); } - for (int i=0;iPrimWriteIdx((ImDrawIdx)base); dl->PrimWriteIdx((ImDrawIdx)(innerB+i)); dl->PrimWriteIdx((ImDrawIdx)(innerB+j)); } - for (int i=0;iPrimWriteIdx((ImDrawIdx)(innerB+i)); dl->PrimWriteIdx((ImDrawIdx)(innerB+j)); dl->PrimWriteIdx((ImDrawIdx)(outerB+j)); - dl->PrimWriteIdx((ImDrawIdx)(innerB+i)); dl->PrimWriteIdx((ImDrawIdx)(outerB+j)); dl->PrimWriteIdx((ImDrawIdx)(outerB+i)); } - dl->_Path.Size = 0; -} -static void ImgOrGrad(ImDrawList* dl, ImVec2 a, ImVec2 b, int idx, ImU32 c1, ImU32 c2, float rnd){ - void* t = PhotoTex(idx); - if (t) dl->AddImageRounded((ImTextureID)(intptr_t)t, a, b, ImVec2(0,0), ImVec2(1,1), IM_COL32(255,255,255,255), rnd); - else RoundedGrad(dl, a, b, c1, c2, c2, c1, rnd); -} + static void ImgOrGrad(ImDrawList* dl, ImVec2 a, ImVec2 b, int idx, ImU32 c1, ImU32 c2, float rnd) { + void* t = PhotoTex(idx); + if (t) dl->AddImageRounded((ImTextureID)(intptr_t)t, a, b, ImVec2(0, 0), ImVec2(1, 1), IM_COL32(255, 255, 255, 255), rnd); + else RoundedGrad(dl, a, b, c1, c2, c2, c1, rnd); + } -static inline char LowerC(char c){ return (c>='A'&&c<='Z') ? (char)(c+32) : c; } -static bool ContainsCI(const char* hay, const char* needle){ - if (!needle || !*needle) return true; if (!hay) return false; - for (const char* h=hay; *h; ++h){ const char* a=h; const char* b=needle; - while (*a && *b && LowerC(*a)==LowerC(*b)) { ++a; ++b; } - if (!*b) return true; } - return false; -} + static inline char LowerC(char c) { return (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c; } + static bool ContainsCI(const char* hay, const char* needle) { + if (!needle || !*needle) return true; if (!hay) return false; + for (const char* h = hay; *h; ++h) { + const char* a = h; const char* b = needle; + while (*a && *b && LowerC(*a) == LowerC(*b)) { ++a; ++b; } + if (!*b) return true; + } + return false; + } -static bool CalcKey(const char* id, ImVec2 c, float bw, float bh, const char* label, - Material m, ImU32 labelCol, float fontSz){ - ImGui::PushID(id); - ImGui::SetCursorScreenPos(ImVec2(c.x - bw*0.5f, c.y - bh*0.5f)); - ImGui::InvisibleButton("k", ImVec2(bw, bh)); - bool hov = ImGui::IsItemHovered(); - bool clicked = ImGui::IsItemDeactivated() && hov; - if (ImGui::IsItemActivated()) PlaySfx(Sfx::CalcKey); - Spring& s = g->springs().Get((uint32_t)ImGui::GetID("k"), 1, SpringStyle::Bouncy, 1.0f); - s.target = ImGui::IsItemActive() ? 0.90f : (hov ? 1.05f : 1.0f); - s.Tick(Dt()); - float sc = Clampf(s.x, 0.8f, 1.2f); - Primitive b; b.cx=c.x; b.cy=c.y; b.hw=bw*0.5f*sc; b.hh=bh*0.5f*sc; - b.corner_radius = bh*0.5f*sc; b.fade=1.0f; b.material=m; b.elevate = hov?1.12f:1.0f; - g->Submit(b); - TextC(ImGui::GetWindowDrawList(), ImGui::GetFont(), fontSz, c, labelCol, label); - ImGui::PopID(); - return clicked; -} + static bool CalcKey(const char* id, ImVec2 c, float bw, float bh, const char* label, + Material m, ImU32 labelCol, float fontSz) { + ImGui::PushID(id); + ImGui::SetCursorScreenPos(ImVec2(c.x - bw * 0.5f, c.y - bh * 0.5f)); + ImGui::InvisibleButton("k", ImVec2(bw, bh)); + bool hov = ImGui::IsItemHovered(); + bool clicked = ImGui::IsItemDeactivated() && hov; + if (ImGui::IsItemActivated()) PlaySfx(Sfx::CalcKey); + Spring& s = g->springs().Get((uint32_t)ImGui::GetID("k"), 1, SpringStyle::Bouncy, 1.0f); + s.target = ImGui::IsItemActive() ? 0.90f : (hov ? 1.05f : 1.0f); + s.Tick(Dt()); + float sc = Clampf(s.x, 0.8f, 1.2f); + Primitive b; b.cx = c.x; b.cy = c.y; b.hw = bw * 0.5f * sc; b.hh = bh * 0.5f * sc; + b.corner_radius = bh * 0.5f * sc; b.fade = 1.0f; b.material = m; b.elevate = hov ? 1.12f : 1.0f; + g->Submit(b); + TextC(ImGui::GetWindowDrawList(), ImGui::GetFont(), fontSz, c, labelCol, label); + ImGui::PopID(); + return clicked; + } -static float TileOn(const char* slotid, bool on){ - Spring& s=g->springs().Get((uint32_t)ImGui::GetID(slotid),9,SpringStyle::Critical,on?1.0f:0.0f); - s.target=on?1.0f:0.0f; s.Tick(Dt()); return Clampf(s.x,0.0f,1.0f); -} + static float TileOn(const char* slotid, bool on) { + Spring& s = g->springs().Get((uint32_t)ImGui::GetID(slotid), 9, SpringStyle::Critical, on ? 1.0f : 0.0f); + s.target = on ? 1.0f : 0.0f; s.Tick(Dt()); return Clampf(s.x, 0.0f, 1.0f); + } -static bool SurfaceHit(const char* id, ImVec2 tl, ImVec2 sz, bool* hovOut=nullptr, Sfx clickSfx=Sfx::Tap){ - ImVec2 keep = ImGui::GetCursorScreenPos(); - ImGui::PushID(id); - ImGui::SetCursorScreenPos(tl); - ImGui::InvisibleButton("##hit", ImVec2(sz.x<1.0f?1.0f:sz.x, sz.y<1.0f?1.0f:sz.y), ImGuiButtonFlags_AllowOverlap); - bool hov = ImGui::IsItemHovered(); - bool clk = ImGui::IsItemDeactivated() && hov; - if (ImGui::IsItemActivated()) PlaySfx(clickSfx); - ImGui::PopID(); - ImGui::SetCursorScreenPos(keep); - if (hovOut) *hovOut = hov; - return clk; -} + static bool SurfaceHit(const char* id, ImVec2 tl, ImVec2 sz, bool* hovOut = nullptr, Sfx clickSfx = Sfx::Tap) { + ImVec2 keep = ImGui::GetCursorScreenPos(); + ImGui::PushID(id); + ImGui::SetCursorScreenPos(tl); + ImGui::InvisibleButton("##hit", ImVec2(sz.x < 1.0f ? 1.0f : sz.x, sz.y < 1.0f ? 1.0f : sz.y), ImGuiButtonFlags_AllowOverlap); + bool hov = ImGui::IsItemHovered(); + bool clk = ImGui::IsItemDeactivated() && hov; + if (ImGui::IsItemActivated()) PlaySfx(clickSfx); + ImGui::PopID(); + ImGui::SetCursorScreenPos(keep); + if (hovOut) *hovOut = hov; + return clk; + } -static void RowWash(ImDrawList* dl, ImVec2 tl, ImVec2 br, float rnd, bool sel, bool hov){ - if (sel) dl->AddRectFilled(tl, br, SA(Accent(), 0.20f), rnd); - else if (hov) dl->AddRectFilled(tl, br, SA(kInkSoft, 0.10f), rnd); -} + static void RowWash(ImDrawList* dl, ImVec2 tl, ImVec2 br, float rnd, bool sel, bool hov) { + if (sel) dl->AddRectFilled(tl, br, SA(Accent(), 0.20f), rnd); + else if (hov) dl->AddRectFilled(tl, br, SA(kInkSoft, 0.10f), rnd); + } #include "surfaces/part1.inc" #include "surfaces/part2.inc" #include "surfaces/part3.inc" #include "surfaces/part4.inc" #include "surfaces/part5.inc" #include "surfaces/part6.inc" -struct SurfaceDef { const char* name; const char* sub; Icon icon; ImU32 tint; void(*draw)(float); }; -static SurfaceDef g_surfaces[] = { - { "Weather", "Today & 10-day", Icon::CloudSun, IM_COL32(64,156,255,255), Draw_Weather }, - { "Music", "Now Playing", Icon::Music, IM_COL32(255,55,95,255), Draw_Music }, - { "Clock", "World & local", Icon::Clock, IM_COL32(255,159,10,255), Draw_Clock }, - { "Settings", "System settings", Icon::Gear, IM_COL32(142,142,147,255),Draw_Settings }, - { "Photos", "Library & memories", Icon::Images, IM_COL32(255,90,140,255), Draw_Photos }, - { "Notifications","Center & widgets", Icon::Bell, IM_COL32(255,69,58,255), Draw_NotifCenter }, - { "Stocks", "Markets & charts", Icon::Bolt, IM_COL32(48,209,88,255), Draw_Stocks }, - { "Files", "File browser", Icon::Folder, IM_COL32(64,156,255,255), Draw_Files }, - { "Maps", "Find your way", Icon::Map, IM_COL32(76,200,120,255), Draw_Maps }, - { "Messages", "Conversations", Icon::Comment, IM_COL32(48,209,88,255), Draw_Messages }, - { "Mail", "Inbox", Icon::Envelope, IM_COL32(64,156,255,255), Draw_Mail }, - { "Home Screen","Apps & dock", Icon::House, IM_COL32(94,92,230,255), Draw_Home }, - { "Reminders", "To-do & lists", Icon::CheckCircle,IM_COL32(255,149,0,255), Draw_Reminders }, - { "Health", "Activity rings", Icon::Heart, IM_COL32(255,55,95,255), Draw_Health }, - { "Cards", "Cards & passes", Icon::CreditCard, IM_COL32(60,60,64,255), Draw_Wallet }, - { "Lock Screen","Clock & glances", Icon::Lock, IM_COL32(120,120,128,255),Draw_Lock }, - { "Calendar", "Month & agenda", Icon::CalendarDays,IM_COL32(255,69,58,255), Draw_Calendar }, - { "Camera", "Viewfinder", Icon::Camera, IM_COL32(120,120,128,255),Draw_Camera }, - { "Spotlight", "Search anything", Icon::Search, IM_COL32(94,92,230,255), Draw_Spotlight }, - { "App Store", "Discover apps", Icon::Bag, IM_COL32(64,156,255,255), Draw_AppStore }, - { "Notes", "Jot it down", Icon::PenEdit, IM_COL32(255,214,90,255), Draw_Notes }, - { "Podcasts", "Listen", Icon::Microphone, IM_COL32(146,82,232,255), Draw_Podcasts }, - { "Voice Memos","Record", Icon::Microphone, IM_COL32(255,69,58,255), Draw_VoiceMemos }, - { "Keyboard", "Type it out", Icon::Keyboard, IM_COL32(120,120,128,255),Draw_Keyboard }, - { "Translate", "Any language", Icon::Globe, IM_COL32(64,156,255,255), Draw_Translate }, - { "Control Ctr","Toggles & sliders",Icon::Sliders, IM_COL32(94,92,230,255), Draw_CControl }, - { "Fitness", "Move & workouts", Icon::Dumbbell, IM_COL32(126,255,40,255), Draw_Fitness }, - { "News", "Top stories", Icon::Newspaper, IM_COL32(255,69,58,255), Draw_News }, - { "Books", "Reading list", Icon::Book, IM_COL32(255,149,0,255), Draw_Books }, - { "Video Calls","Group call", Icon::Video, IM_COL32(48,209,88,255), Draw_FaceTime }, - { "Device Finder","People & devices",Icon::LocationArrow,IM_COL32(48,209,88,255), Draw_FindMy }, - { "Shortcuts", "Automations", Icon::Bolt, IM_COL32(146,82,232,255), Draw_Shortcuts }, - { "Freeform", "Whiteboard", Icon::PenEdit, IM_COL32(64,156,255,255), Draw_Freeform }, - { "Game Center","Achievements", Icon::Trophy, IM_COL32(255,159,10,255), Draw_GameCenter }, - { "Components", "Glass toolkit", Icon::Cube, IM_COL32(94,92,230,255), Draw_Components }, - { "Compass", "Find north", Icon::Compass, IM_COL32(255,69,58,255), Draw_Compass }, - { "Mindfulness","Breathe", Icon::Leaf, IM_COL32(48,209,88,255), Draw_Breathe }, - { "Timer", "Countdown", Icon::Stopwatch, IM_COL32(255,159,10,255), Draw_Timer }, - { "TV", "Movies & shows", Icon::Tv, IM_COL32(40,44,70,255), Draw_TV }, - { "Sports", "Live scores", Icon::Trophy, IM_COL32(48,209,88,255), Draw_Sports }, - { "Widgets", "Today gallery", Icon::Grid, IM_COL32(64,156,255,255), Draw_Widgets }, - { "Alarms", "Wake & sleep", Icon::Bell, IM_COL32(255,69,58,255), Draw_Alarms }, - { "Browser", "Browse the web", Icon::Compass, IM_COL32(64,156,255,255), Draw_Safari }, - { "Phone", "Keypad", Icon::Phone, IM_COL32(48,209,88,255), Draw_Phone }, - { "Contacts", "People", Icon::Person, IM_COL32(120,120,128,255),Draw_Contacts }, - { "Home", "Smart home", Icon::House, IM_COL32(255,159,10,255), Draw_HomeKit }, - { "Battery", "Usage graph", Icon::BatteryFull,IM_COL32(48,209,88,255), Draw_Battery }, - { "Studio", "Make music", Icon::Guitar, IM_COL32(255,159,10,255), Draw_GarageBand }, - { "Watch", "Faces", Icon::Clock, IM_COL32(255,69,58,255), Draw_Watch }, - { "Headphones", "Battery", Icon::Headphones, IM_COL32(120,120,128,255),Draw_AirPods }, - { "Journal", "Reflect", Icon::Book, IM_COL32(255,159,10,255), Draw_Journal }, - { "Numbers", "Spreadsheet", Icon::Grid, IM_COL32(48,209,88,255), Draw_Numbers }, - { "Measure", "AR ruler", Icon::Crosshairs, IM_COL32(255,214,90,255), Draw_Measure }, - { "Magnifier", "Zoom in", Icon::Search, IM_COL32(120,120,128,255),Draw_Magnifier }, - { "Shazam", "Name that tune", Icon::Music, IM_COL32(64,156,255,255), Draw_Shazam }, - { "Sleep", "Schedule", Icon::Bed, IM_COL32(94,92,230,255), Draw_Sleep }, - { "Docs", "Documents", Icon::FileLines, IM_COL32(255,159,10,255), Draw_Pages }, - { "Slides", "Presentations", Icon::Display, IM_COL32(64,156,255,255), Draw_Keynote }, - { "Video Editor","Edit video", Icon::Film, IM_COL32(146,82,232,255), Draw_iMovie }, - { "Tips", "Learn more", Icon::Lightbulb, IM_COL32(255,214,90,255), Draw_Tips }, - { "Wallpaper", "Personalize", Icon::Image, IM_COL32(146,82,232,255), Draw_Wallpaper }, - { "Focus", "Modes", Icon::Moon, IM_COL32(146,82,232,255), Draw_Focus }, - { "Storage", "Manage space", Icon::Database, IM_COL32(64,156,255,255), Draw_Storage }, - { "About", "Device info", Icon::InfoCircle, IM_COL32(120,120,128,255),Draw_About }, - { "Access.", "Accessibility", Icon::Person, IM_COL32(64,156,255,255), Draw_Accessibility}, - { "Transit", "Get around", Icon::Map, IM_COL32(64,156,255,255), Draw_Transit }, - { "Assistant", "Ask anything", Icon::Microphone, IM_COL32(146,82,232,255), Draw_Siri }, - { "Payments", "Tap to pay", Icon::CreditCard, IM_COL32(40,40,44,255), Draw_GlassPay }, - { "Emoji", "Express", Icon::Heart, IM_COL32(255,214,90,255), Draw_Emoji }, - { "Remote", "Streaming", Icon::Tv, IM_COL32(120,120,128,255),Draw_Remote }, - { "Update", "Software Update", Icon::Download, IM_COL32(64,156,255,255), Draw_SoftwareUpdate}, - { "Dictionary", "Look it up", Icon::Book, IM_COL32(120,120,128,255),Draw_Dictionary }, - { "Stopwatch", "Lap timer", Icon::Stopwatch, IM_COL32(255,159,10,255), Draw_Stopwatch }, - { "Nearby", "Share nearby", Icon::ShareNodes, IM_COL32(64,156,255,255), Draw_AirDrop }, - { "Markup", "Draw & annotate", Icon::PenEdit, IM_COL32(255,69,58,255), Draw_Markup }, - { "Scanner", "Scan documents", Icon::Camera, IM_COL32(120,120,128,255),Draw_Scanner }, - { "Level", "Is it straight?", Icon::Crosshairs, IM_COL32(48,209,88,255), Draw_Level }, - { "Flashlight", "Light it up", Icon::Bolt, IM_COL32(255,214,90,255), Draw_Flashlight }, - { "Library", "Music albums", Icon::Music, IM_COL32(255,55,95,255), Draw_MusicLib }, - { "Lists", "Reminders lists", Icon::List, IM_COL32(255,159,10,255), Draw_ReminderLists}, - { "Steps", "Activity detail", Icon::Running, IM_COL32(255,159,10,255), Draw_StepsDetail }, - { "Shows", "Podcast library", Icon::Microphone, IM_COL32(146,82,232,255), Draw_PodcastLib }, - { "Sounds", "Ringtones", Icon::Speaker, IM_COL32(255,55,95,255), Draw_Sounds }, - { "Feed", "News for you", Icon::Newspaper, IM_COL32(255,69,58,255), Draw_NewsFeed }, - { "Watchlist", "Track stocks", Icon::Bolt, IM_COL32(48,209,88,255), Draw_Watchlist }, - { "Book Store", "Discover books", Icon::Book, IM_COL32(255,69,58,255), Draw_BookStore }, - { "Display", "Brightness", Icon::Display, IM_COL32(64,156,255,255), Draw_Display }, - { "Game", "Tic-Tac-Toe", Icon::Gamepad, IM_COL32(94,92,230,255), Draw_TicTacToe }, - { "App Page", "App Store detail",Icon::Bag, IM_COL32(64,156,255,255), Draw_AppDetail }, - { "Albums", "Photo albums", Icon::Images, IM_COL32(255,90,140,255), Draw_PhotoAlbums }, - { "Portrait", "Camera mode", Icon::Camera, IM_COL32(255,214,90,255), Draw_CameraPortrait}, - { "Compose", "New mail", Icon::PenEdit, IM_COL32(64,156,255,255), Draw_MailCompose }, - { "Chats", "Conversations", Icon::Comment, IM_COL32(48,209,88,255), Draw_MessagesList}, - { "Week", "Calendar week", Icon::CalendarDays,IM_COL32(255,69,58,255), Draw_CalWeek }, - { "Heart", "Heart rate ECG", Icon::Heart, IM_COL32(255,55,95,255), Draw_HeartRate }, - { "Checklist", "Note with checks",Icon::CheckCircle,IM_COL32(255,214,90,255), Draw_Checklist }, - { "Boarding", "Boarding pass", Icon::Airplane, IM_COL32(255,90,70,255), Draw_BoardingPass}, - { "Radio", "Stations", Icon::Wifi, IM_COL32(255,55,95,255), Draw_Radio }, - { "Recents", "Call log", Icon::Phone, IM_COL32(48,209,88,255), Draw_Recents }, - { "Live Text", "Translate camera",Icon::Camera, IM_COL32(64,156,255,255), Draw_TranslateCam}, - { "Counter", "Tap to count", Icon::Plus, IM_COL32(48,209,88,255), Draw_Counter }, - { "Color Mixer","RGB mixer", Icon::Palette, IM_COL32(146,82,232,255), Draw_ColorMixer }, - { "Tip Calc", "Split the bill", Icon::CreditCard, IM_COL32(48,209,88,255), Draw_TipCalc }, - { "Dice", "Roll \xF0\x9F\x8E\xB2", Icon::Dice, IM_COL32(255,69,58,255), Draw_Dice }, - { "Converter", "Units", Icon::Refresh, IM_COL32(64,156,255,255), Draw_UnitConv }, - { "Piano", "Play notes", Icon::Music, IM_COL32(40,40,44,255), Draw_Piano }, - { "Calculator", "Crunch numbers", Icon::Calculator, IM_COL32(255,149,0,255), Draw_Calculator }, + struct SurfaceDef { const char* name; const char* sub; Icon icon; ImU32 tint; void(*draw)(float); }; + static SurfaceDef g_surfaces[] = { + { "Weather", "Today & 10-day", Icon::CloudSun, IM_COL32(64,156,255,255), Draw_Weather }, + { "Music", "Now Playing", Icon::Music, IM_COL32(255,55,95,255), Draw_Music }, + { "Clock", "World & local", Icon::Clock, IM_COL32(255,159,10,255), Draw_Clock }, + { "Settings", "System settings", Icon::Gear, IM_COL32(142,142,147,255),Draw_Settings }, + { "Photos", "Library & memories", Icon::Images, IM_COL32(255,90,140,255), Draw_Photos }, + { "Notifications","Center & widgets", Icon::Bell, IM_COL32(255,69,58,255), Draw_NotifCenter }, + { "Stocks", "Markets & charts", Icon::Bolt, IM_COL32(48,209,88,255), Draw_Stocks }, + { "Files", "File browser", Icon::Folder, IM_COL32(64,156,255,255), Draw_Files }, + { "Maps", "Find your way", Icon::Map, IM_COL32(76,200,120,255), Draw_Maps }, + { "Messages", "Conversations", Icon::Comment, IM_COL32(48,209,88,255), Draw_Messages }, + { "Mail", "Inbox", Icon::Envelope, IM_COL32(64,156,255,255), Draw_Mail }, + { "Home Screen","Apps & dock", Icon::House, IM_COL32(94,92,230,255), Draw_Home }, + { "Reminders", "To-do & lists", Icon::CheckCircle,IM_COL32(255,149,0,255), Draw_Reminders }, + { "Health", "Activity rings", Icon::Heart, IM_COL32(255,55,95,255), Draw_Health }, + { "Cards", "Cards & passes", Icon::CreditCard, IM_COL32(60,60,64,255), Draw_Wallet }, + { "Lock Screen","Clock & glances", Icon::Lock, IM_COL32(120,120,128,255),Draw_Lock }, + { "Calendar", "Month & agenda", Icon::CalendarDays,IM_COL32(255,69,58,255), Draw_Calendar }, + { "Camera", "Viewfinder", Icon::Camera, IM_COL32(120,120,128,255),Draw_Camera }, + { "Spotlight", "Search anything", Icon::Search, IM_COL32(94,92,230,255), Draw_Spotlight }, + { "App Store", "Discover apps", Icon::Bag, IM_COL32(64,156,255,255), Draw_AppStore }, + { "Notes", "Jot it down", Icon::PenEdit, IM_COL32(255,214,90,255), Draw_Notes }, + { "Podcasts", "Listen", Icon::Microphone, IM_COL32(146,82,232,255), Draw_Podcasts }, + { "Voice Memos","Record", Icon::Microphone, IM_COL32(255,69,58,255), Draw_VoiceMemos }, + { "Keyboard", "Type it out", Icon::Keyboard, IM_COL32(120,120,128,255),Draw_Keyboard }, + { "Translate", "Any language", Icon::Globe, IM_COL32(64,156,255,255), Draw_Translate }, + { "Control Ctr","Toggles & sliders",Icon::Sliders, IM_COL32(94,92,230,255), Draw_CControl }, + { "Fitness", "Move & workouts", Icon::Dumbbell, IM_COL32(126,255,40,255), Draw_Fitness }, + { "News", "Top stories", Icon::Newspaper, IM_COL32(255,69,58,255), Draw_News }, + { "Books", "Reading list", Icon::Book, IM_COL32(255,149,0,255), Draw_Books }, + { "Video Calls","Group call", Icon::Video, IM_COL32(48,209,88,255), Draw_FaceTime }, + { "Device Finder","People & devices",Icon::LocationArrow,IM_COL32(48,209,88,255), Draw_FindMy }, + { "Shortcuts", "Automations", Icon::Bolt, IM_COL32(146,82,232,255), Draw_Shortcuts }, + { "Freeform", "Whiteboard", Icon::PenEdit, IM_COL32(64,156,255,255), Draw_Freeform }, + { "Game Center","Achievements", Icon::Trophy, IM_COL32(255,159,10,255), Draw_GameCenter }, + { "Components", "Glass toolkit", Icon::Cube, IM_COL32(94,92,230,255), Draw_Components }, + { "Compass", "Find north", Icon::Compass, IM_COL32(255,69,58,255), Draw_Compass }, + { "Mindfulness","Breathe", Icon::Leaf, IM_COL32(48,209,88,255), Draw_Breathe }, + { "Timer", "Countdown", Icon::Stopwatch, IM_COL32(255,159,10,255), Draw_Timer }, + { "TV", "Movies & shows", Icon::Tv, IM_COL32(40,44,70,255), Draw_TV }, + { "Sports", "Live scores", Icon::Trophy, IM_COL32(48,209,88,255), Draw_Sports }, + { "Widgets", "Today gallery", Icon::Grid, IM_COL32(64,156,255,255), Draw_Widgets }, + { "Alarms", "Wake & sleep", Icon::Bell, IM_COL32(255,69,58,255), Draw_Alarms }, + { "Browser", "Browse the web", Icon::Compass, IM_COL32(64,156,255,255), Draw_Safari }, + { "Phone", "Keypad", Icon::Phone, IM_COL32(48,209,88,255), Draw_Phone }, + { "Contacts", "People", Icon::Person, IM_COL32(120,120,128,255),Draw_Contacts }, + { "Home", "Smart home", Icon::House, IM_COL32(255,159,10,255), Draw_HomeKit }, + { "Battery", "Usage graph", Icon::BatteryFull,IM_COL32(48,209,88,255), Draw_Battery }, + { "Studio", "Make music", Icon::Guitar, IM_COL32(255,159,10,255), Draw_GarageBand }, + { "Watch", "Faces", Icon::Clock, IM_COL32(255,69,58,255), Draw_Watch }, + { "Headphones", "Battery", Icon::Headphones, IM_COL32(120,120,128,255),Draw_AirPods }, + { "Journal", "Reflect", Icon::Book, IM_COL32(255,159,10,255), Draw_Journal }, + { "Numbers", "Spreadsheet", Icon::Grid, IM_COL32(48,209,88,255), Draw_Numbers }, + { "Measure", "AR ruler", Icon::Crosshairs, IM_COL32(255,214,90,255), Draw_Measure }, + { "Magnifier", "Zoom in", Icon::Search, IM_COL32(120,120,128,255),Draw_Magnifier }, + { "Shazam", "Name that tune", Icon::Music, IM_COL32(64,156,255,255), Draw_Shazam }, + { "Sleep", "Schedule", Icon::Bed, IM_COL32(94,92,230,255), Draw_Sleep }, + { "Docs", "Documents", Icon::FileLines, IM_COL32(255,159,10,255), Draw_Pages }, + { "Slides", "Presentations", Icon::Display, IM_COL32(64,156,255,255), Draw_Keynote }, + { "Video Editor","Edit video", Icon::Film, IM_COL32(146,82,232,255), Draw_iMovie }, + { "Tips", "Learn more", Icon::Lightbulb, IM_COL32(255,214,90,255), Draw_Tips }, + { "Wallpaper", "Personalize", Icon::Image, IM_COL32(146,82,232,255), Draw_Wallpaper }, + { "Focus", "Modes", Icon::Moon, IM_COL32(146,82,232,255), Draw_Focus }, + { "Storage", "Manage space", Icon::Database, IM_COL32(64,156,255,255), Draw_Storage }, + { "About", "Device info", Icon::InfoCircle, IM_COL32(120,120,128,255),Draw_About }, + { "Access.", "Accessibility", Icon::Person, IM_COL32(64,156,255,255), Draw_Accessibility}, + { "Transit", "Get around", Icon::Map, IM_COL32(64,156,255,255), Draw_Transit }, + { "Assistant", "Ask anything", Icon::Microphone, IM_COL32(146,82,232,255), Draw_Siri }, + { "Payments", "Tap to pay", Icon::CreditCard, IM_COL32(40,40,44,255), Draw_GlassPay }, + { "Emoji", "Express", Icon::Heart, IM_COL32(255,214,90,255), Draw_Emoji }, + { "Remote", "Streaming", Icon::Tv, IM_COL32(120,120,128,255),Draw_Remote }, + { "Update", "Software Update", Icon::Download, IM_COL32(64,156,255,255), Draw_SoftwareUpdate}, + { "Dictionary", "Look it up", Icon::Book, IM_COL32(120,120,128,255),Draw_Dictionary }, + { "Stopwatch", "Lap timer", Icon::Stopwatch, IM_COL32(255,159,10,255), Draw_Stopwatch }, + { "Nearby", "Share nearby", Icon::ShareNodes, IM_COL32(64,156,255,255), Draw_AirDrop }, + { "Markup", "Draw & annotate", Icon::PenEdit, IM_COL32(255,69,58,255), Draw_Markup }, + { "Scanner", "Scan documents", Icon::Camera, IM_COL32(120,120,128,255),Draw_Scanner }, + { "Level", "Is it straight?", Icon::Crosshairs, IM_COL32(48,209,88,255), Draw_Level }, + { "Flashlight", "Light it up", Icon::Bolt, IM_COL32(255,214,90,255), Draw_Flashlight }, + { "Library", "Music albums", Icon::Music, IM_COL32(255,55,95,255), Draw_MusicLib }, + { "Lists", "Reminders lists", Icon::List, IM_COL32(255,159,10,255), Draw_ReminderLists}, + { "Steps", "Activity detail", Icon::Running, IM_COL32(255,159,10,255), Draw_StepsDetail }, + { "Shows", "Podcast library", Icon::Microphone, IM_COL32(146,82,232,255), Draw_PodcastLib }, + { "Sounds", "Ringtones", Icon::Speaker, IM_COL32(255,55,95,255), Draw_Sounds }, + { "Feed", "News for you", Icon::Newspaper, IM_COL32(255,69,58,255), Draw_NewsFeed }, + { "Watchlist", "Track stocks", Icon::Bolt, IM_COL32(48,209,88,255), Draw_Watchlist }, + { "Book Store", "Discover books", Icon::Book, IM_COL32(255,69,58,255), Draw_BookStore }, + { "Display", "Brightness", Icon::Display, IM_COL32(64,156,255,255), Draw_Display }, + { "Game", "Tic-Tac-Toe", Icon::Gamepad, IM_COL32(94,92,230,255), Draw_TicTacToe }, + { "App Page", "App Store detail",Icon::Bag, IM_COL32(64,156,255,255), Draw_AppDetail }, + { "Albums", "Photo albums", Icon::Images, IM_COL32(255,90,140,255), Draw_PhotoAlbums }, + { "Portrait", "Camera mode", Icon::Camera, IM_COL32(255,214,90,255), Draw_CameraPortrait}, + { "Compose", "New mail", Icon::PenEdit, IM_COL32(64,156,255,255), Draw_MailCompose }, + { "Chats", "Conversations", Icon::Comment, IM_COL32(48,209,88,255), Draw_MessagesList}, + { "Week", "Calendar week", Icon::CalendarDays,IM_COL32(255,69,58,255), Draw_CalWeek }, + { "Heart", "Heart rate ECG", Icon::Heart, IM_COL32(255,55,95,255), Draw_HeartRate }, + { "Checklist", "Note with checks",Icon::CheckCircle,IM_COL32(255,214,90,255), Draw_Checklist }, + { "Boarding", "Boarding pass", Icon::Airplane, IM_COL32(255,90,70,255), Draw_BoardingPass}, + { "Radio", "Stations", Icon::Wifi, IM_COL32(255,55,95,255), Draw_Radio }, + { "Recents", "Call log", Icon::Phone, IM_COL32(48,209,88,255), Draw_Recents }, + { "Live Text", "Translate camera",Icon::Camera, IM_COL32(64,156,255,255), Draw_TranslateCam}, + { "Counter", "Tap to count", Icon::Plus, IM_COL32(48,209,88,255), Draw_Counter }, + { "Color Mixer","RGB mixer", Icon::Palette, IM_COL32(146,82,232,255), Draw_ColorMixer }, + { "Tip Calc", "Split the bill", Icon::CreditCard, IM_COL32(48,209,88,255), Draw_TipCalc }, + { "Dice", "Roll \xF0\x9F\x8E\xB2", Icon::Dice, IM_COL32(255,69,58,255), Draw_Dice }, + { "Converter", "Units", Icon::Refresh, IM_COL32(64,156,255,255), Draw_UnitConv }, + { "Piano", "Play notes", Icon::Music, IM_COL32(40,40,44,255), Draw_Piano }, + { "Calculator", "Crunch numbers", Icon::Calculator, IM_COL32(255,149,0,255), Draw_Calculator }, - { "Media", "Music \xC2\xB7 Podcasts \xC2\xB7 TV", Icon::Music, IM_COL32(255,55,95,255), Draw_GroupMedia }, - { "Web", "Browser \xC2\xB7 Maps", Icon::Compass, IM_COL32(64,156,255,255), Draw_GroupWeb }, - { "Connect", "Messages \xC2\xB7 Mail \xC2\xB7 Calls", Icon::Comment, IM_COL32(48,209,88,255), Draw_GroupConnect }, - { "Workspace", "Files \xC2\xB7 Notes \xC2\xB7 Calendar",Icon::Folder, IM_COL32(255,159,10,255), Draw_GroupWork }, - { "Photos", "Library \xC2\xB7 Camera", Icon::Images, IM_COL32(255,90,140,255), Draw_GroupPhotos }, - { "Tools", "Calculator \xC2\xB7 Units", Icon::Calculator,IM_COL32(255,149,0,255), Draw_GroupTools }, - { "System", "Settings \xC2\xB7 Battery", Icon::Gear, IM_COL32(142,142,147,255),Draw_GroupSystem }, - { "Health", "Activity \xC2\xB7 Sleep", Icon::Heart, IM_COL32(255,55,95,255), Draw_GroupHealth }, - { "Cards", "Cards \xC2\xB7 Passes", Icon::CreditCard,IM_COL32(60,60,64,255), Draw_GroupWallet }, - { "Today", "Weather \xC2\xB7 Clock \xC2\xB7 News", Icon::CloudSun, IM_COL32(64,156,255,255), Draw_GroupToday }, - { "Create", "Music \xC2\xB7 Video \xC2\xB7 Docs", Icon::Guitar, IM_COL32(255,159,10,255), Draw_GroupCreate }, -}; + { "Media", "Music \xC2\xB7 Podcasts \xC2\xB7 TV", Icon::Music, IM_COL32(255,55,95,255), Draw_GroupMedia }, + { "Web", "Browser \xC2\xB7 Maps", Icon::Compass, IM_COL32(64,156,255,255), Draw_GroupWeb }, + { "Connect", "Messages \xC2\xB7 Mail \xC2\xB7 Calls", Icon::Comment, IM_COL32(48,209,88,255), Draw_GroupConnect }, + { "Workspace", "Files \xC2\xB7 Notes \xC2\xB7 Calendar",Icon::Folder, IM_COL32(255,159,10,255), Draw_GroupWork }, + { "Photos", "Library \xC2\xB7 Camera", Icon::Images, IM_COL32(255,90,140,255), Draw_GroupPhotos }, + { "Tools", "Calculator \xC2\xB7 Units", Icon::Calculator,IM_COL32(255,149,0,255), Draw_GroupTools }, + { "System", "Settings \xC2\xB7 Battery", Icon::Gear, IM_COL32(142,142,147,255),Draw_GroupSystem }, + { "Health", "Activity \xC2\xB7 Sleep", Icon::Heart, IM_COL32(255,55,95,255), Draw_GroupHealth }, + { "Cards", "Cards \xC2\xB7 Passes", Icon::CreditCard,IM_COL32(60,60,64,255), Draw_GroupWallet }, + { "Today", "Weather \xC2\xB7 Clock \xC2\xB7 News", Icon::CloudSun, IM_COL32(64,156,255,255), Draw_GroupToday }, + { "Create", "Music \xC2\xB7 Video \xC2\xB7 Docs", Icon::Guitar, IM_COL32(255,159,10,255), Draw_GroupCreate }, + }; -static constexpr int kSurfaceTotal = (int)(sizeof(g_surfaces)/sizeof(g_surfaces[0])); -static constexpr int kGroupCount = 11; -static constexpr int kGroupBase = kSurfaceTotal - kGroupCount; -static_assert(kSurfaceTotal > kGroupCount, "g_surfaces must hold the trailing GROUP shells plus the app rows"); -static_assert(kGroupBase >= 0, "kGroupCount exceeds the surface table size"); + static constexpr int kSurfaceTotal = (int)(sizeof(g_surfaces) / sizeof(g_surfaces[0])); + static constexpr int kGroupCount = 11; + static constexpr int kGroupBase = kSurfaceTotal - kGroupCount; + static_assert(kSurfaceTotal > kGroupCount, "g_surfaces must hold the trailing GROUP shells plus the app rows"); + static_assert(kGroupBase >= 0, "kGroupCount exceeds the surface table size"); -int SurfaceCount(){ return (int)(sizeof(g_surfaces)/sizeof(g_surfaces[0])); } -const char* SurfaceName(int i){ return (i>=0&&i=0&&i=0&&i=0&&i=0&&i= 0 && i < SurfaceCount()) ? g_surfaces[i].name : ""; } + const char* SurfaceSubtitle(int i) { return (i >= 0 && i < SurfaceCount()) ? g_surfaces[i].sub : ""; } + Icon SurfaceIcon(int i) { return (i >= 0 && i < SurfaceCount()) ? g_surfaces[i].icon : Icon::None; } + ImU32 SurfaceTint(int i) { return (i >= 0 && i < SurfaceCount()) ? g_surfaces[i].tint : Accent(); } + void SurfaceDraw(int i, float w) { if (i >= 0 && i < SurfaceCount() && g_surfaces[i].draw) g_surfaces[i].draw(w); } -int SurfaceLaunchpad(float w, const char* query){ - int clicked = -1; - ImDrawList* dl = ImGui::GetWindowDrawList(); - ImGui::Dummy(ImVec2(0,2)); - ImVec2 tp = ImGui::GetCursorScreenPos(); - dl->AddText(ImGui::GetFont(), 30.0f, ImVec2(tp.x+2, tp.y), kInk, "Apps"); - bool hasQ = query && query[0]; - int total = SurfaceCount(); - int filt[256]; int fn = 0; - for (int i=0;iAddText(ImGui::GetFont(), 14.0f, ImVec2(tp.x+2, tp.y+38), kInkSoft, hasQ?sub:"A gallery of glass surfaces"); - ImGui::Dummy(ImVec2(w, 70.0f)); - const float tile = 84.0f, gap = 16.0f, lblH = 24.0f; - int cols = (int)((w + gap) / (tile + gap)); if (cols < 1) cols = 1; - float gridW = cols*tile + (cols-1)*gap; - float ox = ImGui::GetCursorScreenPos().x + (w - gridW)*0.5f; - float oy = ImGui::GetCursorScreenPos().y; - for (int k=0;ksprings().Get((uint32_t)ImGui::GetID("app"), 1, SpringStyle::Bouncy, 1.0f); - s.target = ImGui::IsItemActive()?0.92f:(hov?1.06f:1.0f); s.Tick(Dt()); - float sc = Clampf(s.x,0.8f,1.2f); - float gel = 1.0f - sc; - float ic = tile*0.5f*sc; - float ihw = ic*(1.0f + gel*0.5f), ihh = ic*(1.0f - gel*0.4f); - ImVec2 cen(x+tile*0.5f, y+tile*0.5f); - Primitive b; b.cx=cen.x; b.cy=cen.y; b.hw=ihw; b.hh=ihh; b.corner_radius=std::min(ihw,ihh)*0.62f; - b.fade=1.0f; b.material = hov?Material::Accent:Material::Thin; b.elevate = hov?1.18f:1.0f; - g->Submit(b); - DrawIcon(dl, SurfaceIcon(si), cen, tile*0.42f*sc, hov?IM_COL32(255,255,255,255):kInk, 2.2f); - const char* nm = SurfaceName(si); - ImVec2 ts = ImGui::GetFont()->CalcTextSizeA(13.0f, 99999.0f, 0.0f, nm); - dl->AddText(ImGui::GetFont(), 13.0f, ImVec2(cen.x - ts.x*0.5f, y+tile+4.0f), kInk, nm); - ImGui::PopID(); + int SurfaceLaunchpad(float w, const char* query) { + int clicked = -1; + ImDrawList* dl = ImGui::GetWindowDrawList(); + ImGui::Dummy(ImVec2(0, 2)); + ImVec2 tp = ImGui::GetCursorScreenPos(); + dl->AddText(ImGui::GetFont(), 30.0f, ImVec2(tp.x + 2, tp.y), kInk, "Apps"); + bool hasQ = query && query[0]; + int total = SurfaceCount(); + int filt[256]; int fn = 0; + for (int i = 0; i < total && fn < 256; i++) if (!hasQ || ContainsCI(SurfaceName(i), query) || ContainsCI(SurfaceSubtitle(i), query)) filt[fn++] = i; + char sub[80]; + if (hasQ) snprintf(sub, sizeof(sub), "%d result%s for \"%s\"", fn, fn == 1 ? "" : "s", query); + dl->AddText(ImGui::GetFont(), 14.0f, ImVec2(tp.x + 2, tp.y + 38), kInkSoft, hasQ ? sub : "A gallery of glass surfaces"); + ImGui::Dummy(ImVec2(w, 70.0f)); + const float tile = 84.0f, gap = 16.0f, lblH = 24.0f; + int cols = (int)((w + gap) / (tile + gap)); if (cols < 1) cols = 1; + float gridW = cols * tile + (cols - 1) * gap; + float ox = ImGui::GetCursorScreenPos().x + (w - gridW) * 0.5f; + float oy = ImGui::GetCursorScreenPos().y; + for (int k = 0; k < fn; k++) { + int si = filt[k]; + int r = k / cols, c = k % cols; + float x = ox + c * (tile + gap), y = oy + r * (tile + lblH + gap); + ImGui::PushID(si); + ImGui::SetCursorScreenPos(ImVec2(x, y)); + ImGui::InvisibleButton("app", ImVec2(tile, tile + lblH)); + bool hov = ImGui::IsItemHovered(); + if (ImGui::IsItemDeactivated() && hov) clicked = si; + Spring& s = g->springs().Get((uint32_t)ImGui::GetID("app"), 1, SpringStyle::Bouncy, 1.0f); + s.target = ImGui::IsItemActive() ? 0.92f : (hov ? 1.06f : 1.0f); s.Tick(Dt()); + float sc = Clampf(s.x, 0.8f, 1.2f); + float gel = 1.0f - sc; + float ic = tile * 0.5f * sc; + float ihw = ic * (1.0f + gel * 0.5f), ihh = ic * (1.0f - gel * 0.4f); + ImVec2 cen(x + tile * 0.5f, y + tile * 0.5f); + Primitive b; b.cx = cen.x; b.cy = cen.y; b.hw = ihw; b.hh = ihh; b.corner_radius = std::min(ihw, ihh) * 0.62f; + b.fade = 1.0f; b.material = hov ? Material::Accent : Material::Thin; b.elevate = hov ? 1.18f : 1.0f; + g->Submit(b); + DrawIcon(dl, SurfaceIcon(si), cen, tile * 0.42f * sc, hov ? IM_COL32(255, 255, 255, 255) : kInk, 2.2f); + const char* nm = SurfaceName(si); + ImVec2 ts = ImGui::GetFont()->CalcTextSizeA(13.0f, 99999.0f, 0.0f, nm); + dl->AddText(ImGui::GetFont(), 13.0f, ImVec2(cen.x - ts.x * 0.5f, y + tile + 4.0f), kInk, nm); + ImGui::PopID(); + } + if (fn == 0) { + const char* msg = "No apps match your search"; ImVec2 ms = ImGui::GetFont()->CalcTextSizeA(16.0f, 99999.0f, 0, msg); + dl->AddText(ImGui::GetFont(), 16.0f, ImVec2(ox + gridW * 0.5f - ms.x * 0.5f, oy + 40.0f), kInkSoft, msg); + } + int rows = (fn + cols - 1) / cols; if (rows < 1) rows = 1; + ImGui::SetCursorScreenPos(ImVec2(ox, oy)); + ImGui::Dummy(ImVec2(w, rows * (tile + lblH + gap) + 8.0f)); + return clicked; } - if (fn == 0) { const char* msg = "No apps match your search"; ImVec2 ms=ImGui::GetFont()->CalcTextSizeA(16.0f,99999.0f,0,msg); - dl->AddText(ImGui::GetFont(), 16.0f, ImVec2(ox+gridW*0.5f-ms.x*0.5f, oy+40.0f), kInkSoft, msg); } - int rows = (fn+cols-1)/cols; if (rows<1) rows=1; - ImGui::SetCursorScreenPos(ImVec2(ox, oy)); - ImGui::Dummy(ImVec2(w, rows*(tile+lblH+gap) + 8.0f)); - return clicked; -} -int SurfaceDock(float cx, float bottomY, float maxW, int activeSurface){ - ImDrawList* dl = ImGui::GetWindowDrawList(); - ImGuiIO& io = ImGui::GetIO(); - int dk[kGroupCount]; - for (int i = 0; i < kGroupCount; ++i) dk[i] = kGroupBase + i; - const int n = kGroupCount; - const float base = 42.0f, gap = 8.0f, mag = 26.0f, sigma = 74.0f; - float restTotal = n*base + (n-1)*gap; - float barW = maxW * 0.95f; - float barGrow = barW * 0.03f; - barW += barGrow; - float midX = cx + barGrow * 0.5f; - float startX = midX - restTotal*0.5f; - float mx = io.MousePos.x, my = io.MousePos.y; - float dt = Dt(); - bool inRange = my > bottomY - 150.0f && my < bottomY + 26.0f && mx > startX - 60.0f && mx < startX + restTotal + 60.0f; - static float dockAct = 0.0f; - dockAct += ((inRange ? 1.0f : 0.0f) - dockAct) * Clampf(12.0f*dt, 0.0f, 1.0f); - static float scSm[32]; static bool scInit = false; - if (!scInit){ for (int k=0;k<32;k++) scSm[k] = base; scInit = true; } - float sc[32], scaledTotal = 0.0f; - for (int i=0;i bottomY - 150.0f && my < bottomY + 26.0f && mx > startX - 60.0f && mx < startX + restTotal + 60.0f; + static float dockAct = 0.0f; + dockAct += ((inRange ? 1.0f : 0.0f) - dockAct) * Clampf(12.0f * dt, 0.0f, 1.0f); + static float scSm[32]; static bool scInit = false; + if (!scInit) { for (int k = 0; k < 32; k++) scSm[k] = base; scInit = true; } + float sc[32], scaledTotal = 0.0f; + for (int i = 0; i < n; i++) { + float rc = startX + i * (base + gap) + base * 0.5f; float d = mx - rc; + float gmag = expf(-(d * d) / (2.0f * sigma * sigma)) * dockAct; + float target = base + mag * gmag; + scSm[i] += (target - scSm[i]) * Clampf(22.0f * dt, 0.0f, 1.0f); + sc[i] = scSm[i]; scaledTotal += sc[i]; + } + scaledTotal += (n - 1) * gap; + float barH = base + 14.0f; + Spring& barWake = g->springs().Get((uint32_t)ImGui::GetID("dockbar"), 6, SpringStyle::Bouncy, 0.0f); + barWake.target = dockAct; barWake.Tick(dt); + float wake = Clampf(barWake.x, 0.0f, 1.2f); + Primitive bar; bar.cx = midX; bar.cy = bottomY - barH * 0.5f; bar.hw = barW * 0.5f; bar.hh = barH * 0.5f; + bar.corner_radius = 22.0f + 3.0f * wake; bar.fade = 1.0f; bar.material = Material::Regular; + bar.elevate = 1.0f + 0.12f * wake; g->SubmitOverlay(bar); + float x = midX - scaledTotal * 0.5f; int clicked = -1; int hov = -1; float hovCx = midX; + for (int i = 0; i < n; i++) { + float s = sc[i]; float ix = x, iy = bottomY - 6.0f - s; + ImGui::PushID(2000 + i); ImGui::SetCursorScreenPos(ImVec2(ix, iy)); ImGui::InvisibleButton("dk", ImVec2(s, s)); + bool h = ImGui::IsItemHovered(); if (h) hov = i; + bool act = ImGui::IsItemActive(); + uint32_t did = (uint32_t)ImGui::GetID("dk"); + Spring& ps = g->springs().Get(did, 3, SpringStyle::Bouncy, 1.0f); + ps.target = act ? 0.84f : 1.0f; ps.Tick(Dt()); + Spring& bnc = g->springs().Get(did, 4, SpringStyle::Bouncy, 0.0f); + bnc.target = 0.0f; + if (ImGui::IsItemDeactivated() && h) { clicked = dk[i]; bnc.v += 5.5f; } + bnc.Tick(Dt()); + Spring& dotS = g->springs().Get(did, 5, SpringStyle::Bouncy, (dk[i] == activeSurface) ? 1.0f : 0.0f); + dotS.target = (dk[i] == activeSurface) ? 1.0f : 0.0f; dotS.Tick(Dt()); + ImGui::PopID(); + float pv = Clampf(ps.x, 0.7f, 1.1f); + float bub = Clampf(bnc.x, -0.20f, 0.30f); + float dotk = Clampf(dotS.x, 0.0f, 1.3f); + float gel = 1.0f - pv; + float vis = s * pv * (1.0f + bub); + float jw = bub * 0.5f; + ImVec2 igc(ix + s * 0.5f, iy + s * 0.5f); + if (h) hovCx = igc.x; + Primitive ic; ic.cx = igc.x; ic.cy = igc.y; + ic.hw = vis * 0.5f * (1.0f + gel * 0.6f + jw); ic.hh = vis * 0.5f * (1.0f - gel * 0.5f - jw); + ic.corner_radius = std::min(ic.hw, ic.hh) * 0.86f; ic.fade = 1.0f; ic.material = h ? Material::Accent : Material::Regular; + ic.elevate = h ? 1.16f : 1.0f; + g->SubmitOverlay(ic); + DrawIcon(dl, SurfaceIcon(dk[i]), ImVec2(igc.x + 1.0f, igc.y + 1.0f), vis * 0.50f, SA(IM_COL32(0, 0, 0, 255), 0.30f), 2.2f); + DrawIcon(dl, SurfaceIcon(dk[i]), igc, vis * 0.50f, IM_COL32(255, 255, 255, 255), 2.2f); + if (dotk > 0.01f) + dl->AddCircleFilled(ImVec2(ix + s * 0.5f, bottomY + 4.0f), 2.4f * dotk, SA(InkColor(), 0.85f * Clampf(dotk, 0.0f, 1.0f))); + x += s + gap; + } + static int sndHov = -1; + if (hov != sndHov) { if (hov >= 0) PlaySfx(Sfx::TapSoft); sndHov = hov; } + static float labA = 0.0f, labX = 0.0f; static int labI = -1; static bool labInit = false; + if (!labInit) { labX = midX; labInit = true; } + labA += (((hov >= 0) ? 1.0f : 0.0f) - labA) * Clampf(16.0f * dt, 0.0f, 1.0f); + if (hov >= 0) { labI = hov; labX += (hovCx - labX) * Clampf(20.0f * dt, 0.0f, 1.0f); } + if (labA > 0.01f && labI >= 0 && labI < n) { + const char* nm = SurfaceName(dk[labI]); + ImVec2 ts = ImGui::GetFont()->CalcTextSizeA(14.0f, 99999.0f, 0, nm); + float rise = (1.0f - labA) * 8.0f; + float lx = labX, ly = bottomY - 6.0f - sc[labI] - 30.0f + rise; + int bgA = (int)(0.9f * labA * 255.0f), txA = (int)(labA * 255.0f); + dl->AddRectFilled(ImVec2(lx - ts.x * 0.5f - 10, ly - 4), ImVec2(lx + ts.x * 0.5f + 10, ly + ts.y + 4), IM_COL32(20, 20, 26, bgA), 8.0f); + dl->AddText(ImGui::GetFont(), 14.0f, ImVec2(lx - ts.x * 0.5f, ly), IM_COL32(255, 255, 255, txA), nm); + } + return clicked; } - scaledTotal += (n-1)*gap; - float barH = base + 14.0f; - Spring& barWake = g->springs().Get((uint32_t)ImGui::GetID("dockbar"), 6, SpringStyle::Bouncy, 0.0f); - barWake.target = dockAct; barWake.Tick(dt); - float wake = Clampf(barWake.x, 0.0f, 1.2f); - Primitive bar; bar.cx = midX; bar.cy = bottomY - barH*0.5f; bar.hw = barW*0.5f; bar.hh = barH*0.5f; - bar.corner_radius = 22.0f + 3.0f*wake; bar.fade = 1.0f; bar.material = Material::Regular; - bar.elevate = 1.0f + 0.12f*wake; g->SubmitOverlay(bar); - float x = midX - scaledTotal*0.5f; int clicked = -1; int hov = -1; float hovCx = midX; - for (int i=0;isprings().Get(did, 3, SpringStyle::Bouncy, 1.0f); - ps.target = act ? 0.84f : 1.0f; ps.Tick(Dt()); - Spring& bnc = g->springs().Get(did, 4, SpringStyle::Bouncy, 0.0f); - bnc.target = 0.0f; - if (ImGui::IsItemDeactivated() && h) { clicked = dk[i]; bnc.v += 5.5f; } - bnc.Tick(Dt()); - Spring& dotS = g->springs().Get(did, 5, SpringStyle::Bouncy, (dk[i]==activeSurface)?1.0f:0.0f); - dotS.target = (dk[i]==activeSurface) ? 1.0f : 0.0f; dotS.Tick(Dt()); - ImGui::PopID(); - float pv = Clampf(ps.x, 0.7f, 1.1f); - float bub = Clampf(bnc.x, -0.20f, 0.30f); - float dotk = Clampf(dotS.x, 0.0f, 1.3f); - float gel = 1.0f - pv; - float vis = s * pv * (1.0f + bub); - float jw = bub * 0.5f; - ImVec2 igc(ix+s*0.5f, iy + s*0.5f); - if (h) hovCx = igc.x; - Primitive ic; ic.cx = igc.x; ic.cy = igc.y; - ic.hw = vis*0.5f*(1.0f + gel*0.6f + jw); ic.hh = vis*0.5f*(1.0f - gel*0.5f - jw); - ic.corner_radius = std::min(ic.hw, ic.hh)*0.86f; ic.fade = 1.0f; ic.material = h ? Material::Accent : Material::Regular; - ic.elevate = h ? 1.16f : 1.0f; - g->SubmitOverlay(ic); - DrawIcon(dl, SurfaceIcon(dk[i]), ImVec2(igc.x+1.0f, igc.y+1.0f), vis*0.50f, SA(IM_COL32(0,0,0,255),0.30f), 2.2f); - DrawIcon(dl, SurfaceIcon(dk[i]), igc, vis*0.50f, IM_COL32(255,255,255,255), 2.2f); - if (dotk > 0.01f) - dl->AddCircleFilled(ImVec2(ix+s*0.5f, bottomY + 4.0f), 2.4f*dotk, SA(InkColor(), 0.85f*Clampf(dotk,0.0f,1.0f))); - x += s + gap; - } - static int sndHov = -1; - if (hov != sndHov) { if (hov >= 0) PlaySfx(Sfx::TapSoft); sndHov = hov; } - static float labA = 0.0f, labX = 0.0f; static int labI = -1; static bool labInit = false; - if (!labInit) { labX = midX; labInit = true; } - labA += (((hov >= 0) ? 1.0f : 0.0f) - labA) * Clampf(16.0f*dt, 0.0f, 1.0f); - if (hov >= 0) { labI = hov; labX += (hovCx - labX) * Clampf(20.0f*dt, 0.0f, 1.0f); } - if (labA > 0.01f && labI >= 0 && labI < n) { - const char* nm = SurfaceName(dk[labI]); - ImVec2 ts = ImGui::GetFont()->CalcTextSizeA(14.0f, 99999.0f, 0, nm); - float rise = (1.0f - labA) * 8.0f; - float lx = labX, ly = bottomY - 6.0f - sc[labI] - 30.0f + rise; - int bgA = (int)(0.9f * labA * 255.0f), txA = (int)(labA * 255.0f); - dl->AddRectFilled(ImVec2(lx-ts.x*0.5f-10, ly-4), ImVec2(lx+ts.x*0.5f+10, ly+ts.y+4), IM_COL32(20,20,26,bgA), 8.0f); - dl->AddText(ImGui::GetFont(), 14.0f, ImVec2(lx-ts.x*0.5f, ly), IM_COL32(255,255,255,txA), nm); - } - return clicked; -} } From d130c392a7d9524500a82e0314dc3fbf06ed44b1 Mon Sep 17 00:00:00 2001 From: Anesthesia <77818664+shimenga@users.noreply.github.com> Date: Sat, 27 Jun 2026 23:42:43 +0800 Subject: [PATCH 2/2] Remove max and min macros to avoid conflicts --- examples/example_win32_directx11/src/glass/backdrop.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/example_win32_directx11/src/glass/backdrop.cpp b/examples/example_win32_directx11/src/glass/backdrop.cpp index 746d3ba..fd67e08 100644 --- a/examples/example_win32_directx11/src/glass/backdrop.cpp +++ b/examples/example_win32_directx11/src/glass/backdrop.cpp @@ -8,7 +8,8 @@ #pragma comment(lib, "dxgi.lib") #pragma comment(lib, "d3dcompiler.lib") #pragma comment(lib, "user32.lib") - +#undef max +#undef min #ifndef WDA_EXCLUDEFROMCAPTURE #define WDA_EXCLUDEFROMCAPTURE 0x00000011 #endif