Added ostd::AsyncJob class

This commit is contained in:
OmniaX-Dev 2026-03-10 00:54:14 +01:00
parent 42a2ee330b
commit 367ad5c92a
10 changed files with 313 additions and 17 deletions

View file

@ -86,6 +86,7 @@ list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Image.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/WindowBaseOutputHandler.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/PixelRenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/Animation.cpp
)
list(APPEND TEST_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/test.cpp

BIN
extra/res/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

View file

@ -1 +1 @@
2009
2020

97
src/ogfx/Animation.cpp Normal file
View file

@ -0,0 +1,97 @@
#include "Animation.hpp"
#include <ostd/math/Random.hpp>
namespace ogfx
{
Animation::Animation(void)
{
create(0, 0, 0, 0, 0);
}
Animation::Animation(int frames, int columns, int rows, int frame_width, int frame_height)
{
create(frames, columns, rows, frame_width, frame_height);
}
Animation::Animation(AnimationData& ad)
{
create(ad);
}
void Animation::create(AnimationData& ad)
{
create(ad.length, ad.columns, ad.rows, ad.frame_width, ad.frame_height);
m_backwards = ad.backwards;
m_still = ad.still;
m_column_offset = ad.column_offset;
m_row_offset = ad.row_offset;
m_frame_time = ad.speed;
m_random = false;
}
void Animation::create(int frames, int columns, int rows, int frame_width, int frame_height)
{
m_frames = frames;
m_columns = columns;
m_frame_width = frame_width;
m_frame_height = frame_height;
m_rows = rows;
m_frame_time = 5;
m_current_time = 0;
m_current_frame = 0;
m_backwards = false;
m_back = false;
m_still = false;
m_random = false;
m_column_offset = 0;
m_row_offset = 0;
}
void Animation::resetAnimation(void)
{
m_current_frame = 0;
m_current_time = 0;
}
void Animation::update(void)
{
if (m_current_time++ > m_frame_time && !m_still)
{
m_current_time = 0;
if (m_random)
{
m_current_frame = ostd::Random::geti32(0, m_frames);
}
else if (m_backwards)
{
if (!m_back && m_current_frame >= m_frames - 1)
{
m_back = true;
m_current_frame--;
}
else if (!m_back)
m_current_frame++;
else if (m_back && m_current_frame <= 0)
{
m_back = false;
m_current_frame++;
}
else if (m_back)
m_current_frame--;
}
else
{
if (m_current_frame++ >= m_frames - 1)
m_current_frame = 0;
}
}
else if (m_still)
m_current_frame = 1; //TODO: Hardcoded value
int x = ((m_current_frame % m_columns) + m_column_offset) * m_frame_width;
int y = m_row_offset * m_frame_height;
if (m_rows > 1)
y = ((m_current_frame / m_columns) + m_row_offset) * m_frame_height;
m_frame_rect = { static_cast<float>(x), static_cast<float>(y), static_cast<float>(m_frame_width), static_cast<float>(m_frame_height) };
}
}

98
src/ogfx/Animation.hpp Normal file
View file

@ -0,0 +1,98 @@
#pragma once
#include <ostd/data_types/Types.hpp>
#include <ostd/math/Geometry.hpp>
#include <ogfx/Image.hpp>
namespace ogfx
{
class Animation
{
public: struct AnimationData {
int32_t length;
int32_t speed;
int32_t still_frame;
int32_t row_offset;
int32_t column_offset;
int32_t rows;
int32_t columns;
int32_t frame_width;
int32_t frame_height;
bool still;
bool backwards;
bool random;
AnimationData(void)
{
length = 3;
speed = 10;
row_offset = 0;
column_offset = 0;
rows = 1;
columns = 3;
frame_width = 32;
frame_height = 32;
still = false;
backwards = true;
random = false;
still_frame = 1;
}
};
public:
Animation(void);
Animation(int32_t frames, int32_t columns, int32_t rows, int32_t frame_width, int32_t frame_height);
Animation(AnimationData& ad);
void create(int32_t frames, int32_t columns, int32_t rows, int32_t frame_width, int32_t frame_height);
void create(AnimationData& ad);
void update(void);
void resetAnimation(void);
inline void setFrameNumber(int32_t n) { m_frames = n; }
inline void setColumnNumber(int32_t n) { m_columns = n; }
inline void setBackwards(bool b) { m_backwards = b; }
inline void setSpeed(int32_t d) { m_frame_time = d; }
inline void setColumnOffset(int32_t o) { m_column_offset = o; }
inline void setRowOffset(int32_t o) { m_row_offset = o; }
inline void setStill(bool s) { m_still = s; }
inline void setSpriteSheet(const Image& img) { m_spriteSheet = &img; }
inline int32_t getFrameNumber(void) const { return m_frames; }
inline int32_t getColumnNumber(void) const { return m_columns; }
inline bool getBackwards(void) const { return m_backwards; }
inline int32_t getDelay(void) const { return m_frame_time; }
inline int32_t getColumnOffset(void) const { return m_column_offset; }
inline int32_t getRowOffset(void) const { return m_row_offset; }
inline bool isStill(void) const { return m_still; }
inline ostd::Rectangle getFrameRect(void) const { return m_frame_rect; }
inline const Image& getSpriteSheet(void) const { return (m_spriteSheet != nullptr ? *m_spriteSheet : InvalidImage); }
inline bool hasImage(void) const { return m_spriteSheet != nullptr; }
private:
const Image* m_spriteSheet { nullptr };
inline static const Image InvalidImage;
int32_t m_frames;
int32_t m_rows;
int32_t m_columns;
int32_t m_frame_width;
int32_t m_frame_height;
int32_t m_column_offset;
int32_t m_row_offset;
int32_t m_frame_time;
int32_t m_current_time;
int32_t m_current_frame;
bool m_backwards;
bool m_back;
bool m_still;
bool m_random;
ostd::Rectangle m_frame_rect;
};
}

View file

@ -1,5 +1,6 @@
#include "BasicRenderer.hpp"
#include "WindowBase.hpp"
#include <SDL2/SDL_rect.h>
namespace ogfx
{
@ -22,7 +23,7 @@ namespace ogfx
m_ttfr.setFontSize(fontSize);
}
void BasicRenderer2D::drawImage(const ogfx::Image& image, const ostd::Vec2& position)
void BasicRenderer2D::drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Rectangle& rect)
{
if (!m_initialized) return;
if (!image.isLoaded()) return;
@ -31,7 +32,28 @@ namespace ogfx
texr.y = position.y;
texr.w = image.getSize().x;
texr.h = image.getSize().y;
SDL_RenderCopy(m_window->getSDLRenderer(), image.getSDLTexture(), nullptr, &texr);
SDL_Rect srcRect;
srcRect.x = rect.x;
srcRect.y = rect.y;
srcRect.w = rect.w;
srcRect.h = rect.w;
if (srcRect.x == 0 && srcRect.y == 0 && srcRect.w == 0 && srcRect.h == 0)
SDL_RenderCopy(m_window->getSDLRenderer(), image.getSDLTexture(), nullptr, &texr);
else
{
texr.w = srcRect.w;
texr.h = srcRect.h;
SDL_RenderCopy(m_window->getSDLRenderer(), image.getSDLTexture(), &srcRect, &texr);
}
}
void BasicRenderer2D::drawAnimation(const Animation& anim, const ostd::Vec2& position)
{
if (!m_initialized) return;
if (!anim.hasImage()) return;
const auto& img = anim.getSpriteSheet();
if (!img.isLoaded() || !img.isValid()) return;
drawImage(img, position, anim.getFrameRect());
}
void BasicRenderer2D::drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize)

