]> git.tdb.fi Git - libs/gltk.git/commitdiff
Cache widget parts in meshes
authorMikko Rasa <tdb@tdb.fi>
Fri, 30 Nov 2012 20:21:55 +0000 (22:21 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 30 Nov 2012 20:43:03 +0000 (22:43 +0200)
This initial implementation is rather rough, but it paves the way for
using GL::Renderer.  It uses a lot of VBOs and is generally less efficient
than it could, but those will be addressed in the near future.  All
widgets haven't been tested, but the helloworld example works.

31 files changed:
source/button.cpp
source/button.h
source/dropdown.cpp
source/dropdown.h
source/entry.cpp
source/entry.h
source/graphic.cpp
source/graphic.h
source/hslider.cpp
source/hslider.h
source/image.cpp
source/image.h
source/label.cpp
source/label.h
source/list.cpp
source/list.h
source/part.cpp
source/part.h
source/partcache.cpp [new file with mode: 0644]
source/partcache.h [new file with mode: 0644]
source/slider.cpp
source/table.cpp
source/table.h
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 5f9b18bfdf3290a830d4bc392b126d0be3649a19..939d02646249b8d2aec450299edba5f422ea37dc 100644 (file)
@@ -1,4 +1,4 @@
-#include <msp/gl/immediate.h>
+#include <msp/gl/meshbuilder.h>
 #include "button.h"
 #include "part.h"
 #include "style.h"
@@ -39,44 +39,52 @@ void Button::autosize()
                        geom.h = max(geom.h, icon->get_height()+margin.top+margin.bottom);
                }
        }
+
+       rebuild();
 }
 
 void Button::set_text(const std::string &t)
 {
        text = t;
        signal_autosize_changed.emit();
+       rebuild();
 }
 
 void Button::set_icon(const GL::Texture2D *i)
 {
        icon = i;
+       rebuild();
 }
 
-void Button::render_special(const Part &part) const
+void Button::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="text")
-               text.render(part, geom);
-       if(part.get_name()=="icon" && icon)
+               text.build(part, geom, cache);
+       if(part.get_name()=="icon")
        {
-               Geometry rgeom;
-               rgeom.w = icon->get_width();
-               rgeom.h = icon->get_height();
-               part.get_alignment().apply(rgeom, geom, part.get_margin());
-
-               icon->bind();
-               GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
-               imm.color(1.0f, 1.0f, 1.0f);
-               imm.begin(GL::QUADS);
-               imm.texcoord(0, 0);
-               imm.vertex(rgeom.x, rgeom.y);
-               imm.texcoord(1, 0);
-               imm.vertex(rgeom.x+rgeom.w, rgeom.y);
-               imm.texcoord(1, 1);
-               imm.vertex(rgeom.x+rgeom.w, rgeom.y+rgeom.h);
-               imm.texcoord(0, 1);
-               imm.vertex(rgeom.x, rgeom.y+rgeom.h);
-               imm.end();
-               GL::Texture::unbind();
+               cache.texture = icon;
+               if(icon)
+               {
+                       Geometry rgeom;
+                       rgeom.w = icon->get_width();
+                       rgeom.h = icon->get_height();
+                       part.get_alignment().apply(rgeom, geom, part.get_margin());
+
+                       cache.clear_mesh();
+
+                       GL::MeshBuilder bld(*cache.mesh);
+                       bld.color(1.0f, 1.0f, 1.0f);
+                       bld.begin(GL::QUADS);
+                       bld.texcoord(0, 0);
+                       bld.vertex(rgeom.x, rgeom.y);
+                       bld.texcoord(1, 0);
+                       bld.vertex(rgeom.x+rgeom.w, rgeom.y);
+                       bld.texcoord(1, 1);
+                       bld.vertex(rgeom.x+rgeom.w, rgeom.y+rgeom.h);
+                       bld.texcoord(0, 1);
+                       bld.vertex(rgeom.x, rgeom.y+rgeom.h);
+                       bld.end();
+               }
        }
 }
 
index 31009c731ec1d3cae065e98ca0e286f771aee1f2..e99f16b2503ac568d589928d2ae1729c517d2aee 100644 (file)
@@ -42,7 +42,7 @@ public:
        void set_icon(const GL::Texture2D *);
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 
 public:
        virtual void button_press(int, int, unsigned);
index 47496f4bc385121d7c5c2862cec06947427cb799..c2ceefa78957348ee6edd188e71e8ec1faf1fd95 100644 (file)
@@ -36,6 +36,8 @@ void Dropdown::autosize()
                unsigned line_height = static_cast<unsigned>((font.get_ascent()-font.get_descent())*font_size);
                geom.h = max(geom.h, line_height+margin.top+margin.bottom);
        }
+
+       rebuild();
 }
 
 void Dropdown::append(const string &item)
@@ -78,14 +80,20 @@ int Dropdown::get_selected_index() const
        return list.get_selected_index();
 }
 
-void Dropdown::render_special(const Part &part) const
+void Dropdown::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="text")
        {
                if(list.get_selected_index()>=0)
-                       Text(*style, list.get_selected()).render(part, geom);
+                       Text(*style, list.get_selected()).build(part, geom, cache);
+               else
+                       cache.texture = 0;
        }
-       else if(part.get_name()=="list" && dropped)
+}
+
+void Dropdown::render_special(const Part &part) const
+{
+       if(part.get_name()=="list" && dropped)
                list.render();
 }
 
index ece84baa0862a58dfcd29496ddf0edd92363cf66..4af5a5fe9a265cb484a509950ee5982d8d486713 100644 (file)
@@ -45,6 +45,7 @@ public:
        int get_selected_index() const;
 
 private:
+       virtual void rebuild_special(const Part &, CachedPart &);
        virtual void render_special(const Part &) const;
 
 public:
index a0df8cb9e423c1372c56997be5cf1ba74db50c9b..ca185bea0168c4e40b1accf63055136443ced6e2 100644 (file)
@@ -1,6 +1,6 @@
 #include <msp/gl/matrix.h>
+#include <msp/gl/meshbuilder.h>
 #include <msp/gl/texture.h>
-#include <msp/gl/transform.h>
 #include <msp/input/keys.h>
 #include "entry.h"
 #include "graphic.h"
@@ -72,6 +72,8 @@ void Entry::autosize()
 
                check_view_range();
        }
+
+       rebuild();
 }
 
 void Entry::set_text(const string &t)
@@ -81,6 +83,8 @@ void Entry::set_text(const string &t)
 
        if(multiline)
                check_view_range();
+
+       rebuild();
 }
 
 void Entry::set_multiline(bool m)
@@ -100,29 +104,41 @@ void Entry::set_multiline(bool m)
        }
 }
 
-void Entry::render_special(const Part &part) const
+void Entry::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="text")
-               text.render(part, geom, first_row);
+               text.build(part, geom, first_row, cache);
        else if(part.get_name()=="cursor")
        {
                if(!text_part || !part.get_graphic(state))
+               {
+                       cache.texture = 0;
                        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);
 
-               GL::push_matrix();
-               GL::translate(rgeom.x, rgeom.y, 0);
-               part.get_graphic(state)->render(part.get_geometry().w, part.get_geometry().h);
-               GL::pop_matrix();
+               cache.texture = part.get_graphic(state)->get_texture();
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
+               bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
+               part.get_graphic(state)->build(part.get_geometry().w, part.get_geometry().h, bld);
        }
-       else if(part.get_name()=="slider" && multiline)
+}
+
+void Entry::render_special(const Part &part) const
+{
+       if(part.get_name()=="slider" && multiline)
                slider->render();
 }
 
@@ -131,37 +147,24 @@ void Entry::key_press(unsigned key, unsigned)
        if(key==Input::KEY_LEFT)
        {
                if(edit_pos>0)
-               {
-                       --edit_pos;
-                       check_view_range();
-               }
+                       set_edit_position(edit_pos-1);
        }
        else if(key==Input::KEY_RIGHT)
        {
                if(edit_pos<text.size())
-               {
-                       ++edit_pos;
-                       check_view_range();
-               }
+                       set_edit_position(edit_pos+1);
        }
        else if(key==Input::KEY_DOWN && multiline)
        {
                unsigned row, col;
                text.offset_to_coords(edit_pos, row, col);
-               edit_pos = text.coords_to_offset(row+1, col);
-               check_view_range();
+               set_edit_position(text.coords_to_offset(row+1, col));
        }
        else if(key==Input::KEY_UP && multiline)
        {
                unsigned row, col;
                text.offset_to_coords(edit_pos, row, col);
-               if(row>0)
-               {
-                       edit_pos = text.coords_to_offset(row-1, col);
-                       check_view_range();
-               }
-               else
-                       edit_pos = 0;
+               set_edit_position(row>0 ? text.coords_to_offset(row-1, col) : 0);
        }
        else if(key==Input::KEY_BACKSPACE)
        {
@@ -169,6 +172,7 @@ void Entry::key_press(unsigned key, unsigned)
                {
                        text.erase(--edit_pos, 1);
                        check_view_range();
+                       rebuild();
                }
        }
        else if(key==Input::KEY_ENTER)
@@ -177,6 +181,7 @@ void Entry::key_press(unsigned key, unsigned)
                {
                        text.insert(edit_pos++, "\n");
                        check_view_range();
+                       rebuild();
                }
                else
                        signal_enter.emit();
@@ -189,6 +194,7 @@ void Entry::character(wchar_t ch)
        {
                text.insert(edit_pos, StringCodec::encode<StringCodec::Utf8>(StringCodec::ustring(1, ch)));
                ++edit_pos;
+               rebuild();
        }
 }
 
@@ -218,6 +224,13 @@ void Entry::on_style_change()
                check_view_range();
 }
 
