/*
CGUITTFont FreeType class for Irrlicht
Copyright (c) 2009-2010 John Norman
+ Copyright (c) 2016 Nathanaƫl Courant
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
*/
#include <irrlicht.h>
+#include <iostream>
#include "CGUITTFont.h"
namespace irr
//
+/** Checks that no dimension of the FT_BitMap object is negative. If either is
+ * negative, abort execution.
+ */
+inline void checkFontBitmapSize(const FT_Bitmap &bits)
+{
+ if ((s32)bits.rows < 0 || (s32)bits.width < 0) {
+ std::cout << "Insane font glyph size. File: "
+ << __FILE__ << " Line " << __LINE__
+ << std::endl;
+ abort();
+ }
+}
+
video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
{
+ // Make sure our casts to s32 in the loops below will not cause problems
+ checkFontBitmapSize(bits);
+
// Determine what our texture size should be.
// Add 1 because textures are inclusive-exclusive.
core::dimension2du d(bits.width + 1, bits.rows + 1);
const u32 image_pitch = image->getPitch() / sizeof(u16);
u16* image_data = (u16*)image->lock();
u8* glyph_data = bits.buffer;
- for (s32 y = 0; y < bits.rows; ++y)
+
+ for (s32 y = 0; y < (s32)bits.rows; ++y)
{
u16* row = image_data;
- for (s32 x = 0; x < bits.width; ++x)
+ for (s32 x = 0; x < (s32)bits.width; ++x)
{
// Monochrome bitmaps store 8 pixels per byte. The left-most pixel is the bit 0x80.
// So, we go through the data each bit at a time.
const u32 image_pitch = image->getPitch() / sizeof(u32);
u32* image_data = (u32*)image->lock();
u8* glyph_data = bits.buffer;
- for (s32 y = 0; y < bits.rows; ++y)
+ for (s32 y = 0; y < (s32)bits.rows; ++y)
{
u8* row = glyph_data;
- for (s32 x = 0; x < bits.width; ++x)
+ for (s32 x = 0; x < (s32)bits.width; ++x)
{
image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
//data[y * image_pitch + x] |= ((u32)(*bitsdata++) << 24);
//////////////////////
-CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias, const bool transparency)
+CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias, const bool transparency, const u32 shadow, const u32 shadow_alpha)
{
if (!c_libraryLoaded)
{
return 0;
}
+ font->shadow_offset = shadow;
+ font->shadow_alpha = shadow_alpha;
+
return font;
}
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
+ draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
+}
+
+void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
+{
+ std::vector<video::SColor> colors = text.getColors();
+
if (!Driver)
return;
}
// Convert to a unicode string.
- core::ustring utext(text);
+ core::ustring utext = text.getString();
// Set up our render map.
core::map<u32, CGUITTGlyphPage*> Render_Map;
u32 n;
uchar32_t previousChar = 0;
core::ustring::const_iterator iter(utext);
+ std::vector<video::SColor> applied_colors;
while (!iter.atEnd())
{
uchar32_t currentChar = *iter;
n = getGlyphIndexByChar(currentChar);
bool visible = (Invisible.findFirst(currentChar) == -1);
- if (n > 0 && visible)
+ bool lineBreak=false;
+ if (currentChar == L'\r') // Mac or Windows breaks
{
- bool lineBreak=false;
- if (currentChar == L'\r') // Mac or Windows breaks
- {
- lineBreak = true;
- if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
- currentChar = *(++iter);
- }
- else if (currentChar == (uchar32_t)'\n') // Unix breaks
- {
- lineBreak = true;
- }
+ lineBreak = true;
+ if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks.
+ currentChar = *(++iter);
+ }
+ else if (currentChar == (uchar32_t)'\n') // Unix breaks
+ {
+ lineBreak = true;
+ }
- if (lineBreak)
- {
- previousChar = 0;
- offset.Y += font_metrics.ascender / 64;
- offset.X = position.UpperLeftCorner.X;
+ if (lineBreak)
+ {
+ previousChar = 0;
+ offset.Y += font_metrics.height / 64;
+ offset.X = position.UpperLeftCorner.X;
- if (hcenter)
- offset.X += (position.getWidth() - textDimension.Width) >> 1;
- ++iter;
- continue;
- }
+ if (hcenter)
+ offset.X += (position.getWidth() - textDimension.Width) >> 1;
+ ++iter;
+ continue;
+ }
+ if (n > 0 && visible)
+ {
// Calculate the glyph offset.
s32 offx = Glyphs[n-1].offset.X;
s32 offy = (font_metrics.ascender / 64) - Glyphs[n-1].offset.Y;
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
page->render_source_rects.push_back(glyph.source_rect);
Render_Map.set(glyph.glyph_page, page);
+ u32 current_color = iter.getPos();
+ if (current_color < colors.size())
+ applied_colors.push_back(colors[current_color]);
}
offset.X += getWidthFromCharacter(currentChar);
CGUITTGlyphPage* page = n->getValue();
- if (!use_transparency) color.color |= 0xff000000;
- Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, color, true);
+ if (shadow_offset) {
+ for (size_t i = 0; i < page->render_positions.size(); ++i)
+ page->render_positions[i] += core::vector2di(shadow_offset, shadow_offset);
+ Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, video::SColor(shadow_alpha,0,0,0), true);
+ for (size_t i = 0; i < page->render_positions.size(); ++i)
+ page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
+ }
+ for (size_t i = 0; i < page->render_positions.size(); ++i) {
+ irr::video::SColor col;
+ if (!applied_colors.empty()) {
+ col = applied_colors[i < applied_colors.size() ? i : 0];
+ } else {
+ col = irr::video::SColor(255, 255, 255, 255);
+ }
+ if (!use_transparency)
+ col.color |= 0xff000000;
+ Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
+ }
}
}