Initial engine repository
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/graphics/types.h>
|
||||
#include <frostbite2D/graphics/texture.h>
|
||||
#include <frostbite2D/graphics/shader.h>
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
struct BatchKey {
|
||||
uint32_t shaderID;
|
||||
uint32_t textureID;
|
||||
uint32_t blendMode;
|
||||
|
||||
bool operator<(const BatchKey& other) const {
|
||||
if (shaderID != other.shaderID) return shaderID < other.shaderID;
|
||||
if (textureID != other.textureID) return textureID < other.textureID;
|
||||
return blendMode < other.blendMode;
|
||||
}
|
||||
};
|
||||
|
||||
class Batch {
|
||||
public:
|
||||
static constexpr int MAX_QUADS = 2048;
|
||||
static constexpr int MAX_VERTICES = MAX_QUADS * 4;
|
||||
static constexpr int MAX_INDICES = MAX_QUADS * 6;
|
||||
|
||||
Batch();
|
||||
~Batch();
|
||||
|
||||
bool init();
|
||||
void shutdown();
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
|
||||
void submitQuad(const Quad& quad, const Transform2D& transform,
|
||||
Ptr<Texture> texture, Shader* shader,
|
||||
BlendMode blendMode = BlendMode::Normal);
|
||||
|
||||
void flush();
|
||||
void flushIfNeeded(const BatchKey& newKey, Shader* shader, Ptr<Texture> texture);
|
||||
uint32 drawCallCount() const { return drawCallCount_; }
|
||||
|
||||
private:
|
||||
void setupMesh();
|
||||
void flushCurrentBatch();
|
||||
|
||||
struct BatchData {
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<uint16> indices;
|
||||
BatchKey key;
|
||||
Shader* shader = nullptr;
|
||||
Ptr<Texture> texture;
|
||||
};
|
||||
|
||||
uint32_t vao_ = 0;
|
||||
uint32_t vbo_ = 0;
|
||||
uint32_t ibo_ = 0;
|
||||
|
||||
BatchData currentBatch_;
|
||||
std::vector<BatchData> batches_;
|
||||
|
||||
bool begun_ = false;
|
||||
uint32 drawCallCount_ = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/types/type_math.h>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
|
||||
void setPosition(const Vec2& pos);
|
||||
void setZoom(float zoom);
|
||||
void setViewport(int width, int height);
|
||||
void setFlipY(bool flip) { flipY_ = flip; } // Debug Y-axis flip.
|
||||
void setPixelSnapEnabled(bool enabled) { pixelSnapEnabled_ = enabled; }
|
||||
|
||||
const Vec2& getPosition() const { return position_; }
|
||||
Vec2 getRenderPosition() const;
|
||||
Vec2 snapWorldPosition(const Vec2& position) const;
|
||||
float getZoom() const { return zoom_; }
|
||||
int getViewportWidth() const { return viewportWidth_; }
|
||||
int getViewportHeight() const { return viewportHeight_; }
|
||||
float getVisibleWidth() const;
|
||||
float getVisibleHeight() const;
|
||||
bool isPixelSnapEnabled() const { return pixelSnapEnabled_; }
|
||||
|
||||
void lookAt(const Vec2& target);
|
||||
void move(const Vec2& delta);
|
||||
void zoomAt(float factor, const Vec2& screenPos);
|
||||
|
||||
glm::mat4 getViewMatrix() const;
|
||||
glm::mat4 getProjectionMatrix() const;
|
||||
|
||||
private:
|
||||
Vec2 position_;
|
||||
float zoom_ = 1.0f;
|
||||
int viewportWidth_ = 1280;
|
||||
int viewportHeight_ = 720;
|
||||
bool flipY_ = false; // Debug Y-axis flip.
|
||||
bool pixelSnapEnabled_ = false;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class FontManager {
|
||||
public:
|
||||
static FontManager& get();
|
||||
|
||||
bool init();
|
||||
void shutdown();
|
||||
|
||||
bool registerFont(const std::string& name, const std::string& path, int fontSize);
|
||||
TTF_Font* getFont(const std::string& name);
|
||||
bool hasFont(const std::string& name) const;
|
||||
void unregisterFont(const std::string& name);
|
||||
void unloadAll();
|
||||
|
||||
struct FontInfo {
|
||||
std::string name;
|
||||
std::string path;
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
std::optional<FontInfo> getFontInfo(const std::string& name) const;
|
||||
|
||||
FontManager(const FontManager&) = delete;
|
||||
FontManager& operator=(const FontManager&) = delete;
|
||||
|
||||
private:
|
||||
FontManager() = default;
|
||||
~FontManager();
|
||||
|
||||
std::unordered_map<std::string, TTF_Font*> fonts_;
|
||||
std::unordered_map<std::string, FontInfo> fontInfos_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/types/type_math.h>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
/**
|
||||
* @brief 虚拟分辨率缩放模式
|
||||
*/
|
||||
enum class ResolutionScaleMode {
|
||||
Disabled, ///< 不保持纵横比,直接按窗口宽高分别缩放
|
||||
Fit, ///< 保持纵横比并完整显示,按较小缩放因子适配
|
||||
FitHeight, ///< 以高度优先适配,宽度不足时回退为 Fit
|
||||
};
|
||||
|
||||
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
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
/**
|
||||
* @brief 2D 渲染风格预设 ID
|
||||
*/
|
||||
enum class RenderStyleProfileId {
|
||||
PixelArt2D, ///< 世界与 UI 都按像素风策略渲染
|
||||
Smooth2D, ///< 世界与 UI 都按平滑 2D 策略渲染
|
||||
Hybrid2D ///< 世界走像素风,UI 走平滑策略
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染风格作用层级
|
||||
*/
|
||||
enum class RenderStyleLayerRole {
|
||||
World, ///< 世界层,如地图、角色、场景特效
|
||||
UI ///< UI 层,如 HUD、菜单、文字
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 单个层级的渲染风格开关集合
|
||||
*/
|
||||
struct RenderStyleLayerSettings {
|
||||
bool cameraPixelSnap = false; ///< 是否让相机位置吸附到像素网格
|
||||
bool vertexPixelSnap = false; ///< 是否让世界顶点在提交前做像素对齐
|
||||
bool pixelArtSampling = false; ///< 是否优先使用像素风采样(如 GL_NEAREST)
|
||||
bool shrinkSubTextureUVs = false; ///< 是否对子纹理 UV 做向内收缩,减轻图集边缘闪烁
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 一套完整的 2D 渲染风格设置
|
||||
*/
|
||||
struct RenderStyleSettings {
|
||||
RenderStyleLayerSettings world; ///< 世界层使用的渲染风格
|
||||
RenderStyleLayerSettings ui; ///< UI 层使用的渲染风格
|
||||
|
||||
/**
|
||||
* @brief 根据预设 ID 生成对应的渲染风格
|
||||
*/
|
||||
static RenderStyleSettings FromProfile(RenderStyleProfileId profile) {
|
||||
RenderStyleSettings settings;
|
||||
|
||||
switch (profile) {
|
||||
case RenderStyleProfileId::PixelArt2D:
|
||||
settings.world = {true, true, true, true};
|
||||
settings.ui = {true, true, true, true};
|
||||
break;
|
||||
case RenderStyleProfileId::Smooth2D:
|
||||
settings.world = {false, false, false, false};
|
||||
settings.ui = {false, false, false, false};
|
||||
break;
|
||||
case RenderStyleProfileId::Hybrid2D:
|
||||
default:
|
||||
settings.world = {true, true, true, true};
|
||||
settings.ui = {false, false, false, false};
|
||||
break;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取指定层级对应的风格设置
|
||||
*/
|
||||
const RenderStyleLayerSettings& layer(RenderStyleLayerRole role) const {
|
||||
return role == RenderStyleLayerRole::UI ? ui : world;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/base/RefObject.h>
|
||||
#include <frostbite2D/graphics/texture.h>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class Renderer;
|
||||
|
||||
/// @brief 2D 离屏渲染目标,封装颜色纹理和对应的 framebuffer。
|
||||
class RenderTexture : public RefObject {
|
||||
public:
|
||||
RenderTexture() = default;
|
||||
~RenderTexture() override;
|
||||
|
||||
bool Init(int width, int height);
|
||||
bool Resize(int width, int height);
|
||||
void Reset();
|
||||
|
||||
bool IsValid() const { return framebufferID_ != 0 && texture_ != nullptr; }
|
||||
int GetWidth() const { return width_; }
|
||||
int GetHeight() const { return height_; }
|
||||
Ptr<Texture> GetTexture() const { return texture_; }
|
||||
|
||||
private:
|
||||
Ptr<Texture> texture_ = nullptr;
|
||||
uint32 framebufferID_ = 0;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
friend class Renderer;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
@@ -0,0 +1,179 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/graphics/batch.h>
|
||||
#include <frostbite2D/graphics/camera.h>
|
||||
#include <frostbite2D/graphics/render_resolution.h>
|
||||
#include <frostbite2D/graphics/render_style.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 <vector>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class RenderTexture;
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
static Renderer& get();
|
||||
|
||||
bool init();
|
||||
void shutdown();
|
||||
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
void flush();
|
||||
bool beginRenderToTexture(RenderTexture& target, Camera* camera,
|
||||
const Color& clearColor = Color(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
bool clear = true);
|
||||
bool endRenderToTexture();
|
||||
|
||||
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 setSeparateUIVirtualResolutionEnabled(bool enabled);
|
||||
void setUIVirtualResolution(int width, int height);
|
||||
void setUIResolutionScaleMode(ResolutionScaleMode mode);
|
||||
void setClearColor(float r, float g, float b, float a = 1.0f);
|
||||
void setClearColor(const Color& color);
|
||||
void clear(uint32_t flags);
|
||||
/**
|
||||
* @brief 设置应用默认渲染风格预设
|
||||
*/
|
||||
void setDefaultRenderStyleProfile(RenderStyleProfileId profile);
|
||||
/**
|
||||
* @brief 获取应用默认渲染风格预设
|
||||
*/
|
||||
RenderStyleProfileId getDefaultRenderStyleProfile() const {
|
||||
return defaultRenderStyleProfile_;
|
||||
}
|
||||
/**
|
||||
* @brief 切换当前正在使用的渲染风格上下文
|
||||
*/
|
||||
void setActiveRenderStyleProfile(RenderStyleProfileId profile,
|
||||
RenderStyleLayerRole role);
|
||||
/**
|
||||
* @brief 将指定风格作用到某个相机
|
||||
*/
|
||||
void applyRenderStyleToCamera(Camera* camera, RenderStyleProfileId profile,
|
||||
RenderStyleLayerRole role) const;
|
||||
|
||||
void setCamera(Camera* camera);
|
||||
Camera* getCamera() { return camera_; }
|
||||
int getVirtualWidth() const;
|
||||
int getVirtualHeight() const;
|
||||
int getUIVirtualWidth() const;
|
||||
int getUIVirtualHeight() const;
|
||||
Rect getViewportRect() const;
|
||||
Rect getUIViewportRect() const;
|
||||
const RenderResolutionState& getResolutionState() const {
|
||||
return resolutionState_;
|
||||
}
|
||||
const RenderResolutionState& getUIResolutionState() const {
|
||||
return uiResolutionState_;
|
||||
}
|
||||
bool isInitialized() const { return initialized_; }
|
||||
bool isFrameActive() const { return frameActive_; }
|
||||
bool isRenderingToTexture() const { return !renderTargetStack_.empty(); }
|
||||
void setCullingEnabled(bool enabled) { cullingEnabled_ = enabled; }
|
||||
bool isCullingEnabled() const { return cullingEnabled_; }
|
||||
void applyWorldViewport() const;
|
||||
void applyUIViewport() const;
|
||||
Vec2 screenToVirtual(const Vec2& screenPos) const;
|
||||
Vec2 screenToUIVirtual(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, float cb = 1.0f, float ca = 1.0f);
|
||||
void drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture);
|
||||
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 Rect& srcRect, const Vec2& texSize,
|
||||
Ptr<Texture> texture,
|
||||
const Color& color = Color(1, 1, 1, 1));
|
||||
void setupBlendMode(BlendMode mode);
|
||||
/**
|
||||
* @brief 获取当前激活的层级风格设置
|
||||
*/
|
||||
const RenderStyleLayerSettings& getActiveRenderStyle() const {
|
||||
return activeRenderStyle_;
|
||||
}
|
||||
/**
|
||||
* @brief 当前风格是否要求顶点像素对齐
|
||||
*/
|
||||
bool shouldSnapVertices() const { return activeRenderStyle_.vertexPixelSnap; }
|
||||
/**
|
||||
* @brief 当前风格是否优先使用像素风采样
|
||||
*/
|
||||
bool shouldUsePixelArtSampling() const {
|
||||
return activeRenderStyle_.pixelArtSampling;
|
||||
}
|
||||
/**
|
||||
* @brief 当前风格是否需要对子纹理 UV 做向内收缩
|
||||
*/
|
||||
bool shouldShrinkSubTextureUVs() const {
|
||||
return activeRenderStyle_.shrinkSubTextureUVs;
|
||||
}
|
||||
|
||||
ShaderManager& getShaderManager() { return shaderManager_; }
|
||||
Batch& getBatch() { return batch_; }
|
||||
|
||||
private:
|
||||
Renderer();
|
||||
|
||||
void updateUniforms();
|
||||
void recalculateResolutionState();
|
||||
void recalculateSingleResolutionState(RenderResolutionState& state,
|
||||
bool useVirtualResolution,
|
||||
int virtualWidth, int virtualHeight,
|
||||
ResolutionScaleMode mode) const;
|
||||
void syncCameraViewport();
|
||||
|
||||
struct RenderTargetState {
|
||||
uint32 framebuffer = 0;
|
||||
int viewportX = 0;
|
||||
int viewportY = 0;
|
||||
int viewportWidth = 1;
|
||||
int viewportHeight = 1;
|
||||
float clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
Camera* camera = nullptr;
|
||||
bool startedStandaloneBatch = false;
|
||||
bool cullingEnabled = true;
|
||||
};
|
||||
|
||||
ShaderManager shaderManager_;
|
||||
Batch batch_;
|
||||
Camera* camera_ = nullptr;
|
||||
RenderStyleProfileId defaultRenderStyleProfile_ = RenderStyleProfileId::Hybrid2D;
|
||||
RenderStyleProfileId activeRenderStyleProfile_ = RenderStyleProfileId::Hybrid2D;
|
||||
RenderStyleLayerRole activeRenderStyleRole_ = RenderStyleLayerRole::World;
|
||||
RenderStyleLayerSettings activeRenderStyle_;
|
||||
|
||||
uint32_t clearColor_[4] = {0, 0, 0, 255};
|
||||
bool useVirtualResolution_ = false;
|
||||
int virtualWidth_ = 1280;
|
||||
int virtualHeight_ = 720;
|
||||
ResolutionScaleMode resolutionMode_ = ResolutionScaleMode::Fit;
|
||||
bool useSeparateUIVirtualResolution_ = false;
|
||||
int uiVirtualWidth_ = 0;
|
||||
int uiVirtualHeight_ = 0;
|
||||
ResolutionScaleMode uiResolutionMode_ = ResolutionScaleMode::Fit;
|
||||
RenderResolutionState resolutionState_;
|
||||
RenderResolutionState uiResolutionState_;
|
||||
|
||||
bool initialized_ = false;
|
||||
bool frameActive_ = false;
|
||||
bool cullingEnabled_ = true;
|
||||
std::vector<RenderTargetState> renderTargetStack_;
|
||||
|
||||
Renderer(const Renderer&) = delete;
|
||||
Renderer& operator=(const Renderer&) = delete;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
#include <frostbite2D/types/type_math.h>
|
||||
#include <frostbite2D/base/RefObject.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class Shader : public RefObject {
|
||||
public:
|
||||
Shader() = default;
|
||||
~Shader();
|
||||
|
||||
void use();
|
||||
void unuse();
|
||||
|
||||
bool isValid() const { return programID_ != 0; }
|
||||
uint32_t getID() const { return programID_; }
|
||||
const std::string& getName() const { return name_; }
|
||||
|
||||
void setInt(const std::string& name, int value);
|
||||
void setFloat(const std::string& name, float value);
|
||||
void setVec2(const std::string& name, const Vec2& value);
|
||||
void setVec3(const std::string& name, const glm::vec3& value);
|
||||
void setVec4(const std::string& name, const glm::vec4& value);
|
||||
void setMat3(const std::string& name, const glm::mat3& value);
|
||||
void setMat4(const std::string& name, const glm::mat4& value);
|
||||
void setTexture(const std::string& name, int slot);
|
||||
|
||||
private:
|
||||
Shader(const std::string& name, uint32_t programID);
|
||||
|
||||
friend class ShaderManager;
|
||||
|
||||
bool compile(uint32_t type, const std::string& source);
|
||||
bool link(uint32_t vertexID, uint32_t fragmentID);
|
||||
int getUniformLocation(const std::string& name);
|
||||
|
||||
uint32_t programID_ = 0;
|
||||
std::string name_;
|
||||
std::unordered_map<std::string, int> uniformLocations_;
|
||||
|
||||
Shader(const Shader&) = delete;
|
||||
Shader& operator=(const Shader&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/graphics/shader.h>
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class Renderer;
|
||||
|
||||
class ShaderManager {
|
||||
public:
|
||||
static ShaderManager& get();
|
||||
|
||||
bool init(const std::string& shadersDir);
|
||||
void shutdown();
|
||||
|
||||
Shader* getShader(const std::string& name);
|
||||
bool hasShader(const std::string& name) const;
|
||||
const std::unordered_map<std::string, Ptr<Shader>>& getLoadedShaders() const {
|
||||
return shaders_;
|
||||
}
|
||||
|
||||
~ShaderManager() = default;
|
||||
|
||||
ShaderManager() = default;
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<std::string, Ptr<Shader>> shaders_;
|
||||
std::string shadersDir_;
|
||||
|
||||
bool loadShadersFromConfig(const std::string& configPath);
|
||||
bool loadShader(const std::string& name, const std::string& vertPath,
|
||||
const std::string& fragPath);
|
||||
|
||||
ShaderManager(const ShaderManager&) = delete;
|
||||
ShaderManager& operator=(const ShaderManager&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/graphics/types.h>
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
#include <frostbite2D/base/RefObject.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
enum class TextureSampling {
|
||||
Linear,
|
||||
PixelArt
|
||||
};
|
||||
|
||||
class Texture : public RefObject {
|
||||
public:
|
||||
static Ptr<Texture> loadFromFile(const std::string& path);
|
||||
static Ptr<Texture> createFromMemory(const uint8* data, int width, int height, int channels);
|
||||
static Ptr<Texture> createEmpty(int width, int height);
|
||||
|
||||
~Texture();
|
||||
|
||||
void bind(uint32_t slot = 0, bool preferPixelArtSampling = false);
|
||||
void unbind();
|
||||
|
||||
void setWrapMode(uint32_t wrapS, uint32_t wrapT);
|
||||
void setFilterMode(uint32_t minFilter, uint32_t magFilter);
|
||||
void setSampling(TextureSampling sampling);
|
||||
TextureSampling getSampling() const { return sampling_; }
|
||||
|
||||
int getWidth() const { return width_; }
|
||||
int getHeight() const { return height_; }
|
||||
uint32_t getID() const { return textureID_; }
|
||||
const std::string& getPath() const { return path_; }
|
||||
|
||||
private:
|
||||
Texture(int width, int height, uint32_t id);
|
||||
void applyFilter(uint32_t minFilter, uint32_t magFilter);
|
||||
void applySampling(bool preferPixelArtSampling);
|
||||
|
||||
uint32_t textureID_ = 0;
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
int channels_ = 0;
|
||||
std::string path_;
|
||||
TextureSampling sampling_ = TextureSampling::Linear;
|
||||
uint32_t appliedMinFilter_ = 0;
|
||||
uint32_t appliedMagFilter_ = 0;
|
||||
|
||||
Texture() = default;
|
||||
Texture(const Texture&) = delete;
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
#include <frostbite2D/types/type_alias.h>
|
||||
#include <frostbite2D/types/type_math.h>
|
||||
#include <frostbite2D/types/type_color.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
enum class BlendMode {
|
||||
None,
|
||||
Normal,
|
||||
Additive,
|
||||
Screen,
|
||||
Premultiplied,
|
||||
Subtractive,
|
||||
Multiply
|
||||
};
|
||||
|
||||
enum class PrimitiveType {
|
||||
Triangles,
|
||||
TriangleStrip,
|
||||
TriangleFan,
|
||||
Quads
|
||||
};
|
||||
|
||||
struct Vertex {
|
||||
Vec2 position;
|
||||
Vec2 texCoord;
|
||||
float r, g, b, a;
|
||||
|
||||
Vertex() = default;
|
||||
Vertex(const Vec2& pos, const Vec2& uv, float cr, float cg, float cb, float ca)
|
||||
: position(pos), texCoord(uv), r(cr), g(cg), b(cb), a(ca) {}
|
||||
};
|
||||
|
||||
struct Quad {
|
||||
Vertex vertices[4];
|
||||
|
||||
Quad() = default;
|
||||
|
||||
static Quad create(const Rect& rect, float cr = 1.0f, float cg = 1.0f,
|
||||
float cb = 1.0f, float ca = 1.0f) {
|
||||
Quad q;
|
||||
Vec2 bl(rect.left(), rect.bottom());
|
||||
Vec2 br(rect.right(), rect.bottom());
|
||||
Vec2 tl(rect.left(), rect.top());
|
||||
Vec2 tr(rect.right(), rect.top());
|
||||
|
||||
q.vertices[0] = Vertex(bl, Vec2(0, 0), cr, cg, cb, ca);
|
||||
q.vertices[1] = Vertex(br, Vec2(1, 0), cr, cg, cb, ca);
|
||||
q.vertices[2] = Vertex(tl, Vec2(0, 1), cr, cg, cb, ca);
|
||||
q.vertices[3] = Vertex(tr, Vec2(1, 1), cr, cg, cb, ca);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static Quad createTextured(const Rect& destRect, const Rect& srcRect,
|
||||
const Vec2& texSize, float cr = 1.0f,
|
||||
float cg = 1.0f, float cb = 1.0f, float ca = 1.0f,
|
||||
bool shrinkSubTextureUVs = false) {
|
||||
Quad q;
|
||||
|
||||
Vec2 bl(destRect.left(), destRect.bottom());
|
||||
Vec2 br(destRect.right(), destRect.bottom());
|
||||
Vec2 tl(destRect.left(), destRect.top());
|
||||
Vec2 tr(destRect.right(), destRect.top());
|
||||
|
||||
auto resolveUvX = [&srcRect, &texSize, shrinkSubTextureUVs](bool useRightEdge) {
|
||||
float pixelInset = 0.0f;
|
||||
if (!shrinkSubTextureUVs) {
|
||||
return (useRightEdge ? srcRect.right() : srcRect.left()) / texSize.x;
|
||||
}
|
||||
if (useRightEdge && srcRect.right() < texSize.x) {
|
||||
pixelInset = -0.5f;
|
||||
} else if (!useRightEdge && srcRect.left() > 0.0f) {
|
||||
pixelInset = 0.5f;
|
||||
}
|
||||
return (useRightEdge ? srcRect.right() : srcRect.left()) / texSize.x +
|
||||
pixelInset / texSize.x;
|
||||
};
|
||||
|
||||
auto resolveUvY = [&srcRect, &texSize, shrinkSubTextureUVs](bool useBottomEdge) {
|
||||
float pixelInset = 0.0f;
|
||||
if (!shrinkSubTextureUVs) {
|
||||
return (useBottomEdge ? srcRect.bottom() : srcRect.top()) / texSize.y;
|
||||
}
|
||||
if (useBottomEdge && srcRect.bottom() < texSize.y) {
|
||||
pixelInset = -0.5f;
|
||||
} else if (!useBottomEdge && srcRect.top() > 0.0f) {
|
||||
pixelInset = 0.5f;
|
||||
}
|
||||
return (useBottomEdge ? srcRect.bottom() : srcRect.top()) / texSize.y +
|
||||
pixelInset / texSize.y;
|
||||
};
|
||||
|
||||
Vec2 uvBL(resolveUvX(false), resolveUvY(true));
|
||||
Vec2 uvBR(resolveUvX(true), resolveUvY(true));
|
||||
Vec2 uvTL(resolveUvX(false), resolveUvY(false));
|
||||
Vec2 uvTR(resolveUvX(true), resolveUvY(false));
|
||||
|
||||
q.vertices[0] = Vertex(bl, uvBL, cr, cg, cb, ca);
|
||||
q.vertices[1] = Vertex(br, uvBR, cr, cg, cb, ca);
|
||||
q.vertices[2] = Vertex(tl, uvTL, cr, cg, cb, ca);
|
||||
q.vertices[3] = Vertex(tr, uvTR, cr, cg, cb, ca);
|
||||
|
||||
return q;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user