# eduwin 3D 渲染 API（D3D11）

eduwin 对 Direct3D 11 的轻量封装。

**核心约定：**

- 矩阵采用 **row-major 存储**，与 `D3DMATRIX` 和 HLSL 的 `row_major float4x4` 一致
- 顶点格式包含**位置 + 法线 + UV + 顶点色**（共 48 字节）
- 常量缓冲包含世界/视图/投影矩阵 + 光照参数
- 着色器支持：环境光 + 方向光 + 点光源的漫反射光照

---

## 数据类型

```c
typedef struct { float m[16]; } dx_mat4;
```

4×4 矩阵，row-major 存储（`m[row*4+col]`）。例如 `m[0]=_11`，`m[1]=_12`，`m[4]=_21`，`m[12]=_41`。

```c
typedef struct {
    float x, y, z;       // 位置  0-11
    float nx, ny, nz;    // 法线  12-23
    float u, v;          // UV    24-31
    float r, g, b, a;    // 颜色  32-47
} dx_vertex;
```

顶点格式：位置（3 float）+ 法线（3 float）+ UV（2 float）+ 顶点色（4 float），共 48 字节。

```c
typedef struct { void *vb; void *ib; int icount; } dx_geometry;
```

`dx_geometry` 包含顶点缓冲和索引缓冲。通过 `dx_create_geometry` 创建，`dx_free_geometry` 释放。

```c
typedef struct dx_texture_t dx_texture;
```

纹理是不透明类型，通过 `dx_create_texture` 或 `dx_create_texture_rgba` 创建。

---

## 生命周期

```c
int dx_init(HWND hwnd, int w, int h);
```

初始化 D3D11。创建 swap chain、编译 shader、创建常量缓冲和光栅化状态。成功返回 1，失败返回 0。

- `hwnd` — 渲染窗口句柄
- `w`, `h` — 客户区宽高（像素）
- 内部自动调用 `dx_resize` 创建 render target 和 depth stencil

```c
void dx_shutdown(void);
```

销毁所有 D3D11 资源（rasterizer state、constant buffer、input layout、shaders、render target、depth stencil、swap chain、device context、device）。

```c
void dx_begin(float r, float g, float b, float a);
```

开始一帧渲染。清空 render target 为指定颜色，清空 depth stencil。**每帧必须在所有绘制前调用一次。**

```c
void dx_end(void);
```

结束一帧渲染。调用 `Present(1, 0)` 交换前后缓冲。

```c
void dx_resize(int w, int h);
```

重建 render target 和 depth stencil。窗口大小变化时调用。

---

## 矩阵设置

```c
void dx_set_world(dx_mat4 world);
void dx_set_view(dx_mat4 view);
void dx_set_projection(dx_mat4 proj);
```

设置世界矩阵、视图矩阵、投影矩阵。在 `dx_begin` / `dx_end` 之间调用，每次 `dx_draw_indexed` 前需先设 world。三个矩阵在常量缓冲中的 HLSL 代码路径为：

```hlsl
p = mul(p, mWorld);
p = mul(p, mView);
p = mul(p, mProjection);
```

---

## 相机封装

```c
typedef struct {
    float position[3];   /* 相机位置   camera.position */
    float target[3];     /* 观察目标   camera.lookAt */
    float up[3];         /* 上方向 */
    float fov;           /* 视场角 */
    float aspect;        /* 宽高比     width/height */
    float near_z;        /* 近裁剪面 */
    float far_z;         /* 远裁剪面 */
} dx_camera;

void dx_camera_init(dx_camera *cam, float px, float py, float pz, float aspect);
void dx_camera_update(dx_camera *cam);
```

用法：

```c
dx_camera cam;
dx_camera_init(&cam, 0, 3, -5, 800.0f / 600.0f);  // 初始化
dx_camera_update(&cam);                             // 每帧更新

// 窗口 resize 时改 aspect 再 update：
cam.aspect = 1024.0f / 768.0f;
dx_camera_update(&cam);
```

