Files
Leviathan/Client/Game/engine/Ui/KTextEmoticonRender.cpp
T
2026-06-01 12:46:52 +02:00

385 lines
10 KiB
C++

#include "stdafx.h"
#include "KTextEmoticonRender.h"
#include "KViewport.h"
#include "KPrimitiveSprite.h"
#include "KResourceManager.h"
#include <toolkit/XStringUtil.h>
#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<float>(m_rcRegion.left), static_cast<float>(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<KTextEmoticon*>::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<KTextEmoticon*>::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<int>(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<int>(::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<KTextEmoticon*>::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<int>(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<KTextEmoticon*>::iterator it = m_vecEmoticonList.begin();
for (; it != m_vecEmoticonList.end(); ++it)
{
(*it)->setSize(aniName, width, height);
}
}