示例#1
0
文件: Font.cpp 项目: mfichman/sfr
Glyph Font::glyph(char code) const {
    if (size_t(code) < glyph_.size()) {
        return glyph_[code];
    } else {
        return Glyph();
    }
}
示例#2
0
//-----------------------------------------------------------------------------------------------
BitmapFont::BitmapFont( const std::string& glyphSheetFileName, const std::string& xmlMetaDataFileName )
{
	m_glyphSheet = Texture::CreateOrGetTexture( glyphSheetFileName );

	XMLDocument fontInfo( xmlMetaDataFileName );
	fontInfo.SetCurrentNodeToChild( "FontDefinition" );
	fontInfo.SetCurrentNodeToChild( "FontInfo" );
	m_fontName = GetStringXMLAttribute( fontInfo, "name", "null" );

	while( !fontInfo.GetCurrentNode().IsNull() )
	{
		fontInfo.SetCurrentNodeToNextSibling();

		unsigned int ucsIndex = GetUnsignedIntXMLAttribute( fontInfo, "ucsIndex", 0 );
		unsigned int sheetNumber = GetUnsignedIntXMLAttribute( fontInfo, "sheet", 0 );
		float ttfA = GetFloatXMLAttribute( fontInfo, "ttfA", 0.f );
		float ttfB = GetFloatXMLAttribute( fontInfo, "ttfB", 0.f );
		float ttfC = GetFloatXMLAttribute( fontInfo, "ttfC", 0.f );

		Vector2 texCoordMins = GetVector2XMLAttribute( fontInfo, "texCoordMins", Vector2( 0.f, 0.f ) );
		Vector2 texCoordMaxs = GetVector2XMLAttribute( fontInfo, "texCoordMaxs", Vector2( 0.f, 0.f ) );

		m_glyphData[ ucsIndex ] = Glyph( ucsIndex, sheetNumber, texCoordMins, texCoordMaxs, ttfA, ttfB, ttfC );
	}
}
示例#3
0
float FTGlyphContainer::Advance(const unsigned int charCode,
                                const unsigned int nextCharCode)
{
    unsigned int left = charMap->FontIndex(charCode);
    unsigned int right = charMap->FontIndex(nextCharCode);

    return face->KernAdvance(left, right).Xf() + Glyph(charCode)->Advance();
}
示例#4
0
    void reset() {
        this->glyph_stamp = 0;

        for (auto & array : this->glyphs) {
            for (auto & glyph : array) {
                glyph = Glyph();
            }
        }
    }
