summaryrefslogtreecommitdiff
path: root/lib/nes/app/graphics/renderer.cc
blob: 8d1a16860f300dc7f51e9b1539a92ed7df728eba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "nes/app/graphics/renderer.hh"
#include "nes/app/graphics/color.hh"
#include "nes/app/graphics/mask-tile.hh"
#include "nes/app/graphics/image-tile.hh"
#include "nes/app/graphics/image-view.hh"
#include "nes/common/display.hh"

namespace nes::app
{
	renderer::renderer(display& display)
		: display_{ display }
	{
	}

	auto renderer::render_image_tile(unsigned const x, unsigned const y, image_tile const tile) -> void
	{
		if (x >= width || y >= height) { return; }

		for (auto y_px = unsigned{ 0 }; y_px < 8; ++y_px)
		{
			for (auto x_px = unsigned{ 0 }; x_px < 8; ++x_px)
			{
				auto const c = tile.data[y_px * 8 + x_px];
				if (c != color::transparent)
				{
					display_.set(8 * x + x_px, 8 * y + y_px, resolve_color(c));
				}
			}
		}
	}

	auto renderer::render_mask_tile(unsigned const x, unsigned const y, mask_tile const tile, color const c) -> void
	{
		if (c == color::transparent) { return; }
		if (x >= width || y >= height) { return; }

		auto const resolved = resolve_color(c);
		for (auto y_px = unsigned{ 0 }; y_px < 8; ++y_px)
		{
			auto row = tile.data[y_px];
			for (auto x_px = unsigned{ 0 }; x_px < 8; ++x_px)
			{
				if (row & 0b10000000)
				{
					display_.set(8 * x + x_px, 8 * y + y_px, resolved);
				}
				row <<= 1;
			}
		}
	}

	auto renderer::render_image(unsigned const x, unsigned const y, image_view const image) -> void
	{
		for (auto y_img = unsigned{ 0 }; y_img < image.get_height(); ++y_img)
		{
			for (auto x_img = unsigned{ 0 }; x_img < image.get_width(); ++x_img)
			{
				render_image_tile(x + x_img, y + y_img, image.get(x, y));
			}
		}
	}

	auto renderer::render_rect(
		unsigned const x, unsigned const y, unsigned const width, unsigned const height, color const c) -> void
	{
		if (c == color::transparent) { return; }
		if (x >= width || y >= height) { return; }

		auto const resolved = resolve_color(c);
		auto const x_stop = std::min(x + width, renderer::width);
		auto const y_stop = std::min(y + height, renderer::height);
		for (auto y_px = unsigned{ y * 8 }; y_px < y_stop * 8; ++y_px)
		{
			for (auto x_px = unsigned{ x * 8 }; x_px < x_stop * 8; ++x_px)
			{
				display_.set(x_px, y_px, resolved);
			}
		}
	}

	auto renderer::render_fill(color const c) -> void
	{
		render_rect(0, 0, width, height, c);
	}

	auto renderer::resolve_color(color const c) const -> rgb
	{
		switch (c)
		{
			case color::transparent: break;
			case color::background_primary: return rgb::from_hex(0x004058);
			case color::background_secondary: return rgb::from_hex(0x002B3B);
			case color::foreground_primary: return rgb::from_hex(0xFCFCFC);
			case color::foreground_secondary: return rgb::from_hex(0x008888);
			case color::accent_primary: return rgb::from_hex(0xE45C10);
			case color::accent_secondary: return rgb::from_hex(0x881400);
			case color::fixed_white: return rgb::from_hex(0xFCFCFC);
			case color::fixed_gray: return rgb::from_hex(0xBCBCBC);
			case color::fixed_black: return rgb::from_hex(0x000000);
		}

		return rgb::from_hex(0x000000);
	}
} // namespace nes::app