View file

@ -20,6 +20,7 @@
#pragma once
#include "Animation.hpp"
#include <ogfx/FontUtils.hpp>
#include <ostd/math/Geometry.hpp>
#include <ogfx/Image.hpp>
@ -40,7 +41,8 @@ namespace ogfx
void setFont(const ostd::String& fontFilePath);
void setFontSize(int32_t fontSize);
void drawImage(const ogfx::Image& image, const ostd::Vec2& position);
void drawImage(const ogfx::Image& image, const ostd::Vec2& position, const ostd::Rectangle& rect = { 0, 0, 0, 0 });
void drawAnimation(const Animation& anim, const ostd::Vec2& position);
void drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize = 0);
void drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize = 0);

View file

@ -1,4 +1,5 @@
#include "Image.hpp"
#include "io/Logger.hpp"
#include <SDL2/SDL_render.h>
#include <ogfx/BasicRenderer.hpp>
#include <ogfx/WindowBase.hpp>
@ -16,13 +17,18 @@ namespace ogfx
Image& Image::loadFromFile(const ostd::String& filePath, BasicRenderer2D& gfx)
{
if (!gfx.isInitialized())
return *this; //TODO: Error
m_sdl_texture = IMG_LoadTexture(gfx.getWindow().getSDLRenderer(), filePath.c_str());
SDL_QueryTexture(m_sdl_texture, nullptr, nullptr, &m_width, &m_height);
m_loaded = true;
setTypeName("ogfx::Image");
validate();
return *this;
if (!gfx.isInitialized())
return *this; //TODO: Error
m_sdl_texture = IMG_LoadTexture(gfx.getWindow().getSDLRenderer(), filePath.c_str());
if (!m_sdl_texture)
{
OX_ERROR("Failed to load Image: %s", IMG_GetError());
return *this;
}
SDL_QueryTexture(m_sdl_texture, nullptr, nullptr, &m_width, &m_height);
m_loaded = true;
setTypeName("ogfx::Image");
validate();
return *this;
}
}