+void Entry::set_edit_position(unsigned ep)
+{
+       edit_pos = ep;
+       check_view_range();
+       rebuild();
+}
+
 void Entry::reposition_slider()
 {
        if(!style || !slider)
index 058ef3fb38321df9c2e782888859a3d331daf684..968e3994580b042e35d19c3a4813ec5c6fcc1ec0 100644 (file)
@@ -52,6 +52,7 @@ public:
        bool is_multiline() const { return multiline; }
 
 private:
+       virtual void rebuild_special(const Part &, CachedPart &);
        virtual void render_special(const Part &) const;
 
 public:
@@ -61,6 +62,7 @@ private:
        virtual void on_geometry_change();
        virtual void on_style_change();
 
+       void set_edit_position(unsigned);
        void reposition_slider();
        void check_view_range();
        void slider_value_changed(double);
index 005d30fb4ef8f7929326093766d49ae62332dcbe..0b0ba0e6ef055ee23251b3b40338479f34674a65 100644 (file)
@@ -1,4 +1,3 @@
-#include <msp/gl/immediate.h>
 #include "graphic.h"
 #include "resources.h"
 
@@ -12,7 +11,7 @@ Graphic::Graphic():
        repeat(false)
 { }
 
-void Graphic::render(unsigned wd, unsigned ht) const
+void Graphic::build(unsigned wd, unsigned ht, GL::PrimitiveBuilder &bld) const
 {
        vector<float> x, y;
        create_coords(0.0f-shadow.left, wd+shadow.right, border.left, border.right, slice.w-border.left-border.right, x);
@@ -27,27 +26,25 @@ void Graphic::render(unsigned wd, unsigned ht) const
        unsigned ymin = border.bottom ? 0 : 1;
        unsigned ymax = y.size()-(border.top ? 2 : 3);
 
-       texture->bind();
-       GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
-       imm.color(1.0f, 1.0f, 1.0f);
-       imm.begin(GL::QUADS);
+       bld.color(1.0f, 1.0f, 1.0f);
+       bld.begin(GL::QUADS);
        for(unsigned i=ymin; i<=ymax; ++i)
        {
                unsigned i2 = (i==0 ? 0 : i==y.size()-2 ? 2 : 1);
                for(unsigned j=xmin; j<=xmax; ++j)
                {
                        unsigned j2 = (j==0 ? 0 : j==x.size()-2 ? 2 : 1);
-                       imm.texcoord(u[j2], v[i2]);
-                       imm.vertex(x[j], y[i]);
-                       imm.texcoord(u[j2+1], v[i2]);
-                       imm.vertex(x[j+1], y[i]);
-                       imm.texcoord(u[j2+1], v[i2+1]);
-                       imm.vertex(x[j+1], y[i+1]);
-                       imm.texcoord(u[j2], v[i2+1]);
-                       imm.vertex(x[j], y[i+1]);
+                       bld.texcoord(u[j2], v[i2]);
+                       bld.vertex(x[j], y[i]);
+                       bld.texcoord(u[j2+1], v[i2]);
+                       bld.vertex(x[j+1], y[i]);
+                       bld.texcoord(u[j2+1], v[i2+1]);
+                       bld.vertex(x[j+1], y[i+1]);
+                       bld.texcoord(u[j2], v[i2+1]);
+                       bld.vertex(x[j], y[i+1]);
                }
        }
-       imm.end();
+       bld.end();
 }
 
 void Graphic::create_coords(float low, float high, float brd1, float brd2, float block, vector<float> &coords) const
index 81ad669c717f0a66d1a977825f33212254edbaf1..f457d3690b297a91d989dc92ed9ce5fa634268d4 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_GLTK_GRAPHIC_H_
 #define MSP_GLTK_GRAPHIC_H_
 
+#include <msp/gl/primitivebuilder.h>
 #include <msp/gl/texture2d.h>
 #include <msp/datafile/loader.h>
 #include "geometry.h"
@@ -48,7 +49,7 @@ public:
        const GL::Texture2D *get_texture() const { return texture; }
        unsigned get_width() const  { return slice.w; }
        unsigned get_height() const { return slice.h; }
-       void render(unsigned, unsigned) const;
+       void build(unsigned, unsigned, GL::PrimitiveBuilder &) const;
 private:
        void create_coords(float, float, float, float, float, std::vector<float> &) const;
        void create_texcoords(float, float, float, float, float, std::vector<float> &) const;
index 18a163c844258d503f4cb2601387fcc191e4bf81..fbd9b943a8c4703dc8fe77acc542df843777173f 100644 (file)
@@ -1,5 +1,5 @@
 #include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
 #include "graphic.h"
 #include "hslider.h"
 #include "part.h"
@@ -28,7 +28,7 @@ void HSlider::autosize()
        }
 }
 
