From bd63f83f8134e89eeed932562e113b118c2c380c Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 7 Aug 2022 16:26:04 +0200 Subject: [PATCH 01/17] Before using templates --- src/drawtext.cpp | 197 ++++++++++++++++++++++++----------------------- src/drawtext.h | 154 ++++++++++++++++++------------------ src/main.cpp | 26 ++++--- 3 files changed, 192 insertions(+), 185 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 2a813a4..8598c9d 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -5,131 +5,134 @@ #include #include -DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor) +DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, int initialCharacter, int finalCharacter) : + initialCharacter_{ initialCharacter }, finalCharacter_{ finalCharacter }, totalCharacters_{ static_cast(finalCharacter_ - initialCharacter_) }, + alphabet{ new SDL_Surface * [totalCharacters_] } { - TTF_Font* font = TTF_OpenFont(fontPath, fontSize); - if (!font) { - std::stringstream message; - message << "DrawText::DrawText: " << TTF_GetError(); - throw std::runtime_error(message.str()); - } - createAlphabet(font, fontColor); - TTF_CloseFont(font); + if (totalCharacters_ <= 0) { + throw std::logic_error("The final character must be bigger than the initial character."); + } + + TTF_Font* font = TTF_OpenFont(fontPath, fontSize); + if (!font) { + std::stringstream message; + message << "DrawText::DrawText: " << TTF_GetError(); + throw std::runtime_error(message.str()); + } + createAlphabet(font, fontColor); + TTF_CloseFont(font); } DrawText::~DrawText() { - for (auto& i : alphabet) { - SDL_FreeSurface(i); - } + delete alphabet; } void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { - for (Uint16 c = INITIAL_CHARACTER; c <= FINAL_CHARACTER; c++) { - alphabet[c - INITIAL_CHARACTER] = TTF_RenderGlyph_Blended(font, c, fontColor); - } + for (auto c = initialCharacter_; c < finalCharacter_; c++) { + alphabet[c - initialCharacter_] = TTF_RenderGlyph_Blended(font, c, fontColor); + } } void DrawText::drawGlyph(SDL_Surface* destinationSurface, const unsigned char character, int& x, - int& y) + int& y) { - if (character == '\n') { - SDL_Surface* glyph = alphabet[0]; - y = y + glyph->h; - newLine = true; - return; - } - - unsigned char i = character - INITIAL_CHARACTER; - SDL_Surface* glyph = alphabet[i]; - - SDL_Rect dst_rect; - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = glyph->w; - dst_rect.h = glyph->h; - - x = x + glyph->w; - SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); + if (character == '\n') { + SDL_Surface* glyph = alphabet[0]; + y = y + glyph->h; + newLine_ = true; + return; + } + + auto i = static_cast(character - initialCharacter_); + if (i >= totalCharacters_) { + throw std::logic_error("Trying to access a glyph outside of the limits"); + } + SDL_Surface* glyph = alphabet[i]; + + SDL_Rect dst_rect; + dst_rect.x = x; + dst_rect.y = y; + dst_rect.w = glyph->w; + dst_rect.h = glyph->h; + + x = x + glyph->w; + SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } -void DrawText::print(SDL_Surface* destinationSurface, const std::string& text, int x, int y) +void DrawText::drawGlyphW(SDL_Surface* destinationSurface, const wchar_t character, int& x, int& y) { - auto tmp_x = x; - auto tmp_y = y; - - for (const char* c = text.c_str(); *c != '\0'; c++) { - if (newLine) { - tmp_x = x; - newLine = false; - } - drawGlyph(destinationSurface, *c, tmp_x, tmp_y); - } + if (character == '\n') { + SDL_Surface* glyph = alphabet[0]; + y = y + glyph->h; + newLine_ = true; + return; + } + auto i = static_cast(character - initialCharacter_); + if (i >= totalCharacters_) { + throw std::logic_error("Trying to access a glyph outside of the limits"); + } + SDL_Surface* glyph = alphabet[i]; + + SDL_Rect dst_rect; + dst_rect.x = x; + dst_rect.y = y; + dst_rect.w = glyph->w; + dst_rect.h = glyph->h; + + x = x + glyph->w; + SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } -void DrawText::drawGlyphW(SDL_Surface* destinationSurface, const wchar_t character, int& x, int& y) +void DrawText::print(SDL_Surface* destinationSurface, const std::string& text, int x, int y) { - if (character == '\n') { - SDL_Surface* glyph = alphabet[0]; - y = y + glyph->h; - newLine = true; - return; - } - unsigned char i = (unsigned char)character - INITIAL_CHARACTER; - if (i >= FINAL_CHARACTER) { - return; - } - SDL_Surface* glyph = alphabet[i]; - - SDL_Rect dst_rect; - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = glyph->w; - dst_rect.h = glyph->h; - - x = x + glyph->w; - SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); + auto tmp_x = x; + auto tmp_y = y; + + for (const char* c = text.c_str(); *c != '\0'; c++) { + if (newLine_) { + tmp_x = x; + newLine_ = false; + } + drawGlyph(destinationSurface, *c, tmp_x, tmp_y); + } } void DrawText::print(SDL_Surface* destinationSurface, const std::wstring& text, int x, int y) { - auto tmp_x = x; - auto tmp_y = y; - - for (auto character = text.c_str(); *character != '\0'; character++) { - if (newLine) { - tmp_x = x; - newLine = false; - } - drawGlyphW(destinationSurface, *character, tmp_x, tmp_y); - } + auto tmp_x = x; + auto tmp_y = y; + + for (auto character = text.c_str(); *character != '\0'; character++) { + if (newLine_) { + tmp_x = x; + newLine_ = false; + } + drawGlyphW(destinationSurface, *character, tmp_x, tmp_y); + } } std::string DrawText::format(const std::string text, ...) { - std::string a; - - char buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; - a = buffer; - return a; + char buffer[BUFFER_SIZE] = {}; + { + va_list list; + va_start(list, text); + vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); + va_end(list); + }; + + return { buffer }; } std::wstring DrawText::format(const std::wstring text, ...) { - std::wstring out; - wchar_t buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; - out = buffer; - return out; + wchar_t buffer[BUFFER_SIZE] = {}; + { + va_list list; + va_start(list, text); + vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); + va_end(list); + }; + return { buffer }; } \ No newline at end of file diff --git a/src/drawtext.h b/src/drawtext.h index cb10028..5b703a7 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -3,98 +3,98 @@ #include #include + #include +#include class DrawText { public: - /** - * @brief Defines the properties of the text to draw on the screen. - * @param fontPath Path to the TTF file to be used. - * @param fontSize Size of the font to write on screen. - * @param fontColor Color of the text to write. - */ - DrawText(const char *fontPath, int fontSize, const SDL_Color &fontColor); + /** + * @brief Defines the properties of the text to draw on the screen. + * @param fontPath Path to the TTF file to be used. + * @param fontSize Size of the font to write on screen. + * @param fontColor Color of the text to write. + */ + DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, int initialCharacter = 32, int finalCharacter = 255); - /** - * @brief Destroys the alphabet and free memory. - */ - ~DrawText(); + /** + * @brief Destroys the alphabet and free memory. + */ + ~DrawText(); - /** - * @brief Print text on a given surface - * @param destinationSurface Surface where the text will be written. - * @param text Text to write on the screen. - * @param x Horizontal position of the text. - * @param y Vertical position of the text. - * @param ... Optional variables for the special characters in the string. - */ - void print(SDL_Surface *destinationSurface, const std::string& text, int x, int y); + /** + * @brief Print text on a given surface + * @param destinationSurface Surface where the text will be written. + * @param text Text to write on the screen. + * @param x Horizontal position of the text. + * @param y Vertical position of the text. + * @param ... Optional variables for the special characters in the string. + */ + void print(SDL_Surface* destinationSurface, const std::string& text, int x, int y); - /** - * @brief Print text on a given surface - * @param destinationSurface Surface where the text will be written. - * @param text Unicode text to write on the screen. - * @param x Horizontal position of the text. - * @param y Vertical position of the text. - */ - void print(SDL_Surface *destinationSurface, const std::wstring& text, int x, int y); + /** + * @brief Print text on a given surface + * @param destinationSurface Surface where the text will be written. + * @param text Unicode text to write on the screen. + * @param x Horizontal position of the text. + * @param y Vertical position of the text. + */ + void print(SDL_Surface* destinationSurface, const std::wstring& text, int x, int y); - /** - * @brief Formats a string - * @param text The text or format specifier to convert - * @param ... Extra parameters to replace by the format specifier - * @return Resulting string after applying the format specifier - */ - static std::string format(const std::string text, ...); + /** + * @brief Formats a string + * @param text The text or format specifier to convert + * @param ... Extra parameters to replace by the format specifier + * @return Resulting string after applying the format specifier + */ + static std::string format(const std::string text, ...); - /** - * @brief Formats a string - * @param text The text or format specifier to convert - * @param ... Extra parameters to replace by the format specifier - * @return Resulting string after applying the format specifier - */ - static std::wstring format(const std::wstring string, ...); + /** + * @brief Formats a string + * @param text The text or format specifier to convert + * @param ... Extra parameters to replace by the format specifier + * @return Resulting string after applying the format specifier + */ + static std::wstring format(const std::wstring string, ...); private: - /** - * @brief Creates the glyphs that composes the alphabet. - * @param font Pointer to the TTF_Font that contains a valid font. - * @param fontColor Color for the glyphs. - */ - void createAlphabet(TTF_Font *font, const SDL_Color &fontColor); - - /** - * @brief Draw a glyph on the screen - * @param destinationSurface Surface where the character will be written. - * @param character Character to write on the screen. - * @param x Horizontal position for the glyph. - * @param y Vertical position for the glyph. - */ - void drawGlyph(SDL_Surface *destinationSurface, unsigned char character, - int &x, int &y); - /** - * @brief Draw a glyph on the screen - * @param destinationSurface Surface where the character will be written. - * @param character Unicode character to write on the screen. - * @param x Horizontal position for the glyph. - * @param y Vertical position for the glyph. - */ - void drawGlyphW(SDL_Surface *destinationSurface, wchar_t character, int &x, - int &y); + static constexpr size_t BUFFER_SIZE = 255; + /** + * @brief Creates the glyphs that composes the alphabet. + * @param font Pointer to the TTF_Font that contains a valid font. + * @param fontColor Color for the glyphs. + */ + void createAlphabet(TTF_Font* font, const SDL_Color& fontColor); - /// @brief Maximum size for the buffer for the message on screen. - static constexpr int BUFFER_SIZE = 256; + /** + * @brief Draw a glyph on the screen + * @param destinationSurface Surface where the character will be written. + * @param character Character to write on the screen. + * @param x Horizontal position for the glyph. + * @param y Vertical position for the glyph. + */ + void drawGlyph(SDL_Surface* destinationSurface, unsigned char character, + int& x, int& y); + /** + * @brief Draw a glyph on the screen + * @param destinationSurface Surface where the character will be written. + * @param character Unicode character to write on the screen. + * @param x Horizontal position for the glyph. + * @param y Vertical position for the glyph. + */ + void drawGlyphW(SDL_Surface* destinationSurface, wchar_t character, int& x, + int& y); - /// @brief Initial character for the glyph alphabet. - static constexpr int INITIAL_CHARACTER = 32; - /// @brief Final character for the glyph alphabet. - static constexpr int FINAL_CHARACTER = 255; + /// Initial character for the alphabet. + int initialCharacter_; + /// Final character for the alphabet. + int finalCharacter_; + /// Total number of characters in alphabet. + size_t totalCharacters_; - ///@brief Total number of characters in the glyph alphabet. - static constexpr int TOTAL_CHARACTERS = FINAL_CHARACTER - INITIAL_CHARACTER; + SDL_Surface** alphabet; - SDL_Surface *alphabet[TOTAL_CHARACTERS]{}; - bool newLine{false}; + bool newLine_{ false }; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 7a45d82..b14ddc9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,17 @@ +#include "drawtext.h" + #include #include -#include -#include "drawtext.h" +#include +#include SDL_Renderer* renderer; SDL_Window* window; SDL_Surface* screen; SDL_Texture* texture; -int init() +void init() { static constexpr int WINDOW_WIDTH = 800; static constexpr int WINDOW_HEIGHT = 600; @@ -19,14 +21,16 @@ int init() window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN); if (window == NULL) { - std::cout << "Could not create window: " << SDL_GetError() << std::endl; - return -1; + std::stringstream out; + out << "Can't create window: " << SDL_GetError(); + throw std::runtime_error(out.str()); } renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { - std::cout << "Renderer could not be created! SDL Error: " << SDL_GetError() << std::endl; - return -1; + std::stringstream out; + out << "Can't create render: " << SDL_GetError(); + throw std::runtime_error(out.str()); } #if SDL_BYTEORDER == SDL_BIG_ENDIAN @@ -38,10 +42,10 @@ int init() texture = SDL_CreateTextureFromSurface(renderer, screen); if (TTF_Init() < 0) { - std::cout << "Can't init TTF: " << SDL_GetError() << std::endl; - return -1; + std::stringstream out; + out << "Can't init TTF: " << SDL_GetError(); + throw std::runtime_error(out.str()); } - return 0; } void updateScreen() @@ -56,7 +60,7 @@ void mainLoop() static constexpr unsigned int MINIMUM_FRAME_TIME = 10; SDL_Event event; - bool quit = false; + auto quit = false; unsigned int initialTime = 0; while (!quit) { From 8a8ab793d2e1834fb0ff462564a8e64ec4167881 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 7 Aug 2022 16:33:40 +0200 Subject: [PATCH 02/17] lfs support --- .gitattributes | 1 + build/fonts/OfenbacherSchwabCAT.ttf | Bin 87336 -> 130 bytes 2 files changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e4c28ea --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.ttf filter=lfs diff=lfs merge=lfs -text diff --git a/build/fonts/OfenbacherSchwabCAT.ttf b/build/fonts/OfenbacherSchwabCAT.ttf index 759611107affab668c249f42e88b79fa5e87eba3..25ce53b1956856b7ce0f08a6ff56f88a5fbe189f 100644 GIT binary patch literal 130 zcmWN|xe>!45CFhjRnUONd%&q1o|9q5HX0vN;OebtqrK?MeSAcl^WaU&XP=MP&g*SE z^IFDR@iZw;7F<2-{E6_0mYC}G_tbKLKsT7I@g;ap@4iEqn OT5A^WKN5Gee)$8)s3x!g literal 87336 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

