mirror of https://github.com/axmolengine/axmol.git
Port my variant of font-rendering over to dev branch -- adds correct alignment behavior.
This commit is contained in:
parent
a8ac892c0b
commit
0287f273e0
|
@ -89,33 +89,58 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool divideString(TTF_Font *face, const char* sText, int iMaxWidth, int iMaxHeight) {
|
bool divideString(TTF_Font *face, const char* sText, int iMaxWidth, int iMaxHeight) {
|
||||||
const char* pText = sText;
|
|
||||||
|
|
||||||
//init stringstream
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
|
||||||
while (*pText != '\0') {
|
// if there is no maximum width specified, just slam the whole input
|
||||||
if (*pText == '\n') {
|
// string into a single line, thereby avoiding many expensive calls to
|
||||||
buildLine(ss, face);
|
// compute font metrics.
|
||||||
|
if(iMaxWidth == 0)
|
||||||
|
{
|
||||||
|
std::string text = sText;
|
||||||
|
ss << text;
|
||||||
|
buildLine(ss, face);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pText++;
|
std::vector<std::string> words;
|
||||||
|
std::string text = sText;
|
||||||
|
std::istringstream iss(text);
|
||||||
|
copy(std::istream_iterator<std::string>(iss),
|
||||||
|
std::istream_iterator<std::string>(),
|
||||||
|
std::back_inserter< vector<string> >(words));
|
||||||
|
|
||||||
|
for(std::vector<string>::iterator i = words.begin(); i != words.end(); ++i)
|
||||||
|
{
|
||||||
|
// Specially handle the case where a single word exceeds the
|
||||||
|
// available width.
|
||||||
|
TTF_SizeText(face, i->c_str(), &w, &h);
|
||||||
|
if(w > iMaxWidth)
|
||||||
|
{
|
||||||
|
buildLine(ss, face);
|
||||||
|
for(std::string::iterator c = i->begin(); c != i->end(); ++c)
|
||||||
|
{
|
||||||
|
ss << *c;
|
||||||
|
TTF_SizeText(face, ss.str().c_str(), &w, &h);
|
||||||
|
if(w > iMaxWidth)
|
||||||
|
{
|
||||||
|
buildLine(ss, face);
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check its width
|
|
||||||
//divide it when exceeding
|
|
||||||
std::string s = ss.str();
|
|
||||||
s.push_back(*pText);
|
|
||||||
TTF_SizeText(face, s.c_str(), &w, &h);
|
|
||||||
|
|
||||||
if (iMaxWidth > 0 && (w > iMaxWidth)) {
|
std::string tmp = ss.str() + std::string(" ") + *i;
|
||||||
|
TTF_SizeText(face, tmp.c_str(), &w, &h);
|
||||||
|
if(w > iMaxWidth)
|
||||||
|
{
|
||||||
buildLine(ss, face);
|
buildLine(ss, face);
|
||||||
|
ss << *i;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ss << " " << *i;
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << *pText;
|
|
||||||
pText++;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildLine(ss, face);
|
buildLine(ss, face);
|
||||||
|
@ -130,54 +155,55 @@ public:
|
||||||
* while -1 means fail
|
* while -1 means fail
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int computeLineStart(TTF_Font *face, Image::TextAlign eAlignMask, char cText,
|
int computeLineStart(Image::TextAlign eAlignMask, int lineWidth, int maxLineWidth)
|
||||||
int iLineIndex) {
|
{
|
||||||
return 0;
|
int result = 0;
|
||||||
/*
|
if( eAlignMask == Image::TextAlign::CENTER ||
|
||||||
int iRet;
|
eAlignMask == Image::TextAlign::TOP ||
|
||||||
int iError = FT_Load_Glyph(face, FT_Get_Char_Index(face, cText),
|
eAlignMask == Image::TextAlign::BOTTOM)
|
||||||
FT_LOAD_DEFAULT);
|
{
|
||||||
if (iError) {
|
result = (maxLineWidth / 2) - (lineWidth / 2);
|
||||||
return -1;
|
}
|
||||||
}
|
else if(eAlignMask == Image::TextAlign::RIGHT ||
|
||||||
|
eAlignMask == Image::TextAlign::TOP_RIGHT ||
|
||||||
if (eAlignMask == Image::kAlignCenter) {
|
eAlignMask == Image::TextAlign::BOTTOM_RIGHT)
|
||||||
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth) / 2
|
{
|
||||||
- RSHIFT6(face->glyph->metrics.horiBearingX );
|
result = maxLineWidth - lineWidth;
|
||||||
|
}
|
||||||
} else if (eAlignMask == Image::kAlignRight) {
|
// In all other cases (left alignment, most likely), return 0.
|
||||||
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth)
|
|
||||||
- RSHIFT6(face->glyph->metrics.horiBearingX );
|
// Attempt to ensure that we don't produce any completely invalid reslts.
|
||||||
} else {
|
if(result < 0)
|
||||||
// left or other situation
|
{
|
||||||
iRet = -RSHIFT6(face->glyph->metrics.horiBearingX );
|
result = 0;
|
||||||
}
|
}
|
||||||
return iRet;
|
return result;
|
||||||
*/
|
}
|
||||||
}
|
|
||||||
|
int computeLineStartY(Image::TextAlign eAlignMask, int lineHeight, int maxLineHeight)
|
||||||
int computeLineStartY( TTF_Font *face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){
|
{
|
||||||
return 0;
|
int result = 0;
|
||||||
/*
|
if( eAlignMask == Image::TextAlign::CENTER ||
|
||||||
int iRet;
|
eAlignMask == Image::TextAlign::RIGHT ||
|
||||||
if (eAlignMask == Image::kAlignCenter || eAlignMask == Image::kAlignLeft ||
|
eAlignMask == Image::TextAlign::LEFT)
|
||||||
eAlignMask == Image::kAlignRight ) {
|
{
|
||||||
//vertical center
|
result = (maxLineHeight / 2) - (lineHeight / 2);
|
||||||
iRet = (borderHeight - txtHeight)/2 + RSHIFT6(face->size->metrics.ascender);
|
}
|
||||||
|
else if(eAlignMask == Image::TextAlign::BOTTOM ||
|
||||||
|
eAlignMask == Image::TextAlign::BOTTOM_RIGHT ||
|
||||||
|
eAlignMask == Image::TextAlign::BOTTOM_LEFT)
|
||||||
|
{
|
||||||
|
result = maxLineHeight - lineHeight;
|
||||||
|
}
|
||||||
|
// In all other cases (top alignment, most likely), return 0;
|
||||||
|
|
||||||
|
if(result < 0)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (eAlignMask == Image::kAlignBottomRight ||
|
|
||||||
eAlignMask == Image::kAlignBottom ||
|
|
||||||
eAlignMask == Image::kAlignBottomLeft ) {
|
|
||||||
//vertical bottom
|
|
||||||
iRet = borderHeight - txtHeight + RSHIFT6(face->size->metrics.ascender);
|
|
||||||
} else {
|
|
||||||
// left or other situation
|
|
||||||
iRet = RSHIFT6(face->size->metrics.ascender);
|
|
||||||
}
|
|
||||||
return iRet;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) {
|
bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) {
|
||||||
const char* pText = text;
|
const char* pText = text;
|
||||||
int pxSize = (int)fontSize;
|
int pxSize = (int)fontSize;
|
||||||
|
@ -213,7 +239,10 @@ public:
|
||||||
// pass back SDL's buffer then, though would need additional logic to
|
// pass back SDL's buffer then, though would need additional logic to
|
||||||
// call SDL_FreeSurface appropriately.
|
// call SDL_FreeSurface appropriately.
|
||||||
|
|
||||||
// FIXME: handle alignment, etc.
|
// Y offset for vertical alignment remains constant throughout, as it
|
||||||
|
// is the entire block of text that must be vertically aligned.
|
||||||
|
int yOffset = computeLineStartY(eAlignMask, vLines.size() * pxSize, iMaxLineHeight);
|
||||||
|
|
||||||
for (size_t l = 0; l < vLines.size(); l++) {
|
for (size_t l = 0; l < vLines.size(); l++) {
|
||||||
pText = vLines[l].sLineStr.c_str();
|
pText = vLines[l].sLineStr.c_str();
|
||||||
if(!strlen(pText))
|
if(!strlen(pText))
|
||||||
|
@ -229,6 +258,10 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The lock/unlock pair is required since Emscripten's SDL
|
||||||
|
// implementation copies pixel data from its off-screen canvas to
|
||||||
|
// the pixels array in the unlock operation. Without this, we would
|
||||||
|
// be reading uninitialized memory.
|
||||||
SDL_LockSurface(tSurf);
|
SDL_LockSurface(tSurf);
|
||||||
SDL_UnlockSurface(tSurf);
|
SDL_UnlockSurface(tSurf);
|
||||||
|
|
||||||
|
@ -237,17 +270,20 @@ public:
|
||||||
int *pixels = (int*)tSurf->pixels;
|
int *pixels = (int*)tSurf->pixels;
|
||||||
int *out = (int*)_data;
|
int *out = (int*)_data;
|
||||||
|
|
||||||
|
// Compute offset to produce horizontal alignment.
|
||||||
|
int xOffset = computeLineStart(eAlignMask, tSurf->w, iMaxLineWidth);
|
||||||
|
|
||||||
// (i, j) should be treated as (x, y) coordinates in the source
|
// (i, j) should be treated as (x, y) coordinates in the source
|
||||||
// bitmap. This loop maps those locations to the target bitmap.
|
// bitmap. This loop maps those locations to the target bitmap.
|
||||||
// Need to ensure that those values do not exceed the allocated
|
// Need to ensure that those values do not exceed the allocated
|
||||||
// memory.
|
// memory.
|
||||||
int minWidth = MIN(tSurf->w, iMaxLineWidth);
|
int minWidth = MIN(tSurf->w, iMaxLineWidth);
|
||||||
for(int i = 0; i < tSurf->h && (i + l * pxSize) < iMaxLineHeight; ++i)
|
for(int j = 0; j < tSurf->h && (j + l * pxSize) < iMaxLineHeight; ++j)
|
||||||
{
|
{
|
||||||
for(int j = 0; j < minWidth; ++j)
|
for(int i = 0; i < minWidth; ++i)
|
||||||
{
|
{
|
||||||
int sourceOffset = i * tSurf->w + j;
|
int sourceOffset = j * tSurf->w + i;
|
||||||
int targetOffset = (l * pxSize + i) * iMaxLineWidth + j;
|
int targetOffset = (l * pxSize + j + yOffset) * iMaxLineWidth + i + xOffset;
|
||||||
|
|
||||||
// HTML5 canvas is non-pre-alpha-multiplied, so alpha-multiply here.
|
// HTML5 canvas is non-pre-alpha-multiplied, so alpha-multiply here.
|
||||||
unsigned char *p = (unsigned char*) &pixels[sourceOffset];
|
unsigned char *p = (unsigned char*) &pixels[sourceOffset];
|
||||||
|
@ -257,7 +293,7 @@ public:
|
||||||
SDL_FreeSurface(tSurf);
|
SDL_FreeSurface(tSurf);
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear all lines
|
// clear all lines
|
||||||
vLines.clear();
|
vLines.clear();
|
||||||
|
|
||||||
TTF_CloseFont(face);
|
TTF_CloseFont(face);
|
||||||
|
@ -300,7 +336,7 @@ bool Image::initWithString(
|
||||||
|
|
||||||
CC_BREAK_IF(! dc.getBitmap(pText, nWidth, nHeight, eAlignMask, fullFontName.c_str(), nSize));
|
CC_BREAK_IF(! dc.getBitmap(pText, nWidth, nHeight, eAlignMask, fullFontName.c_str(), nSize));
|
||||||
|
|
||||||
// assign the dc._data to _data in order to save time
|
// assign the dc.m_pData to m_pData in order to save time
|
||||||
_data = dc._data;
|
_data = dc._data;
|
||||||
CC_BREAK_IF(! _data);
|
CC_BREAK_IF(! _data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue