diff options
| author | fschildt <florian.schildt@protonmail.com> | 2025-09-29 13:20:43 +0200 | 
|---|---|---|
| committer | fschildt <florian.schildt@protonmail.com> | 2025-09-29 13:20:43 +0200 | 
| commit | 9d72ed2d5801b1506158082f08bd0b47e58db17f (patch) | |
| tree | 1fe30ab6dae55db5a3faaac6b8d54f67a31255d3 /src/renderer/RSoftwareBackend.cpp | |
| parent | d793b79dea7d5e19982128528276cf05d6c23b5d (diff) | |
renderer: major refactor; vectors: now aggregates
Diffstat (limited to 'src/renderer/RSoftwareBackend.cpp')
| -rw-r--r-- | src/renderer/RSoftwareBackend.cpp | 210 | 
1 files changed, 210 insertions, 0 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; +    } +} +  | 
