修改OpenGl渲染底层之前

This commit is contained in:
2025-10-20 20:50:12 +08:00
parent 1b011b9b68
commit 2b888aae5b
61 changed files with 1609 additions and 680 deletions

View File

@@ -1,155 +0,0 @@
#include "Debug_Actor.h"
#include "EngineCore/Game.h"
#include <string>
Debug_Actor::Debug_Actor()
{
m_debugFont = TTF_OpenFont("Fonts/VonwaonBitmap-12px.ttf", 12);
if (m_debugFont == nullptr)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load debug font: %s", TTF_GetError());
}
FPS_Text = new Text("当 前 帧 数 :", m_debugFont, SDL_Color{255, 255, 255, 255});
DT_Text = new Text("帧 时 间 :", m_debugFont, SDL_Color{255, 255, 255, 255});
RC_Text = new Text("渲 染 调 用 次 数:", m_debugFont, SDL_Color{255, 255, 255, 255});
if (FPS_Text != nullptr)
{
SDL_Point Pos{26, 26};
FPS_Text->SetPos(Pos);
this->AddComponent(FPS_Text);
}
if (DT_Text != nullptr)
{
SDL_Point Pos{26, 46};
DT_Text->SetPos(Pos);
this->AddComponent(DT_Text);
}
if (RC_Text != nullptr)
{
SDL_Point Pos{26, 66};
RC_Text->SetPos(Pos);
this->AddComponent(RC_Text);
}
}
Debug_Actor::~Debug_Actor()
{
if (m_debugFont != nullptr)
{
TTF_CloseFont(m_debugFont);
m_debugFont = nullptr;
}
}
void Debug_Actor::Update(float deltaTime)
{
Actor::Update(deltaTime);
if (FPS_Text != nullptr)
{
std::string fpsText = "当前帧数 : " + std::to_string(FPS);
FPS_Text->SetText(fpsText);
std::string dtText = "帧时间 : " + std::to_string((int)(deltaTime * 1000));
DT_Text->SetText(dtText);
std::string rcText = "渲染调用次数 : " + std::to_string(RenderCount);
RC_Text->SetText(rcText);
}
}
void Debug_Actor::Render()
{
if (FPS_Text != nullptr)
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
if (renderer != nullptr)
{
SDL_Point textPos = FPS_Text->Pos;
SDL_Point textSize = FPS_Text->Size;
int bgX = textPos.x - padding;
int bgY = textPos.y - padding;
int bgWidth = textSize.x + padding * 2;
int bgHeight = textSize.y + padding * 2 * 4;
DrawRoundedRect(renderer, bgX, bgY, bgWidth, bgHeight, cornerRadius, bgColor);
}
}
Actor::Render();
}
void Debug_Actor::DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color)
{
if (renderer == nullptr)
return;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawLine(renderer, x + radius, y, x + w - radius, y);
SDL_RenderDrawLine(renderer, x + radius, y + h, x + w - radius, y + h);
SDL_RenderDrawLine(renderer, x, y + radius, x, y + h - radius);
SDL_RenderDrawLine(renderer, x + w, y + radius, x + w, y + h - radius);
const int segments = 16;
for (int i = 0; i < segments; i++)
{
float t1 = static_cast<float>(i) / segments;
float t2 = static_cast<float>(i + 1) / segments;
float angle1 = M_PI * (1.0f - t1);
float angle2 = M_PI * (1.0f - t2);
SDL_RenderDrawLineF(
renderer,
x + radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
x + radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
angle1 = 2 * M_PI - t1 * M_PI_2;
angle2 = 2 * M_PI - t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + w - radius + cos(angle1) * radius, y + radius + sin(angle1) * radius,
x + w - radius + cos(angle2) * radius, y + radius + sin(angle2) * radius);
angle1 = t1 * M_PI_2;
angle2 = t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + w - radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
x + w - radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
angle1 = M_PI_2 + t1 * M_PI_2;
angle2 = M_PI_2 + t2 * M_PI_2;
SDL_RenderDrawLineF(
renderer,
x + radius + cos(angle1) * radius, y + h - radius + sin(angle1) * radius,
x + radius + cos(angle2) * radius, y + h - radius + sin(angle2) * radius);
}
for (int dy = 0; dy < h; dy++)
{
int leftIndent = 0;
int rightIndent = 0;
if (dy < radius)
{
float ratio = 1.0f - static_cast<float>(dy) / radius;
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
}
else if (dy > h - radius)
{
float ratio = static_cast<float>(dy - (h - radius)) / radius;
leftIndent = rightIndent = static_cast<int>(radius * (1.0f - sqrt(1.0f - ratio * ratio)));
}
SDL_RenderDrawLine(
renderer,
x + leftIndent, y + dy,
x + w - rightIndent, y + dy);
}
}

