279 lines
7.0 KiB
C++
279 lines
7.0 KiB
C++
#include "Display.h"
|
|
#include "DrawContext.h"
|
|
#include "FrameBuffer.h"
|
|
#include "Image.h"
|
|
#include "SpriteAssetLoader.h"
|
|
#include "SdlPhotoSensor.h"
|
|
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace
|
|
{
|
|
class CaptureDisplay : public Platform::IDisplay
|
|
{
|
|
public:
|
|
const Core::FrameBuffer* framebuffer;
|
|
|
|
CaptureDisplay()
|
|
: framebuffer(nullptr)
|
|
{
|
|
}
|
|
|
|
bool init(int, int) override { return true; }
|
|
void present(const Core::FrameBuffer* fb) override { framebuffer = fb; }
|
|
void poll_events(bool&) override {}
|
|
void shutdown() override {}
|
|
};
|
|
|
|
const Core::FramePixel* PresentPixels(Core::DrawContext& ctx, CaptureDisplay& display)
|
|
{
|
|
ctx.present(&display);
|
|
assert(display.framebuffer != nullptr);
|
|
return static_cast<const Core::FramePixel*>(display.framebuffer->get_buffer());
|
|
}
|
|
|
|
void TestFramePixelIsRgb565()
|
|
{
|
|
static_assert(sizeof(Core::FramePixel) == sizeof(uint16_t), "FramePixel must stay RGB565");
|
|
assert(RenderData::rgba5551_to_rgb565(0xF801u) == 0xF800u);
|
|
assert(RenderData::rgba5551_to_rgb565(0x07C1u) == 0x07E0u);
|
|
assert(RenderData::rgba5551_to_rgb565(0x003Fu) == 0x001Fu);
|
|
}
|
|
|
|
void TestFrameBufferStoresRgb565()
|
|
{
|
|
Core::FrameBuffer framebuffer(2, 1);
|
|
framebuffer.clear(RenderData::Color(255, 0, 0, 255));
|
|
|
|
const Core::FramePixel* pixels = static_cast<const Core::FramePixel*>(framebuffer.get_buffer());
|
|
assert(pixels[0] == 0xF800u);
|
|
assert(pixels[1] == 0xF800u);
|
|
}
|
|
|
|
void TestImageDefaultsToRgba5551AndReturnsRawPixels()
|
|
{
|
|
const uint16_t default_pixels[] = { 0xF801u, 0x0000u };
|
|
RenderData::Image default_image(default_pixels, 1, 1);
|
|
assert(default_image.format == RenderData::PixelFormat::RGBA5551);
|
|
|
|
const uint16_t explicit_pixels[] = { 0x07C1u };
|
|
RenderData::Image explicit_image(
|
|
explicit_pixels,
|
|
1,
|
|
1,
|
|
RenderData::PixelFormat::RGBA5551);
|
|
assert(explicit_image.get_pixel(0, 0) == 0x07C1u);
|
|
}
|
|
|
|
void TestDrawSpriteUsesOneBitAlpha()
|
|
{
|
|
const uint16_t sprite_pixels[] = {
|
|
0xF800u,
|
|
0x07C1u
|
|
};
|
|
|
|
Core::DrawContext ctx(2, 1);
|
|
ctx.clear_color(RenderData::Color(0, 0, 255, 255));
|
|
|
|
RenderData::Image image(
|
|
sprite_pixels,
|
|
2,
|
|
1,
|
|
RenderData::PixelFormat::RGBA5551);
|
|
RenderData::Sprite sprite(&image, 0, 0, image.width, image.height);
|
|
ctx.draw_sprite(0, 0, sprite);
|
|
|
|
CaptureDisplay display;
|
|
ctx.present(&display);
|
|
assert(display.framebuffer != nullptr);
|
|
|
|
const Core::FramePixel* pixels =
|
|
static_cast<const Core::FramePixel*>(display.framebuffer->get_buffer());
|
|
assert(pixels[0] == 0x001Fu);
|
|
assert(pixels[1] == 0x07E0u);
|
|
}
|
|
|
|
void TestDrawSpriteUsesAtlasSubrect()
|
|
{
|
|
const uint16_t atlas_pixels[] = {
|
|
0xF801u,
|
|
0x07C1u
|
|
};
|
|
|
|
RenderData::Image atlas(
|
|
atlas_pixels,
|
|
2,
|
|
1,
|
|
RenderData::PixelFormat::RGBA5551);
|
|
RenderData::Sprite sprite(&atlas, 1, 0, 1, 1);
|
|
|
|
Core::DrawContext ctx(1, 1);
|
|
ctx.clear_color(RenderData::Color::Blue());
|
|
ctx.draw_sprite(0, 0, sprite);
|
|
|
|
CaptureDisplay display;
|
|
const Core::FramePixel* pixels = PresentPixels(ctx, display);
|
|
assert(pixels[0] == 0x07E0u);
|
|
}
|
|
|
|
void TestSpriteAssetLoaderRoundTripsRgba5551()
|
|
{
|
|
const std::string path = "render_pipeline_test.sprite";
|
|
const uint16_t original_pixels[] = {
|
|
0x0000u,
|
|
0xF801u,
|
|
0x07C1u,
|
|
0x003Fu
|
|
};
|
|
|
|
RenderData::Image original(
|
|
original_pixels,
|
|
2,
|
|
2,
|
|
RenderData::PixelFormat::RGBA5551);
|
|
assert(Asset::SpriteAssetLoader::Save(path, original));
|
|
|
|
std::vector<uint16_t> loaded_pixels;
|
|
RenderData::Image loaded;
|
|
const bool loaded_ok = Asset::SpriteAssetLoader::Load(path, loaded_pixels, loaded);
|
|
std::remove(path.c_str());
|
|
|
|
assert(loaded_ok);
|
|
assert(loaded.format == RenderData::PixelFormat::RGBA5551);
|
|
assert(loaded.width == 2);
|
|
assert(loaded.height == 2);
|
|
assert(loaded_pixels.size() == 4u);
|
|
for (size_t i = 0; i < loaded_pixels.size(); ++i)
|
|
{
|
|
assert(loaded_pixels[i] == original_pixels[i]);
|
|
}
|
|
}
|
|
|
|
void TestDrawTextUsesBitMaskAndColor()
|
|
{
|
|
const uint8_t glyph_mask[] = { 0x90u };
|
|
|
|
RenderData::BitmapFont font;
|
|
font.mask_bits = glyph_mask;
|
|
font.atlas_width = 2;
|
|
font.atlas_height = 2;
|
|
font.char_w = 2;
|
|
font.char_h = 2;
|
|
font.columns = 1;
|
|
font.first_char = 'A';
|
|
|
|
Core::DrawContext ctx(2, 2);
|
|
ctx.clear_color(RenderData::Color::Black());
|
|
ctx.draw_text(font, 0, 0, RenderData::Color::Red(), "A");
|
|
|
|
CaptureDisplay display;
|
|
const Core::FramePixel* pixels = PresentPixels(ctx, display);
|
|
assert(pixels[0] == 0xF800u);
|
|
assert(pixels[1] == 0x0000u);
|
|
assert(pixels[2] == 0x0000u);
|
|
assert(pixels[3] == 0xF800u);
|
|
}
|
|
|
|
void TestDrawTextColorChangesPerCallAndBackgroundFill()
|
|
{
|
|
const uint8_t glyph_mask[] = { 0x90u };
|
|
|
|
RenderData::BitmapFont font;
|
|
font.mask_bits = glyph_mask;
|
|
font.atlas_width = 2;
|
|
font.atlas_height = 2;
|
|
font.char_w = 2;
|
|
font.char_h = 2;
|
|
font.columns = 1;
|
|
font.first_char = 'A';
|
|
|
|
Core::DrawContext ctx(4, 2);
|
|
ctx.clear_color(RenderData::Color::Black());
|
|
ctx.draw_text(font, 0, 0, RenderData::Color::White(), RenderData::Color::Blue(), "A");
|
|
ctx.draw_text(font, 2, 0, RenderData::Color::Green(), "A");
|
|
|
|
CaptureDisplay display;
|
|
const Core::FramePixel* pixels = PresentPixels(ctx, display);
|
|
assert(pixels[0] == 0xFFFFu);
|
|
assert(pixels[1] == 0x001Fu);
|
|
assert(pixels[2] == 0x07E0u);
|
|
assert(pixels[3] == 0x0000u);
|
|
assert(pixels[4] == 0x001Fu);
|
|
assert(pixels[5] == 0xFFFFu);
|
|
assert(pixels[6] == 0x0000u);
|
|
assert(pixels[7] == 0x07E0u);
|
|
}
|
|
|
|
void TestDrawTextClipsBitMaskToScreen()
|
|
{
|
|
const uint8_t glyph_mask[] = { 0x90u };
|
|
|
|
RenderData::BitmapFont font;
|
|
font.mask_bits = glyph_mask;
|
|
font.atlas_width = 2;
|
|
font.atlas_height = 2;
|
|
font.char_w = 2;
|
|
font.char_h = 2;
|
|
font.columns = 1;
|
|
font.first_char = 'A';
|
|
|
|
Core::DrawContext ctx(2, 2);
|
|
ctx.clear_color(RenderData::Color::Black());
|
|
ctx.draw_text(font, -1, -1, RenderData::Color::Green(), "A");
|
|
ctx.draw_text(font, 3, 3, RenderData::Color::Red(), "A");
|
|
|
|
CaptureDisplay display;
|
|
const Core::FramePixel* pixels = PresentPixels(ctx, display);
|
|
assert(pixels[0] == 0x07E0u);
|
|
assert(pixels[1] == 0x0000u);
|
|
assert(pixels[2] == 0x0000u);
|
|
assert(pixels[3] == 0x0000u);
|
|
}
|
|
|
|
void TestSdlPhotoSensorClampAndRange()
|
|
{
|
|
Platform::SdlPhotoSensor sensor;
|
|
assert(sensor.init());
|
|
|
|
sensor.set_range(100, 3000);
|
|
assert(sensor.read_level() >= 100);
|
|
assert(sensor.read_level() <= 3000);
|
|
|
|
sensor.set_level(50);
|
|
assert(sensor.read_level() == 100);
|
|
|
|
sensor.set_level(5000);
|
|
assert(sensor.read_level() == 3000);
|
|
|
|
sensor.set_level(1500);
|
|
assert(sensor.read_level() == 1500);
|
|
|
|
sensor.set_step(100);
|
|
assert(sensor.is_open());
|
|
|
|
sensor.shutdown();
|
|
assert(!sensor.is_open());
|
|
assert(sensor.read_level() == 2048);
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
TestFramePixelIsRgb565();
|
|
TestFrameBufferStoresRgb565();
|
|
TestImageDefaultsToRgba5551AndReturnsRawPixels();
|
|
TestDrawSpriteUsesOneBitAlpha();
|
|
TestDrawSpriteUsesAtlasSubrect();
|
|
TestSpriteAssetLoaderRoundTripsRgba5551();
|
|
TestDrawTextUsesBitMaskAndColor();
|
|
TestDrawTextColorChangesPerCallAndBackgroundFill();
|
|
TestDrawTextClipsBitMaskToScreen();
|
|
TestSdlPhotoSensorClampAndRange();
|
|
std::cout << "render_pipeline_tests: PASS\n";
|
|
return 0;
|
|
}
|