aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Font.cpp40
-rw-r--r--src/common/Font.hpp6
-rw-r--r--src/games/Game.cpp4
-rw-r--r--src/games/Game.hpp7
-rw-r--r--src/games/minesweeper/Minesweeper.cpp40
-rw-r--r--src/games/minesweeper/Minesweeper.hpp7
-rw-r--r--src/games/snake/Snake.cpp19
-rw-r--r--src/games/tetris/Board.cpp4
-rw-r--r--src/games/tetris/Tetris.cpp131
-rw-r--r--src/games/tetris/Tetris.hpp6
-rw-r--r--src/games/tetris/Tetromino.cpp2
-rw-r--r--src/renderer/RSoftwareBackend.cpp123
-rw-r--r--src/renderer/RSoftwareBackend.hpp13
-rw-r--r--src/renderer/Renderer.cpp47
-rw-r--r--src/renderer/Renderer.hpp23
15 files changed, 302 insertions, 170 deletions
diff --git a/src/common/Font.cpp b/src/common/Font.cpp
index 82f6ad8..8f058ca 100644
--- a/src/common/Font.cpp
+++ b/src/common/Font.cpp
@@ -12,30 +12,24 @@ is_ch_ascii(char32_t ch)
return result;
}
-Font::~Font()
-{
- delete[] m_file_content;
-}
-
-bool
-Font::Init(const char* path, int font_size)
+Font::Font(const char *path, int font_size)
{
if (!ReadFile(path)) {
- return false;
+ return;
}
- // set font info
+ // init m_file_content, m_font_info
if (!stbtt_InitFont(&m_font_info, (unsigned char*)m_file_content, 0))
{
std::cout << "stbtt_InitFont failed.\n";
delete[] m_file_content;
m_file_content = nullptr;
- return false;
+ return;
}
- // set font settings (scale + vmetrics)
+ // init font settings
float scale = stbtt_ScaleForPixelHeight(&m_font_info, (float)font_size);
int baseline, ascent, descent, line_gap;
stbtt_GetFontVMetrics(&m_font_info, &ascent, &descent, &line_gap);
@@ -44,8 +38,6 @@ Font::Init(const char* path, int font_size)
descent = int(scale * (float)descent);
line_gap = int(scale * (float)line_gap);
-
- // init members
m_font_scale = scale;
m_font_baseline = baseline;
m_font_yadvance = ascent - descent + line_gap;
@@ -53,12 +45,14 @@ Font::Init(const char* path, int font_size)
// load glyphs
for (char c = first_ascii_ch; c <= last_ascii_ch; ++c) {
- LoadGlyph(m_glyphs[c-first_ascii_ch], static_cast<char32_t>(c));
+ InitGlyph(m_glyphs[c-first_ascii_ch], static_cast<char32_t>(c));
}
memset((void*)&m_fail_glyph, 0, sizeof(m_fail_glyph));
+}
-
- return true;
+Font::~Font()
+{
+ delete[] m_file_content;
}
bool
@@ -83,7 +77,7 @@ Font::ReadFile(const char* path)
}
void
-Font::LoadGlyph(Glyph& glyph, char32_t c)
+Font::InitGlyph(Glyph& glyph, char32_t c)
{
int bbx0, bby0, bbx1, bby1;
stbtt_GetCodepointBitmapBox(&m_font_info, (int)c, m_font_scale, m_font_scale, &bbx0, &bby0, &bbx1, &bby1);
@@ -130,8 +124,10 @@ Font::LoadGlyph(Glyph& glyph, char32_t c)
AlphaBitmap&
Font::GetAlphaBitmap(char32_t c)
{
- if (is_ch_ascii(c)) {
- return m_glyphs[c - first_ascii_ch].bitmap;
+ if (m_file_content) {
+ if (is_ch_ascii(c)) {
+ return m_glyphs[c - first_ascii_ch].bitmap;
+ }
}
return m_fail_glyph.bitmap;
@@ -140,8 +136,10 @@ Font::GetAlphaBitmap(char32_t c)
Glyph&
Font::GetGlyph(char32_t c)
{
- if (is_ch_ascii(c)) {
- return m_glyphs[c - first_ascii_ch];
+ if (m_file_content) {
+ if (is_ch_ascii(c)) {
+ return m_glyphs[c - first_ascii_ch];
+ }
}
return m_fail_glyph;
diff --git a/src/common/Font.hpp b/src/common/Font.hpp
index af4ddb5..876b03a 100644
--- a/src/common/Font.hpp
+++ b/src/common/Font.hpp
@@ -23,9 +23,9 @@ struct Glyph {
class Font {
public:
+ explicit Font(const char* path, int size);
~Font();
- bool Init(const char* path, int font_size);
AlphaBitmap& GetAlphaBitmap(char32_t c);
Glyph& GetGlyph(char32_t c);
@@ -33,7 +33,7 @@ public:
private:
bool ReadFile(const char* path);
- void LoadGlyph(Glyph& glyph, char32_t c);
+ void InitGlyph(Glyph& glyph, char32_t c);
private:
@@ -43,12 +43,12 @@ private:
const char* m_file_content = nullptr;
+ stbtt_fontinfo m_font_info;
float m_font_scale;
int m_font_baseline;
int m_font_yadvance;
- stbtt_fontinfo m_font_info;
Glyph m_glyphs[ascii_glyph_count];
Glyph m_fail_glyph;
};
diff --git a/src/games/Game.cpp b/src/games/Game.cpp
index 0e6af1c..c403a40 100644
--- a/src/games/Game.cpp
+++ b/src/games/Game.cpp
@@ -50,7 +50,7 @@ Game::ProcessDt()
}
void
-Game::DrawGameOverMenu()
+Game::DrawDefaultGameOverMenu()
{
ImGui::Begin("DefaultGameOverMenu", nullptr, s_imgui_window_flags_menu);
ImGui::Text("Game Over.");
@@ -64,7 +64,7 @@ Game::DrawGameOverMenu()
}
void
-Game::DrawGamePausedMenu()
+Game::DrawDefaultGamePausedMenu()
{
ImGui::Begin("DefaultGamePauseMenu", nullptr, s_imgui_window_flags_menu);
if (ImGui::Button("Resume")) {
diff --git a/src/games/Game.hpp b/src/games/Game.hpp
index 7de3b66..a020012 100644
--- a/src/games/Game.hpp
+++ b/src/games/Game.hpp
@@ -35,8 +35,8 @@ public:
protected:
- void DrawGameOverMenu();
- void DrawGamePausedMenu();
+ void DrawDefaultGameOverMenu();
+ void DrawDefaultGamePausedMenu();
float ProcessDt();
@@ -46,6 +46,9 @@ protected:
protected:
+ static constexpr const char* s_dejavu_sans_filepath = "./fonts/dejavu_ttf/DejaVuSans.ttf";
+ static constexpr const char* s_dejavu_sans_mono_filepath = "./fonts/dejavu_ttf/DejaVuSansMono.ttf";
+
static constexpr ImGuiWindowFlags s_imgui_window_flags_menu = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize;
static constexpr ImGuiWindowFlags s_imgui_window_flags_default = ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoScrollbar;
};
diff --git a/src/games/minesweeper/Minesweeper.cpp b/src/games/minesweeper/Minesweeper.cpp
index 2a69e4d..a091491 100644
--- a/src/games/minesweeper/Minesweeper.cpp
+++ b/src/games/minesweeper/Minesweeper.cpp
@@ -1,4 +1,3 @@
-#include "games/Game.hpp"
#include <games/minesweeper/Minesweeper.hpp>
#include <renderer/Renderer.hpp>
@@ -6,10 +5,15 @@
#include <algorithm>
#include <random>
-#include <cstdio>
-// Todo: winning condition (maybe: total_cells - uncovered_cells = mine_count)
+// Todo:
+// - First click may not be a mine!
+// - Show current time spent
+// - Show current flags/mines left
+// - Permit uncovering of flagged cell
+// - Game Over: Winning Condition (maybe: total_cells - uncovered_cells == mine_count)
+// - Game Over: Show Highscore for selected difficulty
static constexpr Color s_mine_count_colors[8] = {
@@ -25,11 +29,8 @@ static constexpr Color s_mine_count_colors[8] = {
Minesweeper::Minesweeper()
+ : m_font{s_dejavu_sans_filepath, 22}
{
- bool font_init = m_font.Init(s_font_filepath, 22);
- if (!font_init) {
- printf("m_font.Init(...) failed\n");
- }
}
void
@@ -148,7 +149,7 @@ Minesweeper::Update(std::vector<SDL_Event>& events)
if (m_game_status == game_paused) {
DrawBoard();
- DrawGamePausedMenu();
+ DrawDefaultGamePausedMenu();
}
else if (m_game_status == game_starting) {
DrawStartMenu();
@@ -158,7 +159,7 @@ Minesweeper::Update(std::vector<SDL_Event>& events)
}
else if (m_game_status == game_over) {
DrawBoard();
- DrawGameOverMenu();
+ DrawDefaultGameOverMenu();
}
return true;
@@ -370,7 +371,7 @@ Minesweeper::DrawBoard()
bool is_mine = IsMine(x, y);
if (is_covered) {
- g_renderer.PushRectangle(cell_rect, 0.0f, covered_cell_color);
+ g_renderer.PushRectangle(cell_rect, covered_cell_color, 0.0f);
if (is_flagged) {
@@ -385,7 +386,7 @@ Minesweeper::DrawBoard()
flag_pos.x + flag_size.x,
flag_pos.y + flag_size.y,
};
- g_renderer.PushRectangle(flag_rect, flag_pos.z, flag_color);
+ g_renderer.PushRectangle(flag_rect, flag_color, flag_pos.z);
}
}
else {
@@ -401,26 +402,21 @@ Minesweeper::DrawBoard()
mine_pos.x + m_cell_inner_size.x,
mine_pos.y + m_cell_inner_size.y,
};
- g_renderer.PushRectangle(mine_rect, mine_pos.z, mine_color);
+ g_renderer.PushRectangle(mine_rect, mine_color, mine_pos.z);
}
else {
- g_renderer.PushRectangle(cell_rect, 0.0f, uncovered_cell_color);
+ g_renderer.PushRectangle(cell_rect, uncovered_cell_color, 0.0f);
- // Todo: Figure out how to scale this properly.
- // 256.0f is a random number that just works for now.
V3F32 mine_count_pos = {
- 256.0f * cell_pos.x,
- 256.0f * cell_pos.y,
- 256.0f
+ cell_pos.x,
+ cell_pos.y,
+ 1.0f
};
int32_t mine_count = m_adjacent_mine_counts[y*m_grid_width + x];
if (mine_count > 0) {
Color color = s_mine_count_colors[mine_count-1];
Glyph& glyph = m_font.GetGlyph('0' + (char32_t)mine_count);
- g_renderer.PushAlphaBitmap(
- glyph.bitmap,
- mine_count_pos,
- color);
+ g_renderer.PushAlphaBitmap(glyph.bitmap, mine_count_pos, color);
}
}
}
diff --git a/src/games/minesweeper/Minesweeper.hpp b/src/games/minesweeper/Minesweeper.hpp
index 24672f0..fbdcb30 100644
--- a/src/games/minesweeper/Minesweeper.hpp
+++ b/src/games/minesweeper/Minesweeper.hpp
@@ -4,8 +4,6 @@
#include <common/math.hpp>
#include <common/Font.hpp>
-#include <array>
-
class Minesweeper : public Game {
public:
@@ -21,11 +19,11 @@ public:
bool Update(std::vector<SDL_Event>& events) override;
+
+private:
void ProcessEventDuringPause(SDL_Event& event);
void ProcessEventDuringResume(SDL_Event& event);
-
-private:
void Reset(Difficulty Difficulty);
void InitIsMineBitmap(int32_t mine_count);
void InitAdjacentMineCounters();
@@ -50,7 +48,6 @@ private:
private:
static constexpr int32_t max_map_height = 32;
static constexpr int32_t max_map_width = 32;
- static constexpr const char* s_font_filepath = "./fonts/dejavu_ttf/DejaVuSans.ttf";
private:
diff --git a/src/games/snake/Snake.cpp b/src/games/snake/Snake.cpp
index 7969616..542122e 100644
--- a/src/games/snake/Snake.cpp
+++ b/src/games/snake/Snake.cpp
@@ -1,10 +1,13 @@
-#include "common/defs.hpp"
-#include <chrono>
#include <games/snake/Snake.hpp>
#include <renderer/Renderer.hpp>
#include <imgui.h>
+// Todo:
+// - gradiant from head to tail
+// - reduce thickness from head to tail
+
+
std::mt19937 Snake::s_rng{std::random_device{}()};
@@ -77,10 +80,10 @@ Snake::Update(std::vector<SDL_Event> &events)
MaybeMoveSnake(dt);
} break;
case game_over: {
- DrawGameOverMenu();
+ DrawDefaultGameOverMenu();
} break;
case game_paused: {
- DrawGamePausedMenu();
+ DrawDefaultGamePausedMenu();
} break;
case game_exit: {
return false;
@@ -303,7 +306,7 @@ Snake::Draw()
map_world_pos.y + map_world_dim.y
};
Color bg_color = {0.0f, 0.0f, 0.0f, 1.0f};
- g_renderer.PushRectangle(map_world_rect, map_world_pos.z, bg_color);
+ g_renderer.PushRectangle(map_world_rect, bg_color, map_world_pos.z);
/* draw snake */
@@ -332,7 +335,7 @@ Snake::Draw()
};
Color color = {0.3f, 0.3f, 0.3f, 1.0f};
- g_renderer.PushRectangle(world_rect, world_pos.z, color);
+ g_renderer.PushRectangle(world_rect, color, world_pos.z);
tail++;
}
tail = 0;
@@ -360,7 +363,7 @@ Snake::Draw()
};
Color color = {0.3f, 0.3f, 0.3f, 1.0f};
- g_renderer.PushRectangle(world_rect, world_pos.z, color);
+ g_renderer.PushRectangle(world_rect, color, world_pos.z);
tail++;
}
@@ -379,6 +382,6 @@ Snake::Draw()
pos.y + dim.y
};
Color color = {0.3f, 0.6f, 0.4f, 1.0f};
- g_renderer.PushRectangle(rect, pos.z, color);
+ g_renderer.PushRectangle(rect, color, pos.z);
}
diff --git a/src/games/tetris/Board.cpp b/src/games/tetris/Board.cpp
index 1344d5b..7f391b4 100644
--- a/src/games/tetris/Board.cpp
+++ b/src/games/tetris/Board.cpp
@@ -115,7 +115,7 @@ Board::Draw(int32_t level)
bg_world_pos.y + bg_world_dim.y,
};
Color bg_color = {0.0f, 0.0f, 0.0f, 1.0f};
- g_renderer.PushRectangle(bg_world_rect, bg_world_pos.z, bg_color);
+ g_renderer.PushRectangle(bg_world_rect, bg_color, bg_world_pos.z);
// tetromino parts
@@ -145,7 +145,7 @@ Board::Draw(int32_t level)
Color color = Tetromino::GetColor(tetromino_id);
- g_renderer.PushRectangle(world_rect, world_pos.z, color);
+ g_renderer.PushRectangle(world_rect, color, world_pos.z);
}
}
}
diff --git a/src/games/tetris/Tetris.cpp b/src/games/tetris/Tetris.cpp
index aefdb41..aeb0c99 100644
--- a/src/games/tetris/Tetris.cpp
+++ b/src/games/tetris/Tetris.cpp
@@ -8,11 +8,23 @@
#include <imgui.h>
#include <fstream>
+#include <iostream>
+
+
+static
+std::u32string
+int32_to_u32string(int32_t value)
+{
+ std::string str = std::to_string(value);
+ return std::u32string(str.begin(), str.end());
+}
+
Tetris::Tetris()
- : m_font{}
+ : m_font{s_dejavu_sans_mono_filepath, 22}
, m_active_tetromino{m_board.m_bitmap}
{
+ m_frame_strings.reserve(s_frame_strings_capcity);
}
void
@@ -42,6 +54,8 @@ Tetris::Update(std::vector<SDL_Event>& events)
g_renderer.SetCameraSize(4.0f, 3.0f);
g_renderer.Clear(clear_color);
+ m_frame_strings.clear();
+
if (m_game_status == game_starting) {
Start();
@@ -52,7 +66,7 @@ Tetris::Update(std::vector<SDL_Event>& events)
if (m_game_status == game_resuming) {
- uint32_t softdrop_count = GetSoftdropCount(dt); // side-effect: m_dt_remaining_seconds
+ uint32_t softdrop_count = GetSoftdropCount(dt);
for (uint32_t i{0}; i < softdrop_count; i++) {
bool moved_down = m_active_tetromino.MaybeMoveDown();
if (!moved_down) {
@@ -70,6 +84,7 @@ Tetris::Update(std::vector<SDL_Event>& events)
}
}
+ assert(m_frame_strings.capacity() == s_frame_strings_capcity);
if (m_game_status == game_exit) {
return false;
@@ -232,7 +247,7 @@ Tetris::Draw()
DrawScore();
if (m_game_status == game_paused) {
- DrawGamePausedMenu();
+ DrawDefaultGamePausedMenu();
}
else if (m_game_status == game_over) {
DrawGameOverMenu();
@@ -257,77 +272,87 @@ Tetris::DrawGameOverMenu()
void
Tetris::DrawLineCounter()
{
- V2F32 view_pos = {0.5f, 2.6f};
- ImVec2 screen_pos = g_renderer.ViewPosToScreenPosImGui(view_pos);
+ static std::u32string text = U"Lines: xxx";
+ V3F32 pos = {0.5f, 2.6f, 4.0f};
+ Color color = {0.9f, 0.9f, 0.9f, 1.0f};
- ImGui::SetNextWindowPos(screen_pos);
- ImGui::Begin("TetrisLines", nullptr, s_imgui_window_flags_default);
- ImGui::Text("LINES - %d", m_line_counter);
- ImGui::End();
+ int line_count = std::min(m_line_counter, 999);
+
+ text[9] = U'0' + char32_t(line_count % 10);
+ line_count /= 10;
+ text[8] = U'0' + char32_t(line_count % 10);
+ line_count /= 10;
+ text[7] = U'0' + char32_t(line_count % 10);
+ line_count /= 10;
+
+
+ g_renderer.PushText(text, m_font, pos, color);
+ pos.x += 0.2f;
}
void
Tetris::DrawStatistics()
{
- V2F32 view_tetrominoes_pos = {0.4f, 1.8f};
- V2F32 view_advance = {0.0f, 0.2f};
+ V2F32 pos = {0.4f, 0.5f};
- V2F32 view_text_title_pos = view_tetrominoes_pos + V2F32(0.02f, 0.4f);
- ImVec2 screen_text_title_pos = g_renderer.ViewPosToScreenPosImGui(view_text_title_pos);
- V2F32 view_text_pos = view_tetrominoes_pos + V2F32(0.4f, 0.16f);
- V2F32 view_text_gap = {0.0f, 0.124f};
- ImVec2 screen_text_pos = g_renderer.ViewPosToScreenPosImGui(view_text_pos);
- ImVec2 screen_text_gap = g_renderer.ViewSizeToScreenSizeImGui(view_text_gap);
+ static std::u32string title_text = U"Statistics";
+ V3F32 title_pos = {pos.x + 0.02f, pos.y + 1.64f, s_text_z};
+ g_renderer.PushText(title_text, m_font, title_pos, s_text_color);
- Tetromino::Draw(Tetromino::t_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ float yadvance = -0.2f;
+ float tetrominoes_x0 = pos.x;
+ float tetrominoes_y0 = pos.y - (float)Tetromino::id_count * yadvance;
+ V2F32 tetromino_pos = {tetrominoes_x0, tetrominoes_y0};
- Tetromino::Draw(Tetromino::j_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::t_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- Tetromino::Draw(Tetromino::z_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::j_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- Tetromino::Draw(Tetromino::o_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::z_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- Tetromino::Draw(Tetromino::s_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::o_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- Tetromino::Draw(Tetromino::l_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::s_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- Tetromino::Draw(Tetromino::i_piece, 0, view_tetrominoes_pos, 0.5f);
- view_tetrominoes_pos.y -= view_advance.y;
+ Tetromino::Draw(Tetromino::l_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
+ Tetromino::Draw(Tetromino::i_piece, 0, tetromino_pos, 0.5f);
+ tetromino_pos.y += yadvance;
- ImGui::SetNextWindowPos(screen_text_title_pos);
- ImGui::Begin("TetrisStatisticsTitle", nullptr, s_imgui_window_flags_default);
- ImGui::Text("STATISTICS");
- ImGui::End();
+ float counters_x0 = pos.x + 0.4f;
+ float counters_y0 = pos.y + 0.05f - yadvance * (float)Tetromino::id_count;
+ V3F32 counters_pos = {counters_x0, counters_y0, s_text_z};
- ImGui::SetNextWindowPos(screen_text_pos);
- ImGui::Begin("TetrisStatistics", nullptr, s_imgui_window_flags_default);
-
- ImGui::Text("%d", m_tetromino_counters[Tetromino::t_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::j_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::z_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::o_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::s_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::l_piece]);
- ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_tetromino_counters[Tetromino::i_piece]);
- ImGui::Dummy(screen_text_gap);
+ std::u32string& t_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::t_piece]));
+ std::u32string& j_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::j_piece]));
+ std::u32string& z_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::z_piece]));
+ std::u32string& o_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::o_piece]));
+ std::u32string& s_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::s_piece]));
+ std::u32string& l_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::l_piece]));
+ std::u32string& i_count = m_frame_strings.emplace_back(int32_to_u32string(m_tetromino_counters[Tetromino::i_piece]));
- ImGui::End();
+ g_renderer.PushText(t_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(j_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(z_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(o_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(s_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(l_count, m_font, counters_pos, s_text_color);
+ counters_pos.y += yadvance;
+ g_renderer.PushText(i_count, m_font, counters_pos, s_text_color);
}
void
diff --git a/src/games/tetris/Tetris.hpp b/src/games/tetris/Tetris.hpp
index 03966fd..7f48e37 100644
--- a/src/games/tetris/Tetris.hpp
+++ b/src/games/tetris/Tetris.hpp
@@ -31,6 +31,10 @@ private:
private:
+ static constexpr Color s_text_color {0.9f, 0.9f, 0.9f, 1.0f};
+ static constexpr float s_text_z {10.0f};
+ static constexpr size_t s_frame_strings_capcity {32};
+
Font m_font;
Board m_board;
Tetromino m_active_tetromino;
@@ -43,6 +47,8 @@ private:
int32_t m_level = 0;
int32_t m_softdrop_counter = 0;
int32_t m_highscore = 0;
+
+ std::vector<std::u32string> m_frame_strings;
};
diff --git a/src/games/tetris/Tetromino.cpp b/src/games/tetris/Tetromino.cpp
index 2cde231..416a8df 100644
--- a/src/games/tetris/Tetromino.cpp
+++ b/src/games/tetris/Tetromino.cpp
@@ -233,7 +233,7 @@ Tetromino::Draw(Id id, int32_t ori, V2F32 pos, float scale)
Color color = GetColor(id);
- g_renderer.PushRectangle(world_rect, world_pos.z, color);
+ g_renderer.PushRectangle(world_rect, color, world_pos.z);
}
}
}
diff --git a/src/renderer/RSoftwareBackend.cpp b/src/renderer/RSoftwareBackend.cpp
index 4d78ec7..d05cee7 100644
--- a/src/renderer/RSoftwareBackend.cpp
+++ b/src/renderer/RSoftwareBackend.cpp
@@ -1,3 +1,4 @@
+#include "imgui.h"
#include <renderer/RSoftwareBackend.hpp>
#include <SDL3/SDL_video.h>
@@ -8,9 +9,8 @@
#include <cstdio>
-RSoftwareBackend::RSoftwareBackend(SDL_Window* window, Renderer& renderer)
- : m_window {window}
- , m_renderer {renderer}
+RSoftwareBackend::RSoftwareBackend(Renderer& renderer)
+ : m_renderer {renderer}
{
m_canvas.rshift = 0;
m_canvas.gshift = 8;
@@ -53,21 +53,7 @@ RSoftwareBackend::Draw()
SortRenderEntities();
- REntity_Rectangle clear_rect = {
- REntityType_Rectangle,
- {0, 0, (float)(m_canvas.w-1), (float)(m_canvas.h-1)},
- 0.0f,
- m_renderer.m_clear_color
- };
- DrawRectangle(clear_rect);
-
-
- float z = -1;
for (RSortEntry sort_entry : m_renderer.m_sort_entries) {
- if (sort_entry.z >= z) {
- z = sort_entry.z;
- }
-
REntity& entity = m_renderer.m_render_entities[sort_entry.entity_index];
switch (entity.type) {
case REntityType_Rectangle: {
@@ -78,6 +64,13 @@ RSoftwareBackend::Draw()
DrawAlphaBitmap(entity.bitmap);
} break;
+ case REntityType_Text: {
+ DrawText(entity.text);
+ }; break;
+
+ case REntityType_Circle: {
+ }; break;
+
default:;
}
}
@@ -147,10 +140,10 @@ RSoftwareBackend::DrawRectangle(REntity_Rectangle& entity)
void
RSoftwareBackend::DrawAlphaBitmap(REntity_AlphaBitmap& entity)
{
- int32_t x0 = (int32_t)entity.pos.x;
- int32_t y0 = (int32_t)entity.pos.y;
- int32_t x1 = (int32_t)entity.pos.x + entity.bitmap.w - 1;
- int32_t y1 = (int32_t)entity.pos.y + entity.bitmap.h - 1;
+ int32_t x0 = m_renderer.WorldXToScreenX(entity.pos.x);
+ int32_t y0 = m_renderer.WorldYToScreenY(entity.pos.y);
+ int32_t x1 = x0 + entity.bitmap.w - 1;
+ int32_t y1 = y0 + entity.bitmap.h - 1;
int32_t cut_left = 0;
int32_t cut_bot = 0;
@@ -171,10 +164,6 @@ RSoftwareBackend::DrawAlphaBitmap(REntity_AlphaBitmap& entity)
}
- uint32_t rshift = m_canvas.rshift;
- uint32_t gshift = m_canvas.gshift;
- uint32_t bshift = m_canvas.bshift;
-
uint8_t* alpha_row = (uint8_t*)entity.bitmap.pixels.get() + (-cut_bot * entity.bitmap.w) + (-cut_left);
uint32_t* rgba_row = m_canvas.pixels + y0 * m_canvas.w + x0;
for (int32_t y = y0; y <= y1; y++) {
@@ -193,9 +182,9 @@ RSoftwareBackend::DrawAlphaBitmap(REntity_AlphaBitmap& entity)
float g1 = entity.color.g * alphaf;
float b1 = entity.color.b * alphaf;
- uint32_t r2 = uint32_t(r1 * 255.0f) << rshift;
- uint32_t g2 = uint32_t(g1 * 255.0f) << gshift;
- uint32_t b2 = uint32_t(b1 * 255.0f) << bshift;
+ uint32_t r2 = uint32_t(r1 * 255.0f) << m_canvas.rshift;
+ uint32_t g2 = uint32_t(g1 * 255.0f) << m_canvas.gshift;
+ uint32_t b2 = uint32_t(b1 * 255.0f) << m_canvas.bshift;
uint32_t rgba_result = r2 | g2 | b2;
*rgba = rgba_result;
@@ -209,3 +198,81 @@ RSoftwareBackend::DrawAlphaBitmap(REntity_AlphaBitmap& entity)
}
}
+void
+RSoftwareBackend::DrawText(REntity_Text& entity)
+{
+ int32_t xscreen = m_renderer.WorldXToScreenX(entity.pos.x);
+ int32_t yscreen = m_renderer.WorldYToScreenY(entity.pos.y);
+ for (char32_t ch : entity.text) {
+ Glyph& glyph = entity.font.GetGlyph(ch);
+
+ int32_t x = xscreen + glyph.xoff;
+ int32_t y = yscreen + glyph.yoff;
+ DrawTextGlyph(glyph, entity.color, x, y);
+
+ xscreen += glyph.xadvance;
+ }
+}
+
+void
+RSoftwareBackend::DrawTextGlyph(Glyph& glyph, Color color, int32_t xscreen, int32_t yscreen)
+{
+ int32_t x0 = xscreen;
+ int32_t y0 = yscreen;
+ int32_t x1 = x0 + glyph.bitmap.w - 1;
+ int32_t y1 = y0 + glyph.bitmap.h - 1;
+
+ int32_t cut_left = 0;
+ int32_t cut_bot = 0;
+
+ if (x0 < 0) {
+ cut_left = x0;
+ x0 = 0;
+ }
+ if (y0 < 0) {
+ cut_bot = y0;
+ y0 = 0;
+ }
+ if (x1 >= m_canvas.w) {
+ x1 = m_canvas.w - 1;
+ }
+ if (y1 >= m_canvas.h) {
+ y1 = m_canvas.h - 1;
+ }
+
+
+ uint8_t* alpha_row = (uint8_t*)glyph.bitmap.pixels.get() + (-cut_bot * glyph.bitmap.w) + (-cut_left);
+ uint32_t* rgba_row = m_canvas.pixels + y0 * m_canvas.w + x0;
+
+ for (int32_t y = y0; y <= y1; y++) {
+ uint8_t* alpha = alpha_row;
+ uint32_t* rgba = rgba_row;
+ for (int32_t x = x0; x <= x1; x++) {
+ if (*alpha == 0) {
+ alpha++;
+ rgba++;
+ continue;
+ }
+
+ float alphaf = *alpha / 255.0f;
+
+ float r1 = color.r * alphaf;
+ float g1 = color.g * alphaf;
+ float b1 = color.b * alphaf;
+
+ uint32_t r2 = uint32_t(r1 * 255.0f) << m_canvas.rshift;
+ uint32_t g2 = uint32_t(g1 * 255.0f) << m_canvas.gshift;
+ uint32_t b2 = uint32_t(b1 * 255.0f) << m_canvas.bshift;
+
+ uint32_t rgba_result = r2 | g2 | b2;
+ *rgba = rgba_result;
+
+ alpha++;
+ rgba++;
+ }
+
+ alpha_row += glyph.bitmap.w;
+ rgba_row += m_canvas.w;
+ }
+}
+
diff --git a/src/renderer/RSoftwareBackend.hpp b/src/renderer/RSoftwareBackend.hpp
index 89d6a52..3e5e17d 100644
--- a/src/renderer/RSoftwareBackend.hpp
+++ b/src/renderer/RSoftwareBackend.hpp
@@ -16,11 +16,19 @@ public:
uint32_t* pixels;
};
+ struct DestRect {
+ int32_t x0;
+ int32_t y0;
+ int32_t x1;
+ int32_t y1;
+ };
+
public:
- RSoftwareBackend(SDL_Window* window, Renderer& renderer);
+ RSoftwareBackend(Renderer& renderer);
void Draw();
+ void Clear(Color color);
private:
@@ -29,10 +37,11 @@ private:
void DrawRectangle(REntity_Rectangle& entity);
void DrawAlphaBitmap(REntity_AlphaBitmap& entity);
+ void DrawText(REntity_Text& entity);
+ void DrawTextGlyph(Glyph& glyph, Color color, int32_t xscreen, int32_t yscreen);
private:
- SDL_Window* m_window{};
Renderer& m_renderer;
uint32_t m_gltexture_id{};
diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp
index 4e449ba..956c488 100644
--- a/src/renderer/Renderer.cpp
+++ b/src/renderer/Renderer.cpp
@@ -13,16 +13,10 @@ Renderer g_renderer;
void
Renderer::Init(SDL_Window* window)
{
+ m_window = window;
m_render_entities.reserve(1024);
m_sort_entries.reserve(1024);
-
- m_backend = std::make_unique<RSoftwareBackend>(window, *this);
-}
-
-void
-Renderer::Draw()
-{
- m_backend->Draw();
+ m_backend = std::make_unique<RSoftwareBackend>(*this);
}
void
@@ -30,12 +24,16 @@ Renderer::Reset()
{
m_render_entities.clear();
m_sort_entries.clear();
- m_render_entities.reserve(1024);
- m_sort_entries.reserve(1024);
SetCameraSize(0.0f, 0.0f);
}
void
+Renderer::Draw()
+{
+ m_backend->Draw();
+}
+
+void
Renderer::SetScreenSize(int32_t w, int32_t h)
{
m_screen_w = w;
@@ -66,7 +64,13 @@ Renderer::WorldYToScreenY(float world_y)
void
Renderer::Clear(Color color)
{
- m_clear_color = color;
+ Rectangle rect = {
+ 0.0f,
+ 0.0f,
+ m_camera_w,
+ m_camera_h
+ };
+ PushRectangle(rect, color, -1.0f);
}
void
@@ -74,37 +78,48 @@ Renderer::PushAlphaBitmap(AlphaBitmap& bitmap, V3F32 pos, Color color)
{
m_render_entities.emplace_back(REntity{.bitmap{
REntityType_AlphaBitmap,
- pos,
bitmap,
+ pos,
color
}});
m_sort_entries.emplace_back(pos.z, m_render_entities.size()-1);
}
void
-Renderer::PushRectangle(Rectangle rect, float z, Color color)
+Renderer::PushRectangle(Rectangle rect, Color color, float z)
{
m_render_entities.emplace_back(REntity{.rect{
REntityType_Rectangle,
rect,
- z,
color
}});
m_sort_entries.emplace_back(z, m_render_entities.size()-1);
}
void
-Renderer::PushCircle(Circle circle, float z, Color color)
+Renderer::PushCircle(Circle circle, Color color, float z)
{
m_render_entities.emplace_back(REntity{.circle{
REntityType_Circle,
circle,
- z,
color
}});
m_sort_entries.emplace_back(z, m_render_entities.size()-1);
}
+void
+Renderer::PushText(std::u32string& text, Font& font, V3F32 pos, Color color)
+{
+ m_render_entities.emplace_back(REntity{.text{
+ REntityType_Text,
+ text,
+ font,
+ pos,
+ color
+ }});
+ m_sort_entries.emplace_back(pos.z, m_render_entities.size()-1);
+}
+
/* temporary helper functions (from old RGroup api) */
diff --git a/src/renderer/Renderer.hpp b/src/renderer/Renderer.hpp
index b825681..515e1da 100644
--- a/src/renderer/Renderer.hpp
+++ b/src/renderer/Renderer.hpp
@@ -22,34 +22,44 @@ enum REntityType : int32_t {
REntityType_Rectangle,
REntityType_AlphaBitmap,
REntityType_Circle,
+ REntityType_Text,
};
+
struct REntity_AlphaBitmap {
REntityType type;
- V3F32 pos;
AlphaBitmap& bitmap;
+ V3F32 pos;
Color color;
};
struct REntity_Rectangle {
REntityType type;
Rectangle rect;
- float z;
Color color;
};
struct REntity_Circle {
REntityType type;
Circle circle;
- float z;
Color color;
};
+struct REntity_Text {
+ REntityType type;
+ std::u32string& text;
+ Font& font;
+ V3F32 pos;
+ Color color;
+};
+
+
union REntity {
REntityType type;
REntity_AlphaBitmap bitmap;
REntity_Rectangle rect;
REntity_Circle circle;
+ REntity_Text text;
};
struct RSortEntry {
@@ -69,9 +79,10 @@ public:
void Reset();
void Clear(Color color);
- void PushRectangle(Rectangle rect, float z, Color color);
void PushAlphaBitmap(AlphaBitmap& bitmap, V3F32 pos, Color color);
- void PushCircle(Circle circle, float z, Color color);
+ void PushRectangle(Rectangle rect, Color color, float z);
+ void PushCircle(Circle circle, Color color, float z);
+ void PushText(std::u32string& text, Font& font, V3F32 pos, Color color);
/* helper functions */
@@ -98,6 +109,8 @@ public:
public:
+ SDL_Window* m_window;
+
int32_t m_screen_w;
int32_t m_screen_h;