/*************************************************************************/ /* File : CKFontManager.cpp */ /* */ /*************************************************************************/ #include "CKall.h" #include "CKFontManager.h" #ifdef macintosh #ifndef __GNUC__ #include #else #include #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;jGetObject(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;jGetObject(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;hReadAndFillBuffer(&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;iSetViewRect(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 AdvanceWidths; XArray LeftSideBearing; XArray Bounds; XArray 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* array = (XClassArray*)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 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 ñwhile (*s++ = *t++)î 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