-void HSlider::render_special(const Part &part) const
+void HSlider::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="slider")
        {
@@ -39,10 +39,12 @@ void HSlider::render_special(const Part &part) const
                Geometry pgeom = part.get_geometry();
                align.apply(pgeom, geom, part.get_margin());
 
-               GL::push_matrix();
-               GL::translate(pgeom.x, pgeom.y, 0);
-               part.get_graphic(state)->render(pgeom.w, pgeom.h);
-               GL::pop_matrix();
+               cache.texture = part.get_graphic(state)->get_texture();
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
+               bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0);
+               part.get_graphic(state)->build(pgeom.w, pgeom.h, bld);
        }
 }
 
index a94e8bcaaca2bc914ea56bf492d060806e931ce2..9545c2253f00e4434afb35224239dbc42d46ec99 100644 (file)
@@ -23,7 +23,7 @@ public:
        virtual void autosize();
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 
 public:
        virtual void button_press(int, int, unsigned);
index bff790427657ae3256596220d68bfd81c657d079..a2d44269b86a394115d696796cbc8fbb6fbb5f7c 100644 (file)
@@ -1,6 +1,4 @@
-#include <msp/gl/bindable.h>
-#include <msp/gl/immediate.h>
-#include <msp/gl/matrix.h>
+#include <msp/gl/meshbuilder.h>
 #include "image.h"
 #include "part.h"
 #include "style.h"
@@ -38,25 +36,32 @@ void Image::autosize()
                        geom.h = max(geom.h, margin.top+margin.bottom);
                }
        }
+
+       rebuild();
 }
 
 void Image::set_image(const GL::Texture2D *i)
 {
        image = i;
        signal_autosize_changed.emit();
+       rebuild();
 }
 
 void Image::set_keep_aspect(bool ka)
 {
        keep_aspect = ka;
+       rebuild();
 }
 
-void Image::render_special(const Part &part) const
+void Image::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="image")
        {
                if(!image)
+               {
+                       cache.texture = 0;
                        return;
+               }
 
                const Alignment &align = part.get_alignment();
                Geometry rgeom = part.get_geometry();
@@ -79,19 +84,21 @@ void Image::render_special(const Part &part) const
                        }
                }
 
-               GL::Bind _bind_tex(image);
-               GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
-               imm.color(1.0f, 1.0f, 1.0f);
-               imm.begin(GL::QUADS);
-               imm.texcoord(0.0, 0.0);
-               imm.vertex(rgeom.x, rgeom.y);
-               imm.texcoord(1.0, 0.0);
-               imm.vertex(rgeom.x+rgeom.w, rgeom.y);
-               imm.texcoord(1.0, 1.0);
-               imm.vertex(rgeom.x+rgeom.w, rgeom.y+rgeom.h);
-               imm.texcoord(0.0, 1.0);
-               imm.vertex(rgeom.x, rgeom.y+rgeom.h);
-               imm.end();
+               cache.texture = image;
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
+               bld.color(1.0f, 1.0f, 1.0f);
+               bld.begin(GL::QUADS);
+               bld.texcoord(0.0, 0.0);
+               bld.vertex(rgeom.x, rgeom.y);
+               bld.texcoord(1.0, 0.0);
+               bld.vertex(rgeom.x+rgeom.w, rgeom.y);
+               bld.texcoord(1.0, 1.0);
+               bld.vertex(rgeom.x+rgeom.w, rgeom.y+rgeom.h);
+               bld.texcoord(0.0, 1.0);
+               bld.vertex(rgeom.x, rgeom.y+rgeom.h);
+               bld.end();
        }
 }
 
index 5f6b935d20422050df32664b5c00e71984361e61..064a6c969beb63a97115bb349fa1e9ccde76cfdd 100644 (file)
@@ -27,7 +27,7 @@ public:
        void set_keep_aspect(bool);
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 };
 
 } // namespace GLtk
index 3805eaf587c21a31217229ca2bdb464985c10e1b..f9274b47e2f665ff85ad13d6cf488be49bcec321 100644 (file)
@@ -26,18 +26,21 @@ void Label::autosize()
                geom.w = max(geom.w, text.get_width()+margin.left+margin.right);
                geom.h = max(geom.h, text.get_height()+margin.top+margin.bottom);
        }
+
+       rebuild();
 }
 
 void Label::set_text(const string &t)
 {
        text = t;
        signal_autosize_changed.emit();
+       rebuild();
 }
 
-void Label::render_special(const Part &part) const
+void Label::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="text")
-               text.render(part, geom);
+               text.build(part, geom, cache);
 }
 
 void Label::on_style_change()
index a61776ed6e1c9b6dd4cd32c138fb7466783b6fe4..9a0d1f2e57fa53be157546c49be1a9bec133e261 100644 (file)
@@ -33,7 +33,7 @@ public:
        void set_text(const std::string &);
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 
        virtual void on_style_change();
 };
index a886118ed6c98b8341effd74de1d6fc4c6f61018..19559d1d05b8f51606fc2cd36a4bce5689344901 100644 (file)
@@ -1,6 +1,5 @@
-#include <msp/gl/immediate.h>
 #include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
 #include "graphic.h"
 #include "list.h"
 #include "part.h"
