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

📄 gnewfont.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 2 页
字号:
      nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3;
   }

   // Check the Y once more - sometimes we advance to a new row and run off
   // the end.
   if(nextCurY >= TextureSheetSize)
   {
      routeA = true;
      addSheet();

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

    charInfo.bitmapIndex = mCurSheet;
    charInfo.xOffset = mCurX;
    charInfo.yOffset = mCurY;

   mCurX = nextCurX;

   S32 x, y;
   GBitmap *bmp = mTextureSheets[mCurSheet].getBitmap();

   AssertFatal(bmp->getFormat() == GBitmap::Alpha, "GFont::addBitmap - cannot added characters to non-greyscale textures!");

   for(y = 0;y < charInfo.height;y++)
      for(x = 0;x < charInfo.width;x++)
         *bmp->getAddress(x + charInfo.xOffset, y + charInfo.yOffset) = charInfo.bitmapData[y * charInfo.width + x];

   mTextureSheets[mCurSheet].refresh();
}

void GFont::addSheet()
{
    char buf[30];
    dSprintf(buf, sizeof(buf), "newfont_%d", smSheetIdCount++);

    GBitmap *bitmap = new GBitmap(TextureSheetSize, TextureSheetSize, false, GBitmap::Alpha);

    // Set everything to transparent.
    U8 *bits = bitmap->getWritableBits();
    dMemset(bits, 0, sizeof(U8) *TextureSheetSize*TextureSheetSize);

    TextureHandle handle = TextureHandle(buf, bitmap);
    handle.setFilterNearest();

    mTextureSheets.increment();
    constructInPlace(&mTextureSheets.last());
    mTextureSheets.last() = handle;

    mCurX = 0;
    mCurY = 0;
    mCurSheet = mTextureSheets.size() - 1;
}

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

const PlatformFont::CharInfo &GFont::getCharInfo(const UTF16 in_charIndex)
{
    PROFILE_START(NewFontGetCharInfo);

    AssertFatal(in_charIndex, "GFont::getCharInfo - can't get info for char 0!");

    if(mRemapTable[in_charIndex] == -1)
    {
        bool ret = loadCharInfo(in_charIndex);
    }

    AssertFatal(mRemapTable[in_charIndex] != -1, "No remap info for this character");

    PROFILE_END();
    
    return mCharInfoList[mRemapTable[in_charIndex]];
}

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

U32 GFont::getStrWidth(const UTF8* in_pString)
{
   AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined");
   // If we ain't running debug...
   if (in_pString == NULL)
      return 0;

   return getStrNWidth(in_pString, dStrlen(in_pString));
}

U32 GFont::getStrWidthPrecise(const UTF8* in_pString)
{
   AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined");
   // If we ain't running debug...
   if (in_pString == NULL)
      return 0;

   return getStrNWidthPrecise(in_pString, dStrlen(in_pString));
}


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

