void draw_text(const fvec2 &pos, const fvec2 &size, const std::string &text, HAlignment halign, VAlignment valign) { std::vector<unsigned> tt; for (int i = 0; text[i]; i++) { if (text[i] & 0x80) { if ((text[i] & 0xe0) == 0xc0) { if ((text[i + 1] & 0xc0) == 0x80) { unsigned v = ((text[i] & 0x1f) << 6) | (text[i + 1] & 0x3f); ++i; if (v < 256) { tt.push_back(v); } else { tt.push_back(0); } } else { tt.push_back(0); } } else { tt.push_back(0); } } else { tt.push_back(text[i]); } } if (tt.size() > 64) { throw std::invalid_argument("Text is too long"); } CharVAElement *cvad = static_cast<CharVAElement *>(char_va->attrib(0)->map()); for (int i = 0; i < static_cast<int>(tt.size()); i++) { for (int j = 0; j < 5; j++) { cvad[i * 5 + j].chr = tt[i]; } } char_va->attrib(0)->unmap(); char_va->attrib(1)->load(sizeof(CharVAElement), offsetof(CharVAElement, chr)); fvec2 position = pos; switch (halign) { case ALIGN_LEFT: break; case ALIGN_CENTER: position.x() -= tt.size() * size.x() / 2.f; break; case ALIGN_RIGHT: position.x() -= tt.size() * size.x(); break; default: throw std::invalid_argument("draw_text(): Invalid value given for halign"); } switch (valign) { case ALIGN_TOP: position.y() -= size.y() / 2.f; break; case ALIGN_MIDDLE: break; case ALIGN_BOTTOM: position.y() += size.y() / 2.f; break; default: throw std::invalid_argument("draw_text(): Invalid value given for valign"); } char_prg->use(); font[olo]->bind(); static gl::texture *last_font; if (last_font != font[olo]) { last_font = font[olo]; char_prg->uniform<gl::texture>("font") = *font[olo]; } char_prg->uniform<fvec2>("position") = position; char_prg->uniform<fvec2>("char_size") = size; char_prg->uniform<fvec2>("font_char_fill_ratio") = font_fr[olo]; char_va->set_elements(tt.size() * 5); char_va->draw(GL_TRIANGLE_STRIP); }
inline fvec2 max(const fvec2& a, float b) { return fvec2( a.x() > b ? a.x() : b, a.y() > b ? a.y() : b); }
inline fvec2 max(const fvec2& a, const fvec2& b) { return fvec2( a.x() > b.x() ? a.x() : b.x(), a.y() > b.y() ? a.y() : b.y()); }
inline fvec2 min(const fvec2& a, float b) { return fvec2( a.x() < b ? a.x() : b, a.y() < b ? a.y() : b); }
inline fvec2 min(const fvec2& a, const fvec2& b) { return fvec2( a.x() < b.x() ? a.x() : b.x(), a.y() < b.y() ? a.y() : b.y()); }
inline float dot(const fvec2& v1, const fvec2& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }