/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #include "gpu/gpu_renderer.h" #include "gpu/gpu_triangle_batch.h" #include "core/raster_font.h" #include "log/log.h" using namespace GS; using namespace GS::GPU; //------------------------------------------------------------------------------ void Renderer::Write(const Render::RasterFont &f, const char *t, float &x, float &y, const WriterConfig &config, float s, const Color *c, WriterAlignment a, bool mirrored) { Render::Texture *page = f.GetPage(0); if (!page) __ERRRAW__(__LOG_E__ << "No glyph page in raster font '" << f.name << "'.\n") float scale_width = s; if(mirrored) scale_width = -s; // Aspect ratio, texel/pixel mapping. float ar = config.correct_ar ? viewport.GetHeight() / viewport.GetWidth() : 1.f; // w / h Vector2 glyph_mapping((float)page->GetWidth() / viewport.GetWidth(), (float)page->GetHeight() / viewport.GetHeight()), pixel_mapping(1.f / viewport.GetWidth(), 1.f / viewport.GetHeight()); if (!config.normalized) { x *= pixel_mapping.x; y *= pixel_mapping.y; y = floor(y * viewport.GetHeight()) / viewport.GetHeight(); // Stay on a pixel boundary. } float in_x = x; Vector4 vtx[4]; Vector2 uv[4]; Color col[4]; for (uint n = 0; n < 4; ++n) col[n] = c ? *c : Color(1, 1, 1, 1); // Draw glyphs. Render::Texture *t_page = NULL; bool aligned = false; TriangleBatch batch(*this); for ( ; t[0]; ++t) { // Catch line feed. if (t[0] == '\n') { x = in_x; if (config.normalized) y += f.GetHeight() * s; else { y += f.GetHeight() * glyph_mapping.y * s; y = floor(y * viewport.GetHeight()) / viewport.GetHeight(); // Avoid float drift, stay on pixel boundary. } aligned = false; continue; } // Compute alignment. if (!aligned) { switch (a) { case AlignMiddle: if (config.normalized) x -= f.ComputeLineRect(t).x * scale_width * 0.5f * ar; else x -= f.ComputeLineRect(t).x * scale_width * 0.5f * glyph_mapping.x; break; case AlignRight: if (config.normalized) x -= f.ComputeLineRect(t).x * scale_width * ar; else x -= f.ComputeLineRect(t).x * scale_width * glyph_mapping.x; break; default: break; } // Make sure we stay as close as possible to a pixel boundary for non-normalized modes. if (!config.normalized) x = floor(x * viewport.GetWidth()) / viewport.GetWidth(); aligned = true; } // Output glyph. if (const Render::RasterFont::Glyph *glyph = f.GetGlyphInfos(t[0])) { if ((t_page = f.GetPage(glyph->page)) != NULL) { float _x, _y, _w, _h; if (config.normalized) { _x = x * 2.f - 1.f + glyph->offx * 1.f * scale_width; _y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * s; _w = glyph->w * 2.f * scale_width * ar; _h = glyph->h * 2.f * s; _x *= GetGlobalAspectRatio(); _w *= GetGlobalAspectRatio(); } else { _x = x * 2.f - 1.f + glyph->offx * 2.f * glyph_mapping.x * scale_width; _y = (1.f - y) * 2.f - 1.f - glyph->offy * 2.f * glyph_mapping.y * s; _w = glyph->w * 2.f * glyph_mapping.x * scale_width; _h = glyph->h * 2.f * glyph_mapping.y * s; } vtx[0].Set(_x, _y, 0.5); vtx[1].Set(_x + _w, _y, 0.5); vtx[2].Set(_x + _w, _y - _h, 0.5); vtx[3].Set(_x, _y - _h, 0.5); uv[0].Set(glyph->u, glyph->v); uv[1].Set(glyph->u + glyph->w, glyph->v); uv[2].Set(glyph->u + glyph->w, glyph->v + glyph->h); uv[3].Set(glyph->u, glyph->v + glyph->h); const ushort indice[] = { 0, 1, 2, 0, 2, 3 }; // order is reversed because the quad is drawn from the baseline (bottom to top) batch.DrawTriangle(2, 4, vtx, indice, col, uv, t_page, Core::Material::Blend_Alpha, (Core::Material::RenderWord)(Core::Material::Render_NoZTest | Core::Material::Render_NoZWrite | Core::Material::Render_DoubleSided)); } if (config.normalized) x += glyph->step * scale_width * ar; else x += glyph->step * glyph_mapping.x * scale_width; } } batch.Flush(); if (!config.normalized) { x /= pixel_mapping.x; y /= pixel_mapping.y; } } //------------------------------------------------------------------------------