From 319cde3c06181ba1c3619567525002926d8b4889 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 26 Jun 2013 01:12:19 +0300 Subject: [PATCH] Improve widget part caching A single mesh can now hold multiple parts if they share the same texture. --- source/button.cpp | 9 +++------ source/button.h | 2 +- source/dropdown.cpp | 22 ++++++++++++++-------- source/dropdown.h | 6 ++++-- source/entry.cpp | 19 ++++++------------- source/entry.h | 2 +- source/hslider.cpp | 9 +++------ source/hslider.h | 2 +- source/image.cpp | 10 ++-------- source/image.h | 2 +- source/label.cpp | 4 ++-- source/label.h | 2 +- source/part.cpp | 12 +++--------- source/part.h | 4 ++-- source/partcache.cpp | 34 +++++++++++++++++++++++++++++----- source/partcache.h | 19 ++++++++++++++++++- source/slider.cpp | 6 +++--- source/text.cpp | 13 +++---------- source/text.h | 6 +++--- source/toggle.cpp | 4 ++-- source/toggle.h | 2 +- source/vslider.cpp | 9 +++------ source/vslider.h | 2 +- source/widget.cpp | 30 ++++++++++++++++-------------- source/widget.h | 4 ++-- 25 files changed, 125 insertions(+), 109 deletions(-) diff --git a/source/button.cpp b/source/button.cpp index b881b3f..5582230 100644 --- a/source/button.cpp +++ b/source/button.cpp @@ -56,13 +56,12 @@ void Button::set_icon(const GL::Texture2D *i) rebuild(); } -void Button::rebuild_special(const Part &part, CachedPart &cache) +void Button::rebuild_special(const Part &part) { if(part.get_name()=="text") - text.build(part, geom, cache); + text.build(part, geom, part_cache); if(part.get_name()=="icon") { - cache.texture = icon; if(icon) { Geometry rgeom; @@ -70,9 +69,7 @@ void Button::rebuild_special(const Part &part, CachedPart &cache) rgeom.h = icon->get_height(); part.get_alignment().apply(rgeom, geom, part.get_margin()); - cache.clear_mesh(); - - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(part_cache.create_mesh(part, *icon)); bld.color(1.0f, 1.0f, 1.0f); bld.begin(GL::QUADS); bld.texcoord(0, 0); diff --git a/source/button.h b/source/button.h index 11d8bc7..e75ba9f 100644 --- a/source/button.h +++ b/source/button.h @@ -42,7 +42,7 @@ public: void set_icon(const GL::Texture2D *); private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); public: virtual void button_press(int, int, unsigned); diff --git a/source/dropdown.cpp b/source/dropdown.cpp index ee8ec55..ddf5c92 100644 --- a/source/dropdown.cpp +++ b/source/dropdown.cpp @@ -63,16 +63,19 @@ void Dropdown::autosize() rebuild(); } -void Dropdown::rebuild_special(const Part &part, CachedPart &cache) +void Dropdown::set_selected_index(int index) +{ + list.set_selected_index(index); + if(index<0) + text.set(string()); +} + +void Dropdown::rebuild_special(const Part &part) { if(part.get_name()=="text") - { - int sel = list.get_selected_index(); - if(sel>=0) - Text(*style, list.get_data().get_string(sel)).build(part, geom, cache); - else - cache.texture = 0; - } + text.build(part, geom, part_cache); + else + Widget::rebuild_special(part); } void Dropdown::render_special(const Part &part, GL::Renderer &renderer) const @@ -108,6 +111,7 @@ void Dropdown::on_geometry_change() void Dropdown::on_style_change() { + text.set_style(style); resize_list(); } @@ -156,6 +160,8 @@ void Dropdown::list_item_selected(unsigned index) signal_ungrab_pointer.emit(); } + text.set(list.get_data().get_string(index)); + signal_item_selected.emit(index); rebuild(); } diff --git a/source/dropdown.h b/source/dropdown.h index 7a0f04d..43bde10 100644 --- a/source/dropdown.h +++ b/source/dropdown.h @@ -3,6 +3,7 @@ #include #include "list.h" +#include "text.h" #include "widget.h" namespace Msp { @@ -26,6 +27,7 @@ public: private: List list; bool dropped; + Text text; public: Dropdown(); @@ -42,11 +44,11 @@ public: ListData &get_data() { return list.get_data(); } const ListData &get_data() const { return list.get_data(); } - void set_selected_index(int i) { list.set_selected_index(i); } + void set_selected_index(int); int get_selected_index() const { return list.get_selected_index(); } private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); virtual void render_special(const Part &, GL::Renderer &) const; public: diff --git a/source/entry.cpp b/source/entry.cpp index 1f77842..a635101 100644 --- a/source/entry.cpp +++ b/source/entry.cpp @@ -114,37 +114,30 @@ void Entry::set_multiline(bool m) } } -void Entry::rebuild_special(const Part &part, CachedPart &cache) +void Entry::rebuild_special(const Part &part) { if(part.get_name()=="text") - text.build(part, geom, first_row, cache); + text.build(part, geom, first_row, part_cache); else if(part.get_name()=="cursor") { const Graphic *graphic = part.get_graphic(state); - if(!text_part || !graphic) - { - cache.texture = 0; + if(!text_part || !graphic || !graphic->get_texture()) return; - } unsigned row, col; text.offset_to_coords(edit_pos, row, col); if(row=first_row+visible_rows) - { - cache.texture = 0; return; - } Geometry rgeom = text.coords_to_geometry(*text_part, geom, first_row, row, col); - cache.texture = graphic->get_texture(); - cache.clear_mesh(); - - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture())); bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0); graphic->build(part.get_geometry().w, part.get_geometry().h, bld); } + else + Widget::rebuild_special(part); } void Entry::render_special(const Part &part, GL::Renderer &renderer) const diff --git a/source/entry.h b/source/entry.h index 0bba6f0..edea4c3 100644 --- a/source/entry.h +++ b/source/entry.h @@ -54,7 +54,7 @@ public: bool is_multiline() const { return multiline; } private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); virtual void render_special(const Part &, GL::Renderer &) const; public: diff --git a/source/hslider.cpp b/source/hslider.cpp index 2a36443..837b2ba 100644 --- a/source/hslider.cpp +++ b/source/hslider.cpp @@ -28,12 +28,12 @@ void HSlider::autosize() } } -void HSlider::rebuild_special(const Part &part, CachedPart &cache) +void HSlider::rebuild_special(const Part &part) { if(part.get_name()=="slider") { const Graphic *graphic = part.get_graphic(state); - if(!graphic) + if(!graphic || !graphic->get_texture()) return; Alignment align = part.get_alignment(); @@ -43,10 +43,7 @@ void HSlider::rebuild_special(const Part &part, CachedPart &cache) Geometry pgeom = part.get_geometry(); align.apply(pgeom, geom, part.get_margin()); - cache.texture = part.get_graphic(state)->get_texture(); - cache.clear_mesh(); - - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture())); bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0); graphic->build(pgeom.w, pgeom.h, bld); } diff --git a/source/hslider.h b/source/hslider.h index 9545c22..cb02527 100644 --- a/source/hslider.h +++ b/source/hslider.h @@ -23,7 +23,7 @@ public: virtual void autosize(); private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); public: virtual void button_press(int, int, unsigned); diff --git a/source/image.cpp b/source/image.cpp index a2d4426..2735ab6 100644 --- a/source/image.cpp +++ b/source/image.cpp @@ -53,15 +53,12 @@ void Image::set_keep_aspect(bool ka) rebuild(); } -void Image::rebuild_special(const Part &part, CachedPart &cache) +void Image::rebuild_special(const Part &part) { if(part.get_name()=="image") { if(!image) - { - cache.texture = 0; return; - } const Alignment &align = part.get_alignment(); Geometry rgeom = part.get_geometry(); @@ -84,10 +81,7 @@ void Image::rebuild_special(const Part &part, CachedPart &cache) } } - cache.texture = image; - cache.clear_mesh(); - - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(part_cache.create_mesh(part, *image)); bld.color(1.0f, 1.0f, 1.0f); bld.begin(GL::QUADS); bld.texcoord(0.0, 0.0); diff --git a/source/image.h b/source/image.h index 064a6c9..234f19f 100644 --- a/source/image.h +++ b/source/image.h @@ -27,7 +27,7 @@ public: void set_keep_aspect(bool); private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); }; } // namespace GLtk diff --git a/source/label.cpp b/source/label.cpp index 21974be..f426467 100644 --- a/source/label.cpp +++ b/source/label.cpp @@ -37,10 +37,10 @@ void Label::set_text(const string &t) rebuild(); } -void Label::rebuild_special(const Part &part, CachedPart &cache) +void Label::rebuild_special(const Part &part) { if(part.get_name()=="text") - text.build(part, geom, cache); + text.build(part, geom, part_cache); } void Label::on_style_change() diff --git a/source/label.h b/source/label.h index 6cd9bcb..3e753dd 100644 --- a/source/label.h +++ b/source/label.h @@ -33,7 +33,7 @@ public: void set_text(const std::string &); private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); virtual void on_style_change(); }; diff --git a/source/part.cpp b/source/part.cpp index f0ee4b9..7c98545 100644 --- a/source/part.cpp +++ b/source/part.cpp @@ -23,20 +23,14 @@ const Graphic *Part::get_graphic(State state) const return graphic[state]; } -void Part::build(const Geometry &parent, State state, CachedPart &cache) const +void Part::build(const Geometry &parent, State state, PartCache &cache) const { - if(!graphic[state]) - { - cache.texture = 0; + if(!graphic[state] || !graphic[state]->get_texture()) return; - } - - cache.texture = graphic[state]->get_texture(); - cache.clear_mesh(); Geometry rgeom = geom; align.apply(rgeom, parent, margin); - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(cache.create_mesh(*this, *graphic[state]->get_texture())); bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0); graphic[state]->build(rgeom.w, rgeom.h, bld); } diff --git a/source/part.h b/source/part.h index c35969d..a3e065a 100644 --- a/source/part.h +++ b/source/part.h @@ -9,8 +9,8 @@ namespace Msp { namespace GLtk { -class CachedPart; class Graphic; +class PartCache; class Resources; /** @@ -46,7 +46,7 @@ public: const Geometry &get_geometry() const { return geom; } const Sides &get_margin() const { return margin; } const Alignment &get_alignment() const { return align; } - void build(const Geometry &, State, CachedPart &) const; + void build(const Geometry &, State, PartCache &) const; }; } // namespace GLtk diff --git a/source/partcache.cpp b/source/partcache.cpp index e270dc4..5589b0d 100644 --- a/source/partcache.cpp +++ b/source/partcache.cpp @@ -1,9 +1,13 @@ +#include "part.h" #include "partcache.h" +using namespace std; + namespace Msp { namespace GLtk { CachedPart::CachedPart(): + part(0), texture(0), mesh(0) { } @@ -13,12 +17,32 @@ CachedPart::~CachedPart() delete mesh; } -void CachedPart::clear_mesh() + +void PartCache::clear() +{ + parts.clear(); +} + +void PartCache::insert_special(const Part &part) { - if(!mesh) - mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2)); - else - mesh->clear(); + if(part.get_name().empty()) + throw invalid_argument("PartCache::insert_special"); + + parts.push_back(CachedPart()); + parts.back().part = ∂ +} + +GL::Mesh &PartCache::create_mesh(const Part &part, const GL::Texture2D &tex) +{ + if(!parts.empty() && parts.back().texture==&tex) + return *parts.back().mesh; + + parts.push_back(CachedPart()); + CachedPart &cpart = parts.back(); + cpart.part = ∂ + cpart.texture = &tex; + cpart.mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2)); + return *cpart.mesh; } } // namespace GLtk diff --git a/source/partcache.h b/source/partcache.h index b856f9d..86a3f36 100644 --- a/source/partcache.h +++ b/source/partcache.h @@ -7,15 +7,32 @@ namespace Msp { namespace GLtk { +class Part; + struct CachedPart { + const Part *part; const GL::Texture2D *texture; GL::Mesh *mesh; CachedPart(); ~CachedPart(); +}; + +class PartCache +{ +public: + typedef std::list PartList; + +private: + PartList parts; + +public: + void clear(); + void insert_special(const Part &); + GL::Mesh &create_mesh(const Part &, const GL::Texture2D &); - void clear_mesh(); + const PartList &get_parts() const { return parts; } }; } // namespace GLtk diff --git a/source/slider.cpp b/source/slider.cpp index 32e221e..7123458 100644 --- a/source/slider.cpp +++ b/source/slider.cpp @@ -27,7 +27,10 @@ void Slider::set_value(double v) } if(value!=old_value) + { signal_value_changed.emit(value); + rebuild(); + } } void Slider::set_range(double a, double b) @@ -54,10 +57,7 @@ void Slider::start_drag(int p) void Slider::drag(int p) { if(max>min) - { set_value(drag_start_value+(p-drag_start_pos)*(max-min)/drag_area_size); - rebuild(); - } } void Slider::end_drag() diff --git a/source/text.cpp b/source/text.cpp index af6b17f..4d80ad5 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -158,30 +158,23 @@ Geometry Text::coords_to_geometry(const Part &part, const Geometry &parent, unsi return data.result; } -void Text::build(const Part &part, const Geometry &parent, CachedPart &cache) const +void Text::build(const Part &part, const Geometry &parent, PartCache &cache) const { build(part, parent, 0, cache); } -void Text::build(const Part &part, const Geometry &parent, unsigned first_row, CachedPart &cache) const +void Text::build(const Part &part, const Geometry &parent, unsigned first_row, PartCache &cache) const { if(!style || lines.empty()) - { - cache.texture = 0; return; - } - - cache.clear_mesh(); - GL::MeshBuilder bld(*cache.mesh); const GL::Font &font = style->get_font(); + GL::MeshBuilder bld(cache.create_mesh(part, font.get_texture())); bld.color(style->get_font_color()); RenderData data; data.bld = &bld; - cache.texture = &font.get_texture(); - process_lines(part, parent, first_row, data); } diff --git a/source/text.h b/source/text.h index dc5710b..03cc787 100644 --- a/source/text.h +++ b/source/text.h @@ -7,9 +7,9 @@ namespace Msp { namespace GLtk { -class CachedPart; class Geometry; class Part; +class PartCache; class Style; /** @@ -52,8 +52,8 @@ public: unsigned coords_to_offset(unsigned, unsigned) const; Geometry coords_to_geometry(const Part &, const Geometry &, unsigned, unsigned, unsigned) const; - void build(const Part &, const Geometry &, CachedPart &) const; - void build(const Part &, const Geometry &, unsigned, CachedPart &) const; + void build(const Part &, const Geometry &, PartCache &) const; + void build(const Part &, const Geometry &, unsigned, PartCache &) const; Text &operator=(const std::string &); private: diff --git a/source/toggle.cpp b/source/toggle.cpp index e34b43a..4519269 100644 --- a/source/toggle.cpp +++ b/source/toggle.cpp @@ -70,10 +70,10 @@ void Toggle::set_value(bool v) clear_state(ACTIVE); } -void Toggle::rebuild_special(const Part &part, CachedPart &cache) +void Toggle::rebuild_special(const Part &part) { if(part.get_name()=="text") - text.build(part, geom, cache); + text.build(part, geom, part_cache); } void Toggle::button_press(int, int, unsigned btn) diff --git a/source/toggle.h b/source/toggle.h index 0a8a893..de8c5d2 100644 --- a/source/toggle.h +++ b/source/toggle.h @@ -48,7 +48,7 @@ public: bool get_value() const { return value; } private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); public: virtual void button_press(int, int, unsigned); diff --git a/source/vslider.cpp b/source/vslider.cpp index 1145b97..6a21c53 100644 --- a/source/vslider.cpp +++ b/source/vslider.cpp @@ -28,12 +28,12 @@ void VSlider::autosize() } } -void VSlider::rebuild_special(const Part &part, CachedPart &cache) +void VSlider::rebuild_special(const Part &part) { if(part.get_name()=="slider") { const Graphic *graphic = part.get_graphic(state); - if(!graphic) + if(!graphic || !graphic->get_texture()) return; Alignment align = part.get_alignment(); @@ -43,10 +43,7 @@ void VSlider::rebuild_special(const Part &part, CachedPart &cache) Geometry pgeom = part.get_geometry(); align.apply(pgeom, geom, part.get_margin()); - cache.texture = part.get_graphic(state)->get_texture(); - cache.clear_mesh(); - - GL::MeshBuilder bld(*cache.mesh); + GL::MeshBuilder bld(part_cache.create_mesh(part, *graphic->get_texture())); bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0); graphic->build(pgeom.w, pgeom.h, bld); } diff --git a/source/vslider.h b/source/vslider.h index c6d6a6f..854b075 100644 --- a/source/vslider.h +++ b/source/vslider.h @@ -19,7 +19,7 @@ public: virtual void autosize(); private: - virtual void rebuild_special(const Part &, CachedPart &); + virtual void rebuild_special(const Part &); public: virtual void button_press(int, int, unsigned); diff --git a/source/widget.cpp b/source/widget.cpp index 3d3b006..f642004 100644 --- a/source/widget.cpp +++ b/source/widget.cpp @@ -156,19 +156,22 @@ void Widget::rebuild() if(!style) return; + part_cache.clear(); const Style::PartSeq &parts = style->get_parts(); - list::iterator j = cached_parts.begin(); - for(Style::PartSeq::const_iterator i=parts.begin(); i!=parts.end(); ++i, ++j) + for(Style::PartSeq::const_iterator i=parts.begin(); i!=parts.end(); ++i) { - if(j==cached_parts.end()) - j = cached_parts.insert(j, CachedPart()); if(i->get_name().empty()) - i->build(geom, state, *j); + i->build(geom, state, part_cache); else - rebuild_special(*i, *j); + rebuild_special(*i); } } +void Widget::rebuild_special(const Part &part) +{ + part_cache.insert_special(part); +} + void Widget::render(GL::Renderer &renderer) const { if(!style) @@ -176,17 +179,16 @@ void Widget::render(GL::Renderer &renderer) const GL::MatrixStack::Push _pushm(renderer.matrix_stack()); renderer.matrix_stack() *= GL::Matrix::translation(geom.x, geom.y, 0); - const Style::PartSeq &parts = style->get_parts(); - list::const_iterator j = cached_parts.begin(); - for(Style::PartSeq::const_iterator i=parts.begin(); (i!=parts.end() && j!=cached_parts.end()); ++i, ++j) + const PartCache::PartList &parts = part_cache.get_parts(); + for(PartCache::PartList::const_iterator i=parts.begin(); i!=parts.end(); ++i) { - if(j->mesh && j->texture) + if(i->mesh && i->texture) { - renderer.set_texture(j->texture); - j->mesh->draw(renderer); + renderer.set_texture(i->texture); + i->mesh->draw(renderer); } - else if(!i->get_name().empty()) - render_special(*i, renderer); + else if(i->part) + render_special(*i->part, renderer); } } diff --git a/source/widget.h b/source/widget.h index b00849c..50e3279 100644 --- a/source/widget.h +++ b/source/widget.h @@ -50,7 +50,7 @@ protected: bool focusable; Container *parent; std::string tooltip; - std::list cached_parts; + PartCache part_cache; Widget(); public: @@ -99,7 +99,7 @@ protected: void set_state(State, State); void rebuild(); - virtual void rebuild_special(const Part &, CachedPart &) { } + virtual void rebuild_special(const Part &); public: void render(GL::Renderer &) const; -- 2.43.0