]> git.tdb.fi Git - libs/gltk.git/commitdiff
Improve widget part caching
authorMikko Rasa <tdb@tdb.fi>
Tue, 25 Jun 2013 22:12:19 +0000 (01:12 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 25 Jun 2013 22:12:19 +0000 (01:12 +0300)
A single mesh can now hold multiple parts if they share the same texture.

25 files changed:
source/button.cpp
source/button.h
source/dropdown.cpp
source/dropdown.h
source/entry.cpp
source/entry.h
source/hslider.cpp
source/hslider.h
source/image.cpp
source/image.h
source/label.cpp
source/label.h
source/part.cpp
source/part.h
source/partcache.cpp
source/partcache.h
source/slider.cpp
source/text.cpp
source/text.h
source/toggle.cpp
source/toggle.h
source/vslider.cpp
source/vslider.h
source/widget.cpp
source/widget.h

index b881b3f97fd8b52394b2e6bf9be1bd9869621598..5582230f95985fc05be05869fa1961c718fc22b2 100644 (file)
@@ -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);
index 11d8bc7b3abf435a46fceb1444ac142d88312fda..e75ba9f33a53db37669b0ec34f6433d7ee0b8331 100644 (file)
@@ -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);
index ee8ec55b7d1e8d46874e42deb82c947fa4d02ca4..ddf5c9268500479655796caecf9bad0a1ec71e20 100644 (file)
@@ -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();
 }
index 7a0f04d3f1feb2afed2a5a313bd3c149b1ed4d06..43bde103590abac7c1f3a19c634a4776e1196d86 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <sigc++/signal.h>
 #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:
index 1f778420e0b44eda8b86b5765320f926048cdd27..a635101404423e9b64524ad7dfee6b9471b53c24 100644 (file)
@@ -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 || 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
index 0bba6f0fbe0e26cd74018b81610d4a4a12b27aec..edea4c3a2a1b4ad8b04e32520fc84ace645dc04a 100644 (file)
@@ -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:
index 2a3644367ea52adb85beeb1f2f02abad007fc25c..837b2ba5c2dae4a0344da91665661079c7e427ef 100644 (file)
@@ -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);
        }
index 9545c2253f00e4434afb35224239dbc42d46ec99..cb0252731c80660235b70c45cc8e4917ecd7c307 100644 (file)
@@ -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);
index a2d44269b86a394115d696796cbc8fbb6fbb5f7c..2735ab611e6a059e73faccae8aa079a0c47e8876 100644 (file)
@@ -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);
index 064a6c969beb63a97115bb349fa1e9ccde76cfdd..234f19f100c81848a25643f6514c8f7f9d81aa0c 100644 (file)
@@ -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
index 21974be7b5844f42275181ce47c26f1794dc2299..f42646709a3f90e43786742790df4f9e19eb2775 100644 (file)
@@ -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()
index 6cd9bcb6e1d5a4188d265d6dd8e56f82ecc1af92..3e753dd0d92f97a64c69f1c6f46ea1a29421261d 100644 (file)
@@ -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();
 };
index f0ee4b920a226bd2108bd946523ae92cf4550447..7c98545c87a49ea5442b88a4463bfaf1c18c620b 100644 (file)
@@ -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);
 }
index c35969dd4276bd206a88b97f5cb0dfcea4aa2e83..a3e065a038058e92d8b60c325114062420311b47 100644 (file)
@@ -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
index e270dc4775eef4f005161304587fa3c58d17f915..5589b0dd8b7c948685964fe5c49aa6cb2dda50a4 100644 (file)
@@ -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 = &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 = &part;
+       cpart.texture = &tex;
+       cpart.mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2));
+       return *cpart.mesh;
 }
 
 } // namespace GLtk
index b856f9da47a486151f3a10b62c51f1f0c60fb02c..86a3f364abe21260395493f40580d278f5b5775c 100644 (file)
@@ -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<CachedPart> 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
index 32e221e36dba39d56776570e0b99209c4ce873d9..7123458c0e41b7268ce44b7c556543dfd2af9aa1 100644 (file)
@@ -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()
index af6b17f85e14946b23088909c26cd056dcbe4768..4d80ad548004f57276ce202ffa4e82fcbdc04daf 100644 (file)
@@ -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<RenderData, &Text::build_line>(part, parent, first_row, data);
 }
 
index dc5710bdc2dddd6789de34d0c7ba2ee4816b0878..03cc787bb741151bff97e264ed6998022b354694 100644 (file)
@@ -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:
index e34b43ae38cc743ef721216e5b3d41b1b662ce26..451926956d12520de95ff4ba6aff7e9049556249 100644 (file)
@@ -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)
index 0a8a89378afc937f35bc8eb049d5e14e99ae2852..de8c5d2a71e91a9c193ddbbcbb01a0cdc6ecb0d7 100644 (file)
@@ -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);
index 1145b97c3c762e67dfec564997baa6d6a0114e16..6a21c5301ad6eb45a51d2ff201ababb271a02f21 100644 (file)
@@ -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);
        }
index c6d6a6f9754571d8fce98f5e4f68a0aead8ab5b0..854b075d76e3e3218cbe50daa6d1e4f69a1750e9 100644 (file)
@@ -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);
index 3d3b0068ad6f394b905d8e6854dafdfeebf9769e..f642004e07c3825fc1a79432f7a3acc237c1dadc 100644 (file)
@@ -156,19 +156,22 @@ void Widget::rebuild()
        if(!style)
                return;
 
+       part_cache.clear();
        const Style::PartSeq &parts = style->get_parts();
-       list<CachedPart>::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<CachedPart>::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);
        }
 }
 
index b00849c1598873a6ae7ecdc0e76ff9a036539d76..50e3279e3b5c3d753373246d88d13f7e3a0800e0 100644 (file)
@@ -50,7 +50,7 @@ protected:
        bool focusable;
        Container *parent;
        std::string tooltip;
-       std::list<CachedPart> 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;