Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

#include "SysFont.h"
#include "DDImage.h"
#include "SexyAppBase.h"
#include "Graphics.h"
#include "ImageFont.h"
#include "MemoryImage.h"
#include "D3DInterface.h"
#include "WidgetManager.h"
#include <stdlib.h>

using namespace Sexy;

SysFont::SysFont(const std::string& theFace, int thePointSize, bool bold, bool italics, bool underline)
{
        Init(gSexyAppBase,theFace,thePointSize,ANSI_CHARSET,bold,italics,underline,false);
}

SysFont::SysFont(SexyAppBase* theApp, const std::string& theFace, int thePointSize, int theScript, bool bold, bool italics, bool underline)
{
        Init(theApp,theFace,thePointSize,theScript,bold,italics,underline,true);
}

void SysFont::Init(SexyAppBase* theApp, const std::string& theFace, int thePointSize, int theScript, bool bold, bool italics, bool underline, bool useDevCaps)
{
        mApp = theApp;

        HDC aDC = ::GetDC(mApp->mHWnd);

        int aHeight = -MulDiv(thePointSize, useDevCaps?GetDeviceCaps(aDC, LOGPIXELSY):96, 72);

        mHFont = CreateFontA(aHeight, 0, 0, 0, bold ? FW_BOLD : FW_NORMAL, italics, underline,
                        false, theScript, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
                        DEFAULT_PITCH | FF_DONTCARE, theFace.c_str());
       
        TEXTMETRIC aTextMetric;
        HFONT anOldFont = (HFONT) SelectObject(aDC, mHFont);
        GetTextMetrics(aDC, &aTextMetric);
        SelectObject(aDC, anOldFont);
        ReleaseDC(mApp->mHWnd, aDC);

        mHeight = aTextMetric.tmHeight;
        mAscent = aTextMetric.tmAscent;

        mDrawShadow = false;
        mSimulateBold = false;
}

SysFont::SysFont(const SysFont& theSysFont)
{
        LOGFONT aLogFont;

        GetObject(theSysFont.mHFont, sizeof(LOGFONT), &aLogFont);
        mHFont = CreateFontIndirect(&aLogFont);
        mApp = theSysFont.mApp;
        mHeight = theSysFont.mHeight;
        mAscent = theSysFont.mAscent;

        mDrawShadow = false;
        mSimulateBold = false;
}

SysFont::~SysFont()
{
        DeleteObject(mHFont);
}

ImageFont* SysFont::CreateImageFont()
{
        int i;
        MemoryImage*                    anImage;
        int anImageCharWidth, anImageXOff, anImageYOff;

        ////////////////////////////////////////////////////
        // Step 1: Create image
        anImageCharWidth = CharWidth('W')*2;
        anImageXOff = anImageCharWidth/4;
        anImageYOff = mHeight/2;
        int aWidth = 257*anImageCharWidth;
        int aHeight = mHeight*2;

        BITMAPINFO aBitmapInfo;
        memset(&aBitmapInfo,0,sizeof(aBitmapInfo));
        BITMAPINFOHEADER &aHeader = aBitmapInfo.bmiHeader;
        aHeader.biSize = sizeof(aHeader);
        aHeader.biWidth = aWidth;
        aHeader.biHeight = -aHeight;
        aHeader.biPlanes = 1;
        aHeader.biBitCount = 32;
        aHeader.biCompression = BI_RGB;

        HDC aDC = CreateCompatibleDC(NULL);

        DWORD *aBits = NULL;
        HBITMAP aBitmap = CreateDIBSection(aDC,&aBitmapInfo,DIB_RGB_COLORS,(void**)&aBits,NULL,0);

        HBITMAP anOldBitmap = (HBITMAP)SelectObject(aDC,aBitmap);
        HFONT anOldFont = (HFONT)SelectObject(aDC,mHFont);

        HBRUSH anOldBrush = (HBRUSH)SelectObject(aDC,GetStockObject(BLACK_BRUSH));
        Rectangle(aDC,0,0,aWidth,aHeight);

        SetBkMode(aDC, TRANSPARENT);    
        SetTextColor(aDC, RGB(255,255,255));
                               
        int xpos = anImageXOff;
        int ypos = anImageYOff;
        for (i=0; i<256; i++)
        {
                char aChar = i;
                TextOutA(aDC,xpos,ypos,&aChar,1);
                xpos += anImageCharWidth;
        }
        GdiFlush();


        SelectObject(aDC,anOldBrush);
        SelectObject(aDC,anOldBitmap);
        SelectObject(aDC,anOldFont);

        int aSize = aWidth*aHeight;
        anImage = new MemoryImage(mApp);
        anImage->Create(aWidth,aHeight);
        DWORD *src = aBits;
        DWORD *dst = anImage->GetBits();
        for (i=0; i<aSize; i++)
        {
                DWORD anAlpha = ((*src++)&0xff)<<24;
                *dst++ = anAlpha | 0xFFFFFF;
        }
        anImage->BitsChanged();
        DeleteObject(aBitmap);


        ////////////////////////////////////////////////////
        // Step 2: Create image font

        ImageFont *aFont = new ImageFont(anImage);
        FontLayer *aFontLayer = &aFont->mFontData->mFontLayerList.back();

        aFontLayer->mAscent = mAscent;
        aFontLayer->mHeight = mHeight;

        for (i=0; i<256; i++)
        {
                char aChar = i;

                aFontLayer->mCharData[(uchar) aChar].mImageRect = Rect(aChar*anImageCharWidth,0,anImageCharWidth,anImage->mHeight);
                aFontLayer->mCharData[(uchar) aChar].mWidth = CharWidth(aChar);
                aFontLayer->mCharData[(uchar) aChar].mOffset = Point(-anImageXOff,-anImageYOff);
        }

        aFont->GenerateActiveFontLayers();
        aFont->mActiveListValid = true;

        return aFont;
}