!%i3PU}j_U2Q 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 From 26d19ebd4260a7f5daa1253679463a7fa42bd835 Mon Sep 17 00:00:00 2001 From: Sam Date: Sun, 7 Aug 2022 22:57:38 +0200 Subject: [PATCH 03/17] WIP --- src/drawtext.cpp | 61 +++------------------------------------------- src/drawtext.h | 63 ++++++++++++++++++++++++++---------------------- src/main.cpp | 6 ++--- 3 files changed, 41 insertions(+), 89 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 8598c9d..0cfecf2 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -31,12 +31,11 @@ DrawText::~DrawText() void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { for (auto c = initialCharacter_; c < finalCharacter_; c++) { - alphabet[c - initialCharacter_] = TTF_RenderGlyph_Blended(font, c, fontColor); + alphabet[c - initialCharacter_] = TTF_RenderGlyph_Blended(font, static_cast(c), fontColor); } } -void DrawText::drawGlyph(SDL_Surface* destinationSurface, const unsigned char character, int& x, - int& y) +void DrawText::drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y) { if (character == '\n') { SDL_Surface* glyph = alphabet[0]; @@ -44,9 +43,8 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, const unsigned char ch newLine_ = true; return; } - - auto i = static_cast(character - initialCharacter_); - if (i >= totalCharacters_) { + auto i = character - static_cast(initialCharacter_); + if (i >= totalCharacters_) { throw std::logic_error("Trying to access a glyph outside of the limits"); } SDL_Surface* glyph = alphabet[i]; @@ -61,57 +59,6 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, const unsigned char ch SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } -void DrawText::drawGlyphW(SDL_Surface* destinationSurface, const wchar_t character, int& x, int& y) -{ - if (character == '\n') { - SDL_Surface* glyph = alphabet[0]; - y = y + glyph->h; - newLine_ = true; - return; - } - auto i = static_cast(character - initialCharacter_); - if (i >= totalCharacters_) { - throw std::logic_error("Trying to access a glyph outside of the limits"); - } - SDL_Surface* glyph = alphabet[i]; - - SDL_Rect dst_rect; - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = glyph->w; - dst_rect.h = glyph->h; - - x = x + glyph->w; - SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); -} - -void DrawText::print(SDL_Surface* destinationSurface, const std::string& text, int x, int y) -{ - auto tmp_x = x; - auto tmp_y = y; - - for (const char* c = text.c_str(); *c != '\0'; c++) { - if (newLine_) { - tmp_x = x; - newLine_ = false; - } - drawGlyph(destinationSurface, *c, tmp_x, tmp_y); - } -} - -void DrawText::print(SDL_Surface* destinationSurface, const std::wstring& text, int x, int y) -{ - auto tmp_x = x; - auto tmp_y = y; - - for (auto character = text.c_str(); *character != '\0'; character++) { - if (newLine_) { - tmp_x = x; - newLine_ = false; - } - drawGlyphW(destinationSurface, *character, tmp_x, tmp_y); - } -} std::string DrawText::format(const std::string text, ...) { char buffer[BUFFER_SIZE] = {}; diff --git a/src/drawtext.h b/src/drawtext.h index 5b703a7..f6b3fbf 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -6,6 +6,7 @@ #include #include +#include class DrawText { public: @@ -20,26 +21,40 @@ class DrawText { /** * @brief Destroys the alphabet and free memory. */ - ~DrawText(); + virtual ~DrawText(); - /** - * @brief Print text on a given surface - * @param destinationSurface Surface where the text will be written. - * @param text Text to write on the screen. - * @param x Horizontal position of the text. - * @param y Vertical position of the text. - * @param ... Optional variables for the special characters in the string. - */ - void print(SDL_Surface* destinationSurface, const std::string& text, int x, int y); + /** + * @brief Print text on a given surface + * @param destinationSurface Surface where the text will be written. + * @param text Unicode text to write on the screen. + * @param x Horizontal position of the text. + * @param y Vertical position of the text. + */ + template + void print(SDL_Surface* destinationSurface, T const & text, int x, int y) + { + auto tmp_x = x; + auto tmp_y = y; - /** - * @brief Print text on a given surface - * @param destinationSurface Surface where the text will be written. - * @param text Unicode text to write on the screen. - * @param x Horizontal position of the text. - * @param y Vertical position of the text. - */ - void print(SDL_Surface* destinationSurface, const std::wstring& text, int x, int y); + auto process_elements = [&](auto temp_string) ->void { + for (auto& c : temp_string) { + if (newLine_) { + tmp_x = x; + newLine_ = false; + } + drawGlyphW(destinationSurface, static_cast(c), tmp_x, tmp_y); + } + }; + + if constexpr (std::is_convertible_v) { + std::string t = text; + process_elements(t); + } + else if constexpr (std::is_convertible_v) { + std::wstring t = text; + process_elements(t); + } + } /** * @brief Formats a string @@ -65,15 +80,6 @@ class DrawText { */ void createAlphabet(TTF_Font* font, const SDL_Color& fontColor); - /** - * @brief Draw a glyph on the screen - * @param destinationSurface Surface where the character will be written. - * @param character Character to write on the screen. - * @param x Horizontal position for the glyph. - * @param y Vertical position for the glyph. - */ - void drawGlyph(SDL_Surface* destinationSurface, unsigned char character, - int& x, int& y); /** * @brief Draw a glyph on the screen * @param destinationSurface Surface where the character will be written. @@ -81,10 +87,9 @@ class DrawText { * @param x Horizontal position for the glyph. * @param y Vertical position for the glyph. */ - void drawGlyphW(SDL_Surface* destinationSurface, wchar_t character, int& x, + void drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y); - /// Initial character for the alphabet. int initialCharacter_; /// Final character for the alphabet. diff --git a/src/main.cpp b/src/main.cpp index b14ddc9..c33c566 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -96,10 +96,10 @@ int main(int argc, char* argv[]) SDL_Color white = { 255, 255, 255, 0 }; SDL_Color red = { 255, 0, 0, 0 }; - auto* text = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 25, white); - auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); + auto* text = new DrawText("fonts/times.ttf", 25, white); + auto* redText = new DrawText("fonts/times.ttf", 20, red); - // Print some text + text->print(screen, L"Uicode string:\nEn un lugar de la Mancha," "de cuyo nombre no quiero acordarme,\nno ha mucho tiempo" "que vivía un hidalgo de los de lanza en astillero," From c8dad938882cf6049582f6e63adeec438148e940 Mon Sep 17 00:00:00 2001 From: Samuel Salinas Date: Wed, 10 Aug 2022 21:31:15 +0200 Subject: [PATCH 04/17] Tested under Linux --- .clang-format | 7 ++ .idea/.gitignore | 8 ++ .idea/SDL_DrawText.iml | 2 + .idea/misc.xml | 4 + .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ CMakeLists.txt | 2 +- src/drawtext.cpp | 107 ++++++++++++++------------- src/drawtext.h | 164 ++++++++++++++++++++--------------------- src/main.cpp | 157 ++++++++++++++++++++------------------- 10 files changed, 252 insertions(+), 213 deletions(-) create mode 100644 .clang-format create mode 100644 .idea/.gitignore create mode 100644 .idea/SDL_DrawText.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..06f8ea8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +BasedOnStyle: Microsoft +UseTab: Never +IndentWidth: 4 +AllowShortFunctionsOnASingleLine: InlineOnly +ColumnLimit: 100 +BreakBeforeBraces: Linux +PointerAlignment: Left \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/SDL_DrawText.iml b/.idea/SDL_DrawText.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/SDL_DrawText.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a310a14 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f8c222..846d61e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(BIN_DIR ${test_SOURCE_DIR}/bin) # Bump up warning levels appropriately for clang, gcc & msvc and build in debug mode if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -std=c++14") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2") elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 0cfecf2..9d2277f 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -5,81 +5,84 @@ #include #include -DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, int initialCharacter, int finalCharacter) : - initialCharacter_{ initialCharacter }, finalCharacter_{ finalCharacter }, totalCharacters_{ static_cast(finalCharacter_ - initialCharacter_) }, - alphabet{ new SDL_Surface * [totalCharacters_] } +DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, + int initialCharacter, int finalCharacter) + : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, + totalCharacters_{static_cast(finalCharacter_ - initialCharacter_)}, + alphabet{new SDL_Surface*[totalCharacters_]} { - if (totalCharacters_ <= 0) { - throw std::logic_error("The final character must be bigger than the initial character."); - } + if (totalCharacters_ <= 0) { + throw std::logic_error("The final character must be bigger than the initial character."); + } - TTF_Font* font = TTF_OpenFont(fontPath, fontSize); - if (!font) { - std::stringstream message; - message << "DrawText::DrawText: " << TTF_GetError(); - throw std::runtime_error(message.str()); - } - createAlphabet(font, fontColor); - TTF_CloseFont(font); + TTF_Font* font = TTF_OpenFont(fontPath, fontSize); + if (!font) { + std::stringstream message; + message << "DrawText::DrawText: " << TTF_GetError(); + throw std::runtime_error(message.str()); + } + createAlphabet(font, fontColor); + TTF_CloseFont(font); } DrawText::~DrawText() { - delete alphabet; + delete[] alphabet; } void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { - for (auto c = initialCharacter_; c < finalCharacter_; c++) { - alphabet[c - initialCharacter_] = TTF_RenderGlyph_Blended(font, static_cast(c), fontColor); - } + for (auto c = initialCharacter_; c < finalCharacter_; c++) { + alphabet[c - initialCharacter_] = + TTF_RenderGlyph_Blended(font, static_cast(c), fontColor); + } } void DrawText::drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y) { - if (character == '\n') { - SDL_Surface* glyph = alphabet[0]; - y = y + glyph->h; - newLine_ = true; - return; - } - auto i = character - static_cast(initialCharacter_); - if (i >= totalCharacters_) { - throw std::logic_error("Trying to access a glyph outside of the limits"); - } - SDL_Surface* glyph = alphabet[i]; + if (character == '\n') { + SDL_Surface* glyph = alphabet[0]; + y = y + glyph->h; + newLine_ = true; + return; + } + auto i = character - static_cast(initialCharacter_); + if (i >= totalCharacters_) { + throw std::logic_error("Trying to access a glyph outside of the limits"); + } + SDL_Surface* glyph = alphabet[i]; - SDL_Rect dst_rect; - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = glyph->w; - dst_rect.h = glyph->h; + SDL_Rect dst_rect; + dst_rect.x = x; + dst_rect.y = y; + dst_rect.w = glyph->w; + dst_rect.h = glyph->h; - x = x + glyph->w; - SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); + x = x + glyph->w; + SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } std::string DrawText::format(const std::string text, ...) { - char buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; + char buffer[BUFFER_SIZE] = {}; + { + va_list list; + va_start(list, text); + vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); + va_end(list); + }; - return { buffer }; + return {buffer}; } std::wstring DrawText::format(const std::wstring text, ...) { - wchar_t buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; - return { buffer }; + wchar_t buffer[BUFFER_SIZE] = {}; + { + va_list list; + va_start(list, text); + vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); + va_end(list); + }; + return {buffer}; } \ No newline at end of file diff --git a/src/drawtext.h b/src/drawtext.h index f6b3fbf..577d71b 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -4,102 +4,100 @@ #include #include -#include #include +#include #include -class DrawText { -public: - /** - * @brief Defines the properties of the text to draw on the screen. - * @param fontPath Path to the TTF file to be used. - * @param fontSize Size of the font to write on screen. - * @param fontColor Color of the text to write. - */ - DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, int initialCharacter = 32, int finalCharacter = 255); +class DrawText +{ + public: + /** + * @brief Defines the properties of the text to draw on the screen. + * @param fontPath Path to the TTF file to be used. + * @param fontSize Size of the font to write on screen. + * @param fontColor Color of the text to write. + */ + DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, + int initialCharacter = 32, int finalCharacter = 255); + + /** + * @brief Destroys the alphabet and free memory. + */ + virtual ~DrawText(); - /** - * @brief Destroys the alphabet and free memory. - */ - virtual ~DrawText(); + /** + * @brief Print text on a given surface + * @param destinationSurface Surface where the text will be written. + * @param text Unicode text to write on the screen. + * @param x Horizontal position of the text. + * @param y Vertical position of the text. + */ + template void print(SDL_Surface* destinationSurface, T const& text, int x, int y) + { + auto tmp_x = x; + auto tmp_y = y; - /** - * @brief Print text on a given surface - * @param destinationSurface Surface where the text will be written. - * @param text Unicode text to write on the screen. - * @param x Horizontal position of the text. - * @param y Vertical position of the text. - */ - template - void print(SDL_Surface* destinationSurface, T const & text, int x, int y) - { - auto tmp_x = x; - auto tmp_y = y; + auto process_elements = [&](auto& temp_string) -> void { + for (auto c = std::begin(temp_string); *c != '\0'; c++) { + if (newLine_) { + tmp_x = x; + newLine_ = false; + } + drawGlyphW(destinationSurface, static_cast(*c), tmp_x, tmp_y); + } + }; - auto process_elements = [&](auto temp_string) ->void { - for (auto& c : temp_string) { - if (newLine_) { - tmp_x = x; - newLine_ = false; - } - drawGlyphW(destinationSurface, static_cast(c), tmp_x, tmp_y); - } - }; + if (std::is_convertible()) { + process_elements(text); + } else if (std::is_convertible()) { + process_elements(text); + } + } - if constexpr (std::is_convertible_v) { - std::string t = text; - process_elements(t); - } - else if constexpr (std::is_convertible_v) { - std::wstring t = text; - process_elements(t); - } - } + /** + * @brief Formats a string + * @param text The text or format specifier to convert + * @param ... Extra parameters to replace by the format specifier + * @return Resulting string after applying the format specifier + */ + static std::string format(const std::string text, ...); - /** - * @brief Formats a string - * @param text The text or format specifier to convert - * @param ... Extra parameters to replace by the format specifier - * @return Resulting string after applying the format specifier - */ - static std::string format(const std::string text, ...); + /** + * @brief Formats a string + * @param text The text or format specifier to convert + * @param ... Extra parameters to replace by the format specifier + * @return Resulting string after applying the format specifier + */ + static std::wstring format(const std::wstring string, ...); - /** - * @brief Formats a string - * @param text The text or format specifier to convert - * @param ... Extra parameters to replace by the format specifier - * @return Resulting string after applying the format specifier - */ - static std::wstring format(const std::wstring string, ...); -private: - static constexpr size_t BUFFER_SIZE = 255; - /** - * @brief Creates the glyphs that composes the alphabet. - * @param font Pointer to the TTF_Font that contains a valid font. - * @param fontColor Color for the glyphs. - */ - void createAlphabet(TTF_Font* font, const SDL_Color& fontColor); + private: + static constexpr size_t BUFFER_SIZE = 255; + /** + * @brief Creates the glyphs that composes the alphabet. + * @param font Pointer to the TTF_Font that contains a valid font. + * @param fontColor Color for the glyphs. + */ + void createAlphabet(TTF_Font* font, const SDL_Color& fontColor); - /** - * @brief Draw a glyph on the screen - * @param destinationSurface Surface where the character will be written. - * @param character Unicode character to write on the screen. - * @param x Horizontal position for the glyph. - * @param y Vertical position for the glyph. - */ - void drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, - int& y); + /** + * @brief Draw a glyph on the screen + * @param destinationSurface Surface where the character will be written. + * @param character Unicode character to write on the screen. + * @param x Horizontal position for the glyph. + * @param y Vertical position for the glyph. + */ + void drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y); - /// Initial character for the alphabet. - int initialCharacter_; - /// Final character for the alphabet. - int finalCharacter_; - /// Total number of characters in alphabet. - size_t totalCharacters_; + /// Initial character for the alphabet. + int initialCharacter_; + /// Final character for the alphabet. + int finalCharacter_; + /// Total number of characters in alphabet. + size_t totalCharacters_; - SDL_Surface** alphabet; + SDL_Surface** alphabet; - bool newLine_{ false }; + bool newLine_{false}; }; #endif diff --git a/src/main.cpp b/src/main.cpp index c33c566..effe02b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,110 +13,113 @@ SDL_Texture* texture; void init() { - static constexpr int WINDOW_WIDTH = 800; - static constexpr int WINDOW_HEIGHT = 600; - static constexpr int WINDOW_BPP = 32; - - SDL_Init(SDL_INIT_VIDEO); - - window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN); - if (window == NULL) { - std::stringstream out; - out << "Can't create window: " << SDL_GetError(); - throw std::runtime_error(out.str()); - } - - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - if (renderer == NULL) { - std::stringstream out; - out << "Can't create render: " << SDL_GetError(); - throw std::runtime_error(out.str()); - } + static constexpr int WINDOW_WIDTH = 800; + static constexpr int WINDOW_HEIGHT = 600; + static constexpr int WINDOW_BPP = 32; + + SDL_Init(SDL_INIT_VIDEO); + + window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, + 600, SDL_WINDOW_SHOWN); + if (window == NULL) { + std::stringstream out; + out << "Can't create window: " << SDL_GetError(); + throw std::runtime_error(out.str()); + } + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (renderer == NULL) { + std::stringstream out; + out << "Can't create render: " << SDL_GetError(); + throw std::runtime_error(out.str()); + } #if SDL_BYTEORDER == SDL_BIG_ENDIAN - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff); #else - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0xff000000); #endif - texture = SDL_CreateTextureFromSurface(renderer, screen); + texture = SDL_CreateTextureFromSurface(renderer, screen); - if (TTF_Init() < 0) { - std::stringstream out; - out << "Can't init TTF: " << SDL_GetError(); - throw std::runtime_error(out.str()); - } + if (TTF_Init() < 0) { + std::stringstream out; + out << "Can't init TTF: " << SDL_GetError(); + throw std::runtime_error(out.str()); + } } void updateScreen() { - SDL_UpdateTexture(texture, NULL, screen->pixels, screen->pitch); - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); + SDL_UpdateTexture(texture, NULL, screen->pixels, screen->pitch); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); } void mainLoop() { - static constexpr unsigned int MINIMUM_FRAME_TIME = 10; - - SDL_Event event; - auto quit = false; - unsigned int initialTime = 0; - - while (!quit) { - SDL_PollEvent(&event); - if (event.type == SDL_QUIT) { - quit = true; - } - - initialTime = SDL_GetTicks(); - updateScreen(); - - auto delta_time = SDL_GetTicks() - initialTime; - if (delta_time < MINIMUM_FRAME_TIME) { - SDL_Delay(MINIMUM_FRAME_TIME - delta_time); - } - } + static constexpr unsigned int MINIMUM_FRAME_TIME = 10; + + SDL_Event event; + auto quit = false; + unsigned int initialTime = 0; + + while (!quit) { + SDL_PollEvent(&event); + if (event.type == SDL_QUIT) { + quit = true; + } + + initialTime = SDL_GetTicks(); + updateScreen(); + + auto delta_time = SDL_GetTicks() - initialTime; + if (delta_time < MINIMUM_FRAME_TIME) { + SDL_Delay(MINIMUM_FRAME_TIME - delta_time); + } + } } void quit() { - SDL_FreeSurface(screen); - SDL_DestroyTexture(texture); - SDL_DestroyWindow(window); - TTF_Quit(); - SDL_Quit(); + SDL_FreeSurface(screen); + SDL_DestroyTexture(texture); + SDL_DestroyWindow(window); + TTF_Quit(); + SDL_Quit(); } int main(int argc, char* argv[]) { - init(); + init(); - // Init DrawText object - SDL_Color white = { 255, 255, 255, 0 }; - SDL_Color red = { 255, 0, 0, 0 }; + // Init DrawText object + SDL_Color white = {255, 255, 255, 0}; + SDL_Color red = {255, 0, 0, 0}; - auto* text = new DrawText("fonts/times.ttf", 25, white); - auto* redText = new DrawText("fonts/times.ttf", 20, red); + auto* text = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 25, white); + auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); - - text->print(screen, L"Uicode string:\nEn un lugar de la Mancha," - "de cuyo nombre no quiero acordarme,\nno ha mucho tiempo" - "que vivía un hidalgo de los de lanza en astillero," - "\nadarga antigua, rocín flaco y galgo corredor.", - 10, 50); + text->print(screen, + L"Unicode string:\nEn un lugar de la Mancha,\n" + "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", + 10, 50); - text->print(screen, - "Non-uicode string:\nEn un lugar de la Mancha," - "de cuyo nombre no quiero acordarme,\nno ha mucho tiempo" - "que vivía un hidalgo de los de lanza en astillero," - "\nadarga antigua, rocín flaco y galgo corredor.", - 10, 200); + text->print(screen, + "Non-unicode string:\nEn un lugar de la Mancha,\n" + "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", + 10, 200); - redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); + redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); - mainLoop(); + mainLoop(); - quit(); - return 0; + quit(); + return 0; } From 0efb40a86a5b5d2462cbac9811a7166f0f1f249c Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 10 Aug 2022 22:58:31 +0200 Subject: [PATCH 05/17] works in Windows --- src/drawtext.h | 2 +- src/main.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/drawtext.h b/src/drawtext.h index 577d71b..b0c7376 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -38,7 +38,7 @@ class DrawText auto tmp_y = y; auto process_elements = [&](auto& temp_string) -> void { - for (auto c = std::begin(temp_string); *c != '\0'; c++) { + for (auto c = std::begin(temp_string); c != std::end(temp_string) && *c != '\0'; c++) { if (newLine_) { tmp_x = x; newLine_ = false; diff --git a/src/main.cpp b/src/main.cpp index effe02b..3f1ba9c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,8 +19,8 @@ void init() SDL_Init(SDL_INIT_VIDEO); - window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, - 600, SDL_WINDOW_SHOWN); + window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN); if (window == NULL) { std::stringstream out; out << "Can't create window: " << SDL_GetError(); @@ -103,14 +103,14 @@ int main(int argc, char* argv[]) auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); text->print(screen, - L"Unicode string:\nEn un lugar de la Mancha,\n" + L"Unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" "que vivía un hidalgo de los de lanza en astillero,\n" "adarga antigua, rocín flaco y galgo corredor.", 10, 50); text->print(screen, - "Non-unicode string:\nEn un lugar de la Mancha,\n" + "Non-unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" "que vivía un hidalgo de los de lanza en astillero,\n" "adarga antigua, rocín flaco y galgo corredor.", From ebcd663643e72e2794c4811b84cdfd1c48a313ed Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 12 Aug 2022 21:51:39 +0200 Subject: [PATCH 06/17] cleans code --- src/drawtext.cpp | 17 ++++++----------- src/drawtext.h | 8 +++----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 9d2277f..a2398aa 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -9,7 +9,7 @@ DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fo int initialCharacter, int finalCharacter) : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, totalCharacters_{static_cast(finalCharacter_ - initialCharacter_)}, - alphabet{new SDL_Surface*[totalCharacters_]} + alphabet_{new SDL_Surface*[totalCharacters_]} { if (totalCharacters_ <= 0) { throw std::logic_error("The final character must be bigger than the initial character."); @@ -27,13 +27,13 @@ DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fo DrawText::~DrawText() { - delete[] alphabet; + delete[] alphabet_; } void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { for (auto c = initialCharacter_; c < finalCharacter_; c++) { - alphabet[c - initialCharacter_] = + alphabet_[c - initialCharacter_] = TTF_RenderGlyph_Blended(font, static_cast(c), fontColor); } } @@ -41,7 +41,7 @@ void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) void DrawText::drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y) { if (character == '\n') { - SDL_Surface* glyph = alphabet[0]; + SDL_Surface* glyph = alphabet_[0]; y = y + glyph->h; newLine_ = true; return; @@ -50,13 +50,8 @@ void DrawText::drawGlyphW(SDL_Surface* destinationSurface, unsigned char charact if (i >= totalCharacters_) { throw std::logic_error("Trying to access a glyph outside of the limits"); } - SDL_Surface* glyph = alphabet[i]; - - SDL_Rect dst_rect; - dst_rect.x = x; - dst_rect.y = y; - dst_rect.w = glyph->w; - dst_rect.h = glyph->h; + auto* glyph = alphabet_[i]; + SDL_Rect dst_rect = {x, y, glyph->w, glyph->h}; x = x + glyph->w; SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); diff --git a/src/drawtext.h b/src/drawtext.h index b0c7376..0dea495 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -34,10 +33,9 @@ class DrawText */ template void print(SDL_Surface* destinationSurface, T const& text, int x, int y) { - auto tmp_x = x; - auto tmp_y = y; - auto process_elements = [&](auto& temp_string) -> void { + auto tmp_x = x; + auto tmp_y = y; for (auto c = std::begin(temp_string); c != std::end(temp_string) && *c != '\0'; c++) { if (newLine_) { tmp_x = x; @@ -95,7 +93,7 @@ class DrawText /// Total number of characters in alphabet. size_t totalCharacters_; - SDL_Surface** alphabet; + SDL_Surface** alphabet_; bool newLine_{false}; }; From f3d6de2b60861ead7b32743e289125ecf5d0c414 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Aug 2022 12:54:12 +0200 Subject: [PATCH 07/17] characters as uint16_t --- src/drawtext.cpp | 15 +++++++++------ src/drawtext.h | 10 +++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index a2398aa..328f280 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -6,7 +6,7 @@ #include DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, - int initialCharacter, int finalCharacter) + uint16_t initialCharacter, uint16_t finalCharacter) : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, totalCharacters_{static_cast(finalCharacter_ - initialCharacter_)}, alphabet_{new SDL_Surface*[totalCharacters_]} @@ -33,20 +33,23 @@ DrawText::~DrawText() void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { for (auto c = initialCharacter_; c < finalCharacter_; c++) { - alphabet_[c - initialCharacter_] = - TTF_RenderGlyph_Blended(font, static_cast(c), fontColor); + auto glyph = TTF_RenderGlyph_Blended(font, c, fontColor); + if (glyph == NULL) { + throw std::runtime_error("Error creating alphabet"); + } + alphabet_[c - initialCharacter_] = glyph; } } -void DrawText::drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y) +void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y) { if (character == '\n') { - SDL_Surface* glyph = alphabet_[0]; + auto* glyph = alphabet_[0]; y = y + glyph->h; newLine_ = true; return; } - auto i = character - static_cast(initialCharacter_); + auto i = character - initialCharacter_; if (i >= totalCharacters_) { throw std::logic_error("Trying to access a glyph outside of the limits"); } diff --git a/src/drawtext.h b/src/drawtext.h index 0dea495..e34647d 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -17,7 +17,7 @@ class DrawText * @param fontColor Color of the text to write. */ DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, - int initialCharacter = 32, int finalCharacter = 255); + uint16_t initialCharacter = 32, uint16_t finalCharacter = 255); /** * @brief Destroys the alphabet and free memory. @@ -41,7 +41,7 @@ class DrawText tmp_x = x; newLine_ = false; } - drawGlyphW(destinationSurface, static_cast(*c), tmp_x, tmp_y); + drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); } }; @@ -84,12 +84,12 @@ class DrawText * @param x Horizontal position for the glyph. * @param y Vertical position for the glyph. */ - void drawGlyphW(SDL_Surface* destinationSurface, unsigned char character, int& x, int& y); + void drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y); /// Initial character for the alphabet. - int initialCharacter_; + uint16_t initialCharacter_; /// Final character for the alphabet. - int finalCharacter_; + uint16_t finalCharacter_; /// Total number of characters in alphabet. size_t totalCharacters_; From 41ddfe6b98a61b67c48d025824c196ffca8a8587 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Aug 2022 17:15:12 +0200 Subject: [PATCH 08/17] changes file encoding to ansi --- src/main.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3f1ba9c..66e4756 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,9 +93,10 @@ void quit() int main(int argc, char* argv[]) { + init(); - // Init DrawText object + //// Init DrawText object SDL_Color white = {255, 255, 255, 0}; SDL_Color red = {255, 0, 0, 0}; @@ -103,23 +104,24 @@ int main(int argc, char* argv[]) auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); text->print(screen, - L"Unicode string\nEn un lugar de la Mancha,\n" + L"Non-unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", 10, 50); text->print(screen, - "Non-unicode string\nEn un lugar de la Mancha,\n" + L"Non-unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", 10, 200); redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); mainLoop(); - quit(); + // quit(); + return 0; } From ab4ac14a5b31b5dd5c8b0c1c426b8dbaa6f25e5c Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Aug 2022 18:18:13 +0200 Subject: [PATCH 09/17] unicode --- src/main.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 66e4756..0bedaa0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,7 +93,6 @@ void quit() int main(int argc, char* argv[]) { - init(); //// Init DrawText object @@ -104,17 +103,17 @@ int main(int argc, char* argv[]) auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); text->print(screen, - L"Non-unicode string\nEn un lugar de la Mancha,\n" + L"Unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + "que viv�a un hidalgo de los de lanza en astillero,\n" + "adarga antigua, roc�n flaco y galgo corredor.", 10, 50); text->print(screen, L"Non-unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + "que viv�a un hidalgo de los de lanza en astillero,\n" + "adarga antigua, roc�n flaco y galgo corredor.", 10, 200); redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); From 3bf7b8aa1e26c755541b7a4e6524ad9381c92f4d Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 15 Aug 2022 21:21:26 +0200 Subject: [PATCH 10/17] Corrects colors on Windows --- src/main.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0bedaa0..b4deeca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,11 +35,11 @@ void init() } #if SDL_BYTEORDER == SDL_BIG_ENDIAN - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, - 0x00ff0000, 0x0000ff00, 0x000000ff); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff); #else - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0x000000ff, - 0x0000ff00, 0x00ff0000, 0xff000000); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0, + 0, 0, 0); #endif texture = SDL_CreateTextureFromSurface(renderer, screen); @@ -105,15 +105,15 @@ int main(int argc, char* argv[]) text->print(screen, L"Unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que viv�a un hidalgo de los de lanza en astillero,\n" - "adarga antigua, roc�n flaco y galgo corredor.", + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", 10, 50); text->print(screen, L"Non-unicode string\nEn un lugar de la Mancha,\n" "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que viv�a un hidalgo de los de lanza en astillero,\n" - "adarga antigua, roc�n flaco y galgo corredor.", + "que vivía un hidalgo de los de lanza en astillero,\n" + "adarga antigua, rocín flaco y galgo corredor.", 10, 200); redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); From e091b8afd7bd9405cf47df0b3fee4b06c819dfa5 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 26 Aug 2022 14:07:04 +0200 Subject: [PATCH 11/17] template print --- src/drawtext.cpp | 49 ++++++++++++++++--------------- src/drawtext.h | 76 ++++++++++++++++++++++++++++++++++++------------ src/main.cpp | 11 ++++--- 3 files changed, 88 insertions(+), 48 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 328f280..7a5d05d 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -4,6 +4,7 @@ #include #include #include +#include DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, uint16_t initialCharacter, uint16_t finalCharacter) @@ -60,27 +61,27 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } -std::string DrawText::format(const std::string text, ...) -{ - char buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; - - return {buffer}; -} - -std::wstring DrawText::format(const std::wstring text, ...) -{ - wchar_t buffer[BUFFER_SIZE] = {}; - { - va_list list; - va_start(list, text); - vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); - va_end(list); - }; - return {buffer}; -} \ No newline at end of file +//std::string DrawText::format(const std::string text, ...) +//{ +// char buffer[BUFFER_SIZE] = {}; +// { +// va_list list; +// va_start(list, text); +// vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); +// va_end(list); +// }; +// +// return {buffer}; +//} +// +//std::wstring DrawText::format(const std::wstring text, ...) +//{ +// wchar_t buffer[BUFFER_SIZE] = {}; +// { +// va_list list; +// va_start(list, text); +// vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); +// va_end(list); +// }; +// return {buffer}; +//} \ No newline at end of file diff --git a/src/drawtext.h b/src/drawtext.h index e34647d..52a80ef 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -4,8 +4,12 @@ #include #include +#include #include #include +#include + +#include class DrawText { @@ -31,24 +35,41 @@ class DrawText * @param x Horizontal position of the text. * @param y Vertical position of the text. */ - template void print(SDL_Surface* destinationSurface, T const& text, int x, int y) + // template void print(SDL_Surface* destinationSurface, T const& text, int x, int + // y) + //{ + // auto process_elements = [&](auto& temp_string) -> void { + // auto tmp_x = x; + // auto tmp_y = y; + // for (auto c = std::begin(temp_string); c != std::end(temp_string) && *c != '\0'; c++) + // { + // if (newLine_) { + // tmp_x = x; + // newLine_ = false; + // } + // drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); + // } + // }; + + // if (std::is_convertible()) { + // process_elements(text); + // } else if (std::is_convertible()) { + // process_elements(text); + // } + //} + + template ::value, std::string>, + typename = std::enable_if::value, std::wstring>> + void print(SDL_Surface* destinationSurface, T const& text, int x, int y) { - auto process_elements = [&](auto& temp_string) -> void { - auto tmp_x = x; - auto tmp_y = y; - for (auto c = std::begin(temp_string); c != std::end(temp_string) && *c != '\0'; c++) { - if (newLine_) { - tmp_x = x; - newLine_ = false; - } - drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); + auto tmp_x = x; + auto tmp_y = y; + for (auto c = std::begin(text); c != std::end(text) && *c != '\0'; c++) { + if (newLine_) { + tmp_x = x; + newLine_ = false; } - }; - - if (std::is_convertible()) { - process_elements(text); - } else if (std::is_convertible()) { - process_elements(text); + drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); } } @@ -58,7 +79,7 @@ class DrawText * @param ... Extra parameters to replace by the format specifier * @return Resulting string after applying the format specifier */ - static std::string format(const std::string text, ...); + // static std::string format(const std::string text, ...); /** * @brief Formats a string @@ -66,7 +87,26 @@ class DrawText * @param ... Extra parameters to replace by the format specifier * @return Resulting string after applying the format specifier */ - static std::wstring format(const std::wstring string, ...); + // static std::wstring format(const std::wstring string, ...); + + template static std::string format(const std::string& text, Args&&... args) + { + size_t n = std::snprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + auto buffer = new char[n]; + std::snprintf(buffer, n, text.c_str(), std::forward(args)...); + std::string result = buffer; + delete[] buffer; + return result; + } + template static std::wstring format(const std::wstring& text, Args&&... args) + { + int n = swprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + auto buffer = new wchar_t[n]; + swprintf(buffer, n, text.c_str(), std::forward(args)...); + std::wstring result = buffer; + delete[] buffer; + return result; + } private: static constexpr size_t BUFFER_SIZE = 255; diff --git a/src/main.cpp b/src/main.cpp index b4deeca..895a333 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,11 +35,10 @@ void init() } #if SDL_BYTEORDER == SDL_BIG_ENDIAN - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, - 0x00ff0000, 0x0000ff00, 0x000000ff); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff); #else - screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0, - 0, 0, 0); + screen = SDL_CreateRGBSurface(0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, 0, 0, 0, 0); #endif texture = SDL_CreateTextureFromSurface(renderer, screen); @@ -116,11 +115,11 @@ int main(int argc, char* argv[]) "adarga antigua, rocín flaco y galgo corredor.", 10, 200); - redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); + redText->print(screen, L"test", 10, 350); mainLoop(); - // quit(); + quit(); return 0; } From 0096d2e5d4499b83692115f16dba29f4cb2e8a0a Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 26 Aug 2022 17:14:44 +0200 Subject: [PATCH 12/17] Cleaning --- src/drawtext.cpp | 4 ++-- src/drawtext.h | 44 +++++++++----------------------------------- src/main.cpp | 23 ++++++++++++----------- 3 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 7a5d05d..7e2897d 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -61,7 +61,7 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } -//std::string DrawText::format(const std::string text, ...) +// std::string DrawText::format(const std::string text, ...) //{ // char buffer[BUFFER_SIZE] = {}; // { @@ -74,7 +74,7 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in // return {buffer}; //} // -//std::wstring DrawText::format(const std::wstring text, ...) +// std::wstring DrawText::format(const std::wstring text, ...) //{ // wchar_t buffer[BUFFER_SIZE] = {}; // { diff --git a/src/drawtext.h b/src/drawtext.h index 52a80ef..3458cd8 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -9,7 +9,7 @@ #include #include -#include +#include class DrawText { @@ -35,29 +35,6 @@ class DrawText * @param x Horizontal position of the text. * @param y Vertical position of the text. */ - // template void print(SDL_Surface* destinationSurface, T const& text, int x, int - // y) - //{ - // auto process_elements = [&](auto& temp_string) -> void { - // auto tmp_x = x; - // auto tmp_y = y; - // for (auto c = std::begin(temp_string); c != std::end(temp_string) && *c != '\0'; c++) - // { - // if (newLine_) { - // tmp_x = x; - // newLine_ = false; - // } - // drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); - // } - // }; - - // if (std::is_convertible()) { - // process_elements(text); - // } else if (std::is_convertible()) { - // process_elements(text); - // } - //} - template ::value, std::string>, typename = std::enable_if::value, std::wstring>> void print(SDL_Surface* destinationSurface, T const& text, int x, int y) @@ -78,20 +55,14 @@ class DrawText * @param text The text or format specifier to convert * @param ... Extra parameters to replace by the format specifier * @return Resulting string after applying the format specifier + * @throw Fails if the resulting string has a size of zero */ - // static std::string format(const std::string text, ...); - - /** - * @brief Formats a string - * @param text The text or format specifier to convert - * @param ... Extra parameters to replace by the format specifier - * @return Resulting string after applying the format specifier - */ - // static std::wstring format(const std::wstring string, ...); - template static std::string format(const std::string& text, Args&&... args) { size_t n = std::snprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + if (n == 0) { + throw std::logic_error("The formated string has a size of zero."); + } auto buffer = new char[n]; std::snprintf(buffer, n, text.c_str(), std::forward(args)...); std::string result = buffer; @@ -100,7 +71,10 @@ class DrawText } template static std::wstring format(const std::wstring& text, Args&&... args) { - int n = swprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + int n = std::swprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + if (n == 0) { + throw std::logic_error("The formated string has a size of zero."); + } auto buffer = new wchar_t[n]; swprintf(buffer, n, text.c_str(), std::forward(args)...); std::wstring result = buffer; diff --git a/src/main.cpp b/src/main.cpp index 895a333..d0570b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ void init() SDL_Init(SDL_INIT_VIDEO); - window = SDL_CreateWindow("Examples", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + window = SDL_CreateWindow("Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN); if (window == NULL) { std::stringstream out; @@ -94,28 +94,29 @@ int main(int argc, char* argv[]) { init(); - //// Init DrawText object + // Init DrawText object SDL_Color white = {255, 255, 255, 0}; SDL_Color red = {255, 0, 0, 0}; auto* text = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 25, white); auto* redText = new DrawText("fonts/OfenbacherSchwabCAT.ttf", 20, red); + // Print some text text->print(screen, - L"Unicode string\nEn un lugar de la Mancha,\n" - "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + DrawText::format(L"Uicode string:\nEn un lugar de la Mancha," + "de cuyo nombre no quiero acordarme,\nno ha mucho tiempo" + "que vivía un hidalgo de los de lanza en astillero," + "\nadarga antigua, rocín flaco y galgo corredor."), 10, 50); text->print(screen, - L"Non-unicode string\nEn un lugar de la Mancha,\n" - "de cuyo nombre no quiero acordarme, no ha mucho tiempo\n" - "que vivía un hidalgo de los de lanza en astillero,\n" - "adarga antigua, rocín flaco y galgo corredor.", + DrawText::format("Non-uicode string:\nEn un lugar de la Mancha," + "de cuyo nombre no quiero acordarme,\nno ha mucho tiempo" + "que vivía un hidalgo de los de lanza en astillero," + "\nadarga antigua, rocín flaco y galgo corredor."), 10, 200); - redText->print(screen, L"test", 10, 350); + redText->print(screen, DrawText::format("Pi=%f", 3.141592), 10, 350); mainLoop(); From 5f0c5ddde9f929fccdab2b20d78886014d811ad5 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 26 Aug 2022 17:17:01 +0200 Subject: [PATCH 13/17] Removes old c code --- src/drawtext.cpp | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 7e2897d..7f24002 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -59,29 +59,4 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in x = x + glyph->w; SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); -} - -// std::string DrawText::format(const std::string text, ...) -//{ -// char buffer[BUFFER_SIZE] = {}; -// { -// va_list list; -// va_start(list, text); -// vsnprintf(buffer, BUFFER_SIZE, text.c_str(), list); -// va_end(list); -// }; -// -// return {buffer}; -//} -// -// std::wstring DrawText::format(const std::wstring text, ...) -//{ -// wchar_t buffer[BUFFER_SIZE] = {}; -// { -// va_list list; -// va_start(list, text); -// vswprintf(buffer, BUFFER_SIZE, text.c_str(), list); -// va_end(list); -// }; -// return {buffer}; -//} \ No newline at end of file +} \ No newline at end of file From 212a16ccecb7fd5f34056df51212bf66fa7c9346 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 26 Aug 2022 18:05:41 +0200 Subject: [PATCH 14/17] map alphabet --- src/drawtext.cpp | 47 +++++++++++++++++++++++++++++++++-------------- src/drawtext.h | 17 ++++++++--------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 7f24002..860ea0e 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -1,6 +1,7 @@ #include "drawtext.h" #include +#include #include #include #include @@ -8,11 +9,9 @@ DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, uint16_t initialCharacter, uint16_t finalCharacter) - : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, - totalCharacters_{static_cast(finalCharacter_ - initialCharacter_)}, - alphabet_{new SDL_Surface*[totalCharacters_]} + : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter} { - if (totalCharacters_ <= 0) { + if (finalCharacter_ - initialCharacter_ <= 0) { throw std::logic_error("The final character must be bigger than the initial character."); } @@ -28,35 +27,55 @@ DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fo DrawText::~DrawText() { - delete[] alphabet_; + for (std::map::iterator it = alphabet_.begin(); it != alphabet_.end(); + it++) { + SDL_FreeSurface(it->second); + } } void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { - for (auto c = initialCharacter_; c < finalCharacter_; c++) { + for (auto c = initialCharacter_; c <= finalCharacter_; c++) { auto glyph = TTF_RenderGlyph_Blended(font, c, fontColor); if (glyph == NULL) { throw std::runtime_error("Error creating alphabet"); } - alphabet_[c - initialCharacter_] = glyph; + alphabet_[c] = glyph; } } void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y) { - if (character == '\n') { - auto* glyph = alphabet_[0]; + auto get_glyph_of_character = [&](uint16_t c) -> SDL_Surface* { + try { + auto* glyph = alphabet_.at(c); + return glyph; + } catch (std::out_of_range& e) { + std::stringstream out; + out << "Exception trying to get element " << std::to_string(c) + << " from alphabet with limits [" << std::to_string(initialCharacter_) << ";" + << std::to_string(finalCharacter_) << "]." << static_cast(c) + << std::endl; + + std::cout << out.str(); + } + return nullptr; + }; + if (character == static_cast('\n')) { + auto* glyph = get_glyph_of_character(initialCharacter_); + if (glyph == nullptr) { + return; + } y = y + glyph->h; newLine_ = true; return; } - auto i = character - initialCharacter_; - if (i >= totalCharacters_) { - throw std::logic_error("Trying to access a glyph outside of the limits"); + + auto* glyph = get_glyph_of_character(character); + if (glyph == nullptr) { + return; } - auto* glyph = alphabet_[i]; SDL_Rect dst_rect = {x, y, glyph->w, glyph->h}; - x = x + glyph->w; SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); } \ No newline at end of file diff --git a/src/drawtext.h b/src/drawtext.h index 3458cd8..496593b 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -5,12 +5,12 @@ #include #include +#include +#include #include #include #include -#include - class DrawText { public: @@ -21,7 +21,7 @@ class DrawText * @param fontColor Color of the text to write. */ DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, - uint16_t initialCharacter = 32, uint16_t finalCharacter = 255); + uint16_t initialCharacter = 5, uint16_t finalCharacter = 255); /** * @brief Destroys the alphabet and free memory. @@ -34,6 +34,7 @@ class DrawText * @param text Unicode text to write on the screen. * @param x Horizontal position of the text. * @param y Vertical position of the text. + * @throw Out of range if the string contains characters not contained in the alphabet */ template ::value, std::string>, typename = std::enable_if::value, std::wstring>> @@ -46,7 +47,7 @@ class DrawText tmp_x = x; newLine_ = false; } - drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); + drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); } } @@ -82,8 +83,7 @@ class DrawText return result; } - private: - static constexpr size_t BUFFER_SIZE = 255; + private: /** * @brief Creates the glyphs that composes the alphabet. * @param font Pointer to the TTF_Font that contains a valid font. @@ -102,12 +102,11 @@ class DrawText /// Initial character for the alphabet. uint16_t initialCharacter_; + /// Final character for the alphabet. uint16_t finalCharacter_; - /// Total number of characters in alphabet. - size_t totalCharacters_; - SDL_Surface** alphabet_; + std::map alphabet_; bool newLine_{false}; }; From 7ad646bdc3613f7e2591595f1c46ad17b910e94d Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 26 Aug 2022 21:34:00 +0200 Subject: [PATCH 15/17] simplify loop --- src/drawtext.cpp | 8 ++++---- src/drawtext.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 860ea0e..3efad60 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -35,9 +35,9 @@ DrawText::~DrawText() void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) { - for (auto c = initialCharacter_; c <= finalCharacter_; c++) { - auto glyph = TTF_RenderGlyph_Blended(font, c, fontColor); - if (glyph == NULL) { + for (uint16_t c = initialCharacter_; c <= finalCharacter_; c++) { + auto* glyph = TTF_RenderGlyph_Blended(font, c, fontColor); + if (glyph == nullptr) { throw std::runtime_error("Error creating alphabet"); } alphabet_[c] = glyph; @@ -52,7 +52,7 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in return glyph; } catch (std::out_of_range& e) { std::stringstream out; - out << "Exception trying to get element " << std::to_string(c) + out << "Out of range exc. Trying to get element " << std::to_string(c) << " from alphabet with limits [" << std::to_string(initialCharacter_) << ";" << std::to_string(finalCharacter_) << "]." << static_cast(c) << std::endl; diff --git a/src/drawtext.h b/src/drawtext.h index 496593b..ab9e170 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -42,12 +42,12 @@ class DrawText { auto tmp_x = x; auto tmp_y = y; - for (auto c = std::begin(text); c != std::end(text) && *c != '\0'; c++) { + for (auto c = std::begin(text); c != std::end(text) && *c != '\0'; ++c) { if (newLine_) { tmp_x = x; newLine_ = false; } - drawGlyph(destinationSurface, static_cast(*c), tmp_x, tmp_y); + drawGlyph(destinationSurface,*c, tmp_x, tmp_y); } } @@ -83,7 +83,7 @@ class DrawText return result; } - private: + private: /** * @brief Creates the glyphs that composes the alphabet. * @param font Pointer to the TTF_Font that contains a valid font. From c9cb42afe9cba30f28872de0c367071909aaf23e Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 2 Sep 2022 22:40:45 +0200 Subject: [PATCH 16/17] new drawing constrains --- src/drawtext.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++------ src/drawtext.h | 23 ++++++++++++++++---- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 3efad60..1b9253b 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -8,8 +8,9 @@ #include DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, - uint16_t initialCharacter, uint16_t finalCharacter) - : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter} + uint16_t initialCharacter, uint16_t finalCharacter, bool throwExceptions) + : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, throwExceptions_{ + throwExceptions} { if (finalCharacter_ - initialCharacter_ <= 0) { throw std::logic_error("The final character must be bigger than the initial character."); @@ -44,8 +45,12 @@ void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) } } -void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y) +void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y, + Constrain constrain) { + if (y > (constrain.x0 + constrain.height) && constrain.height != 0) { + return; + } auto get_glyph_of_character = [&](uint16_t c) -> SDL_Surface* { try { auto* glyph = alphabet_.at(c); @@ -54,13 +59,17 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in std::stringstream out; out << "Out of range exc. Trying to get element " << std::to_string(c) << " from alphabet with limits [" << std::to_string(initialCharacter_) << ";" - << std::to_string(finalCharacter_) << "]." << static_cast(c) - << std::endl; + << std::to_string(finalCharacter_) << "]." << static_cast(c) << std::endl; + if (throwExceptions_) { + throw e; + } std::cout << out.str(); } return nullptr; }; + + // New line if (character == static_cast('\n')) { auto* glyph = get_glyph_of_character(initialCharacter_); if (glyph == nullptr) { @@ -71,11 +80,43 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in return; } + // Normal character auto* glyph = get_glyph_of_character(character); if (glyph == nullptr) { return; } - SDL_Rect dst_rect = {x, y, glyph->w, glyph->h}; + + auto calculate_increment = [](int x0, int w0, int x1, int w1) -> int { + int dx = 0; + if (w0 == 0) { + dx = w1; + } else { + dx = (x0 + w0) > (x1 + w1) ? w1 : w1 - (x1 + w1 - x0 - w0); + } + return dx; + }; + + int dx = calculate_increment(constrain.x0, constrain.width, x, glyph->w); + int dy = calculate_increment(constrain.y0, constrain.height, y, glyph->h); + + // if (constrain.width == 0) { + // dx = glyph->w; + //} else { + // dx = (constrain.x0 + constrain.width) > (x + glyph->w) + // ? glyph->w + // : glyph->w - (x + glyph->w - constrain.x0 - constrain.width); + //} + + // if (constrain.height == 0) { + // dy = glyph->h; + //} else { + // dy = (constrain.y0 + constrain.height) > (y + glyph->h) + // ? glyph->h + // : glyph->h - (y + glyph->h - constrain.y0 - constrain.height); + //} + + SDL_Rect src_rect = {0, 0, dx, dy}; + SDL_Rect dst_rect = {x, y, dx, dy}; x = x + glyph->w; - SDL_BlitSurface(glyph, NULL, destinationSurface, &dst_rect); + SDL_BlitSurface(glyph, &src_rect, destinationSurface, &dst_rect); } \ No newline at end of file diff --git a/src/drawtext.h b/src/drawtext.h index ab9e170..7d4a273 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -21,7 +21,8 @@ class DrawText * @param fontColor Color of the text to write. */ DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, - uint16_t initialCharacter = 5, uint16_t finalCharacter = 255); + uint16_t initialCharacter = 5, uint16_t finalCharacter = 255, + bool throwExceptions = false); /** * @brief Destroys the alphabet and free memory. @@ -34,11 +35,14 @@ class DrawText * @param text Unicode text to write on the screen. * @param x Horizontal position of the text. * @param y Vertical position of the text. + * @param width Sets a maximum width for the text. 0 for no limitations. + * @param height Sets a maxium height for the text. 0 for no limitations. * @throw Out of range if the string contains characters not contained in the alphabet */ template ::value, std::string>, typename = std::enable_if::value, std::wstring>> - void print(SDL_Surface* destinationSurface, T const& text, int x, int y) + void print(SDL_Surface* destinationSurface, T const& text, int x, int y, int width = 0, + int height = 0) { auto tmp_x = x; auto tmp_y = y; @@ -47,7 +51,7 @@ class DrawText tmp_x = x; newLine_ = false; } - drawGlyph(destinationSurface,*c, tmp_x, tmp_y); + drawGlyph(destinationSurface, *c, tmp_x, tmp_y, Constrain{x, y, width, height}); } } @@ -84,6 +88,12 @@ class DrawText } private: + struct Constrain { + int x0{0}; + int y0{0}; + int width{0}; + int height{0}; + }; /** * @brief Creates the glyphs that composes the alphabet. * @param font Pointer to the TTF_Font that contains a valid font. @@ -97,8 +107,12 @@ class DrawText * @param character Unicode character to write on the screen. * @param x Horizontal position for the glyph. * @param y Vertical position for the glyph. + * @param Constrain sets the drawing limitations. + * + * If the width or height in the constrain struct are zero the dimension is ignored. */ - void drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y); + void drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y, + Constrain constrain = Constrain{0, 0, 0, 0}); /// Initial character for the alphabet. uint16_t initialCharacter_; @@ -109,6 +123,7 @@ class DrawText std::map alphabet_; bool newLine_{false}; + bool throwExceptions_{false}; }; #endif From 53d231519c013ffbf0dee40e922ecfed88e22f55 Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 12 Nov 2022 23:41:47 +0100 Subject: [PATCH 17/17] refactoring --- src/drawtext.cpp | 70 +++++++++++++++--------------------------------- src/drawtext.h | 27 ++++++++++--------- 2 files changed, 36 insertions(+), 61 deletions(-) diff --git a/src/drawtext.cpp b/src/drawtext.cpp index 1b9253b..6a41f4c 100644 --- a/src/drawtext.cpp +++ b/src/drawtext.cpp @@ -1,18 +1,16 @@ #include "drawtext.h" #include -#include #include #include #include #include -DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fontColor, +DrawText::DrawText(const char* fontPath, int fontSize, const SDL_Color& fontColor, uint16_t initialCharacter, uint16_t finalCharacter, bool throwExceptions) - : initialCharacter_{initialCharacter}, finalCharacter_{finalCharacter}, throwExceptions_{ - throwExceptions} + : throwExceptions_{throwExceptions} { - if (finalCharacter_ - initialCharacter_ <= 0) { + if (finalCharacter - initialCharacter <= 0) { throw std::logic_error("The final character must be bigger than the initial character."); } @@ -22,7 +20,7 @@ DrawText::DrawText(const char* fontPath, const int fontSize, const SDL_Color& fo message << "DrawText::DrawText: " << TTF_GetError(); throw std::runtime_error(message.str()); } - createAlphabet(font, fontColor); + createAlphabet(font, fontColor, initialCharacter, finalCharacter); TTF_CloseFont(font); } @@ -34,9 +32,10 @@ DrawText::~DrawText() } } -void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) +void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor, uint16_t initialCharacter, + uint16_t finalCharacter) { - for (uint16_t c = initialCharacter_; c <= finalCharacter_; c++) { + for (uint16_t c = initialCharacter; c <= finalCharacter; c++) { auto* glyph = TTF_RenderGlyph_Blended(font, c, fontColor); if (glyph == nullptr) { throw std::runtime_error("Error creating alphabet"); @@ -45,6 +44,17 @@ void DrawText::createAlphabet(TTF_Font* font, const SDL_Color& fontColor) } } +static int calculateIncrement(int x0, int w0, int x1, int w1) +{ + int dx = 0; + if (w0 == 0) { + dx = w1; + } else { + dx = (x0 + w0) > (x1 + w1) ? w1 : w1 - (x1 + w1 - x0 - w0); + } + return dx; +} + void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y, Constrain constrain) { @@ -56,25 +66,16 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in auto* glyph = alphabet_.at(c); return glyph; } catch (std::out_of_range& e) { - std::stringstream out; - out << "Out of range exc. Trying to get element " << std::to_string(c) - << " from alphabet with limits [" << std::to_string(initialCharacter_) << ";" - << std::to_string(finalCharacter_) << "]." << static_cast(c) << std::endl; - if (throwExceptions_) { - throw e; + throw std::logic_error("Trying to print character not defined in alphabet."); } - std::cout << out.str(); } return nullptr; }; // New line if (character == static_cast('\n')) { - auto* glyph = get_glyph_of_character(initialCharacter_); - if (glyph == nullptr) { - return; - } + auto* glyph = get_glyph_of_character(alphabet_.begin()->first); y = y + glyph->h; newLine_ = true; return; @@ -86,35 +87,8 @@ void DrawText::drawGlyph(SDL_Surface* destinationSurface, uint16_t character, in return; } - auto calculate_increment = [](int x0, int w0, int x1, int w1) -> int { - int dx = 0; - if (w0 == 0) { - dx = w1; - } else { - dx = (x0 + w0) > (x1 + w1) ? w1 : w1 - (x1 + w1 - x0 - w0); - } - return dx; - }; - - int dx = calculate_increment(constrain.x0, constrain.width, x, glyph->w); - int dy = calculate_increment(constrain.y0, constrain.height, y, glyph->h); - - // if (constrain.width == 0) { - // dx = glyph->w; - //} else { - // dx = (constrain.x0 + constrain.width) > (x + glyph->w) - // ? glyph->w - // : glyph->w - (x + glyph->w - constrain.x0 - constrain.width); - //} - - // if (constrain.height == 0) { - // dy = glyph->h; - //} else { - // dy = (constrain.y0 + constrain.height) > (y + glyph->h) - // ? glyph->h - // : glyph->h - (y + glyph->h - constrain.y0 - constrain.height); - //} - + const int dx = calculateIncrement(constrain.x0, constrain.width, x, glyph->w); + const int dy = calculateIncrement(constrain.y0, constrain.height, y, glyph->h); SDL_Rect src_rect = {0, 0, dx, dy}; SDL_Rect dst_rect = {x, y, dx, dy}; x = x + glyph->w; diff --git a/src/drawtext.h b/src/drawtext.h index 7d4a273..69c3e69 100644 --- a/src/drawtext.h +++ b/src/drawtext.h @@ -64,11 +64,14 @@ class DrawText */ template static std::string format(const std::string& text, Args&&... args) { - size_t n = std::snprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + size_t n = std::snprintf(nullptr, 0, text.c_str(), std::forward(args)...); + if (n < 0) { + throw std::runtime_error("The formated string has a size of zero."); + } if (n == 0) { - throw std::logic_error("The formated string has a size of zero."); + return {}; } - auto buffer = new char[n]; + auto buffer = new char[n+1]; std::snprintf(buffer, n, text.c_str(), std::forward(args)...); std::string result = buffer; delete[] buffer; @@ -76,11 +79,14 @@ class DrawText } template static std::wstring format(const std::wstring& text, Args&&... args) { - int n = std::swprintf(nullptr, 0, text.c_str(), std::forward(args)...) + 1; + int n = std::swprintf(nullptr, 0, text.c_str(), std::forward(args)...); + if (n < 0) { + throw std::runtime_error("The formated string has a size of zero."); + } if (n == 0) { - throw std::logic_error("The formated string has a size of zero."); + return {}; } - auto buffer = new wchar_t[n]; + auto buffer = new wchar_t[n+1]; swprintf(buffer, n, text.c_str(), std::forward(args)...); std::wstring result = buffer; delete[] buffer; @@ -99,7 +105,8 @@ class DrawText * @param font Pointer to the TTF_Font that contains a valid font. * @param fontColor Color for the glyphs. */ - void createAlphabet(TTF_Font* font, const SDL_Color& fontColor); + void createAlphabet(TTF_Font* font, const SDL_Color& fontColor, uint16_t initialCharacter, + uint16_t finalCharacter); /** * @brief Draw a glyph on the screen @@ -114,12 +121,6 @@ class DrawText void drawGlyph(SDL_Surface* destinationSurface, uint16_t character, int& x, int& y, Constrain constrain = Constrain{0, 0, 0, 0}); - /// Initial character for the alphabet. - uint16_t initialCharacter_; - - /// Final character for the alphabet. - uint16_t finalCharacter_; - std::map alphabet_; bool newLine_{false};