deargui-vpl/ref/virtools/Samples/Behaviors/Interface/Sources/CKFontManager.cpp

2382 lines
60 KiB
C++
Raw Permalink Blame History

/*************************************************************************/
/* File : CKFontManager.cpp */
/* */
/*************************************************************************/
#include "CKall.h"
#include "CKFontManager.h"
#ifdef macintosh
#ifndef __GNUC__
#include <FixMath.h>
#else
#include <QuickTime/QuickTime.h>
#endif
#include "VxWindowFunctions.h"
#endif
#define FONTMANAGERVERSION1 1
#ifdef macintosh
#define FONTSIZE128 (8)
#define FONTSIZE256 (12)
#define FONTSIZE512 (24)
#define FONTSIZE1024 (48)
#else
#define FONTSIZE128 (-5)
#define FONTSIZE256 (-10)
#define FONTSIZE512 (-20)
#define FONTSIZE1024 (-40)
#endif
const char* CKFontManager::Name = "Font Manager";
#ifdef USEQUICKDRAWTEXT
class GWorldSwitcher{
public:
GWorldSwitcher(GWorldPtr gw){
GetGWorld (&m_op, &m_od);
SetGWorld(gw,NULL);
}
~GWorldSwitcher(){
SetGWorld(m_op,m_od);
}
protected:
CGrafPtr m_op; // Former Graf Port
GDHandle m_od; // Former Device Handle
};
#define SETOFFSCREENPORT() GWorldSwitcher gws(m_GDC);
void PStrFromXString(const XString& SrcX, Str255 dst);
XString XStringFromPStr(ConstStr255Param pString);
#endif
/*************************************************
Name: parent2DHidden, parent3DHidden
Summary: look the parent of an entity to verify it's visibility
Arguments: ent : entity to check for visibility
Return Value: TRUE if a parent is hidden else FALSE
Remarks: none
See also: DrawTextCallback
*************************************************/
inline
CKBOOL parent2DHidden(CK2dEntity* ent) {
while(ent) {
if(ent->IsHierarchicallyHide()) return TRUE;
ent = ent->GetParent();
}
return FALSE;
}
inline
CKBOOL parent3DHidden(CK3dEntity* ent) {
while(ent) {
if(ent->IsHierarchicallyHide()) return TRUE;
ent = ent->GetParent();
}
return FALSE;
}
// Post render callback
CKFontManager::CKFontManager(CKContext* ctx):CKBaseManager(ctx,FONT_MANAGER_GUID,(char*)Name)
{
m_DebugFont = NULL;
m_TextureLoaded = FALSE;
m_VersionUpdate = FALSE;
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
Rect ImageRect;
ImageRect.left = 0;
ImageRect.right = 512;
ImageRect.bottom = 512;
ImageRect.top = 0;
m_GDC = NULL;
NewGWorld(&m_GDC,32,&ImageRect,NULL,NULL,0);
#ifndef __GNUC__
if(m_GDC == NULL) throw "Font Manager -- Unable to create a screen compatible Gworld";
#endif
m_CurrentFont = 0;
#else
m_BackupFont = NULL;
// System font device context initialisation
m_DC = ::CreateCompatibleDC(NULL);
if(m_DC == NULL) throw "Font Manager -- Unable to create a screen compatible DC";
#endif
#endif
ctx->RegisterNewManager(this);
}
CKFontManager::~CKFontManager()
{
for (CKTextureFont** it = m_FontArray.Begin();it != m_FontArray.End();it++) {
CKTextureFont* font = *it;
CKTexture* texture = (CKTexture*)m_Context->GetObject(font->m_FontTexture);
DeleteFontHandle(font->m_FontName);
delete font;
}
m_FontArray.Clear();
ClearTextData();
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
// Free the GWorld
DisposeGWorld(m_GDC);
#else
// Release memory device context
::DeleteDC(m_DC);
#endif
#endif
}
void CKFontManager::DeleteFont(int fontIndex)
{
CKTextureFont* font = GetFont(fontIndex);
if (!font) return;
m_FontArray.RemoveAt(fontIndex-1);
DeleteFontHandle(font->m_FontName);
CKTexture* tex = font->GetFontTexture();
if (tex->IsDynamic()) {
// we now search if the texture is used anywhere else
CKTextureFont** it = m_FontArray.Begin();
for (;it != m_FontArray.End();it++) {
if ((*it)->GetFontTexture() == tex) break;
}
if (it == m_FontArray.End()) { // Not used : we delete it
CKDestroyObject(tex);
}
}
delete font;
RebuildFontEnumeration();
}
// Delete the font data
void CKFontManager::ClearFontData(void)
{
// CKBOOL needToRebuildEnum = FALSE;
// delete the texture font and the font handle if exists
for (CKTextureFont** it = m_FontArray.Begin();it != m_FontArray.End();) {
CKTextureFont* font = *it;
CKTexture* texture = (CKTexture*)m_Context->GetObject(font->m_FontTexture);
if (!texture || texture->IsDynamic()) {
DeleteFontHandle(font->m_FontName);
delete font;
// needToRebuildEnum = TRUE;
it = m_FontArray.Remove(it);
} else ++it;
}
/* Commented because more user friendly to have the font type that remains after a reset
// we now rebuild the enum
if (needToRebuildEnum)
RebuildFontEnumeration();
*/
}
// Delete the text data struct
void CKFontManager::ClearTextData(void)
{
// Delete the text data for multiple settings if exists
// this tables contains only references
m_2DTexts.Resize(0);
m_3DTexts.Resize(0);
// the real data are here, we delete them
for(TextDataTableIterator textIt = m_Texts.Begin(); textIt != m_Texts.End() ; textIt++)
delete *textIt;
// the real data are here, we delete them
for(TextDataTableIterator textIt = m_TextsRespectZorder.Begin(); textIt != m_TextsRespectZorder.End() ; textIt++)
delete *textIt;
m_Texts.Clear();
m_TextsRespectZorder.Clear();
}
//{secret}
CKERROR CKFontManager::PostClearAll()
{
RegisterAttributes();
ClearFontData();
ClearTextData();
#ifndef FONTMANAGER_NOSYSFONT
// delete all font objects...
FontIterator it = m_fonts.Begin();
FontIterator fend = m_fonts.End();
// And we release the handle
while (it != fend) {
#if defined(macintosh)
VxDeleteFont(*it);
#else
::DeleteObject(*it);
#endif
++it;
}
m_fonts.Clear();
#endif
return CK_OK;
}
void
CKFontManager::RegisterAttributes()
{
CKParameterManager* pm = m_Context->GetParameterManager();
pm->RegisterNewEnum(CKPGUID_FONT,"Font Type", "No Font=0");
pm->ChangeEnumDeclaration(CKPGUID_FONT,"No Font=0");
CKParameterTypeDesc* pt = pm->GetParameterTypeDescription(CKPGUID_FONT);
pt->Saver_Manager = FONT_MANAGER_GUID;
}
/*************************************************
Name:
Summary: Not Yet Documented
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
CKERROR
CKFontManager::OnCKInit()
{
RegisterAttributes();
RegenerateFontEnumeration();
return CK_OK;
}
/*************************************************
Name:
Summary: Not Yet Documented
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
CKERROR
CKFontManager::OnCKEnd()
{
return CK_OK;
}
/*************************************************
Name:
Summary: Not Yet Documented
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
CKERROR CKFontManager::OnPostRender(CKRenderContext* dev)
{
DrawTextCallback3D(dev, this);
return CK_OK;
}
CKERROR
CKFontManager::OnPostBackToFront(CKRenderContext* dev)
{
#ifndef PSP
// Clear the reference table for next use
m_2DTexts.Resize(0);
m_3DTexts.Resize(0);
m_Rectangles.Resize(0);
#endif
return CK_OK;
}
CKERROR CKFontManager::OnPostSpriteRender(CKRenderContext* dev)
{
// 2.5 change
// changes for text to appear after the 2D entities
DrawTextCallback2D(dev, this);
DrawRectanglesCallback(dev);
return CK_OK;
}
CKERROR
CKFontManager::PreProcess()
{
#ifdef PSP
// Clear the reference table for next use
m_2DTexts.Resize(0);
m_3DTexts.Resize(0);
m_Rectangles.Resize(0);
#else
///
// we need to find the 2DEntity under the mouse cursor
m_EntityUnderMouse = NULL;
CKInputManager* im = (CKInputManager*)m_Context->GetManagerByGuid(INPUT_MANAGER_GUID);
if (!im) return CK_OK;
Vx2DVector mp;
im->GetMousePosition(mp,FALSE);
CKRenderContext* rc = m_Context->GetPlayerRenderContext();
if (rc) {
VxRect screen;
rc->GetWindowRect(screen,FALSE);
mp += screen.GetTopLeft();
m_EntityUnderMouse = rc->Pick2D(mp);
}
#endif
return CK_OK;
}
CKERROR
CKFontManager::OnCKReset()
{
ClearFontData();
ClearTextData();
return CK_OK;
}
/*************************************************
Name: SequenceToBeDeleted
Summary: System font could be created from dynamical texture.
We must destroy these font if the texture is deleted
Arguments: the objects deleted
Return Value:
Remarks:
See also:
*************************************************/
CKERROR
CKFontManager::SequenceToBeDeleted(CK_ID *objids,int count)
{
// Check the texture
OnTextureToBeDeleted();
// We check the compiled data
for (CompiledTextTableIterator compIt = m_CompiledText.Begin(); compIt != m_CompiledText.End() ; ) {
CKObject* obj = m_Context->GetObject(compIt.GetKey());
if (obj->IsToBeDeleted()) {
delete *compIt;
compIt = m_CompiledText.Remove(compIt);
} else compIt++;
}
// check the 3D texts
TextData** td;
for (td = m_3DTexts.Begin(); td != m_3DTexts.End();) {
CK3dEntity* ent = (CK3dEntity*)m_Context->GetObject((*td)->m_Entity);
if (ent->IsToBeDeleted()) {
td = m_3DTexts.Remove(td);
} else ++td;
}
// check the 2D texts
for (td = m_2DTexts.Begin(); td != m_2DTexts.End();) {
CK2dEntity* ent = (CK2dEntity*)m_Context->GetObject((*td)->m_Entity);
if (ent->IsToBeDeleted()) {
td = m_2DTexts.Remove(td);
} else ++td;
}
// We check the text Data
for (TextDataTableIterator textIt = m_Texts.Begin(); textIt != m_Texts.End() ; ) {
CKObject* obj = m_Context->GetObject(textIt.GetKey());
if (!obj || obj->IsToBeDeleted()) {
delete *textIt;
textIt = m_Texts.Remove(textIt);
} else textIt++;
}
// We check the text Data
for (TextDataTableIterator textIt = m_TextsRespectZorder.Begin(); textIt != m_TextsRespectZorder.End() ; ) {
CKObject* obj = m_Context->GetObject(textIt.GetKey());
if (!obj || obj->IsToBeDeleted()) {
delete *textIt;
textIt = m_TextsRespectZorder.Remove(textIt);
} else textIt++;
}
return CK_OK;
}
// Conveniences for SequenceToBeDeleted
void CKFontManager::OnTextureToBeDeleted()
{
// CKBOOL needToRebuildEnum = FALSE;
int index = 0;
CKTextureFont** it = m_FontArray.Begin();
while (it != m_FontArray.End()) {
CKTextureFont* font = *it;
CKTexture* tex = (CKTexture*)m_Context->GetObject(font->m_FontTexture);
if (tex && tex->IsToBeDeleted()) {
// the texture is destroyed : delete the associated logical font if any
DeleteFontHandle(font->m_FontName);
// we delete the texture
delete font;
// and we remove it from the array
it = m_FontArray.Remove(it);
// We update the local parameters using this deleted texture
CK_ID* ids = m_Context->GetObjectsListByClassID(CKCID_PARAMETERLOCAL);
int j,idcount = m_Context->GetObjectsCountByClassID(CKCID_PARAMETERLOCAL);
for (j=0;j<idcount;++j) {
CKParameterLocal* pl = (CKParameterLocal*)m_Context->GetObject(ids[j]);
if (pl && (pl->GetGUID() == CKPGUID_FONT)) {
int *value = (int*)pl->GetWriteDataPtr();
if (*value == (index+1))
*value = 0;
else
if(*value > (index+1))
(*value)--;
}
}
ids = m_Context->GetObjectsListByClassID(CKCID_PARAMETEROUT);
idcount = m_Context->GetObjectsCountByClassID(CKCID_PARAMETEROUT);
for (j=0;j<idcount;++j) {
CKParameterOut* pl = (CKParameterOut*)m_Context->GetObject(ids[j]);
if (pl && (pl->GetGUID() == CKPGUID_FONT)) {
int *value = (int*)pl->GetWriteDataPtr();
if (*value == (index+1))
*value = 0;
else
if(*value > (index+1))
(*value)--;
}
}
// needToRebuildEnum = TRUE;
// break;
} else {
++it;
++index;
}
}
/* Commented because more user friendly to have the font type that remains after a reset
// we now rebuild the enum
if (needToRebuildEnum)
RebuildFontEnumeration();
*/
}
/*************************************************
Name: RebuildFontEnumeration
Summary: Build the enumeration representing the available fonts
Arguments:
Return Value:
Remarks: Called at font creation or font deletion
See also:
*************************************************/
void
CKFontManager::RebuildFontEnumeration(void)
{
XString xenumstring;
XString xtmp;
int index = 1;
// Scan all available fonts
for(CKTextureFont** it = m_FontArray.Begin();it != m_FontArray.End();it++,++index) {
CKTextureFont* font = *it;
xtmp.Format("%s=%d", font->m_FontName, index);
xenumstring+=xtmp;
if(index != m_FontArray.Size())
xenumstring+=",";
}
if (!xenumstring.Length())
xenumstring="No Font=0";
// Register the new enumeration
m_Context->GetParameterManager()->ChangeEnumDeclaration(CKPGUID_FONT, xenumstring.Str());
}
/*************************************************
Name: GetFontTexture
Summary: Get the CKTexture associated with a Font.
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
CKTexture*
CKFontManager::GetFontTexture(unsigned int fontindex)
{
CKTextureFont* font = m_FontArray[fontindex-1];
return font->GetFontTexture();
}
/*************************************************
Name: GetFontName
Summary: Get the name of a font from its index.
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
CKSTRING
CKFontManager::GetFontName(unsigned int fontindex)
{
CKTextureFont* font = m_FontArray[fontindex-1];
return font->m_FontName;
}
/*************************************************
Name: GetFontIndex
Summary: Get the index of a font from its name
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
int
CKFontManager::GetFontIndex(CKSTRING name)
{
if(!name) return 0;
int index = 1;
for (CKTextureFont** it = m_FontArray.Begin();it != m_FontArray.End();it++,index++) {
CKTextureFont* font = *it;
if(font->m_FontName)
if(font && !strcmp(font->m_FontName, name))
return index;
}
return 0;
}
/*************************************************
Name: RegisterFont
Summary: Add a new font to the font manager
Arguments: a CKTextureFont representing the font
Return Value:
Remarks:
See also:
*************************************************/
int
CKFontManager::RegisterFont(CKTextureFont* font)
{
// Add to the font array
m_FontArray.PushBack(font);
// Change the enum
RebuildFontEnumeration();
// To have the font in Level VIew
int fontindex = m_FontArray.Size();
m_Context->SendInterfaceMessage(CKUIM_FONTCREATED, fontindex, (CKDWORD)this);
// return Index+1
return fontindex;
}
/*************************************************
Name:
Summary: Not Yet Documented
Arguments:
Return Value:
Remarks:
See also:
*************************************************/
int
CKFontManager::CreateTextureFont(CKSTRING FontName,CKTexture* fonttexture,VxRect& tzone,Vx2DVector& charnumber,CKBOOL fixed,int firstcharacter,float iSpaceSize)
{
if(!fonttexture) return -1;
if(!FontName) return -1;
// WE create the new font
CKTextureFont* font = new CKTextureFont(this,m_Context,FontName);
font->CreateCKFont(fonttexture,tzone,charnumber,fixed,firstcharacter,iSpaceSize);
font->m_ScreenExtents.Set(fonttexture->GetWidth(),fonttexture->GetHeight());
if (!strcmp(FontName,"VDebugFont")) {
XASSERT(m_DebugFont == NULL);
m_DebugFont = font;
return 0;
}
// We look for existant
int index = GetFontIndex(FontName);
if (index) { // the font was found..
// we delete the old one
CKTextureFont* old = m_FontArray[index-1];
delete old;
// we store the new one
m_FontArray[index-1] = font;
return index;
} else { // No similar font found : we create a new one
// We add the font to the font array
return RegisterFont(font);
}
}
CKTextureFont*
CKFontManager::GetFont(unsigned int font)
{
if (font <= 0) return NULL;
if (font > (unsigned int)m_FontArray.Size()) return NULL;
CKTextureFont* tf = m_FontArray[font-1];
if (tf->m_SpacingProperties&CKTextureFont::CREATED) return tf;
else return NULL;
}
// Text Lines
void
CKFontManager::ClearLines()
{
m_Lines.Resize(0);
}
void
CKFontManager::AddLine(LineData& data)
{
m_Lines.PushBack(data);
}
int
CKFontManager::GetLineCount()
{
return m_Lines.Size();
}
LineData*
CKFontManager::GetLine(int i)
{
if(i < m_Lines.Size()) {
return &m_Lines[i];
}
return NULL;
}
#define FONT_VERSION1 0x8001
#define FONT_VERSION2 0x8002
CKStateChunk*
CKFontManager::SaveData(CKFile* SavedFile)
{
if(!m_FontArray.Size()) return NULL;
///////////////////////////////////
// FONTS SAVING
//////////////////////////////////
int textureCount = 0;
CKTextureFont** it;
for(it = m_FontArray.Begin();it != m_FontArray.End();it++) {
CKTextureFont* font = *it;
CKTexture* texture = (CKTexture*)m_Context->GetObject(font->m_FontTexture);
if (!texture) continue; // does not exist
if (texture->IsDynamic()) continue; // does not need to be saved
if (!SavedFile->IsObjectToBeSaved(font->m_FontTexture)) continue; // the texture is not gonna be saved
textureCount++;
}
if (!textureCount) return NULL;
CKStateChunk *mychunk=CreateCKStateChunk((CK_CLASSID)FONTMANAGERVERSION1,SavedFile);
mychunk->StartWrite();
// Font Identifier
mychunk->WriteIdentifier(FONT_VERSION2);
// we write the number of fonts
mychunk->WriteInt(textureCount);
// Fonts processing
for (it = m_FontArray.Begin();it != m_FontArray.End();it++) {
CKTextureFont* font = *it;
CKTexture* texture = (CKTexture*)m_Context->GetObject(font->m_FontTexture);
if (!texture) continue; // does not exist
if (texture->IsDynamic()) continue; // does not need to be saved
if (!SavedFile->IsObjectToBeSaved(font->m_FontTexture)) continue; // the texture is not gonna be saved
// FontName
mychunk->WriteString(font->m_FontName);
// CharNumber
mychunk->WriteBuffer(sizeof(Vx2DVector),&(font->m_CharNumber));
// FontZone
mychunk->WriteBuffer(sizeof(VxRect),&(font->m_FontZone));
// Texture ID
mychunk->WriteObjectID(font->m_FontTexture);
// Spacing Properties
mychunk->WriteInt(font->m_SpacingProperties & CKTextureFont::TOBESAVED);
// First Character
mychunk->WriteInt(font->m_FirstCharacter);
// we now maybe have to save the spacing properties for the given font
if (font->m_SpacingProperties & CKTextureFont::SPACINGTOBESAVED) {
mychunk->WriteBufferNoSize_LEndian(256*sizeof(CharacterTextureCoordinates),&(font->m_FontCoordinates));
}
}
mychunk->CloseChunk();
return mychunk;
}
// {secret}
CKERROR
CKFontManager::LoadData(CKStateChunk *chunk,CKFile* LoadedFile)
{
if (!chunk) return CKERR_INVALIDPARAMETER;
chunk->StartRead();
///////////////////////////////////
// FONTS LOADING
//////////////////////////////////
// font Identifier
int version = 2;
if (!chunk->SeekIdentifier(FONT_VERSION2)) {
if (chunk->SeekIdentifier(FONT_VERSION1)) version = 1;
else version = 0;
}
if (version) {
// we read the number of fonts
int fn = chunk->ReadInt();
int* ConversionTable=new int[fn+1];
// No Remapping for the first one
memset(ConversionTable,0,4*(fn+1));
char buffer[128];
// we read the font
for(int h=0;h<fn;h++) {
// Font Name
chunk->ReadAndFillBuffer(&buffer);
// char Number
Vx2DVector cn;
chunk->ReadAndFillBuffer_LEndian(&cn);
// Font Zone
VxRect fz;
chunk->ReadAndFillBuffer_LEndian(&fz);
// Texture ID
CK_ID id = chunk->ReadObjectID();
CKObject* obj=CKGetObject(id);
if (!CKIsChildClassOf(obj,CKCID_TEXTURE)) id=0;
// Spacing
int spacing = chunk->ReadInt();
// First character
int firstcharacter = chunk->ReadInt();
int index = GetFontIndex(buffer);
if(!index && id) { // Font does not already exists and the texture is present
// New font
CKTextureFont* font = new CKTextureFont(this,m_Context,buffer);
font->m_FontZone = fz;
font->m_CharNumber = cn;
if (version == 1) {
if (spacing == 1) font->m_SpacingProperties = CKTextureFont::FIXED;
else font->m_SpacingProperties = 0;
} else { // version2
font->m_SpacingProperties = spacing;
if (spacing & CKTextureFont::SPACINGTOBESAVED) { // We have saved spacing data too
chunk->ReadAndFillBuffer_LEndian(256*sizeof(CharacterTextureCoordinates),(&font->m_FontCoordinates));
// the font is marked as created
font->m_SpacingProperties |= CKTextureFont::CREATED;
}
}
font->m_FontTexture = id;
font->m_FirstCharacter = firstcharacter;
// We add the font to the existing one
index = RegisterFont(font);
m_TextureLoaded = TRUE;
} else { // if version 2, we need to skip the spacing if they were saved
if ((version == 2) && (spacing & CKTextureFont::SPACINGTOBESAVED)) { // We have saved spacing data too
chunk->Skip(256*sizeof(CharacterTextureCoordinates)/4);
}
}
// Remapping [oldindex] = newindex
ConversionTable[h+1] = index;
//
}
///
// Remapping
LoadedFile->RemapManagerInt(FONT_MANAGER_GUID,ConversionTable,fn+1);
delete [] ConversionTable;
}
//chunk->CloseChunk();
return CK_OK;
}
CKERROR
CKFontManager::PostLoad()
{
if (m_TextureLoaded) {
// We now create the font that were only prepared by the loading
for (CKTextureFont** it = m_FontArray.Begin();it != m_FontArray.End();it++) {
CKTextureFont* font = *it;
font->CreateFromTexture();
}
m_TextureLoaded = FALSE;
}
return CK_OK;
}
CompiledTextData*
CKFontManager::AddCompiledText(CK_ID id)
{
CompiledTextData* ctdata = new CompiledTextData;
m_CompiledText.Insert(id,ctdata,TRUE);
return ctdata;
}
void
CKFontManager::RemoveCompiledText(CK_ID id)
{
CompiledTextData* ctdata;
if (m_CompiledText.LookUp(id,ctdata)) {
delete ctdata;
m_CompiledText.Remove(id);
}
}
CompiledTextData*
CKFontManager::GetCompiledText(CK_ID id)
{
CompiledTextData* ctdata = NULL;
m_CompiledText.LookUp(id,ctdata);
return ctdata;
}
void
CKFontManager::DrawRectangle(const RectangleData& rd)
{
m_Rectangles.PushBack(rd);
}
CKBOOL
MultipleRespectZOrder2DRenderCallback(CKRenderContext *dev,CKRenderObject* obj,void *Argument)
{
TextData* td = (TextData*)Argument;
CKContext* ctx = obj->GetCKContext();
CKFontManager* fm = (CKFontManager*)ctx->GetManagerByGuid(FONT_MANAGER_GUID);
// If the entity is hidden don't draw
if(parent2DHidden((CK2dEntity*)obj))
return FALSE;
// Restore entity parameters in texture font
CKTextureFont* font = fm->GetFont(td->m_FontIndex);
font->m_Scale = td->m_Scale;
font->m_Leading = td->m_Leading;
font->m_StartColor = td->m_StartColor;
font->m_EndColor = td->m_EndColor;
font->m_Margins = td->m_Margins;
font->m_Offset = td->m_Offset;
font->m_ParagraphIndentation= td->m_ParagraphIndentation;
font->m_CaretMaterial = td->m_CaretMaterial;
font->m_CaretSize = td->m_CaretSize;
font->m_ClippingRect = td->m_ClippingRect;
VxRect oldclip;
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->GetViewRect(oldclip);
VxRect clip = oldclip;
dev->GetWindowRect(clip);
clip.Translate(-clip.GetTopLeft());
dev->SetViewRect(clip);
}
// draw the text
font->DrawCKText(dev, obj, td->m_String,td->m_Align,td->m_Textzone,td->m_Mat,td->m_Textflags, TRUE);
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->SetViewRect(oldclip);
}
return TRUE;
}
int
MultipleRespectZOrder3DRenderCallback(CKRenderContext *dev,CKRenderObject* obj,void *Argument)
{
TextData* td = (TextData*)Argument;
CKContext* ctx = obj->GetCKContext();
CKFontManager* fm = (CKFontManager*)ctx->GetManagerByGuid(FONT_MANAGER_GUID);
CK3dEntity* ent = (CK3dEntity*)obj;
// If the entity is hidden don't draw
if(parent3DHidden(ent))
return FALSE;
// we calculate the scales of the frame
VxVector entscale;
ent->GetScale(&entscale,FALSE);
VxRect textzone(-entscale.x,-entscale.y,entscale.x,entscale.y);
if (CKIsChildClassOf(ent,CKCID_SPRITE3D)) { // the size must be take into account the bounding box of sprite3D
const VxBbox& bbox = ent->GetBoundingBox(TRUE);
textzone.left = bbox.Min.x*entscale.x;
textzone.right = bbox.Max.x*entscale.x;
textzone.top = bbox.Min.y*entscale.y;
textzone.bottom = bbox.Max.y*entscale.y;
}
///
// We set the transformation to the 3D Entity (slightly transformed (Y negative))
const VxMatrix& mat = ent->GetWorldMatrix();
VxMatrix resmat = mat;
resmat[0] = (mat[0]/entscale.x);
resmat[1] = -(mat[1]/entscale.y);
resmat[2] = -(mat[2]/entscale.z);
dev->SetWorldTransformationMatrix(resmat);
// Restore entity parameters in texture font
CKTextureFont* font = fm->GetFont(td->m_FontIndex);
font->m_Scale = td->m_Scale;
font->m_Leading = td->m_Leading;
font->m_StartColor = td->m_StartColor;
font->m_EndColor = td->m_EndColor;
font->m_Margins = td->m_Margins;
font->m_Offset = td->m_Offset;
font->m_ParagraphIndentation= td->m_ParagraphIndentation;
font->m_CaretMaterial = td->m_CaretMaterial;
font->m_CaretSize = td->m_CaretSize;
font->m_ClippingRect = td->m_ClippingRect;
VxRect oldclip;
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->GetViewRect(oldclip);
VxRect clip = oldclip;
dev->GetWindowRect(clip);
clip.Translate(-clip.GetTopLeft());
dev->SetViewRect(clip);
}
// draw the text
font->DrawCKText(dev, obj, td->m_String,td->m_Align,td->m_Textzone,td->m_Mat,td->m_Textflags, TRUE);
// we restore the transfo mat
dev->SetWorldTransformationMatrix(mat);
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->SetViewRect(oldclip);
}
return TRUE;
}
/*************************************************
Name: DrawText
Summary: Store text data in manager : used by the texts block with multiple
setting checked
Arguments: entity : ID of the targeted frame (2D/3D)
fontindex : index of the font to use
string : text to store
scale, endColor, align, textzone, mat, textflags : parameter associated with data : see 2D/3D Text blocks
Return Value: none
Remarks: the data are stored in m_Texts, a reference is added to m_2DTexts or m_3DTexts
they are used when we retrieve the data for an entity, so we don't scan all the data
in case we use 2D and 3D texts blocks
See also:
*************************************************/
void
CKFontManager::DrawText(CK_ID entity, int fontindex, CKSTRING string, Vx2DVector scale, CKDWORD startColor, CKDWORD endColor, int align, VxRect textzone, CKMaterial* mat, int textflags)
{
// No text : do nothing
if(!string)
return;
#ifdef PSP
textflags |= TEXT_RESPECTZORDER;
#endif
if (textflags & TEXT_RESPECTZORDER) {
TextData* td = NULL;
if(m_TextsRespectZorder.LookUp(entity, td)) {
// does not override existing text
// overwrite old values
td->m_FontIndex = fontindex;
CKStrdelete(td->m_String); // The string length can change, don't overwrite directly
td->m_String = CKStrdup(string);
td->m_Scale = scale;
td->m_StartColor = startColor;
td->m_EndColor = endColor;
td->m_Align = align;
td->m_Textzone = textzone;
td->m_Mat = mat;
td->m_Textflags = textflags;
} else {
// No TextData for this entity, create a new structure and add it to the list
td = new TextData(entity, fontindex, string, scale, startColor, endColor, align, textzone, mat, textflags);
m_TextsRespectZorder.Insert(entity, td, TRUE);
}
CKTextureFont* fn = GetFont(fontindex);
if (td && fn) {
td->m_Margins = fn->m_Margins;
td->m_Offset = fn->m_Offset;
td->m_ParagraphIndentation = fn->m_ParagraphIndentation;
td->m_CaretMaterial = fn->m_CaretMaterial;
td->m_CaretSize = fn->m_CaretSize;
td->m_ClippingRect = fn->m_ClippingRect;
td->m_Leading = fn->m_Leading;
}
CK2dEntity* ent = CK2dEntity::Cast(m_Context->GetObject(entity));
if (ent) {
ent->AddPostRenderCallBack(MultipleRespectZOrder2DRenderCallback, td, TRUE);
} else { // for 3D Objects
CK3dEntity* ent3D = CK3dEntity::Cast(m_Context->GetObject(entity));
if (ent3D)
ent3D->AddPostRenderCallBack(MultipleRespectZOrder3DRenderCallback, td, TRUE);
}
return;
}
// If we already have a TextData struct for this entity, re-use it
TextData* td = NULL;
if(m_Texts.LookUp(entity, td)) {
// we don't use COMPILED setting
if(!(textflags&TEXT_COMPILED)) {
// overwrite old values
td->m_FontIndex = fontindex;
CKStrdelete(td->m_String); // The string length can change, don't overwrite directly
td->m_String = CKStrdup(string);
td->m_Scale = scale;
td->m_StartColor = startColor;
td->m_EndColor = endColor;
td->m_Align = align;
td->m_Textzone = textzone;
td->m_Mat = mat;
td->m_Textflags = textflags;
}
// for now, if COMPILED setting is used, we don't change the text data content
// changes goes here
} else {
// No TextData for this entity, create a new structure and add it to the list
td = new TextData(entity, fontindex, string, scale, startColor, endColor, align, textzone, mat, textflags);
m_Texts.Insert(entity, td, TRUE);
}
CKTextureFont* fn = GetFont(fontindex);
if (td && fn) {
td->m_Margins = fn->m_Margins;
td->m_Offset = fn->m_Offset;
td->m_ParagraphIndentation = fn->m_ParagraphIndentation;
td->m_CaretMaterial = fn->m_CaretMaterial;
td->m_CaretSize = fn->m_CaretSize;
td->m_ClippingRect = fn->m_ClippingRect;
}
// Store the reference in the good table, theses array are cleared when render are done
// so we can add the data without check
if(textflags & TEXT_3D)
m_3DTexts.PushBack(td);
else
m_2DTexts.PushBack(td);
}
void
CKFontManager::DrawText(CKRenderContext* iRC, int iFontIndex, const char* iText, const Vx2DVector& iPosition, const Vx2DVector& iScale, CKDWORD iStartColor, CKDWORD iEndColor)
{
CKTextureFont* font = NULL;
if (iFontIndex) {
CKTextureFont* font = GetFont(iFontIndex);
} else {
font = m_DebugFont;
}
if (!font) return;
font->m_Scale = iScale;
font->m_StartColor = iStartColor;
font->m_EndColor = iEndColor;
font->m_Leading.x = -3.0f;
font->m_Properties |= FONT_DISABLEFILTER;
// draw the text
font->DrawStringEx(iRC, iText, VxRect(iPosition.x,iPosition.y,(float)iRC->GetWidth(),(float)iRC->GetHeight()),0);
}
void
CKFontManager::DrawRectanglesCallback(CKRenderContext* dev)
{
if (!m_Rectangles.Size()) return;
VxRect oldclip;
dev->GetViewRect(oldclip);
VxRect clip;dev->GetWindowRect(clip);clip.Translate(-clip.GetTopLeft());
dev->SetViewRect(clip);
// We draw all the rectangles
for (int i=0;i<m_Rectangles.Size();++i) {
float size = m_Rectangles[i].m_BorderSize;
if (size == 0.0f) { // No Border
DrawFillRectangle(dev,m_Rectangles[i].m_InColor,m_Rectangles[i].m_Material,m_Rectangles[i].m_Screen,m_Rectangles[i].m_InUVs);
} else {
if (size < 0.0f) { // Border
DrawBorderRectangle(dev,m_Rectangles[i].m_BorderColor,m_Rectangles[i].m_Material,m_Rectangles[i].m_Screen,-size);
} else { // Interior + Border
VxRect rect = m_Rectangles[i].m_Screen;
rect.Inflate(Vx2DVector(-size,-size));
DrawFillRectangle(dev,m_Rectangles[i].m_InColor,m_Rectangles[i].m_Material,rect,m_Rectangles[i].m_InUVs);
DrawBorderRectangle(dev,m_Rectangles[i].m_BorderColor,m_Rectangles[i].m_Material,m_Rectangles[i].m_Screen,size);
}
}
}
dev->SetViewRect(oldclip);
}
/*************************************************
Name: DrawTextCallback
Summary: Retrieve the text data stored by text blocks with
multiple setting checked and send it to render functions
Arguments: dev : current render context
arg : a pointer to the CKFontManager
Return Value: none
Remarks: arg must not be NULL and point to the good manager !
See also:
*************************************************/
void
CKFontManager::DrawTextCallback2D(CKRenderContext* dev, void* arg)
{
CKFontManager* fm = (CKFontManager*)arg;
CK2dEntity *ent1, *ent2;
CKBeObject *obj;
struct TextData* td;
int i,limit = fm->m_2DTexts.Size();
// Sort by z-order, bubble sort
for( i=0 ; i < limit-1 ; i++) {
for(int j=i+1 ; j < limit ; j++) {
ent1 = (CK2dEntity*)fm->m_Context->GetObject(fm->m_2DTexts[i]->m_Entity);
if(ent1) {
ent2 = (CK2dEntity*)fm->m_Context->GetObject(fm->m_2DTexts[j]->m_Entity);
if(ent2) {
// Swap data if not in the good order
if(ent1->GetZOrder() < ent2->GetZOrder()) {
memcpy(&td, &(fm->m_2DTexts[i]), sizeof(struct TextData*));
memcpy(&(fm->m_2DTexts[i]), &(fm->m_2DTexts[j]), sizeof(struct TextData*));
memcpy(&(fm->m_2DTexts[j]), &td, sizeof(struct TextData*));
}
}
}
}
}
// Draw pending 2D texts
for(i = 0 ; i < limit ; i++) {
TextData* td = fm->m_2DTexts[i];
obj = (CKBeObject*)fm->m_Context->GetObject(td->m_Entity);
if(obj) {
// If the entity is hidden don't draw
if(parent2DHidden((CK2dEntity*)obj))
continue;
// Restore entity parameters in texture font
CKTextureFont* font = fm->GetFont(td->m_FontIndex);
font->m_Scale = td->m_Scale;
font->m_StartColor = td->m_StartColor;
font->m_EndColor = td->m_EndColor;
font->m_Margins = td->m_Margins;
font->m_Offset = td->m_Offset;
font->m_ParagraphIndentation= td->m_ParagraphIndentation;
font->m_CaretMaterial = td->m_CaretMaterial;
font->m_CaretSize = td->m_CaretSize;
font->m_ClippingRect = td->m_ClippingRect;
VxRect oldclip;
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->GetViewRect(oldclip);
VxRect clip = oldclip;
dev->GetWindowRect(clip);
clip.Translate(-clip.GetTopLeft());
dev->SetViewRect(clip);
}
// draw the text
font->DrawCKText(dev, obj, td->m_String,td->m_Align,td->m_Textzone,td->m_Mat,td->m_Textflags, TRUE);
if (!(td->m_Textflags & TEXT_SCREENCLIP)) {
dev->SetViewRect(oldclip);
}
}
}
}
void
CKFontManager::DrawTextCallback3D(CKRenderContext* dev, void* arg)
{
CKFontManager* fm = (CKFontManager*)arg;
CKBeObject *obj;
struct TextData* td;
CK3dEntity* ent3, *ent4;
VxVector viewpos;
CK3dEntity* viewpt = dev->GetViewpoint();
viewpt->GetPosition(&viewpos);
int limit = fm->m_3DTexts.Size();
int i;
// Sort by z-order
for (i=0 ; i < limit-1 ; i++) {
for(int j=i+1 ; j < limit ; j++) {
ent3 = (CK3dEntity*)fm->m_Context->GetObject(fm->m_3DTexts[i]->m_Entity);
if(ent3) {
ent4 = (CK3dEntity*)fm->m_Context->GetObject(fm->m_3DTexts[j]->m_Entity);
if(ent4) {
// Retrieve position
VxVector v1, v2, pos1, pos2;
ent3->GetPosition(&pos1); viewpt->InverseTransform(&v1, &pos1);
ent4->GetPosition(&pos2); viewpt->InverseTransform(&v2, &pos2);
// Swap values if not in the good order
if(v1.z < v2.z) {
memcpy(&td, &(fm->m_3DTexts[i]), sizeof(struct TextData*));
memcpy(&(fm->m_3DTexts[i]), &(fm->m_3DTexts[j]), sizeof(struct TextData*));
memcpy(&(fm->m_3DTexts[j]), &td, sizeof(struct TextData*));
}
}
}
}
}
// Draw pending 3D texts
for (i = 0 ; i < limit ; i++) {
TextData* td = fm->m_3DTexts[i];
obj = (CKBeObject*)fm->m_Context->GetObject(td->m_Entity);
if(obj) {
ent3 = (CK3dEntity*)obj;
if (!ent3->IsAllOutsideFrustrum()) {
// If the entity is hidden don't draw the text
if(parent3DHidden(ent3))
continue;
///
// We set the transformation to the 3D Entity (slightly transformed)
const VxMatrix& mat = ent3->GetWorldMatrix();
// we inverse the Y of the matrix, so the text is written in a good way
VxVector entscale;
ent3->GetScale(&entscale,FALSE);
VxMatrix resmat = mat;
resmat[0] = (mat[0]/entscale.x);
resmat[1] = -(mat[1]/entscale.y);
resmat[2] = -(mat[2]/entscale.z);
dev->SetWorldTransformationMatrix(resmat);
// Restore the entity parameter in the font texture
CKTextureFont* font = fm->GetFont(td->m_FontIndex);
font->m_Scale = td->m_Scale;
font->m_StartColor = td->m_StartColor;
font->m_EndColor = td->m_EndColor;
font->m_Margins = td->m_Margins;
font->m_Offset = td->m_Offset;
font->m_ParagraphIndentation= td->m_ParagraphIndentation;
font->m_CaretMaterial = td->m_CaretMaterial;
font->m_CaretSize = td->m_CaretSize;
font->m_ClippingRect = td->m_ClippingRect;
// Draw the text
font->DrawCKText(dev,obj,td->m_String,td->m_Align,td->m_Textzone,td->m_Mat,td->m_Textflags, TRUE);
// Set the bounding box for clipping
VxBbox bbox;
bbox.Min.Set(font->m_TextExtents.left, -font->m_TextExtents.bottom,-0.01f);
bbox.Max.Set(font->m_TextExtents.right,-font->m_TextExtents.top,0.01f);
//ent3->SetBoundingBox(&bbox,TRUE);
}
}
}
}
/***********************************************************************/
/***********************************************************************/
// System font functions
/***********************************************************************/
/***********************************************************************/
/*************************************************
Name: DeleteFont
Summary: Delete a specific system font from the manager
Arguments: the font name
Return Value:
Remarks: Release the GDI handle associated with this font
Delete unused fonts free up system ressources
See also:
*************************************************/
void CKFontManager::DeleteFontHandle(CKSTRING fontName)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifndef USEQUICKDRAWTEXT
// We localize the font
FontIterator it = m_fonts.Find(XString(fontName));
// And we release the handle
if(it != m_fonts.End()) {
::DeleteObject(*it);
// Remove entry
m_fonts.Remove(it);
}
#else
// No need to dispose font handles on mac
#endif
#endif
}
/*************************************************
Name: CreateFont
Summary: Create a new logical font having its name and properties
Arguments: fontName - the name used to retrieve the font in the manager
sysFontIndex - a system font index from enumeration (CKPGUID_FONTNAME)
weight - the weight of the font (a value between 100 and 900 (step by 100)) use the enumeration
'Font Weight' CKPGUID_FONTWEIGHT
italic - TRUE if we want an italic font
underline - TRUE if we want an underlined font
resolution - determine the size of the font (CKPGUID_FONTRESOLUTION enumeration)
use 1 --> 128x128 texture
2 --> 256x256
4 --> 512x512
5 --> 1024x1024
other value --> 512x512
Return Value: TRUE if success
Remarks:
See also:
*************************************************/
CKBOOL CKFontManager::CreateFont(CKSTRING fontName, int sysFontIndex, int weight, CKBOOL italic, CKBOOL underline, int resolution, int iFontSize)
{
#ifndef FONTMANAGER_NOSYSFONT
// No font name : do nothing
if(!fontName)
return FALSE;
CKParameterManager* pm = m_Context->GetParameterManager();
if(!pm) return FALSE;
CKEnumStruct* data = pm->GetEnumDescByType(pm->ParameterGuidToType(CKPGUID_FONTNAME));
if((sysFontIndex < 0) || (sysFontIndex > data->NbData))
return FALSE;
// We check if the fontName is present
FontIterator it = m_fonts.Find(XString(fontName));
if(it == m_fonts.End()) { // We create it
// We select the font size according to the desired texture resolution
int fontSize = FONTSIZE512;
if (!iFontSize) {
switch(resolution) {
case 1: // 128x128
fontSize = FONTSIZE128;
break;
case 2: // 256x256
fontSize = FONTSIZE256;
break;
case 4: // 512x512
fontSize = FONTSIZE512;
break;
case 8: // 1024x1024
fontSize = FONTSIZE1024;
break;
}
} else
{
fontSize = iFontSize;
}
// We create the logical font and retrieves a font handle
FONTHANDLE fontHandle = (FONTHANDLE)VxCreateFont(data->Desc[sysFontIndex], fontSize, weight, italic, underline);
// If the font can't be created
if(fontHandle == NULL) return FALSE;
// We add the new font to the list
m_fonts.Insert(XString(fontName), fontHandle);
}
return TRUE;
#else
return FALSE;
#endif
}
/*************************************************
Name: GetOutlineFontMetric
Summary: Retrieve the outline font metric for the currently selected
Arguments: The name of the font in the manager and a FONT_OUTLINEMETRIC struct
or a FONT_METRIC struct to fill
Return Value: TRUE if success
Remarks: See the Win32 documentation for the content of OUTLINETEXTMETRIC or TEXTMETRIC
structs
See also:
*************************************************/
CKBOOL CKFontManager::GetOutlineFontMetric(FONT_OUTLINEMETRIC& metric)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
SETOFFSCREENPORT()
return FALSE;
#else
return ::GetOutlineTextMetrics(m_DC, sizeof(FONT_OUTLINEMETRIC), &metric);
#endif
#else
return FALSE;
#endif
}
CKBOOL CKFontManager::GetFontMetrics(FONT_METRIC& metric)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
SETOFFSCREENPORT()
FMetricRec MetricPtr;
FontMetrics(&MetricPtr);
metric.tmAscent = MetricPtr.ascent;
metric.tmDescent = MetricPtr.descent;
metric.tmHeight = 0;
metric.tmMaxCharWidth = MetricPtr.widMax;
metric.tmWeight = 0;
metric.tmAveCharWidth = 0;
return TRUE;
#else
return ::GetTextMetrics(m_DC, &metric);
#endif
#else
return FALSE;
#endif
}
/*************************************************
Name: IsTrueTypeFont
Summary: test if the currently selected fotn is a true type font
Arguments: none
Return Value: TRUE if it's a true type
Remarks:
See also:
*************************************************/
CKBOOL CKFontManager::IsTrueTypeFont(void)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
#pragma todo("Is true Type font always returns TRUE for the moment")
return TRUE;
#else
TEXTMETRIC metric;
if(::GetTextMetrics(m_DC, &metric))
return (metric.tmPitchAndFamily & TMPF_TRUETYPE);
#endif
return FALSE;
#else
return FALSE;
#endif
}
/*************************************************
Name: SelectFont
Summary: Select the current font
Arguments: fontName - the font name in the manager
Return Value: TRUE if success
Remarks: must be call before use of get*fontmetrics, getchar*width
See also:
*************************************************/
CKBOOL CKFontManager::SelectFont(CKSTRING fontName)
{
#ifndef FONTMANAGER_NOSYSFONT
// if no font name is given then we are simply trying to restore the
// DC current font on PC
if (!fontName) {
#ifndef USEQUICKDRAWTEXT
::SelectObject(m_DC, m_BackupFont);
m_BackupFont = NULL;
#endif
return TRUE;
}
// We try to localize the font
FontIterator it = m_fonts.Find(XString(fontName));
if(it == m_fonts.End()) return FALSE;
#ifdef USEQUICKDRAWTEXT
m_CurrentFont = *it;
return TRUE;
#else
// If it is present, we select it in the DC and retrieves the information
m_BackupFont = (HFONT)::SelectObject(m_DC, *it);
return (m_BackupFont != NULL);
#endif
#else
return FALSE;
#endif
}
/*************************************************
Name: GetCharABCWidth
Summary: Retrieves the width of a range of char for the current selected font
Arguments: startChar/endChar - define the character range to use (inclusive range)
ABCWidth - an array of FONT_ABC structs to store the results
Return Value: TRUE if success
Remarks: the FONT_ABC array must be large enough to store the result
See also:
*************************************************/
CKBOOL CKFontManager::GetCharABCWidths(CKBYTE startChar, CKBYTE endChar, FONT_ABC* ABCwidths)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
XArray<Fixed> AdvanceWidths;
XArray<Fixed> LeftSideBearing;
XArray<Rect> Bounds;
XArray<CKBYTE> String;
int i,Count = (int)endChar-(int)startChar;
String.Resize(Count+1);
AdvanceWidths.Resize(Count);
LeftSideBearing.Resize(Count);
Bounds.Resize(Count);
for (i=0; i < Count; ++i)
{
String[i] = CKFontManager::PCToPlatformCharacter(startChar+i);
}
String[i] = 0;
Point same;
same.h = 1;
same.v = 1;
SETOFFSCREENPORT()
VxMacFont* vxmf = (VxMacFont*) m_CurrentFont;
if(vxmf)
{
vxmf->SetAsCurrent();
}
OSErr error= OutlineMetrics(Count,String.Begin(),same,same,NULL,NULL,AdvanceWidths.Begin(),LeftSideBearing.Begin(),Bounds.Begin());
if(error == noErr){
/*
struct FONT_ABC {
int abcA; // Left Side Bearing
UInt32 abcB; // Glyph Width
int abcC; // Advance Width
};
*/
for (i=0; i < Count; ++i){
ABCwidths[i].abcA = Fix2Long(LeftSideBearing[i]);
// GG 3/26 : Added 1 to the width
ABCwidths[i].abcB = Bounds[i].right + 1;
ABCwidths[i].abcC = Fix2Long(AdvanceWidths[i]) - ABCwidths[i].abcA - ABCwidths[i].abcB;
}
}
return (error == noErr);
#else
return ::GetCharABCWidths(m_DC, startChar, endChar, ABCwidths);
#endif
#else
return FALSE;
#endif
}
/*************************************************
Name: GetCharWidth
Summary: Retrieves the width of a range of char for non true-type font currently selected
Arguments: startChar/endChar - define the character range to use (inclusive range)
Widths - an array of int to store the results
Return Value: TRUE if success
Remarks: the widths array must be large enough to store the result
See also:
*************************************************/
CKBOOL CKFontManager::GetCharWidths(CKBYTE startChar, CKBYTE endChar, int* widths)
{
#ifndef FONTMANAGER_NOSYSFONT
#ifdef USEQUICKDRAWTEXT
#pragma todo("CKFontManager::GetCharWidths")
return FALSE;
#else
VX_OSINFO osinfo;
osinfo = VxGetOs();
if (osinfo == VXOS_WIN98
|| osinfo == VXOS_WIN95
|| osinfo == VXOS_WINME) {
return ::GetCharWidth(m_DC, startChar, endChar, widths);
}
else {
return ::GetCharWidth32(m_DC, startChar, endChar, widths);
}
#endif
#else
return FALSE;
#endif
}
/*************************************************
Name: CreateTextureFromFont
Summary: Create a CKTexture representing the characters of the designed font
Arguments: sysFontIndex - the index of the font in enumeration CKPGUID_FONTNAME
resolution - the size of the texture (CKPGUID_FONTRESOLUTION enumeration)
use 1 --> 128x128 texture
2 --> 256x256
4 --> 512x512
8 --> 1024x1024
other value --> 512x512
extended - if false, we create a half height texture with only the first 128 ASCII chars
else, we have a full size texture with all the chars
renderControls - if false, we don't draw the chars with ASCII code < 32
(i.e. control characters are all blank)
dynamic - if true, the texture created is a dynamical object
Return Value: the texture if sucess NULL otherwise
Remarks:
See also:
*************************************************/
CKTexture* CKFontManager::CreateTextureFromFont(int sysFontIndex, int resolution, CKBOOL extended, int bold, CKBOOL italic, CKBOOL underline, CKBOOL renderControls, CKBOOL dynamic,int iForcedSize)
{
#ifndef FONTMANAGER_NOSYSFONT
CKParameterManager* pm = m_Context->GetParameterManager();
if(!pm) return NULL;
CKEnumStruct* data = pm->GetEnumDescByType(pm->ParameterGuidToType(CKPGUID_FONTNAME));
if((sysFontIndex < 0) || (sysFontIndex > data->NbData))
return FALSE;
// Get the font name by index
CKSTRING fontName = data->Desc[sysFontIndex];
// we compose the texture name
XString textureName("FONT_");
textureName << fontName;
switch(resolution) {
case 1:
textureName << "_128x128";
break;
case 2:
textureName << "_256x256";
break;
case 4:
textureName << "_512x512";
break;
case 8:
textureName << "_1024x1024";
break;
}
if (iForcedSize) {
textureName << "(" << iForcedSize << ")";
}
if(extended) textureName << "_E";
if(renderControls) textureName << "_C";
textureName << "_";
switch(bold) {
case 100:
textureName << "THIN";
break;
case 200:
textureName << "XLIGHT";
break;
case 300:
textureName << "LIGHT";
break;
case 400:
textureName << "NORMAL";
break;
case 500:
textureName << "MEDIUM";
break;
case 600:
textureName << "DBOLD";
break;
case 700:
textureName << "BOLD";
break;
case 800:
textureName << "XBOLD";
break;
case 900:
textureName << "HEAVY";
break;
}
if(italic) textureName << "_I";
if(underline) textureName << "_U";
CKTexture* texture = (CKTexture*)m_Context->GetObjectByNameAndClass(textureName.Str(), CKCID_TEXTURE);
if(!texture) {
// We try to localize the font
FontIterator it = m_fonts.Find(textureName);
if(it == m_fonts.End()) {
if(!CreateFont(textureName.Str(), sysFontIndex, bold, italic, underline, resolution,iForcedSize))
return NULL;
// exists this time because we just create it !
it = m_fonts.Find(textureName);
}
// CKTexture object creation
if(dynamic)
texture = (CKTexture*)m_Context->CreateObject(CKCID_TEXTURE, textureName.Str(), CK_OBJECTCREATION_DYNAMIC);
else
texture = (CKTexture*)m_Context->CreateObject(CKCID_TEXTURE, textureName.Str());
// If we couldn't create it
if(!texture) return NULL;
int nbLine = 8, nbCol = 16;
int texHeight = 64, texWidth = 128;
// If we draw all 256 chars
if(extended) {
nbLine = 16;
texHeight *= 2;
}
// Texture size from desired resolution
texWidth *= resolution;
texHeight *= resolution;
int nbPixels = texHeight*texWidth, charCellSize = texWidth/nbCol;
// We create the surface
texture->Create(texWidth, texHeight, 32);
// We get the texture description
VxImageDescEx vxTexDesc;
texture->GetSystemTextureDesc(vxTexDesc);
vxTexDesc.Image=texture->LockSurfacePtr();
if (vxTexDesc.Image)
{
// We clear the texture surface (white for the color and black for the alpha)
CKDWORD colorDef = RGBAITOCOLOR(0xff,0xff,0xff,0x00);
#if defined(macintosh) && defined(__ppc__)
BYTE* AlphaDest=(BYTE*)vxTexDesc.Image;
#else
BYTE* AlphaDest=(BYTE*)vxTexDesc.Image+3;
#endif
VxFillStructure(nbPixels,(BYTE*)vxTexDesc.Image,4,4,&colorDef);
#ifndef USEQUICKDRAWTEXT
// We create a system memory bitmap for font rendering
BITMAP_HANDLE hBitmap = VxCreateBitmap(vxTexDesc);
// If it exists we get the handle
HFONT hFont = *it;
// We select the GDI objects
HFONT oldFont = (HFONT)::SelectObject(m_DC, hFont);
HBITMAP oldBitmap = (HBITMAP)::SelectObject(m_DC, (HBITMAP)hBitmap);
// Set colors
RECT r;SetRect(&r,0,0,texWidth,texHeight);
::FillRect(m_DC,&r,(HBRUSH)::GetStockObject(BLACK_BRUSH));
::SetTextColor(m_DC, RGBAITOCOLOR(255, 255, 255, 0));
::SetBkColor(m_DC, RGBAITOCOLOR(0, 0, 0, 0));
// Rendering rectangle
RECT rect; rect.top = 0; rect.left = 0; rect.bottom = charCellSize; rect.right = charCellSize;
// For each character, we draw it in the bitmap at the good position
int i, j; char c;
// Render a grid
HPEN hp = ::CreatePen(PS_SOLID,1,RGB(255,255,255));
HPEN bp = ::CreatePen(PS_SOLID,1,RGB(0,0,0));
HPEN op = (HPEN) ::SelectObject(m_DC,hp);
// Draw a grid
/*
#pragma todo("ro remove !!!")
for(i = 0; i < nbLine ; i++) {
::MoveToEx(m_DC,i*charCellSize,0,NULL);
::LineTo(m_DC,i*charCellSize,texHeight);
::MoveToEx(m_DC,0,i*charCellSize,NULL);
::LineTo(m_DC,texWidth,i*charCellSize);
}
::SelectObject(m_DC,op);
*/
for(i = 0; i < nbLine ; i++) {
for(j = 0; j < nbCol ; j++) {
c = i*nbCol+j;
if(renderControls)
::DrawText(m_DC, &c, 1, &rect, DT_LEFT | DT_TOP | DT_NOPREFIX);
else
if((unsigned char)c >= 32)
::DrawText(m_DC, &c, 1, &rect, DT_LEFT | DT_TOP | DT_NOPREFIX);
rect.left += charCellSize;
rect.right += charCellSize;
}
rect.left = 0;
rect.right = charCellSize;
rect.top += charCellSize;
rect.bottom += charCellSize;
}
for(i = 0; i < nbLine ; i++) {
//(HPEN) ::SelectObject(m_DC,bp);
//::MoveToEx(m_DC,i*charCellSize,0,NULL);
//::LineTo(m_DC,i*charCellSize,texHeight);
(HPEN) ::SelectObject(m_DC,bp);
::MoveToEx(m_DC,i*charCellSize-1,0,NULL);
::LineTo(m_DC,i*charCellSize-1,texHeight);
//(HPEN) ::SelectObject(m_DC,bp);
//::MoveToEx(m_DC,0,i*charCellSize,NULL);
//::LineTo(m_DC,texWidth,i*charCellSize);
(HPEN) ::SelectObject(m_DC,bp);
::MoveToEx(m_DC,0,i*charCellSize-1,NULL);
::LineTo(m_DC,texWidth,i*charCellSize-1);
}
// For each pixel of the bitmap, we reduce to a grayscale color
// and fill an alpha table
BITMAP dib;
GetObject(hBitmap,sizeof(BITMAP),&dib);
DWORD Bpp = dib.bmBitsPixel>>3;
DWORD Pitch = dib.bmWidthBytes;
BYTE* Colors=(BYTE*)dib.bmBits+(dib.bmHeight-1)*dib.bmWidthBytes;
#else
Rect ImageRect;
ImageRect.left = 0;
ImageRect.right = 0;
ImageRect.bottom = 0;
ImageRect.top = 0;
GetPortBounds((CGrafPtr)m_GDC,&ImageRect);
if(ImageRect.right!= texWidth || ImageRect.bottom != texHeight)
{
ImageRect.right = texWidth;
ImageRect.bottom = texHeight;
DisposeGWorld(m_GDC);
NewGWorld(&m_GDC,32,&ImageRect,NULL,NULL,0);
}
SETOFFSCREENPORT()
Rect portRect;
portRect.left = 0;
portRect.top = 0;
portRect.bottom = 512;
portRect.right = 512;
RGBColor theBlackColor = { 0, 0, 0 };
RGBColor theWhiteColor = { 65535, 65535, 65535 };
RGBBackColor(&theBlackColor);
RGBForeColor(&theWhiteColor);
EraseRect(&portRect);
// TODO : Text Face
//TextFace();
VxMacFont* vxmf = (VxMacFont*) *it;
if(vxmf)
{
vxmf->SetAsCurrent();
}
FontInfo info;
GetFontInfo(&info);
// Rendering rectangle
Rect rect; rect.top = 0; rect.left = 0; rect.bottom = charCellSize; rect.right = charCellSize;
int i, j; char c;
SInt16 sz;
BOOL aa = IsAntiAliasedTextEnabled(&sz);
if(!aa){
SetAntiAliasedTextEnabled(true,sz);
}
// Render a grid
/*
for(i = 0; i < nbLine ; i++) {
MoveTo(i*charCellSize,0);
LineTo(i*charCellSize,texHeight);
MoveTo(0,i*charCellSize);
LineTo(texWidth,i*charCellSize);
}
*/
// For each character, we draw it in the bitmap at the good position
for(i = 0; i < nbLine ; i++) {
for(j = 0; j < nbCol ; j++) {
c = i*nbCol+j;
//MoveTo(rect.left+info.leading,rect.top+info.ascent);
// GG 3/26 : Added 1 to the position
MoveTo(rect.left + 1,rect.top+info.ascent);
if(renderControls || (unsigned char)c >= 32)
{
const unsigned char platformCode = CKFontManager::PCToPlatformCharacter(c);
DrawChar(platformCode);
}
rect.left += charCellSize;
rect.right += charCellSize;
}
rect.left = 0;
rect.right = charCellSize;
rect.top += charCellSize;
rect.bottom += charCellSize;
}
if(!aa)
SetAntiAliasedTextEnabled(false,sz);
// Get The PixMap
PixMapHandle px = GetGWorldPixMap(m_GDC);
DWORD Pitch = 0;
DWORD Bpp = 0;
BYTE* Colors= NULL;
if (px) {
Pitch = QTGetPixMapHandleRowBytes(px);
OSType pixelFormat = GETPIXMAPPIXELFORMAT(*px);
Bpp = QTGetPixelSize(pixelFormat) >> 3;
Colors=(BYTE*)GetPixBaseAddr(px);
Pitch = -Pitch;
}
#endif
DWORD RGBIntensity[3][256];
for (i=0;i<256;++i) {
RGBIntensity[0][i]=(unsigned long)(0.299f*(float)i);
RGBIntensity[1][i]=(unsigned long)(0.587f*(float)i);
RGBIntensity[2][i]=(unsigned long)(0.114f*(float)i);
}
if (!Colors) {
for(i = 0 ; i < texHeight ; i++)
for(j= 0 ; j < texWidth ; j++,AlphaDest+=4) {
#ifdef USEQUICKDRAWTEXT
RGBColor col;
GetCPixel(j,i,&col);
*AlphaDest = 0xFF &
(unsigned char)(RGBIntensity[0][col.red>>8]
+ RGBIntensity[1][col.green>>8]
+ RGBIntensity[2][col.blue>>8]);
#else
COLORREF currentColor = ::GetPixel(m_DC, j, i);
*AlphaDest = 0xFF &
(unsigned char)(RGBIntensity[0][GetRValue(currentColor)]
+ RGBIntensity[1][GetGValue(currentColor)]
+ RGBIntensity[2][GetBValue(currentColor)]);
//ENDIANSWAP32(*AlphaDest);
#endif
}
} else {
for(i = 0 ; i < texHeight ; i++,Colors-=Pitch) {
BYTE* col=Colors;
for(j= 0 ; j < texWidth ; j++,AlphaDest+=4,col+=Bpp) {
#if defined(macintosh)
*AlphaDest = 0xff & (unsigned char)(RGBIntensity[2][col[1]]+ RGBIntensity[1][col[2]]+ RGBIntensity[0][col[3]]);
#else
*AlphaDest = 0xff & (unsigned char)(RGBIntensity[2][col[0]]+ RGBIntensity[1][col[1]]+ RGBIntensity[0][col[2]]);
#endif
}
}
}
#ifndef USEQUICKDRAWTEXT
// We deselect and delete the GDI objects
::SelectObject(m_DC, oldBitmap);
::SelectObject(m_DC, oldFont);
::SelectObject(m_DC, op);
::DeleteObject(bp);
::DeleteObject(hp);
VxDeleteBitmap(hBitmap);
#endif
texture->ReleaseSurfacePtr();
}
// Some texture settings
texture->SetDesiredVideoFormat(_32_ARGB8888);
texture->UseMipmap(-1);
// Wie add the new texture to the current level
m_Context->GetCurrentLevel()->AddObject(texture);
}
/*
{
CGrafPtr m_op; // Former Graf Port
GDHandle m_od; // Former Device Handle
GetGWorld (&m_op, &m_od);
Rect srcImageRect;
srcImageRect.left = 0;
srcImageRect.right = 512;
srcImageRect.bottom = 512;
srcImageRect.top = 0;
Rect dstImageRect;
dstImageRect.left = 100;
dstImageRect.right = 612;
dstImageRect.bottom = 612;
dstImageRect.top = 100;
CopyBits(GetPortBitMapForCopyBits(m_GDC),
GetPortBitMapForCopyBits(m_op),
&srcImageRect,
&dstImageRect,
srcCopy,
NULL);
}
*/
return texture;
#else
return NULL;
#endif
}
/*************************************************
Name: FontEnumeratorCallBack
Summary: Add a new font name to the array font name list
Arguments: font info and the array to fill (in the param field)
Return Value: TRUE in any way
Remarks: Called automatically by the system
See also: RegenerateFontEnumeration
*************************************************/
#ifndef FONTMANAGER_NOSYSFONT
#ifndef USEQUICKDRAWTEXT
BOOL CALLBACK FontEnumeratorCallBack(LPLOGFONT lplf, LPNEWTEXTMETRIC lpntm, DWORD FontType, LPVOID param)
{
// Retrieves the parameters
XClassArray<XString>* array = (XClassArray<XString>*)param;
array->PushBack(XString(lplf->lfFaceName));
return TRUE;
}
#endif
#endif
/*************************************************
Name: RegenerateFontEnumeration
Summary: Fill an enumeration CKPGUID_FONTNAME with the list of system font names found
Arguments: -
Return Value: FALSE if fails, in this case the enum is set to empty
See also: -
*************************************************/
CKBOOL CKFontManager::RegenerateFontEnumeration(void)
{
#ifndef FONTMANAGER_NOSYSFONT
CKParameterManager* pm = m_Context->GetParameterManager();
if(!pm) return FALSE;
XClassArray<XString> array;
array.Reserve(64);
#ifdef USEQUICKDRAWTEXT
FMFontIterator myFontIterator;
OSStatus status = 0;
FMFont myFont;
// The first parameter is NULL because we are not filtering font
// information. The second parameter is NULL because we are not using
// a custom filter function. The default options constants specifies
// to apply the iterator only to those fonts accessible to your
// application. Pass an unitialized font iterator.
status = FMCreateFontIterator (NULL, NULL, kFMDefaultOptions,
&myFontIterator);
while (status == noErr)
{
status = FMGetNextFont (&myFontIterator, &myFont);
FMFontFamily Family;
FMFontStyle Style;
Str255 FontName;
FMGetFontFamilyInstanceFromFont(myFont,&Family,&Style);
if (noErr == FMGetFontFamilyName(Family,FontName)) {
array.PushBack(XStringFromPStr(FontName));
}
}
// Dispose of the contents of the font iterator.
status = FMDisposeFontIterator (&myFontIterator);
#else
// Fill the array (automatic call to FontEnumeratorCallback for each font found)
if(!EnumFontFamilies(m_DC, (LPCTSTR) NULL, (FONTENUMPROC)FontEnumeratorCallBack, (LPARAM) &array)) {
pm->ChangeEnumDeclaration(CKPGUID_FONTNAME, "");
return FALSE;
}
#endif
// Presents font in lexical order
array.Sort();
// Generate the new enum
XString newEnum;
char buffer[64];
int i = 0;
for(XString* it = array.Begin() ; it != array.End() ; it++) {
if(i++ != 0) newEnum << ",";
newEnum << (*it);
sprintf(buffer, "=%d", i-1);
newEnum << buffer;
}
pm->ChangeEnumDeclaration(CKPGUID_FONTNAME, newEnum.Str());
return TRUE;
#else
return FALSE;
#endif
}
#ifdef USEQUICKDRAWTEXT
void PStrFromXString(const XString& SrcX, Str255 dst)
{
char* src = (char*) SrcX.CStr();
short length = 0;
// handle case of overlapping strings
if ( (void*)src == (void*)dst )
{
unsigned char* curdst = &dst[1];
unsigned char thisChar;
thisChar = *(const unsigned char*)src++;
while ( thisChar != '\0' )
{
unsigned char nextChar;
// use nextChar so we don't overwrite what we are about to read
nextChar = *(const unsigned char*)src++;
*curdst++ = thisChar;
thisChar = nextChar;
if ( ++length >= 255 )
break;
}
}
else if ( src != NULL )
{
unsigned char* curdst = &dst[1];
short overflow = 255; // count down so test it loop is faster
register char temp;
// Can't do the K&R C thing of <20>while (*s++ = *t++)<29> because it will copy trailing zero
// which might overrun pascal buffer. Instead we use a temp variable.
while ( (temp = *src++) != 0 )
{
*(char*)curdst++ = temp;
if ( --overflow <= 0 )
break;
}
length = 255 - overflow;
}
dst[0] = length;
}
XString XStringFromPStr(ConstStr255Param pString)
{
// Allocates a cString and copies a Pascal string into it.
XString tmp;
unsigned int len = pString[0];
tmp.Create((char *)&pString[1],len);
return tmp;
}
#endif