示例#5
0
Font::Font(const String &filename) : Image(filename, 16, 16) {
	m_x = 0;
	m_y = 0;
	m_speedX = 0;
	m_speedY = 0;

	for (unsigned short int f = 0; f < GetNumFrames(); f++)
		glyphs.Add(Glyph(0, 0, GetWidth(), GetHeight()));

	int width32 = 0;
	int height32 = 0;
	int *ptrComp = nullptr;
	
	uint8 * const buffer = stbi_load(filename.ToCString(), &width32, &height32, ptrComp, 4);	//this pointer should never be missing
	
	if (buffer) {
		uint8 *ptrBuffer = buffer;

		//0x<A><B><G><R>
		const uint32 red = 0xff0000ff;
		const uint32 yellow = 0xff00ffff;
		const uint32 black = 0xff000000;
		const uint32 transparent = 0x00000000;

		unsigned short int i, j;
		uint16 row = 0;
		uint16 col = 0;

		for (unsigned short int frame = 0; frame < GetNumFrames(); frame++) {
			row = frame / GetHFrames();
			col = frame % GetHFrames();
			ptrBuffer = buffer + ((GetWidth() * col) * 4) + (row * GetHeight() * GetWidth() * GetHFrames() * 4);
			for (j = 0; j < GetHeight(); j++) {
				for (i = 0; i < GetWidth(); i++) {
					//inside each frame
					if (*((uint32 *)(ptrBuffer)) == black)
						memset(ptrBuffer, transparent, 4);
					else if (*((uint32 *)(ptrBuffer)) == yellow) {
						glyphs[frame].SetOrigX(i);
						glyphs[frame].SetOrigY(j);
						memset(ptrBuffer, transparent, 4);
					} else if (*((uint32 *)(ptrBuffer)) == red) {
						glyphs[frame].SetEndX(i);
						glyphs[frame].SetEndY(j);
						memset(ptrBuffer, transparent, 4);
					}
					ptrBuffer += 4;
				}
				ptrBuffer += ((GetHFrames() * GetWidth()) - GetWidth()) * 4;
			}
		}
		Renderer::Instance().GenFontImage(buffer, width32, height32);
		delete buffer;
	}
}
示例#6
0
float FTGlyphContainer::Advance(const unsigned int charCode,
                                const unsigned int nextCharCode)
{
    unsigned int left = FontIndex(charCode);
    unsigned int right = FontIndex(nextCharCode);
    const FTGlyph *glyph = Glyph(charCode);

    if (!glyph)
      return 0.0f;

    return font->KernAdvance(left, right).Xf() + glyph->Advance();
}
void Font::Render(Bitmap& bmp, int const x, int const y, Bitmap const& sys, int color, char32_t code) {
	if(color != ColorShadow) {
		BitmapRef system = Cache::System();
		Render(bmp, x + 1, y + 1, system->GetShadowColor(), code);
	}

	BitmapRef bm = Glyph(code);

	unsigned const
		src_x = color == ColorShadow? 16 : color % 10 * 16 + 2,
		src_y = color == ColorShadow? 32 : color / 10 * 16 + 48 + 16 - bm->height();

	bmp.MaskedBlit(Rect(x, y, bm->width(), bm->height()), *bm, 0, 0, sys, src_x, src_y);
}
	void insertCharacter(char character)
	{
		FT_UInt glyphIndex = FT_Get_Char_Index(_face, character);
		if(glyphIndex == 0) {
			printError("Undefined character.");
			return;
		}

		FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_DEFAULT);
		if(error) {
			printError("Could not load glyph.");
			return;
		}

		FT_GlyphSlot slot = _face->glyph;
		if(slot->format != FT_GLYPH_FORMAT_BITMAP) {
			error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
			if(error) {
				printError("Could not render glyph.");
				return;
			}
		}

		if(_insert.X() + slot->bitmap.width > static_cast<size_t>(_pitch)) {
			_insert = vec2<size_t>(_insert.X(), _insert.Y() + _lineHeight + 1);
			_lineHeight = 0;
		}


		byte * bufferPos = _buffer + _pitch * _insert.Y() + _insert.X();

		byte * const bitmapEnd = abs(slot->bitmap.pitch) * slot->bitmap.rows +
			slot->bitmap.buffer;
		size_t const bitmapPitch = abs(slot->bitmap.pitch);
		for(byte * bitmapPos = slot->bitmap.buffer; bitmapPos < bitmapEnd;
			bitmapPos += bitmapPitch) {
			memcpy(bufferPos, bitmapPos, slot->bitmap.width);

			bufferPos += _pitch;
		}

		vec2<size_t> size(slot->bitmap.width, slot->bitmap.rows);
		_cachedChars[character] = Glyph(_insert, size);

		_insert = vec2<size_t>(_insert.X() + size.X() + 1, _insert.Y());
		if(size.Y() > _lineHeight) {
			_lineHeight = size.Y();
		}
	}
