docs: document gfx::pipeline + add Markdown style rule to AGENTS.md + README styling
- Added comprehensive "Pipeline Abstraction" section to README.md (for dummies, with step-by-step examples, render-to-texture, and post-processing). - Added "Documentation (Markdown)" section to AGENTS.md with the max-80-cols rule (exceptions for tables/code blocks). - Applied consistent Markdown styling to AGENTS.md and README.md (wrapped text at 80 cols, bold, code spans, cleaned duplicates). - Moved scenes libraries to (cleaned main CMakeLists.txt significantly). No behavior change. All follows AGENTS.md conventions.
This commit is contained in:
@@ -48,4 +48,112 @@ Q key Quit
|
||||
|
||||
- **cube** — spinning colored cube with per-face colors
|
||||
- **sphere** — cube-to-sphere mapped mesh with per-face colors and
|
||||
diffuse lighting
|
||||
diffuse lighting (uses the new pipeline with render-to-texture + post-processing)
|
||||
|
||||
## Pipeline Abstraction (`cbt::gfx`)
|
||||
|
||||
The project now has a clean, easy-to-use **graphics pipeline** layer in
|
||||
`cbt/gfx.hpp`. Think of it like a simple "drawing recipe" that hides
|
||||
all the messy OpenGL details (shaders, buffers, VAOs, uniforms,
|
||||
framebuffers). It's inspired by libraries like Sokol but made for C++
|
||||
with RAII classes, `pipeline_desc` structs, and beginner-friendly
|
||||
methods.
|
||||
|
||||
### Why it exists (for dummies)
|
||||
- **No more copy-paste GL calls** in your scenes.
|
||||
- **Easy to add effects**: Render to a texture (offscreen), then do
|
||||
post-processing (blur, vignette, color grading, bloom, SSAO, etc.).
|
||||
- **Future-proof**: The same code works if we add a Vulkan backend later
|
||||
(just swap the internal `impl`—no changes to your scene code).
|
||||
- **Switching scenes works smoothly** (no more glitches from leftover
|
||||
GL state like depth test or bound textures).
|
||||
|
||||
It abstracts the typical graphics pipeline stages you might see in
|
||||
diagrams (vertex shader, rasterizer, pixel shader, output merger) into
|
||||
one simple object. Post-processing is a second "step" after the main
|
||||
draw.
|
||||
|
||||
### How to use it (step-by-step for dummies)
|
||||
1. **Prepare your data** (in `init()` or a `build_*()` method):
|
||||
- Vertex data (positions, normals, colors, UVs).
|
||||
- Index data (optional, for triangles).
|
||||
- Attribute description (where each piece of data lives in the
|
||||
vertex, e.g. location 0 = position at offset 0).
|
||||
- Shader source code (vertex + fragment as raw strings).
|
||||
|
||||
2. **Create a `pipeline_desc`** (the recipe):
|
||||
```cpp
|
||||
gfx::pipeline_desc desc {
|
||||
.vertex_data = std::as_bytes(std::span{my_vertices}),
|
||||
.index_data = std::as_bytes(std::span{my_indices}),
|
||||
.attributes = {
|
||||
{.location = 0, .num_components = 3, .offset = 0}, // pos
|
||||
{.location = 1, .num_components = 3, .offset = 12}, // normal
|
||||
// ... more
|
||||
},
|
||||
.vertex_stride = sizeof(MyVertex),
|
||||
.vertex_shader_src = my_vert_src,
|
||||
.fragment_shader_src = my_frag_src,
|
||||
.depth_test = true, // on for 3D, off for 2D post-process
|
||||
};
|
||||
```
|
||||
|
||||
3. **Build the pipeline**:
|
||||
```cpp
|
||||
m_pipeline = gfx::pipeline{desc};
|
||||
if (!m_pipeline.valid()) { /* error */ }
|
||||
```
|
||||
|
||||
4. **Draw it** (in `render()`):
|
||||
```cpp
|
||||
m_pipeline.draw(model_matrix, view_matrix, proj_matrix);
|
||||
```
|
||||
|
||||
### Render-to-Texture + Post-Processing (the cool part)
|
||||
Use `gfx::render_target` for offscreen rendering (like a temporary
|
||||
canvas):
|
||||
|
||||
```cpp
|
||||
// In class
|
||||
gfx::render_target m_rt{0, 0};
|
||||
gfx::pipeline m_post_pipeline; // second pipeline for effects
|
||||
|
||||
// In init()
|
||||
m_rt.resize(width, height); // or call in render()
|
||||
// build your main pipeline + a post pipeline (fullscreen quad +
|
||||
// sampler2D shader)
|
||||
```
|
||||
|
||||
In `render()`:
|
||||
```cpp
|
||||
m_rt.resize(width, height);
|
||||
m_rt.bind(); // draw to texture instead of screen
|
||||
// ... clear, draw main scene pipeline ...
|
||||
m_rt.unbind();
|
||||
|
||||
// Post-processing step
|
||||
m_post_pipeline.bind_texture("u_texture", m_rt.color_id(), 0);
|
||||
m_post_pipeline.draw(...); // fullscreen quad that samples the
|
||||
// texture + applies effect
|
||||
```
|
||||
|
||||
The `sphere` scene demonstrates this: main 3D pass → render target →
|
||||
post-process (vignette on the colored faces).
|
||||
|
||||
### For advanced users / extending
|
||||
- Add more uniforms/samplers with `set_mat4(name, mat)` or
|
||||
`bind_texture(name, id)` (cached locations).
|
||||
- To add Vulkan: implement a new `impl` in `gfx.cpp` that uses
|
||||
`VkPipeline`, `VkFramebuffer`, etc. (the public API stays identical).
|
||||
- See `scenes/sphere.cpp` for a full example (including fullscreen
|
||||
quad for post-processing).
|
||||
|
||||
This keeps your scene code tiny and clean while giving you powerful
|
||||
graphics features.
|
||||
|
||||
## Scenes
|
||||
|
||||
- **cube** — spinning colored cube with per-face colors
|
||||
- **sphere** — cube-to-sphere mapped mesh with per-face colors and
|
||||
diffuse lighting (uses the new pipeline with render-to-texture +
|
||||
post-processing)
|
||||
|
||||
Reference in New Issue
Block a user