feat(渲染): 添加虚拟分辨率支持并重构相机系统
实现虚拟分辨率渲染系统,支持不同缩放模式 重构相机控制器以使用虚拟分辨率计算可见区域 移除硬编码的屏幕尺寸,改为动态获取 添加分辨率状态管理及相关工具函数 更新窗口和渲染器以处理分辨率变化
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <frostbite2D/core/window.h>
|
#include <frostbite2D/core/window.h>
|
||||||
#include <frostbite2D/graphics/camera.h>
|
#include <frostbite2D/graphics/camera.h>
|
||||||
|
#include <frostbite2D/graphics/render_resolution.h>
|
||||||
#include <frostbite2D/types/type_alias.h>
|
#include <frostbite2D/types/type_alias.h>
|
||||||
#include <frostbite2D/event/event.h>
|
#include <frostbite2D/event/event.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -37,6 +38,26 @@ struct AppConfig {
|
|||||||
*/
|
*/
|
||||||
PlatformType targetPlatform = PlatformType::Auto;
|
PlatformType targetPlatform = PlatformType::Auto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 是否启用虚拟分辨率
|
||||||
|
*/
|
||||||
|
bool useVirtualResolution = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 虚拟分辨率宽度
|
||||||
|
*/
|
||||||
|
int virtualWidth = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 虚拟分辨率高度
|
||||||
|
*/
|
||||||
|
int virtualHeight = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 虚拟分辨率缩放模式
|
||||||
|
*/
|
||||||
|
ResolutionScaleMode resolutionMode = ResolutionScaleMode::Fit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 创建默认配置
|
* @brief 创建默认配置
|
||||||
* @return 默认的应用配置实例
|
* @return 默认的应用配置实例
|
||||||
|
|||||||
@@ -8,30 +8,22 @@
|
|||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 鼠标指针类型
|
|
||||||
*/
|
|
||||||
enum class CursorType {
|
enum class CursorType {
|
||||||
Arrow, ///< 指针
|
Arrow,
|
||||||
TextInput, ///< 文本
|
TextInput,
|
||||||
Hand, ///< 手
|
Hand,
|
||||||
SizeAll, ///< 指向四个方向的箭头
|
SizeAll,
|
||||||
SizeWE, ///< 指向左右方向的箭头
|
SizeWE,
|
||||||
SizeNS, ///< 指向上下方向的箭头
|
SizeNS,
|
||||||
SizeNESW, ///< 指向左下到右上方向的箭头
|
SizeNESW,
|
||||||
SizeNWSE, ///< 指向左上到右下方向的箭头
|
SizeNWSE,
|
||||||
No, ///< 禁止
|
No,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 分辨率
|
|
||||||
*/
|
|
||||||
struct Resolution {
|
struct Resolution {
|
||||||
uint32_t width = 0; ///< 分辨率宽度
|
uint32_t width = 0;
|
||||||
uint32_t height = 0; ///< 分辨率高度
|
uint32_t height = 0;
|
||||||
uint32_t refresh_rate = 0; ///< 刷新率
|
uint32_t refresh_rate = 0;
|
||||||
|
|
||||||
Resolution() = default;
|
Resolution() = default;
|
||||||
|
|
||||||
@@ -39,41 +31,33 @@ struct Resolution {
|
|||||||
: width(width), height(height), refresh_rate(refresh_rate) {}
|
: width(width), height(height), refresh_rate(refresh_rate) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 图标
|
|
||||||
*/
|
|
||||||
struct Icon {
|
struct Icon {
|
||||||
Icon() = default;
|
Icon() = default;
|
||||||
|
|
||||||
Icon(std::string file_path) : file_path(file_path) {}
|
Icon(std::string file_path) : file_path(file_path) {}
|
||||||
|
|
||||||
std::string file_path; ///< 文件路径
|
std::string file_path;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
uint32_t resource_id = 0; ///< 资源ID,仅在windows上生效
|
uint32_t resource_id = 0;
|
||||||
|
|
||||||
Icon(uint32_t resource_id) : resource_id(resource_id) {}
|
Icon(uint32_t resource_id) : resource_id(resource_id) {}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \~chinese
|
|
||||||
* @brief 窗口设置
|
|
||||||
*/
|
|
||||||
struct WindowConfig {
|
struct WindowConfig {
|
||||||
uint32_t width = 640; ///< 窗口宽度
|
uint32_t width = 640;
|
||||||
uint32_t height = 480; ///< 窗口高度
|
uint32_t height = 480;
|
||||||
std::string title = "frostbite2D Game"; ///< 窗口标题
|
std::string title = "frostbite2D Game";
|
||||||
Icon icon; ///< 窗口图标
|
Icon icon;
|
||||||
bool resizable = false; ///< 窗口大小可调整
|
bool resizable = false;
|
||||||
bool fullscreen = false; ///< 窗口全屏
|
bool fullscreen = false;
|
||||||
bool borderless = false; ///< 无边框窗口
|
bool borderless = false;
|
||||||
bool decorated = true; ///< 窗口装饰
|
bool decorated = true;
|
||||||
int multisamples = 0; ///< 多重采样数
|
int multisamples = 0;
|
||||||
bool centered = true; ///< 窗口是否居中
|
bool centered = true;
|
||||||
bool vsync = true; ///< 是否启用垂直同步
|
bool vsync = true;
|
||||||
bool showCursor = true; ///< 是否显示光标
|
bool showCursor = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Window {
|
class Window {
|
||||||
@@ -81,179 +65,55 @@ public:
|
|||||||
Window() = default;
|
Window() = default;
|
||||||
~Window() = default;
|
~Window() = default;
|
||||||
|
|
||||||
/**
|
virtual bool create(const WindowConfig& cfg);
|
||||||
* @brief 创建窗口
|
|
||||||
* @param cfg 窗口配置
|
|
||||||
* @return 创建是否成功
|
|
||||||
*/
|
|
||||||
virtual bool create(const WindowConfig &cfg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 销毁窗口
|
|
||||||
*/
|
|
||||||
virtual void destroy();
|
virtual void destroy();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 轮询事件
|
|
||||||
*/
|
|
||||||
virtual void poll();
|
virtual void poll();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 交换缓冲区
|
|
||||||
*/
|
|
||||||
virtual void swap();
|
virtual void swap();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置窗口关闭标志
|
|
||||||
*/
|
|
||||||
virtual void close();
|
virtual void close();
|
||||||
|
virtual void setTitle(const std::string& title);
|
||||||
/**
|
|
||||||
* @brief 设置窗口标题
|
|
||||||
*/
|
|
||||||
virtual void setTitle(const std::string &title);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置窗口大小
|
|
||||||
*/
|
|
||||||
virtual void setSize(int w, int h);
|
virtual void setSize(int w, int h);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置窗口位置
|
|
||||||
*/
|
|
||||||
virtual void setPos(int x, int y);
|
virtual void setPos(int x, int y);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置全屏模式
|
|
||||||
*/
|
|
||||||
virtual void setFullscreen(bool fs);
|
virtual void setFullscreen(bool fs);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置垂直同步
|
|
||||||
*/
|
|
||||||
virtual void setVSync(bool vsync);
|
virtual void setVSync(bool vsync);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置窗口可见性
|
|
||||||
*/
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取窗口宽度
|
|
||||||
*/
|
|
||||||
virtual int width() const;
|
virtual int width() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取窗口高度
|
|
||||||
*/
|
|
||||||
virtual int height() const;
|
virtual int height() const;
|
||||||
|
virtual int drawableWidth() const;
|
||||||
/**
|
virtual int drawableHeight() const;
|
||||||
* @brief 获取窗口大小
|
|
||||||
*/
|
|
||||||
virtual Size size() const;
|
virtual Size size() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取窗口位置
|
|
||||||
*/
|
|
||||||
virtual Vec2 pos() const;
|
virtual Vec2 pos() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 是否全屏
|
|
||||||
*/
|
|
||||||
virtual bool fullscreen() const;
|
virtual bool fullscreen() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 是否启用垂直同步
|
|
||||||
*/
|
|
||||||
virtual bool vsync() const;
|
virtual bool vsync() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 窗口是否获得焦点
|
|
||||||
*/
|
|
||||||
virtual bool focused() const;
|
virtual bool focused() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 窗口是否最小化
|
|
||||||
*/
|
|
||||||
virtual bool minimized() const;
|
virtual bool minimized() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取内容缩放X
|
|
||||||
*/
|
|
||||||
virtual float scaleX() const;
|
virtual float scaleX() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取内容缩放Y
|
|
||||||
*/
|
|
||||||
virtual float scaleY() const;
|
virtual float scaleY() const;
|
||||||
|
virtual bool refreshMetrics(bool emitResize = false);
|
||||||
/**
|
|
||||||
* @brief 设置光标形状
|
|
||||||
*/
|
|
||||||
virtual void setCursor(CursorType cursor);
|
virtual void setCursor(CursorType cursor);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 显示/隐藏光标
|
|
||||||
*/
|
|
||||||
virtual void showCursor(bool show);
|
virtual void showCursor(bool show);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 锁定/解锁光标
|
|
||||||
*/
|
|
||||||
virtual void lockCursor(bool lock);
|
virtual void lockCursor(bool lock);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 窗口大小改变回调
|
|
||||||
*/
|
|
||||||
using ResizeCb = std::function<void(int, int)>;
|
using ResizeCb = std::function<void(int, int)>;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 窗口关闭回调
|
|
||||||
*/
|
|
||||||
using CloseCb = std::function<void()>;
|
using CloseCb = std::function<void()>;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 窗口焦点改变回调
|
|
||||||
*/
|
|
||||||
using FocusCb = std::function<void(bool)>;
|
using FocusCb = std::function<void(bool)>;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置大小改变回调
|
|
||||||
*/
|
|
||||||
virtual void onResize(ResizeCb cb);
|
virtual void onResize(ResizeCb cb);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置关闭回调
|
|
||||||
*/
|
|
||||||
virtual void onClose(CloseCb cb);
|
virtual void onClose(CloseCb cb);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 设置焦点改变回调
|
|
||||||
*/
|
|
||||||
virtual void onFocus(FocusCb cb);
|
virtual void onFocus(FocusCb cb);
|
||||||
|
virtual void* native() const;
|
||||||
|
|
||||||
/**
|
SDL_Window* sdlWindow() const { return sdlWindow_; }
|
||||||
* @brief 获取原生窗口句柄
|
|
||||||
*/
|
|
||||||
virtual void *native() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取 SDL 窗口句柄
|
|
||||||
*/
|
|
||||||
SDL_Window *sdlWindow() const { return sdlWindow_; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 获取 OpenGL 上下文
|
|
||||||
*/
|
|
||||||
SDL_GLContext glContext() const { return glContext_; }
|
SDL_GLContext glContext() const { return glContext_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SDL_Window *sdlWindow_ = nullptr;
|
SDL_Window* sdlWindow_ = nullptr;
|
||||||
SDL_GLContext glContext_ = nullptr;
|
SDL_GLContext glContext_ = nullptr;
|
||||||
|
|
||||||
int width_ = 1280;
|
int width_ = 1280;
|
||||||
int height_ = 720;
|
int height_ = 720;
|
||||||
|
int drawableWidth_ = 1280;
|
||||||
|
int drawableHeight_ = 720;
|
||||||
bool fullscreen_ = false;
|
bool fullscreen_ = false;
|
||||||
bool vsync_ = true;
|
bool vsync_ = true;
|
||||||
bool focused_ = true;
|
bool focused_ = true;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public:
|
|||||||
float getZoom() const { return zoom_; }
|
float getZoom() const { return zoom_; }
|
||||||
int getViewportWidth() const { return viewportWidth_; }
|
int getViewportWidth() const { return viewportWidth_; }
|
||||||
int getViewportHeight() const { return viewportHeight_; }
|
int getViewportHeight() const { return viewportHeight_; }
|
||||||
|
float getVisibleWidth() const;
|
||||||
|
float getVisibleHeight() const;
|
||||||
|
|
||||||
void lookAt(const Vec2& target);
|
void lookAt(const Vec2& target);
|
||||||
void move(const Vec2& delta);
|
void move(const Vec2& delta);
|
||||||
|
|||||||
43
Frostbite2D/include/frostbite2D/graphics/render_resolution.h
Normal file
43
Frostbite2D/include/frostbite2D/graphics/render_resolution.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <frostbite2D/types/type_math.h>
|
||||||
|
|
||||||
|
namespace frostbite2D {
|
||||||
|
|
||||||
|
enum class ResolutionScaleMode {
|
||||||
|
Disabled,
|
||||||
|
Fit,
|
||||||
|
FitHeight,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderResolutionState {
|
||||||
|
int windowWidth = 1280;
|
||||||
|
int windowHeight = 720;
|
||||||
|
|
||||||
|
int drawableWidth = 1280;
|
||||||
|
int drawableHeight = 720;
|
||||||
|
|
||||||
|
int windowViewportX = 0;
|
||||||
|
int windowViewportY = 0;
|
||||||
|
int windowViewportWidth = 1280;
|
||||||
|
int windowViewportHeight = 720;
|
||||||
|
|
||||||
|
int viewportX = 0;
|
||||||
|
int viewportY = 0;
|
||||||
|
int viewportWidth = 1280;
|
||||||
|
int viewportHeight = 720;
|
||||||
|
|
||||||
|
float contentScaleX = 1.0f;
|
||||||
|
float contentScaleY = 1.0f;
|
||||||
|
float scaleX = 1.0f;
|
||||||
|
float scaleY = 1.0f;
|
||||||
|
|
||||||
|
Rect getWindowViewportRect() const {
|
||||||
|
return Rect(static_cast<float>(windowViewportX),
|
||||||
|
static_cast<float>(windowViewportY),
|
||||||
|
static_cast<float>(windowViewportWidth),
|
||||||
|
static_cast<float>(windowViewportHeight));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frostbite2D
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <frostbite2D/graphics/types.h>
|
|
||||||
#include <frostbite2D/graphics/texture.h>
|
|
||||||
#include <frostbite2D/graphics/shader.h>
|
|
||||||
#include <frostbite2D/graphics/shader_manager.h>
|
|
||||||
#include <frostbite2D/graphics/batch.h>
|
#include <frostbite2D/graphics/batch.h>
|
||||||
#include <frostbite2D/graphics/camera.h>
|
#include <frostbite2D/graphics/camera.h>
|
||||||
|
#include <frostbite2D/graphics/render_resolution.h>
|
||||||
|
#include <frostbite2D/graphics/shader.h>
|
||||||
|
#include <frostbite2D/graphics/shader_manager.h>
|
||||||
|
#include <frostbite2D/graphics/texture.h>
|
||||||
|
#include <frostbite2D/graphics/types.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
@@ -22,21 +23,35 @@ public:
|
|||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
void setViewport(int x, int y, int width, int height);
|
void setViewport(int x, int y, int width, int height);
|
||||||
|
void setWindowSize(int width, int height, float contentScaleX = 1.0f,
|
||||||
|
float contentScaleY = 1.0f);
|
||||||
|
void setVirtualResolutionEnabled(bool enabled);
|
||||||
|
void setVirtualResolution(int width, int height);
|
||||||
|
void setResolutionScaleMode(ResolutionScaleMode mode);
|
||||||
void setClearColor(float r, float g, float b, float a = 1.0f);
|
void setClearColor(float r, float g, float b, float a = 1.0f);
|
||||||
void setClearColor(const Color& color);
|
void setClearColor(const Color& color);
|
||||||
void clear(uint32_t flags);
|
void clear(uint32_t flags);
|
||||||
|
|
||||||
void setCamera(Camera* camera);
|
void setCamera(Camera* camera);
|
||||||
Camera* getCamera() { return camera_; }
|
Camera* getCamera() { return camera_; }
|
||||||
|
int getVirtualWidth() const;
|
||||||
|
int getVirtualHeight() const;
|
||||||
|
Rect getViewportRect() const;
|
||||||
|
const RenderResolutionState& getResolutionState() const {
|
||||||
|
return resolutionState_;
|
||||||
|
}
|
||||||
|
Vec2 screenToVirtual(const Vec2& screenPos) const;
|
||||||
|
Vec2 virtualToScreen(const Vec2& virtualPos) const;
|
||||||
|
|
||||||
void drawQuad(const Vec2& pos, const Size& size, float cr = 1.0f, float cg = 1.0f,
|
void drawQuad(const Vec2& pos, const Size& size, float cr = 1.0f,
|
||||||
float cb = 1.0f, float ca = 1.0f);
|
float cg = 1.0f, float cb = 1.0f, float ca = 1.0f);
|
||||||
void drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture);
|
void drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture);
|
||||||
void drawQuad(const Rect& rect, const Color& color);
|
void drawQuad(const Rect& rect, const Color& color);
|
||||||
|
|
||||||
void drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture);
|
void drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture);
|
||||||
void drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize,
|
void drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize,
|
||||||
Ptr<Texture> texture, const Color& color = Color(1, 1, 1, 1));
|
Ptr<Texture> texture,
|
||||||
|
const Color& color = Color(1, 1, 1, 1));
|
||||||
void setupBlendMode(BlendMode mode);
|
void setupBlendMode(BlendMode mode);
|
||||||
|
|
||||||
ShaderManager& getShaderManager() { return shaderManager_; }
|
ShaderManager& getShaderManager() { return shaderManager_; }
|
||||||
@@ -44,19 +59,21 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer();
|
Renderer();
|
||||||
// ~Renderer() 在 shutdown() 中手动调用销毁
|
|
||||||
|
|
||||||
void updateUniforms();
|
void updateUniforms();
|
||||||
|
void recalculateResolutionState();
|
||||||
|
void syncCameraViewport();
|
||||||
|
|
||||||
ShaderManager shaderManager_;
|
ShaderManager shaderManager_;
|
||||||
Batch batch_;
|
Batch batch_;
|
||||||
Camera* camera_ = nullptr;
|
Camera* camera_ = nullptr;
|
||||||
|
|
||||||
uint32_t clearColor_[4] = {0, 0, 0, 255};
|
uint32_t clearColor_[4] = {0, 0, 0, 255};
|
||||||
int viewportX_ = 0;
|
bool useVirtualResolution_ = false;
|
||||||
int viewportY_ = 0;
|
int virtualWidth_ = 1280;
|
||||||
int viewportWidth_ = 1280;
|
int virtualHeight_ = 720;
|
||||||
int viewportHeight_ = 720;
|
ResolutionScaleMode resolutionMode_ = ResolutionScaleMode::Fit;
|
||||||
|
RenderResolutionState resolutionState_;
|
||||||
|
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|
||||||
@@ -64,4 +81,4 @@ private:
|
|||||||
Renderer& operator=(const Renderer&) = delete;
|
Renderer& operator=(const Renderer&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace frostbite2D
|
||||||
|
|||||||
@@ -180,9 +180,13 @@ bool Application::initCoreModules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window_->onResize([this](int width, int height) {
|
window_->onResize([this](int width, int height) {
|
||||||
renderer_->setViewport(0, 0, width, height);
|
if (!renderer_ || !window_) {
|
||||||
camera_->setViewport(width, height);
|
return;
|
||||||
SDL_Log("Window resized to %dx%d", width, height);
|
}
|
||||||
|
|
||||||
|
renderer_->setWindowSize(width, height, window_->scaleX(), window_->scaleY());
|
||||||
|
SDL_Log("Window resized to %dx%d (drawable %dx%d)", width, height,
|
||||||
|
window_->drawableWidth(), window_->drawableHeight());
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化渲染器
|
// 初始化渲染器
|
||||||
@@ -197,13 +201,19 @@ bool Application::initCoreModules() {
|
|||||||
|
|
||||||
// 设置窗口清除颜色和视口
|
// 设置窗口清除颜色和视口
|
||||||
renderer_->setClearColor(0.0f, 0.0f, 0.0f);
|
renderer_->setClearColor(0.0f, 0.0f, 0.0f);
|
||||||
renderer_->setViewport(0, 0, config_.windowConfig.width, config_.windowConfig.height);
|
renderer_->setVirtualResolutionEnabled(config_.useVirtualResolution);
|
||||||
|
renderer_->setResolutionScaleMode(config_.resolutionMode);
|
||||||
|
if (config_.virtualWidth > 0 && config_.virtualHeight > 0) {
|
||||||
|
renderer_->setVirtualResolution(config_.virtualWidth, config_.virtualHeight);
|
||||||
|
}
|
||||||
|
renderer_->setWindowSize(window_->width(), window_->height(), window_->scaleX(),
|
||||||
|
window_->scaleY());
|
||||||
|
|
||||||
// 创建并设置相机
|
// 创建并设置相机
|
||||||
{
|
{
|
||||||
ScopedStartupTrace stageTrace("Camera setup");
|
ScopedStartupTrace stageTrace("Camera setup");
|
||||||
camera_ = new Camera();
|
camera_ = new Camera();
|
||||||
camera_->setViewport(config_.windowConfig.width, config_.windowConfig.height);
|
camera_->setViewport(renderer_->getVirtualWidth(), renderer_->getVirtualHeight());
|
||||||
camera_->setFlipY(true); // 启用 Y 轴翻转,(0,0) 在左上角
|
camera_->setFlipY(true); // 启用 Y 轴翻转,(0,0) 在左上角
|
||||||
renderer_->setCamera(camera_);
|
renderer_->setCamera(camera_);
|
||||||
}
|
}
|
||||||
@@ -282,6 +292,17 @@ void Application::mainLoop() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sdlEvent.type == SDL_WINDOWEVENT && window_) {
|
||||||
|
switch (sdlEvent.window.event) {
|
||||||
|
case SDL_WINDOWEVENT_RESIZED:
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||||
|
window_->refreshMetrics(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto event = convertSDLEvent(sdlEvent);
|
auto event = convertSDLEvent(sdlEvent);
|
||||||
if (event) {
|
if (event) {
|
||||||
dispatchEvent(*event);
|
dispatchEvent(*event);
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
#include <frostbite2D/resource/asset.h>
|
#include <frostbite2D/resource/asset.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
|
|
||||||
bool Window::create(const WindowConfig &cfg) {
|
bool Window::create(const WindowConfig& cfg) {
|
||||||
|
|
||||||
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
@@ -28,7 +26,6 @@ bool Window::create(const WindowConfig &cfg) {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
@@ -38,17 +35,11 @@ bool Window::create(const WindowConfig &cfg) {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, cfg.multisamples);
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, cfg.multisamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = SDL_WINDOWPOS_CENTERED;
|
int x = cfg.centered ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED;
|
||||||
int y = SDL_WINDOWPOS_CENTERED;
|
int y = cfg.centered ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED;
|
||||||
if (!cfg.centered) {
|
|
||||||
x = SDL_WINDOWPOS_UNDEFINED;
|
|
||||||
y = SDL_WINDOWPOS_UNDEFINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建窗口
|
|
||||||
sdlWindow_ =
|
|
||||||
SDL_CreateWindow(cfg.title.c_str(), x, y, cfg.width, cfg.height, flags);
|
|
||||||
|
|
||||||
|
sdlWindow_ = SDL_CreateWindow(cfg.title.c_str(), x, y, cfg.width, cfg.height,
|
||||||
|
flags);
|
||||||
if (!sdlWindow_) {
|
if (!sdlWindow_) {
|
||||||
SDL_Log("Failed to create window: %s", SDL_GetError());
|
SDL_Log("Failed to create window: %s", SDL_GetError());
|
||||||
return false;
|
return false;
|
||||||
@@ -72,23 +63,12 @@ bool Window::create(const WindowConfig &cfg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0);
|
SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0);
|
||||||
|
refreshMetrics(false);
|
||||||
// 获取实际的可绘制大小(考虑高 DPI 和 Switch 等平台)
|
|
||||||
int drawableWidth, drawableHeight;
|
|
||||||
SDL_GL_GetDrawableSize(sdlWindow_, &drawableWidth, &drawableHeight);
|
|
||||||
width_ = drawableWidth;
|
|
||||||
height_ = drawableHeight;
|
|
||||||
|
|
||||||
// 计算缩放比例
|
|
||||||
int windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(sdlWindow_, &windowWidth, &windowHeight);
|
|
||||||
if (windowWidth > 0 && windowHeight > 0) {
|
|
||||||
scaleX_ = static_cast<float>(drawableWidth) / static_cast<float>(windowWidth);
|
|
||||||
scaleY_ = static_cast<float>(drawableHeight) / static_cast<float>(windowHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
||||||
vsync_ = cfg.vsync;
|
vsync_ = cfg.vsync;
|
||||||
|
cursorVisible_ = cfg.showCursor;
|
||||||
|
showCursor(cfg.showCursor);
|
||||||
|
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
if (!cfg.icon.file_path.empty()) {
|
if (!cfg.icon.file_path.empty()) {
|
||||||
@@ -113,9 +93,11 @@ bool Window::create(const WindowConfig &cfg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Window::destroy() {
|
void Window::destroy() {
|
||||||
if (sdlWindow_) {
|
if (glContext_) {
|
||||||
SDL_GL_DeleteContext(glContext_);
|
SDL_GL_DeleteContext(glContext_);
|
||||||
glContext_ = nullptr;
|
glContext_ = nullptr;
|
||||||
|
}
|
||||||
|
if (sdlWindow_) {
|
||||||
SDL_DestroyWindow(sdlWindow_);
|
SDL_DestroyWindow(sdlWindow_);
|
||||||
sdlWindow_ = nullptr;
|
sdlWindow_ = nullptr;
|
||||||
}
|
}
|
||||||
@@ -129,16 +111,32 @@ void Window::swap() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::close() { shouldClose_ = true; }
|
void Window::close() {
|
||||||
|
shouldClose_ = true;
|
||||||
|
if (closeCb_) {
|
||||||
|
closeCb_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Window::setTitle(const std::string &title) {}
|
void Window::setTitle(const std::string& title) {
|
||||||
|
if (sdlWindow_) {
|
||||||
|
SDL_SetWindowTitle(sdlWindow_, title.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Window::setSize(int w, int h) {
|
void Window::setSize(int w, int h) {
|
||||||
if (sdlWindow_) {
|
if (sdlWindow_) {
|
||||||
SDL_SetWindowSize(sdlWindow_, w, h);
|
SDL_SetWindowSize(sdlWindow_, w, h);
|
||||||
|
refreshMetrics(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
width_ = w;
|
width_ = w;
|
||||||
height_ = h;
|
height_ = h;
|
||||||
|
drawableWidth_ = w;
|
||||||
|
drawableHeight_ = h;
|
||||||
|
scaleX_ = 1.0f;
|
||||||
|
scaleY_ = 1.0f;
|
||||||
if (resizeCb_) {
|
if (resizeCb_) {
|
||||||
resizeCb_(w, h);
|
resizeCb_(w, h);
|
||||||
}
|
}
|
||||||
@@ -150,23 +148,54 @@ void Window::setPos(int x, int y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::setFullscreen(bool fs) { fullscreen_ = fs; }
|
void Window::setFullscreen(bool fs) {
|
||||||
|
fullscreen_ = fs;
|
||||||
|
if (!sdlWindow_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::setVSync(bool vsync) { vsync_ = vsync; }
|
#ifndef __SWITCH__
|
||||||
|
Uint32 flags = fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||||
|
SDL_SetWindowFullscreen(sdlWindow_, flags);
|
||||||
|
refreshMetrics(true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Window::setVisible(bool visible) {}
|
void Window::setVSync(bool vsync) {
|
||||||
|
vsync_ = vsync;
|
||||||
|
if (glContext_) {
|
||||||
|
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::setVisible(bool visible) {
|
||||||
|
if (!sdlWindow_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
SDL_ShowWindow(sdlWindow_);
|
||||||
|
} else {
|
||||||
|
SDL_HideWindow(sdlWindow_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Window::width() const { return width_; }
|
int Window::width() const { return width_; }
|
||||||
|
|
||||||
int Window::height() const { return height_; }
|
int Window::height() const { return height_; }
|
||||||
|
|
||||||
|
int Window::drawableWidth() const { return drawableWidth_; }
|
||||||
|
|
||||||
|
int Window::drawableHeight() const { return drawableHeight_; }
|
||||||
|
|
||||||
Size Window::size() const {
|
Size Window::size() const {
|
||||||
return Size{static_cast<float>(width_), static_cast<float>(height_)};
|
return Size{static_cast<float>(width_), static_cast<float>(height_)};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 Window::pos() const {
|
Vec2 Window::pos() const {
|
||||||
if (sdlWindow_) {
|
if (sdlWindow_) {
|
||||||
int x, y;
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
SDL_GetWindowPosition(sdlWindow_, &x, &y);
|
SDL_GetWindowPosition(sdlWindow_, &x, &y);
|
||||||
return Vec2{static_cast<float>(x), static_cast<float>(y)};
|
return Vec2{static_cast<float>(x), static_cast<float>(y)};
|
||||||
}
|
}
|
||||||
@@ -185,11 +214,90 @@ float Window::scaleX() const { return scaleX_; }
|
|||||||
|
|
||||||
float Window::scaleY() const { return scaleY_; }
|
float Window::scaleY() const { return scaleY_; }
|
||||||
|
|
||||||
void Window::setCursor(CursorType cursor) {}
|
bool Window::refreshMetrics(bool emitResize) {
|
||||||
|
if (!sdlWindow_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::showCursor(bool show) { cursorVisible_ = show; }
|
int prevWidth = width_;
|
||||||
|
int prevHeight = height_;
|
||||||
|
int prevDrawableWidth = drawableWidth_;
|
||||||
|
int prevDrawableHeight = drawableHeight_;
|
||||||
|
|
||||||
void Window::lockCursor(bool lock) { cursorLocked_ = lock; }
|
SDL_GetWindowSize(sdlWindow_, &width_, &height_);
|
||||||
|
SDL_GL_GetDrawableSize(sdlWindow_, &drawableWidth_, &drawableHeight_);
|
||||||
|
|
||||||
|
if (width_ > 0 && height_ > 0) {
|
||||||
|
scaleX_ = static_cast<float>(drawableWidth_) / static_cast<float>(width_);
|
||||||
|
scaleY_ = static_cast<float>(drawableHeight_) / static_cast<float>(height_);
|
||||||
|
} else {
|
||||||
|
scaleX_ = 1.0f;
|
||||||
|
scaleY_ = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 windowFlags = SDL_GetWindowFlags(sdlWindow_);
|
||||||
|
focused_ = (windowFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||||
|
minimized_ = (windowFlags & SDL_WINDOW_MINIMIZED) != 0;
|
||||||
|
fullscreen_ = (windowFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 ||
|
||||||
|
(windowFlags & SDL_WINDOW_FULLSCREEN) != 0;
|
||||||
|
|
||||||
|
bool changed = prevWidth != width_ || prevHeight != height_ ||
|
||||||
|
prevDrawableWidth != drawableWidth_ ||
|
||||||
|
prevDrawableHeight != drawableHeight_;
|
||||||
|
if (emitResize && changed && resizeCb_) {
|
||||||
|
resizeCb_(width_, height_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::setCursor(CursorType cursor) {
|
||||||
|
SDL_SystemCursor systemCursor = SDL_SYSTEM_CURSOR_ARROW;
|
||||||
|
switch (cursor) {
|
||||||
|
case CursorType::Arrow:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_ARROW;
|
||||||
|
break;
|
||||||
|
case CursorType::TextInput:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_IBEAM;
|
||||||
|
break;
|
||||||
|
case CursorType::Hand:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_HAND;
|
||||||
|
break;
|
||||||
|
case CursorType::SizeAll:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_SIZEALL;
|
||||||
|
break;
|
||||||
|
case CursorType::SizeWE:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_SIZEWE;
|
||||||
|
break;
|
||||||
|
case CursorType::SizeNS:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_SIZENS;
|
||||||
|
break;
|
||||||
|
case CursorType::SizeNESW:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_SIZENESW;
|
||||||
|
break;
|
||||||
|
case CursorType::SizeNWSE:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_SIZENWSE;
|
||||||
|
break;
|
||||||
|
case CursorType::No:
|
||||||
|
systemCursor = SDL_SYSTEM_CURSOR_ARROW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Cursor* sdlCursor = SDL_CreateSystemCursor(systemCursor);
|
||||||
|
if (sdlCursor) {
|
||||||
|
SDL_SetCursor(sdlCursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::showCursor(bool show) {
|
||||||
|
cursorVisible_ = show;
|
||||||
|
SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::lockCursor(bool lock) {
|
||||||
|
cursorLocked_ = lock;
|
||||||
|
SDL_SetRelativeMouseMode(lock ? SDL_TRUE : SDL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::onResize(ResizeCb cb) { resizeCb_ = cb; }
|
void Window::onResize(ResizeCb cb) { resizeCb_ = cb; }
|
||||||
|
|
||||||
@@ -197,6 +305,6 @@ void Window::onClose(CloseCb cb) { closeCb_ = cb; }
|
|||||||
|
|
||||||
void Window::onFocus(FocusCb cb) { focusCb_ = cb; }
|
void Window::onFocus(FocusCb cb) { focusCb_ = cb; }
|
||||||
|
|
||||||
void *Window::native() const { return nullptr; }
|
void* Window::native() const { return nullptr; }
|
||||||
|
|
||||||
} // namespace frostbite2D
|
} // namespace frostbite2D
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <frostbite2D/graphics/camera.h>
|
#include <frostbite2D/graphics/camera.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
|
|
||||||
@@ -14,6 +15,16 @@ void Camera::setViewport(int width, int height) {
|
|||||||
viewportHeight_ = height;
|
viewportHeight_ = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Camera::getVisibleWidth() const {
|
||||||
|
float safeZoom = std::max(zoom_, 0.01f);
|
||||||
|
return static_cast<float>(viewportWidth_) / safeZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Camera::getVisibleHeight() const {
|
||||||
|
float safeZoom = std::max(zoom_, 0.01f);
|
||||||
|
return static_cast<float>(viewportHeight_) / safeZoom;
|
||||||
|
}
|
||||||
|
|
||||||
void Camera::lookAt(const Vec2 &target) { position_ = target; }
|
void Camera::lookAt(const Vec2 &target) { position_ = target; }
|
||||||
|
|
||||||
void Camera::move(const Vec2 &delta) { position_ = position_ + delta; }
|
void Camera::move(const Vec2 &delta) { position_ = position_ + delta; }
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
#include "SDL_log.h"
|
#include "SDL_log.h"
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <frostbite2D/graphics/renderer.h>
|
#include <frostbite2D/graphics/renderer.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr float kMinContentScale = 0.01f;
|
||||||
|
|
||||||
|
int roundToInt(float value) {
|
||||||
|
return static_cast<int>(std::lround(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Renderer& Renderer::get() {
|
Renderer& Renderer::get() {
|
||||||
static Renderer instance;
|
static Renderer instance;
|
||||||
return instance;
|
return instance;
|
||||||
@@ -13,21 +25,20 @@ Renderer& Renderer::get() {
|
|||||||
|
|
||||||
Renderer::Renderer() = default;
|
Renderer::Renderer() = default;
|
||||||
|
|
||||||
// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用
|
|
||||||
|
|
||||||
bool Renderer::init() {
|
bool Renderer::init() {
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!batch_.init()) {
|
if (!batch_.init()) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize batch system");
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to initialize batch system");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化着色器管理器
|
|
||||||
if (!shaderManager_.init("assets/shaders")) {
|
if (!shaderManager_.init("assets/shaders")) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize shader manager");
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to initialize shader manager");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +47,7 @@ bool Renderer::init() {
|
|||||||
|
|
||||||
SDL_Log("Renderer initialized");
|
SDL_Log("Renderer initialized");
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
|
recalculateResolutionState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,9 +58,10 @@ void Renderer::shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::beginFrame() {
|
void Renderer::beginFrame() {
|
||||||
glViewport(viewportX_, viewportY_, viewportWidth_, viewportHeight_);
|
glViewport(resolutionState_.viewportX, resolutionState_.viewportY,
|
||||||
|
resolutionState_.viewportWidth, resolutionState_.viewportHeight);
|
||||||
glClearColor(clearColor_[0] / 255.0f, clearColor_[1] / 255.0f,
|
glClearColor(clearColor_[0] / 255.0f, clearColor_[1] / 255.0f,
|
||||||
clearColor_[2] / 255.0f, clearColor_[3] / 255.0f);
|
clearColor_[2] / 255.0f, clearColor_[3] / 255.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
updateUniforms();
|
updateUniforms();
|
||||||
@@ -64,14 +77,66 @@ void Renderer::flush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setViewport(int x, int y, int width, int height) {
|
void Renderer::setViewport(int x, int y, int width, int height) {
|
||||||
viewportX_ = x;
|
resolutionState_.viewportX = x;
|
||||||
viewportY_ = y;
|
resolutionState_.viewportY = y;
|
||||||
viewportWidth_ = width;
|
resolutionState_.viewportWidth = std::max(width, 1);
|
||||||
viewportHeight_ = height;
|
resolutionState_.viewportHeight = std::max(height, 1);
|
||||||
|
|
||||||
if (camera_) {
|
float safeScaleX = std::max(resolutionState_.contentScaleX, kMinContentScale);
|
||||||
camera_->setViewport(width, height);
|
float safeScaleY = std::max(resolutionState_.contentScaleY, kMinContentScale);
|
||||||
}
|
|
||||||
|
resolutionState_.windowViewportX = roundToInt(
|
||||||
|
static_cast<float>(resolutionState_.viewportX) / safeScaleX);
|
||||||
|
resolutionState_.windowViewportY = roundToInt(
|
||||||
|
static_cast<float>(resolutionState_.viewportY) / safeScaleY);
|
||||||
|
resolutionState_.windowViewportWidth = roundToInt(
|
||||||
|
static_cast<float>(resolutionState_.viewportWidth) / safeScaleX);
|
||||||
|
resolutionState_.windowViewportHeight = roundToInt(
|
||||||
|
static_cast<float>(resolutionState_.viewportHeight) / safeScaleY);
|
||||||
|
|
||||||
|
int logicalWidth = std::max(getVirtualWidth(), 1);
|
||||||
|
int logicalHeight = std::max(getVirtualHeight(), 1);
|
||||||
|
resolutionState_.scaleX =
|
||||||
|
static_cast<float>(resolutionState_.windowViewportWidth) /
|
||||||
|
static_cast<float>(logicalWidth);
|
||||||
|
resolutionState_.scaleY =
|
||||||
|
static_cast<float>(resolutionState_.windowViewportHeight) /
|
||||||
|
static_cast<float>(logicalHeight);
|
||||||
|
|
||||||
|
syncCameraViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::setWindowSize(int width, int height, float contentScaleX,
|
||||||
|
float contentScaleY) {
|
||||||
|
resolutionState_.windowWidth = std::max(width, 1);
|
||||||
|
resolutionState_.windowHeight = std::max(height, 1);
|
||||||
|
resolutionState_.contentScaleX = std::max(contentScaleX, kMinContentScale);
|
||||||
|
resolutionState_.contentScaleY = std::max(contentScaleY, kMinContentScale);
|
||||||
|
resolutionState_.drawableWidth = std::max(
|
||||||
|
roundToInt(static_cast<float>(resolutionState_.windowWidth) *
|
||||||
|
resolutionState_.contentScaleX),
|
||||||
|
1);
|
||||||
|
resolutionState_.drawableHeight = std::max(
|
||||||
|
roundToInt(static_cast<float>(resolutionState_.windowHeight) *
|
||||||
|
resolutionState_.contentScaleY),
|
||||||
|
1);
|
||||||
|
recalculateResolutionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::setVirtualResolutionEnabled(bool enabled) {
|
||||||
|
useVirtualResolution_ = enabled;
|
||||||
|
recalculateResolutionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::setVirtualResolution(int width, int height) {
|
||||||
|
virtualWidth_ = std::max(width, 1);
|
||||||
|
virtualHeight_ = std::max(height, 1);
|
||||||
|
recalculateResolutionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::setResolutionScaleMode(ResolutionScaleMode mode) {
|
||||||
|
resolutionMode_ = mode;
|
||||||
|
recalculateResolutionState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setClearColor(float r, float g, float b, float a) {
|
void Renderer::setClearColor(float r, float g, float b, float a) {
|
||||||
@@ -98,15 +163,169 @@ void Renderer::setCamera(Camera* camera) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
camera_ = camera;
|
camera_ = camera;
|
||||||
if (camera) {
|
syncCameraViewport();
|
||||||
camera_->setViewport(viewportWidth_, viewportHeight_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
updateUniforms();
|
updateUniforms();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Renderer::getVirtualWidth() const {
|
||||||
|
if (useVirtualResolution_) {
|
||||||
|
return std::max(virtualWidth_, 1);
|
||||||
|
}
|
||||||
|
return std::max(resolutionState_.windowWidth, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Renderer::getVirtualHeight() const {
|
||||||
|
if (useVirtualResolution_) {
|
||||||
|
return std::max(virtualHeight_, 1);
|
||||||
|
}
|
||||||
|
return std::max(resolutionState_.windowHeight, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect Renderer::getViewportRect() const {
|
||||||
|
return resolutionState_.getWindowViewportRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 Renderer::screenToVirtual(const Vec2& screenPos) const {
|
||||||
|
Rect viewport = getViewportRect();
|
||||||
|
if (viewport.width() <= 0.0f || viewport.height() <= 0.0f) {
|
||||||
|
return screenPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
float localX = screenPos.x - viewport.left();
|
||||||
|
float localY = screenPos.y - viewport.top();
|
||||||
|
return Vec2(localX * static_cast<float>(getVirtualWidth()) / viewport.width(),
|
||||||
|
localY * static_cast<float>(getVirtualHeight()) /
|
||||||
|
viewport.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 Renderer::virtualToScreen(const Vec2& virtualPos) const {
|
||||||
|
Rect viewport = getViewportRect();
|
||||||
|
float logicalWidth = static_cast<float>(std::max(getVirtualWidth(), 1));
|
||||||
|
float logicalHeight = static_cast<float>(std::max(getVirtualHeight(), 1));
|
||||||
|
|
||||||
|
return Vec2(viewport.left() + virtualPos.x * viewport.width() / logicalWidth,
|
||||||
|
viewport.top() + virtualPos.y * viewport.height() /
|
||||||
|
logicalHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::recalculateResolutionState() {
|
||||||
|
resolutionState_.windowWidth = std::max(resolutionState_.windowWidth, 1);
|
||||||
|
resolutionState_.windowHeight = std::max(resolutionState_.windowHeight, 1);
|
||||||
|
resolutionState_.contentScaleX =
|
||||||
|
std::max(resolutionState_.contentScaleX, kMinContentScale);
|
||||||
|
resolutionState_.contentScaleY =
|
||||||
|
std::max(resolutionState_.contentScaleY, kMinContentScale);
|
||||||
|
resolutionState_.drawableWidth = std::max(
|
||||||
|
roundToInt(static_cast<float>(resolutionState_.windowWidth) *
|
||||||
|
resolutionState_.contentScaleX),
|
||||||
|
1);
|
||||||
|
resolutionState_.drawableHeight = std::max(
|
||||||
|
roundToInt(static_cast<float>(resolutionState_.windowHeight) *
|
||||||
|
resolutionState_.contentScaleY),
|
||||||
|
1);
|
||||||
|
|
||||||
|
int windowViewportX = 0;
|
||||||
|
int windowViewportY = 0;
|
||||||
|
int windowViewportWidth = resolutionState_.windowWidth;
|
||||||
|
int windowViewportHeight = resolutionState_.windowHeight;
|
||||||
|
|
||||||
|
if (useVirtualResolution_) {
|
||||||
|
float widthScale = static_cast<float>(resolutionState_.windowWidth) /
|
||||||
|
static_cast<float>(std::max(virtualWidth_, 1));
|
||||||
|
float heightScale = static_cast<float>(resolutionState_.windowHeight) /
|
||||||
|
static_cast<float>(std::max(virtualHeight_, 1));
|
||||||
|
|
||||||
|
switch (resolutionMode_) {
|
||||||
|
case ResolutionScaleMode::Disabled:
|
||||||
|
resolutionState_.scaleX = widthScale;
|
||||||
|
resolutionState_.scaleY = heightScale;
|
||||||
|
break;
|
||||||
|
case ResolutionScaleMode::FitHeight: {
|
||||||
|
float uniformScale = heightScale;
|
||||||
|
float fittedWidth = static_cast<float>(virtualWidth_) * uniformScale;
|
||||||
|
if (fittedWidth > static_cast<float>(resolutionState_.windowWidth)) {
|
||||||
|
uniformScale = std::min(widthScale, heightScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
windowViewportWidth = std::clamp(
|
||||||
|
roundToInt(static_cast<float>(virtualWidth_) * uniformScale), 1,
|
||||||
|
resolutionState_.windowWidth);
|
||||||
|
windowViewportHeight = std::clamp(
|
||||||
|
roundToInt(static_cast<float>(virtualHeight_) * uniformScale), 1,
|
||||||
|
resolutionState_.windowHeight);
|
||||||
|
windowViewportX =
|
||||||
|
(resolutionState_.windowWidth - windowViewportWidth) / 2;
|
||||||
|
windowViewportY =
|
||||||
|
(resolutionState_.windowHeight - windowViewportHeight) / 2;
|
||||||
|
resolutionState_.scaleX =
|
||||||
|
static_cast<float>(windowViewportWidth) /
|
||||||
|
static_cast<float>(std::max(virtualWidth_, 1));
|
||||||
|
resolutionState_.scaleY =
|
||||||
|
static_cast<float>(windowViewportHeight) /
|
||||||
|
static_cast<float>(std::max(virtualHeight_, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ResolutionScaleMode::Fit:
|
||||||
|
default: {
|
||||||
|
float uniformScale = std::min(widthScale, heightScale);
|
||||||
|
windowViewportWidth = std::clamp(
|
||||||
|
roundToInt(static_cast<float>(virtualWidth_) * uniformScale), 1,
|
||||||
|
resolutionState_.windowWidth);
|
||||||
|
windowViewportHeight = std::clamp(
|
||||||
|
roundToInt(static_cast<float>(virtualHeight_) * uniformScale), 1,
|
||||||
|
resolutionState_.windowHeight);
|
||||||
|
windowViewportX =
|
||||||
|
(resolutionState_.windowWidth - windowViewportWidth) / 2;
|
||||||
|
windowViewportY =
|
||||||
|
(resolutionState_.windowHeight - windowViewportHeight) / 2;
|
||||||
|
resolutionState_.scaleX =
|
||||||
|
static_cast<float>(windowViewportWidth) /
|
||||||
|
static_cast<float>(std::max(virtualWidth_, 1));
|
||||||
|
resolutionState_.scaleY =
|
||||||
|
static_cast<float>(windowViewportHeight) /
|
||||||
|
static_cast<float>(std::max(virtualHeight_, 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolutionState_.scaleX = 1.0f;
|
||||||
|
resolutionState_.scaleY = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolutionState_.windowViewportX = windowViewportX;
|
||||||
|
resolutionState_.windowViewportY = windowViewportY;
|
||||||
|
resolutionState_.windowViewportWidth = windowViewportWidth;
|
||||||
|
resolutionState_.windowViewportHeight = windowViewportHeight;
|
||||||
|
resolutionState_.viewportX = roundToInt(
|
||||||
|
static_cast<float>(windowViewportX) * resolutionState_.contentScaleX);
|
||||||
|
resolutionState_.viewportY = roundToInt(
|
||||||
|
static_cast<float>(windowViewportY) * resolutionState_.contentScaleY);
|
||||||
|
resolutionState_.viewportWidth = std::max(
|
||||||
|
roundToInt(static_cast<float>(windowViewportWidth) *
|
||||||
|
resolutionState_.contentScaleX),
|
||||||
|
1);
|
||||||
|
resolutionState_.viewportHeight = std::max(
|
||||||
|
roundToInt(static_cast<float>(windowViewportHeight) *
|
||||||
|
resolutionState_.contentScaleY),
|
||||||
|
1);
|
||||||
|
|
||||||
|
syncCameraViewport();
|
||||||
|
if (initialized_) {
|
||||||
|
updateUniforms();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::syncCameraViewport() {
|
||||||
|
if (!camera_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
camera_->setViewport(getVirtualWidth(), getVirtualHeight());
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::setupBlendMode(BlendMode mode) {
|
void Renderer::setupBlendMode(BlendMode mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case BlendMode::None:
|
case BlendMode::None:
|
||||||
@@ -116,38 +335,37 @@ void Renderer::setupBlendMode(BlendMode mode) {
|
|||||||
case BlendMode::Normal:
|
case BlendMode::Normal:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
|
||||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
case BlendMode::Additive:
|
case BlendMode::Additive:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
|
||||||
GL_ONE, GL_ONE);
|
|
||||||
break;
|
break;
|
||||||
case BlendMode::Screen:
|
case BlendMode::Screen:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR,
|
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ONE,
|
||||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
case BlendMode::Premultiplied:
|
case BlendMode::Premultiplied:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA,
|
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
|
||||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
case BlendMode::Subtractive:
|
case BlendMode::Subtractive:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
|
||||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||||
break;
|
break;
|
||||||
case BlendMode::Multiply:
|
case BlendMode::Multiply:
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendEquation(GL_FUNC_ADD);
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA,
|
glBlendFuncSeparate(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
|
||||||
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
GL_ONE_MINUS_SRC_ALPHA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +396,7 @@ void Renderer::updateUniforms() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawQuad(const Vec2& pos, const Size& size, float cr, float cg,
|
void Renderer::drawQuad(const Vec2& pos, const Size& size, float cr, float cg,
|
||||||
float cb, float ca) {
|
float cb, float ca) {
|
||||||
Rect rect(pos.x, pos.y, size.width, size.height);
|
Rect rect(pos.x, pos.y, size.width, size.height);
|
||||||
Quad quad = Quad::create(rect, cr, cg, cb, ca);
|
Quad quad = Quad::create(rect, cr, cg, cb, ca);
|
||||||
Transform2D transform = Transform2D::identity();
|
Transform2D transform = Transform2D::identity();
|
||||||
@@ -194,7 +412,7 @@ void Renderer::drawQuad(const Vec2& pos, const Size& size, float cr, float cg,
|
|||||||
void Renderer::drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture) {
|
void Renderer::drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture) {
|
||||||
Rect rect(pos.x, pos.y, size.width, size.height);
|
Rect rect(pos.x, pos.y, size.width, size.height);
|
||||||
Quad quad = Quad::createTextured(rect, Rect(0, 0, size.width, size.height),
|
Quad quad = Quad::createTextured(rect, Rect(0, 0, size.width, size.height),
|
||||||
Vec2(size.width, size.height));
|
Vec2(size.width, size.height));
|
||||||
Transform2D transform = Transform2D::identity();
|
Transform2D transform = Transform2D::identity();
|
||||||
|
|
||||||
auto* shader = shaderManager_.getShader("sprite");
|
auto* shader = shaderManager_.getShader("sprite");
|
||||||
@@ -206,20 +424,20 @@ void Renderer::drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawQuad(const Rect& rect, const Color& color) {
|
void Renderer::drawQuad(const Rect& rect, const Color& color) {
|
||||||
drawQuad(Vec2(rect.left(), rect.top()),
|
drawQuad(Vec2(rect.left(), rect.top()), Size(rect.width(), rect.height()),
|
||||||
Size(rect.width(), rect.height()),
|
color.r, color.g, color.b, color.a);
|
||||||
color.r, color.g, color.b, color.a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture) {
|
void Renderer::drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture) {
|
||||||
drawQuad(pos, size, texture);
|
drawQuad(pos, size, texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize,
|
void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect,
|
||||||
Ptr<Texture> texture, const Color& color) {
|
const Vec2& texSize, Ptr<Texture> texture,
|
||||||
|
const Color& color) {
|
||||||
Rect destRect(pos.x, pos.y, srcRect.width(), srcRect.height());
|
Rect destRect(pos.x, pos.y, srcRect.width(), srcRect.height());
|
||||||
Quad quad = Quad::createTextured(destRect, srcRect, texSize,
|
Quad quad = Quad::createTextured(destRect, srcRect, texSize, color.r, color.g,
|
||||||
color.r, color.g, color.b, color.a);
|
color.b, color.a);
|
||||||
Transform2D transform = Transform2D::identity();
|
Transform2D transform = Transform2D::identity();
|
||||||
|
|
||||||
auto* shader = shaderManager_.getShader("sprite");
|
auto* shader = shaderManager_.getShader("sprite");
|
||||||
@@ -230,4 +448,4 @@ void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texS
|
|||||||
batch_.submitQuad(quad, transform, texture, shader, BlendMode::Normal);
|
batch_.submitQuad(quad, transform, texture, shader, BlendMode::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace frostbite2D
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
#include <frostbite2D/graphics/renderer.h>
|
||||||
#include <frostbite2D/scene/ui_scene.h>
|
#include <frostbite2D/scene/ui_scene.h>
|
||||||
|
|
||||||
namespace frostbite2D {
|
namespace frostbite2D {
|
||||||
|
|
||||||
UIScene::UIScene() {
|
UIScene::UIScene() {
|
||||||
|
Renderer& renderer = Renderer::get();
|
||||||
|
camera_.setViewport(renderer.getVirtualWidth(), renderer.getVirtualHeight());
|
||||||
camera_.setFlipY(true);
|
camera_.setFlipY(true);
|
||||||
camera_.setZoom(1.0f);
|
camera_.setZoom(1.0f);
|
||||||
camera_.setPosition(Vec2::Zero());
|
camera_.setPosition(Vec2::Zero());
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ private:
|
|||||||
bool debugEnabled_ = false;
|
bool debugEnabled_ = false;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|
||||||
float zoom_ = 1.2f;
|
float zoom_ = 1.0f;
|
||||||
float debugMoveSpeed_ = 800.0f;
|
float debugMoveSpeed_ = 800.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ private:
|
|||||||
int backgroundRepeatWidth_ = 0;
|
int backgroundRepeatWidth_ = 0;
|
||||||
/// 地图配置里的整体 Y 偏移;既影响层位置,也影响地板校准。
|
/// 地图配置里的整体 Y 偏移;既影响层位置,也影响地板校准。
|
||||||
int mapOffsetY_ = 0;
|
int mapOffsetY_ = 0;
|
||||||
bool debugMode_ = true;
|
bool debugMode_ = false;
|
||||||
/// 硬编码调试开关:关闭后忽略可行走区域检测,允许角色自由移动。
|
/// 硬编码调试开关:关闭后忽略可行走区域检测,允许角色自由移动。
|
||||||
bool movableAreaCheckEnabled_ = false;
|
bool movableAreaCheckEnabled_ = true;
|
||||||
/// 当前地图正在播放的背景音乐。
|
/// 当前地图正在播放的背景音乐。
|
||||||
Ptr<Music> currentMusic_;
|
Ptr<Music> currentMusic_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,9 +34,18 @@ int main(int argc, char **argv) {
|
|||||||
AppConfig config = AppConfig::createDefault();
|
AppConfig config = AppConfig::createDefault();
|
||||||
config.appName = "Frostbite2D Test App";
|
config.appName = "Frostbite2D Test App";
|
||||||
config.appVersion = "1.0.0";
|
config.appVersion = "1.0.0";
|
||||||
|
#ifdef SWITCH
|
||||||
config.windowConfig.width = 1280;
|
config.windowConfig.width = 1280;
|
||||||
config.windowConfig.height = 720;
|
config.windowConfig.height = 720;
|
||||||
|
#else
|
||||||
|
config.windowConfig.width = 1066;
|
||||||
|
config.windowConfig.height = 600;
|
||||||
|
#endif
|
||||||
config.windowConfig.title = "Frostbite2D - Async Init Demo";
|
config.windowConfig.title = "Frostbite2D - Async Init Demo";
|
||||||
|
config.useVirtualResolution = true;
|
||||||
|
config.virtualWidth = 1066;
|
||||||
|
config.virtualHeight = 600;
|
||||||
|
config.resolutionMode = ResolutionScaleMode::FitHeight;
|
||||||
|
|
||||||
Application &app = Application::get();
|
Application &app = Application::get();
|
||||||
{
|
{
|
||||||
@@ -76,19 +85,20 @@ int main(int argc, char **argv) {
|
|||||||
auto LoadingScene = MakePtr<Scene>();
|
auto LoadingScene = MakePtr<Scene>();
|
||||||
SceneManager::get().PushScene(LoadingScene);
|
SceneManager::get().PushScene(LoadingScene);
|
||||||
|
|
||||||
auto Background = Sprite::createFromFile("assets/ImagePacks2/Loading0.jpg");
|
auto Background =
|
||||||
Background->SetSize(1280, 720);
|
Sprite::createFromFile("assets/ImagePacks2/Loading0.png");
|
||||||
|
Background->SetSize(1066, 600);
|
||||||
LoadingScene->AddChild(Background);
|
LoadingScene->AddChild(Background);
|
||||||
|
|
||||||
auto BackgroundBar =
|
auto BackgroundBar =
|
||||||
Sprite::createFromFile("assets/ImagePacks2/Loading1.png");
|
Sprite::createFromFile("assets/ImagePacks2/Loading1.png");
|
||||||
BackgroundBar->SetPosition(0, 686);
|
BackgroundBar->SetPosition(0 - 107, 566);
|
||||||
LoadingScene->AddChild(BackgroundBar);
|
LoadingScene->AddChild(BackgroundBar);
|
||||||
|
|
||||||
auto LoadCircleSp =
|
auto LoadCircleSp =
|
||||||
Sprite::createFromFile("assets/ImagePacks2/Loading2.png");
|
Sprite::createFromFile("assets/ImagePacks2/Loading2.png");
|
||||||
LoadCircleSp->SetAnchor(Vec2(0.5f, 0.5f));
|
LoadCircleSp->SetAnchor(Vec2(0.5f, 0.5f));
|
||||||
LoadCircleSp->SetPosition(1280 / 2.0f, 686 - 60);
|
LoadCircleSp->SetPosition(1066 / 2.0f, 566 - 60);
|
||||||
LoadCircleSp->SetBlendMode(BlendMode::Additive);
|
LoadCircleSp->SetBlendMode(BlendMode::Additive);
|
||||||
LoadCircleSp->AddUpdateListener([](Actor &self, float dt) {
|
LoadCircleSp->AddUpdateListener([](Actor &self, float dt) {
|
||||||
auto rotation = self.GetRotation();
|
auto rotation = self.GetRotation();
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ namespace frostbite2D {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr float kScreenWidth = 1280.0f;
|
|
||||||
constexpr float kScreenHeight = 720.0f;
|
|
||||||
constexpr int kDebugStickDeadzone = 8000;
|
constexpr int kDebugStickDeadzone = 8000;
|
||||||
|
|
||||||
float normalizeControllerAxis(int16 value) {
|
float normalizeControllerAxis(int16 value) {
|
||||||
@@ -180,10 +178,10 @@ void GameCameraController::applyFocus() const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float halfWidth = kScreenWidth * 0.5f / zoom_;
|
|
||||||
float halfHeight = kScreenHeight * 0.5f / zoom_;
|
|
||||||
Vec2 cameraPos(focus_.x - halfWidth, focus_.y - halfHeight);
|
|
||||||
camera->setZoom(zoom_);
|
camera->setZoom(zoom_);
|
||||||
|
float halfWidth = camera->getVisibleWidth() * 0.5f;
|
||||||
|
float halfHeight = camera->getVisibleHeight() * 0.5f;
|
||||||
|
Vec2 cameraPos(focus_.x - halfWidth, focus_.y - halfHeight);
|
||||||
camera->setPosition(cameraPos);
|
camera->setPosition(cameraPos);
|
||||||
map_->ApplyCameraFocus(focus_);
|
map_->ApplyCameraFocus(focus_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ void GameMapTestScene::onEnter() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
ScopedStartupTrace stageTrace("GameMapTestScene character construction");
|
ScopedStartupTrace stageTrace("GameMapTestScene character construction");
|
||||||
character_ = MakePtr<CharacterObject>();
|
character_ = MakePtr<CharacterObject>();
|
||||||
if (!character_->Construction(0)) {
|
if (!character_->Construction(0)) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"GameMapTestScene: failed to construct default character");
|
"GameMapTestScene: failed to construct default character");
|
||||||
character_.Reset();
|
character_.Reset();
|
||||||
} else {
|
} else {
|
||||||
Vec2 spawnPos =
|
Vec2 spawnPos =
|
||||||
map_->ClampCameraFocus(map_->GetDefaultCameraFocus(), 1.2f);
|
map_->ClampCameraFocus(map_->GetDefaultCameraFocus(), 1.0f);
|
||||||
character_->SetCharacterPosition(spawnPos);
|
character_->SetCharacterPosition(spawnPos);
|
||||||
character_->EnableEventReceive();
|
character_->EnableEventReceive();
|
||||||
character_->SetEventPriority(-100);
|
character_->SetEventPriority(-100);
|
||||||
@@ -59,7 +59,6 @@ void GameMapTestScene::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cameraController_.SetMap(map_.Get());
|
cameraController_.SetMap(map_.Get());
|
||||||
// cameraController_.SetZoom(1.2f);
|
|
||||||
cameraController_.SetTarget(character_.Get());
|
cameraController_.SetTarget(character_.Get());
|
||||||
cameraController_.SetDebugEnabled(false);
|
cameraController_.SetDebugEnabled(false);
|
||||||
if (character_) {
|
if (character_) {
|
||||||
|
|||||||
@@ -117,7 +117,6 @@ void GameTown::AddCharacter(RefPtr<Actor> actor, int areaIndex) {
|
|||||||
|
|
||||||
AddChild(mapIt->map);
|
AddChild(mapIt->map);
|
||||||
cameraController_.SetMap(mapIt->map.Get());
|
cameraController_.SetMap(mapIt->map.Get());
|
||||||
cameraController_.SetZoom(1.2f);
|
|
||||||
cameraController_.SetTarget(actor.Get());
|
cameraController_.SetTarget(actor.Get());
|
||||||
cameraController_.SnapToDefaultFocus();
|
cameraController_.SnapToDefaultFocus();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user