View File

@@ -1,36 +0,0 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Component/Text.h"
#include <SDL_ttf.h>
#include <cstdint>
class Debug_Actor : public Actor
{
private:
TTF_Font *m_debugFont;
RefPtr<Text> FPS_Text;
RefPtr<Text> DT_Text;
RefPtr<Text> RC_Text;
public:
Debug_Actor();
~Debug_Actor() override;
void Update(float deltaTime) override;
void Render() override;
uint32_t FPS = 0;
uint32_t RenderCount = 0;
SDL_Color bgColor = {0, 0, 0, 90};
int cornerRadius = 4;
int padding = 12;
#ifdef __SWITCH__
double M_PI = 3.14159265358979323846;
double M_PI_2 = 1.57079632679489661923;
#endif
private:
void DrawRoundedRect(SDL_Renderer *renderer, int x, int y, int w, int h, int radius, SDL_Color color);
};

View File

@@ -32,6 +32,18 @@ void BaseNode::Update(float deltaTime)
}
}
void BaseNode::PreRender()
{
// 如果有子节点并含有渲染标签,则渲染子节点
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
if (child->hasTag(Tag::RENDER))
child->PreRender();
child = child->GetNext();
}
}
void BaseNode::Render()
{
// 如果有子节点并含有渲染标签,则渲染子节点
@@ -150,6 +162,11 @@ void BaseNode::RemoveChild(RefPtr<BaseNode> child)
m_BaseNodes.Remove(child);
}
void BaseNode::RemoveAllChild()
{
m_BaseNodes.Clear();
}
void BaseNode::OnAdded(BaseNode *node)
{
m_Parent = node;
@@ -197,6 +214,11 @@ VecFPos BaseNode::GetPos()
return this->transform.position;
}
VecFPos BaseNode::GetWorldPos()
{
return this->transform.position + this->transformIter.position;
}
void BaseNode::SetScale(VecFPos scale)
{
if (scale == this->transform.scale)
@@ -261,6 +283,16 @@ bool BaseNode::GetVisible()
return this->Visible;
}
void BaseNode::SetAlpha(float alpha)
{
this->Alpha = alpha;
}
float BaseNode::GetAlpha()
{
return this->Alpha;
}
void BaseNode::SetIterationPos(VecFPos pos)
{
if (pos == this->transformIter.position)

View File

@@ -35,6 +35,8 @@ public:
VecFPos Anchor = {0.f, 0.f};
// 大小
VecSize Size = {0, 0};
// 透明度
float Alpha = 1.f;
// 是否显示
bool Visible = true;
// 计算渲染信息Flag (为了保证每帧只计算一次)
@@ -48,6 +50,7 @@ public:
virtual void Init();
virtual void HandleEvents(SDL_Event *e);
virtual void Update(float deltaTime);
virtual void PreRender();
virtual void Render();
virtual void Clear();
@@ -73,6 +76,8 @@ public:
virtual void AddChild(RefPtr<BaseNode> child);
// 移除子对象
void RemoveChild(RefPtr<BaseNode> child);
// 移除所有子对象
void RemoveAllChild();
// 被添加时
virtual void OnAdded(BaseNode *node);
// 设置迭代的二维仿射变换
@@ -101,6 +106,8 @@ public:
virtual void SetPos(VecFPos pos);
// 获取坐标
VecFPos GetPos();
// 获取世界坐标
VecFPos GetWorldPos();
// 设置缩放
virtual void SetScale(VecFPos scale);
// 获取缩放
@@ -121,4 +128,8 @@ public:
virtual void SetVisible(bool visible);
// 获取是否显示
bool GetVisible();
// 设置透明度
virtual void SetAlpha(float alpha);
// 获取透明度
float GetAlpha();
};

View File