bool GFont::read(Stream& io_rStream)
{
    // Handle versioning
    U32 version;
    io_rStream.read(&version);
    if(version != csm_fileVersion)
        return false;

    char buf[256];
    io_rStream.readString(buf);
    mFaceName = StringTable->insert(buf);

    io_rStream.read(&mSize);
    io_rStream.read(&mCharSet);

    io_rStream.read(&mHeight);
    io_rStream.read(&mBaseline);
    io_rStream.read(&mAscent);
    io_rStream.read(&mDescent);

    U32 size = 0;
    io_rStream.read(&size);
    mCharInfoList.setSize(size);
    U32 i;
    for(i = 0; i < size; i++)
    {
        PlatformFont::CharInfo *ci = &mCharInfoList[i];
        io_rStream.read(&ci->bitmapIndex);
        io_rStream.read(&ci->xOffset);
        io_rStream.read(&ci->yOffset);
        io_rStream.read(&ci->width);
        io_rStream.read(&ci->height);
        io_rStream.read(&ci->xOrigin);
        io_rStream.read(&ci->yOrigin);
        io_rStream.read(&ci->xIncrement);
        ci->bitmapData = NULL;
   }

   U32 numSheets = 0;
   io_rStream.read(&numSheets);
   
   for(i = 0; i < numSheets; i++)
   {
       GBitmap *bmp = new GBitmap;
       if(!bmp->readPNG(io_rStream))
       {
           delete bmp;
           return false;
       }

       char buf[30];
       dSprintf(buf, sizeof(buf), "font_%d", smSheetIdCount++);

       mTextureSheets.increment();
       constructInPlace(&mTextureSheets.last());
       mTextureSheets.last() = TextureHandle(buf, bmp);
       mTextureSheets.last().setFilterNearest();
   }
   
   // Read last position info
   io_rStream.read(&mCurX);
   io_rStream.read(&mCurY);
   io_rStream.read(&mCurSheet);

   // Read the remap table.
   U32 minGlyph, maxGlyph;
   io_rStream.read(&minGlyph);
   io_rStream.read(&maxGlyph);

   if(maxGlyph >= minGlyph)
   {
      // Length of buffer..
      U32 buffLen;
      io_rStream.read(&buffLen);

      // Read the buffer.
      FrameTemp<S32> inBuff(buffLen);
      io_rStream.read(buffLen, inBuff);

      // Decompress.
      uLongf destLen = (maxGlyph-minGlyph+1)*sizeof(S32);
      uncompress((Bytef*)&mRemapTable[minGlyph], &destLen, (Bytef*)(S32*)inBuff, buffLen);

      AssertISV(destLen == (maxGlyph-minGlyph+1)*sizeof(S32), "GFont::read - invalid remap table data!");

      // Make sure we've got the right endianness.
      for(i = minGlyph; i <= maxGlyph; i++)
         mRemapTable[i] = convertBEndianToHost(mRemapTable[i]);
   }
   
   return (io_rStream.getStatus() == Stream::Ok);
}

bool GFont::write(Stream& stream)
{
    // Handle versioning
    stream.write(csm_fileVersion);

    // Write font info
    stream.writeString(mFaceName);
    stream.write(mSize);
    stream.write(mCharSet);
   
    stream.write(mHeight);
    stream.write(mBaseline);
    stream.write(mAscent);
    stream.write(mDescent);

    // Write char info list
    stream.write(U32(mCharInfoList.size()));
    U32 i;
    for(i = 0; i < mCharInfoList.size(); i++)
    {
        const PlatformFont::CharInfo *ci = &mCharInfoList[i];
        stream.write(ci->bitmapIndex);
        stream.write(ci->xOffset);
        stream.write(ci->yOffset);
        stream.write(ci->width);
        stream.write(ci->height);
        stream.write(ci->xOrigin);
        stream.write(ci->yOrigin);
        stream.write(ci->xIncrement);
   }

   stream.write(mTextureSheets.size());
   for(i = 0; i < mTextureSheets.size(); i++)
       mTextureSheets[i].getBitmap()->writePNG(stream);

   stream.write(mCurX);
   stream.write(mCurY);
   stream.write(mCurSheet);

   // Get the min/max we have values for, and only write that range out.
   S32 minGlyph = S32_MAX, maxGlyph = 0;

   for(i = 0; i < 65536; i++)
   {
      if(mRemapTable[i] != -1)
      {
         if(i>maxGlyph) maxGlyph = i;
         if(i<minGlyph) minGlyph = i;
      }
   }

   stream.write(minGlyph);
   stream.write(maxGlyph);

   // Skip it if we don't have any glyphs to do...
   if(maxGlyph >= minGlyph)
   {
      // Put everything big endian, to be consistent. Do this inplace.
      for(i = minGlyph; i <= maxGlyph; i++)
         mRemapTable[i] = convertHostToBEndian(mRemapTable[i]);

      {
         // Compress.
         const U32 buffSize = 128 * 1024;
         FrameTemp<S32> outBuff(buffSize);
         uLongf destLen = buffSize * sizeof(S32);
         compress2((Bytef*)(S32*)outBuff, &destLen, (Bytef*)(S32*)&mRemapTable[minGlyph], (maxGlyph-minGlyph+1)*sizeof(S32), 9);

         // Write out.
         stream.write((U32)destLen);
         stream.write(destLen, outBuff);
      }

      // Put us back to normal.
      for(i = minGlyph; i <= maxGlyph; i++)
         mRemapTable[i] = convertBEndianToHost(mRemapTable[i]);
   }
   
   return (stream.getStatus() == Stream::Ok);
}

