179 lines
4.8 KiB
C++
179 lines
4.8 KiB
C++
#include "DrawContext.h"
|
|
#include "FrameBuffer.h"
|
|
#include "DepthBuffer.h"
|
|
#include "Rasterizer.h"
|
|
#include "TriangleRasterizer.h"
|
|
#include "Display.h"
|
|
#include <algorithm>
|
|
|
|
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<int32_t>(*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);
|
|
}
|
|
}
|