@@ -3,6 +3,7 @@
#include "Asset/Asset_Script.h"
#include "Tool/Math.h"
#include "EngineFrame/Actor/Actor.h"
#include "EngineCore/Game.h"
Animation::Animation()
{
@@ -66,20 +67,20 @@ void Animation::Init(std::string AniPath)
// TODO 染色
// 判断是否有Als
if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als"))
{
AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als");
if (Info.AniList.size() > 0)
{
std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1);
for (auto &Ani : Info.AniList)
{
RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
AlsAniObj->SetRenderZOrder(Ani.second.layer[1]);
AddChild(AlsAniObj);
}
}
}
// if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als"))
// {
// AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als");
// if (Info.AniList.size() > 0)
// {
// std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1);
// for (auto &Ani : Info.AniList)
// {
// RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
// AlsAniObj->SetRenderZOrder(Ani.second.layer[1]);
// AddChild(AlsAniObj);
// }
// }
// }
FlushFrame(0);
}
@@ -134,7 +135,18 @@ void Animation::Render()
{
if (!Visible)
return;
Actor::Render();
// 是否裁切
if (CropFlag)
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
SDL_RenderSetClipRect(renderer, &CropRect);
Actor::Render();
SDL_RenderSetClipRect(renderer, NULL);
}
else
{
Actor::Render();
}
}
void Animation::OnAdded(BaseNode *node)
@@ -153,6 +165,7 @@ void Animation::SetVisible(bool visible)
if (visible)
{
CurrentFrame->CalcRenderInfoLogic();
CurrentFrame->CalcRenderInfo();
}
Actor::SetVisible(visible);
}
@@ -192,7 +205,6 @@ void Animation::FlushFrame(int Index)
if (FlagBuf.count("IMAGE_RATE"))
{
VecFPos Rate = std::get<VecFPos>(FlagBuf["IMAGE_RATE"]);
CurrentFrame->SetAnchor(VecFPos{0.5f, 0.5f});
CurrentFrame->SetScale(VecFPos{Rate.x, Rate.y});
}
// 线性减淡
@@ -233,7 +245,6 @@ void Animation::FlushFrame(int Index)
}
// Ani的大小同步为精灵帧对象的大小
SetSize(CurrentFrame->GetSize());
// 裁切 //TODO
}
void Animation::Reset()
@@ -317,3 +328,22 @@ void Animation::InterpolationLogic()
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate);
}
}
void Animation::SetClipRect(SDL_Rect clipRect)
{
CropFlag = true;
CropRect = clipRect;
}
void Animation::UnsetClipRect()
{
CropFlag = false;
}
void Animation::SetShadow()
{
for (auto &Sp : SpriteArr)
{
Sp->SetShadow();
}
}

View File

@@ -36,12 +36,20 @@ public:
void FlushFrame(int Index);
void Reset();
AniScriptParser::AniFrame GetCurrentFrameInfo();
// 设置帧索引
void SetFrameIndex(int Index);
void InterpolationLogic();
// TODO SetOutline
// TODO SetDye
// TODO SetCrop
// 设置裁切区域
void SetClipRect(SDL_Rect clipRect);
// 取消裁切区域
void UnsetClipRect();
// 设置阴影
void SetShadow();
public:
// Ani是否可用
bool IsUsability = true;
@@ -88,7 +96,9 @@ public:
// // 整体染色
// DyeAllFlag = false;
// // 裁切数据
// CropRect = null;
SDL_Rect CropRect = {0, 0, 0, 0};
// 裁切Flag
bool CropFlag = false;
// 附加选项
std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;

View File

