Example #1
0
void ScreenPainter::drawGlyphOutline(const GlyphLayout gl, bool fill)
{
	if (fill)
		drawGlyph(gl);
	m_painter->save();
	bool fr = m_painter->fillRule();
	m_painter->setFillRule(false);

	setupState(false);
	m_painter->translate(0, -(fontSize() * gl.scaleV));

	FPointArray outline = font().glyphOutline(gl.glyph);
	double scaleHv = gl.scaleH * fontSize() / 10.0;
	double scaleVv = gl.scaleV * fontSize() / 10.0;
	QTransform trans;
	trans.scale(scaleHv, scaleVv);
	outline.map(trans);
	m_painter->setupPolygon(&outline, true);
	if (outline.size() > 3)
	{
		m_painter->setLineWidth(strokeWidth());
		m_painter->strokePath();
	}

	m_painter->setFillRule(fr);
	m_painter->restore();

}
Example #2
0
void Font::draw (const char* str, float size, bool autoGLState) {
  glBindTexture(GL_TEXTURE_2D, tex);

  if (autoGLState) {
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  }

  glPushMatrix();
  glScalef(size, size, 1.0f);

  float advanceAccum = 0;
  for (const char* c = str; *c!='\0'; c++) {
    if (*c == '\n') {
      glTranslatef(-advanceAccum, 1, 0);
      advanceAccum = 0;
    } else {
      const Glyph& gi = glyphMap.get((unsigned long)*c);
      drawGlyph(gi);
      glTranslatef(gi.advance, 0, 0);
      advanceAccum += gi.advance;
    }
  }

  if (autoGLState) {
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  }

  glPopMatrix();
}
Example #3
0
void Screen::drawGlyphs(u32 x, u32 y, u8 fc, u8 bc, u16 num, u16 *text, bool *dw)
{
	for (; num--; text++, dw++) {
		drawGlyph(x, y, fc, bc, *text, *dw);
		x += *dw ? FW(2) : FW(1);
	}
}
Example #4
0
void
pamd_text(tuple**       const tuples, 
          int           const cols, 
          int           const rows, 
          int           const depth, 
          sample        const maxval, 
          pamd_point    const pos,
          int           const height, 
          int           const angle, 
          const char *  const sArg, 
          pamd_drawproc       drawProc,
          const void *  const clientdata) {
/*----------------------------------------------------------------------------
   Draw the zero-terminated string 'sArg', with its baseline starting at point
   'pos', inclined by 'angle' degrees to the X axis, with letters 'height'
   tuples high (descenders will extend below the baseline).  We pass the
   supplied drawproc and clientdata to pamd_linep, which performs the actual
   drawing.

   There may be multiple lines of text.  The baseline of the topmost line
   starts at 'pos'.
-----------------------------------------------------------------------------*/
    const struct ppmd_font * const fontP = ppmd_get_font();

    long rotsin, rotcos;
    pamd_point p;
    const char * s;

    pamd_validatePoint(pos);

    p = makePoint(0, 0);
    rotsin = isin(-angle);
    rotcos = icos(-angle);

    for (s = &sArg[0]; *s; ) {
        unsigned char const ch = *s++;

        if (ch >= fontP->header.firstCodePoint &&
            ch < fontP->header.firstCodePoint + fontP->header.characterCount) {

            const struct ppmd_glyph * const glyphP =
                &fontP->glyphTable[ch - fontP->header.firstCodePoint];

            unsigned int cursorAdvance;

            pamd_validatePoint(p); 

            drawGlyph(glyphP, p, tuples, cols, rows, depth, maxval,
                      height, pos, rotcos, rotsin,
                      drawProc, clientdata, &cursorAdvance);
            p.x += cursorAdvance;
        } else if (ch == '\n') {
            /* Move to the left edge of the next line down */
            p.y += Scalef + Descend;
            p.x = 0;
        }
    }
}
Example #5
0
    void DefaultFont::drawString(Graphics* graphics, const std::string& text, int x, int y, bool is_normal)
    {
        unsigned int i;

        for (i = 0; i< text.size(); ++i)
        {
            drawGlyph(graphics, text.at(i), x, y);
            x += getWidth(text);
        }
    }
Example #6
0
 void ImageFont::drawString(Graphics* graphics, const std::string& text, int x, int y)
 {
     unsigned int i;
 
     for (i = 0; i< text.size(); ++i)
     {
         drawGlyph(graphics, text.at(i), x, y);
         x += getWidth(text.at(i));      
     }    
 }
