修改底层渲染为OpenGL

This commit is contained in:
2025-10-23 15:21:12 +08:00
parent 1fe898e09c
commit f9a2300b5a
37 changed files with 2782 additions and 3761 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -20,17 +20,25 @@ void Game::Init(std::function<void()> CallBack)
SDL_JoystickEventState(SDL_ENABLE); SDL_JoystickEventState(SDL_ENABLE);
SDL_JoystickOpen(0); SDL_JoystickOpen(0);
// 设置OpenGL ES 3.2上下文属性
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // 双缓冲
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{ {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not initialize! Error: %s\n", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not initialize! Error: %s\n", SDL_GetError());
m_isRunning = false; m_isRunning = false;
} }
m_window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_W, Screen_H, SDL_WINDOW_SHOWN); m_window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_W, Screen_H, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
if (m_window == nullptr) if (m_window == nullptr)
{ {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Window! Error: %s\n", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Window! Error: %s\n", SDL_GetError());
m_isRunning = false; m_isRunning = false;
} }
// 关闭原生鼠标
SDL_ShowCursor(0);
// 打开所有检测到的控制器 // 打开所有检测到的控制器
int numControllers = SDL_NumJoysticks(); int numControllers = SDL_NumJoysticks();
for (int i = 0; i < numControllers; i++) for (int i = 0; i < numControllers; i++)
@@ -48,16 +56,9 @@ void Game::Init(std::function<void()> CallBack)
} }
} }
} }
// 创建渲染器 // 创建OpenGL渲染器
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); m_renderer = new RenderManager(m_window);
if (m_renderer == nullptr)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Renderer! Error: %s\n", SDL_GetError());
m_isRunning = false;
}
// 启用渲染器的混合功能(必须,否则纹理混合模式无效)
SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_BLEND);
// SDL_RenderSetScale(m_renderer, 1.2, 1.2);
IMG_Init(IMG_INIT_PNG); IMG_Init(IMG_INIT_PNG);
// 初始化SDL_mixer支持OGG格式 // 初始化SDL_mixer支持OGG格式
@@ -149,7 +150,9 @@ void Game::HandleEvents(SDL_Event *e)
void Game::Update(float deltaTime) void Game::Update(float deltaTime)
{ {
if (m_scene != nullptr) //调用松鼠的更新
SquirrelEx::GetInstance().Update(deltaTime);
if (m_scene != nullptr)
m_scene->Update(deltaTime); m_scene->Update(deltaTime);
if (m_uiScene != nullptr) if (m_uiScene != nullptr)
m_uiScene->Update(deltaTime); m_uiScene->Update(deltaTime);
@@ -167,12 +170,12 @@ void Game::Render()
m_uiScene->PreRender(); m_uiScene->PreRender();
// 清空渲染器后渲染 // 清空渲染器后渲染
SDL_RenderClear(m_renderer); m_renderer->ClearScreen();
if (m_scene != nullptr) if (m_scene != nullptr)
m_scene->Render(); m_scene->Render();
if (m_uiScene != nullptr) if (m_uiScene != nullptr)
m_uiScene->Render(); m_uiScene->Render();
SDL_RenderPresent(m_renderer); m_renderer->SwapBuffer();
} }
void Game::Clear() void Game::Clear()
@@ -188,7 +191,6 @@ void Game::Clear()
} }
m_uiScene = nullptr; m_uiScene = nullptr;
IMG_Quit(); IMG_Quit();
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window); SDL_DestroyWindow(m_window);
SDL_Quit(); SDL_Quit();
} }
@@ -213,7 +215,7 @@ void Game::ChangeUIScene(RefPtr<Scene> scene)
m_uiScene->Enter(); m_uiScene->Enter();
} }
SDL_Renderer *Game::GetRenderer() RenderManager *Game::GetRenderer()
{ {
return m_renderer; return m_renderer;
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "EngineFrame/Scene/Scene.h" #include "EngineFrame/Scene/Scene.h"
#include "EngineFrame/Render/RenderManager.h"
#include "Tool/RefPtr.h" #include "Tool/RefPtr.h"
#include <SDL.h> #include <SDL.h>
#include <SDL_image.h> #include <SDL_image.h>
@@ -55,7 +56,7 @@ public:
// 设定UI层场景对象 // 设定UI层场景对象
void ChangeUIScene(RefPtr<Scene> scene); void ChangeUIScene(RefPtr<Scene> scene);
SDL_Renderer *GetRenderer(); RenderManager* GetRenderer();
// 每秒帧率 // 每秒帧率
u32 m_fps; u32 m_fps;
@@ -72,7 +73,7 @@ private:
// 窗口 // 窗口
SDL_Window *m_window; SDL_Window *m_window;
// 渲染器 // 渲染器
SDL_Renderer *m_renderer; RenderManager* m_renderer;
// 游戏层场景 // 游戏层场景
RefPtr<Scene> m_scene; RefPtr<Scene> m_scene;

View File

@@ -1,6 +1,8 @@
#include "Actor.h" #include "Actor.h"
#include "EngineFrame/Scene/Scene.h" #include "EngineFrame/Scene/Scene.h"
#include "EngineCore/Game.h"
#include "EngineFrame/Component/RenderBase.h" #include "EngineFrame/Component/RenderBase.h"
#include "EngineFrame/Render/RenderManager.h"
#include <algorithm> #include <algorithm>
Actor::Actor() Actor::Actor()
@@ -16,6 +18,22 @@ void Actor::Init()
addTag(Tag::UPDATE); addTag(Tag::UPDATE);
} }
void Actor::Render()
{
// 如果有裁切视口
if (this->_CropViewportFlag)
{
RenderManager *renderer = Game::GetInstance().GetRenderer();
renderer->SetClipRect(&this->_CropViewport);
BaseNode::Render();
renderer->CloseClipRect();
}
else
{
BaseNode::Render();
}
}
void Actor::AddComponent(RefPtr<Component> Component) void Actor::AddComponent(RefPtr<Component> Component)
{ {
BaseNode::AddChild(Component); BaseNode::AddChild(Component);
@@ -25,3 +43,21 @@ void Actor::RemoveComponent(RefPtr<Component> Component)
{ {
BaseNode::RemoveChild(Component); BaseNode::RemoveChild(Component);
} }
void Actor::SetCropViewport(SDL_Rect CropViewport)
{
if (CropViewport.x == 0 && CropViewport.y == 0 && CropViewport.w == 0 && CropViewport.h == 0)
{
this->_CropViewportFlag = false;
}
else
{
this->_CropViewportFlag = true;
this->_CropViewport = CropViewport;
}
}
SDL_Rect Actor::GetCropViewport()
{
return this->_CropViewport;
}

View File

@@ -10,14 +10,23 @@ class Scene;
*/ */
class Actor : public BaseNode class Actor : public BaseNode
{ {
private:
//裁切视口Flag
bool _CropViewportFlag = false;
//裁切视口
SDL_Rect _CropViewport = {0, 0, 0, 0};
public: public:
Actor(); Actor();
public: public:
void Init() override; void Init() override;
void Render() override;
void AddComponent(RefPtr<Component> Component); void AddComponent(RefPtr<Component> Component);
void RemoveComponent(RefPtr<Component> Component); void RemoveComponent(RefPtr<Component> Component);
// void AddChild(RefPtr<Actor> child);
// void RemoveChild(RefPtr<Actor> child); // 设置裁切视口(放在Actor里 他与他的子对象都会被裁切)
void SetCropViewport(SDL_Rect CropViewport);
// 获取裁切视口
SDL_Rect GetCropViewport();
}; };

View File

@@ -288,6 +288,11 @@ void BaseNode::SetAlpha(float alpha)
this->Alpha = alpha; this->Alpha = alpha;
} }
BaseNode *BaseNode::GetParent()
{
return this->m_Parent;
}
float BaseNode::GetAlpha() float BaseNode::GetAlpha()
{ {
return this->Alpha; return this->Alpha;

View File

@@ -132,4 +132,7 @@ public:
virtual void SetAlpha(float alpha); virtual void SetAlpha(float alpha);
// 获取透明度 // 获取透明度
float GetAlpha(); float GetAlpha();
//获取父对象
BaseNode *GetParent();
}; };

View File

