Files
DNF_DEV/source/EngineFrame/Component/Sprite.cpp
2025-10-23 15:21:12 +08:00

194 lines
5.6 KiB
C++

#include "Sprite.h"
#include "EngineCore/Game.h"
#include "Text.h"
#include "EngineFrame/Render/RenderManager.h"
void Sprite::Init()
{
this->Size = m_texture->getSize();
RenderBase::Init();
}
void Sprite::SetTexture(RefPtr<Texture> texture)
{
m_texture = texture;
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::Sprite(std::string imgPath, int Index)
{
this->imgPath = imgPath;
this->Index = Index;
m_texture = new Texture();
m_texture->Init(imgPath, Index);
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::Sprite(std::string PngPath)
{
m_texture = new Texture();
m_texture->Init(PngPath);
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::~Sprite()
{
}
RefPtr<Texture> Sprite::GetTexture()
{
return m_texture;
}
void Sprite::CalcRenderInfoLogic()
{
// 获取至在最终的父对象检查是否显示
BaseNode *parentNode = this->GetParent();
while (parentNode != nullptr)
{
if (parentNode->Visible == false)
{
_RenderGuidanceInfo.Visible = false;
return;
}
parentNode = parentNode->GetParent();
}
_RenderGuidanceInfo.Visible = true;
// 计算缩放因子和翻转状态
float scaleX = transformIter.scale.x * transform.scale.x;
float scaleY = transformIter.scale.y * transform.scale.y;
// X轴和Y轴上是否翻转的标志
bool flipX = scaleX < 0;
bool flipY = scaleY < 0;
_RenderGuidanceInfo.flip = SDL_FLIP_NONE;
// 更新翻转状态
if (flipX)
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_HORIZONTAL | _RenderGuidanceInfo.flip);
if (flipY)
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
auto T_Size = m_texture->getSize();
auto T_Pos = m_texture->getPos();
float texturePosX = flipX ? -(T_Size.width + T_Pos.x) + SDL_abs(transform.position.x * 2) : T_Pos.x;
float texturePosY = flipY ? -(T_Size.height + T_Pos.y) + SDL_abs(transform.position.y * 2) : T_Pos.y;
// 先计算Img坐标与精灵坐标合成后的真实坐标
float RealPosX = transform.position.x + texturePosX;
float RealPosY = transform.position.y + texturePosY;
// 计算在世界中的位置
float baseX = transformIter.position.x + RealPosX;
float baseY = transformIter.position.y + RealPosY;
// 获取当前帧的原始尺寸
int frameWidth = Size.width;
int frameHeight = Size.height;
// 原始锚点偏移(基于帧尺寸)
float origAnchorOffsetX = int(frameWidth * Anchor.x);
float origAnchorOffsetY = int(frameHeight * Anchor.y);
// 缩放的绝对值
float absScaleX = SDL_fabs(scaleX);
float absScaleY = SDL_fabs(scaleY);
// 缩放后的尺寸
float scaledWidth = frameWidth * absScaleX;
float scaledHeight = frameHeight * absScaleY;
// 缩放后的锚点偏移
float scaledAnchorOffsetX = int(origAnchorOffsetX * absScaleX);
float scaledAnchorOffsetY = int(origAnchorOffsetY * absScaleY);
// 计算缩放后的锚点偏移与原锚点偏移的差值
float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
float Xpos = baseX - scaleOffsetX;
float Ypos = baseY - scaleOffsetY;
Xpos = (int)Xpos; // 强制转换为整数
Ypos = (int)Ypos; // 强制转换为整数
// 更新渲染信息
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
// 设置纹理透明度
m_texture->setAlpha(this->Alpha);
// 屏幕内检测
int screenWidth = Game::GetInstance().Screen_W;
int screenHeight = Game::GetInstance().Screen_H;
bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
_RenderGuidanceInfo.IsInScreen = isInScreen;
// this->Size = {scaledWidth, scaledHeight};
_RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;
CalcRenderInfoFlag = false;
}
void Sprite::PreRender()
{
if (CalcRenderInfoFlag && Visible)
CalcRenderInfoLogic();
}
void Sprite::Render()
{
if (!Visible)
return;
if (!m_texture)
return;
RenderManager *renderer = Game::GetInstance().GetRenderer();
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
{
SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
// 混合
if (this->_BlendMode != NONE)
Blend();
SDL_Rect srcrect = {0, 0, this->Size.width, this->Size.height};
renderer->DrawTexture(m_texture, &srcrect, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
// 还原混合
if (this->_BlendMode != NONE)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Game::GetInstance().m_RenderCount++;
}
}
void Sprite::Clear()
{
}
void Sprite::SetBlendMode(LE_BlEND_MODE mode)
{
this->_BlendMode = mode;
}
void Sprite::Blend()
{
switch (this->_BlendMode)
{
case LINEARDODGE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
}
}
LE_BlEND_MODE Sprite::GetBlendMode()
{
return this->_BlendMode;
}