# GLFW port notes

## 这次重要修改/新增了什么，为什么这么改
- main.cpp: 改成纯 GLFW/GLAD 版本，重建相机/输入、面板/点阵 VAO/VBO、实例化上传逻辑，避免 Qt 依赖，方便直接跑 OpenGL 核心模式。
- shaders/panel.frag & shaders/dots.frag: 修过语法/Uniform，对接 GLFW 管线，并保持金属质感（不再做数据伪彩色）；点用内置小纹理，省掉外部贴图。
- myshader.hh: 增加常用 uniform setter、修正 program 链接日志、析构释放 program，方便传矩阵/向量。
- CMakeLists.txt: 指定 C++17，保证可用 std::clamp 等工具。
- README.md: 补了构建、运行和操作说明，标明从项目根运行以找到 `./shaders`。

## Controls
- 右键拖拽：绕物体旋转相机（yaw/pitch）  
- 滚轮：调节视角 FOV 缩放  
- Esc：退出

## Build & run
```bash
mkdir -p build
cd build
cmake ..
make -j
```

从项目根目录运行（确保能找到 `./shaders`）：
```bash
./build/base-project
```

目前用 `update_demo_values` 生成简单波纹示例数据，如需接入传感器数据，替换 main.cpp 里的该函数并在循环前设置好 `set_spec` / `set_panel_size`。

## Heatmap Demo (Heightmap + Dented Surface)

This demo renders a thick slab with a dented top surface based on sensor values.
Values are mapped to a depth range (0-500 -> 0..kDentMax), so higher force makes
the surface go deeper. The side walls follow the dent so it reads as one solid.

### UML (Mermaid)
```mermaid
classDiagram
    class AppState {
        +int minV
        +int maxV
        +mat4 mvp
        +vec3 cameraPos
    }
    class HeightMap {
        +low_values[12x7]
        +height_values[1200x700]
        +update_demo_heightmap(t)
        +upload_height_texture()
    }
    class HeatmapMesh {
        +meshCols
        +meshRows
        +vao/vbo/ibo
    }
    class SkirtMesh {
        +border_uvs
        +update_skirt_vertices()
    }
    class BaseMesh {
        +thickness
        +vao/vbo/ibo
    }
    class Renderer {
        +render_background()
        +render_base()
        +render_skirt()
        +render_heatmap()
    }
    class Shaders {
        +heatmap.vert/frag
        +base.vert/frag
        +bg.vert/frag
    }

    AppState --> Renderer
    HeightMap --> HeatmapMesh
    HeightMap --> SkirtMesh
    Renderer --> HeatmapMesh
    Renderer --> SkirtMesh
    Renderer --> BaseMesh
    Renderer --> Shaders
```

### How It Works (Step-by-Step)
1) `update_demo_heightmap(t)` generates a slow-changing 12x7 grid using a few
   Gaussian blobs. This is the "raw sensor" layer.
2) The 12x7 grid is upsampled to 1200x700 with bilinear filtering, stored in
   `height_values`.
3) `height_values` is uploaded into an `GL_R32F` texture (`height_tex`).
4) `heatmap.vert` samples `height_tex` and displaces the surface in Z:
   `z = uBaseZ + h`, where `h` is the mapped depth (0..kDentMax).
5) `heatmap.frag` re-samples neighbor texels to approximate a normal, then applies
   a simple light + color ramp for readability.
6) `init_skirt_geometry()` builds a ring of border vertices, and
   `update_skirt_vertices()` samples the border heights so the side walls "follow"
   the dent. This keeps the slab looking solid when the edge is depressed.
7) Render order: background grid -> back face -> skirt -> heatmap surface.

### Key Parameters You Can Tune
- `kThickness`: slab thickness.
- `kDentMax`: maximum dent depth (keep <= thickness).
- `kMeshCols/kMeshRows`: heatmap mesh resolution (visual smoothness).
- `kHeightW/kHeightH`: texture resolution (sampling detail).
- `g_state.minV/maxV`: value range (0..500 by default).

### If You Want Real Data
Replace `update_demo_heightmap()` with your sensor values:
- Fill `low_values` from your 12x7 data.
- Run the same upsample step to `height_values`.
- Call `upload_height_texture_if_needed()` and `update_skirt_vertices()` each frame.
