⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gnewfont.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "platform/platform.h"
#include "platform/platformFont.h"
#include "platform/profiler.h"
#include "platform/platformMutex.h"
#include "console/console.h"
#include "core/stream.h"
#include "dgl/gBitmap.h"
#include "core/fileStream.h"
#include "core/findMatch.h"
#include "dgl/gTexManager.h"
#include "dgl/gNewFont.h"
#include "util/safeDelete.h"
#include "core/frameAllocator.h"
#include "core/unicode.h"
#include "zlib.h"

S32 GFont::smSheetIdCount = 0;
const U32 GFont::csm_fileVersion = 3;

ConsoleFunction(populateFontCacheString, void, 4, 4, "(faceName, size, string) - "
                "Populate the font cache for the specified font with characters from the specified string.")
{
   Resource<GFont> f = GFont::create(argv[1], dAtoi(argv[2]), Con::getVariable("$GUI::fontCacheDirectory"));

   if(f.isNull())
   {
      Con::errorf("populateFontCacheString - could not load font '%s %d'!", argv[1], dAtoi(argv[2]));
      return;
   }

   if(!f->hasPlatformFont())
   {
      Con::errorf("populateFontCacheString - font '%s %d' has no platform font! Cannot generate more characters.", argv[1], dAtoi(argv[2]));
      return;
   }

   // This has the side effect of generating character info, including the bitmaps.
   f->getStrWidthPrecise(argv[3]);
}

ConsoleFunction(populateFontCacheRange, void, 5, 5, "(faceName, size, rangeStart, rangeEnd) - "
                "Populate the font cache for the specified font with Unicode code points in the specified range. "
                "Note we only support BMP-0, so code points range from 0 to 65535.")
{
   Resource<GFont> f = GFont::create(argv[1], dAtoi(argv[2]), Con::getVariable("$GUI::fontCacheDirectory"));

   if(f.isNull())
   {
      Con::errorf("populateFontCacheRange - could not load font '%s %d'!", argv[1], dAtoi(argv[2]));
      return;
   }

   U32 rangeStart = dAtoi(argv[3]);
   U32 rangeEnd   = dAtoi(argv[4]);

   if(rangeStart > rangeEnd)
   {
      Con::errorf("populateFontCacheRange - range start is after end!");
      return;
   }

   if(!f->hasPlatformFont())
   {
      Con::errorf("populateFontCacheRange - font '%s %d' has no platform font! Cannot generate more characters.", argv[1], dAtoi(argv[2]));
      return;
   }

   // This has the side effect of generating character info, including the bitmaps.
   for(U32 i=rangeStart; i<rangeEnd; i++)
   {
      if(f->isValidChar(i))
         f->getCharWidth(i);
      else
         Con::warnf("populateFontCacheRange - skipping invalid char 0x%x",  i);
   }

   // All done!
}

ConsoleFunction(dumpFontCacheStatus, void, 1, 1, "() - Return a full description "
                "of all cached fonts, along with info on the codepoints each contains.")
{
   FindMatch match("*.uft", 4096);
   ResourceManager->findMatches(&match);

   Con::printf("--------------------------------------------------------------------------");
   Con::printf("   Font Cache Usage Report (%d fonts found)", match.numMatches());

   for (U32 i = 0; i < match.numMatches(); i++)
   {
      char *curMatch = match.matchList[i];
      Resource<GFont> font = ResourceManager->load(curMatch);

      // Deal with inexplicably missing or failed to load fonts.
      if (font.isNull())
      {
         Con::errorf(" o Couldn't load font : %s", curMatch);
         continue;
      }

      // Ok, dump info!
      font->dumpInfo();
   }
}