@@ -74,6 +73,7 @@ void List::autosize_rows(unsigned n)
        }
 
        check_view_range();
+       rebuild();
 }
 
 void List::autosize_all()
@@ -84,8 +84,7 @@ void List::autosize_all()
 void List::append(const string &v)
 {
        items.push_back(v);
-       check_view_range();
-       signal_autosize_changed.emit();
+       items_changed();
 }
 
 void List::insert(unsigned i, const string &v)
@@ -94,8 +93,7 @@ void List::insert(unsigned i, const string &v)
                throw out_of_range("List::insert");
 
        items.insert(items.begin()+i, v);
-       check_view_range();
-       signal_autosize_changed.emit();
+       items_changed();
 }
 
 void List::remove(unsigned i)
@@ -109,17 +107,21 @@ void List::remove(unsigned i)
        else if(sel_index==static_cast<int>(i))
                sel_index = -1;
 
-       check_view_range();
-       signal_autosize_changed.emit();
+       items_changed();
 }
 
 void List::clear()
 {
        items.clear();
        sel_index = -1;
+       items_changed();
+}
 
+void List::items_changed()
+{
        check_view_range();
        signal_autosize_changed.emit();
+       rebuild();
 }
 
 void List::set_selected_index(int i)
@@ -143,7 +145,7 @@ const string &List::get_selected() const
        return items[sel_index];
 }
 
-void List::render_special(const Part &part) const
+void List::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="items")
        {
@@ -151,14 +153,23 @@ void List::render_special(const Part &part) const
                Geometry pgeom = geom;
                pgeom.h = row_height+margin.top+margin.bottom;
 
-               GL::PushMatrix push_mtx;
-               GL::translate(0, geom.h-pgeom.h, 0);
+               const GL::Font &font = style->get_font();
+               cache.texture = &font.get_texture();
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
+               bld.color(style->get_font_color());
+               bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y+geom.h-pgeom.h, 0);
 
                for(unsigned i=0; (i<n_visible && first+i<items.size()); ++i)
                {
                        if(i!=0)
-                               GL::translate(0, -static_cast<int>(row_height), 0);
-                       Text(*style, items[first+i]).render(part, pgeom);
+                               bld.matrix() *= GL::Matrix::translation(0, -static_cast<int>(row_height), 0);
+
+                       GL::MatrixStack::Push _pushm(bld.matrix());
+                       bld.matrix() *= GL::Matrix::scaling(style->get_font_size());
+
+                       style->get_font().build_string(items[first+i], bld);
                }
        }
        else if(part.get_name()=="selection")
@@ -176,13 +187,21 @@ void List::render_special(const Part &part) const
                        rgeom.x += margin.left;
                        part.get_alignment().apply(rgeom, pgeom);
 
-                       GL::push_matrix();
-                       GL::translate(rgeom.x, rgeom.y, 0);
-                       part.get_graphic(state)->render(rgeom.w, rgeom.h);
-                       GL::pop_matrix();
+                       cache.texture = part.get_graphic(state)->get_texture();
+                       cache.clear_mesh();
+
+                       GL::MeshBuilder bld(*cache.mesh);
+                       bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
+                       part.get_graphic(state)->build(rgeom.w, rgeom.h, bld);
                }
+               else
+                       cache.texture = 0;
        }
-       else if(part.get_name()=="slider")
+}
+
+void List::render_special(const Part &part) const
+{
+       if(part.get_name()=="slider")
                slider.render();
 }
 
@@ -200,6 +219,7 @@ void List::button_press(int x, int y, unsigned btn)
                        sel_index = first+i;
 
                        signal_item_selected.emit(sel_index, items[sel_index]);
+                       rebuild();
                }
        }
 }
@@ -276,7 +296,10 @@ void List::check_view_range()
 void List::slider_value_changed(double value)
 {
        if(items.size()>n_visible)
+       {
                first = items.size()-n_visible-static_cast<unsigned>(value);
+               rebuild();
+       }
 }
 
 
index 56fe6aafd92ee5d2fd033eab45c045c2c724ebe4..2970bb454b19425a5a3626de1c025facd8ccebc3 100644 (file)
@@ -49,6 +49,9 @@ public:
        void insert(unsigned, const std::string &);
        void remove(unsigned);
        void clear();
+private:
+       void items_changed();
+public:
        unsigned get_n_items() const { return items.size(); }
 
        void set_selected_index(int);
@@ -56,6 +59,7 @@ public:
        int get_selected_index() const { return sel_index; }
 
 private:
+       virtual void rebuild_special(const Part &, CachedPart &);
        virtual void render_special(const Part &) const;
 
 public:
index 127397924f19cf5039b2fe8f1b34df780be8ed8f..7037d4b3384374568bc662a9edc1df3299776ba3 100644 (file)
@@ -1,6 +1,7 @@
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
 #include "geometry.h"
 #include "part.h"
+#include "partcache.h"
 #include "resources.h"
 
 using namespace std;
