IRenderContext API Reference
Overview
IRenderContext is the abstract interface through which all rendering operations and resource queries are performed. It defines the contract between the ECS systems and the graphics backend, ensuring complete decoupling from SFML or any specific graphics library.
The IRenderContext is located in the engine's graphics module.
Inheritance: All backends (e.g., SFMLRenderContext) inherit from this pure abstract class.
Interface Definition
class IRenderContext {
public:
virtual ~IRenderContext() = default;
// === Drawing Operations ===
virtual void DrawSprite(const DrawSpriteParams& params) = 0;
virtual void DrawText(const DrawTextParams& params) = 0;
virtual void DrawRectangle(const DrawRectangleParams& params) = 0;
virtual void DrawVertexArray(const VertexArrayParams& params) = 0;
// === Shader Operations ===
virtual void DrawableShader(const DrawableShaderParams& params) = 0;
// === Resource Queries ===
virtual sf::Vector2f GetTextureSize(const std::string& texture_key) = 0;
virtual sf::FloatRect GetTextBounds(const std::string& font_key,
const std::string& text,
unsigned int char_size) = 0;
virtual sf::Vector2i GetGridFrameSize(const std::string& texture_key,
int grid_cols,
int frame_width) = 0;
// === Display ===
virtual void Display() = 0;
virtual void Clear(const sf::Color& color) = 0;
};
Draw Operations
DrawSprite
Renders a textured rectangle to the screen.
Parameters:
struct DrawSpriteParams {
std::string texture_key; // Resource ID (e.g., "player")
sf::Vector2f position; // World position (top-left)
sf::Vector2f origin; // Local offset from position
sf::Vector2f scale; // X, Y scaling
float rotation; // Degrees (CCW)
sf::IntRect source_rect; // Texture region (for atlases/frames)
sf::Color color; // Tint (default: white, fully opaque)
};
Contract:
texture_keymust exist in the backend's cache. If not, backend may throw or return silently (see backend docs).positionis in game world coordinates; backend handles camera/view transformation.originis the offset from position that becomes the pivot for rotation and scaling.source_rectallows drawing a sub-region of the texture; use{0, 0, -1, -1}for full texture.
Example (from DrawableSystem):
DrawSpriteParams params{
.texture_key = drawable.texture_key_,
.position = transform.position_,
.origin = drawable.origin_,
.scale = drawable.scale_,
.rotation = drawable.rotation_,
.source_rect = frame_rect, // Determined by AnimationFrame
.color = sf::Color::White
};
render_context->DrawSprite(params);
DrawText
Renders text to the screen.
Parameters:
struct DrawTextParams {
std::string font_key; // Resource ID (e.g., "default")
std::string text; // String to render
sf::Vector2f position; // World position
sf::Vector2f origin; // Local offset (usually text bounds-based)
unsigned int character_size; // Font size in pixels
sf::Color color; // Text color
float rotation; // Degrees (CCW)
sf::Vector2f scale; // X, Y scaling
};
Contract:
font_keymust exist in the backend's cache.positionis the anchor point;originoffsets from it.character_sizeis the font size in pixels.- To center text, caller computes
originas half ofGetTextBounds(...).size.
Example (from DrawTextSystem):
auto bounds = render_context->GetTextBounds(
draw_text.font_key_, draw_text.text_, draw_text.character_size_);
sf::Vector2f center_offset = bounds.size / 2.0f;
DrawTextParams params{
.font_key = draw_text.font_key_,
.text = draw_text.text_,
.position = transform.position_,
.origin = center_offset,
.character_size = draw_text.character_size_,
.color = draw_text.color_,
.rotation = draw_text.rotation_,
.scale = draw_text.scale_
};
render_context->DrawText(params);
DrawRectangle
Renders a filled or outlined rectangle.
Parameters:
struct DrawRectangleParams {
sf::Vector2f position; // Top-left corner
sf::Vector2f size; // Width and height
sf::Vector2f origin; // Local offset
sf::Vector2f scale; // X, Y scaling
float rotation; // Degrees (CCW)
sf::Color fill_color; // Interior color (or transparent)
sf::Color outline_color; // Border color (or transparent)
float outline_thickness; // Outline width in pixels
};
Contract:
- If
fill_colorhas alpha 0 andoutline_thickness> 0, only the border is drawn. - If
outline_thicknessis 0, no border is drawn. - Origin and scale work the same as sprites: offset and pivot for rotation.
DrawVertexArray
Renders a custom geometry defined by vertices and indices.
Parameters:
struct VertexArrayParams {
std::vector<sf::Vertex> vertices; // Position, color, texture coords
std::vector<unsigned int> indices; // Triangulation (optional)
std::string texture_key; // Resource ID (or empty for untextured)
std::string shader_key; // Shader to apply (or empty)
};
Contract:
- Vertices should be in world space; backend handles view transformation.
- If
indicesis empty, vertices are rendered as-is (e.g., points, lines, triangle strip). - If
indicesis non-empty, vertices are indexed in triangles (every 3 indices = 1 triangle). - If
texture_keyis empty, rendering is untextured (uses vertex colors). - If
shader_keyis non-empty, the shader is applied during rendering.
Typical Use Case (Particles):
VertexArrayParams params{
.vertices = particle_quads, // 4 vertices per quad
.indices = indices, // Tri-strip pattern: 0,1,2, 1,2,3, 4,5,6, ...
.texture_key = "particles",
.shader_key = "" // Use default shader
};
render_context->DrawVertexArray(params);
Shader Operations
DrawableShader
Applies a shader effect to a drawable entity.
Parameters:
struct DrawableShaderParams {
std::string shader_key; // Resource ID (e.g., "charged_glow")
std::string texture_key; // Texture to sample
sf::Vector2f position; // Entity position
sf::Vector2f scale; // Entity scale
int frame; // Current animation frame (for grid/strip)
float elapsed_time; // Animation progress (seconds)
};
Contract:
shader_keymust exist in the backend's shader cache.- The shader receives built-in uniforms:
u_time,u_texture, position and scale info. - Custom uniforms can be defined per-shader in the backend configuration.
Example (from charged projectile system):
if (!drawable.shader_key_.empty()) {
DrawableShaderParams shader_params{
.shader_key = drawable.shader_key_,
.texture_key = drawable.texture_key_,
.position = transform.position_,
.scale = drawable.scale_,
.frame = drawable.frame_,
.elapsed_time = animation.elapsed_time_
};
render_context->DrawableShader(shader_params);
}
Resource Queries
GetTextureSize
Returns the dimensions of a loaded texture.
Signature:
sf::Vector2f GetTextureSize(const std::string& texture_key);
Returns: {width, height} in pixels. Throws or logs error if texture not found.
Use Case: Determining sprite bounds and setting up animation frame calculations.
Example:
auto size = render_context->GetTextureSize("player");
drawable.origin_ = size / 2.0f; // Center sprite origin
GetTextBounds
Returns the bounding rectangle of rendered text.
Signature:
sf::FloatRect GetTextBounds(const std::string& font_key,
const std::string& text,
unsigned int char_size);
Returns: {left, top, width, height} — the bounds of the rendered text in local coordinates (not world space).
Use Case: Centering text, calculating UI layout dimensions.
Example:
auto bounds = render_context->GetTextBounds("default", "Score: 1000", 32);
// bounds.size = {width, height} of the text
sf::Vector2f center = bounds.size / 2.0f;
draw_text.origin_ = center; // Center text on its position
GetGridFrameSize
Returns the size of a single frame in a grid-based texture atlas.
Signature:
sf::Vector2i GetGridFrameSize(const std::string& texture_key,
int grid_cols,
int frame_width);
Parameters:
texture_key: Resource IDgrid_cols: Number of columns in the gridframe_width: Width of one frame in pixels
Returns: {frame_width, frame_height} — calculated from grid layout.
Use Case: Animation systems that use grid-based atlases (e.g., 4×8 sprites on a single texture).
Display and Lifecycle
Clear
Clears the screen to a background color.
Signature:
void Clear(const sf::Color& color);
Contract: Called once per frame before any draws. Typically sf::Color::Black or sf::Color(20, 20, 30).
Display
Presents the rendered frame to the screen.
Signature:
void Display();
Contract: Called once per frame after all draws. Flips the back buffer to the front buffer (double buffering).
Error Handling
The interface does not mandate specific error behavior. Backends may:
- Throw exceptions for missing resources
- Log warnings and continue
- Return default/zero values
Recommendation: The SFML backend logs warnings for missing resources and continues gracefully. Systems should not assume exceptions and should validate resource keys before rendering.
Extension Points
Adding New Draw Operations
To support a new primitive (e.g., DrawCircle):
- Add a new
Draw*Paramsstruct andDraw*method toIRenderContext. - Implement in each backend (e.g.,
SFMLRenderContext). - Update systems to use the new operation.
Backwards Compatibility: Existing systems continue to compile and work unchanged.
Custom Shader Uniforms
Backends can extend shader behavior by:
- Defining custom uniform sets in shader asset files
- Populating them in
DrawableShaderbased on entity data - No changes required to the interface; all happens within the backend