@@ -67,20 +67,20 @@ void Animation::Init(std::string AniPath)
// TODO 染色 // TODO 染色
// 判断是否有Als // 判断是否有Als
// if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als")) if (Asset_Script::GetInstance().GetFileInfo(AniPath + ".als"))
// { {
// AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als"); AniScriptParser::AlsInfo Info = AssetManager::GetInstance().StructAlsInfo(AniPath + ".als");
// if (Info.AniList.size() > 0) if (Info.AniList.size() > 0)
// { {
// std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1); std::string Dir = AniPath.substr(0, AniPath.find_last_of("/") + 1);
// for (auto &Ani : Info.AniList) for (auto &Ani : Info.AniList)
// { {
// RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path); RefPtr<Animation> AlsAniObj = new Animation(Dir + Ani.second.path);
// AlsAniObj->SetRenderZOrder(Ani.second.layer[1]); AlsAniObj->SetRenderZOrder(Ani.second.layer[1]);
// AddChild(AlsAniObj); AddChild(AlsAniObj);
// } }
// } }
// } }
FlushFrame(0); FlushFrame(0);
} }
@@ -133,20 +133,7 @@ void Animation::Update(float deltaTime)
void Animation::Render() void Animation::Render()
{ {
if (!Visible) Actor::Render();
return;
// 是否裁切
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) void Animation::OnAdded(BaseNode *node)
@@ -210,7 +197,7 @@ void Animation::FlushFrame(int Index)
// 线性减淡 // 线性减淡
if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE")) if (FlagBuf.count("GRAPHIC_EFFECT_LINEARDODGE"))
{ {
CurrentFrame->SetBlendMode(SDL_BLENDMODE_ADD); CurrentFrame->SetBlendMode(LINEARDODGE);
} }
// 旋转 // 旋转
if (FlagBuf.count("IMAGE_ROTATE")) if (FlagBuf.count("IMAGE_ROTATE"))
@@ -328,22 +315,3 @@ void Animation::InterpolationLogic()
CurrentFrame->SetRotation(OldAngleData + (NewAngleData - OldAngleData) * InterRate); 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

@@ -43,13 +43,6 @@ public:
// TODO SetDye // TODO SetDye
// TODO SetCrop // TODO SetCrop
// 设置裁切区域
void SetClipRect(SDL_Rect clipRect);
// 取消裁切区域
void UnsetClipRect();
// 设置阴影
void SetShadow();
public: public:
// Ani是否可用 // Ani是否可用
bool IsUsability = true; bool IsUsability = true;
@@ -95,10 +88,6 @@ public:
// DyeFrameList = null; // DyeFrameList = null;
// // 整体染色 // // 整体染色
// DyeAllFlag = false; // DyeAllFlag = false;
// // 裁切数据
SDL_Rect CropRect = {0, 0, 0, 0};
// 裁切Flag
bool CropFlag = false;
// 附加选项 // 附加选项
std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions; std::function<std::string(std::string, Animation::ReplaceData)> AdditionalOptions;

View File

@@ -3,13 +3,6 @@
AnimationManager::AnimationManager() 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() void AnimationManager::PreRender()
@@ -65,35 +58,7 @@ void AnimationManager::PreRender()
void AnimationManager::Render() void AnimationManager::Render()
{ {
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
// 设定渲染目标为纹理
SDL_SetRenderTarget(renderer, m_Texture);
SDL_RenderClear(renderer);
// 渲染所有子对象
Actor::Render(); 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) void AnimationManager::AddAnimation(RefPtr<Animation> ani)

View File

@@ -0,0 +1,62 @@
#include "Canvas.h"
#include "EngineCore/Game.h"
#include "EngineFrame/Render/RenderManager.h"
Canvas::Canvas(VecSize size)
{
m_texture = new Texture();
m_texture->Init(size);
m_sprite = new Sprite();
m_sprite->SetTexture(m_texture);
Actor::Init();
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// 将目标纹理附加到FBO的颜色附着点
glFramebufferTexture2D(
GL_FRAMEBUFFER, // 帧缓冲类型
GL_COLOR_ATTACHMENT0, // 颜色附着点(可多个,这里用第一个)
GL_TEXTURE_2D, // 纹理类型
m_texture->getID(), // 目标纹理ID
0 // 多级渐远纹理级别
);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
}
void Canvas::PreRender()
{
if (m_dirty)
{
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); // 绑定FBO
// glViewport(0, 0, m_texture->getSize().width, m_texture->getSize().height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 全透明黑色
glClear(GL_COLOR_BUFFER_BIT);
Actor::PreRender();
}
else
{
m_sprite->PreRender();
}
}
void Canvas::Render()
{
if (m_dirty)
{
Actor::Render();
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑FBO
// glViewport(0, 0, Game::GetInstance().Screen_W, Game::GetInstance().Screen_H);
m_dirty = false;
}
RenderManager *renderer = Game::GetInstance().GetRenderer();
renderer->SetCurrentShaderProgram("flip_y");
m_sprite->Render();
renderer->SetCurrentShaderProgram("normal");
}
void Canvas::AddChild(RefPtr<BaseNode> child)
{
m_dirty = true;
Actor::AddChild(child);
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "EngineFrame/Actor/Actor.h"
#include "EngineFrame/Render/Texture.h"
#include "EngineFrame/Component/Sprite.h"
class Canvas : public Actor
{
private:
/**纹理 */
RefPtr<Texture> m_texture = nullptr;
/**精灵 */
RefPtr<Sprite> m_sprite = nullptr;
/**脏标记 */
bool m_dirty = true;
/**FBO */
GLuint m_fbo = 0;
public:
Canvas(VecSize size);
void PreRender() override;
void Render() override;
void AddChild(RefPtr<BaseNode> child) override;
};

View File

@@ -1,25 +1,35 @@
#include "Sprite.h" #include "Sprite.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
#include "Text.h" #include "Text.h"
#include "EngineFrame/Render/RenderManager.h"
void Sprite::Init() void Sprite::Init()
{ {
this->Size = m_texture->TextureSize; this->Size = m_texture->getSize();
RenderBase::Init(); RenderBase::Init();
} }
void Sprite::SetTexture(RefPtr<Texture> texture)
{
m_texture = texture;
Init();
CalcRenderInfoLogic(); // 第一次计算
}
Sprite::Sprite(std::string imgPath, int Index) Sprite::Sprite(std::string imgPath, int Index)
{ {
this->imgPath = imgPath; this->imgPath = imgPath;
this->Index = Index; this->Index = Index;
m_texture = new Texture(imgPath, Index); m_texture = new Texture();
m_texture->Init(imgPath, Index);
Init(); Init();
CalcRenderInfoLogic(); // 第一次计算 CalcRenderInfoLogic(); // 第一次计算
} }
Sprite::Sprite(std::string PngPath) Sprite::Sprite(std::string PngPath)
{ {
m_texture = new Texture(PngPath); m_texture = new Texture();
m_texture->Init(PngPath);
Init(); Init();
CalcRenderInfoLogic(); // 第一次计算 CalcRenderInfoLogic(); // 第一次计算
} }
@@ -35,6 +45,19 @@ RefPtr<Texture> Sprite::GetTexture()
void Sprite::CalcRenderInfoLogic() 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 scaleX = transformIter.scale.x * transform.scale.x;
float scaleY = transformIter.scale.y * transform.scale.y; float scaleY = transformIter.scale.y * transform.scale.y;
@@ -51,8 +74,10 @@ void Sprite::CalcRenderInfoLogic()
_RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip); _RenderGuidanceInfo.flip = static_cast<SDL_RendererFlip>(SDL_FLIP_VERTICAL | _RenderGuidanceInfo.flip);
// 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上 // 纹理数据里带的偏移数据 有这个偏移才能保证动画播放时视觉中心点在一个点上
float texturePosX = flipX ? -(m_texture->TextureSize.width + m_texture->TexturePos.x) + SDL_abs(transform.position.x * 2) : m_texture->TexturePos.x; auto T_Size = m_texture->getSize();
float texturePosY = flipY ? -(m_texture->TextureSize.height + m_texture->TexturePos.y) + SDL_abs(transform.position.y * 2) : m_texture->TexturePos.y; 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坐标与精灵坐标合成后的真实坐标 // 先计算Img坐标与精灵坐标合成后的真实坐标
float RealPosX = transform.position.x + texturePosX; float RealPosX = transform.position.x + texturePosX;
@@ -93,13 +118,9 @@ void Sprite::CalcRenderInfoLogic()
// 更新渲染信息 // 更新渲染信息
_RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight}; _RenderGuidanceInfo.rect = {Xpos, Ypos, scaledWidth, scaledHeight};
// 如果有阴影 计算阴影的渲染信息
if (ShadowFlag)
CalculateShadowData();
_RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY}; _RenderGuidanceInfo.AnchorPos = {scaledAnchorOffsetX, scaledAnchorOffsetY};
// 设置纹理透明度 // 设置纹理透明度
SDL_SetTextureAlphaMod(m_texture->GetTexture(), this->Alpha * 255); m_texture->setAlpha(this->Alpha);
// 屏幕内检测 // 屏幕内检测
int screenWidth = Game::GetInstance().Screen_W; int screenWidth = Game::GetInstance().Screen_W;
@@ -113,17 +134,6 @@ void Sprite::CalcRenderInfoLogic()
CalcRenderInfoFlag = false; CalcRenderInfoFlag = false;
} }
void Sprite::SetClipRect(SDL_Rect clipRect)
{
CropFlag = true;
CropRect = clipRect;
}
void Sprite::UnsetClipRect()
{
CropFlag = false;
}
void Sprite::PreRender() void Sprite::PreRender()
{ {
if (CalcRenderInfoFlag && Visible) if (CalcRenderInfoFlag && Visible)
@@ -134,32 +144,26 @@ void Sprite::Render()
{ {
if (!Visible) if (!Visible)
return; return;
SDL_Renderer *renderer = Game::GetInstance().GetRenderer();
if (!m_texture) if (!m_texture)
return; return;
RenderManager *renderer = Game::GetInstance().GetRenderer();
if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible) if (_RenderGuidanceInfo.IsInScreen && _RenderGuidanceInfo.Visible)
{ {
// 如果有阴影绘制阴影 SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
if (ShadowFlag)
{ // 混合
std::array<int, 6> indices = {0, 1, 2, 1, 3, 2}; if (this->_BlendMode != NONE)
SDL_RenderGeometry(renderer, m_texture->GetTexture(), vertices.data(), vertices.size(), indices.data(), indices.size()); 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);
if (_RenderGuidanceInfo.rotation != 0.f || _RenderGuidanceInfo.flip != SDL_FLIP_NONE)
{
SDL_FPoint AnchorPos = _RenderGuidanceInfo.AnchorPos;
SDL_RenderCopyExF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect, _RenderGuidanceInfo.rotation, &AnchorPos, _RenderGuidanceInfo.flip);
}
else
{
SDL_RenderCopyF(renderer, m_texture->GetTexture(), NULL, &_RenderGuidanceInfo.rect);
// // 设置绘制颜色
// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
// // 绘制填充矩形
// SDL_RenderFillRectF(renderer, &_RenderGuidanceInfo.rect);
}
Game::GetInstance().m_RenderCount++; Game::GetInstance().m_RenderCount++;
} }
} }
@@ -168,72 +172,22 @@ void Sprite::Clear()
{ {
} }
void Sprite::SetBlendMode(SDL_BlendMode blendMode) void Sprite::SetBlendMode(LE_BlEND_MODE mode)
{ {
if (GetBlendMode() != blendMode) this->_BlendMode = mode;
m_texture->SetBlendMode(blendMode);
} }
SDL_BlendMode Sprite::GetBlendMode() void Sprite::Blend()
{ {
return m_texture->GetBlendMode(); switch (this->_BlendMode)
}
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 case LINEARDODGE:
if (flipHorizontal) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
{ break;
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;
} }
} }
LE_BlEND_MODE Sprite::GetBlendMode()
{
return this->_BlendMode;
}

View File

@@ -8,7 +8,7 @@ class Game;
/** /**
* @brief Sprite类继承自Component类用于表示游戏中的精灵组件 * @brief Sprite类继承自Component类用于表示游戏中的精灵组件
*/ */
class Sprite : public RenderBase class Sprite : public RenderBase
{ {
protected: protected:
RefPtr<Texture> m_texture = nullptr; RefPtr<Texture> m_texture = nullptr;
@@ -22,36 +22,26 @@ public:
void PreRender() override; void PreRender() override;
void Clear() override; void Clear() override;
void Init() override; void Init() override;
void SetTexture(RefPtr<Texture> texture);
RefPtr<Texture> GetTexture(); RefPtr<Texture> GetTexture();
public: public:
// 渲染信息 // 渲染信息
RenderGuidanceInfo _RenderGuidanceInfo; RenderGuidanceInfo _RenderGuidanceInfo;
// 裁切数据 // 混合模式
SDL_Rect CropRect = {0, 0, 0, 0}; LE_BlEND_MODE _BlendMode = NONE;
// 裁切Flag
bool CropFlag = false;
// 阴影数据
std::array<SDL_Vertex, 4> vertices;
// 阴影Flag
bool ShadowFlag = false;
std::string imgPath; std::string imgPath;
int Index; int Index;
public: public:
// 计算渲染信息 // 计算渲染信息
void CalcRenderInfoLogic(); void CalcRenderInfoLogic();
// 设置裁切区域
void SetClipRect(SDL_Rect clipRect);
// 取消裁切区域
void UnsetClipRect();
// 设置混合模式 // 设置混合模式
void SetBlendMode(SDL_BlendMode blendMode); void SetBlendMode(LE_BlEND_MODE mode);
// 混合
void Blend();
// 获取混合模式 // 获取混合模式
SDL_BlendMode GetBlendMode(); LE_BlEND_MODE GetBlendMode();
// 设置阴影
void SetShadow();
// 计算阴影数据
void CalculateShadowData();
}; };

View File