void GFont::exportStrip(const char *fileName, U32 padding, U32 kerning)
{
   // Figure dimensions of our strip by iterating over all the char infos.
   U32 totalHeight = 0;
   U32 totalWidth = 0;

   S32 heightMin=0, heightMax=0;

   for(S32 i=0; i<mCharInfoList.size(); i++)
   {
      totalWidth += mCharInfoList[i].width + kerning + 2*padding;
      heightMin = getMin((S32)heightMin, (S32)getBaseline() - (S32)mCharInfoList[i].yOrigin);
      heightMax = getMax((S32)heightMax, (S32)getBaseline() - (S32)mCharInfoList[i].yOrigin + (S32)mCharInfoList[i].height);
   }

   totalHeight = heightMax - heightMin + 2*padding;

   // Make the bitmap.
   GBitmap gb(totalWidth, totalHeight, false, mTextureSheets[0].getBitmap()->getFormat());

   dMemset(gb.getWritableBits(), 0, sizeof(U8) * totalHeight * totalWidth );

   // Ok, copy some rects, taking into account padding, kerning, offset.
   U32 curWidth = kerning + padding;

   for(S32 i=0; i<mCharInfoList.size(); i++)
   {
      // Skip invalid stuff.
      if(mCharInfoList[i].bitmapIndex == -1 || mCharInfoList[i].height == 0 || mCharInfoList[i].width == 0)
         continue;

      // Copy the rect.
      U32 bitmap = mCharInfoList[i].bitmapIndex;

      RectI ri(mCharInfoList[i].xOffset, mCharInfoList[i].yOffset, mCharInfoList[i].width, mCharInfoList[i].height );
      Point2I outRi(curWidth, padding + getBaseline() - mCharInfoList[i].yOrigin);
      gb.copyRect(mTextureSheets[bitmap].getBitmap(), ri, outRi); 

      // Advance.
      curWidth +=  mCharInfoList[i].width + kerning + 2*padding;
   }

   // Write the image!
   FileStream fs;
   
   if(!ResourceManager->openFileForWrite(fs, fileName))
   {
      Con::errorf("GFont::exportStrip - failed to open '%s' for writing.", fileName);
      return;
   }
 
   // Done!
   gb.writePNG(fs, false);
}

/// Used for repacking in GFont::importStrip.
struct GlyphMap
{
   U32 charId;
   GBitmap *bitmap;
};

static S32 QSORT_CALLBACK GlyphMapCompare(const void *a, const void *b)
{
   S32 ha = ((GlyphMap *) a)->bitmap->height;
   S32 hb = ((GlyphMap *) b)->bitmap->height;

   return hb - ha;
}


