From 9d72ed2d5801b1506158082f08bd0b47e58db17f Mon Sep 17 00:00:00 2001 From: fschildt Date: Mon, 29 Sep 2025 13:20:43 +0200 Subject: renderer: major refactor; vectors: now aggregates --- src/renderer/RSoftwareBackend.cpp | 210 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 src/renderer/RSoftwareBackend.cpp (limited to 'src/renderer/RSoftwareBackend.cpp') 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 + +#include +#include + +#include +#include +#include + + +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; + } +} + -- cgit v1.2.3