@@ -5,200 +5,56 @@ 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() Text::~Text()
{ {
} }
void Text::Init(std::string Str, TTF_Font *font, SDL_Color color) void Text::Init(std::string Str, TTF_Font *font, SDL_Color color)
{ {
// 标记该组件需要渲染和更新 if (!m_texture)
addTag(Tag::RENDER); {
addTag(Tag::UPDATE); this->m_font = font;
this->m_color = color;
// TTF_SetFontOutline(font, 1); }
// 先渲染为表面 // 先渲染为表面
SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color); SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, Str.c_str(), color);
if (!textSurface) if (!textSurface)
{ {
SDL_LogError(0, "文字渲染为表面失败TTF_Error:%s", TTF_GetError()); SDL_LogError(0, "文字渲染为表面失败TTF_Error:%s", TTF_GetError());
} }
// 转换为RGBA8888格式与OpenGL的GL_RGBA匹配
SDL_Surface *rgbaSurface = SDL_ConvertSurfaceFormat(
textSurface,
SDL_PIXELFORMAT_ABGR8888,
0);
SDL_FreeSurface(textSurface);
// 再将表面转换为纹理 // 再将表面转换为纹理
SDL_Renderer *renderer = Game::GetInstance().GetRenderer(); RenderManager *renderer = Game::GetInstance().GetRenderer();
m_texture = SDL_CreateTextureFromSurface(renderer, textSurface); m_texture = new Texture;
if (!m_texture) m_texture->Init(rgbaSurface);
{
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); SDL_FreeSurface(rgbaSurface);
} Sprite::Init();
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() void Text::Render()
{ {
SDL_Renderer *renderer = Game::GetInstance().GetRenderer(); Sprite::Render();
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) void Text::SetText(std::string Str)
{ {
if (Str == m_text) if (Str == m_text)
return; return;
if (!m_font)
{
SDL_LogError(0, "SetText失败字体指针为空");
return;
}
// 如果有原纹理先删除原纹理 // 如果有原纹理先删除原纹理
if (m_texture) if (m_texture)
{ {
SDL_DestroyTexture(m_texture);
m_texture = nullptr; // 置空指针 m_texture = nullptr; // 置空指针
} }
m_text = Str; m_text = Str;
// 根据是否有描边选择对应的Init方法 Init(Str, m_font, m_color);
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() std::string Text::GetText()

View File

@@ -1,59 +1,30 @@
#pragma once #pragma once
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h> #include <SDL2/SDL_ttf.h>
#include "EngineFrame/Component/Component.h" #include "EngineFrame/Component/Sprite.h"
class Game;
class Text : public Component class Text : public Sprite
{ {
private:
/* data */
SDL_Texture *m_texture = nullptr;
public: public:
Text(/* args */); Text(/* args */);
Text(std::string Str, TTF_Font *font, SDL_Color color);
Text(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
~Text(); ~Text();
// 显式引入基类的Init方法避免隐藏 // 显式引入基类的Init方法避免隐藏
using Component::Init; using Component::Init;
void Init(std::string Str, TTF_Font *font, SDL_Color color); void Init(std::string Str, TTF_Font *font, SDL_Color color);
void Init(std::string Str, TTF_Font *font, SDL_Color textColor, SDL_Color strokeColor, int strokeSize);
void HandleEvents(SDL_Event *e) override;
void Update(float deltaTime) override;
void Render() override; void Render() override;
void Clear() override;
SDL_Texture *GetTexture();
public: public:
// 组件标签 /** 文本内容 */
Tag m_tag = Tag::RENDER | Tag::UPDATE; // 标记该组件需要渲染和更新
std::string m_text; std::string m_text;
/** 字体 */
TTF_Font *m_font; TTF_Font *m_font;
SDL_Color m_text_color; /** 字体颜色 */
SDL_Color m_stroke_color; SDL_Color m_color;
int m_stroke_size = 0;
SDL_Point Pos = {0, 0}; // 位置坐标
SDL_Point TextureSize = {0, 0}; // 纹理大小
SDL_Point Size = {0, 0}; // 大小
SDL_Point Anchor = {0, 0}; // 中心点
float Angle = 0.0f; // 旋转角度
SDL_RendererFlip flip = SDL_FLIP_NONE; // 翻转
public: public:
// 设置坐标
void SetPos(SDL_Point pos);
// 设置文本 // 设置文本
void SetText(std::string Str); void SetText(std::string Str);
// 获取坐标
SDL_Point GetPos();
// 获取文本 // 获取文本
std::string GetText(); std::string GetText();
}; };

View File

@@ -0,0 +1,359 @@
#include "RenderManager.h"
#include <fstream>
#include "Texture.h"
RenderManager::RenderManager(SDL_Window *window)
{
_window = window;
// 创建OpenGL上下文
_ctx = SDL_GL_CreateContext(window);
if (!_ctx)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL context create failed: %s\n", SDL_GetError());
}
// 初始化GLAD
if (!gladLoadGLES2Loader((GLADloadproc)SDL_GL_GetProcAddress))
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GLAD init failed!\n");
}
// 获取窗口大小
int width, height;
SDL_GetWindowSize(window, &width, &height);
// 设置视口
glViewport(0, 0, width, height);
// 设置窗口尺寸
_windowWidth = width;
_windowHeight = height;
// 设置正交投影矩阵
_orthoMatrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f, -1.0f, 1.0f);
// 设置清屏颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 启用混合模式
glEnable(GL_BLEND);
// 默认设置标准alpha混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 初始化着色器程序
InitShaderProgram();
// 初始化绘制2D纹理缓冲程序
Init2DTextureProgram();
// 设定默认使用的着色器程序和缓冲程序
SetCurrentShaderProgram("normal");
SetCurrentBufferObject("2DTexture");
}
RenderManager::~RenderManager()
{
// 释放着色器程序
for (auto &[name, program] : _shaderProgramMap)
{
glDeleteProgram(program);
}
// 释放缓冲对象
for (auto &[name, program] : _RenderParamsMap)
{
glDeleteVertexArrays(1, &program.VAO);
glDeleteBuffers(1, &program.VBO);
glDeleteBuffers(1, &program.EBO);
}
// 释放OpenGL上下文
SDL_GL_DeleteContext(_ctx);
}
void RenderManager::InitShaderProgram()
{
std::ifstream shaderFile("shader/config.json");
nlohmann::json shaderConfig;
shaderFile >> shaderConfig;
for (auto &[groupName, groupData] : shaderConfig["shader"].items())
{
if (!groupData.is_object())
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "着色器组 %s 格式错误,跳过\n", groupName.c_str());
continue;
}
if (!groupData.contains("vertex") || !groupData["vertex"].is_string())
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 vertex 路径,跳过\n", groupName.c_str());
continue;
}
if (!groupData.contains("fragment") || !groupData["fragment"].is_string())
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 缺少 fragment 路径,跳过\n", groupName.c_str());
continue;
}
std::string vertPath = groupData["vertex"].get<std::string>();
std::string fragPath = groupData["fragment"].get<std::string>();
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertPath);
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragPath);
if (vertexShader == 0 || fragmentShader == 0)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器编译失败,跳过\n", groupName.c_str());
continue;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint programLinksuccess;
glGetProgramiv(program, GL_LINK_STATUS, &programLinksuccess);
if (!programLinksuccess)
{
char infoLog[512];
glGetProgramInfoLog(program, 512, nullptr, infoLog);
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "组 %s 着色器链接失败,失败原因: %s\n", groupName.c_str(), infoLog);
}
_shaderProgramMap[groupName] = program;
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
}
void RenderManager::Init2DTextureProgram()
{
// 初始化顶点数据(矩形的四个顶点)
float vertices[] = {
0.0f, 0.0f, 0.0f, 0.0f, // 左下(单位坐标)
1.0f, 0.0f, 1.0f, 0.0f, // 右下
1.0f, 1.0f, 1.0f, 1.0f, // 右上
0.0f, 1.0f, 0.0f, 1.0f // 左上
};
// 索引数组
unsigned int indices[] = {0, 1, 2, 2, 3, 0};
GLuint VAO, VBO, EBO;
// 创建VAO/VBO/EBO
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// 创建完解绑
glBindVertexArray(0);
SetCurrentShaderProgram("normal");
glUseProgram(_currentShaderProgram);
// 获取uniform变量位置
GLuint _uModelLoc = glGetUniformLocation(_currentShaderProgram, "uModel");
GLuint _uViewProjLoc = glGetUniformLocation(_currentShaderProgram, "uViewProj");
GLuint _uTextureLoc = glGetUniformLocation(_currentShaderProgram, "uTexture");
if (_uModelLoc == -1 || _uViewProjLoc == -1 || _uTextureLoc == -1)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无法获取着色器 uniform 变量位置\n");
}
std::vector<GLuint> uniformLocs = {_uModelLoc, _uViewProjLoc, _uTextureLoc};
DrawLogicFunc drawFunc = [this](
RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
{
GLuint texture = textureObj->getID();
if (!texture || !dstrect)
return;
glUseProgram(_currentShaderProgram);
glm::mat4 model = glm::mat4(1.0f);
// 平移
model = glm::translate(model, glm::vec3(dstrect->x, dstrect->y, 0.0f));
// 计算旋转中心
float centerX = center ? center->x : dstrect->w * 0.5f;
float centerY = center ? center->y : dstrect->h * 0.5f;
// 旋转中心平移
model = glm::translate(model, glm::vec3(centerX, centerY, 0.0f));
// 旋转
if (angle != 0.0)
{
model = glm::rotate(model, glm::radians(static_cast<float>(angle)), glm::vec3(0.0f, 0.0f, 1.0f));
}
// 旋转中心平移
model = glm::translate(model, glm::vec3(-centerX, -centerY, 0.0f));
// 缩放和翻转
float scaleX = dstrect->w;
float scaleY = dstrect->h;
// 应用翻转(通过负缩放实现)
if (flip & SDL_FLIP_HORIZONTAL)
scaleX = -scaleX;
if (flip & SDL_FLIP_VERTICAL)
scaleY = -scaleY;
model = glm::scale(model, glm::vec3(scaleX, scaleY, 1.0f));
// 翻转后的位置补偿
if (flip & SDL_FLIP_HORIZONTAL)
{
model = glm::translate(model, glm::vec3(-1.0f, 0.0f, 0.0f));
}
if (flip & SDL_FLIP_VERTICAL)
{
model = glm::translate(model, glm::vec3(0.0f, -1.0f, 0.0f));
}
// 设置着色器 uniforms
glUniformMatrix4fv(_currentRenderParams.UnimLocs[0], 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(_currentRenderParams.UnimLocs[1], 1, GL_FALSE, glm::value_ptr(_orthoMatrix));
// 绑定纹理并设置采样器
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(_currentRenderParams.UnimLocs[2], 0);
// 处理纹理裁剪
int texWidth = textureObj->getSize().width;
int texHeight = textureObj->getSize().height;
// 计算纹理坐标
float minu, minv, maxu, maxv;
if (srcrect)
{
minu = (float)srcrect->x / texWidth;
minv = (float)srcrect->y / texHeight;
maxu = (float)(srcrect->x + srcrect->w) / texWidth;
maxv = (float)(srcrect->y + srcrect->h) / texHeight;
}
else
{
minu = 0.0f;
minv = 0.0f;
maxu = 1.0f;
maxv = 1.0f;
}
// 计算顶点位置(单位矩形,通过模型变换进行缩放和平移)
float minx = 0.0f;
float miny = 0.0f;
float maxx = 1.0f;
float maxy = 1.0f;
// 创建顶点数据(位置 + 纹理坐标)
float vertices[] = {
// 位置 // 纹理坐标
minx, miny, minu, minv, // 左上
maxx, miny, maxu, minv, // 右上
maxx, maxy, maxu, maxv, // 右下
minx, maxy, minu, maxv // 左下
};
// 更新VBO数据
glBindBuffer(GL_ARRAY_BUFFER, _currentRenderParams.VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
// 绘制纹理
glBindVertexArray(_currentRenderParams.VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
};
GL_RenderParams bufferObject = {VAO, VBO, EBO, uniformLocs, drawFunc};
AddBufferObject("2DTexture", bufferObject);
}
void RenderManager::SetCurrentShaderProgram(std::string name)
{
if (_shaderProgramMap.find(name) != _shaderProgramMap.end())
{
this->_currentShaderProgram = _shaderProgramMap[name];
}
else
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到着色器程序: %s\n", name.c_str());
}
void RenderManager::SetCurrentBufferObject(std::string name)
{
if (_RenderParamsMap.find(name) != _RenderParamsMap.end())
{
this->_currentRenderParams = _RenderParamsMap[name];
}
else
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染参数: %s\n", name.c_str());
}
void RenderManager::ClearScreen()
{
glClear(GL_COLOR_BUFFER_BIT);
}
void RenderManager::SwapBuffer()
{
SDL_GL_SwapWindow(_window);
}
void RenderManager::SetClipRect(const SDL_Rect *rect)
{
glEnable(GL_SCISSOR_TEST);
glScissor(rect->x, _windowHeight - rect->y - rect->h, rect->w, rect->h);
}
void RenderManager::CloseClipRect()
{
glDisable(GL_SCISSOR_TEST);
}
void RenderManager::DrawTexture(RefPtr<Texture> textureObj, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata)
{
if (_currentRenderParams.DrawFunc != nullptr)
_currentRenderParams.DrawFunc(textureObj, srcrect, dstrect, angle, center, flip, userdata);
else
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "找不到渲染逻辑函数\n");
}
GLuint RenderManager::CompileShader(GLenum type, std::string Path)
{
std::ifstream Source("shader/" + Path);
if (!Source.is_open())
{
SDL_LogError(0, "Failed to open shader file: %s\n", Path.c_str());
return 0;
}
std::string ShaderSource((std::istreambuf_iterator<char>(Source)), std::istreambuf_iterator<char>());
const char *SourcePtr = ShaderSource.c_str();
GLuint ShaderId = glCreateShader(type);
glShaderSource(ShaderId, 1, &SourcePtr, NULL);
glCompileShader(ShaderId);
// 检查编译错误
GLint success;
glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetShaderInfoLog(ShaderId, 512, nullptr, infoLog);
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Shader compile error: %s\n", infoLog);
glDeleteShader(ShaderId);
return 0;
}
return ShaderId;
}
void RenderManager::AddBufferObject(std::string name, GL_RenderParams bufferObject)
{
_RenderParamsMap[name] = bufferObject;
}

View File

@@ -0,0 +1,78 @@
#pragma once
#include <SDL.h>
#include <SDL_image.h>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
#include <string>
#include <json.hpp>
#include "EngineFrame/Render/Texture.h"
class RenderManager
{
public:
// 绘制纹理的逻辑函数
using DrawLogicFunc = std::function<void(RefPtr<Texture>, const SDL_Rect *, const SDL_FRect *,
double, const SDL_FPoint *, SDL_RendererFlip,
void *)>;
struct GL_RenderParams
{
GLuint VAO;
GLuint VBO;
GLuint EBO;
std::vector<GLuint> UnimLocs;
DrawLogicFunc DrawFunc = nullptr;
};
private:
SDL_Window *_window;
// 窗口尺寸
int _windowWidth;
int _windowHeight;
// 正交投影矩阵
glm::mat4 _orthoMatrix;
// 渲染器上下文
SDL_GLContext _ctx;
// 着色器程序
std::map<std::string, GLuint> _shaderProgramMap;
// 渲染参数
std::map<std::string, GL_RenderParams> _RenderParamsMap;
// 当前使用着色器程序
GLuint _currentShaderProgram;
// 当前使用渲染参数
GL_RenderParams _currentRenderParams;
public:
RenderManager(SDL_Window *window);
~RenderManager();
// 初始化着色器程序
void InitShaderProgram();
// 初始化绘制2D纹理缓冲程序
void Init2DTextureProgram();
// 设定当前使用的着色器程序
void SetCurrentShaderProgram(std::string name);
// 设定当前使用的缓冲对象
void SetCurrentBufferObject(std::string name);
// 清空屏幕
void ClearScreen();
// 交换缓冲区
void SwapBuffer();
// 设置裁切区域
void SetClipRect(const SDL_Rect *rect);
// 关闭裁切区域
void CloseClipRect();
// 绘制纹理
void DrawTexture(RefPtr<Texture> texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, void *userdata = nullptr);
private:
// 编译着色器
GLuint CompileShader(GLenum type, std::string Path);
// 新增缓冲程序
void AddBufferObject(std::string name, GL_RenderParams bufferObject);
};

View File

@@ -1,91 +1,204 @@
#include "EngineFrame/Render/Texture.h" #include "Texture.h"
#include "Asset/Asset_ImagePack.h" #include "Asset/Asset_ImagePack.h"
#include "EngineCore/Game.h" #include "EngineCore/Game.h"
#include "Texture.h"
Texture::Texture() Texture::Texture()
{ {
} }
Texture::Texture(std::string PngPath) Texture::~Texture()
{
glDeleteTextures(1, &m_TextureID);
}
bool Texture::Init(std::string PngPath)
{ {
SDL_Surface *surface = IMG_Load(PngPath.c_str()); SDL_Surface *surface = IMG_Load(PngPath.c_str());
if (!surface) if (!surface)
{ {
SDL_Log("无法加载图片: %s", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Couldn't load image %s: %s", PngPath.c_str(), IMG_GetError());
return; return false;
} }
SDL_Surface *rgbaSurface = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
m_texture = SDL_CreateTextureFromSurface(Game::GetInstance().GetRenderer(), surface);
if (!m_texture)
{
SDL_Log("无法创建纹理: %s", SDL_GetError());
SDL_FreeSurface(surface); // 记得释放surface
return;
}
this->TextureSize.width = surface->w;
this->TextureSize.height = surface->h;
this->TextureFramepos.width = surface->w;
this->TextureFramepos.height = surface->h;
SDL_FreeSurface(surface); SDL_FreeSurface(surface);
if (!rgbaSurface)
{
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to convert surface: %s\n", SDL_GetError());
return false;
}
// 生成OpenGL纹理
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
// 环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 缩小过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// 放大过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// 处理像素对齐确保SDL的像素行对齐与OpenGL兼容
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 记录纹理信息
m_TextureSize.width = rgbaSurface->w;
m_TextureSize.height = rgbaSurface->h;
m_FrameSize.width = rgbaSurface->w;
m_FrameSize.height = rgbaSurface->h;
m_Path = PngPath;
// 将像素数据上传到GPU
glTexImage2D(
GL_TEXTURE_2D,
0, // 纹理级别(基础级)
GL_RGBA8, // 内部存储格式8位RGBA
m_TextureSize.width,
m_TextureSize.height,
0, // 边框必须为0
GL_RGBA, // 源数据格式与SDL转换后的格式一致
GL_UNSIGNED_BYTE, // 源数据类型(无符号字节)
rgbaSurface->pixels);
// 释放转换后的表面数据已上传到GPU
SDL_FreeSurface(rgbaSurface);
return true;
} }
Texture::Texture(std::string imgPath, int Index) bool Texture::Init(std::string ImgPath, int Index)
{ {
this->ImgPath = imgPath; m_Path = ImgPath;
this->Index = Index; m_TextureIndex = Index;
Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(imgPath); Asset_ImagePack::IMG *Info = Asset_ImagePack::GetInstance().GetIMG(ImgPath);
if (Info->lpImgName == "sprite/interface/base.img") if (Info->lpImgName == "sprite/interface/base.img")
return; return false;
Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index]; Asset_ImagePack::ImgInfo &Buf = Info->lp_lplist[Index];
m_texture = SDL_CreateTexture( // 检查像素数据是否有效
Game::GetInstance().GetRenderer(), if (!Buf.PNGdata || Buf.Width <= 0 || Buf.Height <= 0)
SDL_PIXELFORMAT_ARGB8888, // 匹配RGBA数据格式
SDL_TEXTUREACCESS_STREAMING,
Buf.Width, Buf.Height);
if (!m_texture)
{ {
SDL_Log("纹理创建失败: %s", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_ERROR, "无效的图像数据: %s (index: %d)", ImgPath.c_str(), Index);
return false;
} }
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_ScaleModeNearest);
this->TexturePos.x = Buf.Xpos; int pixelCount = Buf.Width * Buf.Height;
this->TexturePos.y = Buf.Ypos; uint32_t *srcPixels = reinterpret_cast<uint32_t *>(Buf.PNGdata);
this->TextureSize.width = Buf.Width; uint32_t *dstPixels = new uint32_t[pixelCount];
this->TextureSize.height = Buf.Height; for (int i = 0; i < pixelCount; ++i)
this->TextureFramepos.width = Buf.FrameXpos; {
this->TextureFramepos.height = Buf.FrameYpos; uint8_t b = (srcPixels[i] >> 0) & 0xFF; // 蓝
uint8_t g = (srcPixels[i] >> 8) & 0xFF; // 绿
uint8_t r = (srcPixels[i] >> 16) & 0xFF; // 红
uint8_t a = (srcPixels[i] >> 24) & 0xFF; // 透明
dstPixels[i] = (a << 24) | (b << 16) | (g << 8) | r; // 重组为 RGBA
}
// 生成OpenGL纹理
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
// 设置纹理参数保持与原有SDL纹理相同的采样模式
// 环绕方式:重复
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 过滤方式最近邻与SDL_ScaleModeNearest对应
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 处理像素对齐SDL表面可能有不同的行对齐方式
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 记录纹理信息
m_TextureSize.width = Buf.Width;
m_TextureSize.height = Buf.Height;
m_FrameSize.width = Buf.FrameXpos;
m_FrameSize.height = Buf.FrameYpos;
m_TexturePos.x = Buf.Xpos;
m_TexturePos.y = Buf.Ypos;
// 上传纹理数据到GPU
glTexImage2D(
GL_TEXTURE_2D,
0, // 基础纹理级别
GL_RGBA8, // 内部存储格式8位RGBA
m_TextureSize.width,
m_TextureSize.height,
0, // 无边框
GL_RGBA, // 源数据格式(根据实际数据格式调整)
GL_UNSIGNED_BYTE, // 源数据类型
dstPixels);
return true;
} }
Texture::~Texture() bool Texture::Init(SDL_Surface *rgbaSurface)
{ {
SDL_DestroyTexture(m_texture); // 生成OpenGL纹理
glGenTextures(1, &m_TextureID);
glBindTexture(GL_TEXTURE_2D, m_TextureID);
// 环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 缩小过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 放大过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 处理像素对齐确保SDL的像素行对齐与OpenGL兼容
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 记录纹理信息
m_TextureSize.width = rgbaSurface->w;
m_TextureSize.height = rgbaSurface->h;
m_FrameSize.width = rgbaSurface->w;
m_FrameSize.height = rgbaSurface->h;
// 将像素数据上传到GPU
glTexImage2D(
GL_TEXTURE_2D,
0, // 纹理级别(基础级)
GL_RGBA8, // 内部存储格式8位RGBA
m_TextureSize.width,
m_TextureSize.height,
0, // 边框必须为0
GL_RGBA, // 源数据格式与SDL转换后的格式一致
GL_UNSIGNED_BYTE, // 源数据类型(无符号字节)
rgbaSurface->pixels);
return true;
} }
SDL_Texture *Texture::GetTexture() bool Texture::Init(VecSize size)
{ {
return m_texture; glGenTextures(1, &m_TextureID);
} glBindTexture(GL_TEXTURE_2D, m_TextureID);
// 设置纹理参数(根据需求调整尺寸、格式)
glTexImage2D(
GL_TEXTURE_2D,
0, // 多级渐远纹理级别
GL_RGBA, // 内部格式(存储格式)
size.width, // 纹理宽度
size.height, // 纹理高度
0, // 边框必须为0
GL_RGBA, // 源数据格式
GL_UNSIGNED_BYTE, // 源数据类型
nullptr // 初始数据(为空,后续绘制填充)
);
RefPtr<Texture> Texture::GetTextureCopy() // 记录纹理信息
{ m_TextureSize = size;
RefPtr<Texture> nt = new Texture(this->ImgPath, this->Index); m_FrameSize = size;
return nt;
}
void Texture::SetBlendMode(SDL_BlendMode blendMode) // 环绕方式
{ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
SDL_SetTextureBlendMode(m_texture, blendMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
} // 缩小过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// 放大过滤:使用最近邻采样
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
SDL_BlendMode Texture::GetBlendMode() glBindTexture(GL_TEXTURE_2D, 0); // 解绑
{ return true;
SDL_BlendMode blendMode; }
SDL_GetTextureBlendMode(m_texture, &blendMode);
return blendMode;
}

View File

@@ -1,33 +1,59 @@
#pragma once #pragma once
#include <SDL.h> #include <SDL.h>
#include <SDL_image.h>
#include <glad/glad.h>
#include <string> #include <string>
#include "Tool/RefPtr.h" #include "Tool/Common.h"
#include "Tool/RefObject.h" #include "Tool/RefObject.h"
#include "Tool/RefPtr.h"
#include "Tool/IntrusiveList.hpp"
class Texture : public RefObject class Texture : public RefObject
{ {
private: private:
SDL_Texture *m_texture = nullptr; // OpenGL 纹理ID
std::string ImgPath = ""; GLuint m_TextureID;
int Index = 0; // 纹理大小
public: VecSize m_TextureSize;
VecSize TextureSize = {0, 0}; // 纹理大小 // 帧域大小
VecPos TexturePos = {0, 0}; // 纹理位置 VecSize m_FrameSize;
VecSize TextureFramepos = {0, 0}; // 帧域宽高 // 纹理坐标
VecPos m_TexturePos;
// 纹理透明度
float m_Alpha = 1.0f;
// 纹理路径
std::string m_Path;
// 纹理编号(可选 在使用img构造时才会有编号)
int m_TextureIndex = -1;
public: public:
Texture(/* args */); Texture(/* args */);
Texture(std::string PngPath);
Texture(std::string imgPath, int Index);
~Texture(); ~Texture();
Texture(const Texture &) = delete;
Texture &operator=(const Texture &) = delete;
public: public:
void SetBlendMode(SDL_BlendMode blendMode); // 获取纹理ID
// 获取混合模式 GLuint getID() const { return m_TextureID; }
SDL_BlendMode GetBlendMode(); // 设置纹理透明度
// 获取纹理 void setAlpha(float alpha) { m_Alpha = alpha; }
SDL_Texture *GetTexture(); // 获取纹理透明度
// 获取一个拷贝的纹理 float getAlpha() const { return m_Alpha; }
RefPtr<Texture> GetTextureCopy(); // 获取纹理大小
VecSize getSize() const { return m_TextureSize; }
// 获取纹理坐标
VecPos getPos() const { return m_TexturePos; }
// 获取纹理路径
std::string getPath() const { return m_Path; }
// 获取纹理编号
int getIndex() const { return m_TextureIndex; }
// 获取帧域大小
VecSize getFrameSize() const { return m_FrameSize; }
public:
bool Init(std::string PngPath);
bool Init(std::string ImgPath, int index);
bool Init(SDL_Surface *surface);
bool Init(VecSize size);
}; };

View File

@@ -85,6 +85,11 @@ typedef struct VecPos
return *this; return *this;
} }
// 乘法
VecPos operator*(float value) const
{
return VecPos(x * value, y * value);
}
} VecPos; } VecPos;
// 浮点数坐标向量 // 浮点数坐标向量
@@ -195,6 +200,12 @@ typedef struct VecSize
height -= other.height; height -= other.height;
return *this; return *this;
} }
// 乘法
VecSize operator*(float value) const
{
return VecSize(width * value, height * value);
}
} VecSize; } VecSize;
typedef struct VecPos3 typedef struct VecPos3
@@ -247,4 +258,10 @@ typedef struct VecSpeed3
{ {
return x == other.x && y == other.y && z == other.z; return x == other.x && y == other.y && z == other.z;
} }
} VecSpeed3; } VecSpeed3;
enum LE_BlEND_MODE
{
NONE,
LINEARDODGE
};

