#include "DrawContext.h" #include "FrameBuffer.h" #include "DepthBuffer.h" #include "Rasterizer.h" #include "TriangleRasterizer.h" #include "Display.h" #include namespace Gfx { DrawContext::DrawContext(int32_t width, int32_t height) { frameBuffer = new Core::FrameBuffer(width, height); depthBuffer = new Core::DepthBuffer(width, height); rasterizer = new Rasterizer::Rasterizer(frameBuffer, depthBuffer); triangleRasterizer = new Rasterizer::TriangleRasterizer(frameBuffer, depthBuffer); } DrawContext::~DrawContext() { delete triangleRasterizer; delete rasterizer; delete depthBuffer; delete frameBuffer; } int32_t DrawContext::get_width() const { return frameBuffer->get_width(); } int32_t DrawContext::get_height() const { return frameBuffer->get_height(); } void DrawContext::clear(const RenderData::Color& color) { frameBuffer->clear(color); depthBuffer->clear(); } void DrawContext::clear_depth() { depthBuffer->clear(); } void DrawContext::draw_line(const Math::Vector2Int& from, const Math::Vector2Int& to, const RenderData::Color& color) { rasterizer->DrawLine(from, to, color); } void DrawContext::draw_triangle(const RenderData::Triangle& triangle, const RenderData::Color& color) { triangleRasterizer->DrawTriangle2D(triangle, color); } void DrawContext::draw_sprite(int32_t dst_x, int32_t dst_y, const RenderData::Image& img) { draw_sprite_region(dst_x, dst_y, img, 0, 0, img.width, img.height); } void DrawContext::draw_sprite_region(int32_t dst_x, int32_t dst_y, const RenderData::Image& img, int32_t src_x, int32_t src_y, int32_t src_w, int32_t src_h) { draw_sprite_ex(dst_x, dst_y, img, src_x, src_y, src_w, src_h, 1, false, false); } void DrawContext::draw_sprite_ex(int32_t dst_x, int32_t dst_y, const RenderData::Image& img, int32_t src_x, int32_t src_y, int32_t src_w, int32_t src_h, int32_t scale, bool flip_h, bool flip_v) { if (scale < 1 || !img.pixels) return; const int32_t img_w = img.width; const uint32_t* src = img.pixels; const bool has_key = img.has_color_key; const uint32_t key = img.color_key; for (int32_t sy = 0; sy < src_h; ++sy) { const int32_t read_y = flip_v ? (src_y + src_h - 1 - sy) : (src_y + sy); const uint32_t* row = src + read_y * img_w; for (int32_t sx = 0; sx < src_w; ++sx) { const int32_t read_x = flip_h ? (src_x + src_w - 1 - sx) : (src_x + sx); const uint32_t pixel = row[read_x]; if (has_key && pixel == key) continue; const int32_t base_x = dst_x + sx * scale; const int32_t base_y = dst_y + sy * scale; if (scale == 1) { frameBuffer->set_pixel(base_x, base_y, pixel); } else { for (int32_t dy = 0; dy < scale; ++dy) { for (int32_t dx = 0; dx < scale; ++dx) { frameBuffer->set_pixel(base_x + dx, base_y + dy, pixel); } } } } } } void DrawContext::fill_rect(int32_t x, int32_t y, int32_t w, int32_t h, const RenderData::Color& color) { const uint32_t rgba = color.to_rgba(); for (int32_t row = y; row < y + h; ++row) { for (int32_t col = x; col < x + w; ++col) { frameBuffer->set_pixel(col, row, rgba); } } } void DrawContext::draw_text(const RenderData::BitmapFont& font, int32_t x, int32_t y, const RenderData::Color& color, const char* text) { if (!font.atlas.pixels || !text) return; const uint32_t rgba = color.to_rgba(); const int32_t cw = font.char_w; const int32_t ch = font.char_h; const int32_t atlas_w = font.atlas.width; const uint32_t* src = font.atlas.pixels; int32_t cursor_x = x; for (const char* p = text; *p; ++p) { const int32_t index = static_cast(*p) - font.first_char; if (index < 0) { cursor_x += cw; continue; } const int32_t col = index % font.columns; const int32_t row = index / font.columns; const int32_t src_x = col * cw; const int32_t src_y = row * ch; for (int32_t sy = 0; sy < ch; ++sy) { const uint32_t* atlas_row = src + (src_y + sy) * atlas_w; const int32_t dst_y_abs = y + sy; for (int32_t sx = 0; sx < cw; ++sx) { const uint32_t pixel = atlas_row[src_x + sx]; if ((pixel & 0xFF) == 0) continue; frameBuffer->set_pixel(cursor_x + sx, dst_y_abs, rgba); } } cursor_x += cw; } } void DrawContext::draw_text(const RenderData::BitmapFont& font, int32_t x, int32_t y, const RenderData::Color& color, const RenderData::Color& bg_color, const char* text) { if (!text) return; int32_t len = 0; for (const char* p = text; *p; ++p) ++len; fill_rect(x, y, len * font.char_w, font.char_h, bg_color); draw_text(font, x, y, color, text); } void DrawContext::present(Platform::IDisplay* display) { display->present(frameBuffer); } }