@@ -23,15 +24,22 @@ const Graphic *Part::get_graphic(State state) const
        return graphic[state];
 }
 
-void Part::render(const Geometry &parent, State state) const
+void Part::build(const Geometry &parent, State state, CachedPart &cache) const
 {
        if(!graphic[state])
+       {
+               cache.texture = 0;
                return;
+       }
+
+       cache.texture = graphic[state]->get_texture();
+       cache.clear_mesh();
 
        Geometry rgeom = geom;
        align.apply(rgeom, parent, margin);
-       GL::translate(rgeom.x, rgeom.y, 0);
-       graphic[state]->render(rgeom.w, rgeom.h);
+       GL::MeshBuilder bld(*cache.mesh);
+       bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
+       graphic[state]->build(rgeom.w, rgeom.h, bld);
 }
 
 
index b4ada58e96bdcc8862b3b76495cdcf231fedbd32..c35969dd4276bd206a88b97f5cb0dfcea4aa2e83 100644 (file)
@@ -9,6 +9,7 @@
 namespace Msp {
 namespace GLtk {
 
+class CachedPart;
 class Graphic;
 class Resources;
 
@@ -45,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 render(const Geometry &, State) const;
+       void build(const Geometry &, State, CachedPart &) const;
 };
 
 } // namespace GLtk
