207 lines
5.5 KiB
C++
207 lines
5.5 KiB
C++
#include "EngineFrame/Component/Text.h"
|
||
#include "Text.h"
|
||
#include "EngineCore/Game.h"
|
||
Text::Text()
|
||
{
|
||
}
|
||
|
||
Text::Text(std::string Str, TTF_Font *font, SDL_Color color)
|
||
{
|
||
m_text = Str;
|
||
m_font = font;
|
||
m_text_color = color;
|
||
Init(Str, font, color);
|
||
}
|
||
|
||
Text::Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||
{
|
||
m_text = Str;
|
||
m_font = font;
|
||
m_text_color = textColor;
|
||
m_stroke_color = strokeColor;
|
||
m_stroke_size = strokeSize;
|
||
Init(Str, font, textColor, strokeColor, strokeSize);
|
||
}
|
||
|
||
Text::~Text()
|
||
{
|
||
}
|
||
|
||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color color)
|
||
{
|
||
// 标记该组件需要渲染和更新
|
||
addTag(Tag::RENDER);
|
||
addTag(Tag::UPDATE);
|
||
|
||
// TTF_SetFontOutline(font, 1);
|
||
// 先渲染为表面
|
||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color);
|
||
if (!textSurface)
|
||
{
|
||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||
}
|
||
// 再将表面转换为纹理
|
||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||
m_texture = SDL_CreateTextureFromSurface(renderer, textSurface);
|
||
if (!m_texture)
|
||
{
|
||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||
}
|
||
// 设置纹理过滤模式为最近邻,避免缩放模糊
|
||
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
|
||
Size.x = textSurface->w;
|
||
Size.y = textSurface->h;
|
||
TextureSize.x = textSurface->w;
|
||
TextureSize.y = textSurface->h;
|
||
|
||
// 释放表面
|
||
SDL_FreeSurface(textSurface);
|
||
}
|
||
|
||
void Text::Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize)
|
||
{
|
||
// 先保存原始字体的轮廓设置
|
||
int originalOutline = TTF_GetFontOutline(font);
|
||
|
||
// 设置字体轮廓大小(描边宽度)
|
||
TTF_SetFontOutline(font, strokeSize);
|
||
|
||
// 渲染描边(使用描边颜色)
|
||
SDL_Surface *strokeSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), strokeColor);
|
||
if (!strokeSurface)
|
||
{
|
||
SDL_LogError(0, "描边渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||
return;
|
||
}
|
||
|
||
// 恢复字体轮廓设置,用于渲染文字本身
|
||
TTF_SetFontOutline(font, 0);
|
||
|
||
// 渲染文字本身(使用文字颜色)
|
||
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), textColor);
|
||
if (!textSurface)
|
||
{
|
||
SDL_LogError(0, "文字渲染为表面失败!TTF_Error:%s", TTF_GetError());
|
||
SDL_FreeSurface(strokeSurface);
|
||
TTF_SetFontOutline(font, originalOutline); // 恢复原始设置
|
||
return;
|
||
}
|
||
|
||
// 创建一个合并描边和文字的表面
|
||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||
|
||
// 计算最终纹理大小(描边会增加额外尺寸)
|
||
int finalWidth = strokeSurface->w;
|
||
int finalHeight = strokeSurface->h;
|
||
|
||
// 创建一个临时表面用于合并描边和文字
|
||
SDL_Surface *finalSurface = SDL_CreateRGBSurfaceWithFormat(
|
||
0, finalWidth, finalHeight, 32, SDL_PIXELFORMAT_RGBA32);
|
||
if (!finalSurface)
|
||
{
|
||
SDL_LogError(0, "创建最终表面失败!SDL_Error:%s", SDL_GetError());
|
||
SDL_FreeSurface(textSurface);
|
||
SDL_FreeSurface(strokeSurface);
|
||
TTF_SetFontOutline(font, originalOutline);
|
||
return;
|
||
}
|
||
|
||
// 将描边绘制到最终表面
|
||
SDL_Rect strokeRect = {0, 0, strokeSurface->w, strokeSurface->h};
|
||
SDL_BlitSurface(strokeSurface, nullptr, finalSurface, &strokeRect);
|
||
|
||
// 计算文字在描边中间的位置
|
||
SDL_Rect textRect = {
|
||
strokeSize, // X偏移(描边宽度)
|
||
strokeSize, // Y偏移(描边宽度)
|
||
textSurface->w,
|
||
textSurface->h};
|
||
SDL_BlitSurface(textSurface, nullptr, finalSurface, &textRect);
|
||
|
||
// 将合并后的表面转换为纹理
|
||
m_texture = SDL_CreateTextureFromSurface(renderer, finalSurface);
|
||
if (!m_texture)
|
||
{
|
||
SDL_LogError(0, "表面转换为纹理失败!SDL_Error:%s", SDL_GetError());
|
||
}
|
||
|
||
// 设置尺寸信息
|
||
Size.x = finalSurface->w;
|
||
Size.y = finalSurface->h;
|
||
TextureSize.x = finalSurface->w;
|
||
TextureSize.y = finalSurface->h;
|
||
|
||
// 释放所有临时表面
|
||
SDL_FreeSurface(textSurface);
|
||
SDL_FreeSurface(strokeSurface);
|
||
SDL_FreeSurface(finalSurface);
|
||
|
||
// 恢复字体原始轮廓设置
|
||
TTF_SetFontOutline(font, originalOutline);
|
||
}
|
||
|
||
void Text::HandleEvents(SDL_Event *e)
|
||
{
|
||
}
|
||
|
||
void Text::Update(float deltaTime)
|
||
{
|
||
}
|
||
|
||
void Text::Render(float deltaTime)
|
||
{
|
||
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
|
||
if (!renderer || !m_texture)
|
||
return;
|
||
SDL_Rect dstrect = {Pos.x, Pos.y, Size.x, Size.y};
|
||
|
||
SDL_RenderCopy(renderer, m_texture, NULL, &dstrect);
|
||
}
|
||
|
||
void Text::Clear()
|
||
{
|
||
}
|
||
|
||
void Text::SetPos(SDL_Point pos)
|
||
{
|
||
Pos = pos;
|
||
}
|
||
|
||
SDL_Point Text::GetPos()
|
||
{
|
||
return Pos;
|
||
}
|
||
|
||
void Text::SetText(std::string Str)
|
||
{
|
||
if (Str == m_text)
|
||
return;
|
||
if (!m_font)
|
||
{
|
||
SDL_LogError(0, "SetText失败:字体指针为空!");
|
||
return;
|
||
}
|
||
|
||
// 如果有原纹理先删除原纹理
|
||
if (m_texture)
|
||
{
|
||
SDL_DestroyTexture(m_texture);
|
||
m_texture = nullptr; // 置空指针
|
||
}
|
||
m_text = Str;
|
||
// 根据是否有描边选择对应的Init方法
|
||
if (m_stroke_size > 0)
|
||
{
|
||
Init(Str, m_font, m_text_color, m_stroke_color, m_stroke_size);
|
||
}
|
||
else
|
||
{
|
||
Init(Str, m_font, m_text_color);
|
||
}
|
||
}
|
||
|
||
std::string Text::GetText()
|
||
{
|
||
return m_text;
|
||
} |