mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-21 12:25:30 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
242
Engine/source/gfx/gfxFontRenderBatcher.cpp
Normal file
242
Engine/source/gfx/gfxFontRenderBatcher.cpp
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "gfx/gfxFontRenderBatcher.h"
|
||||
#include "gfx/gFont.h"
|
||||
|
||||
FontRenderBatcher::FontRenderBatcher() : mStorage(8096)
|
||||
{
|
||||
if (!mFontSB)
|
||||
{
|
||||
GFXStateBlockDesc f;
|
||||
f.zDefined = true;
|
||||
f.zEnable = false;
|
||||
f.zWriteEnable = false;
|
||||
f.cullDefined = true;
|
||||
f.cullMode = GFXCullNone;
|
||||
f.blendDefined = true;
|
||||
f.blendEnable = true;
|
||||
f.blendSrc = GFXBlendSrcAlpha;
|
||||
f.blendDest = GFXBlendInvSrcAlpha;
|
||||
f.samplersDefined = true;
|
||||
f.samplers[0].alphaOp = GFXTOPModulate;
|
||||
f.samplers[0].magFilter = GFXTextureFilterPoint;
|
||||
f.samplers[0].minFilter = GFXTextureFilterPoint;
|
||||
f.samplers[0].addressModeU = GFXAddressClamp;
|
||||
f.samplers[0].addressModeV = GFXAddressClamp;
|
||||
f.samplers[0].alphaArg1 = GFXTATexture;
|
||||
f.samplers[0].alphaArg2 = GFXTADiffuse;
|
||||
// This is an add operation because in D3D, when a texture of format D3DFMT_A8
|
||||
// is used, the RGB channels are all set to 0. Therefore a modulate would
|
||||
// result in the text always being black. This may not be the case in OpenGL
|
||||
// so it may have to change. -bramage
|
||||
f.samplers[0].textureColorOp = GFXTOPAdd;
|
||||
mFontSB = GFX->createStateBlock(f);
|
||||
}
|
||||
}
|
||||
|
||||
void FontRenderBatcher::render( F32 rot, const Point2F &offset )
|
||||
{
|
||||
if( mLength == 0 )
|
||||
return;
|
||||
|
||||
GFX->setStateBlock(mFontSB);
|
||||
GFX->disableShaders();
|
||||
for(U32 i = 0; i < GFX->getNumSamplers(); i++)
|
||||
GFX->setTexture(i, NULL);
|
||||
|
||||
MatrixF rotMatrix;
|
||||
|
||||
bool doRotation = rot != 0.f;
|
||||
if(doRotation)
|
||||
rotMatrix.set( EulerF( 0.0, 0.0, mDegToRad( rot ) ) );
|
||||
|
||||
// Write verts out.
|
||||
U32 currentPt = 0;
|
||||
GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile);
|
||||
verts.lock();
|
||||
|
||||
for( S32 i = 0; i < mSheets.size(); i++ )
|
||||
{
|
||||
// Do some early outs...
|
||||
if(!mSheets[i])
|
||||
continue;
|
||||
|
||||
if(!mSheets[i]->numChars)
|
||||
continue;
|
||||
|
||||
mSheets[i]->startVertex = currentPt;
|
||||
const GFXTextureObject *tex = mFont->getTextureHandle(i);
|
||||
|
||||
for( S32 j = 0; j < mSheets[i]->numChars; j++ )
|
||||
{
|
||||
// Get some general info to proceed with...
|
||||
const CharMarker &m = mSheets[i]->charIndex[j];
|
||||
const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c );
|
||||
|
||||
// Where are we drawing it?
|
||||
F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG;
|
||||
F32 drawX = offset.x + m.x + ci.xOrigin;
|
||||
|
||||
// Figure some values.
|
||||
const F32 texWidth = (F32)tex->getWidth();
|
||||
const F32 texHeight = (F32)tex->getHeight();
|
||||
const F32 texLeft = (F32)(ci.xOffset) / texWidth;
|
||||
const F32 texRight = (F32)(ci.xOffset + ci.width) / texWidth;
|
||||
const F32 texTop = (F32)(ci.yOffset) / texHeight;
|
||||
const F32 texBottom = (F32)(ci.yOffset + ci.height) / texHeight;
|
||||
|
||||
const F32 fillConventionOffset = GFX->getFillConventionOffset();
|
||||
const F32 screenLeft = drawX - fillConventionOffset;
|
||||
const F32 screenRight = drawX - fillConventionOffset + ci.width * TEXT_MAG;
|
||||
const F32 screenTop = drawY - fillConventionOffset;
|
||||
const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG;
|
||||
|
||||
// Build our vertices. We NEVER read back from the buffer, that's
|
||||
// incredibly slow, so for rotation do it into tmp. This code is
|
||||
// ugly as sin.
|
||||
Point3F tmp;
|
||||
|
||||
tmp.set( screenLeft, screenTop, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texLeft, texTop );
|
||||
currentPt++;
|
||||
|
||||
tmp.set( screenLeft, screenBottom, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texLeft, texBottom );
|
||||
currentPt++;
|
||||
|
||||
tmp.set( screenRight, screenBottom, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texRight, texBottom );
|
||||
currentPt++;
|
||||
|
||||
tmp.set( screenRight, screenBottom, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texRight, texBottom );
|
||||
currentPt++;
|
||||
|
||||
tmp.set( screenRight, screenTop, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texRight, texTop );
|
||||
currentPt++;
|
||||
|
||||
tmp.set( screenLeft, screenTop, 0.f );
|
||||
if(doRotation)
|
||||
rotMatrix.mulP( tmp, &verts[currentPt].point);
|
||||
else
|
||||
verts[currentPt].point = tmp;
|
||||
verts[currentPt].color = m.color;
|
||||
verts[currentPt].texCoord.set( texLeft, texTop );
|
||||
currentPt++;
|
||||
}
|
||||
}
|
||||
|
||||
verts->unlock();
|
||||
|
||||
AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!");
|
||||
|
||||
GFX->setVertexBuffer(verts);
|
||||
|
||||
// Now do an optimal render!
|
||||
for( S32 i = 0; i < mSheets.size(); i++ )
|
||||
{
|
||||
if(!mSheets[i])
|
||||
continue;
|
||||
|
||||
if(!mSheets[i]->numChars )
|
||||
continue;
|
||||
|
||||
GFX->setupGenericShaders( GFXDevice::GSAddColorTexture );
|
||||
GFX->setTexture( 0, mFont->getTextureHandle(i) );
|
||||
GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2);
|
||||
}
|
||||
}
|
||||
|
||||
void FontRenderBatcher::queueChar( UTF16 c, S32 ¤tX, GFXVertexColor ¤tColor )
|
||||
{
|
||||
const PlatformFont::CharInfo &ci = mFont->getCharInfo( c );
|
||||
U32 sidx = ci.bitmapIndex;
|
||||
|
||||
if( ci.width != 0 && ci.height != 0 )
|
||||
{
|
||||
SheetMarker &sm = getSheetMarker(sidx);
|
||||
|
||||
CharMarker &m = sm.charIndex[sm.numChars];
|
||||
sm.numChars++;
|
||||
|
||||
m.c = c;
|
||||
m.x = (F32)currentX;
|
||||
m.color = currentColor;
|
||||
}
|
||||
|
||||
currentX += ci.xIncrement;
|
||||
}
|
||||
|
||||
FontRenderBatcher::SheetMarker & FontRenderBatcher::getSheetMarker( U32 sheetID )
|
||||
{
|
||||
// Allocate if it doesn't exist...
|
||||
if(mSheets.size() <= sheetID || !mSheets[sheetID])
|
||||
{
|
||||
if(sheetID >= mSheets.size())
|
||||
mSheets.setSize(sheetID+1);
|
||||
|
||||
S32 size = sizeof( SheetMarker) + mLength * sizeof( CharMarker );
|
||||
mSheets[sheetID] = (SheetMarker *)mStorage.alloc(size);
|
||||
mSheets[sheetID]->numChars = 0;
|
||||
mSheets[sheetID]->startVertex = 0; // cosmetic initialization
|
||||
}
|
||||
|
||||
return *mSheets[sheetID];
|
||||
}
|
||||
|
||||
void FontRenderBatcher::init( GFont *font, U32 n )
|
||||
{
|
||||
// Clear out batched results
|
||||
dMemset(mSheets.address(), 0, mSheets.memSize());
|
||||
mSheets.clear();
|
||||
mStorage.freeBlocks(true);
|
||||
|
||||
mFont = font;
|
||||
mLength = n;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue