Started work on new <ogfx> library

This commit is contained in:
OmniaX-dev 2024-03-29 22:36:16 +01:00
parent 1663e6db7c
commit d7fa13d875
16 changed files with 864 additions and 9 deletions

19
.vscode/settings.json vendored
View file

@ -139,5 +139,22 @@
],
"editor.insertSpaces": false,
"workbench.list.openMode": "doubleClick"
"workbench.list.openMode": "doubleClick",
"files.autoSave": "afterDelay",
"files.autoSaveDelay": 200,
"workbench.activityBar.location": "hidden",
"workbench.editor.openPositioning": "last",
"workbench.editor.tabActionCloseVisibility": false,
"window.density.editorTabHeight": "compact",
"window.zoomLevel": 1,
"explorer.autoReveal": false,
"editor.stickyScroll.enabled": false,
"workbench.statusBar.visible": false,
"breadcrumbs.enabled": false,
"workbench.tree.enableStickyScroll": false,
"cmake.configureOnOpen": false,
"cmake.options.statusBarVisibility": "hidden",
"git.openRepositoryInParentFolders": "never"
}

View file

@ -4,6 +4,7 @@ set(PROJ_NAME omnia-framework)
set(MAJOR_VER 0)
set(MINOR_VER 1)
set(OMNIA_STD_LIB ostd)
set(OMNIA_GFX_LIB ogfx)
set(TEST_TARGET ostd_test)
set(RUN_CONFIG O_F_DEBUG)
#-----------------------------------------------------------------------------------------
@ -26,6 +27,7 @@ message("** Building ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
list(APPEND INCLUDE_DIRS
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/src/ostd
${CMAKE_CURRENT_LIST_DIR}/src/ogfx
${CMAKE_CURRENT_LIST_DIR}/src/ostd/vendor
)
list(APPEND OSTD_SOURCE_FILES
@ -52,6 +54,11 @@ list(APPEND OSTD_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ostd/TextStyleParser.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ostd/Utils.cpp
)
list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/FontUtils.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/WindowBase.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/BasicRenderer.cpp
)
list(APPEND TEST_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/test.cpp
)
@ -60,12 +67,16 @@ list(APPEND TEST_SOURCE_FILES
#Targets
#-----------------------------------------------------------------------------------------
add_library(${OMNIA_STD_LIB} SHARED ${OSTD_SOURCE_FILES})
add_library(${OMNIA_GFX_LIB} SHARED ${OGFX_SOURCE_FILES})
add_executable(${TEST_TARGET} ${TEST_SOURCE_FILES})
target_compile_definitions(${OMNIA_STD_LIB} PUBLIC ${RUN_CONFIG} BUILD_NR=${BUILD_NUMBER} MAJ_V=${MAJOR_VER} MIN_V=${MINOR_VER} VERSION_STR="${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
target_compile_definitions(${OMNIA_GFX_LIB} PUBLIC ${RUN_CONFIG} BUILD_NR=${BUILD_NUMBER} MAJ_V=${MAJOR_VER} MIN_V=${MINOR_VER} VERSION_STR="${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
target_include_directories(${OMNIA_STD_LIB} PUBLIC ${INCLUDE_DIRS})
target_include_directories(${OMNIA_GFX_LIB} PUBLIC ${INCLUDE_DIRS})
target_include_directories(${TEST_TARGET} PUBLIC ${INCLUDE_DIRS})
target_link_libraries(${OMNIA_GFX_LIB} PUBLIC ${OMNIA_STD_LIB})
target_link_libraries(${TEST_TARGET} PUBLIC ${OMNIA_STD_LIB})
#TODO: Different flags for Release/Debug
@ -73,7 +84,9 @@ add_compile_options(-O3 -m32 -MMD -MP -Wall -ggdb -fsanitize=address)
if (UNIX)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")
target_link_libraries(${OMNIA_STD_LIB} PUBLIC tinfo boost_regex)
target_link_libraries(${OMNIA_GFX_LIB} PUBLIC xcb xcb-randr)
endif (UNIX)
target_link_libraries(${OMNIA_GFX_LIB} PUBLIC SDL2main SDL2 SDL2_gfx SDL2_ttf)
#-----------------------------------------------------------------------------------------
#Finalize
@ -84,5 +97,5 @@ add_custom_command(TARGET ${OMNIA_STD_LIB} POST_BUILD
VERBATIM
)
add_custom_target(FinalMessage ALL ${CMAKE_COMMAND} -E cmake_echo_color --cyan "[100%] Built ${PROJ_NAME} ${MAJOR_VER}.${MINOR_VER}.${BUILD_NUMBER}")
add_dependencies(FinalMessage ${OMNIA_STD_LIB})
add_dependencies(FinalMessage ${OMNIA_GFX_LIB})
#-----------------------------------------------------------------------------------------

View file

@ -12,7 +12,8 @@ download MSYS2 from https://www.msys2.org/ and install it
run MSYS2, and in the terminal run:
```
pacman -Syuu
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-gdb mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-make mingw-w64-ucrt-x86_64-boost
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-clang mingw-w64-ucrt-x86_64-gdb mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-make mingw-w64-ucrt-x86_64-boost mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-SDL2_image mingw-w64-ucrt-x86_64-SDL2_ttf
```
```
**Step 3:**
@ -28,7 +29,7 @@ execute this command:
open a terminal and run:
```
sudo pacman -Syuu
sudo pacman -S --needed base-devel clang gdb cmake make boost
sudo pacman -S --needed base-devel clang gdb cmake make boost sdl2 sdl2_mixer sdl2_image sdl2_ttf
```
**Step 2:**
@ -41,7 +42,7 @@ open a terminal inside the root directory of the project and run this command:
open a terminal and run:
```
sudo apt update && sudo apt upgrade
sudo apt install clang gdb make cmake libboost-all-dev
sudo apt install clang gdb make cmake libboost-all-dev libsdl2-dev libsdl2-mixer-dev libsdl2-image-dev libsdl2-ttf-dev libxcb-randr0-dev
```
**Step 2:**

View file

@ -1 +1 @@
1824
1850

View file

@ -12,9 +12,12 @@ if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
mkdir -p ./Release/lib
cp ./bin/libostd.so ./Release/lib
cp ./bin/libogfx.so ./Release/lib
mkdir -p ./Release/include/ostd/vendor
mkdir -p ./Release/include/ogfx/
find ./src/ostd -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ostd \;
find ./src/ogfx -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ogfx \;
find ./src/ostd/vendor -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ostd/vendor \;
cp -r ./licences ./Release
@ -37,9 +40,15 @@ elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
cp C:/msys64/ucrt64/bin/libgcc_s_seh-1.dll ./Release/lib
cp C:/msys64/ucrt64/bin/libstdc++-6.dll ./Release/lib
cp C:/msys64/ucrt64/bin/libwinpthread-1.dll ./Release/lib
cp C:/msys64/ucrt64/bin/SDL2.dll ./Release/lib
cp C:/msys64/ucrt64/bin/SDL2_image.dll ./Release/lib
cp C:/msys64/ucrt64/bin/SDL2_ttf.dll ./Release/lib
cp C:/msys64/ucrt64/bin/SDL2_gfx.dll ./Release/lib
mkdir -p ./Release/include/ostd/vendor
mkdir -p ./Release/include/ogfx/
find ./src/ostd -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ostd \;
find ./src/ogfx -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ogfx \;
find ./src/ostd/vendor -maxdepth 1 -name "*.hpp" -exec cp {} ./Release/include/ostd/vendor \;
cp -r ./licences ./Release

137
src/ogfx/BasicRenderer.cpp Normal file
View file

@ -0,0 +1,137 @@
#include "BasicRenderer.hpp"
#include "WindowBase.hpp"
#include <SDL2/SDL2_gfxPrimitives.h>
namespace ogfx
{
void BasicRenderer2D::init(WindowBase& window)
{
m_window = &window;
m_ttfr.init(window.getSDLRenderer());
m_initialized = true;
}
void BasicRenderer2D::setFont(const ostd::String& fontFilePath)
{
if (!m_initialized) return;
m_ttfr.openFont(fontFilePath, m_ttfr.getFontSize());
}
void BasicRenderer2D::setFontSize(int32_t fontSize)
{
if (!m_initialized) return;
m_ttfr.setFontSize(fontSize);
}
void BasicRenderer2D::drawString(const ostd::String& str, const ostd::Vec2& position, const ostd::Color& color, int32_t fontSize)
{
if (!m_initialized) return;
if (!m_ttfr.isValid()) return;
m_ttfr.renderText(str, (int32_t)std::round(position.x), (int32_t)std::round(position.y), color, fontSize);
}
void BasicRenderer2D::drawCenteredString(const ostd::String& str, const ostd::Vec2& center, const ostd::Color& color, int32_t fontSize)
{
if (!m_initialized) return;
if (!m_ttfr.isValid()) return;
m_ttfr.renderCenteredText(str, (int32_t)std::round(center.x), (int32_t)std::round(center.y), color, fontSize);
}
void BasicRenderer2D::drawLine(const ostd::FLine& line, const ostd::Color& color, int32_t thickness)
{
if (!m_initialized) return;
thickLineRGBA(m_window->getSDLRenderer(), (int32_t)std::round(line.p1.x), (int32_t)std::round(line.p1.y), (int32_t)std::round(line.p2.x), (int32_t)std::round(line.p2.y), thickness, color.r, color.g, color.b, color.a);
}
void BasicRenderer2D::drawRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t thickness)
{
if (!m_initialized) return;
float x1 = rect.x;
float y1 = rect.y;
float x2 = rect.x + rect.w;
float y2 = rect.y + rect.h;
if (thickness == 1)
rectangleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1), (int32_t)std::round(y1), (int32_t)std::round(x2), (int32_t)std::round(y2), color.r, color.g, color.b, color.a);
else if (thickness > 1)
{
for (int32_t i = 0; i < thickness; i++)
rectangleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1 + i), (int32_t)std::round(y1 + i), (int32_t)std::round(x2 - i), (int32_t)std::round(y2 - i), color.r, color.g, color.b, color.a);
}
}
void BasicRenderer2D::drawRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t radius, int32_t thickness)
{
if (!m_initialized) return;
float x1 = rect.x;
float y1 = rect.y;
float x2 = rect.x + rect.w;
float y2 = rect.y + rect.h;
if (thickness == 1)
roundedRectangleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1), (int32_t)std::round(y1), (int32_t)std::round(x2), (int32_t)std::round(y2), radius, color.r, color.g, color.b, color.a);
else if (thickness > 1)
{
for (int32_t i = 0; i < thickness; i++)
roundedRectangleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1 + i), (int32_t)std::round(y1 + i), (int32_t)std::round(x2 - i), (int32_t)std::round(y2 - i), radius, color.r, color.g, color.b, color.a);
}
}
void BasicRenderer2D::drawCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& color, int32_t thickness)
{
if (!m_initialized) return;
if (thickness == 1)
circleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(center.x), (int32_t)std::round(center.y), radius, color.r, color.g, color.b, color.a);
else if (thickness > 1)
{
for (int32_t i = 0; i < thickness; i++)
circleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(center.x), (int32_t)std::round(center.y), radius - i, color.r, color.g, color.b, color.a);
}
}
void BasicRenderer2D::fillRect(const ostd::Rectangle& rect, const ostd::Color& color)
{
if (!m_initialized) return;
float x1 = rect.x;
float y1 = rect.y;
float x2 = rect.x + rect.w;
float y2 = rect.y + rect.h;
boxRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1), (int32_t)std::round(y1), (int32_t)std::round(x2), (int32_t)std::round(y2), color.r, color.g, color.b, color.a);
}
void BasicRenderer2D::fillRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t radius)
{
if (!m_initialized) return;
float x1 = rect.x;
float y1 = rect.y;
float x2 = rect.x + rect.w;
float y2 = rect.y + rect.h;
roundedBoxRGBA(m_window->getSDLRenderer(), (int32_t)std::round(x1), (int32_t)std::round(y1), (int32_t)std::round(x2), (int32_t)std::round(y2), radius, color.r, color.g, color.b, color.a);
}
void BasicRenderer2D::fillCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& color)
{
if (!m_initialized) return;
filledCircleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(center.x), (int32_t)std::round(center.y), radius, color.r, color.g, color.b, color.a);
}
void BasicRenderer2D::outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness)
{
if (!m_initialized) return;
fillRect(rect, fillColor);
drawRect(rect, outlineColor, outlineThickness);
}
void BasicRenderer2D::outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness)
{
if (!m_initialized) return;
fillRoundRect(rect, fillColor, radius);
drawRoundRect(rect, outlineColor, radius, outlineThickness);
}
void BasicRenderer2D::outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness)
{
if (!m_initialized) return;
fillCircle(center, radius, fillColor);
drawCircle(center, radius, outlineColor, outlineThickness);
}
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <ogfx/FontUtils.hpp>
#include <ostd/Geometry.hpp>
namespace ogfx
{
class WindowBase;
class BasicRenderer2D
{
public:
BasicRenderer2D(void) = default;
void init(WindowBase& window);
inline TTFRenderer& getTTFRenderer(void) { return m_ttfr; }
inline ostd::IPoint getStringSize(const ostd::String str, int32_t fontSize = 0) { return m_ttfr.getStringDimensions(str, fontSize); }
inline WindowBase& getWindow(void) { return *m_window; }
inline bool isInitialized(void) { return m_initialized; }
void setFont(const ostd::String& fontFilePath);
void setFontSize(int32_t fontSize);
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);
void drawLine(const ostd::FLine& line, const ostd::Color& color, int32_t thickness = 1);
void drawRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t thickness = 1);
void drawRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t radius, int32_t thickness = 1);
void drawCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& color, int32_t thickness = 1);
void fillRect(const ostd::Rectangle& rect, const ostd::Color& color);
void fillRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t radius);
void fillCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& color);
void outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1);
void outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness = 1);
void outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1);
private:
TTFRenderer m_ttfr;
WindowBase* m_window { nullptr };
bool m_initialized { false };
};
}

218
src/ogfx/FontUtils.cpp Normal file
View file

@ -0,0 +1,218 @@
#include "FontUtils.hpp"
namespace ogfx
{
TTFRenderer::~TTFRenderer(void)
{
closeFont();
}
void TTFRenderer::renderText(const ostd::String& message, int32_t x, int32_t y, const ostd::Color& color, int32_t fontSize)
{
if (!TTFRenderer::m_initialized)
{
set_error_state(tErrors::Uninitialized);
return;
}
if (!m_fontOpen)
{
set_error_state(tErrors::NoFont);
return;
}
if (m_renderer == nullptr)
{
set_error_state(tErrors::NullRenderer);
return;
}
if (m_font == nullptr)
{
set_error_state(tErrors::NullFont);
return;
}
setFontSize(fontSize);
SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), { color.r, color.g, color.b, color.a });
if (surf == nullptr)
{
set_error_state(tErrors::TTFRenderTextBlendedFail);
print_ttf_error("TTF_RenderText_Blended");
return;
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surf);
if (texture == nullptr)
{
set_error_state(tErrors::TTFCreateTextureFromSurfaceFail);
print_ttf_error("SDL_CreateTextureFromSurface");
return;
}
SDL_FreeSurface(surf);
int32_t w = 0, h = 0;
SDL_QueryTexture(texture, NULL, NULL, &w, &h);
SDL_Rect dst;
dst.x = x;
dst.y = y;
dst.w = w;
dst.h = h;
SDL_RenderCopy(m_renderer, texture, NULL, &dst);
SDL_DestroyTexture(texture);
}
void TTFRenderer::renderCenteredText(const ostd::String& message, int32_t center_x, int32_t center_y, const ostd::Color& color, int32_t fontSize)
{
if (!TTFRenderer::m_initialized)
{
set_error_state(tErrors::Uninitialized);
return;
}
if (!m_fontOpen)
{
set_error_state(tErrors::NoFont);
return;
}
if (m_renderer == nullptr)
{
set_error_state(tErrors::NullRenderer);
return;
}
if (m_font == nullptr)
{
set_error_state(tErrors::NullFont);
return;
}
setFontSize(fontSize);
SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), { color.r, color.g, color.b, color.a });
if (surf == nullptr)
{
set_error_state(tErrors::TTFRenderTextBlendedFail);
print_ttf_error("TTF_RenderText_Blended");
return;
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surf);
if (texture == nullptr)
{
set_error_state(tErrors::TTFCreateTextureFromSurfaceFail);
print_ttf_error("SDL_CreateTextureFromSurface");
return;
}
SDL_FreeSurface(surf);
int32_t w = 0, h = 0;
SDL_QueryTexture(texture, NULL, NULL, &w, &h);
SDL_Rect dst;
dst.x = center_x - (w / 2);
dst.y = center_y - (h / 2);
dst.w = w;
dst.h = h;
SDL_RenderCopy(m_renderer, texture, NULL, &dst);
SDL_DestroyTexture(texture);
}
ostd::IPoint TTFRenderer::getStringDimensions(const ostd::String& message, int32_t fontSize)
{
if (!TTFRenderer::m_initialized)
{
set_error_state(tErrors::Uninitialized);
return { 0, 0 };
}
if (!m_fontOpen)
{
set_error_state(tErrors::NoFont);
return { 0, 0 };
}
if (m_renderer == nullptr)
{
set_error_state(tErrors::NullRenderer);
return { 0, 0 };
}
if (m_font == nullptr)
{
set_error_state(tErrors::NullFont);
return { 0, 0 };
}
setFontSize(fontSize);
SDL_Surface* surf = TTF_RenderText_Blended(m_font, message.c_str(), { 0, 0, 0, 255 });
if (surf == nullptr)
{
set_error_state(tErrors::TTFRenderTextBlendedFail);
print_ttf_error("TTF_RenderText_Blended");
return { 0, 0 };
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surf);
if (texture == nullptr)
{
set_error_state(tErrors::TTFCreateTextureFromSurfaceFail);
print_ttf_error("SDL_CreateTextureFromSurface");
return { 0, 0 };
}
SDL_FreeSurface(surf);
int32_t w = 0, h = 0;
SDL_QueryTexture(texture, NULL, NULL, &w, &h);
SDL_DestroyTexture(texture);
return { w, h };
}
int32_t TTFRenderer::init(SDL_Renderer* renderer)
{
if (TTFRenderer::m_initialized) return set_error_state(tErrors::NoError);
if (renderer == nullptr) return set_error_state(tErrors::NullRenderer);
if (TTF_Init() != 0)
{
print_ttf_error("TTF_Init");
SDL_Quit();
return set_error_state(tErrors::FailedToLoad);
}
m_renderer = renderer;
TTFRenderer::m_initialized = true;
return set_error_state(tErrors::NoError);
}
void TTFRenderer::closeFont(void)
{
if (!TTFRenderer::m_initialized || !m_fontOpen) return;
if (m_font != nullptr)
TTF_CloseFont(m_font);
m_font = nullptr;
m_fontOpen = false;
m_fontSize = DefaultFontSize;
set_error_state(tErrors::NoError);
}
int32_t TTFRenderer::openFont(const ostd::String& fontPath, int32_t fontSize)
{
if (!TTFRenderer::m_initialized) return set_error_state(tErrors::Uninitialized);
if (m_fontOpen) closeFont();
if (fontSize <= 0)
fontSize = m_fontSize;
else
m_fontSize = fontSize;
m_font = TTF_OpenFont(fontPath.c_str(), fontSize);
if (m_font == nullptr)
{
print_ttf_error("TTF_OpenFont");
return set_error_state(tErrors::FailedToOpenFontFile);
}
m_fontOpen = true;
return set_error_state(tErrors::NoError);
}
int32_t TTFRenderer::setFontSize(int32_t fontSize)
{
if (!TTFRenderer::m_initialized)
return set_error_state(tErrors::Uninitialized);
if (!m_fontOpen)
return set_error_state(tErrors::NoFont);
if (m_font == nullptr)
return set_error_state(tErrors::NullFont);
if (fontSize == m_fontSize || fontSize <= 0) return set_error_state(tErrors::NoError);
TTF_SetFontSize(m_font, fontSize);
return set_error_state(tErrors::NoError);
}
void TTFRenderer::print_ttf_error(const ostd::String& funcName)
{
m_out.fg(ostd::ConsoleColors::Red).p(funcName).p("(...) failed: ").p(ostd::String(TTF_GetError())).reset().nl();
}
}

57
src/ogfx/FontUtils.hpp Normal file
View file

@ -0,0 +1,57 @@
#pragma once
#include <ogfx/SDLInclude.hpp>
#include <ostd/Signals.hpp>
#include <ostd/IOHandlers.hpp>
namespace ogfx
{
class TTFRenderer
{
public: struct tErrors
{
inline static constexpr int32_t NoError = 0;
inline static constexpr int32_t FailedToLoad = 1;
inline static constexpr int32_t FailedToOpenFontFile = 2;
inline static constexpr int32_t Uninitialized = 3;
inline static constexpr int32_t NullRenderer = 4;
inline static constexpr int32_t InvalidState = 5;
inline static constexpr int32_t TTFRenderTextBlendedFail = 6;
inline static constexpr int32_t TTFCreateTextureFromSurfaceFail = 7;
inline static constexpr int32_t NullFont = 8;
inline static constexpr int32_t NoFont = 9;
};
public:
TTFRenderer(void) = default;
~TTFRenderer(void);
inline TTFRenderer(SDL_Renderer* renderer) { init(renderer); }
int32_t init(SDL_Renderer* renderer);
void closeFont(void);
int32_t openFont(const ostd::String& fontPath, int32_t fontSize = 0);
int32_t setFontSize(int32_t fontSize);
void renderText(const ostd::String& message, int32_t x, int32_t y, const ostd::Color& color, int32_t fontSize = 0);
void renderCenteredText(const ostd::String& message, int32_t center_x, int32_t center_y, const ostd::Color& color, int32_t fontSize = 0);
ostd::IPoint getStringDimensions(const ostd::String& message, int32_t fontSize = 0);
inline bool isInitialized(void) { return TTFRenderer::m_initialized; }
inline bool hasOpenFont(void) { return m_fontOpen; }
inline TTF_Font* getSDLFont(void) { return m_font; }
inline bool isValid(void) { return TTFRenderer::m_initialized && m_fontOpen && m_font != nullptr && m_renderer != nullptr; }
inline int32_t geterrorState(void) { return m_errorState; }
inline int32_t getFontSize(void) { return m_fontSize; }
private:
void print_ttf_error(const ostd::String& funcName);
inline int32_t set_error_state(int32_t err) { m_errorState = err; return m_errorState; }
private:
ostd::ConsoleOutputHandler m_out;
inline static bool m_initialized { false };
bool m_fontOpen { false };
TTF_Font* m_font { nullptr };
SDL_Renderer* m_renderer { nullptr };
int32_t m_errorState { tErrors::NoError };
int32_t m_fontSize { DefaultFontSize };
inline static constexpr int32_t DefaultFontSize { 16 };
};
}

9
src/ogfx/SDLInclude.hpp Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#ifdef _WIN32
#undef __linux__
#endif
#include <SDL2/SDL.h>
#include <SDL2/SDL2_gfxPrimitives.h>
#include <SDL2/SDL_ttf.h>

169
src/ogfx/WindowBase.cpp Normal file
View file

@ -0,0 +1,169 @@
#include "WindowBase.hpp"
namespace ogfx
{
WindowBase::~WindowBase(void)
{
onDestroy();
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
// IMG_Quit();
SDL_Quit();
TTF_Quit();
}
void WindowBase::initialize(int32_t width, int32_t height, const ostd::String& windowTitle)
{
if (m_initialized) return;
m_windowWidth = width;
m_windowHeight = height;
m_title = windowTitle;
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
exit(1);
}
// int imgFlags = IMG_INIT_PNG;
// if (!(IMG_Init(imgFlags) & imgFlags))
// {
// printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
// exit(2);
// }
m_window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_windowWidth, m_windowHeight, SDL_WINDOW_RESIZABLE);
SDL_SetWindowResizable(m_window, SDL_FALSE);
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetWindowMinimumSize(m_window, m_windowWidth, m_windowHeight);
SDL_SetWindowTitle(m_window, m_title.c_str());
m_initialized = true;
m_running = true;
setTypeName("dragon::WindowBase");
enableSignals(true);
validate();
onInitialize();
}
void WindowBase::update(void)
{
if (!m_initialized) return;
Uint64 start = SDL_GetPerformanceCounter();
handleEvents();
SDL_SetRenderDrawColor(m_renderer, m_clearColor.r, m_clearColor.g, m_clearColor.b, m_clearColor.a);
if (m_refreshScreen)
SDL_RenderClear(m_renderer);
onUpdate();
onRender();
SDL_RenderPresent(m_renderer);
Uint64 end = SDL_GetPerformanceCounter();
float elapsed = (end - start) / (float)SDL_GetPerformanceFrequency();
m_redrawAccumulator += elapsed;
if (m_redrawAccumulator >= 0.2f)
{
onFixedUpdate();
m_redrawAccumulator = 0.0f;
}
end = SDL_GetPerformanceCounter();
elapsed = (end - start) / (float)SDL_GetPerformanceFrequency();
m_timeAccumulator += elapsed;
if (m_timeAccumulator >= 0.5f)
{
onSlowUpdate();
m_fps = (int32_t)(1.0f / elapsed);
m_timeAccumulator = 0.0f;
}
}
void WindowBase::setSize(int32_t width, int32_t height)
{
if (!isInitialized()) return;
SDL_SetWindowSize(m_window, width, height);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowResized, ostd::tSignalPriority::RealTime);
}
void WindowBase::setTitle(const ostd::String& title)
{
if (!isInitialized()) return;
m_title = title;
SDL_SetWindowTitle(m_window, m_title.c_str());
}
void WindowBase::handleEvents(void)
{
if (!m_initialized) return;
auto l_getMouseState = [this](void) -> MouseEventData {
int32_t mx = 0, my = 0;
uint32_t btn = SDL_GetMouseState(&mx, &my);
MouseEventData::eButton button = MouseEventData::eButton::None;
switch (btn)
{
case SDL_BUTTON(1): button = MouseEventData::eButton::Left; break;
case SDL_BUTTON(2): button = MouseEventData::eButton::Middle; break;
case SDL_BUTTON(3): button = MouseEventData::eButton::Right; break;
default: button = MouseEventData::eButton::None; break;
}
MouseEventData mmd(*this, mx, my, button);
return mmd;
};
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
m_running = false;
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowClosed, ostd::tSignalPriority::Normal, *this);
}
else if (event.type == SDL_WINDOWEVENT)
{
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
WindowResizedData wrd(*this, m_windowWidth, m_windowHeight, 0, 0);
SDL_GetWindowSize(m_window, &m_windowWidth, &m_windowHeight);
wrd.new_width = m_windowWidth;
wrd.new_height = m_windowHeight;
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowResized, ostd::tSignalPriority::RealTime, wrd);
}
}
else if (event.type == SDL_MOUSEMOTION)
{
MouseEventData mmd = l_getMouseState();
if (isMouseDragEventEnabled() && mmd.button != MouseEventData::eButton::None)
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::WindowClosed, ostd::tSignalPriority::RealTime, mmd);
else
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseMoved, ostd::tSignalPriority::RealTime, mmd);
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
MouseEventData mmd = l_getMouseState();
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MousePressed, ostd::tSignalPriority::RealTime, mmd);
}
else if (event.type == SDL_MOUSEBUTTONUP)
{
MouseEventData mmd = l_getMouseState();
switch (event.button.button)
{
case SDL_BUTTON(1): mmd.button = MouseEventData::eButton::Left; break;
case SDL_BUTTON(2): mmd.button = MouseEventData::eButton::Middle; break;
case SDL_BUTTON(3): mmd.button = MouseEventData::eButton::Right; break;
default: mmd.button = MouseEventData::eButton::None; break;
}
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::MouseReleased, ostd::tSignalPriority::RealTime, mmd);
}
else if (event.type == SDL_KEYDOWN)
{
KeyEventData ked(*this, (int32_t)event.key.keysym.sym, 0, KeyEventData::eKeyEvent::Pressed);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::KeyPressed, ostd::tSignalPriority::RealTime, ked);
}
else if (event.type == SDL_KEYUP)
{
KeyEventData ked(*this, (int32_t)event.key.keysym.sym, 0, KeyEventData::eKeyEvent::Released);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::KeyReleased, ostd::tSignalPriority::RealTime, ked);
}
else if (event.type == SDL_TEXTINPUT)
{
KeyEventData ked(*this, 0, event.text.text[0], KeyEventData::eKeyEvent::Text);
ostd::SignalHandler::emitSignal(ostd::tBuiltinSignals::TextEntered, ostd::tSignalPriority::RealTime, ked);
}
}
}
}

115
src/ogfx/WindowBase.hpp Normal file
View file

@ -0,0 +1,115 @@
#pragma once
#include <ogfx/SDLInclude.hpp>
#include <ostd/Signals.hpp>
#include <ostd/IOHandlers.hpp>
namespace ogfx
{
class WindowBase : public ostd::BaseObject
{
public:
inline WindowBase(void) { }
~WindowBase(void);
inline WindowBase(int32_t width, int32_t height, const ostd::String& windowTitle) { initialize(width, height, windowTitle); }
void initialize(int32_t width, int32_t height, const ostd::String& windowTitle);
void update(void);
void setSize(int32_t width, int32_t height);
void setTitle(const ostd::String& title);
inline virtual void onRender(void) { }
inline virtual void onUpdate(void) { }
inline virtual void onFixedUpdate(void) { }
inline virtual void onSlowUpdate(void) { }
inline virtual void onInitialize(void) { }
inline virtual void onDestroy(void) { }
inline bool isInitialized(void) const { return m_initialized; }
inline bool isRunning(void) const { return m_running; }
inline void hide(void) { SDL_HideWindow(m_window); }
inline void show(void) { SDL_ShowWindow(m_window); }
inline ostd::String getTitle(void) const { return m_title; }
inline int32_t getFPS(void) const { return m_fps; }
inline int32_t getWindowWidth(void) const { return m_windowWidth; }
inline int32_t getWindowHeight(void) const { return m_windowHeight; }
inline SDL_Renderer* getSDLRenderer(void) const { return m_renderer; }
inline bool isMouseDragEventEnabled(void) const { return m_deagEventEnabled; }
inline void enableMouseDragEvent(bool enable = true) { m_deagEventEnabled = enable; }
inline ostd::Color getClearColor(void) const { return m_clearColor; }
inline void setClearColor(const ostd::Color& color) { m_clearColor = color; }
private:
void handleEvents(void);
protected:
ostd::ConsoleOutputHandler out;
SDL_Window* m_window { nullptr };
SDL_Renderer* m_renderer { nullptr };
bool m_refreshScreen { true };
private:
int32_t m_windowWidth { 0 };
int32_t m_windowHeight { 0 };
ostd::String m_title { "" };
int32_t m_fps { 0 };
ostd::Color m_clearColor { 10, 10, 10, 255 };
float m_timeAccumulator { 0.0f };
float m_redrawAccumulator { 0.0f };
bool m_deagEventEnabled { false };
bool m_running { false };
bool m_initialized { false };
};
class WindowResizedData : public ostd::BaseObject
{
public:
inline WindowResizedData(WindowBase& parent, int32_t _oldx, int32_t _oldy, int32_t _newx, int32_t _newy) : parentWindow(parent), old_width(_oldx), old_height(_oldy), new_width(_newx), new_height(_newy)
{
setTypeName("ogfx::WindowResizedData");
validate();
}
public:
int32_t new_width;
int32_t new_height;
int32_t old_width;
int32_t old_height;
WindowBase& parentWindow;
};
class MouseEventData : public ostd::BaseObject
{
public: enum class eButton { None = 0, Left, Middle, Right };
public:
inline MouseEventData(WindowBase& parent, int32_t mousex, int32_t mousey, eButton btn) : parentWindow(parent), position_x(mousex), position_y(mousey), button(btn)
{
setTypeName("ogfx::MouseEventData");
validate();
}
public:
int32_t position_x;
int32_t position_y;
eButton button;
WindowBase& parentWindow;
};
class KeyEventData : public ostd::BaseObject
{
public: enum class eKeyEvent { Pressed = 0, Released, Text };
public:
inline KeyEventData(WindowBase& parent, int32_t key, char _text, eKeyEvent evt) : parentWindow(parent), keyCode(key), text(_text), eventType(evt)
{
setTypeName("ogfx::KeyEventData");
validate();
}
public:
int32_t keyCode;
char text;
eKeyEvent eventType;
WindowBase& parentWindow;
};
}

View file

@ -353,6 +353,56 @@ namespace ostd
float w;
float h;
};
template<class T>
class Rect
{
public:
Rect(void) = default;
inline Rect(T pos_x, T pos_y, T size_x, T size_y) : position(pos_x, pos_y), size(size_x, size_y) { }
inline Rect(Point<T> pos, Point<T> _size) : position(pos), size(_size) { }
template <class T2> inline Rect(Rect<T2> copy) { position = { (T2)(copy.position.x), (T2)(copy.position.y) }; size = { (T2)(copy.size.x), (T2)(copy.size.y) }; }
public:
Point<T> position;
Point<T> size;
};
typedef Rect<float> FRect;
typedef Rect<double> DRect;
typedef Rect<uint32_t> UIRect;
typedef Rect<uint64_t> UI64Rect;
typedef Rect<float> UI16Rect;
typedef Rect<uint8_t> UI8Rect;
typedef Rect<int32_t> IRect;
typedef Rect<int64_t> I64Rect;
typedef Rect<int16_t> I16Rect;
typedef Rect<int8_t> I8Rect;
template<class T>
class Line
{
public:
Line(void) = default;
inline Line(T x1, T y1, T x2, T y2) : p1(x1, y1), p2(x2, y2) { }
inline Line(Point<T> _p1, Point<T> _p2) : p1(_p1), p2(_p2) { }
template <class T2> inline Line(Line<T2> copy) { p1 = { (T2)(copy.p1.x), (T2)(copy.p1.y) }; p2 = { (T2)(copy.p2.x), (T2)(copy.p2.y) }; }
public:
Point<T> p1;
Point<T> p2;
};
typedef Line<float> FLine;
typedef Line<double> DLine;
typedef Line<uint32_t> UILine;
typedef Line<uint64_t> UI64Line;
typedef Line<float> UI16Line;
typedef Line<uint8_t> UI8Line;
typedef Line<int32_t> ILine;
typedef Line<int64_t> I64Line;
typedef Line<int16_t> I16Line;
typedef Line<int8_t> I8Line;
}
#endif

View file

@ -42,7 +42,7 @@ namespace ostd
m_sw = nullptr;
m_ne = nullptr;
m_se = nullptr;
setTypeName("ox::QuadTree");
setTypeName("ostd::QuadTree");
setValid(true);
}

View file

@ -240,7 +240,10 @@ namespace ostd
String& String::add(float f, uint8_t precision)
{
std::stringstream stream;
if (precision != 0)
stream << std::fixed << std::setprecision(precision) << f;
else
stream << f;
cpp_string s = stream.str();
return add(s);
}
@ -248,7 +251,10 @@ namespace ostd
String& String::add(double f, uint8_t precision)
{
std::stringstream stream;
if (precision != 0)
stream << std::fixed << std::setprecision(precision) << f;
else
stream << f;
cpp_string s = stream.str();
return add(s);
}

View file

@ -2,14 +2,24 @@
if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
sudo rm -r /usr/include/ostd
sudo rm -r /usr/include/ogfx
sudo rm -r /usr/lib/libostd.so
sudo rm -r /usr/lib/libogfx.so
sudo cp -r ./Release/include/ostd /usr/include/
sudo cp -r ./Release/include/ogfx /usr/include/
sudo cp -r ./Release/lib/libostd.so /usr/lib/
sudo cp -r ./Release/lib/libogfx.so /usr/lib/
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
rm -r C:/msys64/ucrt64/include/ostd
rm -r C:/msys64/ucrt64/include/ogfx
rm -r C:/msys64/ucrt64/bin/libostd.dll
rm -r C:/msys64/ucrt64/lib/libostd.dll.a
rm -r C:/msys64/ucrt64/bin/libogfx.dll
rm -r C:/msys64/ucrt64/lib/libogfx.dll.a
cp -r ./Release/include/ostd C:/msys64/ucrt64/include/
cp -r ./Release/include/ogfx C:/msys64/ucrt64/include/
cp -r ./Release/lib/libostd.dll C:/msys64/ucrt64/bin/
cp -r ./Release/lib/libostd.dll.a C:/msys64/ucrt64/lib/
cp -r ./Release/lib/libogfx.dll C:/msys64/ucrt64/bin/
cp -r ./Release/lib/libogfx.dll.a C:/msys64/ucrt64/lib/
fi