Files
DNF_DEV/source/EngineFrame/Component/Sprite.cpp

215 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}
GlMatrix Sprite::matrix3x2ToGLMatrix(const Matrix3x2 &mat)
{
return {
// 列0x轴线性变换
mat._11, // [0][0]
mat._12, // [1][0]
0.0f, // [2][0]
0.0f, // [3][0]
// 列1y轴线性变换
mat._21, // [0][1]
mat._22, // [1][1]
0.0f, // [2][1]
0.0f, // [3][1]
// 列2z轴固定
0.0f, // [0][2]
0.0f, // [1][2]
1.0f, // [2][2]
0.0f, // [3][2]
// 列3平移
mat._31, // [0][3]x平移
mat._32, // [1][3]y平移
0.0f, // [2][3]
1.0f // [3][3]
};
}
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;
AnchorPos.x = _RenderGuidanceInfo.AnchorPos.x;
AnchorPos.y = _RenderGuidanceInfo.AnchorPos.y;
// 混合
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);
}
}
void Sprite::Clear()
{
}
void Sprite::Blend()
{
switch (this->_BlendMode)
{
case LINEARDODGE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
}
}