All rendering in Quake 3 stores data in an array (vertex position, colors, etc) [see shaderCommands_t structure] and draws it using a shader. 2D and 3D graphics share the same main rendering functions. Modern games called Q3’s “shaders” materials to avoid confusing with GPU shaders.
Introduction to Q3 shaders: http://fd.fabiensanglard.net/quake3/Q3%20Shaders.pdf
2D graphic drawing.
- Register shader using trap_R_RegisterShader() which finds explicit shader definition or uses implicit shader and loads necessary image files.
- Add render command using trap_R_DrawStretchPic() which calls RE_StretchPic() in the engine.
- Later render commands are executed by RB_ExecuteRenderCommands().
- RB_StretchPic() sets up the shader / vertex information.
- Later when attempting to draw a different shader or finished drawing for the scene, RB_EndSurface() is called which preforms the shader drawing. Typically using RB_StageIteratorGeneric().
code/renderergl1/tr_shader.c has the default implicit shader information for LIGHTMAP_2D (“2D graphics”) and loading shader files. RB_StageIteratorGeneric() and basically the entirety of code/renderergl1/tr_shade.c and code/renderergl1/tr_shade_calc.c does the actually drawing.