From 1aa6cd9b865e366737dcc9d2d36c4f8faed5bc4f Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 30 Nov 2012 22:21:55 +0200 Subject: [PATCH] Cache widget parts in meshes 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. --- source/button.cpp | 54 +++++++++++++++++++++---------------- source/button.h | 2 +- source/dropdown.cpp | 14 +++++++--- source/dropdown.h | 1 + source/entry.cpp | 63 ++++++++++++++++++++++++++------------------ source/entry.h | 2 ++ source/graphic.cpp | 27 +++++++++---------- source/graphic.h | 3 ++- source/hslider.cpp | 14 +++++----- source/hslider.h | 2 +- source/image.cpp | 41 ++++++++++++++++------------ source/image.h | 2 +- source/label.cpp | 7 +++-- source/label.h | 2 +- source/list.cpp | 59 ++++++++++++++++++++++++++++------------- source/list.h | 4 +++ source/part.cpp | 16 ++++++++--- source/part.h | 3 ++- source/partcache.cpp | 25 ++++++++++++++++++ source/partcache.h | 24 +++++++++++++++++ source/slider.cpp | 3 +++ source/table.cpp | 15 ++++++----- source/table.h | 2 +- source/text.cpp | 34 +++++++++++++++--------- source/text.h | 6 +++-- source/toggle.cpp | 7 +++-- source/toggle.h | 2 +- source/vslider.cpp | 14 +++++----- source/vslider.h | 2 +- source/widget.cpp | 41 +++++++++++++++++++++------- source/widget.h | 5 ++++ 31 files changed, 336 insertions(+), 160 deletions(-) create mode 100644 source/partcache.cpp create mode 100644 source/partcache.h diff --git a/source/button.cpp b/source/button.cpp index 5f9b18b..939d026 100644 --- a/source/button.cpp +++ b/source/button.cpp @@ -1,4 +1,4 @@ -#include +#include #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(); + } } } diff --git a/source/button.h b/source/button.h index 31009c7..e99f16b 100644 --- a/source/button.h +++ b/source/button.h @@ -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); diff --git a/source/dropdown.cpp b/source/dropdown.cpp index 47496f4..c2ceefa 100644 --- a/source/dropdown.cpp +++ b/source/dropdown.cpp @@ -36,6 +36,8 @@ void Dropdown::autosize() unsigned line_height = static_cast((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(); } diff --git a/source/dropdown.h b/source/dropdown.h index ece84ba..4af5a5f 100644 --- a/source/dropdown.h +++ b/source/dropdown.h @@ -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: diff --git a/source/entry.cpp b/source/entry.cpp index a0df8cb..ca185be 100644 --- a/source/entry.cpp +++ b/source/entry.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include #include #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+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_pos0) - { - 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::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) diff --git a/source/entry.h b/source/entry.h index 058ef3f..968e399 100644 --- a/source/entry.h +++ b/source/entry.h @@ -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); diff --git a/source/graphic.cpp b/source/graphic.cpp index 005d30f..0b0ba0e 100644 --- a/source/graphic.cpp +++ b/source/graphic.cpp @@ -1,4 +1,3 @@ -#include #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 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 &coords) const diff --git a/source/graphic.h b/source/graphic.h index 81ad669..f457d36 100644 --- a/source/graphic.h +++ b/source/graphic.h @@ -1,6 +1,7 @@ #ifndef MSP_GLTK_GRAPHIC_H_ #define MSP_GLTK_GRAPHIC_H_ +#include #include #include #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 &) const; void create_texcoords(float, float, float, float, float, std::vector &) const; diff --git a/source/hslider.cpp b/source/hslider.cpp index 18a163c..fbd9b94 100644 --- a/source/hslider.cpp +++ b/source/hslider.cpp @@ -1,5 +1,5 @@ #include -#include +#include #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); } } diff --git a/source/hslider.h b/source/hslider.h index a94e8bc..9545c22 100644 --- a/source/hslider.h +++ b/source/hslider.h @@ -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); diff --git a/source/image.cpp b/source/image.cpp index bff7904..a2d4426 100644 --- a/source/image.cpp +++ b/source/image.cpp @@ -1,6 +1,4 @@ -#include -#include -#include +#include #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(); } } diff --git a/source/image.h b/source/image.h index 5f6b935..064a6c9 100644 --- a/source/image.h +++ b/source/image.h @@ -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 diff --git a/source/label.cpp b/source/label.cpp index 3805eaf..f9274b4 100644 --- a/source/label.cpp +++ b/source/label.cpp @@ -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() diff --git a/source/label.h b/source/label.h index a61776e..9a0d1f2 100644 --- a/source/label.h +++ b/source/label.h @@ -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(); }; diff --git a/source/list.cpp b/source/list.cpp index a886118..19559d1 100644 --- a/source/list.cpp +++ b/source/list.cpp @@ -1,6 +1,5 @@ -#include #include -#include +#include #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(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(row_height), 0); - Text(*style, items[first+i]).render(part, pgeom); + bld.matrix() *= GL::Matrix::translation(0, -static_cast(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(value); + rebuild(); + } } diff --git a/source/list.h b/source/list.h index 56fe6aa..2970bb4 100644 --- a/source/list.h +++ b/source/list.h @@ -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: diff --git a/source/part.cpp b/source/part.cpp index 1273979..7037d4b 100644 --- a/source/part.cpp +++ b/source/part.cpp @@ -1,6 +1,7 @@ -#include +#include #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); } diff --git a/source/part.h b/source/part.h index b4ada58..c35969d 100644 --- a/source/part.h +++ b/source/part.h @@ -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 index 0000000..e270dc4 --- /dev/null +++ b/source/partcache.cpp @@ -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 index 0000000..b856f9d --- /dev/null +++ b/source/partcache.h @@ -0,0 +1,24 @@ +#ifndef MSP_GLTK_PARTCACHE_H_ +#define MSP_GLTK_PARTCACHE_H_ + +#include +#include + +namespace Msp { +namespace GLtk { + +struct CachedPart +{ + const GL::Texture2D *texture; + GL::Mesh *mesh; + + CachedPart(); + ~CachedPart(); + + void clear_mesh(); +}; + +} // namespace GLtk +} // namespace Msp + +#endif diff --git a/source/slider.cpp b/source/slider.cpp index de4d12e..dc8a28a 100644 --- a/source/slider.cpp +++ b/source/slider.cpp @@ -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() diff --git a/source/table.cpp b/source/table.cpp index 1fe6961..32db6c4 100644 --- a/source/table.cpp +++ b/source/table.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #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 #include +#include #include +#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(part, parent, first_row, data); + process_lines(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); } diff --git a/source/text.h b/source/text.h index 077558b..dc5710b 100644 --- a/source/text.h +++ b/source/text.h @@ -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 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; }; diff --git a/source/toggle.cpp b/source/toggle.cpp index f2cf552..789ae37 100644 --- a/source/toggle.cpp +++ b/source/toggle.cpp @@ -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) diff --git a/source/toggle.h b/source/toggle.h index b6195e1..fd7e762 100644 --- a/source/toggle.h +++ b/source/toggle.h @@ -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); diff --git a/source/vslider.cpp b/source/vslider.cpp index 93e485a..a32e484 100644 --- a/source/vslider.cpp +++ b/source/vslider.cpp @@ -1,5 +1,5 @@ #include -#include +#include #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); } } diff --git a/source/vslider.h b/source/vslider.h index e405599..c6d6a6f 100644 --- a/source/vslider.h +++ b/source/vslider.h @@ -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); diff --git a/source/widget.cpp b/source/widget.cpp index b10b6b5..4b48e8b 100644 --- a/source/widget.cpp +++ b/source/widget.cpp @@ -1,6 +1,4 @@ -#include #include -#include #include #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::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::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() diff --git a/source/widget.h b/source/widget.h index 9bdc2c0..ba49b09 100644 --- a/source/widget.h +++ b/source/widget.h @@ -4,6 +4,7 @@ #include #include #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 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: -- 2.43.0