ConsoleFunction(writeFontCache, void, 1, 1, "() - force all cached fonts to"
                "serialize themselves to the cache.")
{
   FindMatch match("*.uft", 4096);
   ResourceManager->findMatches(&match);

   Con::printf("--------------------------------------------------------------------------");
   Con::printf("   Writing font cache to disk (%d fonts found)", match.numMatches());

   for (U32 i = 0; i < match.numMatches(); i++)
   {
      char *curMatch = match.matchList[i];
      Resource<GFont> font = ResourceManager->load(curMatch);

      // Deal with inexplicably missing or failed to load fonts.
      if (font.isNull())
      {
         Con::errorf(" o Couldn't find font : %s", curMatch);
         continue;
      }

      // Ok, dump info!
      FileStream stream;
      if(ResourceManager->openFileForWrite(stream, curMatch)) 
      {
         Con::printf("      o Writing '%s' to disk...", curMatch);
         font->write(stream);
         stream.close();
      }
      else
      {
         Con::errorf("      o Could not open '%s' for write!", curMatch);
      }
   }
}

ConsoleFunction(populateAllFontCacheString, void, 2, 2, "(string) - "
                "Populate the font cache for all fonts with characters from the specified string.")
{
   FindMatch match("*.uft", 4096);
   ResourceManager->findMatches(&match);

   Con::printf("Populating font cache with string '%s' (%d fonts found)", argv[1], match.numMatches());

   for (U32 i = 0; i < match.numMatches(); i++)
   {
      char *curMatch = match.matchList[i];
      Resource<GFont> font = ResourceManager->load(curMatch);

      // Deal with inexplicably missing or failed to load fonts.
      if (font.isNull())
      {
         Con::errorf(" o Couldn't load font : %s", curMatch);
         continue;
      }

      if(!font->hasPlatformFont())
      {
         Con::errorf("populateAllFontCacheString - font '%s' has no platform font! Cannot generate more characters.", curMatch);
         continue;
      }

      // This has the side effect of generating character info, including the bitmaps.
      font->getStrWidthPrecise(argv[1]);
   }
}

ConsoleFunction(populateAllFontCacheRange, void, 3, 3, "(rangeStart, rangeEnd) - "
                "Populate the font cache for all fonts with Unicode code points in the specified range. "
                "Note we only support BMP-0, so code points range from 0 to 65535.")
{
   U32 rangeStart = dAtoi(argv[1]);
   U32 rangeEnd   = dAtoi(argv[2]);

   if(rangeStart > rangeEnd)
   {
      Con::errorf("populateAllFontCacheRange - range start is after end!");
      return;
   }

   FindMatch match("*.uft", 4096);
   ResourceManager->findMatches(&match);

   Con::printf("Populating font cache with range 0x%x to 0x%x (%d fonts found)", rangeStart, rangeEnd, match.numMatches());

   for (U32 i = 0; i < match.numMatches(); i++)
   {
      char *curMatch = match.matchList[i];
      Resource<GFont> font = ResourceManager->load(curMatch);

      // Deal with inexplicably missing or failed to load fonts.
      if (font.isNull())
      {
         Con::errorf(" o Couldn't load font : %s", curMatch);
         continue;
      }

      if(!font->hasPlatformFont())
      {
         Con::errorf("populateAllFontCacheRange - font '%s' has no platform font! Cannot generate more characters.", curMatch);
         continue;
      }

      // This has the side effect of generating character info, including the bitmaps.
      Con::printf("   o Populating font '%s'", curMatch);
      for(U32 i=rangeStart; i<rangeEnd; i++)
      {
         if(font->isValidChar(i))
            font->getCharWidth(i);
         else
            Con::warnf("populateAllFontCacheRange - skipping invalid char 0x%x",  i);
      }
   }
   // All done!
}

ConsoleFunction(exportCachedFont, void, 6, 6, "(fontName, size, fileName, padding, kerning) - "
                "Export specified font to the specified filename as a PNG. The "
                "image can then be processed in Photoshop or another tool and "
                "reimported using importCachedFont. Characters in the font are"
                "exported as one long strip.")
{
   // Read in some params.
   const char *fontName = argv[1];
   S32 fontSize   = dAtoi(argv[2]);
   const char *fileName = argv[3];
   S32 padding    = dAtoi(argv[4]);
   S32 kerning    = dAtoi(argv[5]);

   // Tell the font to export itself.
   Resource<GFont> f = GFont::create(argv[1], dAtoi(argv[2]), Con::getVariable("$GUI::fontCacheDirectory"));

   if(f.isNull())
   {
      Con::errorf("populateFontCacheString - could not load font '%s %d'!", argv[1], dAtoi(argv[2]));
      return;
   }

   f->exportStrip(fileName, padding, kerning);
}

