diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d2720a1..a612525b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,8 @@ project(PracticalToolsForSimpleDesign) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -if (MSVC) + +if(MSVC) set(TARGET_COMPILE_OPTIONS /W4 ) @@ -17,7 +18,7 @@ else() ) endif() -if (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # see https://github.com/ntut-open-source-club/practical-tools-for-simple-design/issues/22 set(CMAKE_RC_FLAGS="-C 1252") endif() @@ -52,11 +53,13 @@ set(SRC_FILES ${SRC_DIR}/Util/Color.cpp ${SRC_DIR}/Util/Animation.cpp ${SRC_DIR}/Util/MissingTexture.cpp + ${SRC_DIR}/Util/SpriteSheet.cpp ${SRC_DIR}/App.cpp ${SRC_DIR}/Giraffe.cpp ${SRC_DIR}/GiraffeText.cpp ${SRC_DIR}/Cat.cpp + ${SRC_DIR}/SpriteSheetTester.cpp ) set(INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) set(INCLUDE_FILES @@ -90,12 +93,14 @@ set(INCLUDE_FILES ${INCLUDE_DIR}/Util/TransparentImage.hpp ${INCLUDE_DIR}/Util/Base64.hpp ${INCLUDE_DIR}/Util/Animation.hpp + ${INCLUDE_DIR}/Util/SpriteSheet.hpp ${INCLUDE_DIR}/App.hpp ${INCLUDE_DIR}/Giraffe.hpp ${INCLUDE_DIR}/GiraffeText.hpp ${INCLUDE_DIR}/Cat.hpp ${INCLUDE_DIR}/config.hpp + ${INCLUDE_DIR}/SpriteSheetTester.hpp ) set(TEST_DIR ${CMAKE_SOURCE_DIR}/test) set(TEST_FILES @@ -118,11 +123,13 @@ target_include_directories(Sample SYSTEM PRIVATE target_include_directories(Sample PRIVATE ${INCLUDE_DIR} ) -if (${PTSD_ENABLE_PCH}) + +if(${PTSD_ENABLE_PCH}) target_precompile_headers(Sample PRIVATE include/pch.hpp ) endif() + target_compile_options(Sample PRIVATE ${TARGET_COMPILE_OPTIONS} ) diff --git a/include/App.hpp b/include/App.hpp index 63421aaa..11745683 100644 --- a/include/App.hpp +++ b/include/App.hpp @@ -1,6 +1,7 @@ #ifndef APP_HPP #define APP_HPP +#include "SpriteSheetTester.hpp" #include "pch.hpp" // IWYU pragma: export #include "Util/Renderer.hpp" @@ -31,6 +32,8 @@ class App { // std::make_shared(); std::shared_ptr m_Cat = std::make_shared(); + std::shared_ptr m_SpriteSheet = + std::make_shared(); Util::Renderer m_Root; }; diff --git a/include/SpriteSheetTester.hpp b/include/SpriteSheetTester.hpp new file mode 100644 index 00000000..61b984e5 --- /dev/null +++ b/include/SpriteSheetTester.hpp @@ -0,0 +1,16 @@ +#ifndef SPRITESHEETTESTER_HPP +#define SPRITESHEETTESTER_HPP + +#include "Util/GameObject.hpp" +#include "Util/SpriteSheet.hpp" +class SpriteSheetTester : public Util::GameObject { +public: + SpriteSheetTester(); + + void Update(); + +private: + std::shared_ptr m_Spritesheet; +}; + +#endif diff --git a/include/Util/Image.hpp b/include/Util/Image.hpp index ec6df9ef..a4209c0e 100644 --- a/include/Util/Image.hpp +++ b/include/Util/Image.hpp @@ -1,10 +1,12 @@ #ifndef UTIL_IMAGE_HPP #define UTIL_IMAGE_HPP +#include "SDL_surface.h" #include "pch.hpp" // IWYU pragma: export #include #include +#include #include "Core/Drawable.hpp" #include "Core/Texture.hpp" @@ -59,6 +61,21 @@ class Image : public Core::Drawable { */ void Draw(const Util::Transform &transform, const float zIndex) override; + /** + * @brief Get the SDL_Surface that current draw. + * + * This function return the SDL_Surface that current draw. + * + */ + SDL_Surface &GetSDLSurface() const { return *m_Surface.get(); } + /** + * @brief Update TextureDate by SDL_Surface + * + * This function Update TextureDate by SDL_Surface. + * + */ + void UpdateTextureData(const SDL_Surface &surface); + private: void InitProgram(); void InitVertexArray(); @@ -72,7 +89,7 @@ class Image : public Core::Drawable { private: std::unique_ptr m_Texture = nullptr; - + std::unique_ptr> m_Surface; std::string m_Path; glm::vec2 m_Size; }; diff --git a/include/Util/SpriteSheet.hpp b/include/Util/SpriteSheet.hpp new file mode 100644 index 00000000..f1f5139f --- /dev/null +++ b/include/Util/SpriteSheet.hpp @@ -0,0 +1,56 @@ +#ifndef UTIL_SPRITESHEET_HPP +#define UTIL_SPRITESHEET_HPP + +#include "Core/Drawable.hpp" +#include "SDL_rect.h" +#include "Util/Image.hpp" +#include +namespace Util { +class SpriteSheet : public Core::Drawable { +public: + SpriteSheet(const std::string &filepath); + /** + * @brief Draws the image with a given transform and z-index. + * + * This function draws the image at the specified z-index and applies the + * given transform. + * + * @param transform The transform to apply to the image. + * @param zIndex The z-index at which to draw the image. + */ + void Draw(const Util::Transform &transform, const float zIndex) override; + /** + * @brief Retrieves the size of the image. + * + * This function returns the size of the image. + * + * @return The size of the image as a vec2(x, y). + */ + glm::vec2 GetSize() const override; + /** + * @brief Sets the image to the specified file path. + * + * This function sets the image to the specified file path. + * it will reset the DrawRect + * + * @param filepath The file path to the image. + */ + void SetImage(const std::string &filepath); + + /** + * @brief Set draw range. + * + * @param displayRect The Rect of draw range + */ + void SetDrawRect(const SDL_Rect displayRect); + + void RestDrawRect(); + +private: + std::unique_ptr m_Image; + SDL_Rect m_OriginRect; +}; + +} // namespace Util + +#endif diff --git a/src/App.cpp b/src/App.cpp index 26aa1d80..e1e0a0f8 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -17,6 +17,7 @@ void App::Start() { m_Root.AddChild(m_Giraffe); m_Root.AddChild(m_Cat); + m_Root.AddChild(m_SpriteSheet); m_CurrentState = State::UPDATE; } @@ -56,6 +57,7 @@ void App::Update() { m_Giraffe->Update(); m_Cat->Update(); + m_SpriteSheet->Update(); m_Root.Update(); } diff --git a/src/SpriteSheetTester.cpp b/src/SpriteSheetTester.cpp new file mode 100644 index 00000000..8650f31f --- /dev/null +++ b/src/SpriteSheetTester.cpp @@ -0,0 +1,21 @@ +#include "SpriteSheetTester.hpp" +#include "Util/Input.hpp" +#include "Util/Keycode.hpp" +#include "Util/SpriteSheet.hpp" +#include + +SpriteSheetTester::SpriteSheetTester() + : m_Spritesheet(std::make_shared( + "../assets/sprites/cat/cat-0.bmp")) { + m_Transform.translation = {200, -200}; + SetDrawable(m_Spritesheet); +} + +void SpriteSheetTester::Update() { + if (Util::Input::IsKeyDown(Util::Keycode::Y)) { + m_Spritesheet->SetDrawRect({20, 20, 250, 250}); + } + if (Util::Input::IsKeyUp(Util::Keycode::Y)) { + m_Spritesheet->RestDrawRect(); + } +} diff --git a/src/Util/Image.cpp b/src/Util/Image.cpp index 63ffd682..0d4fc515 100644 --- a/src/Util/Image.cpp +++ b/src/Util/Image.cpp @@ -1,5 +1,7 @@ #include "Util/Image.hpp" +#include "SDL_surface.h" +#include "Util/Logger.hpp" #include "pch.hpp" #include "Core/Texture.hpp" @@ -9,6 +11,7 @@ #include "Util/TransformUtils.hpp" #include "config.hpp" +#include namespace Util { Image::Image(const std::string &filepath) @@ -23,38 +26,35 @@ Image::Image(const std::string &filepath) InitUniformBuffer(); } - auto surface = + m_Surface = std::unique_ptr>{ IMG_Load(filepath.c_str()), SDL_FreeSurface, }; - if (surface == nullptr) { - surface = {GetMissingTextureSDLSurface(), SDL_FreeSurface}; + if (m_Surface == nullptr) { + m_Surface = {GetMissingTextureSDLSurface(), SDL_FreeSurface}; LOG_ERROR("Failed to load image: '{}'", filepath); LOG_ERROR("{}", IMG_GetError()); } m_Texture = std::make_unique( - Core::SdlFormatToGlFormat(surface->format->format), surface->w, - surface->h, surface->pixels); - m_Size = {surface->w, surface->h}; + Core::SdlFormatToGlFormat(m_Surface->format->format), m_Surface->w, + m_Surface->h, m_Surface->pixels); + m_Size = {m_Surface->w, m_Surface->h}; } void Image::SetImage(const std::string &filepath) { - auto surface = + m_Surface = std::unique_ptr>{ IMG_Load(filepath.c_str()), SDL_FreeSurface, }; - if (surface == nullptr) { + if (m_Surface == nullptr) { LOG_ERROR("Failed to load image: '{}'", filepath); LOG_ERROR("{}", IMG_GetError()); } - - m_Texture->UpdateData(Core::SdlFormatToGlFormat(surface->format->format), - surface->w, surface->h, surface->pixels); - m_Size = {surface->w, surface->h}; + UpdateTextureData(*m_Surface.get()); } void Image::Draw(const Util::Transform &transform, const float zIndex) { @@ -120,6 +120,12 @@ void Image::InitUniformBuffer() { *s_Program, "Matrices", 0); } +void Image::UpdateTextureData(const SDL_Surface &surface) { + m_Texture->UpdateData(Core::SdlFormatToGlFormat(surface.format->format), + surface.w, surface.h, surface.pixels); + m_Size = {surface.w, surface.h}; +} + std::unique_ptr Image::s_Program = nullptr; std::unique_ptr Image::s_VertexArray = nullptr; std::unique_ptr> Image::s_UniformBuffer = diff --git a/src/Util/SpriteSheet.cpp b/src/Util/SpriteSheet.cpp new file mode 100644 index 00000000..6b98beea --- /dev/null +++ b/src/Util/SpriteSheet.cpp @@ -0,0 +1,63 @@ +#include "Util/SpriteSheet.hpp" +#include "Util/Image.hpp" +#include + +namespace Util { +SpriteSheet::SpriteSheet(const std::string &filepath) + : m_Image(std::make_unique(filepath)) { + m_OriginRect.x = 0; + m_OriginRect.y = 0; + m_OriginRect.w = m_Image->GetSize().x; + m_OriginRect.h = m_Image->GetSize().y; +} + +void SpriteSheet::SetImage(const std::string &filepath) { + m_Image->SetImage(filepath); + m_OriginRect.x = 0; + m_OriginRect.y = 0; + m_OriginRect.w = m_Image->GetSize().x; + m_OriginRect.h = m_Image->GetSize().y; +} + +void SpriteSheet::Draw(const Util::Transform &transform, const float zIndex) { + m_Image->Draw(transform, zIndex); +} + +glm::vec2 SpriteSheet::GetSize() const { + return m_Image->GetSize(); +} + +void SpriteSheet::RestDrawRect() { + SetDrawRect(m_OriginRect); +} + +void SpriteSheet::SetDrawRect(const SDL_Rect displayRect) { + // can't just simplely use SDL_SetClipRect, because we use opengl to render + // and I'm not sure this way if cost a lot performance? + SDL_Surface &originSDLSurface = m_Image->GetSDLSurface(); + + if (displayRect.h + displayRect.y > originSDLSurface.h || + displayRect.w + displayRect.x > originSDLSurface.w) { + LOG_DEBUG("SetDrawRect OverRange"); + return; + } + + auto targetSurface = + std::unique_ptr>{ + SDL_CreateRGBSurfaceWithFormat( + 0, displayRect.w, displayRect.h, + originSDLSurface.format->BitsPerPixel, + originSDLSurface.format->format), + SDL_FreeSurface, + }; + + int isCopyWork = SDL_BlitSurface(&originSDLSurface, &displayRect, + targetSurface.get(), NULL); + if (isCopyWork != 0) { + LOG_ERROR("{}", SDL_GetError()); + return; + } + m_Image->UpdateTextureData(*targetSurface.get()); +} + +} // namespace Util