203 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			203 lines
		
	
	
		
			5.4 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) | |||
|  | { | |||
|  |     // 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; | |||
|  | } |