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:
@@ -12,11 +12,11 @@
|
|||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cmake -S . -B build -GNinja
|
cmake -S . -B build -GNinja
|
||||||
ninja -C build
|
ninja -C build
|
||||||
./build/cuber
|
./build/cuber
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
@@ -34,7 +34,8 @@ To add a new dependency:
|
|||||||
|
|
||||||
The project is split into static libraries:
|
The project is split into static libraries:
|
||||||
|
|
||||||
- **`cbt_opengl`** — OpenGL abstraction and window management (window, context, buffer, texture, vao, shader, descriptor)
|
- **`cbt_opengl`** — OpenGL abstraction and window management (window,
|
||||||
|
context, buffer, texture, vao, shader, descriptor)
|
||||||
- **`cbt_scene`** — Base scene class
|
- **`cbt_scene`** — Base scene class
|
||||||
- **`scenes_cube`** — Spinning cube scene implementation
|
- **`scenes_cube`** — Spinning cube scene implementation
|
||||||
- **`scenes_sphere`** — Cube-to-sphere mapped mesh with diffuse lighting
|
- **`scenes_sphere`** — Cube-to-sphere mapped mesh with diffuse lighting
|
||||||
@@ -52,10 +53,13 @@ to the custom scripts instead of system-installed packages.
|
|||||||
- **No semicolons after closing braces** for namespaces/classes
|
- **No semicolons after closing braces** for namespaces/classes
|
||||||
- `auto` for obvious types (e.g. `auto main(...) -> int`)
|
- `auto` for obvious types (e.g. `auto main(...) -> int`)
|
||||||
- **East const** (e.g. `char const*` not `const char*`)
|
- **East const** (e.g. `char const*` not `const char*`)
|
||||||
- **Trailing return type** for all function definitions, including operators (e.g. `auto operator=(T&&) noexcept -> T&`)
|
- **Trailing return type** for all function definitions, including
|
||||||
- **Public members first** in class declarations, private members at the bottom
|
operators (e.g. `auto operator=(T&&) noexcept -> T&`)
|
||||||
|
- **Public members first** in class declarations, private members at the
|
||||||
|
bottom
|
||||||
- `<>` includes only for system headers (std, OS, etc.)
|
- `<>` includes only for system headers (std, OS, etc.)
|
||||||
- `""` includes for third-party dependencies (e.g. `fmt`, `nlohmann/json`)
|
- `""` includes for third-party dependencies (e.g. `fmt`,
|
||||||
|
`nlohmann/json`)
|
||||||
- **Naming:** `snake_case` for variables, functions, and classes
|
- **Naming:** `snake_case` for variables, functions, and classes
|
||||||
- **Naming:** `SCREAMING_SNAKE_CASE` only for macros and constants
|
- **Naming:** `SCREAMING_SNAKE_CASE` only for macros and constants
|
||||||
- Include order:
|
- Include order:
|
||||||
@@ -82,21 +86,34 @@ to the custom scripts instead of system-installed packages.
|
|||||||
- Follow the 50/72 rule:
|
- Follow the 50/72 rule:
|
||||||
- Subject line: max 50 characters
|
- Subject line: max 50 characters
|
||||||
- Body lines: wrapped at 72 characters
|
- Body lines: wrapped at 72 characters
|
||||||
- Use conventional commit prefixes (`feat:`, `fix:`, `docs:`, `chore:`, etc.)
|
- Use conventional commit prefixes (`feat:`, `fix:`, `docs:`, `chore:`,
|
||||||
|
etc.)
|
||||||
- Separate subject from body with a blank line
|
- Separate subject from body with a blank line
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
feat: add stopwatch timer
|
feat: add stopwatch timer
|
||||||
|
|
||||||
Replace Hello World with a live stopwatch that prints elapsed time
|
Replace Hello World with a live stopwatch that prints elapsed time
|
||||||
in HH:MM:SS.mmm format, updating every 10ms with color output.
|
in HH:MM:SS.mmm format, updating every 10ms with color output.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Documentation (Markdown)
|
||||||
|
|
||||||
|
- Wrap normal text and lists at **max 80 columns** (for readability in
|
||||||
|
terminals and editors).
|
||||||
|
- **Exceptions**: Tables and code blocks (```` ``` ````) can exceed 80
|
||||||
|
columns when formatting requires it (e.g. trees, alignment).
|
||||||
|
- Use standard Markdown: `**bold**`, `` `inline code` ``, `##` headings,
|
||||||
|
`-` or numbered lists, fenced code blocks with language hints
|
||||||
|
(```` ```cpp ````, ```` ```sh ````).
|
||||||
|
- Keep examples concise, up-to-date, and self-documenting.
|
||||||
|
- This file (`AGENTS.md`) follows its own rules.
|
||||||
|
|
||||||
## Source Layout
|
## Source Layout
|
||||||
|
|
||||||
```
|
```text
|
||||||
cuber/
|
cuber/
|
||||||
CMakeLists.txt # Build configuration
|
CMakeLists.txt # Build configuration
|
||||||
cuber.cpp # Entry point
|
cuber.cpp # Entry point
|
||||||
|
|||||||
@@ -48,4 +48,112 @@ Q key Quit
|
|||||||
|
|
||||||
- **cube** — spinning colored cube with per-face colors
|
- **cube** — spinning colored cube with per-face colors
|
||||||
- **sphere** — cube-to-sphere mapped mesh with per-face colors and
|
- **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