Tutorial 09 — Shaders and post-processing¶
Copyright (c) 2024-2026 Jack Waechter. MIT licensed.
Two related paths:
- Custom GLSL on the immediate 2D pass (
AP_UseShaderthenAP_FillRect). - Post stack that runs at
AP_Presentwhen enabled (AP_SetPostEnabled).
Custom fragment on a quad¶
Pass NULL for the vertex stage to keep the builtin (window-pixel positions, u_resolution).
Immediate layout:
location 0vec2 a_positionlocation 1vec4 a_colorlocation 2vec2 a_uvuniform vec2 u_resolutionuniform sampler2D u_texture(white 1×1 when untextured)
static const char *k_wave_fs =
"#version 330 core\n"
"in vec4 v_color;\n"
"in vec2 v_uv;\n"
"uniform sampler2D u_texture;\n"
"uniform float u_time;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" vec2 uv = v_uv;\n"
" uv.x += 0.04 * sin(uv.y * 24.0 + u_time * 3.0);\n"
" frag_color = v_color * texture(u_texture, uv);\n"
"}\n";
AP_Shader *wave = AP_CreateShader(NULL, k_wave_fs);
/* in the loop, after AP_Clear: */
AP_UseShader(wave);
AP_SetUniformF("u_time", (float)AP_GetTime());
AP_SetDrawColor(1.0f, 1.0f, 1.0f, 1.0f);
AP_FillRect(&(AP_FRect){0.0f, 0.0f, 1280.0f, 720.0f});
AP_UseShader(NULL);
AP_DestroyShader(wave) at shutdown. AP_SetUniformF2 / F3 / F4 cover vectors.
Load from disk with AP_CreateShaderFromFile(vs_path, fs_path).
Post stack¶
When post is on, AP_Clear captures offscreen. Effects run inside AP_Present.
AP_SetPostEnabled(true);
AP_SetPostVignette(0.45f);
AP_SetPostBloom(0.7f, 0.35f);
AP_SetPostColorGrade(1.05f, 1.08f, 0.02f);
AP_SetPostGrain(0.08f);
AP_SetGuiLayer(AP_GUI_LAYER_OVERLAY); /* UI not processed */
The setters enable their flags when the amount is > 0. You can also:
AP_EnablePostFlag(AP_POST_CHROMATIC);
AP_SetPostChromatic(0.004f);
Flags: vignette, bloom, color grade, chromatic, grain, sharpen, custom shader.
Antialiasing¶
Two independent knobs, since they cover different rendering paths:
AP_WINDOW_MSAA(window creation flag,msaa_samplesinAP_WindowConfig) — antialiases direct-to-backbuffer rendering, i.e. everything drawn while post-processing is disabled.AP_SetPostMSAA(samples)— real multisampling for the offscreen scene and GUI capture used while post-processing is enabled. Without it, the scene/GUI textures behind the post stack are single-sample and every mesh edge, rounded rect, and glyph will look jagged no matter whatAP_WINDOW_MSAAis set to.
AP_SetPostEnabled(true);
AP_SetPostMSAA(4); /* 0 disables; otherwise clamped to GL_MAX_SAMPLES */
AP_GetPostMSAA() reads back the clamped value actually in use.
Custom post shader¶
AP_SetPostShader(my_fullscreen_shader);
AP_EnablePostFlag(AP_POST_CUSTOM);
GUI overlay vs scene:
AP_SetPostIncludeGui(false); /* default: overlay after post */
Order reminder¶
AP_PumpEvents
AP_Clear /* starts post capture if enabled */
AP_Begin3D … AP_End3D
2D scene (AP_FillRect, AP_DrawTexture, …)
AP_Gui* /* overlay unless you change the layer */
AP_Present /* post, then swap */
Next¶
Build something: Breakout, Top-down walker, or Desktop tool. For a deeper dive, see Camera rigs and cinematic post.