int     SysFont::StringWidth(const SexyString& theString)
{
        HDC aDC = ::GetDC(mApp->mHWnd);
        HFONT anOldFont = (HFONT)::SelectObject(aDC, mHFont);
        int aWidth = 0;

#ifdef _USE_WIDE_STRING
        if (CheckFor98Mill())
        {
                SIZE aSize = { 0, 0 };
                GetTextExtentPoint32W(aDC, theString.c_str(), theString.length(), &aSize);
                aWidth = int(aSize.cx);
        }
        else
#endif
        {
                RECT aRect = {0, 0, 0, 0};     
                DrawTextEx(aDC, (SexyChar*)theString.c_str(), theString.length(), &aRect, DT_CALCRECT | DT_NOPREFIX, NULL);
                aWidth = aRect.right;
        }

        ::SelectObject(aDC, anOldFont);
        ::ReleaseDC(mApp->mHWnd, aDC);

        return aWidth;
}

void SysFont::DrawString(Graphics* g, int theX, int theY, const SexyString& theString, const Color& theColor, const Rect& theClipRect)
{
        DDImage* aDDImage = dynamic_cast<DDImage*>(g->mDestImage);

        if (aDDImage != NULL)
        {
                LPDIRECTDRAWSURFACE aSurface = aDDImage->GetSurface();
                if (aSurface != NULL)
                {
                        HDC aDC;

                        if (aDDImage->mLockCount > 0)
                                aDDImage->mSurface->Unlock(NULL);

                        if ((g->mDestImage == gSexyAppBase->mWidgetManager->mImage) && (gSexyAppBase->Is3DAccelerated()))
                                gSexyAppBase->mDDInterface->mD3DInterface->Flush();                            
                       
                        if (aSurface->GetDC(&aDC) == DD_OK)
                        {                              
                                HFONT anOldFont = (HFONT) SelectObject(aDC, mHFont);
                                SetBkMode(aDC, TRANSPARENT);
                                IntersectClipRect(aDC, theClipRect.mX, theClipRect.mY, theClipRect.mX + theClipRect.mWidth, theClipRect.mY + theClipRect.mHeight);

                                if (mDrawShadow)
                                {
                                        SetTextColor(aDC, RGB(0,0,0));
                                        TextOut(aDC, theX + g->mTransX+1, theY - mAscent + 1 + g->mTransY+1, theString.c_str(), theString.length());
                                        if (mSimulateBold)
                                                TextOut(aDC, theX + g->mTransX+2, theY - mAscent + 1 + g->mTransY+1, theString.c_str(), theString.length());
                                }
                                SetTextColor(aDC, RGB(theColor.GetRed(), theColor.GetGreen(), theColor.GetBlue()));
                                TextOut(aDC, theX + g->mTransX, theY - mAscent + 1 + g->mTransY, theString.c_str(), theString.length());
                                if (mSimulateBold)
                                        TextOut(aDC, theX + g->mTransX + 1, theY - mAscent + 1 + g->mTransY, theString.c_str(), theString.length());

                                ::SelectObject(aDC, anOldFont);
                                aSurface->ReleaseDC(aDC);
                                aDDImage->DeleteAllNonSurfaceData();                           
                        }                      

                        if (aDDImage->mLockCount > 0)
                                aDDImage->mSurface->Lock(NULL, &aDDImage->mLockedSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);                    
                }
        }
        else if (g->mDestImage != &Graphics::mStaticImage) // DrawString can be called when not drawing onto an image.
        {
                HDC aDC = CreateCompatibleDC(NULL);
                HFONT anOldFont = (HFONT) SelectObject(aDC, mHFont);

                int aWidth = StringWidth(theString);
                int aHeight = mHeight;

                BITMAPINFOHEADER bih;
                memset(&bih, 0, sizeof(bih));

                bih.biPlanes = 1;
                bih.biWidth = aWidth;
                bih.biHeight = -aHeight;
                bih.biCompression = BI_RGB;
                bih.biBitCount = 32;
                bih.biSize = sizeof(BITMAPINFOHEADER);

                ulong* whiteBits, * blackBits;
                HBITMAP whiteBitmap = (HBITMAP)CreateDIBSection(aDC, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&whiteBits, NULL, 0);
                HBITMAP blackBitmap = (HBITMAP)CreateDIBSection(aDC, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&blackBits, NULL, 0);

                RECT rc = { 0, 0, aWidth, aHeight };

#define DRAW_BITMAP(bmp, brush) \
                {                                                                                                                                                                                       \
                        HBITMAP oldBmp = (HBITMAP) SelectObject(aDC, bmp);                                                                              \
                        ::FillRect(aDC, &rc, brush);                                                                                                                    \
                        SetBkMode(aDC, TRANSPARENT);                                                                                                                    \
                                                                                                                                                                                                        \
                        if (mDrawShadow)                                                                                                                                                \
                        {                                                                                                                                                                               \
                                SetTextColor(aDC, RGB(0,0,0));                                                                                                          \
                                TextOut(aDC, 1, 1, theString.c_str(), theString.length());                                                      \
                                if (mSimulateBold)                                                                                                                                      \
                                        TextOut(aDC, 2, 1, theString.c_str(), theString.length());                                              \
                        }                                                                                                                                                                               \
                        SetTextColor(aDC, RGB(theColor.GetRed(), theColor.GetGreen(), theColor.GetBlue()));             \
                        TextOut(aDC, 0, 0, theString.c_str(), theString.length());                                                              \
                        if (mSimulateBold)                                                                                                                                              \
                                TextOut(aDC, 1, 0, theString.c_str(), theString.length());                                                      \
                                                                                                                                                                                                        \
                        SelectObject(aDC, oldBmp);                                                                                                                              \
                }


                DRAW_BITMAP(whiteBitmap, (HBRUSH)GetStockObject(WHITE_BRUSH));
                DRAW_BITMAP(blackBitmap, (HBRUSH)GetStockObject(BLACK_BRUSH));

                SelectObject(aDC, anOldFont);

                MemoryImage aTempImage;
                aTempImage.Create(aWidth, aHeight);

                int aCount = aHeight*aWidth;
                ulong* ptr1 = whiteBits, *ptr2 = blackBits;
                while (aCount > 0)
                {
                        if (*ptr1 == *ptr2)
                                *ptr1 |= 0xFF000000;
                        else if ((*ptr1 & 0xFFFFFF) != 0xFFFFFF || (*ptr2 & 0xFFFFFF) != 0x000000) // if not the background of either, it's a 'blend'
                        {
                                int ba = 255 + (*ptr2 & 0xFF) - (*ptr1 & 0xFF);
                                int ga = 255 + ((*ptr2 >> 8) & 0xFF) - ((*ptr1 >> 8) & 0xFF);
                                int ra = 255 + ((*ptr2 >> 16) & 0xFF) - ((*ptr1 >> 16) & 0xFF);
                                int aBlue = 255 * (*ptr2 & 0xFF) / ba;
                                int aGreen = 255 * ((*ptr2 >> 8) & 0xFF) / ga;
                                int aRed = 255 * ((*ptr2 >> 16) & 0xFF) / ra;
                                int anAlpha = min(ra, min(ga, ba));
                                *ptr1 = (aBlue) | (aGreen << 8) | (aRed << 16) | (anAlpha << 24);
                        }
                        else *ptr1 &= 0;

                        ptr1++;
                        ptr2++;
                        --aCount;
                }

                memcpy(aTempImage.GetBits(), whiteBits, aWidth*aHeight*sizeof(ulong));
                g->DrawImage(&aTempImage, theX, theY - mAscent);

                DeleteObject(whiteBitmap);
                DeleteObject(blackBitmap);
                DeleteDC(aDC);
        }
}

Font* SysFont::Duplicate()
{
        return new SysFont(*this);
}