- Add markDirty() calls to setProperty() methods in: - UISprite: position, scale, sprite_index changes - UICaption: position, font_size, colors, text changes - UIGrid: position, size, center, zoom, color changes - UILine: thickness, position, endpoints, color changes - UICircle: radius, position, colors changes - UIArc: radius, angles, position, color changes - UIEntity: position changes propagate to parent grid - Expand getMetrics() Python API to include detailed timing breakdown: - grid_render_time, entity_render_time, fov_overlay_time - python_time, animation_time - grid_cells_rendered, entities_rendered, total_entities - Add comprehensive benchmark suite (tests/benchmarks/benchmark_suite.py): - 6 scenarios: empty, static UI, animated UI, mixed, deep hierarchy, grid stress - Automated metrics collection and performance assessment - Timing breakdown percentages This enables proper dirty flag propagation for the upcoming texture caching system (#144) and provides infrastructure for performance benchmarking (#104). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6c496b8732
commit
219a559c35
9 changed files with 442 additions and 3 deletions
|
|
@ -1233,17 +1233,29 @@ PyObject* McRFPy_API::_getMetrics(PyObject* self, PyObject* args) {
|
|||
// Create a dictionary with metrics
|
||||
PyObject* dict = PyDict_New();
|
||||
if (!dict) return NULL;
|
||||
|
||||
|
||||
// Add frame time metrics
|
||||
PyDict_SetItemString(dict, "frame_time", PyFloat_FromDouble(game->metrics.frameTime));
|
||||
PyDict_SetItemString(dict, "avg_frame_time", PyFloat_FromDouble(game->metrics.avgFrameTime));
|
||||
PyDict_SetItemString(dict, "fps", PyLong_FromLong(game->metrics.fps));
|
||||
|
||||
|
||||
// Add draw call metrics
|
||||
PyDict_SetItemString(dict, "draw_calls", PyLong_FromLong(game->metrics.drawCalls));
|
||||
PyDict_SetItemString(dict, "ui_elements", PyLong_FromLong(game->metrics.uiElements));
|
||||
PyDict_SetItemString(dict, "visible_elements", PyLong_FromLong(game->metrics.visibleElements));
|
||||
|
||||
|
||||
// #144 - Add detailed timing breakdown (in milliseconds)
|
||||
PyDict_SetItemString(dict, "grid_render_time", PyFloat_FromDouble(game->metrics.gridRenderTime));
|
||||
PyDict_SetItemString(dict, "entity_render_time", PyFloat_FromDouble(game->metrics.entityRenderTime));
|
||||
PyDict_SetItemString(dict, "fov_overlay_time", PyFloat_FromDouble(game->metrics.fovOverlayTime));
|
||||
PyDict_SetItemString(dict, "python_time", PyFloat_FromDouble(game->metrics.pythonScriptTime));
|
||||
PyDict_SetItemString(dict, "animation_time", PyFloat_FromDouble(game->metrics.animationTime));
|
||||
|
||||
// #144 - Add grid-specific metrics
|
||||
PyDict_SetItemString(dict, "grid_cells_rendered", PyLong_FromLong(game->metrics.gridCellsRendered));
|
||||
PyDict_SetItemString(dict, "entities_rendered", PyLong_FromLong(game->metrics.entitiesRendered));
|
||||
PyDict_SetItemString(dict, "total_entities", PyLong_FromLong(game->metrics.totalEntities));
|
||||
|
||||
// Add general metrics
|
||||
PyDict_SetItemString(dict, "current_frame", PyLong_FromLong(game->getFrame()));
|
||||
PyDict_SetItemString(dict, "runtime", PyFloat_FromDouble(game->runtime.getElapsedTime().asSeconds()));
|
||||
|
|
|
|||
|
|
@ -206,30 +206,36 @@ void UIArc::resize(float w, float h) {
|
|||
bool UIArc::setProperty(const std::string& name, float value) {
|
||||
if (name == "radius") {
|
||||
setRadius(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "start_angle") {
|
||||
setStartAngle(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "end_angle") {
|
||||
setEndAngle(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "thickness") {
|
||||
setThickness(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "x") {
|
||||
center.x = value;
|
||||
position = center;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
center.y = value;
|
||||
position = center;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -238,6 +244,7 @@ bool UIArc::setProperty(const std::string& name, float value) {
|
|||
bool UIArc::setProperty(const std::string& name, const sf::Color& value) {
|
||||
if (name == "color") {
|
||||
setColor(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -246,6 +253,7 @@ bool UIArc::setProperty(const std::string& name, const sf::Color& value) {
|
|||
bool UIArc::setProperty(const std::string& name, const sf::Vector2f& value) {
|
||||
if (name == "center") {
|
||||
setCenter(value);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -471,71 +471,84 @@ bool UICaption::setProperty(const std::string& name, float value) {
|
|||
if (name == "x") {
|
||||
position.x = value;
|
||||
text.setPosition(position); // Keep text in sync
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
position.y = value;
|
||||
text.setPosition(position); // Keep text in sync
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "font_size" || name == "size") { // Support both for backward compatibility
|
||||
text.setCharacterSize(static_cast<unsigned int>(value));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline") {
|
||||
text.setOutlineThickness(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.r") {
|
||||
auto color = text.getFillColor();
|
||||
color.r = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setFillColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.g") {
|
||||
auto color = text.getFillColor();
|
||||
color.g = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setFillColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.b") {
|
||||
auto color = text.getFillColor();
|
||||
color.b = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setFillColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.a") {
|
||||
auto color = text.getFillColor();
|
||||
color.a = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setFillColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline_color.r") {
|
||||
auto color = text.getOutlineColor();
|
||||
color.r = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setOutlineColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline_color.g") {
|
||||
auto color = text.getOutlineColor();
|
||||
color.g = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setOutlineColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline_color.b") {
|
||||
auto color = text.getOutlineColor();
|
||||
color.b = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setOutlineColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline_color.a") {
|
||||
auto color = text.getOutlineColor();
|
||||
color.a = static_cast<sf::Uint8>(std::clamp(value, 0.0f, 255.0f));
|
||||
text.setOutlineColor(color);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "z_index") {
|
||||
z_index = static_cast<int>(value);
|
||||
markDirty(); // #144 - Z-order change affects parent
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -544,10 +557,12 @@ bool UICaption::setProperty(const std::string& name, float value) {
|
|||
bool UICaption::setProperty(const std::string& name, const sf::Color& value) {
|
||||
if (name == "fill_color") {
|
||||
text.setFillColor(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "outline_color") {
|
||||
text.setOutlineColor(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -556,6 +571,7 @@ bool UICaption::setProperty(const std::string& name, const sf::Color& value) {
|
|||
bool UICaption::setProperty(const std::string& name, const std::string& value) {
|
||||
if (name == "text") {
|
||||
text.setString(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -172,15 +172,19 @@ void UICircle::resize(float w, float h) {
|
|||
bool UICircle::setProperty(const std::string& name, float value) {
|
||||
if (name == "radius") {
|
||||
setRadius(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
} else if (name == "outline") {
|
||||
setOutline(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
} else if (name == "x") {
|
||||
position.x = value;
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
} else if (name == "y") {
|
||||
position.y = value;
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -189,9 +193,11 @@ bool UICircle::setProperty(const std::string& name, float value) {
|
|||
bool UICircle::setProperty(const std::string& name, const sf::Color& value) {
|
||||
if (name == "fill_color") {
|
||||
setFillColor(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
} else if (name == "outline_color") {
|
||||
setOutlineColor(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -200,6 +206,7 @@ bool UICircle::setProperty(const std::string& name, const sf::Color& value) {
|
|||
bool UICircle::setProperty(const std::string& name, const sf::Vector2f& value) {
|
||||
if (name == "center" || name == "position") {
|
||||
position = value;
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -674,15 +674,18 @@ bool UIEntity::setProperty(const std::string& name, float value) {
|
|||
if (name == "x") {
|
||||
position.x = value;
|
||||
// Don't update sprite position here - UIGrid::render() handles the pixel positioning
|
||||
if (grid) grid->markDirty(); // #144 - Propagate to parent grid for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
position.y = value;
|
||||
// Don't update sprite position here - UIGrid::render() handles the pixel positioning
|
||||
if (grid) grid->markDirty(); // #144 - Propagate to parent grid for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "sprite_scale") {
|
||||
sprite.setScale(sf::Vector2f(value, value));
|
||||
if (grid) grid->markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -691,6 +694,7 @@ bool UIEntity::setProperty(const std::string& name, float value) {
|
|||
bool UIEntity::setProperty(const std::string& name, int value) {
|
||||
if (name == "sprite_index" || name == "sprite_number") {
|
||||
sprite.setSpriteIndex(value);
|
||||
if (grid) grid->markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2725,54 +2725,66 @@ bool UIGrid::setProperty(const std::string& name, float value) {
|
|||
position.x = value;
|
||||
box.setPosition(position);
|
||||
output.setPosition(position);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
position.y = value;
|
||||
box.setPosition(position);
|
||||
output.setPosition(position);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "w" || name == "width") {
|
||||
box.setSize(sf::Vector2f(value, box.getSize().y));
|
||||
output.setTextureRect(sf::IntRect(0, 0, box.getSize().x, box.getSize().y));
|
||||
markDirty(); // #144 - Size change
|
||||
return true;
|
||||
}
|
||||
else if (name == "h" || name == "height") {
|
||||
box.setSize(sf::Vector2f(box.getSize().x, value));
|
||||
output.setTextureRect(sf::IntRect(0, 0, box.getSize().x, box.getSize().y));
|
||||
markDirty(); // #144 - Size change
|
||||
return true;
|
||||
}
|
||||
else if (name == "center_x") {
|
||||
center_x = value;
|
||||
markDirty(); // #144 - View change affects content
|
||||
return true;
|
||||
}
|
||||
else if (name == "center_y") {
|
||||
center_y = value;
|
||||
markDirty(); // #144 - View change affects content
|
||||
return true;
|
||||
}
|
||||
else if (name == "zoom") {
|
||||
zoom = value;
|
||||
markDirty(); // #144 - View change affects content
|
||||
return true;
|
||||
}
|
||||
else if (name == "z_index") {
|
||||
z_index = static_cast<int>(value);
|
||||
markDirty(); // #144 - Z-order change affects parent
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.r") {
|
||||
fill_color.r = static_cast<uint8_t>(std::max(0.0f, std::min(255.0f, value)));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.g") {
|
||||
fill_color.g = static_cast<uint8_t>(std::max(0.0f, std::min(255.0f, value)));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.b") {
|
||||
fill_color.b = static_cast<uint8_t>(std::max(0.0f, std::min(255.0f, value)));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "fill_color.a") {
|
||||
fill_color.a = static_cast<uint8_t>(std::max(0.0f, std::min(255.0f, value)));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -2783,16 +2795,19 @@ bool UIGrid::setProperty(const std::string& name, const sf::Vector2f& value) {
|
|||
position = value;
|
||||
box.setPosition(position);
|
||||
output.setPosition(position);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "size") {
|
||||
box.setSize(value);
|
||||
output.setTextureRect(sf::IntRect(0, 0, box.getSize().x, box.getSize().y));
|
||||
markDirty(); // #144 - Size change
|
||||
return true;
|
||||
}
|
||||
else if (name == "center") {
|
||||
center_x = value.x;
|
||||
center_y = value.y;
|
||||
markDirty(); // #144 - View change affects content
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -207,36 +207,43 @@ bool UILine::setProperty(const std::string& name, float value) {
|
|||
if (name == "thickness") {
|
||||
thickness = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "x") {
|
||||
float dx = value - position.x;
|
||||
move(dx, 0);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
float dy = value - position.y;
|
||||
move(0, dy);
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "start_x") {
|
||||
start_pos.x = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "start_y") {
|
||||
start_pos.y = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "end_x") {
|
||||
end_pos.x = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "end_y") {
|
||||
end_pos.y = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -246,6 +253,7 @@ bool UILine::setProperty(const std::string& name, const sf::Color& value) {
|
|||
if (name == "color") {
|
||||
color = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -255,11 +263,13 @@ bool UILine::setProperty(const std::string& name, const sf::Vector2f& value) {
|
|||
if (name == "start") {
|
||||
start_pos = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "end") {
|
||||
end_pos = value;
|
||||
vertices_dirty = true;
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -499,27 +499,33 @@ bool UISprite::setProperty(const std::string& name, float value) {
|
|||
if (name == "x") {
|
||||
position.x = value;
|
||||
sprite.setPosition(position); // Keep sprite in sync
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "y") {
|
||||
position.y = value;
|
||||
sprite.setPosition(position); // Keep sprite in sync
|
||||
markDirty(); // #144 - Propagate to parent for texture caching
|
||||
return true;
|
||||
}
|
||||
else if (name == "scale") {
|
||||
sprite.setScale(sf::Vector2f(value, value));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "scale_x") {
|
||||
sprite.setScale(sf::Vector2f(value, sprite.getScale().y));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "scale_y") {
|
||||
sprite.setScale(sf::Vector2f(sprite.getScale().x, value));
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "z_index") {
|
||||
z_index = static_cast<int>(value);
|
||||
markDirty(); // #144 - Z-order change affects parent
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -528,10 +534,12 @@ bool UISprite::setProperty(const std::string& name, float value) {
|
|||
bool UISprite::setProperty(const std::string& name, int value) {
|
||||
if (name == "sprite_index" || name == "sprite_number") {
|
||||
setSpriteIndex(value);
|
||||
markDirty(); // #144 - Content change
|
||||
return true;
|
||||
}
|
||||
else if (name == "z_index") {
|
||||
z_index = value;
|
||||
markDirty(); // #144 - Z-order change affects parent
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue