#include "renderer/Renderer.hpp" #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_AlphaBitmap: { DrawAlphaBitmap(entity.bitmap); } 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& entity) { int32_t xmin = m_renderer.WorldXToScreenX(entity.rect.x0); int32_t ymin = m_renderer.WorldYToScreenY(entity.rect.y0); int32_t xmax = m_renderer.WorldXToScreenX(entity.rect.x1); int32_t ymax = m_renderer.WorldYToScreenY(entity.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)(entity.color.r * 255.0f); uint32_t g = (uint32_t)(entity.color.g * 255.0f); uint32_t b = (uint32_t)(entity.color.b * 255.0f); uint32_t val = r << rshift | g << gshift | b << bshift; *pixel++ = val; } } } 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 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* 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++) { 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 = entity.color.r * alphaf; 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 rgba_result = r2 | g2 | b2; *rgba = rgba_result; alpha++; rgba++; } alpha_row += entity.bitmap.w; rgba_row += m_canvas.w; } }