示例#9
0
FTPoint FTGlyphContainer::Render(const unsigned int charCode,
                                 const unsigned int nextCharCode,
                                 FTPoint penPosition)
{
    unsigned int left = FontIndex(charCode);
    unsigned int right = FontIndex(nextCharCode);

    FTPoint kernAdvance = font->KernAdvance(left, right);

    FTGlyph * glyph = Glyph(charCode);
    if (glyph != NULL)
        kernAdvance += glyph->Render(penPosition);

    return kernAdvance;
}
示例#10
0
//--------------------------------------------------------------
void testApp::setup()
{
    ofSetVerticalSync(true);
    ofSetFrameRate(60);
    
    keyPressed('3');
    bDebug = false;

    // Create an alphabet.
    for (int i = 0; i < 26; i++) {
        alphabet.push_back(Glyph());
    }
    alphaScale = 8;

    VF.setupField(60, 40, ofGetWidth(), ofGetHeight());
}
示例#11
0
文件: Font.cpp 项目: elmindreda/Nori
const Font::Glyph* Font::addGlyph(uint32 codepoint)
{
  const int index = m_face->indexForCodePoint(codepoint);
  if (!index)
    return nullptr;

  m_glyphs.push_back(Glyph());
  Glyph& glyph = m_glyphs.back();

  glyph.codepoint = codepoint;
  glyph.advance = ceil(m_face->advance(index, m_scale));
  glyph.bearing = ceil(m_face->bearing(index, m_scale));

  if (Ref<Image> image = m_face->glyph(index, m_scale))
  {
    if (m_position.x + image->width() + 1 > m_texture->width())
    {
      m_position.x = 1;
      m_position.y += int(m_height) + 1;

      if (m_position.y + image->height() + 1 > m_texture->height())
      {
        if (!addGlyphTextureRow())
          return nullptr;
      }
    }

    if (!m_texture->copyFrom(0, *image, m_position.x, m_position.y))
    {
      logError("Failed to copy glyph image data for font %s",
                name().c_str());
      return nullptr;
    }

    glyph.offset = vec2(m_position);
    glyph.size = vec2(image->width(), image->height());

    m_position.x += image->width() + 1;
  }

  return &glyph;
}
示例#12
0
void SCR_DrawConsoleFontUnichar( float x, float y, int ch )
{
	if ( cls.useLegacyConsoleFont )
	{
		SCR_DrawSmallUnichar( ( int ) x, ( int ) y, ch );
		return;
	}

	if ( ch != ' ' )
	{
		glyphInfo_t *glyph = Glyph( ch );
		float       yadj = glyph->top;
		float       xadj = ( SCR_ConsoleFontUnicharWidth( ch ) - glyph->xSkip ) / 2.0;

		re.DrawStretchPic( x + xadj, y - yadj, glyph->imageWidth, glyph->imageHeight,
		                   glyph->s, glyph->t,
		                   glyph->s2, glyph->t2,
		                   glyph->glyph );
	}
}
示例#13
0
	//////////////////////////////////////////////////////////
	// Protected member functions
	/////////////////////////////////////////////////////////
	Font::Glyph Font::loadGlyph( XMLParser& parser, XMLNode* node )
	{
		unsigned int ucsIndex = 0;
		unsigned int sheet = 0;
		
		ucsIndex = (unsigned int)parser.getXMLAttributeAsInt( node, "ucsIndex", 0 );
		sheet = (unsigned int)parser.getXMLAttributeAsInt( node, "sheet", 0 );
				
		vec2f texCoordMin = parser.getXMLAttributeAsVec2( node, "texCoordMins", vec2f( -1.0f ) );
		vec2f texCoordMax = parser.getXMLAttributeAsVec2( node, "texCoordMaxs", vec2f( -1.0f ) );

		assertion( texCoordMin.x != -1.0f, "Min texture coordinate invalid" );
		assertion( texCoordMax.x != 1.0f, "Max texture coordinate invalid" );
				
		float A = parser.getXMLAttributeAsFloat( node, "ttfA", -1000.0f );
		float B = parser.getXMLAttributeAsFloat( node, "ttfB", -1000.0f);
		float C = parser.getXMLAttributeAsFloat( node, "ttfC", -1000.0f );
		assertion( A != -1000.0f, "Error loading A value for font: %s", m_fontName.c_str() );
		assertion( B != -1000.0f, "Error loading B value for font: %s", m_fontName.c_str() );
		assertion( C != -1000.0f, "Error loading C value for font: %s", m_fontName.c_str() );

		return Glyph( ( unsigned char )ucsIndex, ( unsigned char )sheet, 
			texCoordMin, texCoordMax, A, B, C );
	}
示例#14
0
FTBBox FTGlyphContainer::BBox(const unsigned int charCode) const
{
    return Glyph(charCode)->BBox();
}
示例#15
0
		row = ch>>4;
		col = ch&15;

		frow = row*0.0625;
		fcol = col*0.0625;
		size = 0.0625;

		// adjust for baseline
		re.DrawStretchPic( x, y - (int)( SMALLCHAR_HEIGHT / ( CONSOLE_FONT_VPADDING + 1 ) ),
		                SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
				fcol, frow,
				fcol + size, frow + size,
				cls.charSetShader );
	} else {
		glyphInfo_t *glyph = Glyph( ch );

		re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, glyph->imageHeight,
				glyph->s,
				glyph->t,
				glyph->s2,
				glyph->t2,
				glyph->glyph );
	}
}

/*
==================
SCR_DrawSmallString[Color]

Draws a multi-colored string with a drop shadow, optionally forcing
示例#16
0
const Glyph& TextRenderer::getGlyph(char c) {
    Glyph& glyph = _glyphs[c];
    if (glyph.isValid()) {
        return glyph;
    }
    // we use 'J' as a representative size for the solid block character
    QChar ch = (c == SOLID_BLOCK_CHAR) ? QChar('J') : QChar(c);
    QRect bounds = _metrics.boundingRect(ch);
    if (bounds.isEmpty()) {
        glyph = Glyph(0, QPoint(), QRect(), _metrics.width(ch));
        return glyph;
    }
    // grow the bounds to account for effect, if any
    if (_effectType == SHADOW_EFFECT) {
        bounds.adjust(-_effectThickness, 0, 0, _effectThickness);
    
    } else if (_effectType == OUTLINE_EFFECT) {
        bounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness);
    }
    
    // grow the bounds to account for antialiasing
    bounds.adjust(-1, -1, 1, 1);
    
    if (_x + bounds.width() > IMAGE_SIZE) {
        // we can't fit it on the current row; move to next
        _y += _rowHeight;
        _x = _rowHeight = 0;
    }
    if (_y + bounds.height() > IMAGE_SIZE) {
        // can't fit it on current texture; make a new one
        glGenTextures(1, &_currentTextureID);
        _x = _y = _rowHeight = 0;
        
        glBindTexture(GL_TEXTURE_2D, _currentTextureID);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE, IMAGE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        _allTextureIDs.append(_currentTextureID);
           
    } else {
        glBindTexture(GL_TEXTURE_2D, _currentTextureID);
    }
    // render the glyph into an image and copy it into the texture
    QImage image(bounds.width(), bounds.height(), QImage::Format_ARGB32);
    if (c == SOLID_BLOCK_CHAR) {
        image.fill(QColor(255, 255, 255));
    
    } else {
        image.fill(0);
        QPainter painter(&image);
        painter.setFont(_font);
        if (_effectType == SHADOW_EFFECT) {
            for (int i = 0; i < _effectThickness; i++) {
                painter.drawText(-bounds.x() - 1 - i, -bounds.y() + 1 + i, ch);
            }
        } else if (_effectType == OUTLINE_EFFECT) {
            QPainterPath path;
            QFont font = _font;
            font.setStyleStrategy(QFont::ForceOutline);
            path.addText(-bounds.x() - 0.5, -bounds.y() + 0.5, font, ch);
            QPen pen;
            pen.setWidth(_effectThickness);
            pen.setJoinStyle(Qt::RoundJoin);
            pen.setCapStyle(Qt::RoundCap);
            painter.setPen(pen);
            painter.setRenderHint(QPainter::Antialiasing);
            painter.drawPath(path);
        }
        painter.setPen(QColor(255, 255, 255));
        painter.drawText(-bounds.x(), -bounds.y(), ch);
    }    
    glTexSubImage2D(GL_TEXTURE_2D, 0, _x, _y, bounds.width(), bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
       
    glyph = Glyph(_currentTextureID, QPoint(_x, _y), bounds, _metrics.width(ch));
    _x += bounds.width();
    _rowHeight = qMax(_rowHeight, bounds.height());
    
    glBindTexture(GL_TEXTURE_2D, 0);
    return glyph;
}
示例#17
0
	RenderedSubtitle* Renderer::Lookup(const Subtitle* s, const CSize& vs, const CRect& vr)
	{
		m_sra.UpdateTarget(vs, vr);

		if(s->m_text.IsEmpty()) {
			return NULL;
		}

		CRect spdrc = s->m_frame.reference == _T("video") ? vr : CRect(CPoint(0, 0), vs);

		if(spdrc.IsRectEmpty()) {
			return NULL;
		}

		RenderedSubtitle* rs = NULL;

		if(m_rsc.Lookup(s->m_name, rs)) {
			if(!s->m_animated && rs->m_spdrc == spdrc) {
				return rs;
			}

			m_rsc.Invalidate(s->m_name);
		}

		const Style& style = s->m_text.GetHead().style;

		Size scale;

		scale.cx = (float)spdrc.Width() / s->m_frame.resolution.cx;
		scale.cy = (float)spdrc.Height() / s->m_frame.resolution.cy;

		CRect frame;

		frame.left = (int)(64.0f * (spdrc.left + style.placement.margin.l * scale.cx) + 0.5);
		frame.top = (int)(64.0f * (spdrc.top + style.placement.margin.t * scale.cy) + 0.5);
		frame.right = (int)(64.0f * (spdrc.right - style.placement.margin.r * scale.cx) + 0.5);
		frame.bottom = (int)(64.0f * (spdrc.bottom - style.placement.margin.b * scale.cy) + 0.5);

		CRect clip;

		if(style.placement.clip.l == -1) {
			clip.left = 0;
		} else {
			clip.left = (int)(spdrc.left + style.placement.clip.l * scale.cx);
		}
		if(style.placement.clip.t == -1) {
			clip.top = 0;
		} else {
			clip.top = (int)(spdrc.top + style.placement.clip.t * scale.cy);
		}
		if(style.placement.clip.r == -1) {
			clip.right = vs.cx;
		} else {
			clip.right = (int)(spdrc.left + style.placement.clip.r * scale.cx);
		}
		if(style.placement.clip.b == -1) {
			clip.bottom = vs.cy;
		} else {
			clip.bottom = (int)(spdrc.top + style.placement.clip.b * scale.cy);
		}

		clip.left = max(clip.left, 0);
		clip.top = max(clip.top, 0);
		clip.right = min(clip.right, vs.cx);
		clip.bottom = min(clip.bottom, vs.cy);

		scale.cx *= 64;
		scale.cy *= 64;

		bool vertical = s->m_direction.primary == _T("down") || s->m_direction.primary == _T("up");

		// create glyph paths

		WCHAR c_prev = 0, c_next;

		CAutoPtrList<Glyph> glyphs;

		POSITION pos = s->m_text.GetHeadPosition();
		while(pos) {
			const Text& t = s->m_text.GetNext(pos);

			LOGFONT lf;
			memset(&lf, 0, sizeof(lf));
			lf.lfCharSet = DEFAULT_CHARSET;
			_tcscpy_s(lf.lfFaceName, CString(t.style.font.face));
			lf.lfHeight = (LONG)(t.style.font.size * scale.cy + 0.5);
			lf.lfWeight = (LONG)(t.style.font.weight + 0.5);
			lf.lfItalic = !!t.style.font.italic;
			lf.lfUnderline = !!t.style.font.underline;
			lf.lfStrikeOut = !!t.style.font.strikethrough;
			lf.lfOutPrecision = OUT_TT_PRECIS;
			lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
			lf.lfQuality = ANTIALIASED_QUALITY;
			lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;

			FontWrapper* font = m_fc.Create(m_hDC, lf);

			if(!font) {
				_tcscpy_s(lf.lfFaceName, _T("Arial"));

				font = m_fc.Create(m_hDC, lf);
				if(!font) {
					ASSERT(0);
					continue;
				}
			}

			HFONT hOldFont = SelectFont(m_hDC, *font);

			const TEXTMETRIC& tm = font->GetTextMetric();

			for(LPCWSTR c = t.str; *c; c++) {
				CAutoPtr<Glyph> g(DNew Glyph());

				g->c = *c;
				g->style = t.style;
				g->scale = scale;
				g->vertical = vertical;
				g->font = font;

				c_next = !c[1] && pos ? c_next = s->m_text.GetAt(pos).str[0] : c[1];
				Arabic::Replace(g->c, c_prev, c_next);
				c_prev = c[0];

				CSize extent;
				GetTextExtentPoint32W(m_hDC, &g->c, 1, &extent);
				ASSERT(extent.cx >= 0 && extent.cy >= 0);

				if(vertical) {
					g->spacing = (int)(t.style.font.spacing * scale.cy + 0.5);
					g->ascent = extent.cx / 2;
					g->descent = extent.cx - g->ascent;
					g->width = extent.cy;

					// TESTME
					if(g->c == Text::SP) {
						g->width /= 2;
					}
				} else {
					g->spacing = (int)(t.style.font.spacing * scale.cx + 0.5);
					g->ascent = tm.tmAscent;
					g->descent = tm.tmDescent;
					g->width = extent.cx;
				}

				if(g->c == Text::LSEP) {
					g->spacing = 0;
					g->width = 0;
					g->ascent /= 2;
					g->descent /= 2;
				} else {
					GlyphPath* path = m_gpc.Create(m_hDC, font, g->c);
					if(!path) {
						ASSERT(0);
						continue;
					}
					g->path = *path;
				}

				glyphs.AddTail(g);
			}

			SelectFont(m_hDC, hOldFont);
		}

		// break glyphs into rows

		CAutoPtrList<Row> rows;
		CAutoPtr<Row> row;

		pos = glyphs.GetHeadPosition();
		while(pos) {
			CAutoPtr<Glyph> g = glyphs.GetNext(pos);
			if(!row) {
				row.Attach(DNew Row());
			}
			WCHAR c = g->c;
			row->AddTail(g);
			if(c == Text::LSEP || !pos) {
				rows.AddTail(row);
			}
		}

		// kerning

		if(s->m_direction.primary == _T("right")) { // || s->m_direction.primary == _T("left")
			for(POSITION rpos = rows.GetHeadPosition(); rpos; rows.GetNext(rpos)) {
				Row* r = rows.GetAt(rpos);

				POSITION gpos = r->GetHeadPosition();
				while(gpos) {
					Glyph* g1 = r->GetNext(gpos);
					if(!gpos) {
						break;
					}

					Glyph* g2 = r->GetAt(gpos);
					if(g1->font != g2->font || !g1->style.font.kerning || !g2->style.font.kerning) {
						continue;
					}

					if(int size = g1->font->GetKernAmount(g1->c, g2->c)) {
						g2->path.MovePoints(CPoint(size, 0));
						g2->width += size;
					}
				}
			}
		}

		// wrap rows

		if(s->m_wrap == _T("normal") || s->m_wrap == _T("even")) {
			int maxwidth = abs((int)(vertical ? frame.Height() : frame.Width()));
			int minwidth = 0;

			for(POSITION rpos = rows.GetHeadPosition(); rpos; rows.GetNext(rpos)) {
				Row* r = rows.GetAt(rpos);

				POSITION brpos = NULL;

				if(s->m_wrap == _T("even")) {
					int fullwidth = 0;

					for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
						const Glyph* g = r->GetAt(gpos);

						fullwidth += g->width + g->spacing;
					}

					fullwidth = abs(fullwidth);

					if(fullwidth > maxwidth) {
						maxwidth = fullwidth / ((fullwidth / maxwidth) + 1);
						minwidth = maxwidth;
					}
				}

				int width = 0;

				for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
					const Glyph* g = r->GetAt(gpos);

					width += g->width + g->spacing;

					if(brpos && abs(width) > maxwidth && g->c != Text::SP) {
						row.Attach(DNew Row());
						POSITION next = brpos;
						r->GetNext(next);
						do {
							row->AddHead(r->GetPrev(brpos));
						} while(brpos);
						rows.InsertBefore(rpos, row);
						while(!r->IsEmpty() && r->GetHeadPosition() != next) {
							r->RemoveHeadNoReturn();
						}
						g = r->GetAt(gpos = next);
						width = g->width + g->spacing;
					}

					if(abs(width) >= minwidth) {
						if(g->style.linebreak == _T("char")
								|| g->style.linebreak == _T("word") && g->c == Text::SP) {
							brpos = gpos;
						}
					}
				}
			}
		}

		// trim rows

		for(POSITION pos = rows.GetHeadPosition(); pos; rows.GetNext(pos)) {
			Row* r = rows.GetAt(pos);

			while(!r->IsEmpty() && r->GetHead()->c == Text::SP) {
				r->RemoveHead();
			}

			while(!r->IsEmpty() && r->GetTail()->c == Text::SP) {
				r->RemoveTail();
			}
		}

		// calc fill width for each glyph

		CAtlList<Glyph*> glypsh2fill;
		int fill_id = 0;
		int fill_width = 0;

		for(POSITION pos = rows.GetHeadPosition(); pos; rows.GetNext(pos)) {
			Row* r = rows.GetAt(pos);

			POSITION gpos = r->GetHeadPosition();
			while(gpos) {
				Glyph* g = r->GetNext(gpos);

				if(!glypsh2fill.IsEmpty() && fill_id && (g->style.fill.id != fill_id || !pos && !gpos)) {
					int w = (int)(g->style.fill.width * fill_width + 0.5);

					while(!glypsh2fill.IsEmpty()) {
						Glyph* g = glypsh2fill.RemoveTail();
						fill_width -= g->width;
						g->fill = w - fill_width;
					}

					ASSERT(glypsh2fill.IsEmpty());
					ASSERT(fill_width == 0);

					glypsh2fill.RemoveAll();
					fill_width = 0;
				}

				fill_id = g->style.fill.id;

				if(g->style.fill.id) {
					glypsh2fill.AddTail(g);
					fill_width += g->width;
				}
			}
		}

		// calc row sizes and total subtitle size

		CSize size(0, 0);

		if(s->m_direction.secondary == _T("left") || s->m_direction.secondary == _T("up")) {
			ReverseList(rows);
		}

		for(POSITION pos = rows.GetHeadPosition(); pos; rows.GetNext(pos)) {
			Row* r = rows.GetAt(pos);

			if(s->m_direction.primary == _T("left") || s->m_direction.primary == _T("up")) {
				ReverseList(*r);
			}

			int w = 0, h = 0;

			r->width = 0;

			for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
				const Glyph* g = r->GetAt(gpos);

				w += g->width;
				if(gpos) {
					w += g->spacing;
				}
				h = max(h, g->ascent + g->descent);

				r->width += g->width;
				if(gpos) {
					r->width += g->spacing;
				}
				r->ascent = max(r->ascent, g->ascent);
				r->descent = max(r->descent, g->descent);
				r->border = max(r->border, g->GetBackgroundSize());
			}

			for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
				Glyph* g = r->GetAt(gpos);
				g->row_ascent = r->ascent;
				g->row_descent = r->descent;
			}

			if(vertical) {
				size.cx += h;
				size.cy = max(size.cy, w);
			} else {
				size.cx = max(size.cx, w);
				size.cy += h;
			}
		}

		// align rows and calc glyph positions

		rs = DNew RenderedSubtitle(spdrc, clip);

		CPoint p = GetAlignPoint(style.placement, scale, frame, size);
		CPoint org = GetAlignPoint(style.placement, scale, frame);

		// collision detection

		if(!s->m_animated) {
			int tlb = !rows.IsEmpty() ? rows.GetHead()->border : 0;
			int brb = !rows.IsEmpty() ? rows.GetTail()->border : 0;

			CRect r(p, size);
			m_sra.GetRect(r, s, style.placement.align, tlb, brb);
			org += r.TopLeft() - p;
			p = r.TopLeft();
		}

		CRect subrect(p, size);

		// continue positioning

		for(POSITION pos = rows.GetHeadPosition(); pos; rows.GetNext(pos)) {
			Row* r = rows.GetAt(pos);

			CSize rsize;
			rsize.cx = rsize.cy = r->width;

			if(vertical) {
				p.y = GetAlignPoint(style.placement, scale, frame, rsize).y;

				for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
					CAutoPtr<Glyph> g = r->GetAt(gpos);
					g->tl.x = p.x + (int)(g->style.placement.offset.x * scale.cx + 0.5) + r->ascent - g->ascent;
					g->tl.y = p.y + (int)(g->style.placement.offset.y * scale.cy + 0.5);
					p.y += g->width + g->spacing;
					rs->m_glyphs.AddTail(g);
				}

				p.x += r->ascent + r->descent;
			} else {
				p.x = GetAlignPoint(style.placement, scale, frame, rsize).x;

				for(POSITION gpos = r->GetHeadPosition(); gpos; r->GetNext(gpos)) {
					CAutoPtr<Glyph> g = r->GetAt(gpos);
					g->tl.x = p.x + (int)(g->style.placement.offset.x * scale.cx + 0.5);
					g->tl.y = p.y + (int)(g->style.placement.offset.y * scale.cy + 0.5) + r->ascent - g->ascent;
					p.x += g->width + g->spacing;
					rs->m_glyphs.AddTail(g);
				}

				p.y += r->ascent + r->descent;
			}
		}

		// bkg, precalc style.placement.path, transform

		pos = rs->m_glyphs.GetHeadPosition();
		while(pos) {
			Glyph* g = rs->m_glyphs.GetNext(pos);
			g->CreateBkg();
			g->CreateSplineCoeffs(spdrc);
			g->Transform(org, subrect);
		}

		// merge glyphs (TODO: merge 'fill' too)

		Glyph* g0 = NULL;

		pos = rs->m_glyphs.GetHeadPosition();
		while(pos) {
			POSITION cur = pos;

			Glyph* g = rs->m_glyphs.GetNext(pos);

			CRect r = g->bbox + g->tl;

			int size = (int)(g->GetBackgroundSize() + 0.5);
			int depth = (int)(g->GetShadowDepth() + 0.5);

			r.InflateRect(size, size);
			r.InflateRect(depth, depth);

			r.left >>= 6;
			r.top >>= 6;
			r.right = (r.right + 32) >> 6;
			r.bottom = (r.bottom + 32) >> 6;

			if((r & clip).IsRectEmpty()) { // clip
				rs->m_glyphs.RemoveAt(cur);
			} else if(g0 && g0->style.IsSimilar(g->style)) { // append
				CPoint o = g->tl - g0->tl;

				g->path.MovePoints(o);

				g0->path.types.Append(g->path.types);
				g0->path.points.Append(g->path.points);

				g->path_bkg.MovePoints(o);

				g0->path_bkg.types.Append(g->path_bkg.types);
				g0->path_bkg.points.Append(g->path_bkg.points);

				g0->bbox |= g->bbox + o;

				rs->m_glyphs.RemoveAt(cur);
			} else { // leave alone
				g0 = g;
			}
		}

		// rasterize

		pos = rs->m_glyphs.GetHeadPosition();
		while(pos) {
			rs->m_glyphs.GetNext(pos)->Rasterize();
		}

		// cache

		m_rsc.Add(s->m_name, rs);

		m_fc.Flush();

		return rs;
	}
示例#18
0
Font::Font(const String& filename) : Image(filename, 16, 16)
{
	_glyphs = Array<Glyph>();
	Glyph myGlyph = Glyph();

	// Cargamos el buffer con la imagen
	int iWidth;
	int iHeight;
	unsigned char* buffer = stbi_load(filename.ToCString(), &iWidth, &iHeight, NULL, nElemPixel);

	// Calculamos las dimensiones de cada frame
	bool dimX = false;
	for (int i = 1; i < iWidth / nElemPixel && !dimX; i++)
	{
		uint8 r = buffer[i * nElemPixel];
		uint8 g = buffer[i * nElemPixel + 1];
		uint8 b = buffer[i * nElemPixel + 2];
		if (IsColor(r, g, b, 255, 255, 0))
		{
			_dimFrameX = i;
			dimX = true;
		}
	}
	bool dimY = false;
	for (int i = 1; i < iHeight / nElemPixel && !dimY; i++)
	{
		uint8 r = buffer[i * iWidth * nElemPixel];
		uint8 g = buffer[i * iWidth * nElemPixel + 1];
		uint8 b = buffer[i * iWidth * nElemPixel + 2];
		if (IsColor(r, g, b, 255, 255, 0))
		{
			_dimFrameY = i;
			dimY = true;
		}
	}

	// Tratamos los pixeles dentro de cada frame
	if ( buffer ) {
		if (dimX && dimY)
		{
			for (int j = 0; j < nFrameY; j++)
			{
				for (int i = 0; i < nFrameX; i++)
				{
					// Accedemos al frame[i,j]
					for (int k = 0; k < _dimFrameX; k++)
					{
						for (int l = 0; l < _dimFrameY; l++)
						{
							// Accedemos al pixel[k,l] del frame[i,j]
							uint8 r = buffer[IndexFrom(i, j, k, l, iWidth, 0)];
							uint8 g = buffer[IndexFrom(i, j, k, l, iWidth, 1)];
							uint8 b = buffer[IndexFrom(i, j, k, l, iWidth, 2)];
							if (IsColor(r, g, b, 255, 255, 0))
							{
								myGlyph.SetIni(i * _dimFrameX + k, j * _dimFrameY + l);
								buffer[IndexFrom(i, j, k, l, iWidth, 3)] = 0;
							}
							else if (IsColor(r, g, b, 255, 0, 0))
							{
								myGlyph.SetFin(i * _dimFrameX + k, j * _dimFrameY + l);
								buffer[IndexFrom(i, j, k, l, iWidth, 3)] = 0;
							}
							else if (IsColor(r, g, b, 0, 0, 0))
							{
								buffer[IndexFrom(i, j, k, l, iWidth, 3)] = 0;
							}
						}
					}
					if (myGlyph.GetIniX() != 0 || myGlyph.GetIniY() != 0 || myGlyph.GetFinX() != 0 || myGlyph.GetFinY() != 0)
						_glyphs.Add(myGlyph);
				}
			}
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
		}
		free(buffer);
	}
}
void Font::Render(Bitmap& bmp, int x, int y, Color const& color, char32_t code) {
	BitmapRef bm = Glyph(code);

	bmp.MaskedBlit(Rect(x, y, bm->width(), bm->height()), *bm, 0, 0, color);
}