View File

@@ -54,4 +54,19 @@ std::string Tool_TruncatePath(const std::string &path)
// 如果没有找到 '/',返回原字符串(或根据需求返回空) // 如果没有找到 '/',返回原字符串(或根据需求返回空)
return path; return path;
} }
int Tool_get_file_size(const std::string &path)
{
FILE *file = fopen(path.c_str(), "rb");
if (file == nullptr)
{
return -1;
}
fseek(file, 0, SEEK_END);
int size = ftell(file);
fclose(file);
return size;
}

View File

@@ -7,4 +7,6 @@ std::string Tool_toLowerCase(const std::string &str);
std::string Tool_RegRealPath(const std::string &Path); std::string Tool_RegRealPath(const std::string &Path);
std::string Tool_TruncatePath(const std::string &path); std::string Tool_TruncatePath(const std::string &path);
int Tool_get_file_size(const std::string &path);

View File

@@ -78,7 +78,9 @@ bool SquirrelEx::Compilebuffer(std::string Path, std::string Code)
void SquirrelEx::Init() void SquirrelEx::Init()
{ {
v = sq_open(1024); // 栈大小1024 // 初始化虚拟机
if (v == nullptr)
v = sq_open(1024); // 栈大小1024
sqstd_seterrorhandlers(v); sqstd_seterrorhandlers(v);
sq_pushroottable(v); sq_pushroottable(v);
sqstd_register_bloblib(v); sqstd_register_bloblib(v);
@@ -89,6 +91,20 @@ void SquirrelEx::Init()
sq_setprintfunc(v, printfunc, errorfunc); sq_setprintfunc(v, printfunc, errorfunc);
#ifdef __SWITCH__
#else
// 获取工作目录 switch 不允许)
WorkPath = SDL_GetBasePath();
FILE *file1 = fopen("DevMode.ini", "rb");
if (file1)
{
sq_enabledebuginfo(v, true);
dbg = sqdbg_attach_debugger(v);
sqdbg_listen_socket(dbg, 2222);
}
#endif
// 加载脚本 // 加载脚本
LoadLocalScript(); LoadLocalScript();
} }
@@ -151,6 +167,14 @@ void SquirrelEx::LoadLocalScript()
continue; continue;
std::string RegistPath = "sqr/" + clean_line; std::string RegistPath = "sqr/" + clean_line;
#ifndef __SWITCH__
std::replace(RegistPath.begin(), RegistPath.end(), '/', '\\');
RegistPath = WorkPath + RegistPath;
_scriptmap[RegistPath] = Tool_get_file_size(RegistPath);
#endif
if (!SQ_SUCCEEDED(sqstd_dofile(v, (SQChar *)(RegistPath.c_str()), SQFalse, SQTrue))) if (!SQ_SUCCEEDED(sqstd_dofile(v, (SQChar *)(RegistPath.c_str()), SQFalse, SQTrue)))
{ {
SDL_LogError(0, "脚本文件未找到,请检查项目目录 %s 文件是否存在", RegistPath.c_str()); SDL_LogError(0, "脚本文件未找到,请检查项目目录 %s 文件是否存在", RegistPath.c_str());
@@ -198,6 +222,37 @@ void SquirrelEx::Run()
sq_settop(v, top); // restores the original stack size sq_settop(v, top); // restores the original stack size
} }
void SquirrelEx::Update(float Dt)
{
#ifdef __SWITCH__
#else
sqdbg_frame(dbg);
// 热重载
if (HotReload)
{
for (auto &script : _scriptmap)
{
std::string path = script.first;
int value = script.second;
int newvalue = Tool_get_file_size(path);
if (value != newvalue)
{
if (SQ_SUCCEEDED(sqstd_dofile(v, (SQChar *)(path.c_str()), SQFalse, SQTrue)))
{
SDL_Log("脚本文件热重载成功 %s", path.c_str());
_scriptmap[path] = newvalue;
}
else
{
SDL_Log("脚本文件热重载失败 %s", path.c_str());
}
}
}
}
#endif
}
void SquirrelEx::Clean() void SquirrelEx::Clean()
{ {
sq_close(v); sq_close(v);

View File

@@ -12,6 +12,11 @@
#include "Tool/Tool_Network.h" #include "Tool/Tool_Network.h"
#ifdef __SWITCH__
#else
#include "sqdbg.h"
#endif
#ifdef SQUNICODE #ifdef SQUNICODE
#define scvprintf vfwprintf #define scvprintf vfwprintf
@@ -50,6 +55,7 @@ public:
void LoadLocalScript(); void LoadLocalScript();
// 运行 // 运行
void Run(); void Run();
void Update(float Dt);
// 清理 // 清理
void Clean(); void Clean();
@@ -60,5 +66,16 @@ private:
SquirrelEx(/* args */); SquirrelEx(/* args */);
~SquirrelEx(); ~SquirrelEx();
HSQUIRRELVM v = nullptr; HSQUIRRELVM v = nullptr;
#ifdef __SWITCH__
#else
// 虚拟机调试对象
HSQDEBUGSERVER dbg;
#endif
//工作目录
std::string WorkPath;
//热重载
bool HotReload = true;
std::map<std::string, int> _scriptmap;
}; };

