diff --git a/Frostbite2D/include/frostbite2D/2d/sprite.h b/Frostbite2D/include/frostbite2D/2d/sprite.h new file mode 100644 index 0000000..2640c89 --- /dev/null +++ b/Frostbite2D/include/frostbite2D/2d/sprite.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace frostbite2D { + +class Sprite : public Actor { +public: + Sprite(); + explicit Sprite(Ptr texture); + virtual ~Sprite(); + + static Ptr createFromFile(const std::string& path); + static Ptr createFromMemory(uint8* data, int width, int height, int channels); + + void Render() override; + + void SetTexture(Ptr texture); + Ptr GetTexture() const { return texture_; } + + void SetShader(const std::string& shaderName); + void SetDefaultShader(); + const std::string& GetShaderName() const { return shaderName_; } + bool HasCustomShader() const { return !shaderName_.empty(); } + + void SetSourceRect(const Rect& rect); + const Rect& GetSourceRect() const { return srcRect_; } + + void SetColor(const Color& color); + void SetColor(float r, float g, float b, float a = 1.0f); + const Color& GetColor() const { return color_; } + + void SetFlippedX(bool flipped); + void SetFlippedY(bool flipped); + bool IsFlippedX() const { return flippedX_; } + bool IsFlippedY() const { return flippedY_; } + + void SetBlendMode(BlendMode mode); + BlendMode GetBlendMode() const { return blendMode_; } + + void SetSizeToTexture(); + +private: + void updateTransform(); + Shader* getActiveShader() const; + Quad createQuad() const; + + Ptr texture_; + std::string shaderName_; + Color color_ = Color(1.0f, 1.0f, 1.0f, 1.0f); + Rect srcRect_; + bool flippedX_ = false; + bool flippedY_ = false; + BlendMode blendMode_ = BlendMode::Normal; + Transform2D transform_; + + static constexpr const char* DEFAULT_SHADER = "sprite"; +}; + +} + diff --git a/Frostbite2D/src/frostbite2D/2d/sprite.cpp b/Frostbite2D/src/frostbite2D/2d/sprite.cpp new file mode 100644 index 0000000..60a5d94 --- /dev/null +++ b/Frostbite2D/src/frostbite2D/2d/sprite.cpp @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include + +namespace frostbite2D { + +Sprite::Sprite() + : Actor() { +} + +Sprite::Sprite(Ptr texture) + : Actor() + , texture_(texture) { +} + +Sprite::~Sprite() { +} + +Ptr Sprite::createFromFile(const std::string& path) { + Ptr texture = Texture::loadFromFile(path); + if (!texture) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load texture: %s", path.c_str()); + return nullptr; + } + + auto sprite = MakePtr(texture); + sprite->SetSizeToTexture(); + return sprite; +} + +Ptr Sprite::createFromMemory(uint8* data, int width, int height, int channels) { + Ptr texture = Texture::createFromMemory(data, width, height, channels); + if (!texture) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to create texture from memory"); + return nullptr; + } + + auto sprite = MakePtr(texture); + sprite->SetSizeToTexture(); + return sprite; +} + +void Sprite::Render() { + if (!IsVisible()) { + RenderChildren(); + return; + } + + if (!texture_) { + RenderChildren(); + return; + } + + Renderer& renderer = Renderer::get(); + Batch& batch = renderer.getBatch(); + + Shader* shader = getActiveShader(); + if (!shader || !shader->isValid()) { + RenderChildren(); + return; + } + + updateTransform(); + + Quad quad = createQuad(); + + batch.submitQuad(quad, transform_, texture_, shader, blendMode_); + + RenderChildren(); +} + +void Sprite::SetTexture(Ptr texture) { + texture_ = texture; +} + +void Sprite::SetShader(const std::string& shaderName) { + shaderName_ = shaderName; +} + +void Sprite::SetDefaultShader() { + shaderName_.clear(); +} + +void Sprite::SetSourceRect(const Rect& rect) { + srcRect_ = rect; +} + +void Sprite::SetColor(const Color& color) { + color_ = color; +} + +void Sprite::SetColor(float r, float g, float b, float a) { + color_ = Color(r, g, b, a); +} + +void Sprite::SetFlippedX(bool flipped) { + flippedX_ = flipped; +} + +void Sprite::SetFlippedY(bool flipped) { + flippedY_ = flipped; +} + +void Sprite::SetBlendMode(BlendMode mode) { + blendMode_ = mode; +} + +void Sprite::SetSizeToTexture() { + if (texture_) { + SetSize(texture_->getWidth(), texture_->getHeight()); + } +} + +void Sprite::updateTransform() { + Vec2 pos = GetPosition(); + float rotation = GetRotation(); + Vec2 scale = GetScale(); + + transform_ = Transform2D::translation(pos.x, pos.y) * + Transform2D::rotation(rotation) * + Transform2D::scaling(scale.x, scale.y); +} + +Shader* Sprite::getActiveShader() const { + Renderer& renderer = Renderer::get(); + ShaderManager& shaderManager = renderer.getShaderManager(); + + if (!shaderName_.empty()) { + Shader* shader = shaderManager.getShader(shaderName_); + if (shader && shader->isValid()) { + return shader; + } else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Shader '%s' not found or invalid, fallback to default", + shaderName_.c_str()); + } + } + + return shaderManager.getShader(DEFAULT_SHADER); +} + +Quad Sprite::createQuad() const { + Rect srcRect = srcRect_; + if (srcRect.empty()) { + srcRect = Rect(0, 0, texture_->getWidth(), texture_->getHeight()); + } + + Vec2 destPos(0, 0); + Vec2 destSizeVec = GetSize(); + if (destSizeVec.x == 0) { + destSizeVec.x = srcRect.width(); + } + if (destSizeVec.y == 0) { + destSizeVec.y = srcRect.height(); + } + + Rect destRect(0, 0, destSizeVec.x, destSizeVec.y); + + Vec2 texSize(texture_->getWidth(), texture_->getHeight()); + + Quad quad = Quad::createTextured( + destRect, srcRect, texSize, + color_.r, color_.g, color_.b, color_.a + ); + + if (flippedX_) { + std::swap(quad.vertices[0].texCoord, quad.vertices[1].texCoord); + std::swap(quad.vertices[2].texCoord, quad.vertices[3].texCoord); + } + if (flippedY_) { + std::swap(quad.vertices[0].texCoord, quad.vertices[2].texCoord); + std::swap(quad.vertices[1].texCoord, quad.vertices[3].texCoord); + } + + return quad; +} + +} + diff --git a/Frostbite2D/src/frostbite2D/core/application.cpp b/Frostbite2D/src/frostbite2D/core/application.cpp index f3053c9..4e9fe74 100644 --- a/Frostbite2D/src/frostbite2D/core/application.cpp +++ b/Frostbite2D/src/frostbite2D/core/application.cpp @@ -197,7 +197,12 @@ void Application::update() { } void Application::render() { + Renderer& renderer = Renderer::get(); + Batch& batch = renderer.getBatch(); + + batch.begin(); SceneManager::get().Render(); + batch.end(); if (window_) { window_->swap(); diff --git a/Game/assets/player.png b/Game/assets/player.png new file mode 100644 index 0000000..ad3a78f Binary files /dev/null and b/Game/assets/player.png differ diff --git a/Game/src/main.cpp b/Game/src/main.cpp index aa0f293..75a29ba 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace frostbite2D; @@ -28,6 +29,13 @@ int main(int argc, char **argv) { SDL_Log("Starting main loop..."); + auto menuScene = MakePtr(); + SceneManager::get().PushScene(menuScene); + + auto sprite = Sprite::createFromFile("assets\\player.png"); + sprite->SetPosition(100, 100); + menuScene->AddActor(sprite); + app.run(); app.shutdown();