diff --git a/source/partcache.cpp b/source/partcache.cpp
new file mode 100644 (file)
index 0000000..e270dc4
--- /dev/null
@@ -0,0 +1,25 @@
+#include "partcache.h"
+
+namespace Msp {
+namespace GLtk {
+
+CachedPart::CachedPart():
+       texture(0),
+       mesh(0)
+{ }
+
+CachedPart::~CachedPart()
+{
+       delete mesh;
+}
+
+void CachedPart::clear_mesh()
+{
+       if(!mesh)
+               mesh = new GL::Mesh((GL::TEXCOORD2, GL::COLOR4_UBYTE, GL::VERTEX2));
+       else
+               mesh->clear();
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/partcache.h b/source/partcache.h
new file mode 100644 (file)
index 0000000..b856f9d
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MSP_GLTK_PARTCACHE_H_
+#define MSP_GLTK_PARTCACHE_H_
+
+#include <msp/gl/mesh.h>
+#include <msp/gl/texture2d.h>
+
+namespace Msp {
+namespace GLtk {
+
+struct CachedPart
+{
+       const GL::Texture2D *texture;
+       GL::Mesh *mesh;
+
+       CachedPart();
+       ~CachedPart();
+
+       void clear_mesh();
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
index de4d12e3d69646f4960d65c5ee4316901cbc9bcd..dc8a28a6ff0c0ca718000cb3923c5e03c1050633 100644 (file)
@@ -54,7 +54,10 @@ 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 1fe69619f911aa892563c27b54dba76e613d1c5d..32db6c4af30ddbee2546730291bb8942e4477d3d 100644 (file)
@@ -1,6 +1,6 @@
 #include <stdexcept>
 #include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
 #include "part.h"
 #include "style.h"
 #include "table.h"
@@ -52,7 +52,7 @@ void Table::set_cell_text(unsigned r, unsigned c, const string &t)
        data[r*columns+c] = t;
 }
 
-void Table::render_special(const Part &part) const
+void Table::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="cells")
        {
@@ -67,6 +67,10 @@ void Table::render_special(const Part &part) const
                cgeom.h = geom.h/rows;
                cgeom.y = geom.h-cgeom.h;
 
+               cache.texture = &font.get_texture();
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
                for(unsigned i=0; i<rows; ++i)
                {
                        cgeom.x = 0;
@@ -86,11 +90,10 @@ void Table::render_special(const Part &part) const
 
                                part.get_alignment().apply(rgeom, cgeom, part.get_margin());
 
-                               GL::push_matrix();
-                               GL::translate(rgeom.x, rgeom.y, 0);
-                               GL::scale_uniform(font_size);
+                               GL::MatrixStack::Push _push(bld.matrix());
+                               bld.matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
+                               bld.matrix() *= GL::Matrix::scaling(font_size);
                                font.draw_string(text);
-                               GL::pop_matrix();
 
                                cgeom.x += cgeom.w;
                        }
index 1b0a80d857a1d4fd24136ec914dd618a33fff99a..072714416fa6880132bdcb6ee7207d035b9c6eb2 100644 (file)
@@ -41,7 +41,7 @@ public:
 private:
        virtual const char *get_class() const { return "table"; }
 
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
        virtual void on_style_change();
 };
 
index 0b582c5e8b6c0eb47b64784eef13fb3182161971..08846a4c75acd587fa47bce8dd1b835cbd42e153 100644 (file)
@@ -1,6 +1,7 @@
-#include <msp/gl/immediate.h>
 #include <msp/gl/matrix.h>
+#include <msp/gl/meshbuilder.h>
 #include <msp/gl/texture2d.h>
+#include "partcache.h"
 #include "style.h"
 #include "text.h"
 
@@ -157,22 +158,31 @@ Geometry Text::coords_to_geometry(const Part &part, const Geometry &parent, unsi
        return data.result;
 }
 
-void Text::render(const Part &part, const Geometry &parent, unsigned first_row) const
+void Text::build(const Part &part, const Geometry &parent, CachedPart &cache) const
+{
+       build(part, parent, 0, cache);
+}
+
+void Text::build(const Part &part, const Geometry &parent, unsigned first_row, CachedPart &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();
-       const GL::Color &color = style->get_font_color();
-       GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
-       imm.color(color.r, color.g, color.b);
+       bld.color(style->get_font_color());
 
        RenderData data;
-       data.bld = &imm;
+       data.bld = &bld;
 
-       GL::Bind bind_tex(font.get_texture());
+       cache.texture = &font.get_texture();
 
-       process_lines<RenderData, &Text::render_line>(part, parent, first_row, data);
+       process_lines<RenderData, &Text::build_line>(part, parent, first_row, data);
 }
 
 Text &Text::operator=(const string &t)
@@ -238,13 +248,13 @@ void Text::process_lines(const Part &part, const Geometry &parent, unsigned firs
        }
 }
 
-void Text::render_line(unsigned i, const Geometry &rgeom, RenderData &data) const
+void Text::build_line(unsigned i, const Geometry &rgeom, RenderData &data) const
 {
        const Line &line = lines[i];
 
-       GL::PushMatrix _pushm;
-       GL::translate(rgeom.x, rgeom.y, 0);
-       GL::scale_uniform(style->get_font_size());
+       GL::MatrixStack::Push _pushm(data.bld->matrix());
+       data.bld->matrix() *= GL::Matrix::translation(rgeom.x, rgeom.y, 0);
+       data.bld->matrix() *= GL::Matrix::scaling(style->get_font_size());
 
        style->get_font().build_string(text.substr(line.start, line.length), *data.bld);
 }
index 077558bb84a34b27e7ceba181fad311a57abb031..dc5710bdc2dddd6789de34d0c7ba2ee4816b0878 100644 (file)
@@ -7,6 +7,7 @@
 namespace Msp {
 namespace GLtk {
 
+class CachedPart;
 class Geometry;
 class Part;
 class Style;
@@ -51,7 +52,8 @@ public:
        unsigned coords_to_offset(unsigned, unsigned) const;
        Geometry coords_to_geometry(const Part &, const Geometry &, unsigned, unsigned, unsigned) const;
 
-       void render(const Part &, const Geometry &, unsigned = 0) const;
+       void build(const Part &, const Geometry &, CachedPart &) const;
+       void build(const Part &, const Geometry &, unsigned, CachedPart &) const;
 
        Text &operator=(const std::string &);
 private:
@@ -60,7 +62,7 @@ private:
        template<typename T, void (Text::*)(unsigned, const Geometry &, T &) const>
        void process_lines(const Part &, const Geometry &, unsigned, T &) const;
 
-       void render_line(unsigned, const Geometry &, RenderData &) const;
+       void build_line(unsigned, const Geometry &, RenderData &) const;
        void coords_to_geom_line(unsigned, const Geometry &, CoordsToGeomData &) const;
 };
 
index f2cf55202183f44d42cf132bb2d9746a165b096f..789ae37ecfec59fdd5987b9739fa0818dc98f8d9 100644 (file)
@@ -30,12 +30,15 @@ void Toggle::autosize()
                geom.w = max(geom.w, text.get_width()+margin.left+margin.right);
                geom.h = max(geom.h, text.get_height()+margin.top+margin.bottom);
        }
+
+       rebuild();
 }
 
 void Toggle::set_text(const string &t)
 {
        text = t;
        signal_autosize_changed.emit();
+       rebuild();
 }
 
 void Toggle::set_exclusive(bool e)
@@ -67,10 +70,10 @@ void Toggle::set_value(bool v)
                clear_state(ACTIVE);
 }
 
-void Toggle::render_special(const Part &part) const
+void Toggle::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="text")
-               text.render(part, geom);
+               text.build(part, geom, cache);
 }
 
 void Toggle::button_press(int, int, unsigned btn)
index b6195e1d470f65a79ddd5e450ca5f2fbfce1cc7c..fd7e762734ab295ad25be775ba5568f4970a5b75 100644 (file)
@@ -49,7 +49,7 @@ public:
        bool get_value() const { return value; }
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 
 public:
        virtual void button_press(int, int, unsigned);
index 93e485ab6b77844039dda3646531af8ee70721fa..a32e484906c19b0944599a47f8b0932adde24b0b 100644 (file)
@@ -1,5 +1,5 @@
 #include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
 #include "graphic.h"
 #include "part.h"
 #include "style.h"
@@ -28,7 +28,7 @@ void VSlider::autosize()
        }
 }
 
