예제 #1
0
//----------------------------------------------------------------//
bool MOAIVertexFormat::ComputeBounds ( void* buffer, u32 size, USRect& bounds ) {

	u32 total = this->mVertexSize ? ( size / this->mVertexSize ) : 0;
	if ( !total ) return false;

	u32 coordAttributeIdx = this->mAttributeUseTable [ ARRAY_VERTEX ].mAttrID;
	if ( coordAttributeIdx >= this->mTotalAttributes ) return false;

	MOAIVertexAttribute& coordAttr = this->mAttributes [ coordAttributeIdx ];
	if ( coordAttr.mType != GL_FLOAT ) return false; // TODO: handle other types
	if ( coordAttr.mSize < 2 ) return false;
	
	buffer = ( void* )(( size_t )buffer + coordAttr.mOffset );
	
	USVec2D* coord = ( USVec2D* )buffer;
	bounds.Init ( *coord );
	bounds.Inflate ( 0.0000001f ); // prevent 'empty' bounds on cardinal direction lines or single vertex objects
	
	for ( u32 i = 1; i < total; ++i ) {
		
		buffer = ( void* )(( size_t )buffer + this->mVertexSize );
		coord = ( USVec2D* )buffer;
		bounds.Grow ( *coord );
	}
	return true;
}
예제 #2
0
//----------------------------------------------------------------//
USRect MOAIGfxQuadListDeck2D::GetBounds ( u32 idx, MOAIDeckRemapper* remapper ) {

	USRect rect;
	rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );

	u32 size = this->mSprites.Size ();
	if ( size ) {

		idx = remapper ? remapper->Remap ( idx ) : idx;
		idx = ( idx - 1 ) % size;
	
		USSprite& sprite = this->mSprites [ idx ];
		
		if ( sprite.mTotalPairs ) {
			
			USSpritePair prim = this->mPairs [ sprite.mBasePair ];
			USQuad& baseQuad = this->mQuads [ prim.mQuadID ];
			
			baseQuad.GetBounds ( rect );
			
			for ( u32 i = 1; i < sprite.mTotalPairs; ++i ) {
				
				prim = this->mPairs [ sprite.mBasePair + i ];
				USQuad& quad = this->mQuads [ prim.mQuadID ];
				
				rect.Grow ( quad.mV [ 0 ]);
				rect.Grow ( quad.mV [ 1 ]);
				rect.Grow ( quad.mV [ 2 ]);
				rect.Grow ( quad.mV [ 3 ]);
			}
		}
	}
	return rect;
}
예제 #3
0
//----------------------------------------------------------------//
USRect MOAIDeck::GetBounds ( u32 idx, MOAIDeckRemapper* remapper ) {
	UNUSED ( idx );
	UNUSED ( remapper );

	USRect rect;
	rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
	return rect;
}
예제 #4
0
//----------------------------------------------------------------//
USRect MOAIQuadBrush::GetUVBounds () {

	USRect rect;
	
	rect.Init ( this->mUV [ 0 ]);
	rect.Grow ( this->mUV [ 1 ]);
	rect.Grow ( this->mUV [ 2 ]);
	rect.Grow ( this->mUV [ 3 ]);
	
	return rect;
}
예제 #5
0
//----------------------------------------------------------------//
USRect MOAIQuadBrush::GetVtxBounds () {

	USRect rect;
	
	rect.Init ( this->mVtx [ 0 ]);
	rect.Grow ( this->mVtx [ 1 ]);
	rect.Grow ( this->mVtx [ 2 ]);
	rect.Grow ( this->mVtx [ 3 ]);
	
	return rect;
}
예제 #6
0
//----------------------------------------------------------------//
USRect USGLQuad::GetVtxBounds () {

	USRect rect;
	
	rect.Init ( this->mVtx [ 0 ]);
	rect.Grow ( this->mVtx [ 1 ]);
	rect.Grow ( this->mVtx [ 2 ]);
	rect.Grow ( this->mVtx [ 3 ]);
	
	return rect;
}
예제 #7
0
//----------------------------------------------------------------//
USRect USGLQuad::GetUVBounds () {

	USRect rect;
	
	rect.Init ( this->mUV [ 0 ]);
	rect.Grow ( this->mUV [ 1 ]);
	rect.Grow ( this->mUV [ 2 ]);
	rect.Grow ( this->mUV [ 3 ]);
	
	return rect;
}
예제 #8
0
//----------------------------------------------------------------//
USRect MOAIMesh::GetBounds ( u32 idx, MOAIDeckRemapper* remapper ) {
	UNUSED ( idx );
	UNUSED ( remapper );
	
	if ( this->mVertexBuffer ) {
		return this->mVertexBuffer->GetBounds ();
	}
	USRect bounds;
	bounds.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
	return bounds;
}
예제 #9
0
//----------------------------------------------------------------//
USRect MOAISurfaceDeck2D::GetRect ( u32 idx, MOAIDeckRemapper* remapper ) {

    idx = remapper ? remapper->Remap ( idx ) : idx;
    idx = idx - 1;

    if ( idx < this->mBrushes.Size ()) {
        return this->mBrushes [ idx ].mBounds;
    }

    USRect rect;
    rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
    return rect;
}
예제 #10
0
USRect MOAISurfaceDeck2D::GetRect () {

    u32 size = this->mBrushes.Size ();

    USRect totalRect;
    totalRect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );

    for ( int i = 0; i < size; ++i ) {
        totalRect.Grow ( this->mBrushes [ i ].mBounds );
    }

    return totalRect;
}
예제 #11
0
//----------------------------------------------------------------//
USBox MOAIGfxQuadDeck2D::ComputeMaxBounds () {

    USRect rect;
    rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );

    u32 size = this->mQuads.Size ();
    for ( u32 i = 0; i < size; ++i ) {
        rect.Grow ( this->mQuads [ i ].GetVtxBounds ());
    }

    USBox bounds;
    bounds.Init ( rect.mXMin, rect.mYMax, rect.mXMax, rect.mYMin, 0.0f, 0.0f );
    return bounds;
}
예제 #12
0
USRect MOAIGfxQuadDeck2D::GetRect ( ) {

	u32 size = this->mQuads.Size ();
	USRect totalRect;
	totalRect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );

	for ( u32 i = 0; i < size; ++i ) {
		MOAIQuadBrush& quad = this->mQuads [ i ];
		USRect rect = quad.GetVtxBounds ();

		totalRect.Grow ( rect );
	}
	return totalRect;
}
예제 #13
0
//----------------------------------------------------------------//
bool USFrustum::GetXYSectRect ( const USAffine3D& mtx, USRect& rect ) const {

	u32 nHits = 0;
	USVec2D hits [ 12 ];

	USVec3D nlt = this->mPoints [ NEAR_LT_POINT ];
	USVec3D nrt = this->mPoints [ NEAR_RT_POINT ];
	USVec3D nrb = this->mPoints [ NEAR_RB_POINT ];
	USVec3D nlb = this->mPoints [ NEAR_LB_POINT ];
	
	USVec3D flt = this->mPoints [ FAR_LT_POINT ];
	USVec3D frt = this->mPoints [ FAR_RT_POINT ];
	USVec3D frb = this->mPoints [ FAR_RB_POINT ];
	USVec3D flb = this->mPoints [ FAR_LB_POINT ];
	
	mtx.Transform ( nlt );
	mtx.Transform ( nrt );
	mtx.Transform ( nrb );
	mtx.Transform ( nlb );
	
	mtx.Transform ( flt );
	mtx.Transform ( frt );
	mtx.Transform ( frb );
	mtx.Transform ( flb );
	
	if ( _vecToXYPlane ( nlt, flt, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nrt, frt, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nrb, frb, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nlb, flb, hits [ nHits ])) ++nHits;
	
	if ( _vecToXYPlane ( nlt, nrt, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nrt, nrb, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nrb, nlb, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( nlb, nlt, hits [ nHits ])) ++nHits;
	
	if ( _vecToXYPlane ( flt, frt, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( frt, frb, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( frb, flb, hits [ nHits ])) ++nHits;
	if ( _vecToXYPlane ( flb, flt, hits [ nHits ])) ++nHits;
	
	if ( nHits ) {
		rect.Init ( hits [ 0 ]);
		for ( u32 i = 1; i < nHits; ++i ) {
			rect.Grow ( hits [ i ]);
		}
		return true;
	}
	return false;
}
예제 #14
0
//----------------------------------------------------------------//
USBox MOAISurfaceDeck2D::ComputeMaxBounds () {
	
	u32 size = this->mBrushes.Size ();

	USRect rect;
	rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );

	for ( u32 i = 0; i < size; ++i ) {
		rect.Grow ( this->mBrushes [ i ].mBounds );
	}

	USBox bounds;
	bounds.Init ( rect.mXMin, rect.mYMax, rect.mXMax, rect.mYMin, 0.0f, 0.0f );	
	return bounds;
}
예제 #15
0
//----------------------------------------------------------------//
USRect MOAIGfxQuadDeck2D::GetBounds ( u32 idx, MOAIDeckRemapper* remapper ) {
	
	u32 size = this->mQuads.Size ();
	if ( size ) {

		idx = remapper ? remapper->Remap ( idx ) : idx;
		idx = ( idx - 1 ) % size;
	
		MOAIQuadBrush& quad = this->mQuads [ idx ];
		return quad.GetVtxBounds ();
	}
	USRect rect;
	rect.Init ( 0.0f, 0.0f, 0.0f, 0.0f );
	return rect;
}
예제 #16
0
//----------------------------------------------------------------//
USRect MOAIGlyph::GetRect ( float x, float y ) const {

    USRect rect;

    x += ( this->mBearingX );
    y -= ( this->mBearingY );

    rect.Init (
        x,
        y,
        x + this->mWidth,
        y + this->mHeight
    );

    return rect;
}
예제 #17
0
//----------------------------------------------------------------//
USRect MOAIScissorRect::GetScissorRect ( const USMatrix4x4& worldToWndMtx ) const {

	USVec3D vtx3D [ 4 ];

	vtx3D [ 0 ].mX = this->mRect.mXMin;
	vtx3D [ 0 ].mY = this->mRect.mYMin;
	vtx3D [ 0 ].mZ = 0.0f;

	vtx3D [ 1 ].mX = this->mRect.mXMin;
	vtx3D [ 1 ].mY = this->mRect.mYMax;
	vtx3D [ 1 ].mZ = 0.0f;
	
	vtx3D [ 2 ].mX = this->mRect.mXMax;
	vtx3D [ 2 ].mY = this->mRect.mYMax;
	vtx3D [ 2 ].mZ = 0.0f;

	vtx3D [ 3 ].mX = this->mRect.mXMax;
	vtx3D [ 3 ].mY = this->mRect.mYMin;
	vtx3D [ 3 ].mZ = 0.0f;

	USMatrix4x4 mtx;
	
	mtx.Init ( this->GetLocalToWorldMtx ());
	mtx.Append ( worldToWndMtx );
	
	mtx.Project ( vtx3D [ 0 ]);
	mtx.Project ( vtx3D [ 1 ]);
	mtx.Project ( vtx3D [ 2 ]);
	mtx.Project ( vtx3D [ 3 ]);
	
	USRect scissorRect;

	scissorRect.Init ( vtx3D [ 0 ]);
	scissorRect.Grow ( vtx3D [ 1 ]);
	scissorRect.Grow ( vtx3D [ 2 ]);
	scissorRect.Grow ( vtx3D [ 3 ]);

	if ( this->mScissorRect ) {
		USRect parentRect = this->mScissorRect->GetScissorRect ( worldToWndMtx );
		parentRect.Clip ( scissorRect );
	}

	return scissorRect;
}
예제 #18
0
파일: MOAIDraw.cpp 프로젝트: LOFI/moai-dev
//----------------------------------------------------------------//
void MOAIDraw::DrawRay ( float x, float y, float dx, float dy ) {
	
	USVec2D loc ( x, y );
	USVec2D vec ( dx, dy );
	
	USMatrix4x4 mtx = MOAIGfxDevice::Get ().GetViewProjMtx ();
	
	USMatrix4x4 invMtx;
	invMtx.Inverse ( mtx );
	
	mtx.Transform ( loc );
	mtx.TransformVec ( vec );
	
	USRect viewRect;
	viewRect.Init ( -1.0f, -1.0f, 1.0f, 1.0f );
	
	USVec2D p0;
	USVec2D p1;
	
	if ( viewRect.GetIntersection ( loc, vec, p0, p1 )) {
		
		invMtx.Transform ( p0 );
		invMtx.Transform ( p1 );
		
		MOAIGfxDevice& gfxDevice = MOAIGfxDevice::Get ();
		
		gfxDevice.BeginPrim ( GL_LINES );
		
			gfxDevice.WriteVtx ( p0.mX, p0.mY, 0.0f );
			gfxDevice.WriteFinalColor4b ();
			
			gfxDevice.WriteVtx ( p1.mX, p1.mY, 0.0f );
			gfxDevice.WriteFinalColor4b ();

		gfxDevice.EndPrim ();
	}
}
예제 #19
0
파일: MOAIDraw.cpp 프로젝트: LOFI/moai-dev
//----------------------------------------------------------------//
void MOAIDraw::DrawAxisGrid ( USVec2D loc, USVec2D vec, float size ) {

	USMatrix4x4 mtx = MOAIGfxDevice::Get ().GetViewProjMtx ();
	
	USMatrix4x4 invMtx;
	invMtx.Inverse ( mtx );
	
	// Set the axis to the grid length so we can get the length back post-transform
	vec.SetLength ( size );
	
	mtx.Transform ( loc );
	mtx.TransformVec ( vec );

	// Get the axis unit vector
	USVec2D norm = vec;
	size = norm.NormSafe ();
	
	// Get the axis normal
	USVec2D perpNorm ( norm.mY, -norm.mX );
	
	// Project the corners of the viewport onto the axis to get the mix/max bounds
	float dot;
	float min;
	float max;
	
	USVec2D corner;
	
	// left, top
	corner.Init ( -1.0f, 1.0f );
	corner.Sub ( loc );
	dot = norm.Dot ( corner );
	
	min = dot;
	max = dot;
	
	// right, top
	corner.Init ( 1.0f, 1.0f );
	corner.Sub ( loc );
	dot = norm.Dot ( corner );
	
	min = ( dot < min ) ? dot : min;
	max = ( dot > max ) ? dot : max;
	
	// right, bottom
	corner.Init ( 1.0f, -1.0f );
	corner.Sub ( loc );
	dot = norm.Dot ( corner );
	
	min = ( dot < min ) ? dot : min;
	max = ( dot > max ) ? dot : max;
	
	// left, bottom
	corner.Init ( -1.0f, -1.0f );
	corner.Sub ( loc );
	dot = norm.Dot ( corner );
	
	min = ( dot < min ) ? dot : min;
	max = ( dot > max ) ? dot : max;
	
	// Get the start andstop grids
	s32 start = ( s32 )( min / size ) - 1;
	s32 stop = ( s32 )( max / size ) + 1;
	
	// Set the pen to the first...
	USVec2D pen = norm;
	pen.Scale (( float )start * size );
	pen.Add ( loc );
	
	// Step along the axis to draw perpendicular grid lines
	USRect viewRect;
	viewRect.Init ( -1.0f, -1.0f, 1.0f, 1.0f );
	
	for ( ; start < stop; ++start ) {
		
		USVec2D p0;
		USVec2D p1;
		
		if ( viewRect.GetIntersection ( pen, perpNorm, p0, p1 )) {
			
			invMtx.Transform ( p0 );
			invMtx.Transform ( p1 );
			
			MOAIDraw::DrawLine ( p0, p1 );
		}
		
		pen.Add ( vec );
	}
}
예제 #20
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;
			}
		}
	}
}
예제 #21
0
//----------------------------------------------------------------//
void MOAIStretchPatch2D::DrawStretch ( u32 idx, float xStretch, float yStretch ) {

	USRect uvRect;
	u32 totalUVRects = this->mUVRects.Size ();
	idx = ( idx - 1 ) % totalUVRects;

	if ( totalUVRects == 0 ) {
		uvRect.Init ( 0.0f, 1.0f, 1.0f, 0.0f );
	}
	else {
		uvRect = this->mUVRects [ idx ];
	}

	float nativeWidth = this->mRect.Width ();
	float nativeHeight = this->mRect.Height ();
	
	float rectWidth = nativeWidth * xStretch;
	float rectHeight = nativeHeight * yStretch;
	
	float xMin = this->mRect.mXMin * xStretch;
	float yMin = this->mRect.mYMin * yStretch;

	float uMin = uvRect.mXMin;
	float vMin = uvRect.mYMin;

	// scale for x patches
	float xPatchScale = 1.0f;
	float xStretchPatchScale = 1.0f;
	
	if ( rectWidth > nativeWidth ) {
		xStretchPatchScale = ( rectWidth - ( nativeWidth * this->mXFix )) / ( nativeWidth * this->mXFlex );
	}
	else {
		xPatchScale = rectWidth / nativeWidth;
		xStretchPatchScale = xPatchScale;
	}

	// scale for y patches
	float yPatchScale = 1.0f;
	float yStretchPatchScale = 1.0f;
	
	if ( rectHeight > nativeHeight ) {
		yStretchPatchScale = ( rectHeight - ( nativeHeight * this->mYFix )) / ( nativeHeight * this->mYFlex );
	}
	else {
		yPatchScale = rectHeight / nativeHeight;
		yStretchPatchScale = yPatchScale;
	}
	
	u32 totalRows = this->mRows.Size ();
	u32 totalCols = this->mCols.Size ();
	
	MOAIQuadBrush quad;
	
	float uSpan = uvRect.mXMax - uvRect.mXMin;
	float vSpan = uvRect.mYMax - uvRect.mYMin;
	
	float y = yMin;
	float v = vMin;
	
	for ( u32 i = 0; i < totalRows; ++i ) {
		
		MOAIStretchPatchSpan& row = this->mRows [ i ];
		float vStep = row.mPercent * vSpan;
		
		float h = nativeHeight * row.mPercent;
		if ( row.mCanStretch ) {
			h *= yStretchPatchScale;
		}
		else {
			h *= yPatchScale;
		}
		
		float x = xMin;
		float u = uMin;
		
		for ( u32 j = 0; j < totalCols; ++j ) {
			
			MOAIStretchPatchSpan& col = this->mCols [ j ];
			float uStep = col.mPercent * uSpan;
			
			float w = nativeWidth * col.mPercent;
			if ( col.mCanStretch ) {
				w *= xStretchPatchScale;
			}
			else {
				w *= xPatchScale;
			}
			
			quad.SetVerts ( x, y, x + w, y + h );
			quad.SetUVs ( u, v, u + uStep, v + vStep );
			quad.Draw ();
			
			x += w;
			u += uStep;
		}
		
		y += h;
		v += vStep;
	}
}