167 lines
4.9 KiB
Markdown
167 lines
4.9 KiB
Markdown
# 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
|
|
|
|
1. **Automatic Clipping**: Children rendered outside parent bounds should be clipped
|
|
2. **Off-screen Rendering**: Enable post-processing effects and complex compositing
|
|
3. **Performance**: Cache static content, only re-render when changed
|
|
4. **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:
|
|
|
|
```cpp
|
|
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:
|
|
1. **UIFrame with clipping enabled** (new property: `clip_children = true`)
|
|
2. **UIDrawables with effects** (future: shaders, blend modes)
|
|
3. **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:
|
|
1. **Fixed Size**: Set at creation (current UIGrid approach)
|
|
2. **Dynamic Size**: Match bounds, recreate on resize
|
|
3. **Pooled Sizes**: Use standard sizes from pool
|
|
|
|
We'll use **Dynamic Size** with lazy creation.
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Base Infrastructure (This PR)
|
|
1. Add RenderTexture members to UIDrawable
|
|
2. Add `enableRenderTexture()` method
|
|
3. Implement dirty flag system
|
|
4. Add `clip_children` property to UIFrame
|
|
|
|
### Phase 2: UIFrame Implementation
|
|
1. Update UIFrame::render() to use RenderTexture when clipping
|
|
2. Test with nested frames
|
|
3. Verify clipping works correctly
|
|
|
|
### Phase 3: Performance Optimization
|
|
1. Implement texture pooling
|
|
2. Add dirty flag propagation
|
|
3. Profile and optimize
|
|
|
|
### Phase 4: Extended Features
|
|
1. Blur/glow effects using RenderTexture
|
|
2. Viewport-based rendering (#8)
|
|
3. Screenshot improvements
|
|
|
|
## API Changes
|
|
|
|
### Python API:
|
|
```python
|
|
# 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:
|
|
```cpp
|
|
// Enable RenderTexture
|
|
frame->enableRenderTexture(width, height);
|
|
frame->setClipChildren(true);
|
|
|
|
// Mark dirty
|
|
frame->markDirty();
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
1. **Memory**: Each RenderTexture uses GPU memory (width * height * 4 bytes)
|
|
2. **Creation Cost**: Creating RenderTextures is expensive, use pooling
|
|
3. **Clear Cost**: Clearing large RenderTextures each frame is costly
|
|
4. **Bandwidth**: Drawing to RenderTexture then to screen doubles bandwidth
|
|
|
|
## Migration Strategy
|
|
|
|
1. All existing code continues to work (direct rendering by default)
|
|
2. Gradually enable RenderTexture for specific use cases
|
|
3. Profile before/after to ensure performance gains
|
|
4. 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
|
|
|
|
1. ✓ Frames can clip children to bounds
|
|
2. ✓ No performance regression for direct rendering
|
|
3. ✓ Scene transitions continue to work
|
|
4. ✓ Memory usage is reasonable
|
|
5. ✓ API is intuitive and documented
|
|
|
|
## Future Extensions
|
|
|
|
1. **Shader Support** (#106): RenderTextures enable post-processing shaders
|
|
2. **Particle Systems** (#107): Render particles to texture for effects
|
|
3. **Caching**: Static UI elements cached in RenderTextures
|
|
4. **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. |