View File

@@ -412,7 +412,7 @@ void GameMap::AddObject(RefPtr<BaseObject> object)
if (object->m_objecttype == ObjectType::CHARACTER) if (object->m_objecttype == ObjectType::CHARACTER)
{ {
CharacterObject *chr = (CharacterObject *)(object.Get()); CharacterObject *chr = (CharacterObject *)(object.Get());
_LayerMap["bottom"]->AddComponent(chr->_Shadow); if( chr->_Shadow != nullptr)_LayerMap["bottom"]->AddComponent(chr->_Shadow);
} }
} }

View File

@@ -12,9 +12,8 @@ GameMapLayer::~GameMapLayer()
void GameMapLayer::Render() void GameMapLayer::Render()
{ {
Actor::Render(); Actor::Render();
SDL_Renderer *renderer = Game::GetInstance().GetRenderer(); RenderManager *renderer = Game::GetInstance().GetRenderer();
// 设置绘制颜色
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 128);
// 自身坐标 // 自身坐标
float Xpos = GetIterationPos().x + GetPos().x; float Xpos = GetIterationPos().x + GetPos().x;
float Ypos = GetIterationPos().y + GetPos().y; float Ypos = GetIterationPos().y + GetPos().y;
@@ -25,10 +24,8 @@ void GameMapLayer::Render()
buf.y = info.y + Ypos; buf.y = info.y + Ypos;
buf.w = info.w; buf.w = info.w;
buf.h = info.h; buf.h = info.h;
// 绘制填充矩形 //TODO: 渲染可行区域
SDL_RenderFillRect(renderer, &buf);
} }
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 250);
} }
void GameMapLayer::AddDebugFeasibleAreaInfo(VecFPos pos, VecSize size) void GameMapLayer::AddDebugFeasibleAreaInfo(VecFPos pos, VecSize size)

