#include "stdafx.h" #include "KViewport.h" #include "KTextRender.h" #include "KPrimitiveSprite.h" #include "KTextPhrase.h" #include "KTextCacheManager.h" #include "KTextEmoticonRender.h" #include "KResourceManager.h" #include #include #include #include "shlobj.h" #ifdef _COUNTRY_ME_ #include "KPangoCairo.h" #endif namespace { const int COLOR_VALUE = 1024; }; XFreeType * KTextRender::s_pFreeType = new XFreeType; K3DRenderDevice * KTextRender::m_pDevice = NULL; KTextRender::FontMap KTextRender::m_mapFontInfo; int KTextRender::m_nDefaultCodePage = CP_ACP; // AziaMafia DEFAUT UTF-8 HDC KTextRender::m_hDC; bool bUseFreeType = false; bool KTextRender::s_bIsOsVista = false; std::string KTextRender::s_strLocale; const char *KTextRender::KDEFAULT_FONT_NAME = "Default"; const char *KTextRender::KDEFAULT_FONT_NAME2 = "font_default"; /// 2010.11.05 - prodongi const char *KTextRender::KDEFAULT_FONT_01 = "font_01"; const char *KTextRender::KDEFAULT_FONT_02 = "font_02"; const char *KTextRender::KDEFAULT_FONT_03 = "font_03"; // 2010.08.26 - prodongi const int KTextRender::KDEFAULT_FONT_SIZE = 9; KTextRender::StringTableHandler* KTextRender::s_pStringTableHandler; float KTextRender::m_fFreeTypeSizeRatio = 1.0f; bool KTextRender::m_bIncreaseEnglishFontSize= false; int KTextRender::m_nFreeTypeYOffset = 0; unsigned char KTextRender::s_randColor[1024]; int KTextRender::s_nColorValue = 0; #ifdef _COUNTRY_ME_ KFontManager KTextRender::s_fontManager; #endif void KTextRender::GenerateRandColor() { for( int i(0); COLOR_VALUE>i; i++ ) { s_randColor[i] = rand()%255; } } unsigned char KTextRender::GetNextRandColor() { if( s_nColorValue > COLOR_VALUE ) s_nColorValue = 0; return s_randColor[s_nColorValue++]; } static int incSizeIfNoMultiByte( const char *str, int nFontSize ) { const unsigned char *p = (const unsigned char *)str; while( *p ) { if( *p & 0x80 ) return nFontSize; ++p; } return nFontSize+2; } KTextRender::FREETYPE_TEXT_FONT_INFO::FREETYPE_TEXT_FONT_INFO( const char *szAlias, const char *szFontFileName,bool *returnSuccess ) { pFontStream = NULL; if(returnSuccess) *returnSuccess = true; //pFontStream = NULL; bIsFreeType = true; KStream *pFontResource = KFileManager::Instance().CreateStreamFromResource( szFontFileName ); if( !pFontResource ) { TCHAR szFontPath[_MAX_PATH]; if( SHGetFolderPath( NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, szFontPath ) == E_FAIL ) { assert(0 && "FREETYPE_TEXT_FONT_INFO - resource not found!!" ); *returnSuccess = false; } else { std::string path = szFontPath; path += "\\"; path += szFontFileName; FILE *fp = fopen(path.c_str(),"rb"); if(fp) { fseek( fp, 0, SEEK_END ); size_t fsize = ftell( fp ); fseek( fp, 0, SEEK_SET ); pFontStream = new char[fsize]; fread( pFontStream, sizeof(char)*fsize, 1, fp ); if( !s_pFreeType->IsInitialized() ) s_pFreeType->Init(); if( !s_pFreeType->LoadFont( szAlias, pFontStream, fsize ) ) { assert(0 && "FREETYPE_TEXT_FONT_INFO - LoadFont Failed!!" ); delete [] pFontStream; if(returnSuccess) *returnSuccess = false; } KFileManager::Instance().DeleteStream( pFontResource ); fclose( fp ); } else { assert(0 && "FREETYPE_TEXT_FONT_INFO - resource not found!!" ); *returnSuccess = false; } } } else { pFontStream = new char[ pFontResource->GetLength() ]; pFontResource->Read( pFontStream, pFontResource->GetLength() ); if( !s_pFreeType->IsInitialized() ) s_pFreeType->Init(); if( !s_pFreeType->LoadFont( szAlias, pFontStream, pFontResource->GetLength() ) ) { assert(0 && "FREETYPE_TEXT_FONT_INFO - LoadFont Failed!!" ); delete [] pFontStream; if(returnSuccess) *returnSuccess = false; } KFileManager::Instance().DeleteStream( pFontResource ); } } #ifndef _COUNTRY_ME_ /// 2011.02.23 isSpriteScroll 추가 - prodongi KTextRender::KTextRender(LPCSTR lpszText, KColor color, LPCSTR lpszFontName, int nSize, DWORD & dwWidth, DWORD & dwHeight, DWORD dwAlign, DWORD dwFlag, bool bStaticSize, KColor color_fx, float fZPos/*0.0f*/, bool bRandomColor/*=false*/, bool bUseEmoticonFilter, bool isSpriteScroll ) :m_dwWidth(dwWidth), m_dwHeight(dwHeight), m_pEmoticonLayerRender(NULL), m_prSprite(NULL) { //assert( _CrtCheckMemory() ); //if( _CrtCheckMemory() == 0 ) // SDEBUGLOG("_CrtCheckMemory - KTextRender::KTextRender"); // SDEBUGLOG("KTextRender::GetStringSize - text[%s], font[%s]", lpszText, lpszFontName); int bufferImgWidth = 0; /// 2011.02.23 Text Image의 사이즈- prodongi int bufferImgHeight = 0; DWORD dwTextColor = DWORD((color.a << 24) | (color.r << 16) | (color.g << 8) | (color.b)); TEXT_FONT_INFO * pFontInfo = _FindFont(lpszFontName, nSize); if( pFontInfo && pFontInfo->bIsFreeType && m_bIncreaseEnglishFontSize ) nSize = incSizeIfNoMultiByte( lpszText, nSize ); // InitTextRender가 불려지지 않았으므로 if(!m_pDevice) { assert(false && "please call InitTextRender"); } m_prSprite = new KSpritePrimitive(false); // [MEMORY_LEAK] 2012. 3. 2 - marine 메모리 해제해줌.. m_spResSprite = new KResSprite; // [MEMORY_LEAK] 2012. 3. 2 - marine 메모리 해제해줌.. std::string strText = lpszText; for( size_t i = 0; i < strText.size(); ++i ) { //if( strText[i] == 0x1D ) strText[i] = '&'; if( strText[i] == 0x1E ) strText[i] = '<'; if( strText[i] == 0x1F ) strText[i] = '>'; } // emoticon bool bExistEmoticon = false; DWORD dwOldHeight = dwHeight; if( bUseEmoticonFilter ) CheckEmoticon( strText, lpszFontName, nSize, dwFlag, dwWidth, dwHeight, bStaticSize, fZPos ); if( dwOldHeight != dwHeight ) bExistEmoticon = true; m_spTexture = KTextCacheManager::GetInstance()->FindCache( strText.c_str(), color, lpszFontName, nSize, dwWidth, dwHeight, dwFlag, color_fx); if(m_spTexture != NULL) { if (isSpriteScroll) /// 2011.03.22 - prodongi { m_spResSprite->SetTexture(m_spTexture, m_spTexture->GetTextOriImgRect()); m_prSprite->SetRes(m_spResSprite); m_prSprite->setScrollImgUv(m_spTexture->GetTextOriImgWidth(), m_spTexture->GetTextOriImgHeight()); } else { m_spResSprite->SetTexture(m_spTexture, NULL); m_prSprite->SetRes(m_spResSprite); } return; } KRect rcTexRect; if( pFontInfo == NULL || !pFontInfo->bIsFreeType ) { BYTE *pBitmapBuffer = NULL; BITMAPINFO bmi; ZeroMemory( &bmi.bmiHeader, sizeof(bmi.bmiHeader) ); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = dwWidth; bmi.bmiHeader.biHeight = -int(dwHeight); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biCompression = BI_RGB; //bmi.bmiHeader.biBitCount = 16; bmi.bmiHeader.biBitCount = 32; HBITMAP hBmBitmap = CreateDIBSection( m_hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBuffer, NULL, 0 ); //DWORD dwStride = dwWidth * 2; DWORD dwStride = dwWidth * 4; if ( dwStride % 4 ) dwStride = ((dwStride / 4) + 1) * 4; ZeroMemory( pBitmapBuffer, dwStride * dwHeight ); WIN32_TEXT_FONT_INFO * pInfo = (WIN32_TEXT_FONT_INFO *)_FindFont(lpszFontName, nSize); if(!pInfo) { if( strlen(lpszFontName) > 0 ) { KTextRender::AddFont(lpszFontName,nSize); pInfo = (WIN32_TEXT_FONT_INFO *)_FindFont(lpszFontName, nSize); } else { pInfo = (WIN32_TEXT_FONT_INFO *)_FindFont("default", nSize); } } HBITMAP hBitmapOld = reinterpret_cast( ::SelectObject(m_hDC, hBmBitmap)); HFONT hFontOld; // Font Flag Setting if(dwFlag & KTFLAG_BOLD) { hFontOld = reinterpret_cast(::SelectObject(m_hDC,pInfo->hBoldFont ) ); } else if(dwFlag & KTFLAG_UNDER) { hFontOld = reinterpret_cast(::SelectObject(m_hDC,pInfo->hUnderLineFont ) ); } else if(dwFlag & KTFLAG_STRIKE) { hFontOld = reinterpret_cast(::SelectObject(m_hDC,pInfo->hStrikeOutFont ) ); } else { hFontOld = reinterpret_cast(::SelectObject(m_hDC, pInfo->hDefaultFont) ); } SetTextAlign(m_hDC, TA_TOP ); DWORD dwColor = RGB(255,255,255); if(dwFlag & KTFLAG_INVERSE) { SetBkMode( m_hDC, TRANSPARENT ); SetBkColor( m_hDC, 0x00000000 ); SetTextColor( m_hDC, dwColor ); } else { SetBkMode( m_hDC, TRANSPARENT ); SetBkColor( m_hDC, 0x00000000 ); SetTextColor( m_hDC, dwColor ); } unsigned int i; for(i = 2; i < dwWidth+4;) i *= 2; DWORD dwTexWidth = i; for(i = 2; i < dwHeight+4;) i *= 2; DWORD dwTexHeight = i; RECT rcRect; rcRect.left = 0; rcRect.top = 0; rcRect.right = dwWidth; rcRect.bottom = dwHeight; rcTexRect.left = 0; rcTexRect.top = 0; rcTexRect.right = dwWidth; rcTexRect.bottom = dwHeight; // MIMI if( bExistEmoticon ) { // 전체 height 의 절반에서 폰트 height 의 절반을 뺀것이 top rcRect.top = dwHeight/2 - dwOldHeight/2; rcRect.top += 2; } ::DrawText(m_hDC, strText.c_str(), static_cast(strText.size()), &rcRect, dwAlign | DT_NOPREFIX #ifdef _COUTNRY_ME_ // sonador #2.4.10.2 | DT_RTLREADING #endif ); m_spTexture = m_pDevice->CreateTexture(dwTexWidth,dwTexHeight, K3DFMT_A8R8G8B8 ); if(m_spTexture == NULL) return; int nStride; DWORD* pImgBuf32; m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32),nStride); assert(pImgBuf32 && "m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32),nStride);"); if( NULL == pImgBuf32 ) { return; } nStride /= sizeof(DWORD); int textoffset = 0; if ( dwFlag & KTFLAG_GLOW ) { textoffset = 2; //unsigned short wGlowColor = unsigned short((0x6 << 12) | (0xa << 8) | (0xa << 4) | 0xa); DWORD dwGlowColor = DWORD((0x60 << 24) | (0xa0 << 16) | (0xa0 << 8) | 0xa0); //for(i = 0; i < dwHeight; ++i) //{ // WORD *pImg = (WORD*)&pBitmapBuffer[i*dwStride]; // for(unsigned int j = 0; j < dwWidth; ++j) // { // if( *pImg++ ) // { // *(pImgBuf16 + (i+0) * nStride + (j+0)) = wGlowColor; // *(pImgBuf16 + (i+0) * nStride + (j+1)) = wGlowColor; // *(pImgBuf16 + (i+0) * nStride + (j+2)) = wGlowColor; // *(pImgBuf16 + (i+0) * nStride + (j+3)) = wGlowColor; // *(pImgBuf16 + (i+0) * nStride + (j+4)) = wGlowColor; // *(pImgBuf16 + (i+1) * nStride + (j+0)) = wGlowColor; // *(pImgBuf16 + (i+2) * nStride + (j+0)) = wGlowColor; // *(pImgBuf16 + (i+3) * nStride + (j+0)) = wGlowColor; // *(pImgBuf16 + (i+4) * nStride + (j+0)) = wGlowColor; // *(pImgBuf16 + (i+1) * nStride + (j+4)) = wGlowColor; // *(pImgBuf16 + (i+2) * nStride + (j+4)) = wGlowColor; // *(pImgBuf16 + (i+3) * nStride + (j+4)) = wGlowColor; // *(pImgBuf16 + (i+4) * nStride + (j+4)) = wGlowColor; // *(pImgBuf16 + (i+4) * nStride + (j+1)) = wGlowColor; // *(pImgBuf16 + (i+4) * nStride + (j+2)) = wGlowColor; // *(pImgBuf16 + (i+4) * nStride + (j+3)) = wGlowColor; // } // } //} for(i = 0; i < dwHeight; ++i) { DWORD *pImg = (DWORD*) &pBitmapBuffer[i*dwStride]; for(unsigned int j = 0; j < dwWidth; ++j) { if( *pImg++ ) { *(pImgBuf32 + (i+0) * nStride + (j+0)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+0) * nStride + (j+1)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+0) * nStride + (j+2)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+0) * nStride + (j+3)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+0) * nStride + (j+4)) = dwGlowColor; if( i != dwHeight - 1 ) { *(pImgBuf32 + (i+1) * nStride + (j+0)) = dwGlowColor; *(pImgBuf32 + (i+2) * nStride + (j+0)) = dwGlowColor; *(pImgBuf32 + (i+3) * nStride + (j+0)) = dwGlowColor; *(pImgBuf32 + (i+4) * nStride + (j+0)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+1) * nStride + (j+4)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+2) * nStride + (j+4)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+3) * nStride + (j+4)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+4) * nStride + (j+4)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+4) * nStride + (j+1)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+4) * nStride + (j+2)) = dwGlowColor; if( j != dwWidth - 1 ) *(pImgBuf32 + (i+4) * nStride + (j+3)) = dwGlowColor; } } } } } if ( dwFlag & KTFLAG_GLOW || dwFlag & KTFLAG_OUTLINE ) { int so = 2; if ( !(dwFlag & KTFLAG_GLOW) ) { textoffset = 1; so = 1; } //unsigned short wShadowColor = unsigned short((0xf << 12) | (0x4 << 8) | (0x4 << 4) | 0x4); //for(i = 0; i < dwHeight; ++i) //{ // WORD *pImg = (WORD*)&pBitmapBuffer[i*dwStride]; // for(unsigned int j = 0; j < dwWidth; ++j) // { // if( *pImg++ ) // { // *(pImgBuf16 + (i+so-1) * nStride + (j+so-1)) = wShadowColor; // *(pImgBuf16 + (i+so-1) * nStride + (j+so)) = wShadowColor; // *(pImgBuf16 + (i+so-1) * nStride + (j+so+1)) = wShadowColor; // *(pImgBuf16 + (i+so) * nStride + (j+so-1)) = wShadowColor; // *(pImgBuf16 + (i+so) * nStride + (j+so+1)) = wShadowColor; // *(pImgBuf16 + (i+so+1) * nStride + (j+so-1)) = wShadowColor; // *(pImgBuf16 + (i+so+1) * nStride + (j+so)) = wShadowColor; // *(pImgBuf16 + (i+so+1) * nStride + (j+so+1)) = wShadowColor; // } // } //} DWORD dwShadowColor = DWORD((0xf0 << 24) | (0x40 << 16) | (0x40 << 8) | 0x40); for(i = 0; i < dwHeight; ++i) { DWORD *pImg = (DWORD*)&pBitmapBuffer[i*dwStride]; for(unsigned int j = 0; j < dwWidth; ++j) { if( *pImg++ ) { if( i + so - 1 < dwHeight ) { if( j + so - 1 < dwWidth ) *(pImgBuf32 + (i+so-1) * nStride + (j+so-1)) = dwShadowColor; if( j + so < dwWidth ) *(pImgBuf32 + (i+so-1) * nStride + (j+so)) = dwShadowColor; if( j + so + 1 < dwWidth ) *(pImgBuf32 + (i+so-1) * nStride + (j+so+1)) = dwShadowColor; } if( i + so < dwHeight ) { if( j + so - 1 < dwWidth ) *(pImgBuf32 + (i+so) * nStride + (j+so-1)) = dwShadowColor; if( j + so + 1 < dwWidth ) *(pImgBuf32 + (i+so) * nStride + (j+so+1)) = dwShadowColor; } if( i + so + 1 < dwHeight ) { if( j + so - 1 < dwWidth ) *(pImgBuf32 + (i+so+1) * nStride + (j+so-1)) = dwShadowColor; if( j + so < dwWidth ) *(pImgBuf32 + (i+so+1) * nStride + (j+so)) = dwShadowColor; if( j + so + 1 < dwWidth ) *(pImgBuf32 + (i+so+1) * nStride + (j+so+1)) = dwShadowColor; } } } } } else if ( dwFlag & KTFLAG_SHADOW ) { //unsigned short wShadowColor = unsigned short((0xf << 12) | (0x4 << 8) | (0x4 << 4) | 0x4); //for(i = 0; i < dwHeight; ++i) //{ // WORD *pImg = (WORD*)&pBitmapBuffer[i*dwStride]; // for(unsigned int j = 0; j < dwWidth; ++j) // { // if( *pImg++ ) // *(pImgBuf16 + (i+1) * nStride + (j+1)) = wShadowColor; // } //} DWORD dwShadowColor = DWORD((0xff << 24) | (0x40 << 16) | (0x40 << 8) | 0x40); for(i = 0; i < dwHeight; ++i) { DWORD *pImg = (DWORD*)&pBitmapBuffer[i*dwStride]; for(unsigned int j = 0; j < dwWidth; ++j) { if( *pImg++ ) { if( i != dwHeight - 1 && j != dwWidth - 1 ) *(pImgBuf32 + (i+1) * nStride + (j+1)) = dwShadowColor; } } } } //unsigned short wTextColor = unsigned short((0xf << 12) | ((color.b>>4) << 8) | ((color.g>>4) << 4) | (color.r>>4)); //for(i = 0; i < dwHeight; ++i) //{ // WORD *pImg = (WORD*)&pBitmapBuffer[i*dwStride]; // for(unsigned int j = 0; j < dwWidth; ++j) // { // if( *pImg++ ) // *(pImgBuf16 + (i+textoffset) * nStride + (j+textoffset)) = wTextColor; // } //} for(i = 0; i < dwHeight; ++i) { DWORD *pImg = (DWORD*)&pBitmapBuffer[i*dwStride]; for(unsigned int j = 0; j < dwWidth; ++j) { if( *pImg++ ) { if( i + textoffset < dwHeight && j + textoffset < dwWidth ) { if( bRandomColor ) { dwTextColor = DWORD((0xFF << 24) | (GetNextRandColor() << 16) | (GetNextRandColor() << 8) | (GetNextRandColor())); } *(pImgBuf32 + (i+textoffset) * nStride + (j+textoffset)) = dwTextColor; } } else if( dwFlag & KTFLAG_INVERSE ) { if( i + textoffset + 3 < dwHeight && j + textoffset < dwWidth ) { *(pImgBuf32 + (i+textoffset) * nStride + (j+textoffset)) = 0xFFCDCDCD; } } } } m_spTexture->Unlock(); SelectObject(m_hDC, hFontOld); SelectObject(m_hDC, hBitmapOld); DeleteObject(hBmBitmap); } else { //SDEBUGLOG("KTextRender::KTextRender s_pFreeType->Draw - begin"); //SDEBUGLOG("\tKTextRender::KTextRender - text[%s], font[%s], %p", lpszText, lpszFontName, s_pFreeType); //SDEBUGLOG("\tKTextRender::KTextRender - %s, %s, %d, %d", strText.c_str(), lpszFontName, strText.size(), m_nDefaultCodePage); /*if( _CrtCheckMemory() == 0 ) SDEBUGLOG("_CrtCheckMemory - KTextRender::KTextRender s_pFreeType->Draw - begin");*/ // assert( _CrtCheckMemory() ); rcTexRect.left = 0; rcTexRect.top = 0; rcTexRect.right = dwWidth; rcTexRect.bottom = dwHeight; wchar_t *pBuffer = new wchar_t[ strText.size()+1 ]; // assert( _CrtCheckMemory() ); int len = ::MultiByteToWideChar( m_nDefaultCodePage, 0, strText.c_str(), strText.size(), pBuffer, strText.size() ); // assert( _CrtCheckMemory() ); pBuffer[len] = 0; // assert( _CrtCheckMemory() ); s_pFreeType->SetFontColor( color.b, color.g, color.r ); //순서에 문제가 n있음. s_pFreeType->SetEffectColor( color_fx.b, color_fx.g, color_fx.r );//순서에 문제가 있음. int nWidth, nHeight; // 폰트 이펙트 불일치는 일단 이렇게 땜빵. -_- int nFlag = 0;/*XFreeType::FT_SHADOW*/; if( dwFlag & KTFLAG_SHADOW ) nFlag = XFreeType::FT_SHADOW_LV1; if( dwFlag & KTFLAG_GLOW ) nFlag = XFreeType::FT_STROKE_LV2; if( dwFlag & KTFLAG_GLOW2X ) nFlag = XFreeType::FT_STROKE_LV3; // 2010. 8. 20 - marine 태그가 적용되지 않아서 추가 if( dwFlag & KTFLAG_OUTLINE) nFlag = XFreeType::FT_OUTLINE; if( dwFlag & KTFLAG_BOLD) nFlag = XFreeType::FT_BOLD; /*if( _CrtCheckMemory() == 0 ) SDEBUGLOG("_CrtCheckMemory - KTextRender::KTextRender s_pFreeType->Draw - 2");*/ // assert( _CrtCheckMemory() ); //SDEBUGLOG("\tKTextRender::KTextRender - text[%s], font[%s], %p, text_w[%ws]", lpszText, lpszFontName, s_pFreeType,pBuffer); //SDEBUGLOG("\tKTextRender::KTextRender - %s, %s, %d, %d", strText.c_str(), lpszFontName, len, m_nDefaultCodePage); // /* LPCSTR lpszText, KColor color, LPCSTR lpszFontName, int nSize, DWORD & dwWidth, DWORD & dwHeight, DWORD dwAlign, DWORD dwFlag, bool bS */ // assert( _CrtCheckMemory() ); const XAlphaImage *pImg = s_pFreeType->Draw( lpszFontName, pBuffer, &nWidth, &nHeight, nSize*m_fFreeTypeSizeRatio, nFlag, m_nFreeTypeYOffset, dwFlag & KTFLAG_UNDER, dwFlag & KTFLAG_INVERSE, false, pFontInfo->bHinting ); //SDEBUGLOG("KTextRender::KTextRender s_pFreeType->Draw - end"); delete [] pBuffer; if( pImg == NULL ) return; DWORD dwTexWidth = pImg->GetWidth(), dwTexHeight = pImg->GetHeight(); if (isSpriteScroll) /// 2011.02.23 - prodongi { dwTexWidth = dwWidth; bufferImgWidth = pImg->GetWidth(); bufferImgHeight = pImg->GetHeight(); } int nExpX, nExpY; K3DRenderDevice::GetSquareSize( dwTexWidth,dwTexHeight, nExpX, nExpY ); m_spTexture = m_pDevice->CreateTexture(nExpX, nExpY, K3DFMT_A8R8G8B8 ); if(m_spTexture == NULL) return; int nStride; //WORD * pImgBuf16 = NULL; char * pImgBuf32 = NULL; rcTexRect.left = 0; rcTexRect.top = 0; rcTexRect.right = dwTexWidth; rcTexRect.bottom = dwTexHeight; m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32),nStride); assert( pImgBuf32 && "m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32),nStride);"); if( !pImgBuf32 ) return; size_t nBufSize = pImg->GetWidth() * pImg->GetHeight(); const XAlphaImage::Pixel *p = pImg->GetBuffer(); int nSrcStride = pImg->GetWidth(); /// 2011.02.23 - prodongi DWORD* pDstColor; DWORD* pSrcColor; DWORD tempColor; for(UINT y = 0; y < rcTexRect.bottom; y++ ) { pDstColor = ( DWORD* )pImgBuf32; /// tex pSrcColor = ( DWORD* )p; /// img for( UINT x = 0; x < rcTexRect.right; x++ ) { if( bRandomColor ) { if( pSrcColor[x] != 0 ) { tempColor = pSrcColor[x]; pDstColor[x] = DWORD((0xFF000000 & tempColor) | (GetNextRandColor() << 16) | (GetNextRandColor() << 8) | (GetNextRandColor())); } else { if (x < nSrcStride) /// 2011.02.23 - prodongi pDstColor[x] = pSrcColor[x]; } } else { if (x < nSrcStride) /// 2011.02.23 - prodongi pDstColor[x] = pSrcColor[x]; } } pImgBuf32 += nStride; p += nSrcStride; } //memcpy( pImgBuf16, pImg->GetBuffer(), dwTexWidth*dwTexHeight*2 ); m_spTexture->Unlock(); } // 이제 Sprite에 Texture를 세팅해 주자 m_spResSprite->SetTexture(m_spTexture, &rcTexRect); m_prSprite->SetRes(m_spResSprite); if (isSpriteScroll) /// 2011.02.23 - prodongi { m_spTexture->SetTextOriImgRect(rcTexRect); m_spTexture->SetTextOriImgSize(bufferImgWidth, bufferImgHeight); m_prSprite->setScrollImgUv(bufferImgWidth, bufferImgHeight); } // Cache에도 등록 KTextCacheManager::GetInstance()->RegisterCache( strText.c_str(), color, lpszFontName, nSize, dwWidth, dwHeight, dwFlag, color_fx, m_spTexture); } #endif KTextRender::~KTextRender() { Clear(); } void KTextRender::Clear() { m_spResSprite->SetTexture( NULL, NULL ); m_prSprite->SetRes( NULL ); SAFE_DELETE(m_prSprite); SAFE_DELETE(m_pEmoticonLayerRender ); } void KTextRender::SetPosition( float fXPos, float fYPos, float fZPos) { m_prSprite->SetPosition(fXPos,fYPos,fZPos); if( m_pEmoticonLayerRender ) m_pEmoticonLayerRender->SetOffset( static_cast(fXPos), static_cast(fYPos) ); } void KTextRender::SetVisibility( float vis ) { m_prSprite->SetVisibility(vis); } void KTextRender::SetClipRect(const KRect & rcRect) { m_rcClipRect = rcRect; m_prSprite->SetClipRect(&m_rcClipRect); } void KTextRender::Render( KViewportObject *viewport, bool isFront/* = false*/ ) { viewport->Register(m_prSprite, isFront); if( m_pEmoticonLayerRender ) m_pEmoticonLayerRender->Render( viewport, isFront ); } #ifdef _COUNTRY_ME_ void KTextRender::InitTextRender( K3DRenderDevice * pDevice, int nCodePage, LPCTSTR strFontName ) { m_pDevice = pDevice; KFontManager::GetInstance()->Create( strFontName ); } void KTextRender::DestroyAll() { KFontManager::GetInstance()->Destroy(); } #else void KTextRender::InitTextRender( K3DRenderDevice * pDevice ) { m_pDevice = pDevice; m_hDC = CreateCompatibleDC( NULL ); SetMapMode( m_hDC, MM_TEXT ); if( !s_pFreeType->IsInitialized() ) s_pFreeType->Init(); //if( !s_pFreeType->Init() ) assert(0 && "KTextRender::InitTextRender - Init Failed!!" ); } void KTextRender::DestroyAll() { //SDEBUGLOG( "KTextRender::DestroyAll()" ); TEXT_FONT_INFO* info; bool res = m_mapFontInfo.get_first_value( info ); while ( res ) { delete info; res = m_mapFontInfo.get_next_value( info ); } m_mapFontInfo.clear(); s_pFreeType->DeInit(); delete s_pFreeType; s_pFreeType = NULL; DeleteDC(m_hDC); } #endif int KTextRender::GetFontHeight( int nFontSize ) { return (int)(nFontSize*1.5f); } void KTextRender::GetStringSize(LPCSTR lpszFontName, int nFontSize, BOOL bBold, LPCSTR lpszString, int nStringLen, DWORD *pStringWidth, DWORD * pStringHeight) { TEXT_FONT_INFO * pInfo = _FindFont(lpszFontName, nFontSize); if( pInfo && pInfo->bIsFreeType && m_bIncreaseEnglishFontSize ) nFontSize = incSizeIfNoMultiByte( lpszString, nFontSize ); std::string strString( lpszString ); for( size_t i = 0; i < strString.size(); ++i ) { if( strString[i] == 0x1E ) strString[i] = '<'; if( strString[i] == 0x1F ) strString[i] = '>'; } if( pInfo == NULL ) { if( strlen(lpszFontName) > 0 ) { KTextRender::AddFont(lpszFontName,nFontSize); pInfo = _FindFont(lpszFontName, nFontSize); } } // lenahyang 2012.09.06 if( pInfo == NULL ) { pInfo = _FindFont( "default", nFontSize ); if( pInfo == NULL ) { *pStringWidth = 0; *pStringHeight = 0; return; } } assert( pInfo && "TEXT_FONT_INFO == NULL 여기 어쩌다 들어 오는데 고치시오~" ); if( pInfo && pInfo->bIsFreeType ) { // assert( _CrtCheckMemory() ); //SDEBUGLOG("KTextRender::GetStringSize - begin (bIsFreeType)"); //SDEBUGLOG("\tKTextRender::GetStringSize - %p, %s, %d, %s, %d",s_pFreeType, lpszFontName, nFontSize, lpszString, nStringLen); wchar_t *pBuffer = new wchar_t[ nStringLen+1 ]; // assert( _CrtCheckMemory() ); int len = ::MultiByteToWideChar( m_nDefaultCodePage, 0, strString.c_str(), nStringLen, pBuffer, nStringLen ); // assert( _CrtCheckMemory() ); pBuffer[len] = 0; // assert( _CrtCheckMemory() ); // 2010.07.20 - prodongi if( !s_pFreeType->GetSize( lpszFontName, pBuffer, (int*)pStringWidth, (int*)pStringHeight, nFontSize*m_fFreeTypeSizeRatio, pInfo->bHinting ) ) //if( !s_pFreeType->GetSize( lpszFontName, pBuffer, (int*)pStringWidth, (int*)pStringHeight, nFontSize*m_fFreeTypeSizeRatio ) ) { //SDEBUGLOG("\tKTextRender::GetStringSize - end1"); *pStringWidth = 0; *pStringHeight = 0; delete [] pBuffer; //SDEBUGLOG("KTextRender::GetStringSize - end1.end"); return; } //SDEBUGLOG("\tKTextRender::GetStringSize - end2"); (*pStringHeight) = GetFontHeight( nFontSize ); delete [] pBuffer; //SDEBUGLOG("KTextRender::GetStringSize - end2.end"); return; } WIN32_TEXT_FONT_INFO *pWin32Info = (WIN32_TEXT_FONT_INFO *)pInfo; HFONT hFontOld; if(bBold) { hFontOld = (HFONT)::SelectObject(m_hDC,pWin32Info->hBoldFont); } else hFontOld = (HFONT)::SelectObject(m_hDC, pWin32Info->hDefaultFont); SIZE size; GetTextExtentPoint32( m_hDC, strString.c_str(), nStringLen, &size ); *pStringWidth = size.cx; *pStringHeight = size.cy; } void KTextRender::SetFontHinting( LPCSTR lpszFontName, bool bHinting ) { TEXT_FONT_INFO* pFontInfo = _FindFont( lpszFontName, -1 ); if ( pFontInfo ) pFontInfo->SetHinting( bHinting ); } bool KTextRender::AddFreeTypeFont( LPCSTR lpszFontName, LPCSTR lpszFontFileName ) { // 이미 Load한 Font는 Add할 필요가 없다. if(_FindFont(lpszFontName,-1) ) { return true; } bool rSuc; FREETYPE_TEXT_FONT_INFO *pInfo = new FREETYPE_TEXT_FONT_INFO( lpszFontName, lpszFontFileName, &rSuc ); if(rSuc) { // SDEBUGLOG( "AddFreeTypeFont : %s %s\n", lpszFontName, lpszFontFileName ); hashPr_font::Key key( lpszFontName, -1 ); m_mapFontInfo.add( key, pInfo ); } else { SAFE_DELETE(pInfo); } return rSuc; } void KTextRender::AddFont(LPCSTR lpszFontName, int nFontSize ) { // 이미 Load한 Font는 Add할 필요가 없다. if(_FindFont(lpszFontName,nFontSize) ) { return; } #ifdef _COUNTRY_TL_ DWORD iCharSet = THAI_CHARSET; #else DWORD iCharSet = DEFAULT_CHARSET; #endif WIN32_TEXT_FONT_INFO * pInfo = WIN32_TEXT_FONT_INFO::CreateTextFont(); int nHeight = -MulDiv( nFontSize, (INT)(GetDeviceCaps(m_hDC, LOGPIXELSY)), 72 ); // 미리 폰트를 생성하자. pInfo->hDefaultFont = ::CreateFont( nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, iCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, lpszFontName ); int nCWeight = FW_BOLD; //일본 비스타 버전에서 BOLD 폰트가 깨지는 문제가 발생.. 뭐냐!!! if( s_bIsOsVista && ( s_strLocale.length() > 0 && _stricmp( s_strLocale.c_str(), "Shift-JIS" ) == 0 ) ) nCWeight = FW_SEMIBOLD; pInfo->hBoldFont = ::CreateFont(nHeight,0,0,0,nCWeight, FALSE, FALSE, FALSE, iCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, lpszFontName ); pInfo->hUnderLineFont = ::CreateFont( nHeight, 0, 0, 0, FW_NORMAL, FALSE, TRUE, FALSE, iCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, lpszFontName); pInfo->hStrikeOutFont = ::CreateFont( nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, TRUE, iCharSet, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, lpszFontName); hashPr_font::Key key( lpszFontName, nFontSize ); m_mapFontInfo.add( key, pInfo ); //_oprint( "AddFont : %s %d\t\n", lpszFontName, nFontSize ); //#ifdef _DEBUG // const char* pTempText = "abc defg, hijklmn"; // DWORD nW, nH; // GetStringSize( lpszFontName, nFontSize, false, pTempText, strlen(pTempText), &nW, &nH ); // _oprint( "Text Len : [%d] [%d] %s\n", nW, nH, pTempText ); //#endif return; } KTextRender::TEXT_FONT_INFO * KTextRender::_FindFont(LPCSTR lpszFontName, int nFontSize) { if( strlen( lpszFontName ) <= 0 ) return NULL; TEXT_FONT_INFO* info; hashPr_font::Key key( lpszFontName, nFontSize ); if ( m_mapFontInfo.lookup( key, info ) ) { return info; } return NULL; } // MIMI 2005/08/10 void KTextRender::CheckEmoticon( std::string & strText, LPCSTR lpszFontName, int nFontSize, DWORD dwFlag, DWORD & dwWidth, DWORD & dwHeight, bool bStaticSize, float fZPos ) { //_LEAK_SUN SAFE_DELETE( m_pEmoticonLayerRender ); m_pEmoticonLayerRender = new KTextEmoticonRender; // [MEMORY_LEAK] 2012. 3. 2 - marine 메모리 해제해줌.. m_pEmoticonLayerRender->CheckEmoticon( strText, lpszFontName, nFontSize, dwFlag, dwWidth, dwHeight, bStaticSize, fZPos ); } const int KTextRender::GetTextSize( const char* szBuf ) { // 이모티콘 필터링 한 후 글자수 리턴 //return m_pEmoticonLayerRender->GetTextSize(szBuf); return KTextEmoticonRender::GetTextSize(szBuf); } void KTextRender::GetEmoticonFilterText( std::string & strBuf ) { KTextEmoticonRender::GetText( strBuf ); } // KDebugRenderer Implement KDebugRenderer *KDebugRenderer::s_pDebugRenderer = NULL; KDebugRenderer::KDebugRenderer() { m_vPosition = K3DVector(0.0f,0.0f,KDRE_RENDER_LAYER); } void KDebugRenderer::Clear() { for(unsigned int i = 0;i < m_vtDebugItem.size(); ++i) { m_vtDebugItem.at(i).Destroy(); } m_vtDebugItem.clear(); } KDebugRenderer & KDebugRenderer::GetInstance() { static KDebugRenderer debugObj; return debugObj; } void KDebugRenderer::Render(KViewportObject * pViewport, DWORD flag, const K3DMatrix * pAttachMat ) { float fYPos = m_vPosition.y; for(unsigned int i = 0; i GetHeight(); } } } bool KDebugRenderer::AddDebugItem(LPCSTR lpszDebugName, LPCSTR lpszDebugInfo) { if( _FindDebugItem(lpszDebugName) != -1) return false; DEBUG_ITEM item; item.SetDebugInfo(lpszDebugName, lpszDebugInfo); m_vtDebugItem.push_back(item); return true; } bool KDebugRenderer::AddDebugItem(LPCSTR lpszDebugName, double DebugInfo) { char buff[512]; sprintf(buff,"%.1f", DebugInfo); return AddDebugItem(lpszDebugName, buff); } bool KDebugRenderer::RemoveDebugItem(LPCSTR lpszDebugName) { int nIndex = _FindDebugItem(lpszDebugName); if(nIndex < 0) return false; m_vtDebugItem.at(nIndex).Destroy(); m_vtDebugItem.erase(m_vtDebugItem.begin() + nIndex); return true; } bool KDebugRenderer::ModifyDebugItem(LPCSTR lpszDebugName, LPCSTR lpszDebugInfo) { int nIndex = _FindDebugItem(lpszDebugName); if(nIndex < 0) return false; m_vtDebugItem.at(nIndex).SetDebugInfo(lpszDebugName, lpszDebugInfo); return true; } bool KDebugRenderer::ModifyDebugItem(LPCSTR lpszDebugName, double DebugInfo) { char buff[512]; sprintf(buff,"%.1f", DebugInfo); return ModifyDebugItem(lpszDebugName, buff); } int KDebugRenderer::_FindDebugItem(LPCSTR lpszDebugName) { for(unsigned int i = 0; i < m_vtDebugItem.size(); ++i) { if(m_vtDebugItem.at(i).sDebugName == lpszDebugName) return i; } return -1; } void KDebugRenderer::DEBUG_ITEM::Destroy() { SAFE_DELETE(pTextPharse); } void KDebugRenderer::DEBUG_ITEM::SetDebugInfo(LPCSTR lpszDebugName, LPCSTR lpszDebugInfo) { sDebugName = lpszDebugName; SAFE_DELETE(pTextPharse); DWORD dwWidth =512; KSize size = KTextPhrase::GetStringSize(lpszDebugInfo, dwWidth); if(size.width == 0 || size.height == 0) return; pTextPharse = new KTextPhrase(size.width, size.height); #ifdef _COUNTRY_ME_ pTextPharse->SetAlign(KTextParagraph::KTALIGN_LEFT | KTextParagraph::KTALIGN_TOP); #else pTextPharse->SetAlign(KTextRender::KTALIGN_LEFT | KTextRender::KTALIGN_TOP); #endif pTextPharse->AddString( lpszDebugInfo); } void KDebugRenderer::DEBUG_ITEM::SetPosition(float fXPos, float fYPos, float fZPos) { if(pTextPharse) { pTextPharse->SetPosition(fXPos,fYPos,fZPos); } } void KDebugRenderer::DEBUG_ITEM::Render(KViewportObject * pViewportObject) { if(pTextPharse) { pTextPharse->Render(pViewportObject); } } //추가 int KTextRender::CalcCarretPos( const char *szAlias, const wchar_t *wszString, int x,int nFontSize, int ft ) { // assert( _CrtCheckMemory() ); return KTextRender::s_pFreeType->CalcCarretPos(szAlias, nFontSize, ft,wszString, x ); } void KTextRender::GetFreeTypeTextWidth( const wchar_t *text, size_t len, LPSIZE lpSize ) { lpSize->cx = 0; lpSize->cy = 13; // assert( _CrtCheckMemory() ); KTextRender::s_pFreeType->GetSize( KTextRender::KDEFAULT_FONT_NAME, text, (int*)&lpSize->cx, NULL, 13 ); } // 2010.05.06 - prodongi void KTextRender::modifyEmoticonSize(std::string const& aniName, int width, int height) { if (!m_pEmoticonLayerRender) return ; m_pEmoticonLayerRender->modifyEmoticonSize(aniName, width, height); } void KTextRender::setSpriteScroll(bool scroll, DWORD type, float v, float margin) /// 2011.01.18 - prodongi { m_prSprite->initScroll(scroll, type, v, margin); } #ifdef _COUNTRY_ME_ BYTE Get5x5FilteredAlphaValue( LPBYTE pSrc, int x, int y, int w, int h, int nStride ) { static double dWeight[5][5] = { { 0.0, 0.1, 0.2, 0.1, 0.0 }, { 0.1, 0.3, 0.5, 0.3, 0.1 }, { 0.2, 0.5, 0.7, 0.5, 0.2 }, { 0.1, 0.3, 0.5, 0.3, 0.1 }, { 0.0, 0.1, 0.2, 0.1, 0.0 } }; double dAlpha = 0.; LPDWORD pdwValue; KColor color; for ( int i = -2; i < 3; ++i ) { if ( y + i >= 0 && y + i < h ) { for ( int j = -2; j < 3; ++j ) { if ( x + j >= 0 && x + j < w ) { pdwValue = (LPDWORD)(pSrc + (x + j) * 4 + (y + i) * nStride); color = *pdwValue; dAlpha += color.a * dWeight[i + 2][j + 2]; } } } } if ( dAlpha > 255 ) dAlpha = 255; return (BYTE)(dAlpha); } void BitBlt_Premultiplied2Nonmultiplied( LPVOID pSrc, LPVOID pDst, int nWidth, int nHeight, int nSrcStride, int nDstStride, bool bGlow ) { LPBYTE pbSrc = (LPBYTE)pSrc; LPBYTE pbDst = (LPBYTE)pDst; LPDWORD pdwSrc, pdwDst; KColor pxSrc, pxDst; int x, y; if ( bGlow ) { for ( y = 0; y < nHeight; y++ ) { pdwDst = (DWORD *)pbDst; for( x = 0; x < nWidth; x++ ) { BYTE bAlpha = Get5x5FilteredAlphaValue( pbSrc, x, y, nWidth, nHeight, nSrcStride ); if ( bAlpha > 0 ) { pxDst.a = bAlpha; pxDst.g = 0; pxDst.b = 74; pxDst.r = 128; *pdwDst++ = pxDst.color; } else *pdwDst++ = 0; } pbDst += nDstStride; } } pbSrc = (LPBYTE)pSrc; pbDst = (LPBYTE)pDst; for ( y = 0; y < nHeight; y++ ) { pdwSrc = (DWORD *)pbSrc; pdwDst = (DWORD *)pbDst; for( x = 0; x < nWidth; x++ ) { pxSrc.color = *pdwSrc++; if ( pxSrc.a > 0 ) { pxDst.r = pxSrc.r * 255 / pxSrc.a; pxDst.g = pxSrc.g * 255 / pxSrc.a; pxDst.b = pxSrc.b * 255 / pxSrc.a; pxDst.a = pxSrc.a; *pdwDst++ = pxDst.color; } else *pdwDst++; } pbSrc += nSrcStride; pbDst += nDstStride; } } KTextRender::KTextRender( KTextParagraph* pString, DWORD dwWidth, DWORD dwHeight, DWORD dwLineGap, DWORD dwAlign, bool bRandomColor ) : m_dwWidth( dwWidth ), m_dwHeight( dwHeight ), m_pEmoticonLayerRender( 0 ) { // InitTextRender가 불려지지 않았으므로 if(!m_pDevice) { assert(false && "please call InitTextRender"); } m_prSprite = new KSpritePrimitive(false); m_spResSprite = new KResSprite; if ( dwWidth == 0 || dwHeight == 0 ) return; DWORD dwOldHeight = dwHeight; m_spTexture = KTextCacheManager::GetInstance()->FindCache( pString->GetString().c_str(), pString->GetAttr()->dwColor, pString->GetAttr()->strFontName.c_str(), pString->GetAttr()->nFontSize, dwWidth, dwHeight, pString->GetAttrHash(), pString->GetAttr()->bShadow + pString->GetAttr()->bBold * 2); if (m_spTexture != NULL) { m_spResSprite->SetTexture(m_spTexture, NULL); m_prSprite->SetRes(m_spResSprite); return; } // 2010.09.07 왜 주석 처리가 되어 있나??? - prodongi KTextLayout layout( dwWidth, dwHeight, dwLineGap, dwAlign ); layout.Render( pString ); int nStride; char * pImgBuf32 = NULL; KRect rcTexRect; rcTexRect.left = 0; rcTexRect.top = 0; rcTexRect.right = dwWidth; rcTexRect.bottom = dwHeight; m_spTexture = m_pDevice->CreateTexture(dwWidth,dwHeight, K3DFMT_A8R8G8B8 ); assert( m_spTexture && "m_spTexture = m_pDevice->CreateTexture(dwTexWidth,dwTexHeight, K3DFMT_A8R8G8B8 )"); if(m_spTexture == NULL) return; m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32), nStride); assert( pImgBuf32 && "m_spTexture->LockRect(&rcTexRect, reinterpret_cast(&pImgBuf32),nStride);"); if( !pImgBuf32 ) return; // 2010.09.07 왜 주석 처리가 되어 있나??? - prodongi BitBlt_Premultiplied2Nonmultiplied( layout.GetImage(), pImgBuf32, dwWidth, dwHeight, layout.GetImageStride(), nStride, pString->GetAttr()->bGlow ); m_spTexture->Unlock(); m_spResSprite->SetTexture(m_spTexture, &rcTexRect); m_prSprite->SetRes(m_spResSprite); KTextCacheManager::GetInstance()->RegisterCache( pString->GetString().c_str(), pString->GetAttr()->dwColor, pString->GetAttr()->strFontName.c_str(), pString->GetAttr()->nFontSize, dwWidth, dwHeight, pString->GetAttrHash(), pString->GetAttr()->bShadow + pString->GetAttr()->bBold * 2, m_spTexture); } #endif