Example #7
0
void GLText::drawString(vector2d loc, double angle, double size, const char* str, HAlignOptions hAlign, VAlignOptions vAlign)
{
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();
  glTranslated(loc.x,loc.y,0.0);
  glScaled(size, size,1.0);
  glRotated(angle,0,0,1);
  
  switch(hAlign){
    case LeftAligned:{
      //Normal rendering will achieve this!
      break;
    }
    case RightAligned:{
      glTranslated(-getWidth(str),0,0);
      break;
    }
    case CenterAligned:{
      glTranslated(-0.5*getWidth(str),0,0);
      break;
    }
  }
  switch(vAlign){
    case BottomAligned:{
      glTranslated(0.0,getDescent(str),0.0);
      break;
    }
    case TopAligned:{
      glTranslated(0.0,-getAscent(str),0.0);
      break;
    }
    case MedianAligned:{
      //Normal rendering will achieve this!
      break;
    }
    case MiddleAligned:{
      glTranslated(0.0,-0.5*getHeight(str),0.0);
      break;
    }
  }
  vector2d textDir;
  textDir.heading(0);
  double d = 0.0;
  while(*str>0){
    drawGlyph(*str);
    d = characterSpacing + 0.5*getWidth(*str);
    str++;
    if((*str)>0){
      d += 0.5*getWidth(*str);
      glTranslated(d*textDir.x,d*textDir.y,0.0);
    }
  }
  glPopMatrix();
}
Example #8
0
void Font::drawWrap(BITMAP* aBuffer, const std::string& aText, int aX, int aY, int aMaxWidth, int aNumberOfCharacters)
{
	int x = aX;
	int y = aY;
	int glyphBitmapMaxHeight = 0;

	std::string text = aText;

	int totChar = 0;
	std::vector<std::string> words = tokenize(text, ' ');
	for(unsigned int i = 0; i < words.size(); i++)
	{
		std::string word = words[i];
		if(aMaxWidth != -1 && x + getWidth(word) > (unsigned int)aMaxWidth)
		{
			x = aX;
			y += glyphBitmapMaxHeight;
			glyphBitmapMaxHeight = 0;
		}
		else
		{
			if(totChar != 0) 
			{
				word = " " + word;
			}
		}

		for(unsigned int j = 0; j < word.size(); j++)
		{
			if(aNumberOfCharacters != -1 && totChar >= aNumberOfCharacters)
			{
				return;
			}
			char currChar = word[j];

			BITMAP* glyphBitmap = getBitmapForGlyph(currChar);

			glyphBitmapMaxHeight = max(glyphBitmapMaxHeight, glyphBitmap->h);

			drawGlyph(aBuffer, currChar, x, y);

			int glyphWidth = glyphBitmap->w;

			x += glyphWidth;
			if(currChar == '\n')
			{
				x = aX;
				y += glyphBitmapMaxHeight;
				glyphBitmapMaxHeight = 0;
			}
			totChar++;
		}
	}
}
Example #9
0
int dispDrawPortal (PORTAL *p)
{
    if (p->type != PORTAL_TEXT)
    {
        setError (EDISP_INVAL, "Invalid portal type in dispDrawPortal");
        return -1;
    }

    if (p->scroll == 1)
        return scrollPortal (p);

    GLYPH g[p->content.text.size];

    //
    // Cycle through the letters in the text to be displayed. We have
    // to resolve justification before rendering the portal. Collect
    // all the glyphs, add up their widths, and move the start points
    // to the appropriate column.
    //

    for (int i = 0; i < p->content.text.size; ++i)
    {
        // get the next letter to render
        char letter = p->content.text.data[i];

        // get the glyph for that letter
        if (fntGetGlyph (p->content.text.font, &g[i], letter) != 0)
        {
            setError (EDISP_FONTERR, "Error getting glyph in dispDrawPortal");
            return -1;
        }
    }

    setJustification (p, g, sizeof g / sizeof g[0]);

    //
    // Draw the portal
    //

    int col = p->startCol;
    int maxCol = p->startCol + p->width;
    for (int i = 0; i < p->content.text.size; ++i)
        drawGlyph (&g[i], &col, p, maxCol);

    //dumpPortal (p);
    return 0;
}
Example #10
0
void Font::printText(char* str, GLfloat Red, GLfloat Green, GLfloat Blue, GLfloat Alpha) {
    // Initialize OpenGL ES States
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Use font program
	glUseProgram(program->ProgramID);
    
    // Activate Texture unit 0 and assign the altas texture
	glActiveTexture (GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, atlasTex);

	TransformObj->TransformPushMatrix();
    GLfloat color[4] = {Red, Green, Blue, Alpha};
    glUniform4fv(FRAG_COLOR, 1, color);

    std::vector< FT_UInt >* codePointsPtr = NULL;
    int glyph_count = 0;
    if ( !produceShape(str, codePointsPtr, glyph_count) )
    {
        LOGI("Error in producing font shape");
        return;
    }

    glyph_count = (int) codePointsPtr->size();
    FT_UInt glyph_index = 0;
    for (int i = 0; i < glyph_count; i++) {
        glyph_index = codePointsPtr->at(i);

        const Glyph& gi = glyphs[glyph_index];
        TransformObj->TransformTranslate(gi.advanceHor / 2.0, 0.0, 0.0);
        drawGlyph(gi);
    }
    TransformObj->TransformPopMatrix();
    return;
}
Example #11
0
void Renderer::render(Order &order)
{
    //Set background
	for(int x = 0; x < width_; x++)
	{
		for(int y = 0; y < height_; y++)
		{
			int pos = x + (y * width_);

			buffer_[pos] = colorBackground_.ABGR();
		}
	}
	
    double width = width_ - marginLeft_ - marginRight_;
	double height = height_ - marginTop_ - marginBottom_;

	double ratio = width / height;	
	int w, h;
	double wasted = grid::findBest(order.size(), ratio, w, h);
	double contentRatio = double(w) / double(h);
	double characterWidth = width / double(w);
	double characterHeight = height / double(h);
    int fontSize = contentRatio < ratio ? (int) characterHeight : (int) characterWidth;
	FT_Select_Charmap(face_, ft_encoding_unicode);
	FT_Set_Pixel_Sizes(face_, 0, fontSize);

	for(int i = 0; i < order.size(); i++)
	{
		int gridX = (i % w) * characterWidth + marginLeft_;
		int gridY = (i / w) * characterHeight + marginTop_;


		renderGlyph(face_, order.kanji(i).character());
		
		drawGlyph(buffer_, width_, gridX, gridY, face_->glyph, fontSize, SRSColor(order.kanji(i).SRS()));
	}
}
S32 LLFontGL::render(const LLWString &wstr, 
					 const S32 begin_offset,
					 const F32 x, const F32 y,
					 const LLColor4 &color,
					 const HAlign halign, const VAlign valign,
					 U8 style,
					 const S32 max_chars, S32 max_pixels,
					 F32* right_x,
					 BOOL use_embedded,
					 BOOL use_ellipses) const
{
	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty())
	{
		return 0;
	} 

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// Strip off any style bits that are already accounted for by the font.
	style = style & (~getFontDesc().getStyle());

	F32 drop_shadow_strength = 0.f;
	if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
		}
	}

	gGL.pushMatrix();
	glLoadIdentity();
	gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);

	// this code snaps the text origin to a pixel grid to start with
	F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
	gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);

	LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);

	gGL.color4fv( color.mV );

	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX);
	cur_y = ((F32)y * sScaleY);

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mAscender;
		break;
	case BOTTOM:
		cur_y += mDescender;
		break;
	case VCENTER:
		cur_y -= ((mAscender - mDescender)/2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = cur_x;

	F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth();
	F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}


	// Remember last-used texture to avoid unnecesssary bind calls.
	LLImageGL *last_bound_texture = NULL;

	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			if (last_bound_texture != ext_image)
			{
				gGL.getTexUnit(0)->bind(ext_image);
				last_bound_texture = ext_image;
			}

			// snap origin to whole screen pixel
			const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX));
			const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight));

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
			drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);

			if (!label.empty())
			{
				gGL.pushMatrix();
				//glLoadIdentity();
				//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
				//glScalef(sScaleX, sScaleY, 1.f);
				getFontExtChar()->render(label, 0,
									 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
									 /*llfloor*/(cur_y / sScaleY),
									 color,
									 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			gGL.color4fv(color.mV);

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;
		}
		else
		{
			if (!hasGlyph(wch))
			{
				addChar(wch);
			}

			const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
			if (!fgi)
			{
				llerrs << "Missing Glyph Info" << llendl;
				break;
			}
			// Per-glyph bitmap texture.
			LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum);
			if (last_bound_texture != image_gl)
			{
				gGL.getTexUnit(0)->bind(image_gl);
				last_bound_texture = image_gl;
			}

			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
					(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
					(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
					(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
			// snap glyph origin to whole screen pixel
			LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
					    llround(cur_render_y + (F32)fgi->mYBearing),
					    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
					    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
			
			drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				if (!hasGlyph(next_char))
				{
					addChar(next_char);
				}
				cur_x += getXKerning(wch, next_char);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)llfloor(cur_x + 0.5f);
			//cur_y = (F32)llfloor(cur_y + 0.5f);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if (right_x)
	{
		*right_x = cur_x / sScaleX;
	}

	if (style & UNDERLINE)
	{
		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - (mDescender));
		gGL.vertex2f(cur_x, cur_y - (mDescender));
		gGL.end();
	}

	// *FIX: get this working in all alignment cases, etc.
	if (draw_ellipses)
	{
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushMatrix();
		//glLoadIdentity();
		//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
		//glScalef(sScaleX, sScaleY, 1.f);
		renderUTF8(std::string("..."), 
				0,
				cur_x / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popMatrix();
	}

	gGL.popMatrix();

	return chars_drawn;
}
	void EditText::doRender()
	{
		if (nullptr == mFont || !mVisible || mEmptyView)
			return;

		if (mRenderItem->getCurrentUpdate() || mTextOutDate)
			updateRawData();

		Vertex* vertex = mRenderItem->getCurrentVertexBuffer();

		const RenderTargetInfo& renderTargetInfo = mRenderItem->getRenderTarget()->getInfo();

		// колличество отрисованных вершин
		size_t vertexCount = 0;

		// текущие цвета
		uint32 colour = mCurrentColourNative;
		uint32 inverseColour = mInverseColourNative;
		uint32 selectedColour = mInvertSelect ? inverseColour : mSelectionBgColor;

		const VectorLineInfo& textViewData = mTextView.getData();

		float top = (float)(-mViewOffset.top + mCoord.top);

		FloatRect vertexRect;

		const FloatRect& selectedUVRect = mFont->getGlyphInfo(mBackgroundNormal ? FontCodeType::Selected : FontCodeType::SelectedBack)->uvRect;

		size_t index = 0;

		for (VectorLineInfo::const_iterator line = textViewData.begin(); line != textViewData.end(); ++line)
		{
			float left = (float)(line->offset - mViewOffset.left + mCoord.left);

			for (VectorCharInfo::const_iterator sim = line->simbols.begin(); sim != line->simbols.end(); ++sim)
			{
				if (sim->isColour())
				{
					colour = sim->getColour() | (colour & 0xFF000000);
					inverseColour = colour ^ 0x00FFFFFF;
					selectedColour = mInvertSelect ? inverseColour : mSelectionBgColor;
					continue;
				}

				// смещение текстуры для фона
				bool select = index >= mStartSelect && index < mEndSelect;

				float fullAdvance = sim->getBearingX() + sim->getAdvance();

				// Render the selection, if any, first.
				if (select)
				{
					vertexRect.set(left, top, left + fullAdvance, top + (float)mFontHeight);

					drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, selectedUVRect, selectedColour);
				}

				// Render the glyph shadow, if any.
				if (mShadow)
				{
					vertexRect.left = left + sim->getBearingX() + 1.0f;
					vertexRect.top = top + sim->getBearingY() + 1.0f;
					vertexRect.right = vertexRect.left + sim->getWidth();
					vertexRect.bottom = vertexRect.top + sim->getHeight();

					drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, sim->getUVRect(), mShadowColourNative);
				}

				// Render the glyph itself.
				vertexRect.left = left + sim->getBearingX();
				vertexRect.top = top + sim->getBearingY();
				vertexRect.right = vertexRect.left + sim->getWidth();
				vertexRect.bottom = vertexRect.top + sim->getHeight();

				drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, sim->getUVRect(), (!select || !mInvertSelect) ? colour : inverseColour);

				left += fullAdvance;
				++index;
			}

			top += mFontHeight;
			++index;
		}

		// Render the cursor, if any, last.
		if (mVisibleCursor)
		{
			IntPoint point = mTextView.getCursorPoint(mCursorPosition) - mViewOffset + mCoord.point();
			GlyphInfo* cursorGlyph = mFont->getGlyphInfo(static_cast<Char>(FontCodeType::Cursor));
			vertexRect.set((float)point.left, (float)point.top, (float)point.left + cursorGlyph->width, (float)(point.top + mFontHeight));

			drawGlyph(renderTargetInfo, vertex, vertexCount, vertexRect, cursorGlyph->uvRect, mCurrentColourNative | 0x00FFFFFF);
		}

		// колличество реально отрисованных вершин
		mRenderItem->setLastVertexCount(vertexCount);
	}