61
src/ostd/utils/Async.hpp Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include <thread>
#include <mutex>
#include <atomic>
#include <optional>
namespace ostd
{
template<typename T>
class AsyncJob
{
public:
AsyncJob() = default;
// Start a new job (callable must return T)
template<typename Callable, typename... Args>
void start(Callable&& func, Args&&... args)
{
// Reset state
m_done.store(false);
{
std::lock_guard<std::mutex> lock(m_mutex);
m_result.reset();
}
// Launch detached worker thread
std::thread([this, func = std::forward<Callable>(func), ... args = std::forward<Args>(args)]() mutable {
T value = func(args...);
{
std::lock_guard<std::mutex> lock(m_mutex);
m_result = std::move(value);
}
m_done.store(true);
}).detach();
}
inline bool isReady(void) const { return m_done.load(); }
// Retrieve the result (only valid if is_ready() == true)
inline T get(void)
{
std::lock_guard<std::mutex> lock(m_mutex);
return *m_result;
}
// Retrieve result as optional (safe even if not ready)
std::optional<T> tryGet(void)
{
if (!m_done.load())
return std::nullopt;
std::lock_guard<std::mutex> lock(m_mutex);
return m_result;
}
private:
std::atomic<bool> m_done { false };
std::optional<T> m_result;
mutable std::mutex m_mutex;
};
}

View file

@ -23,6 +23,8 @@
// #include <ostd/Logger.hpp>
// #include <ostd/Console.hpp>
#include "Image.hpp"
#include "utils/Utils.hpp"
#include <ogfx/WindowBase.hpp>
#include <ogfx/RawTextInput.hpp>
#include <ostd/ostd.hpp>
@ -48,6 +50,10 @@ class Window : public ogfx::WindowBase
m_textInput.setEventListener(m_sigHandler);
// m_textInput.setCharacterFilter(m_numCharFilter);
m_textInput.getTheme().extraPaddingTop = 3;
m_testImg.loadFromFile("res/test.png", m_gfx);
out.p("Image loaded: ").p(STR_BOOL(m_testImg.isLoaded())).nl();
out.p(" ").p(m_testImg.getSize().x).nl();
}
inline void handleSignal(ostd::tSignal& signal) override
@ -79,6 +85,7 @@ class Window : public ogfx::WindowBase
inline void onRender(void) override
{
m_textInput.render(m_gfx);
// m_gfx.drawImage(m_testImg, { 0, 0 });´
}
inline void onFixedUpdate(double frameTime_s) override
@ -88,7 +95,7 @@ class Window : public ogfx::WindowBase
inline void onUpdate(void) override
{
m_textInput.update ();
m_textInput.update();
}
private:
@ -96,6 +103,8 @@ class Window : public ogfx::WindowBase
ogfx::BasicRenderer2D m_gfx;
ogfx::gui::RawTextInputEventListener m_sigHandler;
ogfx::gui::RawTextInputNumberCharacterFilter m_numCharFilter;
ogfx::Image m_testImg;
};
// void test2(const std::string& str) {}