---

## 网格（Mesh = Geometry + Material + Transform）

`dx_mesh` 封装了几何体 + 材质 + 变换，隐藏矩阵操作，仿 Three.js 的 `Mesh`：

```c
typedef struct {
    dx_geometry *geometry;  /* 顶点数据 */
    dx_material *material;  /* 材质（可 NULL） */
    float position[3];      /* 平移 */
    float rotation[3];      /* 旋转（XYZ 欧拉角） */
    float scale[3];         /* 缩放 */
} dx_mesh;

dx_mesh* dx_create_mesh(dx_geometry *geo, dx_material *mat);
void     dx_mesh_set_position(dx_mesh *m, float x, float y, float z);
void     dx_mesh_set_rotation(dx_mesh *m, float x, float y, float z);
void     dx_mesh_set_scale(dx_mesh *m, float x, float y, float z);
void     dx_mesh_draw(dx_mesh *m);
void     dx_free_mesh(dx_mesh *m);
```

`dx_mesh_draw` 内部自动计算 `world = S × Rx × Ry × Rz × T`，绑定材质，绘制几何体。可直接读写字段：

```c
mesh->position[0] = 2;    /* X 位置 */
mesh->rotation[1] = 0.5f; /* Y 旋转 */
```

网格通常由 `dx_create_mesh` 作为指针创建，`dx_free_mesh` 释放（注意：不会释放 geometry/material，共享引用需调用方管理）。

````c
obj.ry = 0.5f;         // 绕 Y 转
obj.rx = 0.1f;         // 绕 X 转
obj.sx = 2.0f;         // X 方向放大 2 倍
---

## 几何体操作

```c
dx_geometry* dx_create_geometry(dx_vertex *verts, int vcount,
                                unsigned short *indices, int icount);
````

创建自定义几何体。上传顶点和索引数据到 D3D11 的默认用途（`D3D11_USAGE_DEFAULT`）缓冲。

```c
dx_geometry* dx_create_box(float w, float h, float d,
                           float r, float g, float b, float a);
```

创建立方体几何体。自动生成 8 个顶点和 36 个索引（12 个三角形），中心在原点。

```c
dx_geometry* dx_create_sphere(float radius,
                              float r, float g, float b, float a);
```

创建 UV 球体几何体（12 环 × 16 段），中心在原点。

```c
dx_geometry* dx_create_cylinder(float radius, float height,
                                float r, float g, float b, float a);
```

创建圆柱体几何体（16 段），中心在原点。

```c
dx_geometry* dx_create_pyramid(float w, float h, float d,
                               float r, float g, float b, float a);
```

创建四棱锥几何体（5 顶点 / 6 三角形），中心在原点。

```c
dx_geometry* dx_create_plane(float w, float h,
                             float r, float g, float b, float a);
```

创建平面几何体（4 顶点 / 2 三角形），默认在 XY 平面、面向 +Z 方向、中心在原点。通过旋转可以变成地面（绕 X 转 -90°）或墙面。

```c
void dx_draw_geometry(dx_geometry *geo, int count, int start_index, int base_vertex);
```

绘制几何体。每次调用前必须设置好 world 矩阵。

```c
void dx_free_geometry(dx_geometry *geo);
```

释放几何体的顶点和索引缓冲，并释放几何体本身。

---

## 光照

```c
void dx_set_ambient_light(float r, float g, float b, float intensity);
```

设置环境光颜色和强度（漫反射系数）。环境光均匀照亮所有物体，无方向感。

```c
void dx_set_directional_light(float dx, float dy, float dz,
                               float r, float g, float b, float intensity);
```

设置方向光。`dx/dy/dz` 是**指向光源**的方向向量（会被归一化），`r/g/b` 是颜色，`intensity` 是强度。

```c
void dx_set_point_light(float px, float py, float pz,
                         float r, float g, float b, float intensity,
                         float range);