ConsoleFunction(importCachedFont, void, 6, 6, "(fontName, size, fileName, padding, kerning) - "
                "Import an image strip from exportCachedFont. Call with the "
                "same parameters you called exportCachedFont.")
{
   // Read in some params.
   const char *fontName = argv[1];
   S32 fontSize   = dAtoi(argv[2]);
   const char *fileName = argv[3];
   S32 padding    = dAtoi(argv[4]);
   S32 kerning    = dAtoi(argv[5]);

   // Tell the font to import itself.
   Resource<GFont> f = GFont::create(argv[1], dAtoi(argv[2]), Con::getVariable("$GUI::fontCacheDirectory"));

   if(f.isNull())
   {
      Con::errorf("populateFontCacheString - could not load font '%s %d'!", argv[1], dAtoi(argv[2]));
      return;
   }

   f->importStrip(fileName, padding, kerning);
}

ConsoleFunction(duplicateCachedFont, void, 4, 4, "(oldFontName, oldFontSize, newFontName) -"
                "Copy the specified old font to a new name. The new copy will not have a "
                "platform font backing it, and so will never have characters added to it. "
                "But this is useful for making copies of fonts to add postprocessing effects "
                "to via exportCachedFont.")
{
   char newFontFile[256];
   GFont::getFontCacheFilename(argv[3], dAtoi(argv[2]), 256, newFontFile);

   // Load the original font.
   Resource<GFont> font = GFont::create(argv[1], dAtoi(argv[2]), Con::getVariable("$GUI::fontCacheDirectory"));

   // Deal with inexplicably missing or failed to load fonts.
   if (font.isNull())
   {
      Con::errorf(" o Couldn't find font : %s", newFontFile);
      return;
   }

   // Ok, dump info!
   FileStream stream;
   if(ResourceManager->openFileForWrite(stream, newFontFile)) 
   {
      Con::printf("      o Writing duplicate font '%s' to disk...", newFontFile);
      font->write(stream);
      stream.close();
   }
   else
   {
      Con::errorf("      o Could not open '%s' for write!", newFontFile);
   }
}

ResourceInstance* constructNewFont(Stream& stream)
{
   GFont *ret = new GFont;

   if(!ret->read(stream))
   {
      SAFE_DELETE(ret);
   }

   if(ret)
   {
      ret->mPlatformFont = createPlatformFont(ret->mFaceName, ret->mSize, ret->mCharSet);
   }
   
   return ret;
}

void GFont::getFontCacheFilename(const char *faceName, U32 size, U32 buffLen, char *outBuff)
{
   dSprintf(outBuff, buffLen, "%s/%s %d (%s).uft", Con::getVariable("$GUI::fontCacheDirectory"), faceName, size, getCharSetName(0));
}

Resource<GFont> GFont::create(const char *faceName, U32 size, const char *cacheDirectory, U32 charset /* = TGE_ANSI_CHARSET */)
{
   char buf[256];
   dSprintf(buf, sizeof(buf), "%s/%s %d (%s).uft", cacheDirectory, faceName, size, getCharSetName(charset));
   
   Resource<GFont> ret = ResourceManager->load(buf);
   if(bool(ret))
   {
      ret->mGFTFile = StringTable->insert(buf);
      return ret;
   }

   PlatformFont *platFont = createPlatformFont(faceName, size, charset);
   
   if (platFont == NULL)
   {
      AssertISV(dStricmp(faceName, "Arial") != 0, "Error, The Arial Font must always be available!");

      // Need to handle this case better.  For now, let's just return a font that we're
      //  positive exists, in the correct size...
      return create("Arial", size, cacheDirectory, charset);
   }

   GFont *resFont = new GFont;
   resFont->mPlatformFont = platFont;
   resFont->addSheet();
   resFont->mGFTFile = StringTable->insert(buf);
   resFont->mFaceName = StringTable->insert(faceName);
   resFont->mSize = size;
   resFont->mCharSet = charset;

   resFont->mHeight   = platFont->getFontHeight();
   resFont->mBaseline = platFont->getFontBaseLine();
   resFont->mAscent   = platFont->getFontBaseLine();
   resFont->mDescent  = platFont->getFontHeight() - platFont->getFontBaseLine();

   ResourceManager->add(buf, resFont, false);
   return ResourceManager->load(buf);
}

//-------------------------------------------------------------------------

GFont::GFont()
{
   VECTOR_SET_ASSOCIATION(mCharInfoList);
   VECTOR_SET_ASSOCIATION(mTextureSheets);

   for (U32 i = 0; i < (sizeof(mRemapTable) / sizeof(S32)); i++)
      mRemapTable[i] = -1;

   mCurX = mCurY = mCurSheet = -1;

   mPlatformFont = NULL;
   mGFTFile = NULL;
   mFaceName = NULL;
   mSize = 0;
   mCharSet = 0;
   
   mMutex = Mutex::createMutex();
}

GFont::~GFont()
{
   if(mGFTFile)
   {
      FileStream stream;
      if(ResourceManager->openFileForWrite(stream, mGFTFile)) 
      {
         write(stream);
         stream.close();
      }
   }
   
   S32 i;

   for(i = 0;i < mCharInfoList.size();i++)
   {
       SAFE_DELETE_ARRAY(mCharInfoList[i].bitmapData);
   }

   SAFE_DELETE(mPlatformFont);
   
   Mutex::destroyMutex(mMutex);
}

void GFont::dumpInfo()
{
   // Number and extent of mapped characters?
   U32 mapCount = 0, mapBegin=0xFFFF, mapEnd=0;
   for(U32 i=0; i<0x10000; i++)
   {
      if(mRemapTable[i] != -1)
      {
         mapCount++;
         if(i<mapBegin) mapBegin = i;
         if(i>mapEnd)   mapEnd   = i;
      }
   }


   // Let's write out all the info we can on this font.
   Con::printf("   '%s' %dpt", mFaceName, mSize);
   Con::printf("      - %d texture sheets, %d mapped characters.", mTextureSheets.size(), mapCount);

   if(mapCount)
      Con::printf("      - Codepoints range from 0x%x to 0x%x.", mapBegin, mapEnd);
   else
      Con::printf("      - No mapped codepoints.", mapBegin, mapEnd);
   Con::printf("      - Platform font is %s.", (mPlatformFont ? "present" : "not present") );
}

//////////////////////////////////////////////////////////////////////////

bool GFont::loadCharInfo(const UTF16 ch)
{
    if(mRemapTable[ch] != -1)
        return true;    // Not really an error

    if(mPlatformFont && mPlatformFont->isValidChar(ch))
    {
        Mutex::lockMutex(mMutex); // the CharInfo returned by mPlatformFont is static data, must protect from changes.
        PlatformFont::CharInfo &ci = mPlatformFont->getCharInfo(ch);
        if(ci.bitmapData)
            addBitmap(ci);

        mCharInfoList.push_back(ci);
        mRemapTable[ch] = mCharInfoList.size() - 1;

        Mutex::unlockMutex(mMutex);
        return true;
    }

    return false;
}

void GFont::addBitmap(PlatformFont::CharInfo &charInfo)
{
   U32 nextCurX = U32(mCurX + charInfo.width ); /*7) & ~0x3;*/
   U32 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3;

   // These are here for postmortem debugging.
   bool routeA = false, routeB = false;

   if(mCurSheet == -1 || nextCurY >= TextureSheetSize)
   {
      routeA = true;
      addSheet();

      // Recalc our nexts.
      nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3;
      nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3;
   }

   if( nextCurX >= TextureSheetSize)
   {
      routeB = true;
      mCurX = 0;
      mCurY = nextCurY;

      // Recalc our nexts.
      nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -