Skip to main content

forge-debug-lines

Add immediate-mode debug line drawing to an SDL GPU project. Render colored lines, grids, axes, circles, and wireframe boxes with world-space (depth-tested) and overlay (always-on-top) modes. Use when someone needs diagnostic visualization, debug drawing, or wireframe rendering in SDL3 GPU.

Zur Installation springen

Quellinformationen

Repository
Nebulavenus/forge-gpu
Letzte Quellaktivität
1. März 2026 um 21:31
Erkannte Sprache von SKILL.md
Englisch
Sterne
38
Forks
7

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
forge-debug-lines
description
Add immediate-mode debug line drawing to an SDL GPU project. Render colored lines, grids, axes, circles, and wireframe boxes with world-space (depth-tested) and overlay (always-on-top) modes. Use when someone needs diagnostic visualization, debug drawing, or wireframe rendering in SDL3 GPU.
# Debug Lines — Immediate-Mode Debug Drawing This skill adds a lightweight debug drawing system to any SDL GPU project. It uses `SDL_GPU_PRIMITIVETYPE_LINELIST` with a dynamic vertex buffer updated every frame via the immediate-mode pattern: reset, accumulate, upload, draw. ## When to use - Visualizing positions, bounds, directions, or other spatial data - Drawing coordinate-axis gizmos (RGB = XYZ) - Rendering wireframe bounding boxes for physics or collision debugging - Drawing circles to show radii, influence zones, or trigger areas - Adding an always-visible overlay for diagnostic indicators - Any per-frame debug visualization that changes based on game state ## Key API calls (ordered) 1. `SDL_CreateGPUGraphicsPipeline` — create two pipelines (depth ON / depth OFF) with `SDL_GPU_PRIMITIVETYPE_LINELIST` and `SDL_GPU_CULLMODE_NONE` 2. `SDL_CreateGPUBuffer` — pre-allocate GPU vertex buffer for max vertices 3. `SDL_CreateGPUTransferBuffer` — pre-allocate upload staging buffer 4. `SDL_MapGPUTransferBuffer` / `SDL_UnmapGPUTransferBuffer` — map, copy, unmap each frame 5. `SDL_UploadToGPUBuffer` — copy pass to transfer data to GPU 6. `SDL_PushGPUVertexUniformData` — push VP matrix 7. `SDL_DrawGPUPrimitives` — draw world lines, then overlay lines with first_vertex offset ## Common mistakes - **Forgetting to reset vertex counts each frame.** The immediate-mode pattern requires `world_count = 0; overlay_count = 0;` at the start of every frame, otherwise vertices accumulate and the buffer overflows. - **Using TRIANGLELIST primitive type.** Debug lines use `LINELIST` — every pair of vertices is a separate line segment. There are no faces, no indices. - **Enabling back-face culling.** Lines have no face orientation. Always use `SDL_GPU_CULLMODE_NONE` for line pipelines. - **Creating separate GPU buffers for world and overlay.** Both can share one buffer — use `first_vertex` offset in the draw call to select the region. - **Forgetting the copy pass before drawing.** The transfer buffer upload requires `SDL_BeginGPUCopyPass` / `SDL_UploadToGPUBuffer` / `SDL_EndGPUCopyPass` / `SDL_SubmitGPUCommandBuffer` before the render pass. ## Code template ### Vertex format ```c typedef struct DebugVertex { vec3 position; /* 12 bytes — world-space position */ vec4 color; /* 16 bytes — RGBA color */ } DebugVertex; /* 28 bytes total */ #define DEBUG_VERTEX_PITCH 28 #define MAX_DEBUG_VERTICES 65536 ``` ### Pipeline creation ```c /* Vertex layout: position (float3) + color (float4) */ SDL_GPUVertexAttribute attrs[2]; SDL_zero(attrs); attrs[0].location = 0; attrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3; attrs[0].offset = offsetof(DebugVertex, position); attrs[1].location = 1; attrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4; attrs[1].offset = offsetof(DebugVertex, color); SDL_GPUGraphicsPipelineCreateInfo pipe; SDL_zero(pipe); pipe.primitive_type = SDL_GPU_PRIMITIVETYPE_LINELIST; pipe.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE; /* World-space pipeline: depth test ON */ pipe.depth_stencil_state.enable_depth_test = true; pipe.depth_stencil_state.enable_depth_write = true; pipe.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; line_pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipe); /* Overlay pipeline: depth test OFF */ pipe.depth_stencil_state.enable_depth_test = false; pipe.depth_stencil_state.enable_depth_write = false; overlay_pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipe); ``` ### Per-frame upload and draw ```c /* 1. Reset counts */ state->world_count = 0; state->overlay_count = 0; /* 2. Accumulate debug shapes */ debug_grid(state, 20, 1.0f, gray); debug_axes(state, origin, 2.0f, true); /* overlay */ debug_box_wireframe(state, min, max, orange, false); /* 3. Upload (map → copy → unmap → copy pass) */ void *mapped = SDL_MapGPUTransferBuffer(device, transfer_buf, true); SDL_memcpy(mapped, vertices, total * sizeof(DebugVertex)); SDL_UnmapGPUTransferBuffer(device, transfer_buf); /* ... copy pass to GPU buffer ... */ /* 4. Draw */ if (world_count > 0) { SDL_BindGPUGraphicsPipeline(pass, line_pipeline); SDL_DrawGPUPrimitives(pass, world_count, 1, 0, 0); } if (overlay_count > 0) { SDL_BindGPUGraphicsPipeline(pass, overlay_pipeline); SDL_DrawGPUPrimitives(pass, overlay_count, 1, world_count, 0); } ``` ### Debug shape helpers ```c /* Single line segment (2 vertices) */ static void debug_line(state, vec3 start, vec3 end, vec4 color, bool overlay); /* Ground grid on XZ plane */ static void debug_grid(state, int half_size, float spacing, vec4 color); /* Coordinate axes: red=X, green=Y, blue=Z (6 vertices) */ static void debug_axes(state, vec3 origin, float size, bool overlay); /* Circle from line segments (2 × segments vertices) */ static void debug_circle(state, vec3 center, float radius, vec3 normal, vec4 color, int segments, bool overlay); /* Wireframe AABB (24 vertices = 12 edges) */ static void debug_box_wireframe(state, vec3 min_pt, vec3 max_pt, vec4 color, bool overlay); ``` ### Shader (HLSL) ```hlsl /* Vertex shader — transform position, pass through color */ cbuffer DebugUniforms : register(b0, space1) { column_major float4x4 view_projection; }; struct VSInput { float3 position : TEXCOORD0; float4 color : TEXCOORD1; }; struct VSOutput { float4 clip_pos : SV_Position; float4 color : TEXCOORD0; }; VSOutput main(VSInput input) { VSOutput output; output.clip_pos = mul(view_projection, float4(input.position, 1.0)); output.color = input.color; return output; } /* Fragment shader — pass-through color */ float4 main(PSInput input) : SV_Target { return input.color; } ``` ## Lesson reference See [Lesson 19 — Debug Lines](../../../lessons/gpu/19-debug-lines/) for the full implementation with detailed comments explaining every step.
Auf GitHub ansehen