- Comprehensive design for Issue #6 implementation - Opt-in architecture to maintain backward compatibility - Phased implementation plan with clear milestones - Performance considerations and risk mitigation - API design for clipping and future effects Also includes Grid background color test
4.9 KiB
4.9 KiB
RenderTexture Overhaul Design Document
Overview
This document outlines the design for implementing RenderTexture support across all UIDrawable classes in McRogueFace. This is Issue #6 and represents a major architectural change to the rendering system.
Goals
- Automatic Clipping: Children rendered outside parent bounds should be clipped
- Off-screen Rendering: Enable post-processing effects and complex compositing
- Performance: Cache static content, only re-render when changed
- Backward Compatibility: Existing code should continue to work
Current State
Classes Already Using RenderTexture:
- UIGrid: Uses a 1920x1080 RenderTexture for compositing grid view
- SceneTransition: Uses two 1024x768 RenderTextures for transitions
- HeadlessRenderer: Uses RenderTexture for headless mode
Classes Using Direct Rendering:
- UIFrame: Renders box and children directly
- UICaption: Renders text directly
- UISprite: Renders sprite directly
Design Decisions
1. Opt-in Architecture
Not all UIDrawables need RenderTextures. We'll use an opt-in approach:
class UIDrawable {
protected:
// RenderTexture support (opt-in)
std::unique_ptr<sf::RenderTexture> render_texture;
sf::Sprite render_sprite;
bool use_render_texture = false;
bool render_dirty = true;
// Enable RenderTexture for this drawable
void enableRenderTexture(unsigned int width, unsigned int height);
void updateRenderTexture();
};
2. When to Use RenderTexture
RenderTextures will be enabled for:
- UIFrame with clipping enabled (new property:
clip_children = true) - UIDrawables with effects (future: shaders, blend modes)
- Complex composites (many children that rarely change)
3. Render Flow
Standard Flow:
render() → render directly to target
RenderTexture Flow:
render() → if dirty → clear RT → render to RT → dirty = false
→ draw RT sprite to target
4. Dirty Flag Management
Mark as dirty when:
- Properties change (position, size, color, etc.)
- Children added/removed
- Child marked as dirty (propagate up)
- Animation frame
5. Size Management
RenderTexture size options:
- Fixed Size: Set at creation (current UIGrid approach)
- Dynamic Size: Match bounds, recreate on resize
- Pooled Sizes: Use standard sizes from pool
We'll use Dynamic Size with lazy creation.
Implementation Plan
Phase 1: Base Infrastructure (This PR)
- Add RenderTexture members to UIDrawable
- Add
enableRenderTexture()method - Implement dirty flag system
- Add
clip_childrenproperty to UIFrame
Phase 2: UIFrame Implementation
- Update UIFrame::render() to use RenderTexture when clipping
- Test with nested frames
- Verify clipping works correctly
Phase 3: Performance Optimization
- Implement texture pooling
- Add dirty flag propagation
- Profile and optimize
Phase 4: Extended Features
- Blur/glow effects using RenderTexture
- Viewport-based rendering (#8)
- Screenshot improvements
API Changes
Python API:
# Enable clipping on frames
frame.clip_children = True # New property
# Future: effects
frame.blur_amount = 5.0
sprite.glow_color = Color(255, 200, 100)
C++ API:
// Enable RenderTexture
frame->enableRenderTexture(width, height);
frame->setClipChildren(true);
// Mark dirty
frame->markDirty();
Performance Considerations
- Memory: Each RenderTexture uses GPU memory (width * height * 4 bytes)
- Creation Cost: Creating RenderTextures is expensive, use pooling
- Clear Cost: Clearing large RenderTextures each frame is costly
- Bandwidth: Drawing to RenderTexture then to screen doubles bandwidth
Migration Strategy
- All existing code continues to work (direct rendering by default)
- Gradually enable RenderTexture for specific use cases
- Profile before/after to ensure performance gains
- Document best practices
Risks and Mitigation
| Risk | Mitigation |
|---|---|
| Performance regression | Opt-in design, profile extensively |
| Memory usage increase | Texture pooling, size limits |
| Complexity increase | Clear documentation, examples |
| Integration issues | Extensive testing with SceneTransition |
Success Criteria
- ✓ Frames can clip children to bounds
- ✓ No performance regression for direct rendering
- ✓ Scene transitions continue to work
- ✓ Memory usage is reasonable
- ✓ API is intuitive and documented
Future Extensions
- Shader Support (#106): RenderTextures enable post-processing shaders
- Particle Systems (#107): Render particles to texture for effects
- Caching: Static UI elements cached in RenderTextures
- Resolution Independence: RenderTextures for DPI scaling
Conclusion
This design provides a foundation for professional rendering capabilities while maintaining backward compatibility and performance. The opt-in approach allows gradual adoption and testing.