View File

@@ -11,7 +11,8 @@ Tile::Tile(std::string Path) : Sprite()
if (std::get<std::string>(m_data["path"]) == "") if (std::get<std::string>(m_data["path"]) == "")
m_data["path"] = "sprite/character/common/circlecooltime.img"; m_data["path"] = "sprite/character/common/circlecooltime.img";
m_texture = new Texture(std::get<std::string>(m_data["path"]), std::get<int>(m_data["idx"])); m_texture = new Texture();
m_texture->Init(std::get<std::string>(m_data["path"]), std::get<int>(m_data["idx"]));
Sprite::Init(); Sprite::Init();
this->imgPath = Path; this->imgPath = Path;
} }

View File

@@ -12,9 +12,9 @@ void CharacterObject::Construction(int job)
// 创建装备管理器 // 创建装备管理器
_EquipmentManager = new Chr_Equipment(); _EquipmentManager = new Chr_Equipment();
_EquipmentManager->Init(this); _EquipmentManager->Init(this);
// 创建阴影对象 // // 创建阴影对象
_Shadow = new Chr_Shadow(); // _Shadow = new Chr_Shadow();
_Shadow->Init(this); // _Shadow->Init(this);
// 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备) // 创建动画管理器(一定要先创建装备管理器再创建动画管理器 因为需要读取身上的装备)
_AnimationManager = new Chr_Animation(); _AnimationManager = new Chr_Animation();
_AnimationManager->Init(this); _AnimationManager->Init(this);

View File

@@ -33,17 +33,17 @@ void Chr_Animation::CreateSkinmationBySlot(std::string actionName, std::string s
// 构造好Ani以后 统一设置为不可见 然后放入ActionAnis表 // 构造好Ani以后 统一设置为不可见 然后放入ActionAnis表
RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data); RefPtr<Animation> Ani = new Animation(path, FormatImgPath, Data);
Ani->SetVisible(false); Ani->SetVisible(false);
Ani->SetRenderZOrder(Variation.Layer); Ani->SetRenderZOrder(Variation.Layer);
this->AddChild(Ani); this->AddChild(Ani);
ActionAnis[actionName].push_back(Ani); ActionAnis[actionName].push_back(Ani);
// 构造一下阴影对象 // 构造一下阴影对象 //TODO
RefPtr<Animation> ShadowAni = new Animation(path, FormatImgPath, Data); // RefPtr<Animation> ShadowAni = new Animation(path, FormatImgPath, Data);
ShadowAni->SetVisible(false); // ShadowAni->SetVisible(false);
// 皮肤统一设置阴影
ShadowAni->SetShadow(); // chr_parent->_Shadow->AddChild(ShadowAni);
chr_parent->_Shadow->AddChild(ShadowAni); // chr_parent->_Shadow->ActionAnis[actionName].push_back(ShadowAni);
chr_parent->_Shadow->ActionAnis[actionName].push_back(ShadowAni);
} }
} }
} }
@@ -82,7 +82,7 @@ void Chr_Animation::Init(CharacterObject *parent)
parent->AddChild(this); parent->AddChild(this);
chr_parent = parent; chr_parent = parent;
GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job]; GlobalCharacterScript::CharacterConfig Config = Global_Game::GetInstance().CharacterConfigs[parent->Job];
// 遍历所有动作Ani路径 // 遍历所有动作Ani路径
for (const auto &pair : Config.animationPath) for (const auto &pair : Config.animationPath)
{ {
@@ -116,5 +116,5 @@ void Chr_Animation::SetAction(std::string actionName)
CurrentActionTag = actionName; CurrentActionTag = actionName;
// 设置阴影的动作 // 设置阴影的动作
chr_parent->_Shadow->SetAction(actionName); if(chr_parent->_Shadow)chr_parent->_Shadow->SetAction(actionName);
} }

View File

@@ -130,6 +130,23 @@ static SQInteger SQR_SetPos(HSQUIRRELVM v)
return 0; return 0;
} }
static SQInteger SQR_GetWorldPos(HSQUIRRELVM v)
{
SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj);
Actor *Aobj = (Actor *)A_obj;
VecFPos Pos = Aobj->GetWorldPos();
sq_newtable(v);
sq_pushstring(v, _SC("x"), -1);
sq_pushfloat(v, Pos.x);
sq_newslot(v, 3, SQFalse);
sq_pushstring(v, _SC("y"), -1);
sq_pushfloat(v, Pos.y);
sq_newslot(v, 3, SQFalse);
return 1;
}
static SQInteger SQR_GetAlpha(HSQUIRRELVM v) static SQInteger SQR_GetAlpha(HSQUIRRELVM v)
{ {
SQUserPointer A_obj; SQUserPointer A_obj;
@@ -287,6 +304,16 @@ static SQInteger SQR_SetSize(HSQUIRRELVM v)
return 0; return 0;
} }
static SQInteger SQR_SetVisible(HSQUIRRELVM v){
SQUserPointer A_obj;
sq_getuserpointer(v, 2, &A_obj);
SQBool Value;
sq_getbool(v, 3, &Value);
Actor *Aobj = (Actor *)A_obj;
Aobj->SetVisible(Value);
return 0;
}
static SQInteger SQR_CreateSprite(HSQUIRRELVM v) static SQInteger SQR_CreateSprite(HSQUIRRELVM v)
{ {
const SQChar *ImgPath; const SQChar *ImgPath;
@@ -323,6 +350,7 @@ static void RegisterUI()
RegisterUINutApi(_SC("sq_SetZOrder"), SQR_SetZOrder, v); RegisterUINutApi(_SC("sq_SetZOrder"), SQR_SetZOrder, v);
RegisterUINutApi(_SC("sq_GetPos"), SQR_GetPos, v); RegisterUINutApi(_SC("sq_GetPos"), SQR_GetPos, v);
RegisterUINutApi(_SC("sq_SetPos"), SQR_SetPos, v); RegisterUINutApi(_SC("sq_SetPos"), SQR_SetPos, v);
RegisterUINutApi(_SC("sq_GetWorldPos"), SQR_GetWorldPos, v);
RegisterUINutApi(_SC("sq_GetAlpha"), SQR_GetAlpha, v); RegisterUINutApi(_SC("sq_GetAlpha"), SQR_GetAlpha, v);
RegisterUINutApi(_SC("sq_SetAlpha"), SQR_SetAlpha, v); RegisterUINutApi(_SC("sq_SetAlpha"), SQR_SetAlpha, v);
RegisterUINutApi(_SC("sq_GetScale"), SQR_GetScale, v); RegisterUINutApi(_SC("sq_GetScale"), SQR_GetScale, v);
@@ -331,6 +359,7 @@ static void RegisterUI()
RegisterUINutApi(_SC("sq_SetRotation"), SQR_SetRotation, v); RegisterUINutApi(_SC("sq_SetRotation"), SQR_SetRotation, v);
RegisterUINutApi(_SC("sq_GetSize"), SQR_GetSize, v); RegisterUINutApi(_SC("sq_GetSize"), SQR_GetSize, v);
RegisterUINutApi(_SC("sq_SetSize"), SQR_SetSize, v); RegisterUINutApi(_SC("sq_SetSize"), SQR_SetSize, v);
RegisterUINutApi(_SC("sq_SetVisible"), SQR_SetVisible, v);
RegisterUINutApi(_SC("sq_CreateSprite"), SQR_CreateSprite, v); RegisterUINutApi(_SC("sq_CreateSprite"), SQR_CreateSprite, v);
} }