@@ -0,0 +1,107 @@
#include "AnimationManager.h"
#include "EngineCore/Game.h"
AnimationManager::AnimationManager()
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
m_Texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_TARGET,
Game::GetInstance().Screen_W,
Game::GetInstance().Screen_H);
}
void AnimationManager::PreRender()
{
Actor::PreRender();
// 标记是否是第一个子对象用于初始化min/max值
bool isFirst = true;
float minX = 0.0f, minY = 0.0f; // 所有子对象的最小X、Y坐标
float maxX = 0.0f, maxY = 0.0f; // 所有子对象的最大X、Y坐标右下角
RefPtr<BaseNode> child = m_BaseNodes.GetFirst();
while (child)
{
// 转换为Animation对象
Animation *ani = static_cast<Animation *>(child.Get());
float width = ani->CurrentFrame->_RenderGuidanceInfo.rect.w;
float height = ani->CurrentFrame->_RenderGuidanceInfo.rect.h;
float x = ani->CurrentFrame->_RenderGuidanceInfo.rect.x;
float y = ani->CurrentFrame->_RenderGuidanceInfo.rect.y;
// 计算子对象的右下角坐标(左上角 + 宽高)
float currentMaxX = x + width;
float currentMaxY = y + height;
// 初始化或更新min/max值
if (isFirst)
{
minX = x;
minY = y;
maxX = currentMaxX;
maxY = currentMaxY;
isFirst = false;
}
else
{
minX = std::min(minX, x);
minY = std::min(minY, y);
maxX = std::max(maxX, currentMaxX);
maxY = std::max(maxY, currentMaxY);
}
child = child->GetNext();
}
// 计算最终的包围盒矩形
if (!isFirst) // 至少有一个子对象时才计算
{
m_RenderRect.x = minX; // 矩形左上角X
m_RenderRect.y = minY; // 矩形左上角Y
m_RenderRect.w = maxX - minX; // 矩形宽度右下角X - 左上角X
m_RenderRect.h = maxY - minY; // 矩形高度右下角Y - 左上角Y
}
}
void AnimationManager::Render()
{
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
// 设定渲染目标为纹理
SDL_SetRenderTarget(renderer, m_Texture);
SDL_RenderClear(renderer);
// 渲染所有子对象
Actor::Render();
// 恢复渲染目标为默认窗口
SDL_SetRenderTarget(renderer, nullptr);
SDL_Rect srcRect = {
static_cast<int>(m_RenderRect.x), // 子对象包围盒左上角X纹理中的位置
static_cast<int>(m_RenderRect.y), // 子对象包围盒左上角Y纹理中的位置
static_cast<int>(m_RenderRect.w), // 包围盒宽度(有效区域宽度)
static_cast<int>(m_RenderRect.h) // 包围盒高度(有效区域高度)
};
// SDL_FRect renderToWindow = {
// m_RenderRect.x, // 窗口上的X位置可自定义
// m_RenderRect.y, // 窗口上的Y位置可自定义
// m_RenderRect.w, // 渲染到窗口的宽度(与源区域等大)
// m_RenderRect.h // 渲染到窗口的高度(与源区域等大)
// };
SDL_FRect renderToWindow = {
0, 0, 1080, 720};
// SDL_Log("m_Texture rect: %f %f %f %f", renderToWindow.x, renderToWindow.y, renderToWindow.w, renderToWindow.h);
// SDL_RenderCopyF(renderer, m_Texture, &srcRect, &renderToWindow);
SDL_RenderCopyF(renderer, m_Texture, NULL, &renderToWindow);
}
void AnimationManager::AddAnimation(RefPtr<Animation> ani)
{
this->AddChild(ani);
}
void AnimationManager::Clear()
{
this->RemoveAllChild();
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "EngineFrame/Component/Animation.h"
#include <vector>
class AnimationManager : public Actor
{
private:
SDL_Texture *m_Texture = nullptr;
SDL_FRect m_RenderRect = {0, 0, 0, 0};
public:
AnimationManager();
// void Update(float deltaTime) override;
void PreRender() override;
void Render() override;
public:
// 添加Ani
void AddAnimation(RefPtr<Animation> ani);
// 清空Ani
void Clear();
};

View File

@@ -9,12 +9,17 @@ class RenderBase : public Component
public:
struct RenderGuidanceInfo
{
SDL_Rect rect;
SDL_FRect rect;
// 旋转角度
float rotation;
// 翻转Flag
SDL_RendererFlip flip = SDL_FLIP_NONE;
VecPos AnchorPos;
// 锚点坐标
VecFPos AnchorPos;
// 是否显示
bool Visible = true;
bool IsInScreen;
// 是否在屏幕内
bool IsInScreen = false;
};
public:

View File

@@ -1,8 +1,11 @@
#include "Sprite.h"
#include "EngineCore/Game.h"
#include "Text.h"
Sprite::Sprite()
void Sprite::Init()
{
this->Size = m_texture->TextureSize;
RenderBase::Init();
}
Sprite::Sprite(std::string imgPath, int Index)
@@ -30,27 +33,12 @@ RefPtr<Texture> Sprite::GetTexture()
return m_texture;
}
void Sprite::SetIterationPos(VecFPos pos)
{
RenderBase::SetIterationPos(pos);
CalcRenderInfo();
}
void Sprite::HandleEvents(SDL_Event *e)
{
}
void Sprite::Update(float deltaTime)
{
if (CalcRenderInfoFlag && Visible)
CalcRenderInfoLogic();
}
void Sprite::CalcRenderInfoLogic()
{
// 计算缩放因子和翻转状态
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;
@@ -63,46 +51,55 @@ void Sprite::CalcRenderInfoLogic()
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
int texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x;
int texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y;
float texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x;
float texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y;
// 先计算Img坐标与精灵坐标合成后的真实坐标
int RealPosX = transform.position.x + texturePosX;
int RealPosY = transform.position.y + texturePosY;
float RealPosX = transform.position.x + texturePosX;
float RealPosY = transform.position.y + texturePosY;
// 计算在世界中的位置
int baseX = transformIter.position.x + RealPosX;
int baseY = transformIter.position.y + RealPosY;
float baseX = transformIter.position.x + RealPosX;
float baseY = transformIter.position.y + RealPosY;
// 获取当前帧的原始尺寸
int frameWidth = m_texture->TextureSize.width;
int frameHeight = m_texture->TextureSize.height;
int frameWidth = Size.width;
int frameHeight = Size.height;
// 原始锚点偏移(基于帧尺寸)
int origAnchorOffsetX = static_cast<int>(frameWidth * Anchor.x);
int origAnchorOffsetY = static_cast<int>(frameHeight * Anchor.y);
float origAnchorOffsetX = int(frameWidth * Anchor.x);
float origAnchorOffsetY = int(frameHeight * Anchor.y);
// 缩放的绝对值
float absScaleX = SDL_abs(scaleX);
float absScaleY = SDL_abs(scaleY);
float absScaleX = SDL_fabs(scaleX);
float absScaleY = SDL_fabs(scaleY);
// 缩放后的尺寸
int scaledWidth = static_cast<int>(frameWidth * absScaleX);
int scaledHeight = static_cast<int>(frameHeight * absScaleY);
float scaledWidth = frameWidth * absScaleX;
float scaledHeight = frameHeight * absScaleY;
// 缩放后的锚点偏移
int scaledAnchorOffsetX = static_cast<int>(origAnchorOffsetX * absScaleX);
int scaledAnchorOffsetY = static_cast<int>(origAnchorOffsetY * absScaleY);
float scaledAnchorOffsetX = int(origAnchorOffsetX * absScaleX);
float scaledAnchorOffsetY = int(origAnchorOffsetY * absScaleY);
// 计算缩放后的锚点偏移与原锚点偏移的差值
int scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
int scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
float scaleOffsetX = scaledAnchorOffsetX - origAnchorOffsetX;
float scaleOffsetY = scaledAnchorOffsetY - origAnchorOffsetY;
// 最终位置计算:世界位置 + 缩放锚点差值 - 缩放后的锚点偏移 + 纹理数据里带的偏移数据 (计算出绘制点的左上角)
int Xpos = baseX + scaleOffsetX;
int Ypos = baseY + scaleOffsetY;
float Xpos = baseX - scaleOffsetX;
float Ypos = baseY - scaleOffsetY;
Xpos = (int)Xpos; // 强制转换为整数
Ypos = (int)Ypos; // 强制转换为整数
// 更新渲染信息
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
// 如果有阴影 计算阴影的渲染信息
if (ShadowFlag)
CalculateShadowData();
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
// 设置纹理透明度
SDL_SetTextureAlphaMod(m_texture->GetTexture(), this->Alpha * 255);
// 屏幕内检测
int screenWidth = Game::GetInstance().Screen_W;
@@ -110,12 +107,29 @@ void Sprite::CalcRenderInfoLogic()
bool isInScreen = (Xpos + scaledWidth >= 0 && Xpos <= screenWidth && Ypos + scaledHeight >= 0 && Ypos <= screenHeight);
_RenderGuidanceInfo.IsInScreen = isInScreen;
this->Size = {scaledWidth, scaledHeight};
// this->Size = {scaledWidth, scaledHeight};
_RenderGuidanceInfo.rotation = transformIter.rotation + transform.rotation;
CalcRenderInfoFlag = false;
}
void Sprite::SetClipRect(SDL_Rect clipRect)
{
CropFlag = true;
CropRect = clipRect;
}
void Sprite::UnsetClipRect()
{
CropFlag = false;
}
void Sprite::PreRender()
{
if (CalcRenderInfoFlag && Visible)
CalcRenderInfoLogic();
}
void Sprite::Render()
{
if (!Visible)
@@ -126,20 +140,27 @@ void Sprite::Render()
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
{
// 如果有阴影绘制阴影
if (ShadowFlag)
{
std::array<int, 6> indices = {0, 1, 2, 1, 3, 2};
SDL_RenderGeometry(renderer, m_texture->GetTexture(), vertices.data(), vertices.size(), indices.data(), indices.size());
}
if (_RenderGuidanceInfo.rotation != 0.f || _RenderGuidanceInfo.flip != SDL_FLIP_NONE)
{
SDL_Point AnchorPos = _RenderGuidanceInfo.AnchorPos;
SDL_RenderCopyEx(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
SDL_RenderCopyExF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
}
else
{
SDL_RenderCopy(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
SDL_RenderCopyF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
// // 设置绘制颜色
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
// // 绘制填充矩形
// SDL_RenderFillRect(renderer, &_RenderGuidanceInfo.rect);
// SDL_RenderFillRectF(renderer, &_RenderGuidanceInfo.rect);
}
Game::GetInstance().RenderCount++;
Game::GetInstance().m_RenderCount++;
}
}
@@ -157,3 +178,62 @@ SDL_BlendMode Sprite::GetBlendMode()
{
return m_texture->GetBlendMode();
}
void Sprite::SetShadow()
{
ShadowFlag = true;
CalcRenderInfo();
}
void Sprite::CalculateShadowData()
{
const float shearX = 1.3f;
SDL_FRect guidance = _RenderGuidanceInfo.rect;
float shadowW = guidance.w; // 影子宽度(建议与角色宽度一致)
float shadowH = guidance.h * 0.33; // 影子高度可根据需求调整比如角色高度的1/4
// 计算角色脚部中点坐标(底部中心,即需要重叠的锚点)
float roleFootX = guidance.x + guidance.w / 2.0f + 3; // 角色X中心 + 位置偏移
float roleFootY = guidance.y + guidance.h - 5; // 角色底部Y坐标脚的位置
// 计算错切后的顶点(局部坐标)
vertices = {
// 左上角(局部坐标)
SDL_Vertex{{0.0f, 0.0f}, {0, 0, 0, 110}, {0.0f, 0.0f}},
// 右上角(局部坐标)
SDL_Vertex{{shadowW, 0.0f}, {0, 0, 0, 110}, {1.0f, 0.0f}},
// 左下角(局部坐标)
SDL_Vertex{{0.0f + shearX * shadowH, shadowH}, {0, 0, 0, 110}, {0.0f, 1.0f}},
// 右下角(局部坐标)
SDL_Vertex{{shadowW + shearX * shadowH, shadowH}, {0, 0, 0, 110}, {1.0f, 1.0f}}};
bool flipHorizontal = (_RenderGuidanceInfo.flip & SDL_FLIP_HORIZONTAL) != 0; // 检查水平翻转标志
bool flipVertical = (_RenderGuidanceInfo.flip & SDL_FLIP_VERTICAL) != 0; // 检查垂直翻转标志
// 应用纹理坐标翻转(核心逻辑)
for (auto &v : vertices)
{
// 水平翻转反转u坐标0→11→0
if (flipHorizontal)
{
v.tex_coord.x = 1.0f - v.tex_coord.x;
}
// 垂直翻转反转v坐标0→11→0
if (flipVertical)
{
v.tex_coord.y = 1.0f - v.tex_coord.y;
}
}
// 计算影子底部中点并对齐角色脚部(与之前逻辑一致)
float shadowFootX = (vertices[2].position.x + vertices[3].position.x) / 2.0f;
float shadowFootY = shadowH;
float offsetX = roleFootX - shadowFootX;
float offsetY = roleFootY - shadowFootY;
// 应用位置偏移
for (auto &v : vertices)
{
v.position.x += offsetX;
v.position.y += offsetY;
}
}

View File

@@ -11,67 +11,47 @@ class Game;
class Sprite : public RenderBase
{
protected:
/* data */
RefPtr<Texture> m_texture = nullptr;
public:
/**
* @brief Sprite类的默认构造函数
*/
Sprite(/* args */);
/**
* @brief Sprite类的带参数构造函数
* @param imgPath 纹理图片路径
* @param Index 索引值
*/
Sprite() = default;
Sprite(std::string imgPath, int Index);
/**
* @brief Sprite类的带参数构造函数
* @param imgPath 纹理图片文件路径
*/
Sprite(std::string PngPath);
/**
* @brief Sprite类的析构函数
*/
~Sprite();
/**
* @brief 处理事件
* @param e SDL事件指针
*/
void HandleEvents(SDL_Event *e) override;
/**
* @brief 更新组件状态
* @param deltaTime 时间增量
*/
void Update(float deltaTime) override;
/**
* @brief 渲染组件
* @param deltaTime 时间增量
*/
void Render() override;
/**
* @brief 清理组件资源
*/
void PreRender() override;
void Clear() override;
void Init() override;
/**
* @brief 获取纹理
* @return SDL_Texture* 纹理指针
*/
RefPtr<Texture> GetTexture();
void SetIterationPos(VecFPos pos) override;
public:
// 渲染信息
RenderGuidanceInfo _RenderGuidanceInfo;
// 裁切数据
SDL_Rect CropRect = {0, 0, 0, 0};
// 裁切Flag
bool CropFlag = false;
// 阴影数据
std::array<SDL_Vertex, 4> vertices;
// 阴影Flag
bool ShadowFlag = false;
std::string imgPath;
int Index;
public:
// 计算渲染信息
void CalcRenderInfoLogic();
// 设置裁切区域
void SetClipRect(SDL_Rect clipRect);
// 取消裁切区域
void UnsetClipRect();
// 设置混合模式
void SetBlendMode(SDL_BlendMode blendMode);
// 获取混合模式
SDL_BlendMode GetBlendMode();
// 设置阴影
void SetShadow();
// 计算阴影数据
void CalculateShadowData();
};

View File

@@ -33,6 +33,8 @@ Texture::Texture(std::string PngPath)
Texture::Texture(std::string imgPath, int Index)
{
this->ImgPath = imgPath;
this->Index = Index;
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath);
if (Info->lpImgName == "sprite/interface/base.img")
return;
@@ -50,7 +52,7 @@ Texture::Texture(std::string imgPath, int Index)
int pitch = Buf.Width * 4;
SDL_UpdateTexture(m_texture, NULL, Buf.PNGdata, pitch);
SDL_SetTextureBlendMode(m_texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeBest);
SDL_SetTextureScaleMode(m_texture, SDL_ScaleModeNearest);
this->TexturePos.x = Buf.Xpos;
this->TexturePos.y = Buf.Ypos;
@@ -70,6 +72,12 @@ SDL_Texture *Texture::GetTexture()
return m_texture;
}
RefPtr<Texture> Texture::GetTextureCopy()
{
RefPtr<Texture> nt = new Texture(this->ImgPath, this->Index);
return nt;
}
void Texture::SetBlendMode(SDL_BlendMode blendMode)
{
SDL_SetTextureBlendMode(m_texture, blendMode);

View File

@@ -9,7 +9,8 @@ class Texture : public RefObject
{
private:
SDL_Texture *m_texture = nullptr;
std::string ImgPath = "";
int Index = 0;
public:
VecSize TextureSize = {0, 0}; // 纹理大小
VecPos TexturePos = {0, 0}; // 纹理位置
@@ -25,5 +26,8 @@ public:
void SetBlendMode(SDL_BlendMode blendMode);
// 获取混合模式
SDL_BlendMode GetBlendMode();
SDL_Texture *GetTexture(); // 获取纹理
// 获取纹理
SDL_Texture *GetTexture();
// 获取一个拷贝的纹理
RefPtr<Texture> GetTextureCopy();
};

View File

@@ -20,3 +20,8 @@ void Scene::Init()
void Scene::Exit()
{
}
RefPtr<BaseNode> Scene::GetCamera()
{
return nullptr;
}

View File

@@ -6,5 +6,6 @@ public:
Scene();
virtual void Enter();
virtual void Exit();
virtual RefPtr<BaseNode> GetCamera();
void Init();
};