#include "stdafx.h" #include "KTextEmoticonRender.h" #include "KViewport.h" #include "KPrimitiveSprite.h" #include "KResourceManager.h" #include #include "KTextRender.h" namespace { const int g_nEmoticonFilterOffset = 3; }; ////////////////////////////////////////////////////////////////////////// // KTextEmoticon KTextEmoticon::KTextEmoticon( int nType, int nOffsetX, int nOffsetY, int nWidth, int nHeight, const char* szAniName, const char* szSprName, float fZPos ) : m_nType( nType ) , m_nOffsetX( nOffsetX ) , m_nOffsetY( nOffsetY ) , m_nWidth( nWidth ) , m_nHeight( nHeight ) , m_strAniName( szAniName ) , m_strSprName( szSprName ) , m_pPrimitive( NULL ) , m_rcRegion( KRect(0, 0, 0, 0) ) , m_fZPos(fZPos) { } KTextEmoticon::~KTextEmoticon() { SAFE_DELETE(m_pPrimitive); } bool KTextEmoticon::Initialize( bool bStaticSize ) { if( m_pPrimitive ) SAFE_DELETE(m_pPrimitive); m_pPrimitive = new KSpritePrimitive; KResSprite* pRes = KSpriteManager::GetManager()->GetSpriteSet(m_strSprName.c_str())->GetSpriteRes( m_strAniName.c_str(), 0 ); if( pRes == NULL || pRes->GetTexture() == NULL ) { std::string strMsg; XStringUtil::Format( strMsg, "SetEmoticon:: emoticon 생성 실패 : spr-%s, ani-%s", m_strSprName.c_str(), m_strAniName.c_str() ); assert( 0 && strMsg.c_str() ); SAFE_DELETE(m_pPrimitive); return false; } // 원본 이미지의 크기를 따른다 if( !bStaticSize ) { m_nWidth = pRes->GetSourceRect().GetWidth(); m_nHeight = pRes->GetSourceRect().GetHeight(); } m_pPrimitive->SetRes( pRes ); m_pPrimitive->SetTargetSize( (float)m_nWidth, (float)m_nHeight ); m_pPrimitive->SetPosition( K3DVector(0, 0, m_fZPos ) ); return true; } void KTextEmoticon::SetOffset( int nX, int nY ) { m_rcRegion.left = m_nOffsetX + nX; m_rcRegion.top = m_nOffsetY + nY; m_rcRegion.right = m_rcRegion.left + m_nWidth; m_rcRegion.bottom = m_rcRegion.top + m_nHeight; if( m_pPrimitive ) m_pPrimitive->SetPosition( static_cast(m_rcRegion.left), static_cast(m_rcRegion.top), m_fZPos ); } void KTextEmoticon::Render( KViewportObject* pViewport, bool bIsFront ) { if( m_pPrimitive == NULL ) return; pViewport->Register( m_pPrimitive, bIsFront ); } // 2010.05.06 - prodongi void KTextEmoticon::setSize(std::string const& aniName, int width, int height) { if (width < 0 && height < 0) return ; if (m_strAniName != aniName) return ; if (width > 0) m_nWidth = width; if (height > 0) m_nHeight = height; m_pPrimitive->SetTargetSize( (float)m_nWidth, (float)m_nHeight ); } ////////////////////////////////////////////////////////////////////////// // KTextEmoticonRender std::vector< EMOTICON_DATA > KTextEmoticonRender::s_vFilterList; std::string KTextEmoticonRender::s_strSprName; KTextEmoticonRender::~KTextEmoticonRender() { Clear(); } void KTextEmoticonRender::Clear() { //_LEAK_SUN //s_vFilterList.clear(); //이거하믄 이모티콘 안나옴. std::vector::iterator it = m_vecEmoticonList.begin(); while( it != m_vecEmoticonList.end() ) { SAFE_DELETE(*it); ++it; } m_vecEmoticonList.clear(); } void KTextEmoticonRender::Render( KViewportObject* pViewport, bool bIsFront ) { if( m_vecEmoticonList.empty() ) return; std::vector::iterator it = m_vecEmoticonList.begin(); while( it != m_vecEmoticonList.end() ) { (*it)->Render( pViewport, bIsFront ); it++; } } void KTextEmoticonRender::CheckEmoticon( std::string & strText, const char* szFontName, int nFontSize, DWORD dwFlag, DWORD & dwWidth, DWORD & dwHeight, bool bStaticSize, float fZPos ) { Clear(); m_bStaticSize = bStaticSize; //for( int i = 0; g_szEmoticonFilter[i] != NULL; i++ ) // CheckFiltering( g_szEmoticonFilter[i], strText, szFontName, nFontSize, dwFlag, dwWidth ); // 텍스트 처음부터 끝까지 읽으면서 필터링 한다. std::string str = strText; size_t begin_pos = 0; for( size_t pos = 0; pos <= str.size(); ) { std::string strTemp = str.substr( begin_pos, pos-begin_pos ); if( strTemp.empty() ) { pos++; continue; } const char* szFilter = GetExistFilter( strTemp.c_str() ); if( szFilter ) { CheckFiltering( szFilter, strText, szFontName, nFontSize, dwFlag, dwWidth, dwHeight, fZPos ); begin_pos = pos; } pos++; } } const char* KTextEmoticonRender::GetExistFilter( const char* szText ) { std::string strText = szText; for( unsigned int i = 0; s_vFilterList.size()>i; i++ ) { if( strText.find( s_vFilterList[i].strFilter.c_str() ) != strText.npos ) return s_vFilterList[i].strFilter.c_str(); } return NULL; } void KTextEmoticonRender::CheckFiltering( const char* szFilter, std::string & strText, const char* szFontName, int nFontSize, DWORD dwFlag, DWORD & dwWidth, DWORD & dwHeight, float fZPos ) { size_t pos = strText.find(szFilter); if( pos == strText.npos ) return; size_t emoticon_delta = 2; if( !m_bStaticSize ) emoticon_delta = 4; const char *pEmotionAniName = NULL; for( size_t i = 0; s_vFilterList.size()>i; i++ ) { if( s_vFilterList[i].strFilter.find( szFilter ) != strText.npos ) { pEmotionAniName = s_vFilterList[i].strAniName.c_str(); break; } } for( pos = 0; pos != strText.npos; ) { pos = strText.find( szFilter, pos ); if( pos == strText.npos ) break; else { // 이모티콘 자리만 남기고 나머지 텍스트는 지워주어야 한다. // ex) "하하하" 를 하나의 이모티콘으로 처리할 경우, "하"만 남기고 하하는 지워주어야 한다. size_t size_offset = ::strlen(szFilter); if( size_offset > emoticon_delta ) strText.erase( pos+emoticon_delta, size_offset-emoticon_delta ); else if( size_offset < emoticon_delta ) { size_t temp = size_offset; while( emoticon_delta-temp > 0 ) { strText.insert( pos+size_offset, "^", 1 ); ++temp; } } std::string str; str = strText.substr( 0, pos ); // 이모티콘 pos 구한다. // 이모티콘 필터 텍스트 직전까지의 텍스쳐 크기가 pos 이다. DWORD dwStringWidth, dwStringHeight; dwStringWidth = 0; dwStringHeight = 0; bool bBold = dwFlag & KTextRender::KTFLAG_BOLD; KTextRender::GetStringSize( szFontName, nFontSize, bBold, str.c_str(), static_cast(str.size()), &dwStringWidth, &dwStringHeight ); // 이모티콘의 크기는 폰트 크기로부터 여분을 더한 크기. // g_nEmoticonFilterOffset 을 조정하면 이모티콘 크기 조정 가능 int nEmoticonSize = nFontSize + g_nEmoticonFilterOffset; // 이모티콘 타입 임시로 int nEmoticonType = KTextEmoticon::TYPE_NORMAL; /* if( ::_stricmp(szFilter, g_szEmoticonFilter[5]) == 0 || ::_stricmp(szFilter, g_szEmoticonFilter[6]) == 0 ) nEmoticonType = KTextEmoticon::TYPE_HARMFUL; */ // end 이모티콘 타입 임시 KTextEmoticon* pEmoticon = new KTextEmoticon( nEmoticonType, dwStringWidth, 0, nEmoticonSize, nEmoticonSize, pEmotionAniName, s_strSprName.c_str(), fZPos ); if( !pEmoticon->Initialize( m_bStaticSize ) ) { pos += emoticon_delta; delete pEmoticon; continue; } m_vecEmoticonList.push_back( pEmoticon ); // 필터 텍스트의 크기를 알아낸다. // 이부분은 미리 가지고 있어도 좋다 DWORD dwFilterWidth; DWORD dwFilterHeight; KTextRender::GetStringSize( szFontName, nFontSize, bBold, szFilter, static_cast(::strlen(szFilter)), &dwFilterWidth, &dwFilterHeight ); // 필터 텍스트 크기 만큼 전체 텍스트 텍스쳐에서 빼주어서 전체 텍스트 텍스쳐 크기 보정한다. int nCheckWidth = dwWidth; nCheckWidth -= dwFilterWidth; if( nCheckWidth < 0 ) nCheckWidth = 0; dwWidth = nCheckWidth; if( m_bStaticSize ) { dwWidth += nEmoticonSize; strText.replace( pos, emoticon_delta, " " ); } else { /// 2011.05.11 redmine #15 strText가 바뀌면서 width가 변해 버리기 때문에, 다시 계산해 줘야 된다. - prodongi DWORD h; strText.replace( pos, emoticon_delta, " " ); dwHeight = pEmoticon->GetHeight(); KTextRender::GetStringSize( szFontName, nFontSize, bBold, strText.c_str(), strText.length(), &dwWidth, &h ); } break; } pos += emoticon_delta; } } void KTextEmoticonRender::SetOffset( int nOffsetX, int nOffsetY ) { if( m_vecEmoticonList.empty() ) return; std::vector::iterator it = m_vecEmoticonList.begin(); while( it != m_vecEmoticonList.end() ) { (*it)->SetOffset( nOffsetX, nOffsetY ); it++; } } const int KTextEmoticonRender::GetTextSize( const char* szBuf ) { if( szBuf == NULL ) return -1; std::string str = szBuf; size_t size_text = str.size(); size_t begin_pos = 0; for( size_t pos = 0; pos <= str.size(); ) { std::string strTemp = str.substr( begin_pos, pos-begin_pos ); if( strTemp.empty() ) { pos++; continue; } const char* szFilter = GetExistFilter( strTemp.c_str() ); if( szFilter ) { size_t size_offset = ::strlen(szFilter); if( size_offset > 2 ) size_text -= (size_offset-2); begin_pos = pos; } pos++; } return static_cast(size_text); } void KTextEmoticonRender::GetText( std::string & strBuf ) { if( strBuf.empty() ) return; //Emoticon symbol text 삭제 for( size_t i = 0; s_vFilterList.size()>i; i++ ) { while( true ) { size_t pos = strBuf.find( s_vFilterList[i].strFilter.c_str() ); if( pos == strBuf.npos ) break; size_t offset = ::strlen(s_vFilterList[i].strFilter.c_str()); if( offset > 1 ) strBuf.erase( pos, offset ); } } } void KTextEmoticonRender::SetSprName( const char * pSprName ) { s_strSprName = pSprName; } void KTextEmoticonRender::AddFilter( const char * pFilter, const char * pAniName ) { assert( strlen(pFilter)>0 && "Filter Name Invalid Length" ); assert( strlen(pAniName)>0 && "Ani Name Invalid Length" ); EMOTICON_DATA emoticon_data; emoticon_data.strFilter = pFilter; emoticon_data.strAniName = pAniName; s_vFilterList.push_back( emoticon_data ); } void KTextEmoticonRender::ClearFilter() { s_vFilterList.clear(); } bool KTextEmoticonRender::FindFilter( std::string & strText ) { for( unsigned int i(0); s_vFilterList.size()>i; i++ ) { size_t pos = strText.find( s_vFilterList[i].strFilter.c_str() ); if( pos != strText.npos ) return true; } return false; } // 2010.05.06 - prodongi void KTextEmoticonRender::modifyEmoticonSize(std::string const& aniName, int width, int height) { std::vector::iterator it = m_vecEmoticonList.begin(); for (; it != m_vecEmoticonList.end(); ++it) { (*it)->setSize(aniName, width, height); } }