aboutsummaryrefslogtreecommitdiff
path: root/src/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/renderer')
-rw-r--r--src/renderer/RSoftwareBackend.cpp210
-rw-r--r--src/renderer/RSoftwareBackend.hpp41
-rw-r--r--src/renderer/RenderGroup.cpp106
-rw-r--r--src/renderer/RenderGroup.hpp84
-rw-r--r--src/renderer/Renderer.cpp311
-rw-r--r--src/renderer/Renderer.hpp110
6 files changed, 459 insertions, 403 deletions
diff --git a/src/renderer/RSoftwareBackend.cpp b/src/renderer/RSoftwareBackend.cpp
new file mode 100644
index 0000000..f0e2e5f
--- /dev/null
+++ b/src/renderer/RSoftwareBackend.cpp
@@ -0,0 +1,210 @@
+#include <renderer/RSoftwareBackend.hpp>
+
+#include <SDL3/SDL_video.h>
+#include <GL/glew.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstdio>
+
+
+RSoftwareBackend::RSoftwareBackend(SDL_Window* window, Renderer& renderer)
+ : m_window {window}
+ , m_renderer {renderer}
+{
+ m_canvas.rshift = 0;
+ m_canvas.gshift = 8;
+ m_canvas.bshift = 16;
+ m_canvas.ashift = 24;
+ m_canvas.pixels = nullptr;
+
+
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenTextures(1, &m_gltexture_id);
+ glBindTexture(GL_TEXTURE_2D, m_gltexture_id);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+}
+
+void
+RSoftwareBackend::ResizeCanvas(int32_t w, int32_t h)
+{
+ size_t realloc_size = (size_t)(w * h) * sizeof(m_canvas.pixels[0]);
+ void *realloc_data = realloc(m_canvas.pixels, realloc_size);
+ if (!realloc_data) {
+ printf("could not resize offscreen buffer\n");
+ return;
+ }
+
+ m_canvas.w = w;
+ m_canvas.h = h;
+ m_canvas.pixels = (uint32_t*)realloc_data;
+}
+
+void
+RSoftwareBackend::Draw()
+{
+ ResizeCanvas(m_renderer.m_screen_w, m_renderer.m_screen_h);
+ 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: {
+ DrawRectangle(entity.rect);
+ } break;
+
+ case REntityType_MonoBitmap: {
+ Color color = {0.0f, 0.0f, 0.0f, 1.0f};
+ DrawMonoBitmap(entity.bitmap, color);
+ } break;
+
+ default:;
+ }
+ }
+
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_gltexture_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_canvas.w, m_canvas.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_canvas.pixels);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
+ glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);
+ glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f);
+ glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
+ glEnd();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void
+RSoftwareBackend::SortRenderEntities()
+{
+ auto& sort_entries = m_renderer.m_sort_entries;
+ std::sort(sort_entries.begin(), sort_entries.end(),
+ [](const RSortEntry& e1, const RSortEntry& e2) {
+ return e1.z < e2.z;
+ });
+}
+
+void
+RSoftwareBackend::DrawRectangle(REntity_Rectangle& rect)
+{
+ int32_t xmin = m_renderer.WorldXToScreenX(rect.x0);
+ int32_t ymin = m_renderer.WorldYToScreenY(rect.y0);
+ int32_t xmax = m_renderer.WorldXToScreenX(rect.x1);
+ int32_t ymax = m_renderer.WorldYToScreenY(rect.y1);
+
+ if (xmin < 0) {
+ xmin = 0;
+ }
+ if (ymin < 0) {
+ ymin = 0;
+ }
+ if (xmax >= m_canvas.w) {
+ xmax = m_canvas.w - 1;
+ }
+ if (ymax >= m_canvas.h) {
+ ymax = m_canvas.h - 1;
+ }
+
+ uint32_t rshift = m_canvas.rshift;
+ uint32_t gshift = m_canvas.gshift;
+ uint32_t bshift = m_canvas.bshift;
+ for (int32_t y = ymin; y <= ymax; ++y) {
+ uint32_t *pixel = m_canvas.pixels + y * m_canvas.w + xmin;
+ for (int32_t x = xmin; x <= xmax; ++x) {
+ uint32_t r = (uint32_t)(rect.color.r * 255.0f);
+ uint32_t g = (uint32_t)(rect.color.g * 255.0f);
+ uint32_t b = (uint32_t)(rect.color.b * 255.0f);
+ uint32_t val = r << rshift | g << gshift | b << bshift;
+ *pixel++ = val;
+ }
+ }
+}
+
+
+void
+RSoftwareBackend::DrawMonoBitmap(REntity_MonoBitmap& mono_bitmap, Color color)
+{
+ int32_t x0 = (int32_t)mono_bitmap.x;
+ int32_t y0 = (int32_t)mono_bitmap.y;
+ int32_t x1 = (int32_t)mono_bitmap.x + mono_bitmap.w - 1;
+ int32_t y1 = (int32_t)mono_bitmap.y + mono_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;
+ }
+
+
+ uint32_t rshift = m_canvas.rshift;
+ uint32_t gshift = m_canvas.gshift;
+ uint32_t bshift = m_canvas.bshift;
+
+ uint8_t* grayscale = (uint8_t*)mono_bitmap.data + (-cut_bot * mono_bitmap.w) + (-cut_left);
+ uint32_t* rgba = m_canvas.pixels + y0 * m_canvas.w + x0;
+ for (int32_t y = y0; y <= y1; y++) {
+ uint8_t *grayscale_pixels = grayscale;
+ uint32_t *rgba_pixels = rgba;
+ for (int32_t x = x0; x <= x1; x++) {
+ float alpha = *grayscale_pixels / 255.0f;
+
+ // Todo: we do not want to blend with existing color!
+
+ uint32_t rgba_result = *rgba_pixels;
+ float r0 = (rgba_result >> rshift) & 0xff;
+ float g0 = (rgba_result >> gshift) & 0xff;
+ float b0 = (rgba_result >> bshift) & 0xff;
+
+ float r1 = r0 + (color.r - r0)*alpha;
+ float g1 = g0 + (color.g - g0)*alpha;
+ float b1 = b0 + (color.b - b0)*alpha;
+
+ rgba_result = (uint32_t)r1 << rshift | (uint32_t)g1 << gshift | (uint32_t)b1 << bshift;
+ *rgba_pixels = rgba_result;
+
+ grayscale_pixels++;
+ rgba_pixels++;
+ }
+
+ grayscale += mono_bitmap.w;
+ rgba += m_canvas.w;
+ }
+}
+
diff --git a/src/renderer/RSoftwareBackend.hpp b/src/renderer/RSoftwareBackend.hpp
new file mode 100644
index 0000000..5457c7e
--- /dev/null
+++ b/src/renderer/RSoftwareBackend.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <SDL3/SDL.h>
+#include <renderer/Renderer.hpp>
+
+
+class RSoftwareBackend {
+public:
+ struct Canvas {
+ uint32_t rshift;
+ uint32_t gshift;
+ uint32_t bshift;
+ uint32_t ashift;
+ int32_t w;
+ int32_t h;
+ uint32_t *pixels;
+ };
+
+
+public:
+ RSoftwareBackend(SDL_Window* window, Renderer& renderer);
+
+ void Draw();
+
+
+private:
+ void ResizeCanvas(int32_t w, int32_t h);
+ void SortRenderEntities();
+
+ void DrawRectangle(REntity_Rectangle& rect);
+ void DrawMonoBitmap(REntity_MonoBitmap& mono_bitmap, Color color);
+
+
+private:
+ SDL_Window* m_window{};
+ Renderer& m_renderer;
+
+ uint32_t m_gltexture_id{};
+ Canvas m_canvas;
+};
+
diff --git a/src/renderer/RenderGroup.cpp b/src/renderer/RenderGroup.cpp
deleted file mode 100644
index e393393..0000000
--- a/src/renderer/RenderGroup.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include <renderer/RenderGroup.hpp>
-#include <algorithm>
-
-RSortEntry::RSortEntry(float z, size_t entity_index)
- : z(z), entity_index(entity_index) {
-}
-
-RenderGroup::RenderGroup() {
- m_REntities.reserve(1024);
- m_RSortEntries.reserve(1024);
-}
-
-void RenderGroup::Reset() {
- m_CameraWidth = 0;
- m_CameraHeight = 0;
- m_REntities.clear();
- m_RSortEntries.clear();
- m_REntities.reserve(1024);
- m_RSortEntries.reserve(1024);
-}
-
-void RenderGroup::SetCameraSize(float width, float height) {
- m_CameraWidth = width;
- m_CameraHeight = height;
-}
-
-float RenderGroup::GetScale() {
- float screen_width = static_cast<float>(m_ScreenWidth);
- float screen_height = static_cast<float>(m_ScreenHeight);
- float xunits = screen_width / m_CameraWidth;
- float yunits = screen_height / m_CameraHeight;
- float scale = std::min(xunits, yunits);
- return scale;
-}
-
-V2F32 RenderGroup::ViewPosToScreenPos(V2F32 view_pos) {
- float scale = GetScale();
- float screen_width = static_cast<float>(m_ScreenWidth);
- float screen_height = static_cast<float>(m_ScreenHeight);
- float viewport_width = m_CameraWidth * scale;
- float viewport_height = m_CameraHeight * scale;
- float viewport_x0 = (screen_width - viewport_width) / 2;
- float viewport_y0 = (screen_height - viewport_height) / 2;
-
- V2F32 result;
- result.x = viewport_x0 + view_pos.x * scale;
- result.y = screen_height - (viewport_y0 + view_pos.y * scale);
-
- return result;
-}
-
-V2F32 RenderGroup::ViewSizeToScreenSize(V2F32 view_size) {
- float scale = GetScale();
-
- V2F32 result;
- result.x = view_size.x * scale;
- result.y = view_size.y * scale;
-
- return result;
-}
-
-ImVec2 RenderGroup::ViewPosToScreenPosImGui(V2F32 view_pos) {
- V2F32 screen_pos = ViewPosToScreenPos(view_pos);
- ImVec2 result = {screen_pos.x, screen_pos.y};
- return result;
-}
-
-ImVec2 RenderGroup::ViewSizeToScreenSizeImGui(V2F32 view_size) {
- V2F32 screen_size = ViewSizeToScreenSize(view_size);
- ImVec2 result = {screen_size.x, screen_size.y};
- return result;
-}
-
-void RenderGroup::Clear(Color color) {
- m_ClearColor = color;
-}
-
-void RenderGroup::PushRectangle(RectF32 rect, float z, Color color) {
- m_REntities.emplace_back(REntity{.rect{
- REntityType_Rectangle,
- rect.x0, rect.y0,
- rect.x1, rect.y1,
- z,
- color}
- });
- m_RSortEntries.emplace_back(z, m_REntities.size()-1);
-}
-
-void RenderGroup::PushBitmap(V3F32 pos, int w, int h, void *data) {
- m_REntities.emplace_back(REntity{.bitmap{
- REntityType_Bitmap,
- pos.x, pos.y,
- w, h,
- pos.z,
- data
- }});
- m_RSortEntries.emplace_back(pos.z, m_REntities.size()-1);
-}
-
-void RenderGroup::Sort() {
- std::sort(m_RSortEntries.begin(), m_RSortEntries.end(),
- [](const RSortEntry& e1, const RSortEntry& e2) {
- return e1.z < e2.z;
- });
-}
-
diff --git a/src/renderer/RenderGroup.hpp b/src/renderer/RenderGroup.hpp
deleted file mode 100644
index ddaa9ff..0000000
--- a/src/renderer/RenderGroup.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-
-#include <basic/defs.hpp>
-#include <basic/math.hpp>
-#include <vector>
-#include <imgui.h>
-
-enum REntityType : int32_t {
- REntityType_Rectangle,
- REntityType_Bitmap,
-};
-
-struct REntity_Rectangle {
- REntityType type;
- float x0;
- float y0;
- float x1;
- float y1;
- float z;
- Color color;
-};
-
-struct REntity_Bitmap {
- REntityType type;
- float x;
- float y;
- int32_t w;
- int32_t h;
- float z;
- void *data;
-};
-
-union REntity {
- REntityType type;
- REntity_Rectangle rect;
- REntity_Bitmap bitmap;
-};
-
-struct RSortEntry {
- RSortEntry(float z, size_t entity_index);
- float z;
- size_t entity_index;
-};
-
-
-class RenderGroup {
-public:
- RenderGroup();
- void Clear(Color color);
- void Reset();
-
- void SetCameraSize(float width, float height);
- V2F32 ViewPosToScreenPos(V2F32 view_pos);
- V2F32 ViewSizeToScreenSize(V2F32 view_size);
- ImVec2 ViewPosToScreenPosImGui(V2F32 view_pos);
- ImVec2 ViewSizeToScreenSizeImGui(V2F32 view_size);
- float GetScale();
-
-
-public:
- void PushRectangle(RectF32 rect, float z, Color color);
- void PushBitmap(V3F32 pos, int w, int h, void *bitmap);
- void Sort();
-
-
-public:
- int32_t m_ScreenWidth;
- int32_t m_ScreenHeight;
-
-
-private:
- friend class Renderer;
-
- float m_CameraWidth;
- float m_CameraHeight;
-
-
- Color m_ClearColor;
-
- std::vector<REntity> m_REntities;
- std::vector<RSortEntry> m_RSortEntries;
-};
-
-
diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp
index 9217f5c..413b3cb 100644
--- a/src/renderer/Renderer.cpp
+++ b/src/renderer/Renderer.cpp
@@ -1,233 +1,158 @@
#include <renderer/Renderer.hpp>
+#include <renderer/RSoftwareBackend.hpp>
+
#include <GL/glew.h>
+#include <imgui.h>
-#include <cstdio>
-#include <cstdlib>
+#include <memory>
-Renderer::Renderer(SDL_Window *window) : m_Window(window), m_Canvas{}
-{
-}
+Renderer g_renderer;
-bool
-Renderer::Init()
+void
+Renderer::Init(SDL_Window* window)
{
- GLenum err = glewInit();
- if (err) {
- printf("glewInit() error\n");
- return false;
- }
-
- int32_t window_width;
- int32_t window_height;
- if (!SDL_GetWindowSize(m_Window, &window_width, &window_height)) {
- printf("Error: SDL_GetWindowSize: %s\n", SDL_GetError());
- return false;
- }
-
-
- m_Canvas.rshift = 0;
- m_Canvas.gshift = 8;
- m_Canvas.bshift = 16;
- m_Canvas.ashift = 24;
- ResizeCanvas(window_width, window_height);
+ m_render_entities.reserve(1024);
+ m_sort_entries.reserve(1024);
+ m_backend = std::make_unique<RSoftwareBackend>(window, *this);
+}
- glEnable(GL_TEXTURE_2D);
- glActiveTexture(GL_TEXTURE0);
+void
+Renderer::Draw()
+{
+ m_backend->Draw();
+}
- glGenTextures(1, &m_GlTexId);
- glBindTexture(GL_TEXTURE_2D, m_GlTexId);
+void
+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);
+}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+void
+Renderer::SetScreenSize(int32_t w, int32_t h)
+{
+ m_screen_w = w;
+ m_screen_h = h;
+}
+void
+Renderer::SetCameraSize(float w, float h)
+{
+ m_camera_w = w;
+ m_camera_h = h;
+}
- return true;
+int32_t
+Renderer::WorldXToScreenX(float world_x)
+{
+ float screen_x = (world_x / m_camera_w) * (float)m_screen_w;
+ return (int32_t)screen_x;
}
+int32_t
+Renderer::WorldYToScreenY(float world_y)
+{
+ float screen_y = (world_y / m_camera_h) * (float)m_screen_h;
+ return (int32_t)screen_y;
+}
void
-Renderer::ResizeCanvas(int32_t w, int32_t h)
+Renderer::Clear(Color color)
{
- size_t realloc_size = (size_t)(w * h) * sizeof(m_Canvas.pixels[0]);
- void *realloc_data = realloc(m_Canvas.pixels, realloc_size);
- if (!realloc_data) {
- printf("could not resize offscreen buffer\n");
- return;
- }
-
- m_Canvas.w = w;
- m_Canvas.h = h;
- m_Canvas.pixels = (uint32_t*)realloc_data;
+ m_clear_color = color;
}
-
void
-Renderer::Draw(RenderGroup& rgroup)
+Renderer::PushRectangle(RectF32 rect, float z, Color color)
{
- rgroup.Sort();
- REntity_Rectangle clear_rect = {
- REntityType_Rectangle,
- 0, 0,
- (float)(m_Canvas.w-1), (float)(m_Canvas.h-1),
- 0.0f,
- rgroup.m_ClearColor
- };
- DrawRectangle(rgroup, clear_rect);
-
-
- float z = -1;
- for (RSortEntry sort_entry : rgroup.m_RSortEntries) {
- if (sort_entry.z >= z) {
- z = sort_entry.z;
- }
-
- REntity& entity = rgroup.m_REntities[sort_entry.entity_index];
- switch (entity.type) {
- case REntityType_Rectangle: {
- DrawRectangle(rgroup, entity.rect);
- } break;
-
- case REntityType_Bitmap: {
- Color color = {0.0f, 0.0f, 0.0f, 1.0f};
- DrawMonoBitmap(entity.bitmap, color);
- } break;
-
- default:;
- }
- }
-
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_GlTexId);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Canvas.w, m_Canvas.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_Canvas.pixels);
-
- glBegin(GL_QUADS);
- glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
- glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);
- glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
- glEnd();
-
- glBindTexture(GL_TEXTURE_2D, 0);
+ m_render_entities.emplace_back(REntity{.rect{
+ REntityType_Rectangle,
+ rect.x0, rect.y0,
+ rect.x1, rect.y1,
+ z,
+ color}
+ });
+ m_sort_entries.emplace_back(z, m_render_entities.size()-1);
}
-
void
-Renderer::DrawRectangle(RenderGroup& rgroup, REntity_Rectangle& rect)
+Renderer::PushMonoBitmap(V3F32 pos, int w, int h, void *data)
{
- int32_t xmin = WorldXToScreenX(rgroup, rect.x0);
- int32_t ymin = WorldYToScreenY(rgroup, rect.y0);
- int32_t xmax = WorldXToScreenX(rgroup, rect.x1);
- int32_t ymax = WorldYToScreenY(rgroup, rect.y1);
-
- if (xmin < 0) {
- xmin = 0;
- }
- if (ymin < 0) {
- ymin = 0;
- }
- if (xmax >= m_Canvas.w) {
- xmax = m_Canvas.w - 1;
- }
- if (ymax >= m_Canvas.h) {
- ymax = m_Canvas.h - 1;
- }
-
- uint32_t rshift = m_Canvas.rshift;
- uint32_t gshift = m_Canvas.gshift;
- uint32_t bshift = m_Canvas.bshift;
- for (int32_t y = ymin; y <= ymax; ++y) {
- uint32_t *pixel = m_Canvas.pixels + y * m_Canvas.w + xmin;
- for (int32_t x = xmin; x <= xmax; ++x) {
- uint32_t r = (uint32_t)(rect.color.r * 255.0f);
- uint32_t g = (uint32_t)(rect.color.g * 255.0f);
- uint32_t b = (uint32_t)(rect.color.b * 255.0f);
- uint32_t val = r << rshift | g << gshift | b << bshift;
- *pixel++ = val;
- }
- }
+ m_render_entities.emplace_back(REntity{.bitmap{
+ REntityType_MonoBitmap,
+ pos.x, pos.y,
+ w, h,
+ pos.z,
+ data
+ }});
+ m_sort_entries.emplace_back(pos.z, m_render_entities.size()-1);
}
-void
-Renderer::DrawMonoBitmap(REntity_Bitmap& bitmap, Color color)
+
+/* temporary helper functions (from old RGroup api) */
+
+float
+Renderer::GetScale()
{
- int32_t x0 = (int32_t)bitmap.x;
- int32_t y0 = (int32_t)bitmap.y;
- int32_t x1 = (int32_t)bitmap.x + bitmap.w - 1;
- int32_t y1 = (int32_t)bitmap.y + 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;
- }
-
-
- uint32_t rshift = m_Canvas.rshift;
- uint32_t gshift = m_Canvas.gshift;
- uint32_t bshift = m_Canvas.bshift;
-
- uint8_t* grayscale = (uint8_t*)bitmap.data + (-cut_bot * bitmap.w) + (-cut_left);
- uint32_t* rgba = m_Canvas.pixels + y0 * m_Canvas.w + x0;
- for (int32_t y = y0; y <= y1; y++) {
- uint8_t *grayscale_pixels = grayscale;
- uint32_t *rgba_pixels = rgba;
- for (int32_t x = x0; x <= x1; x++) {
- float alpha = *grayscale_pixels / 255.0f;
-
- // Todo: we do not want to blend with existing color!
-
- uint32_t rgba_result = *rgba_pixels;
- float r0 = (rgba_result >> rshift) & 0xff;
- float g0 = (rgba_result >> gshift) & 0xff;
- float b0 = (rgba_result >> bshift) & 0xff;
-
- float r1 = r0 + (color.r - r0)*alpha;
- float g1 = g0 + (color.g - g0)*alpha;
- float b1 = b0 + (color.b - b0)*alpha;
-
- rgba_result = (uint32_t)r1 << rshift | (uint32_t)g1 << gshift | (uint32_t)b1 << bshift;
- *rgba_pixels = rgba_result;
-
- grayscale_pixels++;
- rgba_pixels++;
- }
-
- grayscale += bitmap.w;
- rgba += m_Canvas.w;
- }
+ float screen_width = static_cast<float>(m_screen_w);
+ float screen_height = static_cast<float>(m_screen_h);
+ float xunits = screen_width / m_camera_w;
+ float yunits = screen_height / m_camera_h;
+ float scale = std::min(xunits, yunits);
+ return scale;
}
+V2F32
+Renderer::ViewPosToScreenPos(V2F32 view_pos)
+{
+ float scale = GetScale();
+ float screen_width = static_cast<float>(m_screen_w);
+ float screen_height = static_cast<float>(m_screen_h);
+ float viewport_width = m_camera_w * scale;
+ float viewport_height = m_camera_h * scale;
+ float viewport_x0 = (screen_width - viewport_width) / 2;
+ float viewport_y0 = (screen_height - viewport_height) / 2;
+
+ V2F32 result;
+ result.x = viewport_x0 + view_pos.x * scale;
+ result.y = screen_height - (viewport_y0 + view_pos.y * scale);
+
+ return result;
+}
-int32_t
-Renderer::WorldXToScreenX(RenderGroup& rgroup, float x)
+V2F32
+Renderer::ViewSizeToScreenSize(V2F32 view_size)
{
- float xscreen = (x / rgroup.m_CameraWidth) * (float)rgroup.m_ScreenWidth;
- return (int32_t)xscreen;
+ float scale = GetScale();
+
+ V2F32 result;
+ result.x = view_size.x * scale;
+ result.y = view_size.y * scale;
+
+ return result;
}
-int32_t
-Renderer::WorldYToScreenY(RenderGroup& rgroup, float y)
+ImVec2
+Renderer::ViewPosToScreenPosImGui(V2F32 view_pos)
+{
+ V2F32 screen_pos = ViewPosToScreenPos(view_pos);
+ ImVec2 result = {screen_pos.x, screen_pos.y};
+ return result;
+}
+
+ImVec2
+Renderer::ViewSizeToScreenSizeImGui(V2F32 view_size)
{
- float yscreen = (y / rgroup.m_CameraHeight) * (float)rgroup.m_ScreenHeight;
- return (int32_t)yscreen;
+ V2F32 screen_size = ViewSizeToScreenSize(view_size);
+ ImVec2 result = {screen_size.x, screen_size.y};
+ return result;
}
diff --git a/src/renderer/Renderer.hpp b/src/renderer/Renderer.hpp
index 24d4b71..4fdf524 100644
--- a/src/renderer/Renderer.hpp
+++ b/src/renderer/Renderer.hpp
@@ -1,41 +1,111 @@
#pragma once
#include <basic/math.hpp>
-#include <renderer/RenderGroup.hpp>
+
#include <SDL3/SDL.h>
#include <SDL3/SDL_video.h>
+#include <imgui.h>
+
+#include <vector>
+#include <memory>
+
+
+class RSoftwareBackend;
+class Renderer;
+
+extern Renderer g_renderer;
+
+
+enum REntityType : int32_t {
+ REntityType_Rectangle,
+ REntityType_MonoBitmap,
+};
-struct RCanvas {
- uint32_t rshift;
- uint32_t gshift;
- uint32_t bshift;
- uint32_t ashift;
+struct REntity_Rectangle {
+ REntityType type;
+ float x0;
+ float y0;
+ float x1;
+ float y1;
+ float z;
+ Color color;
+};
+
+struct REntity_MonoBitmap {
+ REntityType type;
+ float x;
+ float y;
int32_t w;
int32_t h;
- uint32_t *pixels;
+ float z;
+ void *data;
+};
+
+union REntity {
+ REntityType type;
+ REntity_Rectangle rect;
+ REntity_MonoBitmap bitmap;
+};
+
+struct RSortEntry {
+ float z;
+ size_t entity_index;
};
class Renderer {
public:
- Renderer(SDL_Window *window);
+ void Init(SDL_Window* window);
+
+
+ /* core functions */
+
+ void Draw();
+ void Reset();
+
+ void Clear(Color color);
+ void PushRectangle(RectF32 rect, float z, Color color);
+ void PushMonoBitmap(V3F32 pos, int w, int h, void* bitmap);
+
+
+ /* helper functions */
+
+ void SetScreenSize(int32_t w, int32_t h);
+ void SetCameraSize(float w, float h);
+
+
+ int32_t WorldXToScreenX(float x);
+ int32_t WorldYToScreenY(float y);
+
+ int32_t WorldWidthToScreenWidth(float w);
+ int32_t WorldHeightToScreenHeight(float h);
+
+
+ /* temporary helper functions (from old RGroup api) */
+ float GetScale();
+ V2F32 ViewPosToScreenPos(V2F32 view_pos);
+ V2F32 ViewSizeToScreenSize(V2F32 view_size);
+ ImVec2 ViewPosToScreenPosImGui(V2F32 view_pos);
+ ImVec2 ViewSizeToScreenSizeImGui(V2F32 view_size);
+
+
+
+ // Todo: make this private
+public:
+ int32_t m_screen_w;
+ int32_t m_screen_h;
- bool Init();
- void ResizeCanvas(int32_t w, int32_t h);
- void Draw(RenderGroup &render_group);
+ float m_camera_w;
+ float m_camera_h;
+ Color m_clear_color {};
+ std::vector<REntity> m_render_entities;
+ std::vector<RSortEntry> m_sort_entries;
-private:
- void DrawRectangle(RenderGroup& rgroup, REntity_Rectangle& rect);
- void DrawMonoBitmap(REntity_Bitmap& bitmap, Color color);
- int32_t WorldXToScreenX(RenderGroup& rgroup, float x);
- int32_t WorldYToScreenY(RenderGroup& rgroup, float y);
+ std::unique_ptr<RSoftwareBackend> m_backend;
-private:
- SDL_Window *m_Window;
- uint32_t m_GlTexId;
- RCanvas m_Canvas;
+ friend class RSoftwareBackend;
};