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) {
|
||||
const char* pText = sText;
|
||||
|
||||
//init stringstream
|
||||
std::stringstream ss;
|
||||
int w, h;
|
||||
|
||||
while (*pText != '\0') {
|
||||
if (*pText == '\n') {
|
||||
buildLine(ss, face);
|
||||
// if there is no maximum width specified, just slam the whole input
|
||||
// string into a single line, thereby avoiding many expensive calls to
|
||||
// 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;
|
||||
}
|
||||
|
||||
//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);
|
||||
ss << *i;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << " " << *i;
|
||||
}
|
||||
|
||||
ss << *pText;
|
||||
pText++;
|
||||
|
||||
}
|
||||
|
||||
buildLine(ss, face);
|
||||
|
@ -130,53 +155,54 @@ public:
|
|||
* while -1 means fail
|
||||
*
|
||||
*/
|
||||
int computeLineStart(TTF_Font *face, Image::TextAlign eAlignMask, char cText,
|
||||
int iLineIndex) {
|
||||
return 0;
|
||||
/*
|
||||
int iRet;
|
||||
int iError = FT_Load_Glyph(face, FT_Get_Char_Index(face, cText),
|
||||
FT_LOAD_DEFAULT);
|
||||
if (iError) {
|
||||
return -1;
|
||||
}
|
||||
int computeLineStart(Image::TextAlign eAlignMask, int lineWidth, int maxLineWidth)
|
||||
{
|
||||
int result = 0;
|
||||
if( eAlignMask == Image::TextAlign::CENTER ||
|
||||
eAlignMask == Image::TextAlign::TOP ||
|
||||
eAlignMask == Image::TextAlign::BOTTOM)
|
||||
{
|
||||
result = (maxLineWidth / 2) - (lineWidth / 2);
|
||||
}
|
||||
else if(eAlignMask == Image::TextAlign::RIGHT ||
|
||||
eAlignMask == Image::TextAlign::TOP_RIGHT ||
|
||||
eAlignMask == Image::TextAlign::BOTTOM_RIGHT)
|
||||
{
|
||||
result = maxLineWidth - lineWidth;
|
||||
}
|
||||
// In all other cases (left alignment, most likely), return 0.
|
||||
|
||||
if (eAlignMask == Image::kAlignCenter) {
|
||||
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth) / 2
|
||||
- RSHIFT6(face->glyph->metrics.horiBearingX );
|
||||
// Attempt to ensure that we don't produce any completely invalid reslts.
|
||||
if(result < 0)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} else if (eAlignMask == Image::kAlignRight) {
|
||||
iRet = (iMaxLineWidth - vLines[iLineIndex].iLineWidth)
|
||||
- RSHIFT6(face->glyph->metrics.horiBearingX );
|
||||
} else {
|
||||
// left or other situation
|
||||
iRet = -RSHIFT6(face->glyph->metrics.horiBearingX );
|
||||
}
|
||||
return iRet;
|
||||
*/
|
||||
}
|
||||
int computeLineStartY(Image::TextAlign eAlignMask, int lineHeight, int maxLineHeight)
|
||||
{
|
||||
int result = 0;
|
||||
if( eAlignMask == Image::TextAlign::CENTER ||
|
||||
eAlignMask == Image::TextAlign::RIGHT ||
|
||||
eAlignMask == Image::TextAlign::LEFT)
|
||||
{
|
||||
result = (maxLineHeight / 2) - (lineHeight / 2);
|
||||
}
|
||||
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;
|
||||
|
||||
int computeLineStartY( TTF_Font *face, Image::TextAlign eAlignMask, int txtHeight, int borderHeight ){
|
||||
return 0;
|
||||
/*
|
||||
int iRet;
|
||||
if (eAlignMask == Image::kAlignCenter || eAlignMask == Image::kAlignLeft ||
|
||||
eAlignMask == Image::kAlignRight ) {
|
||||
//vertical center
|
||||
iRet = (borderHeight - txtHeight)/2 + RSHIFT6(face->size->metrics.ascender);
|
||||
|
||||
} 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;
|
||||
*/
|
||||
}
|
||||
if(result < 0)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool getBitmap(const char *text, int nWidth, int nHeight, Image::TextAlign eAlignMask, const char * pFontName, float fontSize) {
|
||||
const char* pText = text;
|
||||
|
@ -213,7 +239,10 @@ public:
|
|||
// pass back SDL's buffer then, though would need additional logic to
|
||||
// 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++) {
|
||||
pText = vLines[l].sLineStr.c_str();
|
||||
if(!strlen(pText))
|
||||
|
@ -229,6 +258,10 @@ public:
|
|||
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_UnlockSurface(tSurf);
|
||||
|
||||
|
@ -237,17 +270,20 @@ public:
|
|||
int *pixels = (int*)tSurf->pixels;
|
||||
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
|
||||
// bitmap. This loop maps those locations to the target bitmap.
|
||||
// Need to ensure that those values do not exceed the allocated
|
||||
// memory.
|
||||
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 targetOffset = (l * pxSize + i) * iMaxLineWidth + j;
|
||||
int sourceOffset = j * tSurf->w + i;
|
||||
int targetOffset = (l * pxSize + j + yOffset) * iMaxLineWidth + i + xOffset;
|
||||
|
||||
// HTML5 canvas is non-pre-alpha-multiplied, so alpha-multiply here.
|
||||
unsigned char *p = (unsigned char*) &pixels[sourceOffset];
|
||||
|
@ -257,7 +293,7 @@ public:
|
|||
SDL_FreeSurface(tSurf);
|
||||
}
|
||||
|
||||
//clear all lines
|
||||
// clear all lines
|
||||
vLines.clear();
|
||||
|
||||
TTF_CloseFont(face);
|
||||
|
@ -300,7 +336,7 @@ bool Image::initWithString(
|
|||
|
||||
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;
|
||||
CC_BREAK_IF(! _data);
|
||||
|
||||
|
|
Loading…
Reference in New Issue