void GFont::importStrip(const char *fileName, U32 padding, U32 kerning)
{
   // Wipe our texture sheets, and reload bitmap data from the specified file.
   // Also deal with kerning.
   // Also, we may have to load RGBA instead of RGB.

   // Wipe our texture sheets.
   mCurSheet = mCurX = mCurY = 0;
   mTextureSheets.clear();

   //  Now, load the font strip.
   GBitmap *strip = GBitmap::load(fileName);

   if(!strip)
   {
      Con::errorf("GFont::importStrip - could not load file '%s'!", fileName);
      return;
   }

   // And get parsing and copying - load up all the characters as separate
   // GBitmaps, sort, then pack. Not terribly efficient but this is basically
   // on offline task anyway.

   // Ok, snag some glyphs.
   Vector<GlyphMap> glyphList;
   glyphList.reserve(mCharInfoList.size());

   U32 curWidth = 0;
   for(S32 i=0; i<mCharInfoList.size(); i++)
   {
      // Skip invalid stuff.
      if(mCharInfoList[i].bitmapIndex == -1 || mCharInfoList[i].height == 0 || mCharInfoList[i].width == 0)
         continue;

      // Allocate a new bitmap for this glyph, taking into account kerning and padding.
      glyphList.increment();
      glyphList.last().bitmap = new GBitmap(mCharInfoList[i].width + kerning + 2*padding, mCharInfoList[i].height + 2*padding, false, strip->getFormat());
      glyphList.last().charId = i;

      // Copy the rect.
      RectI ri(curWidth, getBaseline() - mCharInfoList[i].yOrigin, glyphList.last().bitmap->width, glyphList.last().bitmap->height);
      Point2I outRi(0,0);
      glyphList.last().bitmap->copyRect(strip, ri, outRi); 

      // Update glyph attributes.
      mCharInfoList[i].width = glyphList.last().bitmap->width;
      mCharInfoList[i].height = glyphList.last().bitmap->height;
      mCharInfoList[i].xOffset -= kerning + padding;
      mCharInfoList[i].xIncrement += kerning;
      mCharInfoList[i].yOffset -= padding;

      // Advance.
      curWidth += ri.extent.x;
   }

   // Ok, we have a big list of glyphmaps now. So let's sort them, then pack them.
   dQsort(glyphList.address(), glyphList.size(), sizeof(GlyphMap), GlyphMapCompare);

   // They're sorted by height, so now we can do some sort of awesome packing.
   Point2I curSheetSize(256, 256);
   Vector<U32> sheetSizes;

   S32 curY = 0;
   S32 curX = 0;
   S32 curLnHeight = 0;
   S32 maxHeight = 0;
   for(U32 i = 0; i < glyphList.size(); i++)
   {
      PlatformFont::CharInfo *ci = &mCharInfoList[glyphList[i].charId];
      
      if(ci->height > maxHeight)
         maxHeight = ci->height;

      if(curX + ci->width > curSheetSize.x)
      {
         curY += curLnHeight;
         curX = 0;
         curLnHeight = 0;
      }

      if(curY + ci->height > curSheetSize.y)
      {
         sheetSizes.push_back(curSheetSize.y);
         curX = 0;
         curY = 0;
         curLnHeight = 0;
      }

      if(ci->height > curLnHeight)
         curLnHeight = ci->height;
      
      ci->bitmapIndex = sheetSizes.size();
      ci->xOffset = curX;
      ci->yOffset = curY;
      curX += ci->width;
   }

   // Terminate the packing loop calculations.
   curY += curLnHeight;

   if(curY < 64)
      curSheetSize.y = 64;
   else if(curY < 128)
      curSheetSize.y = 128;

   sheetSizes.push_back(curSheetSize.y);

   if(getHeight() + padding * 2 > maxHeight)
      maxHeight = getHeight() + padding * 2;

   // Allocate texture pages.
   for(S32 i=0; i<sheetSizes.size(); i++)
   {
      char buf[30];
      dSprintf(buf, sizeof(buf), "newfont_%d", smSheetIdCount++);

      GBitmap *bitmap = new GBitmap(TextureSheetSize, TextureSheetSize, false, strip->getFormat());

      // Set everything to transparent.
      U8 *bits = bitmap->getWritableBits();
      dMemset(bits, 0, sizeof(U8) *TextureSheetSize*TextureSheetSize * strip->bytesPerPixel);

      TextureHandle handle = TextureHandle( buf, bitmap );
      mTextureSheets.increment();
      constructInPlace(&mTextureSheets.last());
      mTextureSheets.last() = handle;
   }


   // Alright, we're ready to copy bits!
   for(S32 i=0; i<glyphList.size(); i++)
   {
      // Copy each glyph into the appropriate place.
      PlatformFont::CharInfo *ci = &mCharInfoList[glyphList[i].charId];
      U32 bi = ci->bitmapIndex;
      mTextureSheets[bi].getBitmap()->copyRect(glyphList[i].bitmap, RectI(0,0, glyphList[i].bitmap->width,glyphList[i].bitmap->height), Point2I(ci->xOffset, ci->yOffset));
   }

   // Ok, all done! Just refresh some textures and we're set.
   for(S32 i=0; i<sheetSizes.size(); i++)
      mTextureSheets[i].refresh();
}

⌨️ 快捷键说明

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