Exemple #1
0
//----------------------------------------------------------------//
void MOAIDraw::DrawString ( cc8* text, float x, float y, float width, float height ) {

	// Sanity check
	size_t textLength = strlen ( text );
	if ( textLength <= 0 ) return;
	
	// Get the context data
	assert ( g_CurrentTextDrawContext );

	// Transform the center into 'world' space
	MOAIGfxDevice& gfxDevice = MOAIGfxDevice::Get ();
	const ZLMatrix4x4& orgWorldTransform = gfxDevice.GetVertexTransform ( MOAIGfxDevice::VTX_WORLD_TRANSFORM );
	USVec2D pos ( x, y );
	orgWorldTransform.Transform ( pos );
	x = pos.mX;
	y = pos.mY;

	// Extract the 'state'
	MOAIFont& font = *g_CurrentTextDrawContext->mFont;
	float scale = g_CurrentTextDrawContext->mScale;
	float fontSize = g_CurrentTextDrawContext->mFontSize;
	
	MOAIGlyphSet* glyphSet = font.GetGlyphSet ( fontSize );
	assert ( glyphSet );

	// Let's draw the string!
	float cursorX = x;
	float cursorY = y + glyphSet->GetAscent() * scale;
	MOAIGlyph* prevGlyph = 0;
	
	// Update the glyph cache
	for ( size_t i = 0; i < textLength; i++ ) {

		cc8 c = text [ i ];
		if ( c != '\n' ) {

			font.AffirmGlyph ( fontSize, c );
		}
	}
	font.ProcessGlyphs ();

	glyphSet = font.GetGlyphSet ( fontSize );
	assert ( glyphSet );

	for ( size_t i = 0; i < textLength; i++ ) {

		cc8 c = text [ i ];
		if ( c == '\n' ) {

			// Move to the next line
			cursorX = x;
			cursorY += glyphSet->GetHeight () * scale;
			prevGlyph = 0;

			if ( height > 0 && (cursorY - y) > height ) {
				break;
			}
		}
		else {

			if ( width > 0 && (cursorX - x) > width ) {
				continue;
			}

			// Get the glyph for the current character
			MOAIGlyph* glyph = glyphSet->GetGlyph ( c );
			if ( glyph ) {

				// Draw the current glyph
				MOAITextureBase* glyphTexture = font.GetGlyphTexture ( *glyph );
				if ( glyphTexture ) {

					GlyphPlacement placement = { glyph, cursorX, cursorY };
					g_CurrentTextDrawContext->mGlyphs.push_back( placement );
				}

				// Apply kerning
				if ( prevGlyph ) {

					MOAIKernVec kern = prevGlyph->GetKerning ( glyph->GetCode () );
					cursorX += kern.mX * scale;
				}

				// Move the cursor
				cursorX += glyph->GetAdvanceX () * scale;
			}

			prevGlyph = glyph;
		}
	}
}
Exemple #2
0
//----------------------------------------------------------------//
void MOAITextDesigner::BuildLayout ( MOAITextBox& textBox ) {
	
	if ( !textBox.mStyleMap.GetTop ()) return;
	
	this->mStr = textBox.mText;
	this->mIdx = textBox.mCurrentPageIdx;
	this->mStyleSpan = 0;
	this->mStyle = 0;
	
	int tokenIdx = this->mIdx;
	int lineIdx = this->mIdx;
	
	float width = textBox.mFrame.Width ();
	float height = textBox.mFrame.Height ();
	
	u32 lineStart = 0;
	u32 lineSize = 0;
	
	u32 tokenStart = 0;
	u32 tokenSize = 0;
	
	USRect lineRect;
	lineRect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
	
	USRect tokenRect;
	tokenRect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
	
	float tokenAscent = 0.0f;
	float lineAscent = 0.0f;

	USVec2D pen;
	pen.Init ( 0.0f, 0.0f );
	
	MOAIGlyph* glyph = 0;
	MOAIGlyph* prevGlyph = 0;
	
	textBox.mMore = true;
	
	bool more = true;
	while ( more ) {
	
		u32 c = this->NextChar ( textBox );
		
		float scale = textBox.mGlyphScale * ( this->mStyle ? this->mStyle->mScale : 1.0f );
		
		bool acceptToken = false;
		bool acceptLine = false;
		
		if ( MOAIFont::IsControl ( c )) {
		
			if ( c == '\n' ) {
				
				tokenIdx = this->mIdx - 1;
				tokenStart = textBox.mSprites.GetTop ();
				acceptToken = true;
				acceptLine = true;
				
				if ( !tokenRect.Height ()) {
					tokenRect.mYMax += this->mDeck->mHeight * scale;
				}	
			}
			else if ( c == 0 ) {
				textBox.mMore = false;
				
				tokenIdx = this->mIdx - 1;
				tokenStart = textBox.mSprites.GetTop ();
				acceptToken = true;
				acceptLine = true;
				more = false;
			}
		}
		else {
			
			glyph = this->mDeck->GetGlyph ( c );
			
			if ( !glyph ) continue;
			if ( glyph->mAdvanceX == 0.0f ) continue;
			
			// apply kerning
			if ( prevGlyph ) {
				MOAIKernVec kernVec = prevGlyph->GetKerning ( glyph->mCode );
				pen.mX += kernVec.mX * scale;
			}
			
			prevGlyph = glyph;
			
			if ( MOAIFont::IsWhitespace ( c )) {
				if ( tokenSize ) {
					acceptToken = true;
				}
			}
			else {
				
				float glyphBottom = pen.mY + ( this->mDeck->mHeight * scale );
				
				// handle new token
				if ( !tokenSize ) {
					tokenIdx = this->mIdx - 1;
					tokenStart = textBox.mSprites.GetTop ();
					tokenRect.Init ( pen.mX, pen.mY, pen.mX, glyphBottom );
					tokenAscent = this->mDeck->mAscent * scale;
				}
				
				// check for overrun
				float glyphRight = pen.mX + (( glyph->mBearingX + glyph->mWidth ) * scale );
				bool overrun = glyphRight > width;
				acceptLine = ( lineSize && overrun );
				
				if ( acceptLine || !overrun ) {
					textBox.PushSprite ( this->mIdx - 1, *glyph, *this->mStyle, pen.mX, pen.mY, scale );
					tokenRect.mXMax = glyphRight;
					tokenSize++;
				}
			}
			
			pen.mX += glyph->mAdvanceX * scale;
		}
		
		if ( acceptToken ) {
			
			lineRect.Grow ( tokenRect );
			lineSize += tokenSize;
			lineAscent = tokenAscent > lineAscent ? tokenAscent : lineAscent;
			tokenSize = 0;
		}
		
		if ( acceptLine ) {
			
			textBox.PushLine ( lineStart, lineSize, lineRect, lineAscent );
			
			// end line
			pen.mY += lineRect.Height () + textBox.mLineSpacing;
			lineRect.Init ( 0.0f, pen.mY, 0.0f, pen.mY );
			
			// next line
			lineIdx = tokenIdx;
			lineStart = tokenStart;
			lineSize = 0;
			lineAscent = 0.0f;
			
			prevGlyph = 0;
			
			if ( tokenSize ){
				
				// slide the current token (if any) back to the origin
				for ( u32 i = 0; i < tokenSize; ++i ) {
					MOAITextSprite& sprite = textBox.mSprites [ tokenStart + i ];
					sprite.mX -= tokenRect.mXMin;
					sprite.mY = pen.mY;
				}
				
				pen.mX -= tokenRect.mXMin;
				tokenRect.Init ( 0.0f, pen.mY, tokenRect.Width (), pen.mY + tokenRect.Height ());
			}
			else {
				pen.mX = 0.0f;
				tokenRect.Init ( 0.0f, pen.mY, 0.0f, pen.mY + this->mDeck->mHeight );
			}
		}
		
		// if we overrun height, then back up to the start of the current line
		if ( tokenRect.mYMax > height ) {
			textBox.mSprites.SetTop ( lineStart );
			textBox.mNextPageIdx = lineIdx;
			more = false;
		}
	}
	
	if ( textBox.mSprites.GetTop () == 0 ) {
		textBox.mMore = false;
		return;
	}
		
	float yOff = textBox.mFrame.mYMin;
	float layoutHeight = lineRect.mYMax;

	switch ( textBox.mVAlign ) {
		
		case MOAITextBox::CENTER_JUSTIFY:
			yOff = ( yOff + ( height * 0.5f )) - ( layoutHeight * 0.5f );
			
		case MOAITextBox::LEFT_JUSTIFY:
			break;

		case MOAITextBox::RIGHT_JUSTIFY:
			yOff = textBox.mFrame.mYMax - layoutHeight;
	}
	
	u32 totalLines = textBox.mLines.GetTop ();
	for ( u32 i = 0; i < totalLines; ++i ) {
		MOAITextLine& line = textBox.mLines [ i ];
		
		float xOff = textBox.mFrame.mXMin;
		float lineWidth = line.mRect.Width ();
		
		switch ( textBox.mHAlign ) {
		
			case MOAITextBox::CENTER_JUSTIFY:
				xOff = ( xOff + ( width * 0.5f )) - ( lineWidth * 0.5f );
				
			case MOAITextBox::LEFT_JUSTIFY:
				break;

			case MOAITextBox::RIGHT_JUSTIFY:
				xOff = textBox.mFrame.mXMax - lineWidth;
		}
		
		line.mRect.Offset ( xOff, yOff );
		float spriteYOff = yOff + line.mAscent;
		
		MOAIAnimCurve* curve = 0;
		if ( textBox.mCurves ) {
			curve = textBox.mCurves [ i % textBox.mCurves.Size ()];
		}
		
		for ( u32 j = 0; j < line.mSize; ++j ) {
			
			MOAITextSprite& sprite = textBox.mSprites [ line.mStart + j ];
			
			sprite.mX += xOff;
			
			if ( curve ) {
				sprite.mY += spriteYOff + curve->GetFloatValue (( sprite.mX - textBox.mFrame.mXMin ) / width );
			}
			else {
				sprite.mY += spriteYOff;
			}
		}
	}
}
Exemple #3
0
//----------------------------------------------------------------//
void MOAIDraw::EndDrawString () {

	// Setup for drawing
	MOAIGfxDevice& gfxDevice = MOAIGfxDevice::Get ();

	// Get current state
	const ZLMatrix4x4& orgWorldTransform = gfxDevice.GetVertexTransform ( MOAIGfxDevice::VTX_WORLD_TRANSFORM );

	u32 orgVtxModeInput, orgVtxModeOutput;
	gfxDevice.GetVertexMtxMode ( orgVtxModeInput, orgVtxModeOutput );

	// TODO
	//GLint orgSrcBlend, orgDestBlend;
	//glGetIntegerv ( GL_BLEND_SRC, &orgSrcBlend );
	//glGetIntegerv ( GL_BLEND_DST, &orgDestBlend );

	// Apply render state
	gfxDevice.SetShaderPreset ( MOAIShaderMgr::FONT_SHADER );
	gfxDevice.SetVertexMtxMode ( MOAIGfxDevice::VTX_STAGE_WORLD, MOAIGfxDevice::VTX_STAGE_PROJ );
	gfxDevice.SetBlendMode ( ZGL_BLEND_FACTOR_ONE, ZGL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA );
	MOAIQuadBrush::BindVertexFormat ( gfxDevice );

	// Get the context data
	assert( g_CurrentTextDrawContext );
	
	MOAIFont& font = *g_CurrentTextDrawContext->mFont;
	float scale = g_CurrentTextDrawContext->mScale;
	float shadowOffsetX = g_CurrentTextDrawContext->mShadowOffsetX;
	float shadowOffsetY = g_CurrentTextDrawContext->mShadowOffsetY;

	bool drawDropShadows = fabsf ( shadowOffsetX ) > 0.0001 && fabsf ( shadowOffsetY ) > 0.0001;

	u32 numPasses = 1;
	float offsetX = 0;
	float offsetY = 0;
	ZLColorVec penColor = gfxDevice.GetPenColor ();
	if ( drawDropShadows ) {

		numPasses = 2;		
		gfxDevice.SetPenColor ( 0, 0, 0, 1 );
		offsetX = shadowOffsetX;
		offsetY = shadowOffsetY;
	}

	for ( u32 pass = 0; pass < numPasses; pass++ ) {

		if ( pass == 1 || numPasses == 1 ) {
			gfxDevice.SetPenColor ( penColor );
			offsetX = 0;
			offsetY = 0;
		}

		STLList < GlyphPlacement >::const_iterator it;
		for ( it = g_CurrentTextDrawContext->mGlyphs.begin (); it != g_CurrentTextDrawContext->mGlyphs.end (); ++it ) {

			const GlyphPlacement& glyphPlacement = *it;
			MOAIGlyph* glyph = glyphPlacement.glyph;
			MOAITextureBase* glyphTexture = font.GetGlyphTexture ( *glyph );
			glyph->Draw ( *glyphTexture, glyphPlacement.x + offsetX, glyphPlacement.y + offsetY, scale );
		}
	}

	// Restore render state
	Bind();

	gfxDevice.SetVertexTransform ( MOAIGfxDevice::VTX_WORLD_TRANSFORM, orgWorldTransform );
	gfxDevice.SetVertexMtxMode ( orgVtxModeInput, orgVtxModeOutput );
	//gfxDevice.SetBlendMode ( orgSrcBlend, orgDestBlend ); // TODO
	
	gfxDevice.Flush();

	// Clear context
	g_CurrentTextDrawContext->mFont = 0;
	g_CurrentTextDrawContext->mGlyphs.clear();
	g_CurrentTextDrawContext = 0;
}