From f28e9c3e03a9f94764b3811f7c4aa01991943fc7 Mon Sep 17 00:00:00 2001 From: fschildt Date: Wed, 17 Sep 2025 15:30:21 +0200 Subject: switch to software renderer --- src/renderer/Renderer.cpp | 233 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 224 insertions(+), 9 deletions(-) (limited to 'src/renderer/Renderer.cpp') diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp index 13f5feb..9217f5c 100644 --- a/src/renderer/Renderer.cpp +++ b/src/renderer/Renderer.cpp @@ -1,18 +1,233 @@ #include -#include +#include +#include +#include -std::unique_ptr -Renderer::Select(Api api, SDL_Window *window) { - switch (api) { - case API_OPENGL: { - return std::make_unique(window); + +Renderer::Renderer(SDL_Window *window) : m_Window(window), m_Canvas{} +{ +} + + +bool +Renderer::Init() +{ + 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); + + + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + glGenTextures(1, &m_GlTexId); + glBindTexture(GL_TEXTURE_2D, m_GlTexId); + + 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); + + + return true; +} + + +void +Renderer::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 +Renderer::Draw(RenderGroup& rgroup) +{ + 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:; } - InvalidDefaultCase; } - return nullptr; + + 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); } -Renderer::~Renderer() {} +void +Renderer::DrawRectangle(RenderGroup& rgroup, REntity_Rectangle& rect) +{ + 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; + } + } +} + + +void +Renderer::DrawMonoBitmap(REntity_Bitmap& bitmap, Color color) +{ + 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; + } +} + + +int32_t +Renderer::WorldXToScreenX(RenderGroup& rgroup, float x) +{ + float xscreen = (x / rgroup.m_CameraWidth) * (float)rgroup.m_ScreenWidth; + return (int32_t)xscreen; +} + +int32_t +Renderer::WorldYToScreenY(RenderGroup& rgroup, float y) +{ + float yscreen = (y / rgroup.m_CameraHeight) * (float)rgroup.m_ScreenHeight; + return (int32_t)yscreen; +} + -- cgit v1.2.3