```

设置点光源。`px/py/pz` 是世界坐标位置，`range` 是衰减距离。

光照在 `dx_begin` / `dx_end` 之间、绘制之前设置：

```c
dx_begin(0.15f, 0.15f, 0.2f, 1);

dx_set_ambient_light(0.4f, 0.4f, 0.4f, 1.0f);
dx_set_directional_light(0.3f, -1, 0.5f, 1, 1, 1, 1.2f);
dx_set_point_light(1.5f, 3, 2, 1, 0.8f, 0.6f, 0.8f, 6);

dx_mesh_draw(mesh);
dx_end();
```

---

## 纹理

```c
dx_texture* dx_create_texture(const char *filename);
```

从 BMP/PNG/JPG 文件创建纹理。返回纹理句柄，失败返回 `NULL`。

```c
dx_texture* dx_create_texture_rgba(int w, int h, const unsigned char *rgba);
```

从内存 RGBA 像素数据创建纹理，用于程序生成的纹理。

```c
void dx_free_texture(dx_texture *tex);
```

释放纹理资源。

```c
void dx_bind_texture(dx_texture *tex, int slot);
```

将纹理绑定到着色器的指定插槽（`slot` 从 0 开始）。绑定后后续绘制的物体会使用该纹理。传 `NULL` 可解除绑定。

用法：

```c
dx_texture *tex = dx_create_texture("checker.bmp");
dx_bind_texture(tex, 0);    // 绑定到 slot 0
dx_mesh_draw(mesh);         // 使用纹理绘制
dx_bind_texture(NULL, 0);   // 解绑
```

---

## glTF 加载

```c
dx_mesh** dx_load_gltf(const char *path, int *out_count);
```

从 glTF 文件加载网格，返回 `dx_mesh*` 数组。`out_count` 返回网格数量。失败返回 `NULL`。

```c
void dx_free_geometries(dx_geometry **geos, int count);
```

释放 `dx_load_gltf` 返回的整个网格数组。

用法：

```c
int count;
dx_geometry **geos = dx_load_gltf("model.gltf", &count);
if (geos) {
    for (int i = 0; i < count; i++)
        dx_mesh *m = dx_create_mesh(geos[i], NULL);
    // ...
    dx_free_geometries(geos, count);
}
```

---

## 矩阵数学辅助

所有矩阵函数使用 **row-major** 约定，与 `D3DXMATRIX` 一致。

```c
void dx_mat4_identity(dx_mat4 *m);
void dx_mat4_mul(dx_mat4 *out, const dx_mat4 *a, const dx_mat4 *b);
void dx_mat4_rotation_x(dx_mat4 *m, float angle);
void dx_mat4_rotation_y(dx_mat4 *m, float angle);
void dx_mat4_rotation_z(dx_mat4 *m, float angle);
void dx_mat4_translation(dx_mat4 *m, float x, float y, float z);
void dx_mat4_look_at_lh(dx_mat4 *m, const float eye[3],
                        const float at[3], const float up[3]);
void dx_mat4_perspective_fov_lh(dx_mat4 *m, float fov_y,
                                float aspect, float zn, float zf);
```

---

## 内部结构

| 组件          | 说明                                                           |
| ------------- | -------------------------------------------------------------- |
| Swap Chain    | 双缓冲，`DXGI_SWAP_EFFECT_DISCARD`                             |
| Feature Level | `D3D_FEATURE_LEVEL_11_0`                                       |
| Shader Model  | `vs_5_0` / `ps_5_0`                                            |
| 光栅化        | `D3D11_FILL_SOLID` + `D3D11_CULL_NONE`                         |
| 常量缓冲      | 单个 `register(b0)`，包含 world / view / projection + 光照参数 |
| 光照模型      | 环境光 + 方向光漫反射 + 点光源漫反射衰减                       |
| 顶点格式      | `POSITION` + `NORMAL` + `TEXCOORD` + `COLOR`                   |

---
