Пример #1
0
float CglFont::GetTextWidth_(const std::u8string& text)
{
	if (text.empty()) return 0.0f;

	float w = 0.0f;
	float maxw = 0.0f;

	const GlyphInfo* prv_g=NULL;
	const GlyphInfo* cur_g;

	int pos = 0;
	while (pos < text.length()) {
		const char32_t u = Utf8GetNextChar(text, pos);

		switch (u) {
			// inlined colorcode
			case ColorCodeIndicator:
				pos = SkipColorCodes(text, pos - 1);
				if (pos<0) {
					pos = text.length();
				}
				break;

			// reset color
			case ColorResetIndicator:
				break;

			// newline
			case 0x0d: // CR+LF
				if (pos < text.length() && text[pos] == 0x0a)
					pos++;
			case 0x0a: // LF
				if (prv_g)
					w += prv_g->advance;
				if (w > maxw)
					maxw = w;
				w = 0.0f;
				prv_g = NULL;
				break;

			// printable char
			default:
				cur_g = &GetGlyph(u);
				if (prv_g) w += GetKerning(*prv_g, *cur_g);
				prv_g = cur_g;
		}
	}

	if (prv_g)
		w += prv_g->advance;
	if (w > maxw)
		maxw = w;

	return maxw;
}
Пример #2
0
void CglFont::RenderStringOutlined(float x, float y, const float& scaleX, const float& scaleY, const std::string& str)
{
	const float shiftX = (scaleX/fontSize) * GetOutlineWidth(), shiftY = (scaleY/fontSize) * GetOutlineWidth();

	const float startx = x;
	const float lineHeight_ = scaleY * GetLineHeight();
	const std::u8string& ustr = toustring(str);
	const size_t length = str.length();

	va.EnlargeArrays(length * 4, 0, VA_SIZE_2DT);
	va2.EnlargeArrays(length * 4, 0, VA_SIZE_2DT);

	int skippedLines;
	bool colorChanged;
	const GlyphInfo* g = NULL;
	float4 newColor = textColor;
	char32_t c;
	int i = 0;

	do {
		const bool endOfString = SkipColorCodesAndNewLines(ustr, &i, &newColor, &colorChanged, &skippedLines, &baseTextColor);

		if (endOfString)
			return;

		c = Utf8GetNextChar(str,i);

		if (colorChanged) {
			if (autoOutlineColor) {
				SetColors(&newColor,NULL);
			} else {
				SetTextColor(&newColor);
			}
		}

		const GlyphInfo* c_g = &GetGlyph(c);
		if (skippedLines>0) {
			x  = startx;
			y -= skippedLines * lineHeight_;
		} else if (g) {
			x += scaleX * GetKerning(*g, *c_g);
		}

		g = c_g;

		const auto&  tc = g->texCord;
		const auto& stc = g->shadowTexCord;
		const float dx0 = (scaleX * g->size.x0()) + x, dy0 = (scaleY * g->size.y0()) + y;
		const float dx1 = (scaleX * g->size.x1()) + x, dy1 = (scaleY * g->size.y1()) + y;

		// draw outline
		va2.AddVertexQ2dT(dx0-shiftX, dy1-shiftY, stc.x0(), stc.y1());
		va2.AddVertexQ2dT(dx0-shiftX, dy0+shiftY, stc.x0(), stc.y0());
		va2.AddVertexQ2dT(dx1+shiftX, dy0+shiftY, stc.x1(), stc.y0());
		va2.AddVertexQ2dT(dx1+shiftX, dy1-shiftY, stc.x1(), stc.y1());

		// draw the actual character
		va.AddVertexQ2dT(dx0, dy1, tc.x0(), tc.y1());
		va.AddVertexQ2dT(dx0, dy0, tc.x0(), tc.y0());
		va.AddVertexQ2dT(dx1, dy0, tc.x1(), tc.y0());
		va.AddVertexQ2dT(dx1, dy1, tc.x1(), tc.y1());
	} while(true);
}
Пример #3
0
void CglFont::RenderString(float x, float y, const float& scaleX, const float& scaleY, const std::string& str)
{
	/**
	 * NOTE:
	 * Font rendering does not use display lists, but VAs. It's actually faster
	 * (450% faster with a 7600GT!) for these reasons:
	 *
	 * 1. When using DLs, we can not group multiple glyphs into one glBegin/End pair
	 *    because glTranslatef can not go between such a pair.
	 * 2. We can now eliminate all glPushMatrix/PopMatrix pairs related to font rendering
	 *    because the transformations are calculated on the fly. These are just a couple of
	 *    floating point multiplications and shouldn't be too expensive.
	 */

	const float startx = x;
	const float lineHeight_ = scaleY * GetLineHeight();
	unsigned int length = (unsigned int)str.length();
	const std::u8string& ustr = toustring(str);

	va.EnlargeArrays(length * 4, 0, VA_SIZE_2DT);

	int skippedLines;
	bool colorChanged;
	const GlyphInfo* g = NULL;
	float4 newColor = textColor;
	char32_t c;
	int i = 0;

	do {
		const bool endOfString = SkipColorCodesAndNewLines(ustr, &i, &newColor, &colorChanged, &skippedLines, &baseTextColor);

		if (endOfString)
			return;

		c = Utf8GetNextChar(str,i);

		if (colorChanged) {
			if (autoOutlineColor) {
				SetColors(&newColor,NULL);
			} else {
				SetTextColor(&newColor);
			}
		}
		const GlyphInfo* c_g = &GetGlyph(c);
		if (skippedLines>0) {
			x  = startx;
			y -= skippedLines * lineHeight_;
		} else if (g) {
			x += scaleX * GetKerning(*g, *c_g);
		}

		g = c_g;

		const auto&  tc = g->texCord;
		const float dx0 = (scaleX * g->size.x0()) + x, dy0 = (scaleY * g->size.y0()) + y;
		const float dx1 = (scaleX * g->size.x1()) + x, dy1 = (scaleY * g->size.y1()) + y;

		va.AddVertexQ2dT(dx0, dy1, tc.x0(), tc.y1());
		va.AddVertexQ2dT(dx0, dy0, tc.x0(), tc.y0());
		va.AddVertexQ2dT(dx1, dy0, tc.x1(), tc.y0());
		va.AddVertexQ2dT(dx1, dy1, tc.x1(), tc.y1());
	} while(true);
}
Пример #4
0
float CFont::AddStr(CStrAny &sStr, const CVector<2> &vPos, char chPrevious)
{
  ASSERT(IsValid());
  if (!sStr.Length())
    return 0;
  UINT uiVerts, uiInds, uiVertSize;
  uiVerts = sStr.Length() * 4;
  uiInds = sStr.Length() * 6;
  CGeometry *pGeom = m_pTextModel->m_pGeometry;
  uiVertSize = pGeom->m_pInputDesc->GetSize();
  ASSERT(uiVertSize == sizeof(TPlainVertex));
  if (pGeom->m_pVB->GetSize(0) < (pGeom->m_uiVertices + uiVerts) * uiVertSize)
    return INVALID_LENGTH;
  if (pGeom->m_pIB->GetSize(0) < (pGeom->m_uiIndices + uiInds) * sizeof(uint16_t))
    return INVALID_LENGTH;
  TPlainVertex *pVerts;
  uint16_t *pInds;
  pVerts = (TPlainVertex *) pGeom->m_pVB->Map(0, CResource::RMF_SYSTEM_ONLY, pGeom->m_uiVertices * uiVertSize, uiVerts * uiVertSize);
  ASSERT(pVerts);
  pInds = (uint16_t *) pGeom->m_pIB->Map(0, CResource::RMF_SYSTEM_ONLY, pGeom->m_uiIndices * sizeof(uint16_t), uiInds * sizeof(uint16_t));
  ASSERT(pInds);

  CVector<3> vCur = { vPos.x(), vPos.y() - m_iAscent, 0.5f }, vBoxSize = { 0, (float) m_iHeight, 0 };

  int i, iChars = 0;
  for (i = 0; i < sStr.Length(); i++) {
    char ch = sStr[i];
    if (!m_Chars[(uint8_t) ch].ch)
      continue;
    CRect<> rcInTex = GetCharRect(ch);
    vBoxSize.x() = (float) m_Chars[(uint8_t) ch].iB;
    
    vCur.x() += m_Chars[(uint8_t) ch].iA + GetKerning(chPrevious, ch);

    pVerts[0].vPos.Set(vCur.x(), vCur.y() + vBoxSize.y(), vCur.z());
    pVerts[0].vTex = rcInTex.m_vMin;

    pVerts[1].vPos = vCur;
    pVerts[1].vTex = rcInTex.GetPoint(0, 1);

    pVerts[2].vPos = vCur + vBoxSize;
    pVerts[2].vTex = rcInTex.GetPoint(1, 0);

    pVerts[3].vPos.Set(vCur.x() + vBoxSize.x(), vCur.y(), vCur.z());
    pVerts[3].vTex = rcInTex.m_vMax;

    pInds[0] = pGeom->m_uiVertices + iChars * 4;
    pInds[1] = pInds[0] + 1;
    pInds[2] = pInds[0] + 2;
    pInds[3] = pInds[0] + 2;
    pInds[4] = pInds[0] + 1;
    pInds[5] = pInds[0] + 3;

    vCur.x() += m_Chars[(uint8_t) ch].iB + m_Chars[(uint8_t) ch].iC;
    chPrevious = ch;

    pVerts += 4;
    pInds += 6;
    iChars++;
  }

  pGeom->m_pIB->Unmap();
  pGeom->m_pVB->Unmap();
  pGeom->m_uiVertices += iChars * 4;
  pGeom->m_uiIndices += iChars * 6;

  return vCur.x() - vPos.x();
}
Пример #5
0
CBSurface *CBFontTT::RenderTextToTexture(const WideString &text, int width, TTextAlign align, int maxHeight, int &textOffset) {
	TextLineList lines;
	WrapText(text, width, maxHeight, lines);


	TextLineList::iterator it;

	int textHeight = lines.size() * (m_MaxCharHeight + m_Ascender);
	SDL_Surface *surface = SDL_CreateRGBSurface(0, width, textHeight, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);

	SDL_LockSurface(surface);

	int posY = (int)GetLineHeight() - (int)m_Descender;

	for (it = lines.begin(); it != lines.end(); ++it) {
		TextLine *line = (*it);
		int posX = 0;

		switch (align) {
		case TAL_CENTER:
			posX += (width - line->GetWidth()) / 2;
			break;

		case TAL_RIGHT:
			posX += width - line->GetWidth();
			break;
		}


		textOffset = 0;
		for (size_t i = 0; i < line->GetText().length(); i++) {
			wchar_t ch = line->GetText()[i];

			GlyphInfo *glyph = m_GlyphCache->GetGlyph(ch);
			if (!glyph) continue;

			textOffset = std::max(textOffset, glyph->GetBearingY());
		}


		int origPosX = posX;

		wchar_t prevChar = L'\0';
		for (size_t i = 0; i < line->GetText().length(); i++) {
			wchar_t ch = line->GetText()[i];

			GlyphInfo *glyph = m_GlyphCache->GetGlyph(ch);
			if (!glyph) continue;

			float kerning = 0;
			if (prevChar != L'\0') kerning = GetKerning(prevChar, ch);
			posX += (int)kerning;


			if (glyph->GetBearingY() > 0) {
				int i = 10;
			}

			SDL_Rect rect;
			rect.x = posX + glyph->GetBearingX();
			rect.y = posY - glyph->GetBearingY() + textOffset;
			rect.w = glyph->GetImage()->w;
			rect.h = glyph->GetImage()->h;

			BlitSurface(glyph->GetImage(), surface, &rect);

			prevChar = ch;
			posX += (int)(glyph->GetAdvanceX());
			posY += (int)(glyph->GetAdvanceY());
		}

		if (m_IsUnderline) {
			for (int i = origPosX; i < origPosX + line->GetWidth(); i++) {
				Uint8 *buf = (Uint8 *)surface->pixels + (int)(m_UnderlinePos + m_Ascender) * surface->pitch;
				Uint32 *buf32 = (Uint32 *)buf;

				buf32[i] = SDL_MapRGBA(surface->format, 255, 255, 255, 255);
			}
		}

		SDL_UnlockSurface(surface);

		delete line;
		line = NULL;
		posY += GetLineHeight();
	}

	CBSurfaceSDL *wmeSurface = new CBSurfaceSDL(Game);
	if (SUCCEEDED(wmeSurface->CreateFromSDLSurface(surface))) {
		SDL_FreeSurface(surface);
		return wmeSurface;
	} else {
		SDL_FreeSurface(surface);
		delete wmeSurface;
		return NULL;
	}
}
Пример #6
0
// Generates the geometry required to render a single line of text.
int FontFaceHandle::GenerateString(GeometryList& geometry, const WString& string, const Vector2f& position, const Colourb& colour, int layer_configuration_index, word default_character) const
{
	int geometry_index = 0;
	int line_width = 0;

	ROCKET_ASSERT(layer_configuration_index >= 0);
	ROCKET_ASSERT(layer_configuration_index < (int) layer_configurations.size());

	// Fetch the requested configuration and generate the geometry for each one.
	const LayerConfiguration& layer_configuration = layer_configurations[layer_configuration_index];
	for (size_t i = 0; i < layer_configuration.size(); ++i)
	{
		FontFaceLayer* layer = layer_configuration[i];

		Colourb layer_colour;
		if (layer == base_layer)
			layer_colour = colour;
		else
			layer_colour = layer->GetColour();

		// Resize the geometry list if required.
		if ((int) geometry.size() < geometry_index + layer->GetNumTextures())
			geometry.resize(geometry_index + layer->GetNumTextures());

		// Bind the textures to the geometries.
		for (int i = 0; i < layer->GetNumTextures(); ++i)
			geometry[geometry_index + i].SetTexture(layer->GetTexture(i));

		line_width = 0;
		word prior_character = 0;

		const word* string_iterator = string.CString();
		const word* string_end = string.CString() + string.Length();
		word final_character;

		for (; string_iterator != string_end; string_iterator++)
		{
			final_character = *string_iterator;
			FontGlyphMap::const_iterator iterator = glyphs.find(*string_iterator);

			if (iterator == glyphs.end())
			{
				if (default_character >= 32)
				{
					iterator = glyphs.find(default_character);
					if (iterator == glyphs.end())
					{
						continue;
					}
					else
					{
						final_character = default_character;
					}
				}
				else
				{
					continue;
				}
			}

			// Adjust the cursor for the kerning between this character and the previous one.
			if (prior_character != 0)
				line_width += GetKerning(prior_character, final_character);

			layer->GenerateGeometry(&geometry[geometry_index], final_character, Vector2f(position.x + line_width, position.y), layer_colour);

			line_width += iterator->second.advance;
			prior_character = final_character;
		}

		geometry_index += layer->GetNumTextures();
	}

	// Cull any excess geometry from a previous generation.
	geometry.resize(geometry_index);

	return line_width;
}
Пример #7
0
CTextWrap::word CTextWrap::SplitWord(CTextWrap::word& w, float wantedWidth, bool smart)
{
	// returns two pieces 'L'eft and 'R'ight of the split word (returns L, *wi becomes R)

	word w2;
	w2.pos = w.pos;

	const float spaceAdvance = GetGlyph(spaceUTF16).advance;
	if (w.isLineBreak) {
		// shouldn't happen
		w2 = w;
		w.isSpace = true;
	} else if (w.isSpace) {
		const int split = (int)std::floor(wantedWidth / spaceAdvance);
		w2.isSpace   = true;
		w2.numSpaces = split;
		w2.width     = spaceAdvance * w2.numSpaces;
		w.numSpaces -= split;
		w.width      = spaceAdvance * w.numSpaces;
		w.pos       += split;
	} else {
		if (smart) {
			if (
				(wantedWidth < 8 * spaceAdvance) ||
				(w.text.length() < 1)
			) {
				w2.isSpace = true;
				return w2;
			}
		}

		float width = 0.0f;
		int i = 0;
		float min_penalty = 1e9;
		unsigned int goodbreak = 0;
		char32_t c = Utf8GetNextChar(w.text,i);
		const GlyphInfo* curGlyph = &GetGlyph(c);
		const GlyphInfo* nextGlyph = curGlyph;

		do {
			const int lastCharPos = i;
			const char32_t co     = c;
			curGlyph = nextGlyph;
			c = Utf8GetNextChar(w.text,i);
			nextGlyph = &GetGlyph(c);
			width += GetKerning(*curGlyph, *nextGlyph);

			if (width > wantedWidth) {
				break;
			}

			if (smart) {
				const float penalty = GetPenalty(co, lastCharPos, w.text.length());
				if (penalty < min_penalty) {
					min_penalty = penalty;
					goodbreak   = lastCharPos;
				}
			} else {
				goodbreak = i;
			}
		} while(i < w.text.length());

		w2.text  = toustring(w.text.substr(0,goodbreak));
		w2.width = GetTextWidth(w2.text);
		w.text.erase(0,goodbreak);
		w.width  = GetTextWidth(w.text);
		w.pos   += goodbreak;
	}
	return w2;
}