View File

@@ -10,10 +10,10 @@ Global_Game::~Global_Game()
void Global_Game::Init() void Global_Game::Init()
{ {
// 初始化ttf字体资源 // 初始化ttf字体资源
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/LXGWWenKai-Regular.ttf", 24);
TTF_Font *FontBuf = TTF_OpenFont("Fonts/VonwaonBitmap-12px.ttf", 24); TTF_Font *FontBuf = TTF_OpenFont("Fonts/VonwaonBitmap-12px.ttf", 24);
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gothica-Book.ttf", 24); // TTF_Font *FontBuf = TTF_OpenFont("Fonts/NotoSansSC-Regular.otf", 24);
// TTF_Font *FontBuf = TTF_OpenFont("Fonts/Gasinamu.ttf", 24); // TTF_Font *FontBuf = TTF_OpenFont("Fonts/calibri.ttf", 24);
if (!FontBuf) if (!FontBuf)
{ {
SDL_LogError(0, "字体加载失败: %s", TTF_GetError()); SDL_LogError(0, "字体加载失败: %s", TTF_GetError());

View File

@@ -27,7 +27,7 @@ void Scene_Loading_UI::Enter()
RefPtr<Sprite> LoadCircleSp = new Sprite("ImagePacks2/Loading2.png"); RefPtr<Sprite> LoadCircleSp = new Sprite("ImagePacks2/Loading2.png");
LoadCircleSp->SetName("LoadCircle"); LoadCircleSp->SetName("LoadCircle");
LoadCircleSp->SetPos(VecFPos{1280 - 60, 686 - 60}); LoadCircleSp->SetPos(VecFPos{1280 - 60, 686 - 60});
LoadCircleSp->SetBlendMode(SDL_BLENDMODE_ADD); LoadCircleSp->SetBlendMode(LINEARDODGE);
LoadCircleSp->SetAnchor(VecFPos{0.5f, 0.5f}); LoadCircleSp->SetAnchor(VecFPos{0.5f, 0.5f});
actor->AddComponent(LoadCircleSp); actor->AddComponent(LoadCircleSp);

View File

@@ -16,12 +16,59 @@ void Scene_MainUi::Enter()
sq_call(v, 2, SQFalse, SQTrue); sq_call(v, 2, SQFalse, SQTrue);
} }
sq_settop(v, top); sq_settop(v, top);
} }
void Scene_MainUi::HandleEvents(SDL_Event *e) void Scene_MainUi::HandleEvents(SDL_Event *event)
{ {
Scene::HandleEvents(e); SQInteger EventType = -1;
std::vector<SQInteger> EventData;
switch (event->type)
{
// 鼠标移动
case SDL_MOUSEMOTION:
{
EventType = 0;
EventData.push_back(event->motion.x);
EventData.push_back(event->motion.y);
break;
}
// 鼠标按键按下
case SDL_MOUSEBUTTONDOWN:
{
EventType = 1;
EventData.push_back(event->button.button);
break;
}
// 鼠标按键释放
case SDL_MOUSEBUTTONUP:
{
EventType = 2;
EventData.push_back(event->button.button);
break;
}
// 鼠标滚轮
case SDL_MOUSEWHEEL:
{
EventType = 3;
EventData.push_back(event->wheel.y);
break;
}
// 键盘按键按下
case SDL_KEYDOWN:
{
EventType = 4;
EventData.push_back(event->key.keysym.sym);
break;
}
// 键盘按键释放
case SDL_KEYUP:
{
EventType = 5;
EventData.push_back(event->key.keysym.sym);
break;
}
}
HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM(); HSQUIRRELVM v = SquirrelEx::GetInstance().GetSquirrelVM();
SQInteger top = sq_gettop(v); SQInteger top = sq_gettop(v);
sq_pushroottable(v); sq_pushroottable(v);
@@ -29,8 +76,14 @@ void Scene_MainUi::HandleEvents(SDL_Event *e)
if (SQ_SUCCEEDED(sq_get(v, -2))) if (SQ_SUCCEEDED(sq_get(v, -2)))
{ {
sq_pushroottable(v); sq_pushroottable(v);
sq_pushinteger(v, 1); sq_pushinteger(v, EventType);
sq_call(v, 2, SQFalse, SQTrue); sq_newarray(v, 0);
for (SQInteger i = 0; i < EventData.size(); i++)
{
sq_pushinteger(v, EventData[i]);
sq_arrayappend(v, -2);
}
sq_call(v, 3, SQFalse, SQTrue);
} }
sq_settop(v, top); sq_settop(v, top);
} }

View File

@@ -1,7 +1,10 @@
#include "Scene_Test.h" #include "Scene_Test.h"
#include <memory> #include <memory>
#include <EngineCore/Game.h> #include "EngineCore/Game.h"
#include <EngineFrame/Component/AnimationManager.h> #include "EngineFrame/Component/AnimationManager.h"
#include "EngineFrame/Component/Text.h"
#include "EngineFrame/Component/Canvas.h"
#include "Global/Global_Game.h"
Scene_Test::Scene_Test() Scene_Test::Scene_Test()
{ {
} }
@@ -13,44 +16,55 @@ Scene_Test::~Scene_Test()
void Scene_Test::Enter() void Scene_Test::Enter()
{ {
map = new GameMap; // SetScale(VecFPos(1.2f, 1.2f));
map->LoadMap("map/cataclysm/town/elvengard/new_elvengard.map"); // map = new GameMap;
map->Enter(this); // map->LoadMap("map/cataclysm/town/elvengard/new_elvengard.map");
// map->Enter(this);
RefPtr<CharacterObject> obj = new CharacterObject(); // RefPtr<CharacterObject> obj = new CharacterObject();
obj->SetPosition({1000, 300, 0}); // obj->SetPosition({1000, 300, 0});
obj->Construction(0); // obj->Construction(0);
RefPtr<MonsterObject> monster = new MonsterObject(); // RefPtr<MonsterObject> monster = new MonsterObject();
monster->SetPosition({1200, 301, 0}); // monster->SetPosition({1200, 301, 0});
monster->Construction(1); // monster->Construction(1);
monster->SetDirection(1); // monster->SetDirection(1);
map->AddObject(obj); // map->AddObject(obj);
map->AddObject(monster); // map->AddObject(monster);
_camera = new GameMapCamera; // _camera = new GameMapCamera;
_camera->SetFromActor(obj.Get()); // _camera->SetFromActor(obj.Get());
return; // return;
// SDL_Log("Scene_Test::进入测试场景!"); // // SDL_Log("Scene_Test::进入测试场景!");
RefPtr<Actor> actor = new Actor; RefPtr<Actor> actor = new Actor;
AddChild(actor); AddChild(actor);
// RefPtr<Sprite> sprite = new Sprite("ImagePacks2/test_white_background.png");
// actor->AddComponent(sprite);
// RefPtr<Sprite> chr = new Sprite("sprite/character/swordman/equipment/avatar/skin/sm_body0000.img", 90); RefPtr<Sprite> sprite = new Sprite("ImagePacks2/test_white_background.png");
RefPtr<Sprite> chr = new Sprite("sprite/interface2/hud/hud.img", 0);
// chr->SetPos(VecFPos{200, 100}); // chr->SetPos(VecFPos{200, 100});
// chr->SetAlpha(0.5); // chr->SetAlpha(0.5);
// chr->SetShadow(); // chr->SetShadow();
// actor->AddComponent(chr); actor->AddComponent(chr);
RefPtr<AnimationManager> Am = new AnimationManager; // RefPtr<Canvas> canvas = new Canvas(VecSize{1280, 720});
RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani"); // actor->AddChild(canvas);
Am->AddAnimation(ani4);
// Am->SetPos(VecFPos{200, 100}); // canvas->AddChild(chr);
actor->AddChild(Am);
// RefPtr<AnimationManager> Am = new AnimationManager;
// RefPtr<Animation> ani4 = new Animation("map/cataclysm/town/hendonmyre/animation/object/gateall_02.ani");
// Am->AddAnimation(ani4);
// // Am->SetPos(VecFPos{200, 100});
// actor->AddChild(Am);
// RefPtr<Text> text = new Text();
// text->Init("测试文本", Global_Game::GetInstance().Fonts[0], SDL_Color{255, 255, 255, 255});
// text->SetPos(VecFPos{200, 100});
// actor->AddChild(text);
// // sprite2->UnsetClipRect(); // // sprite2->UnsetClipRect();

View File

@@ -69,7 +69,6 @@ int main(int argc, char *argv[])
Asset_Script::GetInstance(); Asset_Script::GetInstance();
// 初始化线程池 // 初始化线程池
ThreadPool::GetInstance(); ThreadPool::GetInstance();
// 初始化日志系统 // 初始化日志系统
// Logger::GetInstance().Init(); // Logger::GetInstance().Init();
// 初始化Squirrel脚本系统 // 初始化Squirrel脚本系统