Example #14
0
void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly)
{
    drawGlyph(painter,glyph,cellx*width(),celly*height());
}
Example #15
0
void ONScripter::drawChar( char* text, FontInfo *info, bool flush_flag, bool lookback_flag, SDL_Surface *surface, AnimationInfo *cache_info, SDL_Rect *clip )
{
    //printf("draw %x-%x[%s] %d, %d\n", text[0], text[1], text, info->xy[0], info->xy[1] );
    
    if ( info->ttf_font == NULL ){
        if ( info->openFont( font_file, screen_ratio1, screen_ratio2 ) == NULL ){
            fprintf( stderr, "can't open font file: %s\n", font_file );
            quit();
            exit(-1);
        }
    }
#if defined(PSP)
    else
        info->openFont( font_file, screen_ratio1, screen_ratio2 );
#endif

    if ( info->isEndOfLine() ){
        info->newLine();
        for (int i=0 ; i<indent_offset ; i++){
            if (lookback_flag){
                current_page->add(0x81);
                current_page->add(0x40);
            }
            info->advanceCharInHankaku(2);
        }
    }

    old_xy[0] = info->x();
    old_xy[1] = info->y();

    char text2[2] = {text[0], 0};
    if (IS_TWO_BYTE(text[0])) text2[1] = text[1];

    for (int i=0 ; i<2 ; i++){
        int xy[2];
        xy[0] = info->x() * screen_ratio1 / screen_ratio2;
        xy[1] = info->y() * screen_ratio1 / screen_ratio2;
    
        SDL_Color color;
        SDL_Rect dst_rect;
        if ( info->is_shadow ){
            color.r = color.g = color.b = 0;
            drawGlyph(surface, info, color, text2, xy, true, cache_info, clip, dst_rect);
        }
        color.r = info->color[0];
        color.g = info->color[1];
        color.b = info->color[2];
        drawGlyph( surface, info, color, text2, xy, false, cache_info, clip, dst_rect );

        if ( surface == accumulation_surface &&
             !flush_flag &&
             (!clip || AnimationInfo::doClipping( &dst_rect, clip ) == 0) ){
            dirty_rect.add( dst_rect );
        }
        else if ( flush_flag ){
            info->addShadeArea(dst_rect, shade_distance);
            flushDirect( dst_rect, REFRESH_NONE_MODE );
        }

        if (IS_TWO_BYTE(text[0])){
            info->advanceCharInHankaku(2);
            break;
        }
        info->advanceCharInHankaku(1);
        text2[0] = text[1];
        if (text2[0] == 0) break;
    }

    if ( lookback_flag ){
        current_page->add( text[0] );
        if (text[1]) current_page->add( text[1] );
    }
}
Example #16
0
int main(int argc, char *argv[]){
  KGString *tmp1, *tmp2, *test1, *test2, *filename;
  FILE *err;
  char errbuf[errorFileSize];
  char *pos, *cur;
  int dummy;
  int type;
  
  dummy = initDB();
  
  //set default
  kShotai = kMincho;
  //kShotai = kGothic;
  kSize = 200;
  kType = 0; //png
  kInput = 0; //ids or direct
  kResultText = kg_string_new("");
  kMode = 0;
  
  //confirm request
  type = 0;
  //GET request
  if(type == 0){
    tmp1 = kg_string_new((kgchar *)getenv("QUERY_STRING"));
    if(tmp1->len != 0) type = 2;
  }
  //argv(detect after GET request)
  if(type == 0){
    tmp1 = kg_string_new((kgchar *)argv[1]);
    if(tmp1->len != 0) type = 1;
  }
  //redirect
  if(type == 0){
    tmp1 = kg_string_new((kgchar *)getenv("REDIRECT_URL"));
    if(tmp1->len != 0) type = 3;
  }
  //error
  if(type == 0){
    fprintf(stderr, "Request Error.\n");
    return 0;
  }
  pos = tmp1->str;
  
  //separate token
  if(type == 1 || type == 2){ //argv or GET request
    while(1){
      cur = strchr(pos, '&');
      tmp2 = kg_string_new(pos);
      if(cur != NULL) kg_string_set_size(tmp2, cur - pos);
      //got request string
      if(strncmp(tmp2->str, "shotai=mincho", 13) == 0) kShotai = kMincho;
      else if(strncmp(tmp2->str, "shotai=gothic", 13) == 0) kShotai = kGothic;
      else if(strncmp(tmp2->str, "shotai=skeleton", 15) == 0) kShotai = kGothic;
      else if(strncmp(tmp2->str, "type=png", 8) == 0) kType = 0;
      else if(strncmp(tmp2->str, "type=svg", 8) == 0) kType = 1;
      else if(strncmp(tmp2->str, "type=eps", 8) == 0) kType = 2;
      else if(strncmp(tmp2->str, "type=raw", 8) == 0) kType = 3;
      else if(strncmp(tmp2->str, "input=ids", 9) == 0) kInput = 0;
      else if(strncmp(tmp2->str, "input=directwithadjust", 22) == 0) kInput = 2;
      else if(strncmp(tmp2->str, "input=direct", 12) == 0) kInput = 1;
      else if(strncmp(tmp2->str, "size=24", 7) == 0) kSize = 24;
      else if(strncmp(tmp2->str, "size=200", 8) == 0) kSize = 200;
      else test1 = kg_string_new(tmp2->str);
      if(cur == NULL) break;
      pos = cur + 1;
    }
  }
  else{ // redirected request
    kInput = 0;
    while(1){
      cur = strchr(pos, '/');
      tmp2 = kg_string_new(pos);
      if(cur != NULL) kg_string_set_size(tmp2, cur - pos);
      //got request string
      if(strncmp(tmp2->str, "mincho", 6) == 0) kShotai = kMincho;
      else if(strncmp(tmp2->str, "gothic", 6) == 0) kShotai = kGothic;
      else if(strncmp(tmp2->str, "skeleton", 8) == 0) kShotai = kGothic;
      else if(strncmp(tmp2->str, "v0.4", 4) == 0);
      else test1 = kg_string_new(tmp2->str);
      if(cur == NULL) break;
      pos = cur + 1;
    }
    if(strncmp(test1->str + test1->len - 4, ".png", 4) == 0) kType = 0;
    if(strncmp(test1->str + test1->len - 4, ".svg", 4) == 0) kType = 1;
    if(strncmp(test1->str + test1->len - 4, ".eps", 4) == 0) kType = 2;
    if(strncmp(test1->str + test1->len - 4, ".raw", 4) == 0) kType = 3;
    kg_string_set_size(test1, test1->len - 4);
  }
  
  //clear result buffer
  test2 = kg_string_new("");
  if(kType == 1){ //svg
    kg_string_append(kResultText, "<?xml version=\"1.0\"?>\n");
    kg_string_append(kResultText, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
    kg_string_append(kResultText, "<svg width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\">");
    kg_string_append(kResultText, "<g style=\"fill: black; stroke: black\">");
  }
  else if(kType == 2){ //eps
    kg_string_append(kResultText, "%!PS-Adobe-3.0 EPSF-3.0\n");
    kg_string_append(kResultText, "%%BoundingBox: 0 -208 1024 816\n");
    kg_string_append(kResultText, "%%Pages: 0\n");
    kg_string_append(kResultText, "%%Title: ");
    kg_string_append(kResultText, test1->str);
    kg_string_append(kResultText, "\n");
    kg_string_append(kResultText, "%%Creator: KAGE System\n");
    kg_string_append(kResultText, "%%CreationDate: 00:00 1-1-2004\n");
    kg_string_append(kResultText, "%%EndComments\n");
    kg_string_append(kResultText, "%%EndProlog\n");
    kg_string_append(kResultText, "%%Page \"");
    kg_string_append(kResultText, test1->str);
    kg_string_append(kResultText, "\" 1\n");
    kg_string_append(kResultText, "newpath\n");
  }
  kageCanvas = initPng(canvasWidth, canvasHeight);
  if(kInput == 0) generateGlyph(test1, test2);
  else{
    convert99(test1, test2);
    //	  kg_string_append(test2, test1->str);
  }
  
  if(test2->len != 0) test2 = finalAdjustment(test2);
  
  if(kType == 0){ //png(image)
    if(test2->len != 0){
      if(kInput != 1){ //0 and 2
	test2 = CalcSizes(test2, 1);
      }
      DrawBox();
      drawGlyph(test2, DRAW_GLYPH_MODE_NORMAL);
      //output to file
      filename = kg_string_new(pngFilePath);
      if(kShotai == kMincho) kg_string_append(filename, "mincho/");
      else if(kShotai == kGothic) kg_string_append(filename, "gothic/");//skeleton??
      kg_string_append(filename, test1->str);
      kg_string_append(filename, ".png");
      
      //skip for adjustment mode
      //fp = fopen(filename->str, "w");
      //writePng(pngWidth, pngHeight, kageCanvas, fp);
      //fclose(fp);
      //output to stdout
      if(type != 1) fprintf(stdout, "Content-type: image/png\n\n");
      writePng(pngWidth, pngHeight, kageCanvas, stdout);
      //done
      closePng(pngWidth, pngHeight, kageCanvas);
    }
    else{
      err = fopen(errorFileName, "r");
      fread(errbuf, sizeof(char), errorFileSize, err);
      //printf("An error occurred.\r\n");
      if(type != 1) fprintf(stdout, "Content-type: image/png\n\n");
      fwrite(errbuf, sizeof(char), errorFileSize, stdout);
      fclose(err);
    }
  }
  else if(kType == 1){ //svg(vector graphics)
    if(test2->len != 0){
      test2 = CalcSizes(test2, 1);
      kMode = 1;
      drawGlyph(test2, DRAW_GLYPH_MODE_NORMAL);
      kg_string_append(kResultText, "</g></svg>\n");
      if(type != 1) fprintf(stdout, "Content-type: image/svg-xml\n\n");
      fprintf(stdout, "%s", kResultText->str);
    }
    else{
      if(type != 1) fprintf(stdout, "Content-type: text/plain\n\n");
      fprintf(stdout, "An error occurred.");
    }
  }
  else if(kType == 2){ //eps(vector graphics)
    if(test2->len != 0){
      test2 = CalcSizes(test2, 1);
      kMode = 2;
      drawGlyph(test2, DRAW_GLYPH_MODE_NORMAL);
      kg_string_append(kResultText, "fill\n");
      kg_string_append(kResultText, "%%EOF\n");
      if(type != 1) fprintf(stdout, "Content-type: application/postscript\n\n");
      fprintf(stdout, "%s", kResultText->str);
    }
    else{
      if(type != 1) fprintf(stdout, "Content-type: text/plain\n\n");
      fprintf(stdout, "An error occurred.");
    }
  }
  else{ //raw(text)
    
    if(test2->len != 0){
      test2 = CalcSizes(test2, 1);
      if(type != 1) fprintf(stdout, "Content-type: text/plain\n\n");
      fprintf(stdout, "result=%s", test2->str);
    }
    else{
      if(type != 1) fprintf(stdout, "Content-type: text/plain\n\n");
      fprintf(stdout, "result=nodata");
    }
  }
  dummy = closeDB();
  
  return 0;
}
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const
{
	LLFastTimer _(FTM_RENDER_FONTS);

	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty() || !max_pixels)
	{
		return 0;
	} 

	if (max_chars == -1)
		max_chars = S32_MAX;

	const S32 max_index = llmin(llmax(max_chars, begin_offset + max_chars), S32(wstr.length()));
	if (max_index <= 0 || begin_offset >= max_index || max_pixels <= 0)
		return 0;

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// Strip off any style bits that are already accounted for by the font.
	style = style & (~getFontDesc().getStyle());

	F32 drop_shadow_strength = 0.f;
	if (shadow != NO_SHADOW)
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			shadow = NO_SHADOW;
		}
	}

	gGL.pushUIMatrix();

	gGL.loadUIIdentity();
	
	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));

	// Depth translation, so that floating text appears 'in-world'
	// and is correctly occluded.
	gGL.translatef(0.f,0.f,sCurDepth);

	S32 chars_drawn = 0;
	S32 i;
	S32 length = max_index - begin_offset;

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
	cur_y = ((F32)y * sScaleY) + origin.mV[VY];

	// Offset y by vertical alignment.
	// use unscaled font metrics here
	switch (valign)
	{
	case TOP:
		cur_y -= llceil(mFontFreetype->getAscenderHeight());
		break;
	case BOTTOM:
		cur_y += llceil(mFontFreetype->getDescenderHeight());
		break;
	case VCENTER:
		cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = (F32)ll_round(cur_x);

	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();

	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		S32 string_width = ll_round(getWidthF32(wstr, begin_offset, max_chars) * sScaleX);
		if (string_width > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - ll_round(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}

	const LLFontGlyphInfo* next_glyph = NULL;

	const S32 GLYPH_BATCH_SIZE = 30;
	static LL_ALIGN_16(LLVector4a vertices[GLYPH_BATCH_SIZE * 4]);
	static LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
	static LLColor4U colors[GLYPH_BATCH_SIZE * 4];

	LLColor4U text_color(color);

	S32 bitmap_num = -1;
	S32 glyph_count = 0;
	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			gGL.getTexUnit(0)->bind(ext_image);

			// snap origin to whole screen pixel
			const F32 ext_x = (F32)ll_round(cur_render_x + (EXT_X_BEARING * sScaleX));
			const F32 ext_y = (F32)ll_round(cur_render_y + (EXT_Y_BEARING * sScaleY + mFontFreetype->getAscenderHeight() - mFontFreetype->getLineHeight()));

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);

			if (glyph_count > 0)
			{
				gGL.begin(LLRender::QUADS);
				{
					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
				}
				gGL.end();
				glyph_count = 0;
			}
			renderQuad(vertices, uvs, colors, screen_rect, uv_rect, LLColor4U::white, 0);
			//No batching here. It will never happen.
			gGL.begin(LLRender::QUADS);
			{
				gGL.vertexBatchPreTransformed(vertices, uvs, colors, 4);
			}
			gGL.end();

			if (!label.empty())
			{
				gGL.pushMatrix();
				getFontExtChar()->render(label, 0,
									 /*llfloor*/(ext_x / sScaleX) + ext_image->getWidth() + EXT_X_BEARING - sCurOrigin.mX, 
									 /*llfloor*/(cur_render_y / sScaleY) - sCurOrigin.mY,
									 color,
									 halign, BASELINE, UNDERLINE, NO_SHADOW, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;
		}
		else
		{
			const LLFontGlyphInfo* fgi = next_glyph;
			next_glyph = NULL;
			if(!fgi)
			{
				fgi = mFontFreetype->getGlyphInfo(wch);
			}
			if (!fgi)
			{
				LL_ERRS() << "Missing Glyph Info" << LL_ENDL;
				break;
			}
			// Per-glyph bitmap texture.
			S32 next_bitmap_num = fgi->mBitmapNum;
			if (next_bitmap_num != bitmap_num)
			{
				// Actually draw the queued glyphs before switching their texture;
				// otherwise the queued glyphs will be taken from wrong textures.
				if (glyph_count > 0)
				{
					gGL.begin(LLRender::QUADS);
					{
						gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
					}
					gGL.end();
					glyph_count = 0;
				}

				bitmap_num = next_bitmap_num;
				LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
				gGL.getTexUnit(0)->bind(font_image);
			}

			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
					(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
					(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
			// snap glyph origin to whole screen pixel
			LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing),
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing),
				    (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
			
			if (glyph_count >= GLYPH_BATCH_SIZE)
			{
				gGL.begin(LLRender::QUADS);
				{
					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
				}
				gGL.end();

				glyph_count = 0;
			}

			drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style, shadow, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				next_glyph = mFontFreetype->getGlyphInfo(next_char);
				cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)ll_round(cur_x);
			//cur_y = (F32)ll_round(cur_y);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if(glyph_count)
	{
		gGL.begin(LLRender::QUADS);
		{
			gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
		}
		gGL.end();
	}


	if (right_x)
	{
		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
	}

	if (style & UNDERLINE)
	{
		F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight());

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - descender);
		gGL.vertex2f(cur_x, cur_y - descender);
		gGL.end();
	}

	if (draw_ellipses)
	{

		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushUIMatrix();
		renderUTF8(std::string("..."), 
				0,
				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				shadow,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popUIMatrix();
	}

	gGL.popUIMatrix();

	return chars_drawn;
}
Example #18
0
S32 LLFontGL::render(const LLWString &wstr, 
					 const S32 begin_offset,
					 const F32 x, const F32 y,
					 const LLColor4 &color,
					 const HAlign halign, const VAlign valign,
					 U8 style,
					 const S32 max_chars, S32 max_pixels,
					 F32* right_x,
					 BOOL use_embedded,
					 BOOL use_ellipses) const
{
	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	LLGLEnable tex(GL_TEXTURE_2D);

	if (wstr.empty())
	{
		return 0;
	} 

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// HACK for better bolding
	if (style & BOLD)
	{
		if (this == LLFontGL::sSansSerif)
		{
			return LLFontGL::sSansSerifBold->render(
				wstr, begin_offset,
				x, y,
				color,
				halign, valign, 
				(style & ~BOLD),
				max_chars, max_pixels,
				right_x, use_embedded);
		}
	}

	F32 drop_shadow_strength = 0.f;
	if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
		}
	}

	gGL.pushMatrix();
	glLoadIdentity();
	gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
	//glScalef(sScaleX, sScaleY, 1.0f);
	
	// avoid half pixels
	// RN: if we're going to this trouble, might as well snap to nearest pixel all the time
	// but the plan is to get rid of this so that fonts "just work"
	//F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
	//if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
	//{
		gGL.translatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
	//}

	// this code would just snap to pixel grid, although it seems to introduce more jitter
	//F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
	//F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
	//gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);

	// scale back to native pixel size
	//glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
	//glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
	LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);

	gGL.color4fv( color.mV );

	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

	// Bind the font texture
	
	mImageGLp->bind(0);
	
 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX);
	cur_y = ((F32)y * sScaleY);

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mAscender;
		break;
	case BOTTOM:
		cur_y += mDescender;
		break;
	case VCENTER:
		cur_y -= ((mAscender - mDescender)/2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	// Round properly.
	//cur_render_y = (F32)llfloor(cur_y/sScaleY + 0.5f)*sScaleY;
	//cur_render_x = (F32)llfloor(cur_x/sScaleX + 0.5f)*sScaleX;
	
	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = cur_x;

	F32 inv_width = 1.f / mImageGLp->getWidth();
	F32 inv_height = 1.f / mImageGLp->getHeight();

	const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}


	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			ext_image->bind();
			const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);
			const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight);

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
			drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);

			if (!label.empty())
			{
				gGL.pushMatrix();
				//glLoadIdentity();
				//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
				//glScalef(sScaleX, sScaleY, 1.f);
				gExtCharFont->render(label, 0,
									 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
									 /*llfloor*/(cur_y / sScaleY),
									 color,
									 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			gGL.color4fv(color.mV);

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;

			// Bind the font texture
			mImageGLp->bind();
		}
		else
		{
			if (!hasGlyph(wch))
			{
				(const_cast<LLFontGL*>(this))->addChar(wch);
			}

			const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
			if (!fgi)
			{
				llerrs << "Missing Glyph Info" << llendl;
				break;
			}
			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
							(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height,
							(fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
							(fgi->mYBitmapOffset - PAD_AMT) * inv_height);
			LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT,
								cur_render_y + (F32)fgi->mYBearing + PAD_AMT,
								cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + PAD_AMT,
								cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT);

			drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				if (!hasGlyph(next_char))
				{
					(const_cast<LLFontGL*>(this))->addChar(next_char);
				}
				cur_x += getXKerning(wch, next_char);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)llfloor(cur_x + 0.5f);
			//cur_y = (F32)llfloor(cur_y + 0.5f);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if (right_x)
	{
		*right_x = cur_x / sScaleX;
	}

	if (style & UNDERLINE)
	{
		LLGLSNoTexture no_texture;
		gGL.begin(LLVertexBuffer::LINES);
		gGL.vertex2f(start_x, cur_y - (mDescender));
		gGL.vertex2f(cur_x, cur_y - (mDescender));
		gGL.end();
	}

	// *FIX: get this working in all alignment cases, etc.
	if (draw_ellipses)
	{
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushMatrix();
		//glLoadIdentity();
		//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
		//glScalef(sScaleX, sScaleY, 1.f);
		renderUTF8(std::string("..."), 
				0,
				cur_x / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popMatrix();
	}

	gGL.popMatrix();

	return chars_drawn;
}
// Returns character bytes.
// This is where we process ligatures for display text!
int
PonscripterLabel::drawChar(const char* text, Fontinfo* info, bool flush_flag,
        bool lookback_flag, SDL_Surface* surface, AnimationInfo* cache_info,
    SDL_Rect* clip)
{
    int bytes;
    wchar unicode = file_encoding->DecodeWithLigatures(text, *info, bytes);

    bool code = info->processCode(text);
    bool hidden_language = (current_read_language != -1 && current_read_language != current_language);

    if (!code && !hidden_language) {
        // info->doSize() called in GlyphAdvance
        wchar next = file_encoding->DecodeWithLigatures(text + bytes, *info);
        float adv = info->GlyphAdvance(unicode, next);
        if (isNonspacing(unicode)) info->advanceBy(-adv);

        if (info->isNoRoomFor(adv)) info->newLine();

        float x = info->GetX() * screen_ratio1 / screen_ratio2;
        if (info->getRTL())
            x -= adv;
        int   y = info->GetY() * screen_ratio1 / screen_ratio2;

        SDL_Color color;
        SDL_Rect  dst_rect;
        if (info->is_shadow) {
            color.r = color.g = color.b = 0;
            drawGlyph(surface, info, color, unicode, x, y, true, cache_info,
              clip, dst_rect);
        }

        color.r = info->color.r;
        color.g = info->color.g;
        color.b = info->color.b;    
        drawGlyph(surface, info, color, unicode, x, y, false, cache_info,
          clip, dst_rect);

    info->addShadeArea(dst_rect, shade_distance);
        if (surface == accumulation_surface && !flush_flag
            && (!clip || AnimationInfo::doClipping(&dst_rect, clip) == 0)) {
            dirty_rect.add(dst_rect);
        }
        else if (flush_flag) {
          if (surface == accumulation_surface)
            flush(refreshMode()); // hack to fix skip refresh bug
          flushDirect(dst_rect, REFRESH_NONE_MODE);
        }

        /* ---------------------------------------- */
        /* Update text buffer */
        info->advanceBy(adv);
    }

    // textbufferchange
    int j;
    for (j = 0; j < 2; j++) {
        if (current_read_language == j || current_read_language == -1) {
            if (lookback_flag) {
            current_text_buffer[j]->addBytes(text, bytes);
                if (text[0] == '~') current_text_buffer[j]->addBytes(text, bytes);
        
            }
        }
    }
    TextBuffer_dumpstate(1);
    return bytes;
}
Example #20
0
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
{
	LLFastTimer _(FTM_RENDER_FONTS);

	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty())
	{
		return 0;
	} 

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// determine which style flags need to be added programmatically by stripping off the
	// style bits that are drawn by the underlying Freetype font
	U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();

	F32 drop_shadow_strength = 0.f;
	if (shadow != NO_SHADOW)
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			shadow = NO_SHADOW;
		}
	}

	gGL.pushUIMatrix();

	gGL.loadUIIdentity();
	
	//gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);

	// this code snaps the text origin to a pixel grid to start with
	//F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	//F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
	//gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);

	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));
	// snap the text origin to a pixel grid to start with
	origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);


	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
	cur_y = ((F32)y * sScaleY) + origin.mV[VY];

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mFontFreetype->getAscenderHeight();
		break;
	case BOTTOM:
		cur_y += mFontFreetype->getDescenderHeight();
		break;
	case VCENTER:
		cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f;
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = llround(cur_x);

	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();

	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses)
	{
		// check for too long of a string
		S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX);
		if (string_width > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}

	const LLFontGlyphInfo* next_glyph = NULL;

	const S32 GLYPH_BATCH_SIZE = 30;
	LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
	LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
	LLColor4U colors[GLYPH_BATCH_SIZE * 4];

	LLColor4U text_color(color);

	S32 bitmap_num = -1;
	S32 glyph_count = 0;
	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		const LLFontGlyphInfo* fgi = next_glyph;
		next_glyph = NULL;
		if(!fgi)
		{
			fgi = mFontFreetype->getGlyphInfo(wch);
		}
		if (!fgi)
		{
			llerrs << "Missing Glyph Info" << llendl;
			break;
		}
		// Per-glyph bitmap texture.
		S32 next_bitmap_num = fgi->mBitmapNum;
		if (next_bitmap_num != bitmap_num)
		{
			bitmap_num = next_bitmap_num;
			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
			gGL.getTexUnit(0)->bind(font_image);
		}
	
		if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
		{
			// Not enough room for this character.
			break;
		}

		// Draw the text at the appropriate location
		//Specify vertices and texture coordinates
		LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
				(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
				(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
		// snap glyph origin to whole screen pixel
		LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
				    llround(cur_render_y + (F32)fgi->mYBearing),
				    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
				    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
		
		if (glyph_count >= GLYPH_BATCH_SIZE)
		{
			gGL.begin(LLRender::QUADS);
			{
				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
			}
			gGL.end();

			glyph_count = 0;
		}

		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);

		chars_drawn++;
		cur_x += fgi->mXAdvance;
		cur_y += fgi->mYAdvance;

		llwchar next_char = wstr[i+1];
		if (next_char && (next_char < LAST_CHARACTER))
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(next_char);
			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
		}

		// Round after kerning.
		// Must do this to cur_x, not just to cur_render_x, otherwise you
		// will squish sub-pixel kerned characters too close together.
		// For example, "CCCCC" looks bad.
		cur_x = (F32)llround(cur_x);
		//cur_y = (F32)llround(cur_y);

		cur_render_x = cur_x;
		cur_render_y = cur_y;
	}

	gGL.begin(LLRender::QUADS);
	{
		gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
	}
	gGL.end();


	if (right_x)
	{
		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
	}

	//FIXME: add underline as glyph?
	if (style_to_add & UNDERLINE)
	{
		F32 descender = mFontFreetype->getDescenderHeight();

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - (descender));
		gGL.vertex2f(cur_x, cur_y - (descender));
		gGL.end();
	}

	if (draw_ellipses)
	{
		
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushUIMatrix();
		renderUTF8(std::string("..."), 
				0,
				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style_to_add,
				shadow,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popUIMatrix();
	}

	gGL.popUIMatrix();

	return chars_drawn;
}