commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
93
include/framework/font/font_cache.cpp
Normal file
93
include/framework/font/font_cache.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "font/font_cache.h"
|
||||
#include "font/font_extended.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FontEx *FontCache::GetFont(const char *name) const
|
||||
{
|
||||
ListForeachPtr(FontAlias *, alias, font_aliases)
|
||||
if (alias->font->GetName() == name)
|
||||
return alias->font;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
FontAlias *FontCache::GetAlias(const char *alias) const
|
||||
{
|
||||
ListForeachPtr(FontAlias *, font, font_aliases)
|
||||
if (font->alias == alias)
|
||||
return font;
|
||||
return NULL;
|
||||
}
|
||||
FontEx *FontCache::GetAliasedFont(const char *alias) const
|
||||
{
|
||||
FontAlias *fa = GetAlias(alias);
|
||||
return fa ? fa->font.c_ptr() : NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FontEx *FontCache::LoadFont(const char *path, const char *alias)
|
||||
{
|
||||
// Look for an already loaded instance of the font.
|
||||
FontEx *font = GetFont(path);
|
||||
|
||||
// If font is not available, load it.
|
||||
if (font == NULL)
|
||||
{
|
||||
IFont *base_font = font_factory->LoadFont(path);
|
||||
if (base_font == NULL)
|
||||
return NULL;
|
||||
|
||||
// Wrap with an extended font.
|
||||
font = new FontEx(base_font);
|
||||
}
|
||||
|
||||
// Format default alias if none provided.
|
||||
String _alias(path);
|
||||
_alias.FileCutPathAndExtension();
|
||||
if (!alias)
|
||||
alias = _alias;
|
||||
|
||||
// Drop current alias if existing.
|
||||
FontAlias *font_alias = GetAlias(alias);
|
||||
if (font_alias)
|
||||
font_aliases.Remove(font_alias);
|
||||
|
||||
// Create the alias.
|
||||
font_alias = new FontAlias;
|
||||
font_alias->alias = alias;
|
||||
font_alias->font = font;
|
||||
|
||||
font_aliases.Add(font_alias);
|
||||
|
||||
__LOG__ << "Created a new font alias from '" << path << "' to '" << alias << "'.\n";
|
||||
return font;
|
||||
}
|
||||
void FontCache::DeleteAlias(const char *alias)
|
||||
{
|
||||
ListForeachPtr(FontAlias *, a, font_aliases)
|
||||
if (a->alias == alias)
|
||||
font_aliases.Remove(a);
|
||||
}
|
||||
void FontCache::DeleteAllFont()
|
||||
{
|
||||
font_aliases.Clear();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
FontCache::~FontCache()
|
||||
{
|
||||
// [EJ] Get rid of the fonts before the factory.
|
||||
DeleteAllFont();
|
||||
}
|
||||
47
include/framework/font/font_extended.cpp
Normal file
47
include/framework/font/font_extended.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "font/font_extended.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool FontEx::SetPixelSize(int size)
|
||||
{
|
||||
pixel_size = size;
|
||||
return current_glyph_font.IsValid() ? current_glyph_font->SetPixelSize(size) : font->SetPixelSize(size);
|
||||
}
|
||||
bool FontEx::HasKerning() const
|
||||
{ return current_glyph_font.IsValid() ? current_glyph_font->HasKerning() : font->HasKerning(); }
|
||||
int FontEx::GetKerning(uint previous_codepoint, uint codepoint) const
|
||||
{ return current_glyph_font.IsValid() ? current_glyph_font->GetKerning(previous_codepoint, codepoint) : font->GetKerning(previous_codepoint, codepoint); }
|
||||
|
||||
int FontEx::GetHeight() const
|
||||
{ return current_glyph_font.IsValid() ? current_glyph_font->GetHeight() : font->GetHeight(); }
|
||||
int FontEx::GetAdvance() const
|
||||
{ return current_glyph_font.IsValid() ? current_glyph_font->GetAdvance() : font->GetAdvance(); }
|
||||
|
||||
bool FontEx::LoadGlyph(uint codepoint, bool for_render)
|
||||
{
|
||||
current_glyph_font = font;
|
||||
if (font->LoadGlyph(codepoint, for_render))
|
||||
return true;
|
||||
|
||||
// Synchronize and try fallback.
|
||||
if (fallback.IsNull())
|
||||
return false;
|
||||
|
||||
fallback->SetPixelSize(pixel_size);
|
||||
bool r = fallback->LoadGlyph(codepoint, for_render);
|
||||
|
||||
if (r)
|
||||
current_glyph_font = fallback;
|
||||
return r;
|
||||
}
|
||||
bool FontEx::RenderCurrentGlyph(Picture &picture, const iPoint &position, const iRect &clip, const Color &color)
|
||||
{ return current_glyph_font.IsValid() ? current_glyph_font->RenderCurrentGlyph(picture, position, clip, color) : font->RenderCurrentGlyph(picture, position, clip, color); }
|
||||
//------------------------------------------------------------------------------
|
||||
377
include/framework/font/font_renderer.cpp
Normal file
377
include/framework/font/font_renderer.cpp
Normal file
@ -0,0 +1,377 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include "font/font_renderer.h"
|
||||
#include "picture/pict.h"
|
||||
#include "ascii/parser.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::AsciiParser;
|
||||
|
||||
float FontRenderer::default_text_tracking = 0;
|
||||
float FontRenderer::default_text_heading = 0;
|
||||
|
||||
//
|
||||
struct GS::SubString
|
||||
{
|
||||
const char *entry;
|
||||
int char_count;
|
||||
int space_count;
|
||||
int width; // 26.6
|
||||
int height;
|
||||
|
||||
void Reset(const char *string)
|
||||
{
|
||||
entry = string;
|
||||
char_count = 0;
|
||||
space_count = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
};
|
||||
|
||||
int substring_count = 0;
|
||||
SubString substring_array[1024];
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *FontRenderer::CheckCommand(const char *string, Command &command)
|
||||
{
|
||||
command.code = CommandNone;
|
||||
if (!string[0] || !string[1])
|
||||
return string;
|
||||
|
||||
if ((string[0] == '~') && (string[1] == '~'))
|
||||
{
|
||||
//----------------------------------------------------------------------
|
||||
#define PARSE_COMPONENT(_C_, _M_)\
|
||||
{\
|
||||
string = SkipSpace(string + 1, eos);\
|
||||
command.vector._C_ = (float)String::atoi(string);\
|
||||
string = NextEntry(string, eos);\
|
||||
if (string[0] != (_M_))\
|
||||
{\
|
||||
command.code = CommandParseError;\
|
||||
__LOG_E__ << "Error parsing text command components.\n";\
|
||||
return NULL;\
|
||||
}\
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
const char *eos = string + std::strlen(string);
|
||||
|
||||
if (!strncmp("Color(", string + 2, 6) || !strncmp("COLOR(", string + 2, 6)) // [EJ] 1st may: range is [0;255]
|
||||
{
|
||||
command.code = CommandColor;
|
||||
string += 7;
|
||||
|
||||
const char *eop = Find(string, eos, ')');
|
||||
if (!eop)
|
||||
{
|
||||
command.code = CommandParseError;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PARSE_COMPONENT(x, ',');
|
||||
PARSE_COMPONENT(y, ',');
|
||||
PARSE_COMPONENT(z, ',');
|
||||
PARSE_COMPONENT(w, ')');
|
||||
string = eop + 1;
|
||||
}
|
||||
else if (!strncmp("Size(", string + 2, 5) || !strncmp("SIZE(", string + 2, 5))
|
||||
{
|
||||
command.code = CommandSize;
|
||||
|
||||
string += 6;
|
||||
|
||||
const char *eop = Find(string, eos, ')');
|
||||
if (!eop)
|
||||
{
|
||||
command.code = CommandParseError;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PARSE_COMPONENT(x, ')');
|
||||
string = eop + 1;
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
const char *FontRenderer::FetchSubString(const char *string, SubString &substring, TextState &state, int max_width, int max_char)
|
||||
{
|
||||
if (!string)
|
||||
return NULL;
|
||||
|
||||
// Jump over leading spaces.
|
||||
forever
|
||||
{
|
||||
if (string[0] != ' ')
|
||||
break;
|
||||
|
||||
if (!string[0] || (string[0] == '\n'))
|
||||
{
|
||||
substring.Reset(NULL);
|
||||
return string;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
|
||||
// Start sub-string.
|
||||
substring.Reset(string);
|
||||
int previous_codepoint = 0;
|
||||
|
||||
state.font->SetPixelSize(state.GetSize());
|
||||
max_width <<= 6;
|
||||
|
||||
// Word cut point.
|
||||
bool rollback_available = false;
|
||||
SubString rollback_substring;
|
||||
const char *rollback_string = NULL;
|
||||
|
||||
int tracking = int(state.GetTracking() * 64.f);
|
||||
|
||||
forever
|
||||
{
|
||||
Command command;
|
||||
if ((string = CheckCommand(string, command)) == 0)
|
||||
break;
|
||||
|
||||
if (command.code == CommandNone)
|
||||
{
|
||||
if (string[0] == '\n')
|
||||
{
|
||||
string++;
|
||||
break;
|
||||
}
|
||||
if ((string[0] == '\\') && (string[1] == 'n'))
|
||||
{
|
||||
string += 2;
|
||||
break;
|
||||
}
|
||||
if (string[0] == 0)
|
||||
break;
|
||||
if ((max_char > 0) && (substring.char_count == max_char))
|
||||
break;
|
||||
|
||||
// Get glyph.
|
||||
uint codepoint;
|
||||
int codelength = String::Utf8toUtf32((const uchar *)string, &codepoint);
|
||||
|
||||
state.font->LoadGlyph(codepoint, false);
|
||||
|
||||
// Retrieve glyph formatting informations.
|
||||
int advance = state.font->GetAdvance();
|
||||
int kerning = (state.font->HasKerning() && (previous_codepoint != 0)) ? state.font->GetKerning(previous_codepoint, codepoint) : 0;
|
||||
|
||||
// Width constraint.
|
||||
if ((max_width > 0) && ((substring.width + advance) >= max_width))
|
||||
{
|
||||
rollback_available = true;
|
||||
break;
|
||||
}
|
||||
|
||||
substring.width += advance + kerning + tracking;
|
||||
substring.height = Types::Max(state.font->GetHeight(), substring.height);
|
||||
|
||||
// Count space.
|
||||
if (string[0] == ' ')
|
||||
{
|
||||
substring.space_count++;
|
||||
|
||||
// Store the word rollback position.
|
||||
Command dummy_command;
|
||||
CheckCommand(string, dummy_command);
|
||||
|
||||
if ((dummy_command.code == CommandNone) && (string[1] != ' '))
|
||||
{
|
||||
rollback_substring = substring;
|
||||
rollback_string = string;
|
||||
}
|
||||
}
|
||||
substring.char_count++;
|
||||
|
||||
// Next glyph.
|
||||
string += codelength ? codelength : 1;
|
||||
previous_codepoint = codepoint;
|
||||
}
|
||||
else
|
||||
switch (command.code)
|
||||
{
|
||||
case CommandColor: // Irrelevant when not composing.
|
||||
break;
|
||||
|
||||
case CommandSize:
|
||||
state.SetSize((int)command.vector.x);
|
||||
state.font->SetPixelSize(state.GetSize());
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rollback to the last word position.
|
||||
if (rollback_available && rollback_string)
|
||||
{
|
||||
substring = rollback_substring;
|
||||
string = rollback_string;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void FontRenderer::DrawSubString(SubString &line, Picture &output, TextState &state, const iRect &_out_rect, const iRect &clip_rect, int justification)
|
||||
{
|
||||
const char *string = line.entry;
|
||||
state.font->SetPixelSize(state.GetSize());
|
||||
|
||||
iRect out_rect(_out_rect);
|
||||
uint previous_codepoint = 0;
|
||||
|
||||
int tracking = int(state.GetTracking() * 64.f);
|
||||
|
||||
for (int n = 0; n < line.char_count; ++n)
|
||||
{
|
||||
Command command;
|
||||
string = CheckCommand(string, command);
|
||||
|
||||
if (command.code == CommandNone)
|
||||
{
|
||||
// Get glyph.
|
||||
uint codepoint;
|
||||
int codelength = String::Utf8toUtf32((const uchar *)string, &codepoint);
|
||||
|
||||
state.font->LoadGlyph(codepoint, true);
|
||||
|
||||
// Retrieve glyph formatting informations.
|
||||
int advance = state.font->GetAdvance();
|
||||
int kerning = (state.font->HasKerning() && (previous_codepoint != 0)) ? state.font->GetKerning(previous_codepoint, codepoint) : 0;
|
||||
|
||||
// Render.
|
||||
int px = out_rect.sx >> 6;
|
||||
int py = (out_rect.sy + (line.height * 3) / 4) >> 6; // FIXME smells the hack... at best!
|
||||
|
||||
state.font->RenderCurrentGlyph(output, iPoint(px, py), clip_rect, state.color);
|
||||
|
||||
out_rect.sx += advance + kerning + tracking;
|
||||
|
||||
// Next glyph.
|
||||
string += codelength;
|
||||
previous_codepoint = codepoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.code)
|
||||
{
|
||||
case CommandColor:
|
||||
state.color = command.vector ;/// 255.f;
|
||||
break;
|
||||
|
||||
case CommandSize:
|
||||
state.SetSize((int)command.vector.x);
|
||||
state.font->SetPixelSize(state.GetSize());
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
--n;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
iRect FontRenderer::Format(const char *txt, const TextState &in_state, const iRect &out_rect)
|
||||
{
|
||||
if (!in_state.font)
|
||||
return iRect (0, 0, 0, 0);
|
||||
|
||||
// Create working state.
|
||||
TextState state = in_state;
|
||||
|
||||
// Setup formatting rules.
|
||||
int max_width = (state.format == TextState::Line) ? -1 : out_rect.GetWidth(),
|
||||
max_char = (state.format != TextState::Column) ? -1 : state.column_width;
|
||||
|
||||
// Fetch all substrings.
|
||||
substring_count = 0;
|
||||
while (txt && txt[0])
|
||||
txt = FetchSubString(txt, substring_array[substring_count++], state, max_width, max_char);
|
||||
|
||||
// Create full text rectangle.
|
||||
iRect text_rect;
|
||||
text_rect.Set(0, 0, 0, 0);
|
||||
|
||||
int leading = int(state.GetLeading() * 64);
|
||||
|
||||
for (int n = 0; n < substring_count; ++n)
|
||||
{
|
||||
if (text_rect.ex < substring_array[n].width)
|
||||
text_rect.ex = substring_array[n].width;
|
||||
text_rect.ey += substring_array[n].height + leading;
|
||||
}
|
||||
if (substring_count > 0)
|
||||
text_rect.ey -= leading;
|
||||
|
||||
text_rect.ex = text_rect.ex / 64;
|
||||
text_rect.ey = text_rect.ey / 64;
|
||||
return text_rect;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
iRect FontRenderer::Compose(Picture &output, const char *txt, const TextState &in_state, const iRect &out_rect, const iRect &clip_rect)
|
||||
{
|
||||
if (in_state.font.IsNull() || (output.GetPixelFormat().GetBpp() != 32))
|
||||
return iRect(0, 0, 0, 0);
|
||||
|
||||
// Create working state.
|
||||
TextState state = in_state;
|
||||
int leading = int(state.GetLeading() * 64);
|
||||
|
||||
// Draw substrings.
|
||||
iRect work_out_rect(out_rect * 64);
|
||||
|
||||
for (int n = 0; n < substring_count; ++n)
|
||||
{
|
||||
iRect line_rect(work_out_rect);
|
||||
line_rect.ex = line_rect.sx + substring_array[n].width;
|
||||
|
||||
int offset = 0, justification = 0;
|
||||
|
||||
switch (state.alignment)
|
||||
{
|
||||
case TextState::Left:
|
||||
offset = out_rect.sx * 64 - line_rect.sx;
|
||||
break;
|
||||
case TextState::Center:
|
||||
offset = (out_rect.GetWidth() * 64 - line_rect.GetWidth()) / 2;
|
||||
break;
|
||||
case TextState::Right:
|
||||
offset = out_rect.ex * 64 - line_rect.ex;
|
||||
break;
|
||||
|
||||
case TextState::Justify:
|
||||
if (n < (substring_count - 1))
|
||||
justification = (out_rect.GetWidth() * 64 - line_rect.GetWidth()) / substring_array[n].space_count;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
line_rect.sx += offset;
|
||||
|
||||
DrawSubString(substring_array[n], output, state, line_rect, clip_rect, justification);
|
||||
work_out_rect.sy += substring_array[n].height + leading;
|
||||
}
|
||||
return out_rect;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user