-#include <msp/gl/immediate.h>
+#include <msp/gl/meshbuilder.h>
#include "button.h"
#include "part.h"
#include "style.h"
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();
+ }
}
}
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);
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)
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();
}
int get_selected_index() const;
private:
+ virtual void rebuild_special(const Part &, CachedPart &);
virtual void render_special(const Part &) const;
public:
#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"
check_view_range();
}
+
+ rebuild();
}
void Entry::set_text(const string &t)
if(multiline)
check_view_range();
+
+ rebuild();
}
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();
}
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)
{
{
text.erase(--edit_pos, 1);
check_view_range();
+ rebuild();
}
}
else if(key==Input::KEY_ENTER)
{
text.insert(edit_pos++, "\n");
check_view_range();
+ rebuild();
}
else
signal_enter.emit();
{
text.insert(edit_pos, StringCodec::encode<StringCodec::Utf8>(StringCodec::ustring(1, ch)));
++edit_pos;
+ rebuild();
}
}
check_view_range();
}
+void Entry::set_edit_position(unsigned ep)
+{
+ edit_pos = ep;
+ check_view_range();
+ rebuild();
+}
+
void Entry::reposition_slider()
{
if(!style || !slider)
bool is_multiline() const { return multiline; }
private:
+ virtual void rebuild_special(const Part &, CachedPart &);
virtual void render_special(const Part &) const;
public:
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);
-#include <msp/gl/immediate.h>
#include "graphic.h"
#include "resources.h"
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);
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
#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"
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;
#include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
#include "graphic.h"
#include "hslider.h"
#include "part.h"
}
}
-void HSlider::render_special(const Part &part) const
+void HSlider::rebuild_special(const Part &part, CachedPart &cache)
{
if(part.get_name()=="slider")
{
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);
}
}
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);
-#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"
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();
}
}
- 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();
}
}
void set_keep_aspect(bool);
private:
- virtual void render_special(const Part &) const;
+ virtual void rebuild_special(const Part &, CachedPart &);
};
} // namespace GLtk
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()
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();
};
-#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"
}
check_view_range();
+ rebuild();
}
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)
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)
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)
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")
{
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")
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();
}
sel_index = first+i;
signal_item_selected.emit(sel_index, items[sel_index]);
+ rebuild();
}
}
}
void List::slider_value_changed(double value)
{
if(items.size()>n_visible)
+ {
first = items.size()-n_visible-static_cast<unsigned>(value);
+ rebuild();
+ }
}
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);
int get_selected_index() const { return sel_index; }
private:
+ virtual void rebuild_special(const Part &, CachedPart &);
virtual void render_special(const Part &) const;
public:
-#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;
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);
}
namespace Msp {
namespace GLtk {
+class CachedPart;
class Graphic;
class Resources;
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
--- /dev/null
+#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
--- /dev/null
+#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
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()
#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"
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")
{
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;
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;
}
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();
};
-#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"
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)
}
}
-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);
}
namespace Msp {
namespace GLtk {
+class CachedPart;
class Geometry;
class Part;
class Style;
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:
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;
};
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)
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)
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);
#include <msp/gl/matrix.h>
-#include <msp/gl/transform.h>
+#include <msp/gl/meshbuilder.h>
#include "graphic.h"
#include "part.h"
#include "style.h"
}
}
-void VSlider::render_special(const Part &part) const
+void VSlider::rebuild_special(const Part &part, CachedPart &cache)
{
if(part.get_name()=="slider")
{
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);
}
}
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);
-#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"
geom.x = x;
geom.y = y;
on_geometry_change();
+ rebuild();
}
void Widget::set_size(unsigned w, unsigned h)
geom.w = w;
geom.h = h;
on_geometry_change();
+ rebuild();
}
void Widget::autosize()
{
geom = g;
on_geometry_change();
+ rebuild();
}
void Widget::set_parent(Container *p)
on_style_change();
signal_autosize_changed.emit();
+ rebuild();
}
void Widget::set_tooltip(const string &t)
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
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()
#include <string>
#include <msp/datafile/objectloader.h>
#include "geometry.h"
+#include "partcache.h"
#include "state.h"
namespace Msp {
bool focusable;
Container *parent;
std::string tooltip;
+ std::list<CachedPart> cached_parts;
Widget();
public:
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: