You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
912 lines
28 KiB
912 lines
28 KiB
14 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||
|
or by snail mail at:
|
||
|
Cyan Worlds, Inc.
|
||
|
14617 N Newport Hwy
|
||
|
Mead, WA 99021
|
||
|
|
||
|
*==LICENSE==*/
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// plDynamicTextMap Class Functions //
|
||
|
// Derived bitmap class representing a single mipmap. //
|
||
|
// Cyan, Inc. //
|
||
|
// //
|
||
|
//// Version History //////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// 6.7.2001 mcn - Created. //
|
||
|
// //
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "hsTypes.h"
|
||
|
#include "plDynamicTextMap.h"
|
||
|
|
||
|
#include "hsStream.h"
|
||
|
#include "hsExceptions.h"
|
||
|
#include "hsUtils.h"
|
||
|
#include "hsMatrix44.h"
|
||
|
#include "../plPipeline/hsGDeviceRef.h"
|
||
|
#include "../plMessage/plDynamicTextMsg.h"
|
||
|
#include "../pnKeyedObject/plKey.h"
|
||
|
#include "plProfile.h"
|
||
|
#include "../plStatusLog/plStatusLog.h"
|
||
|
#include "plFont.h"
|
||
|
#include "plFontCache.h"
|
||
|
#include "../plResMgr/plLocalization.h"
|
||
|
|
||
|
|
||
|
plProfile_CreateMemCounter("DynaTextMem", "PipeC", DynaTextMem);
|
||
|
plProfile_CreateCounterNoReset("DynaTexts", "PipeC", DynaTexts);
|
||
|
plProfile_Extern(MemMipmaps);
|
||
|
|
||
|
|
||
|
//// Constructor & Destructor /////////////////////////////////////////////////
|
||
|
|
||
|
plDynamicTextMap::plDynamicTextMap() : plMipmap()
|
||
|
{
|
||
|
fVisWidth = fVisHeight = 0;
|
||
|
fHasAlpha = false;
|
||
|
fJustify = kLeftJustify;
|
||
|
fInitBuffer = nil;
|
||
|
fFontFace = nil;
|
||
|
fFontSize = 0;
|
||
|
fFontFlags = 0;
|
||
|
fFontAntiAliasRGB = false;
|
||
|
fFontColor.Set( 0, 0, 0, 1 );
|
||
|
fFontBlockRGB = false;
|
||
|
fHasCreateBeenCalled = false;
|
||
|
|
||
|
}
|
||
|
|
||
|
plDynamicTextMap::~plDynamicTextMap()
|
||
|
{
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
plDynamicTextMap::plDynamicTextMap( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight ) : plMipmap()
|
||
|
{
|
||
|
fInitBuffer = nil;
|
||
|
fFontFace = nil;
|
||
|
Create( width, height, hasAlpha, extraWidth, extraHeight );
|
||
|
}
|
||
|
|
||
|
//// SetNoCreate //////////////////////////////////////////////////////////////
|
||
|
// For export time, we want to set up the config to write to disk, but we
|
||
|
// don't want to actually be creating OS surfaces. So we call this function
|
||
|
// instead, which does just that. It basically does all the setup work that
|
||
|
// Create() does, or enough for us to write out later.
|
||
|
|
||
|
void plDynamicTextMap::SetNoCreate( UInt32 width, UInt32 height, hsBool hasAlpha )
|
||
|
{
|
||
|
// OK, so it really isn't that much work...
|
||
|
fVisWidth = (UInt16)width;
|
||
|
fVisHeight = (UInt16)height;
|
||
|
fHasAlpha = hasAlpha;
|
||
|
fImage = nil; // So we know we haven't actually done anything yet
|
||
|
delete [] fInitBuffer;
|
||
|
fInitBuffer = nil;
|
||
|
}
|
||
|
|
||
|
//// Create ///////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::Create( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight )
|
||
|
{
|
||
|
SetConfig( hasAlpha ? kARGB32Config : kRGB32Config );
|
||
|
|
||
|
|
||
|
fVisWidth = (UInt16)width;
|
||
|
fVisHeight = (UInt16)height;
|
||
|
fHasAlpha = hasAlpha;
|
||
|
|
||
|
for( fWidth = 1; fWidth < width + extraWidth; fWidth <<= 1 );
|
||
|
for( fHeight = 1; fHeight < height + extraHeight; fHeight <<= 1 );
|
||
|
|
||
|
// instead of allocating the fImage here, we'll wait for the first draw operation to be called (in IIsValid)
|
||
|
fHasCreateBeenCalled = true;
|
||
|
|
||
|
fRowBytes = fWidth << 2;
|
||
|
fNumLevels = 1;
|
||
|
fFlags |= plMipmap::kDontThrowAwayImage;
|
||
|
fCompressionType = plMipmap::kUncompressed;
|
||
|
fUncompressedInfo.fType = plMipmap::UncompressedInfo::kRGB8888;
|
||
|
|
||
|
// Destroy the old texture ref, if we have one. This should force the
|
||
|
// pipeline to recreate one more suitable for our use
|
||
|
SetDeviceRef( nil );
|
||
|
|
||
|
// Some init color
|
||
|
SetFont( "Arial", 12 );
|
||
|
hsColorRGBA color;
|
||
|
color.Set( 0,0,1,1);
|
||
|
SetTextColor( color );
|
||
|
|
||
|
SetCurrLevel( 0 );
|
||
|
plProfile_Inc(DynaTexts);
|
||
|
|
||
|
}
|
||
|
|
||
|
//// Reset ////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::Reset( void )
|
||
|
{
|
||
|
IDestroyOSSurface();
|
||
|
|
||
|
plMipmap::Reset();
|
||
|
|
||
|
// they need to call create again to undo the affects of call Reset()
|
||
|
fHasCreateBeenCalled = false;
|
||
|
|
||
|
delete [] fInitBuffer;
|
||
|
fInitBuffer = nil;
|
||
|
|
||
|
delete [] fFontFace;
|
||
|
fFontFace = nil;
|
||
|
|
||
|
// Destroy the old texture ref, since we're no longer using it
|
||
|
SetDeviceRef( nil );
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//// OS-Specific Functions ////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
hsBool plDynamicTextMap::IIsValid( void )
|
||
|
{
|
||
|
if( GetImage() == nil && fHasCreateBeenCalled )
|
||
|
{
|
||
|
// we are going to allocate the fImage at this point... when someone is looking for it
|
||
|
fImage = (void *)IAllocateOSSurface( (UInt16)fWidth, (UInt16)fHeight );
|
||
|
hsColorRGBA color;
|
||
|
if( fInitBuffer != nil )
|
||
|
{
|
||
|
IClearFromBuffer( fInitBuffer );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
color.Set( 0.f, 0.f, 0.f, 1.f );
|
||
|
ClearToColor( color );
|
||
|
FlushToHost();
|
||
|
}
|
||
|
IBuildLevelSizes();
|
||
|
fTotalSize = GetLevelSize( 0 );
|
||
|
SetCurrLevel( 0 );
|
||
|
// Destroy the old texture ref, if we have one. This should force the
|
||
|
// pipeline to recreate one more suitable for our use
|
||
|
SetDeviceRef( nil );
|
||
|
plProfile_NewMem(MemMipmaps, fTotalSize);
|
||
|
plProfile_NewMem(DynaTextMem, fTotalSize);
|
||
|
#ifdef MEMORY_LEAK_TRACER
|
||
|
IAddToMemRecord( this, plRecord::kViaCreate );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if( GetImage() == nil )
|
||
|
return false;
|
||
|
|
||
|
return true;//fWriter->IsValid();
|
||
|
}
|
||
|
|
||
|
// allow the user of the DynaTextMap that they are done with the image... for now
|
||
|
// ... the fImage will be re-created on the next operation that requires the image
|
||
|
void plDynamicTextMap::PurgeImage()
|
||
|
{
|
||
|
IDestroyOSSurface();
|
||
|
fTotalSize = 0;
|
||
|
SetCurrLevel( 0 );
|
||
|
// Destroy the old texture ref, if we have one. This should force the
|
||
|
// pipeline to recreate one more suitable for our use
|
||
|
SetDeviceRef( nil );
|
||
|
}
|
||
|
|
||
|
//// IAllocateOSSurface ///////////////////////////////////////////////////////
|
||
|
// OS-specific. Allocates a rectangular bitmap of the given dimensions that
|
||
|
// the OS can draw text into. Returns a pointer to the pixels.
|
||
|
|
||
|
UInt32* plDynamicTextMap::IAllocateOSSurface( UInt16 width, UInt16 height )
|
||
|
{
|
||
|
UInt32* pixels = TRACKED_NEW UInt32[ width * height ];
|
||
|
return pixels;
|
||
|
}
|
||
|
|
||
|
//// IDestroyOSSurface ////////////////////////////////////////////////////////
|
||
|
// Opposite of allocate. DUH!
|
||
|
|
||
|
void plDynamicTextMap::IDestroyOSSurface( void )
|
||
|
{
|
||
|
#ifdef MEMORY_LEAK_TRACER
|
||
|
if( fImage != nil )
|
||
|
IRemoveFromMemRecord( (UInt8 *)fImage );
|
||
|
#endif
|
||
|
|
||
|
delete [] fImage;
|
||
|
fImage = nil;
|
||
|
|
||
|
plProfile_Dec(DynaTexts);
|
||
|
plProfile_DelMem(DynaTextMem, fTotalSize);
|
||
|
plProfile_DelMem(MemMipmaps, fTotalSize);
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//// Virtual Functions ////////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//// Read /////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
UInt32 plDynamicTextMap::Read( hsStream *s )
|
||
|
{
|
||
|
UInt32 totalRead = plBitmap::Read( s );
|
||
|
|
||
|
// The funny thing is that we don't read anything like a mipmap; we just
|
||
|
// keep the width and height and call Create() after we read those in
|
||
|
|
||
|
fVisWidth = (UInt16)(s->ReadSwap32());
|
||
|
fVisHeight = (UInt16)(s->ReadSwap32());
|
||
|
fHasAlpha = s->ReadBool();
|
||
|
totalRead += 2 * 4;
|
||
|
|
||
|
UInt32 initSize = s->ReadSwap32();
|
||
|
totalRead += 4;
|
||
|
if( initSize > 0 )
|
||
|
{
|
||
|
fInitBuffer = TRACKED_NEW UInt32[ initSize ];
|
||
|
|
||
|
s->ReadSwap32( initSize, fInitBuffer );
|
||
|
totalRead += initSize * 4;
|
||
|
}
|
||
|
else
|
||
|
fInitBuffer = nil;
|
||
|
|
||
|
Create( fVisWidth, fVisHeight, fHasAlpha );
|
||
|
|
||
|
delete [] fInitBuffer;
|
||
|
fInitBuffer = nil;
|
||
|
|
||
|
return totalRead;
|
||
|
}
|
||
|
|
||
|
//// Write ////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
UInt32 plDynamicTextMap::Write( hsStream *s )
|
||
|
{
|
||
|
UInt32 totalWritten = plBitmap::Write( s );
|
||
|
|
||
|
s->WriteSwap32( fVisWidth );
|
||
|
s->WriteSwap32( fVisHeight );
|
||
|
s->WriteBool( fHasAlpha );
|
||
|
|
||
|
s->WriteSwap32( fInitBuffer != nil ? fVisWidth * fVisHeight * sizeof( UInt32 ) : 0 );
|
||
|
if( fInitBuffer != nil )
|
||
|
{
|
||
|
s->WriteSwap32( fVisWidth * fVisHeight, fInitBuffer );
|
||
|
}
|
||
|
|
||
|
return totalWritten;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//// Some More Functions //////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//// SetInitBuffer ////////////////////////////////////////////////////////////
|
||
|
// Sets an initial buffer, which is written to disk and read in to use for
|
||
|
// initializing the color buffer upon creation. If not specified, we init to
|
||
|
// black. ASSUMES the buffer is of dimensions fVisWidth x fVisHeight.
|
||
|
|
||
|
void plDynamicTextMap::SetInitBuffer( UInt32 *buffer )
|
||
|
{
|
||
|
delete [] fInitBuffer;
|
||
|
if( buffer == nil )
|
||
|
{
|
||
|
fInitBuffer = nil;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fInitBuffer = TRACKED_NEW UInt32[ fVisWidth * fVisHeight ];
|
||
|
memcpy( fInitBuffer, buffer, fVisWidth * fVisHeight * sizeof( UInt32 ) );
|
||
|
}
|
||
|
|
||
|
//// CopyFrom /////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::CopyFrom( plMipmap *source )
|
||
|
{
|
||
|
hsAssert( false, "Copying plDynamicTextMaps is not supported." );
|
||
|
}
|
||
|
|
||
|
//// Clone ////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
plMipmap *plDynamicTextMap::Clone( void )
|
||
|
{
|
||
|
static bool alreadyWarned = false;
|
||
|
|
||
|
if( !alreadyWarned )
|
||
|
{
|
||
|
hsAssert( false, "Cloning plDynamicTextMaps is not supported." );
|
||
|
alreadyWarned = true;
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//// Rendering Functions //////////////////////////////////////////////////////
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//// IClearFromBuffer /////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::IClearFromBuffer( UInt32 *clearBuffer )
|
||
|
{
|
||
|
int y;
|
||
|
UInt32 *data = (UInt32 *)fImage, *srcData = clearBuffer;
|
||
|
UInt8 *destAlpha = nil;
|
||
|
|
||
|
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
// Clear *all* to zero
|
||
|
memset( data, 0, fWidth * fHeight * sizeof( UInt32 ) );
|
||
|
|
||
|
// Buffer is of size fVisWidth x fVisHeight, so we need a bit of work to do this right
|
||
|
for( y = 0; y < fVisHeight; y++ )
|
||
|
{
|
||
|
memcpy( data, srcData, fVisWidth * sizeof( UInt32 ) );
|
||
|
data += fWidth;
|
||
|
srcData += fVisWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// ClearToColor /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::ClearToColor( hsColorRGBA &color )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
UInt32 i, hex = color.ToARGB32();
|
||
|
UInt32 *data = (UInt32 *)fImage;
|
||
|
|
||
|
// Buffer is of size fVisWidth x fVisHeight, so we need a bit of work to do this right
|
||
|
for( i = 0; i < fHeight * fWidth; i++ )
|
||
|
data[ i ] = hex;
|
||
|
}
|
||
|
|
||
|
//// SetJustify ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::SetJustify( Justify j )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
fJustify = j;
|
||
|
switch( fJustify )
|
||
|
{
|
||
|
case kLeftJustify: fCurrFont->SetRenderXJustify( plFont::kRenderJustXForceLeft ); break;
|
||
|
case kCenter: fCurrFont->SetRenderXJustify( plFont::kRenderJustXCenter ); break;
|
||
|
case kRightJustify: fCurrFont->SetRenderXJustify( plFont::kRenderJustXRight ); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// SetFont //////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::SetFont( const char *face, UInt16 size, UInt8 fontFlags, hsBool antiAliasRGB )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
delete [] fFontFace;
|
||
|
if (plLocalization::UsingUnicode())
|
||
|
{
|
||
|
// unicode has a bunch of chars that most fonts don't have, so we override the font choice with one
|
||
|
// that will work with the desired language
|
||
|
hsStatusMessageF("We are using a unicode language, overriding font choice of %s", face ? face : "nil");
|
||
|
fFontFace = hsStrcpy( "Unicode" );
|
||
|
}
|
||
|
else
|
||
|
fFontFace = ( face != nil ) ? hsStrcpy( face ) : nil;
|
||
|
fFontSize = size;
|
||
|
fFontFlags = fontFlags;
|
||
|
fFontAntiAliasRGB = antiAliasRGB;
|
||
|
|
||
|
fCurrFont = plFontCache::GetInstance().GetFont( fFontFace, (UInt8)fFontSize,
|
||
|
( ( fFontFlags & kFontBold ) ? plFont::kFlagBold : 0 ) |
|
||
|
( ( fFontFlags & kFontItalic ) ? plFont::kFlagItalic : 0 ) );
|
||
|
if ( fCurrFont == nil )
|
||
|
{
|
||
|
if (!fCurrFont)
|
||
|
hsStatusMessageF("Font missing - %s. Using Arial", fFontFace ? fFontFace : "nil");
|
||
|
|
||
|
if ( fFontFace )
|
||
|
delete [] fFontFace;
|
||
|
fFontFace = hsStrcpy( "Arial" );
|
||
|
// lets try again with Arial
|
||
|
fCurrFont = plFontCache::GetInstance().GetFont( fFontFace, (UInt8)fFontSize,
|
||
|
( ( fFontFlags & kFontBold ) ? plFont::kFlagBold : 0 ) |
|
||
|
( ( fFontFlags & kFontItalic ) ? plFont::kFlagItalic : 0 ) );
|
||
|
}
|
||
|
|
||
|
// This will be nil if we're just running the page optimizer.
|
||
|
if (fCurrFont)
|
||
|
{
|
||
|
fCurrFont->SetRenderYJustify( plFont::kRenderJustYTop );
|
||
|
SetJustify( fJustify );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::SetFont( const wchar_t *face, UInt16 size, UInt8 fontFlags , hsBool antiAliasRGB )
|
||
|
{
|
||
|
char *sFace = hsWStringToString(face);
|
||
|
SetFont(sFace,size,fontFlags,antiAliasRGB);
|
||
|
delete [] sFace;
|
||
|
}
|
||
|
|
||
|
//// SetLineSpacing ///////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::SetLineSpacing( Int16 spacing )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
fLineSpacing = spacing;
|
||
|
fCurrFont->SetRenderLineSpacing(spacing);
|
||
|
}
|
||
|
|
||
|
//// SetTextColor /////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::SetTextColor( hsColorRGBA &color, hsBool blockRGB )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
fFontColor = color;
|
||
|
fFontBlockRGB = blockRGB;
|
||
|
|
||
|
if (fCurrFont)
|
||
|
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
|
||
|
}
|
||
|
|
||
|
//// DrawString ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawString( UInt16 x, UInt16 y, const char *text )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
DrawString(x,y,wText);
|
||
|
delete [] wText;
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::DrawString( UInt16 x, UInt16 y, const wchar_t *text )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
fCurrFont->SetRenderFlag( plFont::kRenderWrap | plFont::kRenderClip, false );
|
||
|
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
|
||
|
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
|
||
|
fCurrFont->RenderString( this, x, y, text );
|
||
|
}
|
||
|
|
||
|
//// DrawClippedString ////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const char *text, UInt16 width, UInt16 height )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
DrawClippedString(x,y,wText,width,height);
|
||
|
delete [] wText;
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, UInt16 width, UInt16 height )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
fCurrFont->SetRenderClipping( x, y, width, height );
|
||
|
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
|
||
|
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
|
||
|
fCurrFont->RenderString( this, x, y, text );
|
||
|
}
|
||
|
|
||
|
//// DrawClippedString ////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const char *text, UInt16 clipX, UInt16 clipY, UInt16 width, UInt16 height )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
DrawClippedString(x,y,wText,clipX,clipY,width,height);
|
||
|
delete [] wText;
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, UInt16 clipX, UInt16 clipY, UInt16 width, UInt16 height )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
fCurrFont->SetRenderClipping( clipX, clipY, width, height );
|
||
|
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
|
||
|
fCurrFont->RenderString( this, x, y, text );
|
||
|
}
|
||
|
|
||
|
//// DrawWrappedString ////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawWrappedString( UInt16 x, UInt16 y, const char *text, UInt16 width, UInt16 height, UInt16 *lastX, UInt16 *lastY )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
DrawWrappedString(x,y,wText,width,height,lastX,lastY);
|
||
|
delete [] wText;
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::DrawWrappedString( UInt16 x, UInt16 y, const wchar_t *text, UInt16 width, UInt16 height, UInt16 *lastX, UInt16 *lastY )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
fCurrFont->SetRenderWrapping( x, y, width, height );
|
||
|
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
|
||
|
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
|
||
|
fCurrFont->RenderString( this, x, y, text, lastX, lastY );
|
||
|
}
|
||
|
|
||
|
//// CalcStringWidth //////////////////////////////////////////////////////////
|
||
|
|
||
|
UInt16 plDynamicTextMap::CalcStringWidth( const char *text, UInt16 *height )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
UInt16 w = CalcStringWidth(wText,height);
|
||
|
delete [] wText;
|
||
|
return w;
|
||
|
}
|
||
|
|
||
|
UInt16 plDynamicTextMap::CalcStringWidth( const wchar_t *text, UInt16 *height )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return 0;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
UInt16 w, h, a, lastX, lastY;
|
||
|
UInt32 firstClipped;
|
||
|
fCurrFont->SetRenderFlag( plFont::kRenderClip | plFont::kRenderWrap, false );
|
||
|
fCurrFont->CalcStringExtents( text, w, h, a, firstClipped, lastX, lastY );
|
||
|
if( height != nil )
|
||
|
*height = h;
|
||
|
return w;
|
||
|
}
|
||
|
|
||
|
//// SetFirstLineIndent ///////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::SetFirstLineIndent( Int16 indent )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
fCurrFont->SetRenderFirstLineIndent( indent );
|
||
|
}
|
||
|
|
||
|
//// CalcWrappedStringSize ////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::CalcWrappedStringSize( const char *text, UInt16 *width, UInt16 *height, UInt32 *firstClippedChar, UInt16 *maxAscent, UInt16 *lastX, UInt16 *lastY )
|
||
|
{
|
||
|
wchar_t *wText = hsStringToWString(text);
|
||
|
CalcWrappedStringSize(wText,width,height,firstClippedChar,maxAscent,lastX,lastY);
|
||
|
delete [] wText;
|
||
|
}
|
||
|
|
||
|
void plDynamicTextMap::CalcWrappedStringSize( const wchar_t *text, UInt16 *width, UInt16 *height, UInt32 *firstClippedChar, UInt16 *maxAscent, UInt16 *lastX, UInt16 *lastY )
|
||
|
{
|
||
|
// ===> Don't need to validate creation
|
||
|
// if( !IIsValid() )
|
||
|
// return;
|
||
|
|
||
|
SetJustify( fJustify );
|
||
|
UInt16 w, h, a, lX, lY;
|
||
|
UInt32 firstClipped;
|
||
|
fCurrFont->SetRenderWrapping( 0, 0, *width, *height );
|
||
|
fCurrFont->CalcStringExtents( text, w, h, a, firstClipped, lX, lY );
|
||
|
*width = w;
|
||
|
*height = h;
|
||
|
if( firstClippedChar != nil )
|
||
|
*firstClippedChar = firstClipped;
|
||
|
if( maxAscent != nil )
|
||
|
*maxAscent = a;
|
||
|
if( lastX != nil )
|
||
|
*lastX = lX;
|
||
|
if( lastY != nil )
|
||
|
*lastY = lY;
|
||
|
}
|
||
|
|
||
|
//// FillRect /////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::FillRect( UInt16 x, UInt16 y, UInt16 width, UInt16 height, hsColorRGBA &color )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
if( x + width > fWidth )
|
||
|
width = (UInt16)(fWidth - x);
|
||
|
|
||
|
// Gee, how hard can it REALLY be?
|
||
|
UInt32 i, hex = color.ToARGB32();
|
||
|
height += y;
|
||
|
if( height > fHeight )
|
||
|
height = (UInt16)fHeight;
|
||
|
for( ; y < height; y++ )
|
||
|
{
|
||
|
UInt32 *destPtr = GetAddr32( x, y );
|
||
|
for( i = 0; i < width; i++ )
|
||
|
destPtr[ i ] = hex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// FrameRect ////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::FrameRect( UInt16 x, UInt16 y, UInt16 width, UInt16 height, hsColorRGBA &color )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
if( x + width > fWidth )
|
||
|
width = (UInt16)(fWidth - x);
|
||
|
if( y + height > fHeight )
|
||
|
height = (UInt16)(fHeight - y);
|
||
|
|
||
|
// Shouldn't be much harder
|
||
|
UInt32 i, hex = color.ToARGB32();
|
||
|
UInt32 *dest1, *dest2;
|
||
|
|
||
|
dest1 = GetAddr32( x, y );
|
||
|
dest2 = GetAddr32( x, y + height - 1 );
|
||
|
for( i = 0; i < width; i++ )
|
||
|
dest1[ i ] = dest2[ i ] = hex;
|
||
|
|
||
|
for( i = 0; i < height; i++ )
|
||
|
{
|
||
|
dest1[ 0 ] = dest1[ width - 1 ] = hex;
|
||
|
dest1 += fWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//// DrawImage ////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawImage( UInt16 x, UInt16 y, plMipmap *image, DrawMethods method )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
plMipmap::CompositeOptions opts;
|
||
|
if( method == kImgNoAlpha )
|
||
|
{
|
||
|
if( fHasAlpha )
|
||
|
opts.fFlags = plMipmap::kForceOpaque;
|
||
|
else
|
||
|
opts.fFlags = plMipmap::kCopySrcAlpha; // Don't care, this is fastest
|
||
|
}
|
||
|
else if( method == kImgBlend )
|
||
|
opts.fFlags = 0; // Default opts
|
||
|
else if( method == kImgSprite )
|
||
|
opts.fFlags = plMipmap::kCopySrcAlpha;
|
||
|
|
||
|
Composite( image, x, y, &opts );
|
||
|
|
||
|
/// HACK for now, since the alpha in the mipmap gets copied straight into the
|
||
|
/// 32-bit color buffer, but our separate hacked alpha buffer hasn't been updated
|
||
|
/* if( fHasAlpha && !respectAlpha )
|
||
|
{
|
||
|
HBRUSH brush = ::CreateSolidBrush( RGB( 255, 255, 255 ) );
|
||
|
RECT rc;
|
||
|
::SetRect( &rc, x, y, x + image->GetWidth(), y + image->GetHeight() );
|
||
|
::FillRect( fWinAlphaDC, &rc, brush );
|
||
|
::DeleteObject( brush );
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
//// DrawClippedImage /////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::DrawClippedImage( UInt16 x, UInt16 y, plMipmap *image,
|
||
|
UInt16 srcClipX, UInt16 srcClipY,
|
||
|
UInt16 srcClipWidth, UInt16 srcClipHeight,
|
||
|
DrawMethods method )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
plMipmap::CompositeOptions opts;
|
||
|
if( method == kImgNoAlpha )
|
||
|
{
|
||
|
if( fHasAlpha )
|
||
|
opts.fFlags = plMipmap::kForceOpaque;
|
||
|
else
|
||
|
opts.fFlags = plMipmap::kCopySrcAlpha; // Don't care, this is fastest
|
||
|
}
|
||
|
else if( method == kImgBlend )
|
||
|
opts.fFlags = 0; // Default opts
|
||
|
else if( method == kImgSprite )
|
||
|
opts.fFlags = plMipmap::kCopySrcAlpha;
|
||
|
|
||
|
opts.fSrcClipX = srcClipX;
|
||
|
opts.fSrcClipY = srcClipY;
|
||
|
opts.fSrcClipWidth = srcClipWidth;
|
||
|
opts.fSrcClipHeight = srcClipHeight;
|
||
|
Composite( image, x, y, &opts );
|
||
|
|
||
|
/// HACK for now, since the alpha in the mipmap gets copied straight into the
|
||
|
/// 32-bit color buffer, but our separate hacked alpha buffer hasn't been updated
|
||
|
/* if( fHasAlpha && !respectAlpha )
|
||
|
{
|
||
|
HBRUSH brush = ::CreateSolidBrush( RGB( 255, 255, 255 ) );
|
||
|
RECT rc;
|
||
|
::SetRect( &rc, x, y, x + ( srcClipWidth > 0 ? srcClipWidth : image->GetWidth() ),
|
||
|
y + ( srcClipHeight > 0 ? srcClipHeight : image->GetHeight() ) );
|
||
|
::FillRect( fWinAlphaDC, &rc, brush );
|
||
|
::DeleteObject( brush );
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
//// FlushToHost //////////////////////////////////////////////////////////////
|
||
|
|
||
|
void plDynamicTextMap::FlushToHost( void )
|
||
|
{
|
||
|
if( !IIsValid() )
|
||
|
return;
|
||
|
|
||
|
// Dirty the mipmap's deviceRef, if there is one
|
||
|
if( GetDeviceRef() != nil )
|
||
|
GetDeviceRef()->SetDirty( true );
|
||
|
}
|
||
|
|
||
|
//// GetLayerTransform ////////////////////////////////////////////////////////
|
||
|
// Since the textGen can actually create a texture bigger than you were expecting,
|
||
|
// you want to be able to apply a layer texture transform that will compensate. This
|
||
|
// function will give you that transform. Just feed it into plLayer->SetTransform().
|
||
|
|
||
|
hsMatrix44 plDynamicTextMap::GetLayerTransform( void )
|
||
|
{
|
||
|
hsMatrix44 xform;
|
||
|
hsVector3 scale;
|
||
|
|
||
|
scale.Set( (float)GetVisibleWidth() / (float)GetWidth(),
|
||
|
(float)GetVisibleHeight() / (float)GetHeight(), 1.f );
|
||
|
|
||
|
xform.MakeScaleMat( &scale );
|
||
|
return xform;
|
||
|
}
|
||
|
|
||
|
//// MsgReceive ///////////////////////////////////////////////////////////////
|
||
|
|
||
|
hsBool plDynamicTextMap::MsgReceive( plMessage *msg )
|
||
|
{
|
||
|
plDynamicTextMsg *textMsg = plDynamicTextMsg::ConvertNoRef( msg );
|
||
|
if( textMsg != nil )
|
||
|
{
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kClear )
|
||
|
ClearToColor( textMsg->fClearColor );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kSetTextColor )
|
||
|
SetTextColor( textMsg->fColor, textMsg->fBlockRGB );
|
||
|
|
||
|
if( (textMsg->fCmd & plDynamicTextMsg::kSetFont ) && textMsg->fString)
|
||
|
SetFont( textMsg->fString, textMsg->fX, (UInt8)(textMsg->fFlags) );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kSetLineSpacing )
|
||
|
SetLineSpacing( textMsg->fLineSpacing );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kSetJustify )
|
||
|
SetJustify( (Justify)textMsg->fFlags );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kFillRect )
|
||
|
FillRect( textMsg->fLeft, textMsg->fTop, textMsg->fRight - textMsg->fLeft + 1,
|
||
|
textMsg->fBottom - textMsg->fTop + 1, textMsg->fColor );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kFrameRect )
|
||
|
FrameRect( textMsg->fLeft, textMsg->fTop, textMsg->fRight - textMsg->fLeft + 1,
|
||
|
textMsg->fBottom - textMsg->fTop + 1, textMsg->fColor );
|
||
|
|
||
|
if( (textMsg->fCmd & plDynamicTextMsg::kDrawString ) && textMsg->fString)
|
||
|
DrawString( textMsg->fX, textMsg->fY, textMsg->fString );
|
||
|
|
||
|
if( (textMsg->fCmd & plDynamicTextMsg::kDrawClippedString ) && textMsg->fString)
|
||
|
DrawClippedString( textMsg->fX, textMsg->fY, textMsg->fString,
|
||
|
textMsg->fLeft, textMsg->fTop, textMsg->fRight - textMsg->fLeft + 1,
|
||
|
textMsg->fBottom - textMsg->fTop + 1 );
|
||
|
|
||
|
if( (textMsg->fCmd & plDynamicTextMsg::kDrawWrappedString ) && textMsg->fString)
|
||
|
DrawWrappedString( textMsg->fX, textMsg->fY, textMsg->fString, textMsg->fRight, textMsg->fBottom );
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kDrawImage )
|
||
|
{
|
||
|
plMipmap *mip = plMipmap::ConvertNoRef( textMsg->fImageKey ? textMsg->fImageKey->ObjectIsLoaded() : nil);
|
||
|
if( mip != nil )
|
||
|
DrawImage( textMsg->fX, textMsg->fY, mip, textMsg->fFlags ? kImgBlend : kImgNoAlpha );
|
||
|
}
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kDrawClippedImage )
|
||
|
{
|
||
|
plMipmap *mip = plMipmap::ConvertNoRef( textMsg->fImageKey ? textMsg->fImageKey->ObjectIsLoaded() : nil);
|
||
|
if( mip != nil )
|
||
|
DrawClippedImage( textMsg->fX, textMsg->fY, mip, textMsg->fLeft, textMsg->fTop,
|
||
|
textMsg->fRight, textMsg->fBottom, textMsg->fFlags ? kImgBlend : kImgNoAlpha );
|
||
|
}
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kFlush )
|
||
|
FlushToHost();
|
||
|
|
||
|
if( textMsg->fCmd & plDynamicTextMsg::kPurgeImage )
|
||
|
PurgeImage();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return plMipmap::MsgReceive( msg );
|
||
|
}
|
||
|
|
||
|
//// Swap /////////////////////////////////////////////////////////////////////
|
||
|
// Swapping is an evil little trick. It's also something that should probably
|
||
|
// be exposed at the mipmap level eventually, but there's no need for it yet.
|
||
|
// Basically, it lets you take the contents of two DTMaps and swap them, as
|
||
|
// if you had swapped pointers, but you didn't. This is so you can, well, swap
|
||
|
// DTMaps without swapping pointers! (Like, say, you don't have access to them)
|
||
|
|
||
|
#define SWAP_ME( Type, a, b ) { Type temp; temp = a; a = b; b = temp; }
|
||
|
|
||
|
void plDynamicTextMap::Swap( plDynamicTextMap *other )
|
||
|
{
|
||
|
// We only do this if the two are the same size, color depth, etc
|
||
|
if( other->GetWidth() != GetWidth() || other->GetHeight() != GetHeight() ||
|
||
|
other->GetPixelSize() != GetPixelSize() )
|
||
|
return;
|
||
|
|
||
|
// Swap image pointers
|
||
|
void *ptr = other->fImage;
|
||
|
other->fImage = fImage;
|
||
|
fImage = ptr;
|
||
|
|
||
|
// Invalidate both device refs (don't risk swapping THOSE)
|
||
|
if( GetDeviceRef() != nil )
|
||
|
GetDeviceRef()->SetDirty( true );
|
||
|
if( other->GetDeviceRef() != nil )
|
||
|
other->GetDeviceRef()->SetDirty( true );
|
||
|
|
||
|
// Swap DTMap info
|
||
|
SWAP_ME( hsBool, fHasAlpha, other->fHasAlpha );
|
||
|
SWAP_ME( hsBool, fShadowed, other->fShadowed );
|
||
|
|
||
|
SWAP_ME( Justify, fJustify, other->fJustify );
|
||
|
SWAP_ME( char *, fFontFace, other->fFontFace );
|
||
|
SWAP_ME( UInt16, fFontSize, other->fFontSize );
|
||
|
SWAP_ME( UInt8, fFontFlags, other->fFontFlags );
|
||
|
SWAP_ME( hsBool, fFontAntiAliasRGB, other->fFontAntiAliasRGB );
|
||
|
SWAP_ME( hsColorRGBA, fFontColor, other->fFontColor );
|
||
|
SWAP_ME( hsBool, fFontBlockRGB, other->fFontBlockRGB );
|
||
|
|
||
|
SWAP_ME( hsBool, fFontBlockRGB, other->fFontBlockRGB );
|
||
|
SWAP_ME( hsBool, fFontBlockRGB, other->fFontBlockRGB );
|
||
|
SWAP_ME( hsBool, fFontBlockRGB, other->fFontBlockRGB );
|
||
|
|
||
|
SWAP_ME( plFont *, fCurrFont, other->fCurrFont );
|
||
|
SWAP_ME( UInt32 *, fInitBuffer, other->fInitBuffer );
|
||
|
}
|