-void VSlider::render_special(const Part &part) const
+void VSlider::rebuild_special(const Part &part, CachedPart &cache)
 {
        if(part.get_name()=="slider")
        {
@@ -39,10 +39,12 @@ void VSlider::render_special(const Part &part) const
                Geometry pgeom = part.get_geometry();
                align.apply(pgeom, geom, part.get_margin());
 
-               GL::push_matrix();
-               GL::translate(pgeom.x, pgeom.y, 0);
-               part.get_graphic(state)->render(pgeom.w, pgeom.h);
-               GL::pop_matrix();
+               cache.texture = part.get_graphic(state)->get_texture();
+               cache.clear_mesh();
+
+               GL::MeshBuilder bld(*cache.mesh);
+               bld.matrix() *= GL::Matrix::translation(pgeom.x, pgeom.y, 0);
+               part.get_graphic(state)->build(pgeom.w, pgeom.h, bld);
        }
 }
 
index e4055994f8c0068b72f18e999b1a82dd69a8ea29..c6d6a6f9754571d8fce98f5e4f68a0aead8ab5b0 100644 (file)
@@ -19,7 +19,7 @@ public:
        virtual void autosize();
 
 private:
-       virtual void render_special(const Part &) const;
+       virtual void rebuild_special(const Part &, CachedPart &);
 
 public:
        virtual void button_press(int, int, unsigned);
index b10b6b560d8226cd9e1ddd68cef905e7189cc0bf..4b48e8ba11400d2f410790de92b8464e890b68b3 100644 (file)
@@ -1,6 +1,4 @@
-#include <msp/gl/immediate.h>
 #include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
 #include <msp/strings/format.h>
 #include "container.h"
 #include "resources.h"
@@ -35,6 +33,7 @@ void Widget::set_position(int x, int y)
        geom.x = x;
        geom.y = y;
        on_geometry_change();
+       rebuild();
 }
 
 void Widget::set_size(unsigned w, unsigned h)
@@ -42,6 +41,7 @@ void Widget::set_size(unsigned w, unsigned h)
        geom.w = w;
        geom.h = h;
        on_geometry_change();
+       rebuild();
 }
 
 void Widget::autosize()
@@ -61,6 +61,7 @@ void Widget::set_geometry(const Geometry &g)
 {
        geom = g;
        on_geometry_change();
+       rebuild();
 }
 
 void Widget::set_parent(Container *p)
@@ -102,6 +103,7 @@ void Widget::update_style()
 
        on_style_change();
        signal_autosize_changed.emit();
+       rebuild();
 }
 
 void Widget::set_tooltip(const string &t)
@@ -137,6 +139,25 @@ void Widget::set_focus()
 void Widget::set_state(State mask, State bits)
 {
        state = (state&~mask)|bits;
+       rebuild();
+}
+
+void Widget::rebuild()
+{
+       if(!style)
+               return;
+
+       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)
+       {
+               if(j==cached_parts.end())
+                       j = cached_parts.insert(j, CachedPart());
+               if(i->get_name().empty())
+                       i->build(geom, state, *j);
+               else
+                       rebuild_special(*i, *j);
+       }
 }
 
 void Widget::render() const
@@ -144,20 +165,20 @@ void Widget::render() const
        if(!style)
                throw logic_error(format("Attempt to render a widget with null style (class=\"%s\", style_name=\"%s\")", get_class(), style_name));
 
-       GL::push_matrix();
-       GL::translate(geom.x, geom.y, 0);
+       GL::MatrixStack::Push _pushm(GL::MatrixStack::modelview());
+       GL::MatrixStack::modelview() *= GL::Matrix::translation(geom.x, geom.y, 0);
        const Style::PartSeq &parts = style->get_parts();
-       for(Style::PartSeq::const_iterator i=parts.begin(); i!=parts.end(); ++i)
+       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)
        {
-               if(i->get_name().empty())
+               if(j->mesh && j->texture)
                {
-                       GL::PushMatrix push_;
-                       i->render(geom, state);
+                       GL::Bind bind_tex(j->texture);
+                       j->mesh->draw();
                }
-               else
+               else if(!i->get_name().empty())
                        render_special(*i);
        }
-       GL::pop_matrix();
 }
 
 void Widget::pointer_enter()
index 9bdc2c0e13eba4a24eca88e585b577a2a706e996..ba49b09e44c90a5abd1644dbbd4f9f3ee276afdd 100644 (file)
@@ -4,6 +4,7 @@
 #include <string>
 #include <msp/datafile/objectloader.h>
 #include "geometry.h"
+#include "partcache.h"
 #include "state.h"
 
 namespace Msp {
@@ -48,6 +49,7 @@ protected:
        bool focusable;
        Container *parent;
        std::string tooltip;
+       std::list<CachedPart> cached_parts;
 
        Widget();
 public:
@@ -102,6 +104,9 @@ protected:
        void clear_state(State s) { set_state(s, NORMAL); }
        void set_state(State, State);
 
+       void rebuild();
+       virtual void rebuild_special(const Part &, CachedPart &) { }
+
 public:
        void render() const;
 protected: