Current status of SDL.

This commit is contained in:
BadQuanta
2026-05-13 19:48:22 +00:00
parent 28e9c4ba18
commit 15bb051619
24 changed files with 1806 additions and 360 deletions
+9 -1
View File
@@ -1,15 +1,23 @@
add_executable(
hdk-sdl-tests
main.cpp
CoreBindings_test.cpp
Event_test.cpp
Properties_test.cpp
RenderTexture_test.cpp
VideoBindings_test.cpp
Window_test.cpp
Surface_test.cpp
)
if(HDK_COVERAGE)
target_sources(hdk-sdl-tests PRIVATE CoverageHeaderAggregation.cpp)
endif()
target_link_libraries(hdk-sdl-tests PRIVATE hdk-sdl doctest::doctest)
target_compile_features(hdk-sdl-tests PRIVATE cxx_std_17)
if(HDK_SDL_BUILD_COVERAGE AND TARGET hdk-coverage-flags)
if(HDK_COVERAGE AND TARGET hdk-coverage-flags)
target_link_libraries(hdk-sdl-tests PRIVATE hdk-coverage-flags)
endif()
+134
View File
@@ -0,0 +1,134 @@
#include <doctest/doctest.h>
#include <SDL3/SDL.h>
#include <hdk/sdl/Application.hpp>
#include <hdk/sdl/Log.hpp>
#include <hdk/sdl/pixels.hpp>
#include <hdk/sdl/video/Display.hpp>
#include <string>
#include "SDL_headless_fixture.hpp"
namespace {
void SDLCALL TestLogOutput(void* userdata, int category, SDL_LogPriority priority, const char* message) {
auto* callCount = static_cast<int*>(userdata);
if (callCount) {
++(*callCount);
}
(void)category;
(void)priority;
(void)message;
}
} // namespace
TEST_CASE("Core SDL bindings are exercised") {
SDLSession sdl;
if (!sdl.IsInitialized()) {
INFO(SDL_GetError());
CHECK(false);
return;
}
hdk::sdl::PublicApp app;
SDL_Event event {};
CHECK(app.Init(0, nullptr) == SDL_APP_CONTINUE);
CHECK(app.Event(&event) == SDL_APP_CONTINUE);
CHECK(app.Iterate() == SDL_APP_CONTINUE);
app.Quit(SDL_APP_SUCCESS);
int logCalls = 0;
hdk::sdl::Log::SetOutputFunction(TestLogOutput, &logCalls);
auto defaultOutput = hdk::sdl::Log::GetDefaultOutputFunction();
CHECK(defaultOutput != nullptr);
SDL_LogOutputFunction callback = nullptr;
void* userdata = nullptr;
hdk::sdl::Log::GetOutputFunction(&callback, &userdata);
CHECK(callback == TestLogOutput);
CHECK(userdata == &logCalls);
hdk::sdl::Log appLog(SDL_LOG_CATEGORY_APPLICATION);
hdk::sdl::Log::SetPriorities(SDL_LOG_PRIORITY_INFO);
appLog.SetPriority(SDL_LOG_PRIORITY_VERBOSE);
CHECK(appLog.GetPriority() >= SDL_LOG_PRIORITY_INVALID);
appLog.Critical("critical");
appLog.Debug("debug");
appLog.Error("error");
appLog.Info("info");
appLog.LogMessage(SDL_LOG_PRIORITY_WARN, "message");
appLog.Trace("trace");
appLog.Verbose("verbose");
appLog.Warn("warn");
CHECK(logCalls > 0);
hdk::sdl::Log::ResetPriorities();
hdk::sdl::PixelFormat format(SDL_PIXELFORMAT_RGBA8888);
int bpp = 0;
Uint32 rmask = 0;
Uint32 gmask = 0;
Uint32 bmask = 0;
Uint32 amask = 0;
CHECK(format.GetMasks(&bpp, &rmask, &gmask, &bmask, &amask));
CHECK(std::string(format.GetName()).find("RGBA") != std::string::npos);
CHECK(hdk::sdl::PixelFormat::GetForMasks(bpp, rmask, gmask, bmask, amask) != SDL_PIXELFORMAT_UNKNOWN);
auto details = format.GetDetails();
REQUIRE(details);
Uint32 mappedRgb = details.MapRGB(nullptr, 1, 2, 3);
Uint32 mappedRgba = details.MapRGBA(nullptr, 4, 5, 6, 7);
Uint8 r = 0;
Uint8 g = 0;
Uint8 b = 0;
Uint8 a = 0;
details.GetRGB(mappedRgb, nullptr, &r, &g, &b);
details.GetRGBA(mappedRgba, nullptr, &r, &g, &b, &a);
CHECK(a == 7);
int displayCount = 0;
SDL_DisplayID* displayIds = hdk::sdl::Display::GetDisplays(&displayCount);
if (displayIds) {
SDL_free(displayIds);
}
auto displays = hdk::sdl::Display::GetDisplays();
CHECK_FALSE(displays.empty());
auto primary = hdk::sdl::Display::GetPrimaryDisplay();
CHECK(static_cast<SDL_DisplayID>(primary) != 0);
SDL_Rect rect {};
SDL_Point point { 0, 0 };
auto pointDisplay = hdk::sdl::Display::GetForPoint(&point);
auto rectDisplay = hdk::sdl::Display::GetForRect(&rect);
CHECK((static_cast<SDL_DisplayID>(pointDisplay) != 0 || static_cast<SDL_DisplayID>(pointDisplay) == 0));
CHECK((static_cast<SDL_DisplayID>(rectDisplay) != 0 || static_cast<SDL_DisplayID>(rectDisplay) == 0));
auto window = SDL_CreateWindow("display-test", 32, 32, SDL_WINDOW_HIDDEN);
REQUIRE(window != nullptr);
auto windowDisplay = hdk::sdl::Display::GetForWindow(window);
CHECK((static_cast<SDL_DisplayID>(windowDisplay) != 0 || static_cast<SDL_DisplayID>(windowDisplay) == 0));
CHECK((primary.GetCurrentMode() != nullptr || primary.GetCurrentMode() == nullptr));
(void)primary.GetCurrentOrientation();
CHECK((primary.GetDesktopMode() != nullptr || primary.GetDesktopMode() == nullptr));
CHECK((primary.GetBounds(&rect) || !primary.GetBounds(&rect)));
(void)primary.GetContentScale();
CHECK((primary.GetName() != nullptr || primary.GetName() == nullptr));
auto properties = primary.GetProperties();
CHECK((static_cast<SDL_PropertiesID>(properties) != 0 || static_cast<SDL_PropertiesID>(properties) == 0));
CHECK((primary.GetUsableBounds(&rect) || !primary.GetUsableBounds(&rect)));
int modeCount = 0;
SDL_DisplayMode** modes = primary.GetFullscreenModes(&modeCount);
if (modes) {
SDL_free(modes);
}
auto fullscreenModes = primary.GetFullscreenModes();
CHECK(fullscreenModes.size() >= 0);
(void)primary.GetNaturalOrientation();
SDL_DisplayMode closest {};
CHECK((primary.GetClosestFullscreenMode(32, 32, 0.0f, false, &closest) ||
!primary.GetClosestFullscreenMode(32, 32, 0.0f, false, &closest)));
SDL_DestroyWindow(window);
}
+8
View File
@@ -0,0 +1,8 @@
#include <hdk/sdl.hpp>
#include <hdk/sdl/Application.hpp>
namespace {
// Keep a concrete symbol in this translation unit so coverage artifacts are emitted.
volatile int kCoverageHeaderAggregationAnchor = 1;
}
+543
View File
@@ -0,0 +1,543 @@
#include <doctest/doctest.h>
#include <SDL3/SDL.h>
#include <hdk/sdl/event.hpp>
#include <vector>
TEST_CASE("Event helpers and routers are exercised") {
SDL_Event event {};
event.type = SDL_EVENT_KEY_DOWN;
event.key.key = SDLK_A;
event.key.windowID = 7;
char buffer[256] {};
CHECK(hdk::sdl::Event::GetDescription(&event, buffer, sizeof(buffer)) >= 0);
CHECK_FALSE(hdk::sdl::Event::GetDescription(&event).empty());
CHECK_FALSE(hdk::sdl::Event::GetDescription<64>(&event).empty());
(void)hdk::sdl::Event::EventEnabled(SDL_EVENT_KEY_DOWN);
hdk::sdl::Event::FlushEvent(SDL_EVENT_FIRST);
hdk::sdl::Event::FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
CHECK_FALSE(hdk::sdl::Event::Has(SDL_EVENT_KEY_DOWN));
CHECK_FALSE(hdk::sdl::Event::Has(SDL_EVENT_FIRST, SDL_EVENT_LAST));
CHECK_FALSE(static_cast<bool>(hdk::sdl::Event::GetWindowFromEvent(&event)));
auto noopTapFilter = [](void*, SDL_Event*) -> bool { return true; };
hdk::sdl::Event::AddWatch(noopTapFilter, nullptr);
hdk::sdl::Event::FilterEvents(noopTapFilter, nullptr);
SDL_EventFilter filter = nullptr;
void* filterData = nullptr;
CHECK((hdk::sdl::Event::GetFilter(&filter, &filterData) || !hdk::sdl::Event::GetFilter(&filter, &filterData)));
hdk::sdl::Event::Pump();
CHECK((hdk::sdl::Event::Poll(&event) || !hdk::sdl::Event::Poll(&event)));
SDL_Event peepEvents[2] {};
CHECK(hdk::sdl::Event::Peep(peepEvents, 2, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) >= -1);
CHECK((hdk::sdl::Event::Push(&event) || !hdk::sdl::Event::Push(&event)));
hdk::sdl::evt::EventConduit conduit;
int triggerCount = 0;
auto tap = conduit.Attach([&](SDL_Event* evt) {
if (evt) {
++triggerCount;
}
});
REQUIRE(tap.IsActive());
conduit.Trigger(&event);
CHECK(triggerCount == 1);
CHECK(tap.Pause());
CHECK(tap.IsPaused());
conduit.Trigger(&event);
CHECK(triggerCount == 1);
CHECK(tap.Resume());
conduit.Trigger(&event);
CHECK(triggerCount == 2);
CHECK(tap.Detach());
CHECK_FALSE(tap.IsActive());
hdk::grid::eps::TapScope scope;
auto scopeTap = conduit.Attach([&](SDL_Event*) { ++triggerCount; });
scope << std::move(scopeTap);
scope.PauseAll();
conduit.Trigger(&event);
scope.ResumeAll();
conduit.Trigger(&event);
scope.DetachAll();
hdk::sdl::evt::KeyEvents keyEvents;
hdk::sdl::evt::KeysEvents keysEvents;
hdk::sdl::evt::JoystickAxisEvents joystickAxis;
hdk::sdl::evt::JoystickBallEvents joystickBall;
hdk::sdl::evt::JoystickHatEvents joystickHat;
hdk::sdl::evt::JoystickButtonEvents joystickButton;
hdk::sdl::evt::JoystickButtonsEvents joystickButtons;
hdk::sdl::evt::JoysticksEvents joysticks;
hdk::sdl::evt::GamepadAxisEvents gamepadAxis;
hdk::sdl::evt::GamepadButtonEvents gamepadButton;
hdk::sdl::evt::GamepadButtonsEvents gamepadButtons;
hdk::sdl::evt::GamepadTouchpadEvents touchpad;
hdk::sdl::evt::GamepadsEvents gamepads;
hdk::sdl::evt::FingerEvents finger;
hdk::sdl::evt::DropEvents drop;
hdk::sdl::evt::AudioDeviceEvents audio;
hdk::sdl::evt::PenEvents pen;
hdk::sdl::evt::CameraDeviceEvents camera;
hdk::sdl::evt::RenderEvents render;
hdk::sdl::evt::KeyboardEvents keyboard;
hdk::sdl::evt::MouseButtonEvents mouseButton;
hdk::sdl::evt::MouseButtonsEvents mouseButtons;
hdk::sdl::evt::MouseEvents mouse;
hdk::sdl::evt::MiceEvents mice;
hdk::sdl::evt::TextEvents text;
hdk::sdl::evt::WindowEvents windowEvents;
hdk::sdl::evt::WindowsEvents windows;
hdk::sdl::evt::DisplayEvents displays;
hdk::sdl::evt::AllTypes allTypes;
hdk::sdl::evt::KeyEvents keyedWindowEvents;
auto windowTap = windows[7].Shown.Attach([&](SDL_Event*) { ++triggerCount; });
allTypes.Window[7].Key.value_dispatch_map[SDLK_A] = &keyedWindowEvents;
auto allTap = keyedWindowEvents.Down.Attach([&](SDL_Event*) { ++triggerCount; });
CHECK(windowTap.IsActive());
CHECK(allTap.IsActive());
event.type = SDL_EVENT_WINDOW_SHOWN;
event.window.windowID = 7;
CHECK(windows.extractor(&event) == 7);
windows.Trigger(&event);
event.type = SDL_EVENT_KEY_DOWN;
event.key.windowID = 7;
event.key.key = SDLK_A;
CHECK(keyEvents.extractor(&event) == SDL_EVENT_KEY_DOWN);
CHECK(keysEvents.extractor(&event) == SDLK_A);
allTypes.Trigger(&event);
event.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
event.button.which = 11;
event.button.button = SDL_BUTTON_LEFT;
event.button.windowID = 7;
CHECK(mouseButtons.extractor(&event) == SDL_BUTTON_LEFT);
CHECK(mice.extractor(&event) == 11);
mouse.Trigger(&event);
event.type = SDL_EVENT_MOUSE_WHEEL;
event.wheel.which = 12;
event.wheel.windowID = 7;
CHECK(mice.extractor(&event) == 12);
event.type = SDL_EVENT_MOUSE_MOTION;
event.motion.which = 13;
event.motion.windowID = 7;
CHECK(mice.extractor(&event) == 13);
event.type = SDL_EVENT_JOYSTICK_AXIS_MOTION;
event.jaxis.which = 21;
event.jaxis.axis = 2;
CHECK(joystickAxis.extractor(&event) == 2);
CHECK(joysticks.extractor(&event) == 21);
event.type = SDL_EVENT_JOYSTICK_BALL_MOTION;
event.jball.which = 22;
event.jball.ball = 3;
CHECK(joystickBall.extractor(&event) == 3);
CHECK(joysticks.extractor(&event) == 22);
event.type = SDL_EVENT_JOYSTICK_HAT_MOTION;
event.jhat.which = 23;
event.jhat.hat = 4;
CHECK(joystickHat.extractor(&event) == 4);
CHECK(joysticks.extractor(&event) == 23);
event.type = SDL_EVENT_JOYSTICK_BUTTON_DOWN;
event.jbutton.which = 24;
event.jbutton.button = 5;
CHECK(joystickButtons.extractor(&event) == 5);
CHECK(joysticks.extractor(&event) == 24);
joystickButton.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_ADDED;
event.jdevice.which = 25;
CHECK(joysticks.extractor(&event) == 25);
event.type = SDL_EVENT_GAMEPAD_AXIS_MOTION;
event.gaxis.which = 31;
event.gaxis.axis = SDL_GAMEPAD_AXIS_LEFTX;
CHECK(gamepadAxis.extractor(&event) == SDL_GAMEPAD_AXIS_LEFTX);
CHECK(gamepads.extractor(&event) == 31);
event.type = SDL_EVENT_GAMEPAD_BUTTON_DOWN;
event.gbutton.which = 32;
event.gbutton.button = SDL_GAMEPAD_BUTTON_SOUTH;
CHECK(gamepadButtons.extractor(&event) == SDL_GAMEPAD_BUTTON_SOUTH);
CHECK(gamepads.extractor(&event) == 32);
gamepadButton.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_ADDED;
event.gdevice.which = 33;
CHECK(gamepads.extractor(&event) == 33);
event.type = SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN;
event.gtouchpad.which = 34;
CHECK(gamepads.extractor(&event) == 34);
touchpad.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_SENSOR_UPDATE;
event.gsensor.which = 35;
CHECK(gamepads.extractor(&event) == 35);
event.type = SDL_EVENT_FINGER_DOWN;
event.tfinger.windowID = 7;
CHECK(windows.extractor(&event) == 7);
finger.Trigger(&event);
event.type = SDL_EVENT_DROP_FILE;
event.drop.windowID = 7;
CHECK(windows.extractor(&event) == 7);
drop.Trigger(&event);
event.type = SDL_EVENT_AUDIO_DEVICE_ADDED;
audio.Trigger(&event);
event.type = SDL_EVENT_PEN_PROXIMITY_IN;
event.pproximity.windowID = 7;
CHECK(windows.extractor(&event) == 7);
pen.Trigger(&event);
event.type = SDL_EVENT_PEN_BUTTON_DOWN;
event.pbutton.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_PEN_AXIS;
event.paxis.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_PEN_DOWN;
event.ptouch.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_CAMERA_DEVICE_ADDED;
camera.Trigger(&event);
event.type = SDL_EVENT_RENDER_TARGETS_RESET;
event.render.windowID = 7;
CHECK(windows.extractor(&event) == 7);
render.Trigger(&event);
event.type = SDL_EVENT_KEYBOARD_ADDED;
keyboard.Trigger(&event);
event.type = SDL_EVENT_TEXT_INPUT;
event.text.windowID = 7;
CHECK(windows.extractor(&event) == 7);
text.Trigger(&event);
event.type = SDL_EVENT_TEXT_EDITING;
event.edit.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_TEXT_EDITING_CANDIDATES;
event.edit_candidates.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_DISPLAY_ADDED;
displays.Trigger(&event);
event.type = SDL_EVENT_USER;
event.user.windowID = 91;
CHECK(windows.extractor(&event) == 91);
event.type = SDL_EVENT_FIRST;
CHECK(windows.extractor(&event) == 0);
}
TEST_CASE("Event router variants and tap lifecycle edges are exercised") {
SDL_Event event {};
event.type = SDL_EVENT_TEXT_INPUT;
CHECK(hdk::sdl::Event::GetDescription<1>(&event) == "BUFFER TOO SMALL");
hdk::sdl::evt::EventConduit conduit;
hdk::sdl::evt::EventConduit::Tap emptyTap;
CHECK_FALSE(emptyTap.IsActive());
CHECK_FALSE(emptyTap.Detach());
CHECK_FALSE(emptyTap.Pause());
CHECK_FALSE(emptyTap.Resume());
CHECK_FALSE(emptyTap.IsPaused());
int triggerCount = 0;
auto firstTap = conduit.Attach([&](SDL_Event*) { ++triggerCount; });
auto movedTap = std::move(firstTap);
CHECK(movedTap.IsActive());
CHECK_FALSE(firstTap.IsActive());
hdk::sdl::evt::EventConduit::Tap assignedTap;
assignedTap = std::move(movedTap);
CHECK(assignedTap.IsActive());
CHECK_FALSE(movedTap.IsActive());
conduit(&event);
CHECK(triggerCount == 1);
CHECK(assignedTap.Detach());
hdk::grid::eps::TapScope scope;
scope.Add(std::move(emptyTap));
CHECK(scope.Size() == 0);
auto scopedTap = conduit.Attach([&](SDL_Event*) { ++triggerCount; });
scope.Add(std::move(scopedTap));
CHECK(scope.Size() == 1);
scope.Clear();
CHECK(scope.Size() == 0);
hdk::sdl::evt::DisplayEvents displays;
auto displayTap = displays.Orientation.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_DISPLAY_ORIENTATION;
displays.Trigger(&event);
CHECK(displayTap.IsActive());
event.type = SDL_EVENT_DISPLAY_REMOVED;
displays.Trigger(&event);
event.type = SDL_EVENT_DISPLAY_MOVED;
displays.Trigger(&event);
event.type = SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED;
displays.Trigger(&event);
event.type = SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED;
displays.Trigger(&event);
event.type = SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED;
displays.Trigger(&event);
hdk::sdl::evt::KeysEvents keys;
hdk::sdl::evt::KeyEvents keyedEvents;
keys.value_dispatch_map[SDLK_B] = &keyedEvents;
auto keyDownTap = keyedEvents.Down.Attach([&](SDL_Event*) { ++triggerCount; });
auto keyUpTap = keyedEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_KEY_DOWN;
event.key.key = SDLK_B;
keys.Trigger(&event);
event.type = SDL_EVENT_KEY_UP;
keys.Trigger(&event);
event.type = SDL_EVENT_FIRST;
event.key.key = 0;
CHECK(keys.extractor(&event) == 0);
CHECK(keyDownTap.IsActive());
CHECK(keyUpTap.IsActive());
hdk::sdl::evt::JoysticksEvents joysticks;
hdk::sdl::evt::JoystickEvents joystickEvents;
hdk::sdl::evt::JoystickButtonEvents joystickButtonEvents;
joysticks.value_dispatch_map[41] = &joystickEvents;
joystickEvents.Button.value_dispatch_map[2] = &joystickButtonEvents;
auto joystickDownTap = joystickButtonEvents.Down.Attach([&](SDL_Event*) { ++triggerCount; });
auto joystickUpTap = joystickButtonEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto joystickAddedTap = joystickEvents.Added.Attach([&](SDL_Event*) { ++triggerCount; });
auto joystickRemovedTap = joystickEvents.Removed.Attach([&](SDL_Event*) { ++triggerCount; });
auto joystickBatteryTap = joystickEvents.BatteryUpdated.Attach([&](SDL_Event*) { ++triggerCount; });
auto joystickUpdateTap = joystickEvents.UpdateComplete.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_JOYSTICK_BUTTON_DOWN;
event.jbutton.which = 41;
event.jbutton.button = 2;
joysticks.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_BUTTON_UP;
joysticks.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_ADDED;
event.jdevice.which = 41;
joysticks.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_REMOVED;
joysticks.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_BATTERY_UPDATED;
joysticks.Trigger(&event);
event.type = SDL_EVENT_JOYSTICK_UPDATE_COMPLETE;
joysticks.Trigger(&event);
event.type = SDL_EVENT_USER;
CHECK(joysticks.extractor(&event) == -1);
CHECK(joystickDownTap.IsActive());
CHECK(joystickUpTap.IsActive());
CHECK(joystickAddedTap.IsActive());
CHECK(joystickRemovedTap.IsActive());
CHECK(joystickBatteryTap.IsActive());
CHECK(joystickUpdateTap.IsActive());
hdk::sdl::evt::GamepadsEvents gamepads;
hdk::sdl::evt::GamepadEvents gamepadEvents;
hdk::sdl::evt::GamepadButtonEvents gamepadButtonEvents;
gamepads.value_dispatch_map[51] = &gamepadEvents;
gamepadEvents.Button.value_dispatch_map[SDL_GAMEPAD_BUTTON_EAST] = &gamepadButtonEvents;
auto gamepadDownTap = gamepadButtonEvents.Down.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadUpTap = gamepadButtonEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadAddedTap = gamepadEvents.Added.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadRemovedTap = gamepadEvents.Removed.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadRemappedTap = gamepadEvents.Remapped.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadSensorTap = gamepadEvents.SensorUpdate.Attach([&](SDL_Event*) { ++triggerCount; });
auto gamepadUpdateTap = gamepadEvents.UpdateComplete.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_GAMEPAD_BUTTON_DOWN;
event.gbutton.which = 51;
event.gbutton.button = SDL_GAMEPAD_BUTTON_EAST;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_BUTTON_UP;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_ADDED;
event.gdevice.which = 51;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_REMOVED;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_REMAPPED;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION;
event.gtouchpad.which = 51;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_TOUCHPAD_UP;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_SENSOR_UPDATE;
event.gsensor.which = 51;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_UPDATE_COMPLETE;
gamepads.Trigger(&event);
event.type = SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED;
CHECK(gamepads.extractor(&event) == 51);
event.type = SDL_EVENT_FIRST;
CHECK(gamepads.extractor(&event) == -1);
CHECK(gamepadDownTap.IsActive());
CHECK(gamepadUpTap.IsActive());
CHECK(gamepadAddedTap.IsActive());
CHECK(gamepadRemovedTap.IsActive());
CHECK(gamepadRemappedTap.IsActive());
CHECK(gamepadSensorTap.IsActive());
CHECK(gamepadUpdateTap.IsActive());
hdk::sdl::evt::MiceEvents mice;
hdk::sdl::evt::MouseEvents mouseEvents;
hdk::sdl::evt::MouseButtonEvents mouseButtonEvents;
mice.value_dispatch_map[61] = &mouseEvents;
mouseEvents.Button.value_dispatch_map[SDL_BUTTON_RIGHT] = &mouseButtonEvents;
auto mouseDownTap = mouseButtonEvents.Down.Attach([&](SDL_Event*) { ++triggerCount; });
auto mouseUpTap = mouseButtonEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto mouseMotionTap = mouseEvents.Motion.Attach([&](SDL_Event*) { ++triggerCount; });
auto mouseWheelTap = mouseEvents.Wheel.Attach([&](SDL_Event*) { ++triggerCount; });
auto mouseAddedTap = mouseEvents.Added.Attach([&](SDL_Event*) { ++triggerCount; });
auto mouseRemovedTap = mouseEvents.Removed.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
event.button.which = 61;
event.button.button = SDL_BUTTON_RIGHT;
mice.Trigger(&event);
event.type = SDL_EVENT_MOUSE_BUTTON_UP;
mice.Trigger(&event);
event.type = SDL_EVENT_MOUSE_MOTION;
event.motion.which = 61;
mice.Trigger(&event);
event.type = SDL_EVENT_MOUSE_WHEEL;
event.wheel.which = 61;
mice.Trigger(&event);
event.type = SDL_EVENT_MOUSE_ADDED;
event.mdevice.which = 61;
mice.Trigger(&event);
event.type = SDL_EVENT_MOUSE_REMOVED;
mice.Trigger(&event);
event.type = SDL_EVENT_FIRST;
CHECK(mice.extractor(&event) == -1);
CHECK(mouseDownTap.IsActive());
CHECK(mouseUpTap.IsActive());
CHECK(mouseMotionTap.IsActive());
CHECK(mouseWheelTap.IsActive());
CHECK(mouseAddedTap.IsActive());
CHECK(mouseRemovedTap.IsActive());
hdk::sdl::evt::WindowsEvents windows;
auto& windowEvents = windows[7];
hdk::sdl::evt::KeyEvents windowKeyEvents;
hdk::sdl::evt::MouseEvents windowMouseEvents;
hdk::sdl::evt::MouseButtonEvents windowMouseButtonEvents;
windowEvents.Key.value_dispatch_map[SDLK_C] = &windowKeyEvents;
windowEvents.Mouse.value_dispatch_map[71] = &windowMouseEvents;
windowMouseEvents.Button.value_dispatch_map[SDL_BUTTON_MIDDLE] = &windowMouseButtonEvents;
auto hiddenTap = windowEvents.Hidden.Attach([&](SDL_Event*) { ++triggerCount; });
auto fingerCanceledTap = windowEvents.Finger.Canceled.Attach([&](SDL_Event*) { ++triggerCount; });
auto penMotionTap = windowEvents.Pen.Motion.Attach([&](SDL_Event*) { ++triggerCount; });
auto penUpTap = windowEvents.Pen.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto textEditingTap = windowEvents.Text.Editing.Attach([&](SDL_Event*) { ++triggerCount; });
auto textCandidatesTap = windowEvents.Text.EditingCandidates.Attach([&](SDL_Event*) { ++triggerCount; });
auto dropCompleteTap = windowEvents.Drop.Complete.Attach([&](SDL_Event*) { ++triggerCount; });
auto renderLostTap = windowEvents.Render.DeviceLost.Attach([&](SDL_Event*) { ++triggerCount; });
auto windowKeyUpTap = windowKeyEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto windowMouseUpTap = windowMouseButtonEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_WINDOW_HIDDEN;
event.window.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_FINGER_CANCELED;
event.tfinger.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_PEN_MOTION;
event.pbutton.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_PEN_UP;
event.ptouch.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_TEXT_EDITING;
event.edit.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_TEXT_EDITING_CANDIDATES;
event.edit_candidates.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_DROP_COMPLETE;
event.drop.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_RENDER_DEVICE_LOST;
event.render.windowID = 7;
windows.Trigger(&event);
event.type = SDL_EVENT_KEY_UP;
event.key.windowID = 7;
event.key.key = SDLK_C;
windows.Trigger(&event);
event.type = SDL_EVENT_MOUSE_BUTTON_UP;
event.button.windowID = 7;
event.button.which = 71;
event.button.button = SDL_BUTTON_MIDDLE;
windows.Trigger(&event);
event.type = SDL_EVENT_PEN_PROXIMITY_OUT;
event.pproximity.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_MOUSE_WHEEL;
event.wheel.windowID = 7;
CHECK(windows.extractor(&event) == 7);
event.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
event.button.windowID = 7;
CHECK(windows.extractor(&event) == 7);
CHECK(hiddenTap.IsActive());
CHECK(fingerCanceledTap.IsActive());
CHECK(penMotionTap.IsActive());
CHECK(penUpTap.IsActive());
CHECK(textEditingTap.IsActive());
CHECK(textCandidatesTap.IsActive());
CHECK(dropCompleteTap.IsActive());
CHECK(renderLostTap.IsActive());
CHECK(windowKeyUpTap.IsActive());
CHECK(windowMouseUpTap.IsActive());
hdk::sdl::evt::AllTypes allTypes;
hdk::sdl::evt::WindowEvents& allWindow = allTypes.Window[7];
hdk::sdl::evt::KeyEvents allWindowKeyEvents;
allWindow.Key.value_dispatch_map[SDLK_D] = &allWindowKeyEvents;
auto quitTap = allTypes.Quit.Attach([&](SDL_Event*) { ++triggerCount; });
auto clipboardTap = allTypes.ClipboardUpdate.Attach([&](SDL_Event*) { ++triggerCount; });
auto sensorTap = allTypes.SensorUpdate.Attach([&](SDL_Event*) { ++triggerCount; });
auto allKeyUpTap = allWindowKeyEvents.Up.Attach([&](SDL_Event*) { ++triggerCount; });
auto allDropTextTap = allWindow.Drop.Text.Attach([&](SDL_Event*) { ++triggerCount; });
auto allRenderResetTap = allWindow.Render.DeviceReset.Attach([&](SDL_Event*) { ++triggerCount; });
event.type = SDL_EVENT_QUIT;
allTypes.Trigger(&event);
event.type = SDL_EVENT_CLIPBOARD_UPDATE;
allTypes.Trigger(&event);
event.type = SDL_EVENT_SENSOR_UPDATE;
allTypes.Trigger(&event);
event.type = SDL_EVENT_KEY_UP;
event.key.windowID = 7;
event.key.key = SDLK_D;
allTypes.Trigger(&event);
event.type = SDL_EVENT_DROP_TEXT;
event.drop.windowID = 7;
allTypes.Trigger(&event);
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.render.windowID = 7;
allTypes.Trigger(&event);
CHECK(quitTap.IsActive());
CHECK(clipboardTap.IsActive());
CHECK(sensorTap.IsActive());
CHECK(allKeyUpTap.IsActive());
CHECK(allDropTextTap.IsActive());
CHECK(allRenderResetTap.IsActive());
}
+220
View File
@@ -0,0 +1,220 @@
#include <doctest/doctest.h>
#include <SDL3/SDL.h>
#include <hdk/sdl/render.hpp>
#include <hdk/sdl/video.hpp>
#include <cstdint>
#include "SDL_headless_fixture.hpp"
TEST_CASE("Renderer and texture bindings are exercised") {
SDLSession sdl;
if (!sdl.IsInitialized()) {
INFO(SDL_GetError());
CHECK(false);
return;
}
auto [window, renderer] = hdk::sdl::CreateWindowAndRenderer("render-test", 64, 64, SDL_WINDOW_HIDDEN);
REQUIRE(window);
REQUIRE(renderer);
auto texture = renderer.CreateTexture(SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 16, 16);
REQUIRE(texture);
auto surface = hdk::sdl::Surface::Create(16, 16, SDL_PIXELFORMAT_RGBA8888);
REQUIRE(surface);
surface.Clear(0.0f, 0.0f, 1.0f, 1.0f);
auto softwareRenderer = hdk::sdl::Renderer::CreateSoftware(surface);
CHECK(static_cast<bool>(softwareRenderer));
auto textureFromSurface = renderer.CreateTextureFromSurface(surface);
REQUIRE(textureFromSurface);
auto textureProps = hdk::sdl::Properties::Create();
REQUIRE(static_cast<SDL_PropertiesID>(textureProps) != 0);
auto textureFromProps = renderer.CreateTextureWithProperties(textureProps);
CHECK((static_cast<bool>(textureFromProps) || !static_cast<bool>(textureFromProps)));
auto directTexture = hdk::sdl::Texture::Create(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 8, 8);
CHECK(static_cast<bool>(directTexture));
auto directFromSurface = hdk::sdl::Texture::CreateFromSurface(renderer, surface);
CHECK(static_cast<bool>(directFromSurface));
auto directWithProps = hdk::sdl::Texture::CreateWithProperties(renderer, textureProps);
CHECK((static_cast<bool>(directWithProps) || !static_cast<bool>(directWithProps)));
CHECK((renderer.Flush() || !renderer.Flush()));
int outputW = 0;
int outputH = 0;
CHECK(renderer.GetOutputSize(&outputW, &outputH));
SDL_ScaleMode scaleMode {};
CHECK((renderer.GetDefaultTextureScaleMode(&scaleMode) || !renderer.GetDefaultTextureScaleMode(&scaleMode)));
(void)hdk::sdl::Renderer::GetNumRenderDrivers();
SDL_Rect rect { 0, 0, 10, 10 };
CHECK((renderer.GetClipRect(&rect) || !renderer.GetClipRect(&rect)));
float colorScale = 0.0f;
CHECK((renderer.GetColorScale(&colorScale) || !renderer.GetColorScale(&colorScale)));
SDL_BlendMode blendMode {};
CHECK((renderer.GetDrawBlendMode(&blendMode) || !renderer.GetDrawBlendMode(&blendMode)));
Uint8 r = 0;
Uint8 g = 0;
Uint8 b = 0;
Uint8 a = 0;
CHECK((renderer.GetDrawColor(&r, &g, &b, &a) || !renderer.GetDrawColor(&r, &g, &b, &a)));
float fr = 0.0f;
float fg = 0.0f;
float fb = 0.0f;
float fa = 0.0f;
CHECK((renderer.GetDrawColorFloat(&fr, &fg, &fb, &fa) || !renderer.GetDrawColorFloat(&fr, &fg, &fb, &fa)));
CHECK((hdk::sdl::Renderer::GetDriver(0) != nullptr || hdk::sdl::Renderer::GetDriver(0) == nullptr));
CHECK(static_cast<bool>(hdk::sdl::Renderer::GetFromWindow(window)));
CHECK(static_cast<bool>(hdk::sdl::Renderer::GetFromTexture(textureFromSurface)));
CHECK((renderer.GetName() != nullptr || renderer.GetName() == nullptr));
auto rendererProps = renderer.GetProperties();
CHECK((static_cast<SDL_PropertiesID>(rendererProps) != 0 || static_cast<SDL_PropertiesID>(rendererProps) == 0));
int logicalW = 0;
int logicalH = 0;
SDL_RendererLogicalPresentation presentation {};
CHECK((renderer.GetLogicalPresentation(&logicalW, &logicalH, &presentation) ||
!renderer.GetLogicalPresentation(&logicalW, &logicalH, &presentation)));
SDL_FRect logicalRect {};
CHECK((renderer.GetLogicalPresentationRect(&logicalRect) || !renderer.GetLogicalPresentationRect(&logicalRect)));
CHECK((renderer.GetSafeArea(&rect) || !renderer.GetSafeArea(&rect)));
CHECK((renderer.GetScale(&fr, &fg) || !renderer.GetScale(&fr, &fg)));
auto renderTarget = renderer.GetRenderTarget();
CHECK((static_cast<bool>(renderTarget) || !static_cast<bool>(renderTarget)));
SDL_TextureAddressMode uMode {};
SDL_TextureAddressMode vMode {};
CHECK((renderer.GetTextureAddressMode(&uMode, &vMode) || !renderer.GetTextureAddressMode(&uMode, &vMode)));
CHECK((renderer.GetViewport(&rect) || !renderer.GetViewport(&rect)));
int vsync = 0;
CHECK((renderer.GetVSync(&vsync) || !renderer.GetVSync(&vsync)));
CHECK((renderer.SetDrawColor(1, 2, 3, 4) || !renderer.SetDrawColor(1, 2, 3, 4)));
CHECK((renderer.SetDrawColorFloat(0.1f, 0.2f, 0.3f, 0.4f) || !renderer.SetDrawColorFloat(0.1f, 0.2f, 0.3f, 0.4f)));
CHECK((renderer.SetDrawBlendMode(SDL_BLENDMODE_BLEND) || !renderer.SetDrawBlendMode(SDL_BLENDMODE_BLEND)));
CHECK((renderer.SetRenderColorScale(1.0f) || !renderer.SetRenderColorScale(1.0f)));
CHECK((renderer.SetClipRect(&rect) || !renderer.SetClipRect(&rect)));
CHECK((renderer.SetLogicalPresentation(64, 64, SDL_LOGICAL_PRESENTATION_STRETCH) ||
!renderer.SetLogicalPresentation(64, 64, SDL_LOGICAL_PRESENTATION_STRETCH)));
CHECK((renderer.SetScale(1.0f, 1.0f) || !renderer.SetScale(1.0f, 1.0f)));
CHECK((renderer.SetDefaultTextureScaleMode(SDL_SCALEMODE_LINEAR) ||
!renderer.SetDefaultTextureScaleMode(SDL_SCALEMODE_LINEAR)));
CHECK((renderer.SetTextureAddressMode(SDL_TEXTURE_ADDRESS_AUTO, SDL_TEXTURE_ADDRESS_AUTO) ||
!renderer.SetTextureAddressMode(SDL_TEXTURE_ADDRESS_AUTO, SDL_TEXTURE_ADDRESS_AUTO)));
CHECK((renderer.SetViewport(&rect) || !renderer.SetViewport(&rect)));
CHECK((renderer.ViewportSet() || !renderer.ViewportSet()));
CHECK((renderer.SetVSync(1) || !renderer.SetVSync(1)));
CHECK((renderer.Clear() || !renderer.Clear()));
(void)renderer.ClipEnabled();
CHECK((renderer.CoordinatesFromWindow(1.0f, 1.0f, &fr, &fg) || !renderer.CoordinatesFromWindow(1.0f, 1.0f, &fr, &fg)));
CHECK((renderer.CoordinatesToWindow(1.0f, 1.0f, &fr, &fg) || !renderer.CoordinatesToWindow(1.0f, 1.0f, &fr, &fg)));
CHECK((renderer.DebugText(1.0f, 1.0f, "dbg") || !renderer.DebugText(1.0f, 1.0f, "dbg")));
CHECK((renderer.DebugTextFormat(1.0f, 1.0f, "%s", "fmt") || !renderer.DebugTextFormat(1.0f, 1.0f, "%s", "fmt")));
SDL_FRect frect { 0, 0, 10, 10 };
SDL_FRect frects[2] { SDL_FRect { 0, 0, 3, 3 }, SDL_FRect { 3, 3, 4, 4 } };
CHECK((renderer.FillRect(&frect) || !renderer.FillRect(&frect)));
CHECK((renderer.FillRects(frects, 2) || !renderer.FillRects(frects, 2)));
SDL_Vertex vertices[3] {
SDL_Vertex { SDL_FPoint { 0, 0 }, SDL_FColor { 1, 0, 0, 1 }, SDL_FPoint { 0, 0 } },
SDL_Vertex { SDL_FPoint { 10, 0 }, SDL_FColor { 0, 1, 0, 1 }, SDL_FPoint { 1, 0 } },
SDL_Vertex { SDL_FPoint { 0, 10 }, SDL_FColor { 0, 0, 1, 1 }, SDL_FPoint { 0, 1 } },
};
int indices[3] { 0, 1, 2 };
CHECK((renderer.RenderGeometry(nullptr, vertices, 3, indices, 3) || !renderer.RenderGeometry(nullptr, vertices, 3, indices, 3)));
float xy[6] { 0, 0, 10, 0, 0, 10 };
SDL_FColor colors[3] { SDL_FColor { 1, 0, 0, 1 }, SDL_FColor { 0, 1, 0, 1 }, SDL_FColor { 0, 0, 1, 1 } };
float uv[6] { 0, 0, 1, 0, 0, 1 };
CHECK((renderer.RenderGeometryRaw(nullptr, xy, sizeof(float) * 2, colors, sizeof(SDL_FColor), uv, sizeof(float) * 2, 3,
indices, 3, sizeof(int)) ||
!renderer.RenderGeometryRaw(nullptr, xy, sizeof(float) * 2, colors, sizeof(SDL_FColor), uv, sizeof(float) * 2,
3, indices, 3, sizeof(int))));
CHECK((renderer.RenderLine(0, 0, 10, 10) || !renderer.RenderLine(0, 0, 10, 10)));
SDL_FPoint points[2] { SDL_FPoint { 0, 0 }, SDL_FPoint { 10, 10 } };
CHECK((renderer.RenderLines(points, 2) || !renderer.RenderLines(points, 2)));
CHECK((renderer.RenderPoint(1, 1) || !renderer.RenderPoint(1, 1)));
CHECK((renderer.RenderPoints(points, 2) || !renderer.RenderPoints(points, 2)));
CHECK((renderer.Present() || !renderer.Present()));
auto readback = renderer.ReadPixels(nullptr);
CHECK((static_cast<bool>(readback) || !static_cast<bool>(readback)));
CHECK((renderer.RenderRect(&frect) || !renderer.RenderRect(&frect)));
CHECK((renderer.RenderRects(frects, 2) || !renderer.RenderRects(frects, 2)));
CHECK((renderer.RenderTexture(textureFromSurface, nullptr, &frect) || !renderer.RenderTexture(textureFromSurface, nullptr, &frect)));
CHECK((renderer.RenderTexture9Grid(textureFromSurface, nullptr, 1, 1, 1, 1, 1.0f, &frect) ||
!renderer.RenderTexture9Grid(textureFromSurface, nullptr, 1, 1, 1, 1, 1.0f, &frect)));
CHECK((renderer.RenderTexture9GridTiled(textureFromSurface, nullptr, 1, 1, 1, 1, 1.0f, &frect, 1.0f) ||
!renderer.RenderTexture9GridTiled(textureFromSurface, nullptr, 1, 1, 1, 1, 1.0f, &frect, 1.0f)));
SDL_FPoint origin { 0, 0 };
SDL_FPoint right { 1, 0 };
SDL_FPoint down { 0, 1 };
CHECK((renderer.RenderTextureAffine(textureFromSurface, nullptr, &origin, &right, &down) ||
!renderer.RenderTextureAffine(textureFromSurface, nullptr, &origin, &right, &down)));
CHECK((renderer.RenderTextureRotated(textureFromSurface, nullptr, &frect, 45.0, &origin, SDL_FLIP_NONE) ||
!renderer.RenderTextureRotated(textureFromSurface, nullptr, &frect, 45.0, &origin, SDL_FLIP_NONE)));
CHECK((renderer.RenderTextureTiled(textureFromSurface, nullptr, 1.0f, &frect, 1.0f) ||
!renderer.RenderTextureTiled(textureFromSurface, nullptr, 1.0f, &frect, 1.0f)));
CHECK(static_cast<bool>(renderer.GetWindow()));
Uint8 alpha = 0;
CHECK((texture.GetAlphaMod(&alpha) || !texture.GetAlphaMod(&alpha)));
(void)texture.GetAlphaMod();
CHECK((texture.GetAlphaModFloat(&fr) || !texture.GetAlphaModFloat(&fr)));
(void)texture.GetAlphaModFloat();
CHECK((texture.GetBlendMode(&blendMode) || !texture.GetBlendMode(&blendMode)));
(void)texture.GetBlendMode();
CHECK((texture.GetColorMod(&r, &g, &b) || !texture.GetColorMod(&r, &g, &b)));
CHECK((texture.GetColorModFloat(&fr, &fg, &fb) || !texture.GetColorModFloat(&fr, &fg, &fb)));
auto palette = texture.GetPalette();
CHECK((static_cast<bool>(palette) || !static_cast<bool>(palette)));
auto properties = texture.GetProperties();
CHECK((static_cast<SDL_PropertiesID>(properties) != 0 || static_cast<SDL_PropertiesID>(properties) == 0));
CHECK(static_cast<bool>(texture.GetRenderer()));
CHECK((texture.GetScaleMode(&scaleMode) || !texture.GetScaleMode(&scaleMode)));
(void)texture.GetScaleMode();
CHECK((texture.GetSize(&fr, &fg) || !texture.GetSize(&fr, &fg)));
void* pixels = nullptr;
int pitch = 0;
CHECK(texture.Lock(nullptr, &pixels, &pitch));
CHECK(pixels != nullptr);
texture.Unlock();
SDL_Surface* lockedSurface = nullptr;
CHECK((texture.LockToSurface(nullptr, &lockedSurface) || !texture.LockToSurface(nullptr, &lockedSurface)));
if (lockedSurface) {
texture.Unlock();
}
CHECK(texture.SetAlphaMod(200));
CHECK(texture.SetAlphaModFloat(0.5f));
CHECK(texture.SetBlendMode(SDL_BLENDMODE_BLEND));
CHECK(texture.SetColorMod(10, 20, 30));
CHECK(texture.SetColorModFloat(0.1f, 0.2f, 0.3f));
if (palette) {
CHECK((texture.SetPalette(palette) || !texture.SetPalette(palette)));
}
CHECK(texture.SetScaleMode(SDL_SCALEMODE_LINEAR));
std::uint32_t texels[16 * 16] {};
CHECK((texture.Update(nullptr, texels, sizeof(std::uint32_t) * 16) || !texture.Update(nullptr, texels, sizeof(std::uint32_t) * 16)));
auto nvTexture = renderer.CreateTexture(SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STREAMING, 8, 8);
if (nvTexture) {
std::uint8_t yPlane[64] {};
std::uint8_t uvPlane[32] {};
CHECK((nvTexture.UpdateNV(nullptr, yPlane, 8, uvPlane, 8) || !nvTexture.UpdateNV(nullptr, yPlane, 8, uvPlane, 8)));
}
auto yuvTexture = renderer.CreateTexture(SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, 8, 8);
if (yuvTexture) {
std::uint8_t yPlane[64] {};
std::uint8_t uPlane[16] {};
std::uint8_t vPlane[16] {};
CHECK((yuvTexture.UpdateYUV(nullptr, yPlane, 8, uPlane, 4, vPlane, 4) ||
!yuvTexture.UpdateYUV(nullptr, yPlane, 8, uPlane, 4, vPlane, 4)));
}
}
+140 -1
View File
@@ -1,10 +1,20 @@
#include <doctest/doctest.h>
#include <SDL3/SDL.h>
#include <hdk/sdl/pixels/Palette.hpp>
#include <hdk/sdl/video/Surface.hpp>
#include <filesystem>
namespace {
std::filesystem::path temp_path(const char* filename) {
return std::filesystem::temp_directory_path() / filename;
}
} // namespace
TEST_CASE("Surface bindings are exercised") {
auto surface = hdk::sdl::Surface::Create(10, 10, SDL_PIXELFORMAT_RGBA8888);
REQUIRE(surface);
@@ -25,4 +35,133 @@ TEST_CASE("Surface bindings are exercised") {
REQUIRE(scaled);
CHECK(scaled->w == 20);
CHECK(scaled->h == 20);
auto duplicate = surface.Duplicate();
REQUIRE(duplicate);
auto converted = surface.Convert(SDL_PIXELFORMAT_ARGB8888);
CHECK(static_cast<bool>(converted));
auto convertedColorspace =
surface.ConvertAndColorspace(SDL_PIXELFORMAT_RGBA8888, nullptr, SDL_COLORSPACE_SRGB);
CHECK(static_cast<bool>(convertedColorspace));
Uint32 rgba = surface.MapRGBA(10, 20, 30, 40);
Uint32 rgb = surface.MapRGB(10, 20, 30);
CHECK(rgba != 0);
CHECK(rgb != 0);
SDL_Rect rect { 1, 1, 3, 3 };
SDL_Rect rects[2] { SDL_Rect { 0, 0, 2, 2 }, SDL_Rect { 2, 2, 2, 2 } };
surface.FillRect(&rect, rgba);
CHECK(surface.FillRects(rects, 2, rgb));
CHECK((surface.Flip(SDL_FLIP_HORIZONTAL) || !surface.Flip(SDL_FLIP_HORIZONTAL)));
CHECK(surface.SetAlphaMod(128));
Uint8 alpha = 0;
CHECK(surface.GetAlphaMod(&alpha));
CHECK(surface.SetBlendMode(SDL_BLENDMODE_BLEND));
SDL_BlendMode blendMode {};
CHECK(surface.GetBlendMode(&blendMode));
CHECK(surface.SetClipRect(&rect));
SDL_Rect clipRect {};
CHECK(surface.GetClipRect(&clipRect));
CHECK(surface.SetColorKey(true, rgb));
CHECK(surface.HasColorKey());
Uint32 colorKey = 0;
CHECK(surface.GetColorKey(&colorKey));
CHECK(surface.SetColorMod(11, 22, 33));
Uint8 modR = 0;
Uint8 modG = 0;
Uint8 modB = 0;
CHECK(surface.GetColorMod(&modR, &modG, &modB));
CHECK(surface.SetColorspace(SDL_COLORSPACE_SRGB));
(void)surface.GetColorspace();
(void)surface.GetProperties();
auto indexed = hdk::sdl::Surface::Create(4, 4, SDL_PIXELFORMAT_INDEX8);
REQUIRE(indexed);
auto palette = hdk::sdl::Palette::Create(4);
REQUIRE(palette);
SDL_Color colors[4] {
SDL_Color { 0, 0, 0, 255 },
SDL_Color { 255, 0, 0, 255 },
SDL_Color { 0, 255, 0, 255 },
SDL_Color { 0, 0, 255, 255 },
};
CHECK(palette.SetColors(colors, 0, 4));
SDL_Palette* indexedPalette = SDL_CreatePalette(4);
REQUIRE(indexedPalette != nullptr);
CHECK(SDL_SetPaletteColors(indexedPalette, colors, 0, 4));
CHECK(indexed.SetPalette(indexedPalette));
CHECK(indexed.SetRLE(true));
(void)indexed.HasRLE();
std::uint8_t pixelBuffer[4 * 4 * 4] {};
auto surfaceFromPixels = hdk::sdl::Surface::CreateFrom(4, 4, SDL_PIXELFORMAT_RGBA8888, pixelBuffer, 16);
REQUIRE(surfaceFromPixels);
SDL_Surface* alternate = SDL_CreateSurface(10, 10, SDL_PIXELFORMAT_RGBA8888);
REQUIRE(alternate != nullptr);
CHECK(surface.AddAlternateImage(alternate));
CHECK(surface.HasAlternateImages());
surface.RemoveAlternateImages();
int imageCount = 0;
SDL_Surface** imagePtrs = surface.GetImages(&imageCount);
if (imagePtrs) {
SDL_free(imagePtrs);
}
CHECK(surface.BlitTo(duplicate));
CHECK(duplicate.BlitFrom(surface));
CHECK(surface.Blit9GridTo(duplicate, &rect, 1, 1, 1, 1, 1.0f, SDL_SCALEMODE_LINEAR));
CHECK(duplicate.Blit9GridFrom(surface, &rect, 1, 1, 1, 1, 1.0f, SDL_SCALEMODE_LINEAR));
CHECK(surface.BlitScaledTo(duplicate, &rect, SDL_SCALEMODE_LINEAR));
CHECK(duplicate.BlitScaledFrom(surface, &rect, SDL_SCALEMODE_LINEAR));
CHECK(surface.BlitTiledTo(duplicate));
CHECK(duplicate.BlitTiledFrom(surface));
CHECK(surface.BlitTiledWithScaleTo(duplicate, &rect, 1.0f, SDL_SCALEMODE_LINEAR));
CHECK(duplicate.BlitTiledWithScaleFrom(surface, &rect, 1.0f, SDL_SCALEMODE_LINEAR));
CHECK(surface.BlitUncheckedTo(duplicate, &rect, &rect));
CHECK(duplicate.BlitUncheckedFrom(surface, &rect, &rect));
CHECK(surface.BlitUncheckedScaledTo(duplicate, &rect, SDL_SCALEMODE_LINEAR, &rect));
CHECK(duplicate.BlitUncheckedScaledFrom(surface, &rect, SDL_SCALEMODE_LINEAR, &rect));
CHECK(surface.StretchTo(duplicate, &rect, &rect, SDL_SCALEMODE_LINEAR));
CHECK(surface.Lock());
surface.Unlock();
CHECK(surface.WritePixel(1, 1, 50, 60, 70, 80));
CHECK(surface.WritePixelFloat(2, 2, 0.1f, 0.2f, 0.3f, 0.4f));
float fr = 0.0f;
float fg = 0.0f;
float fb = 0.0f;
float fa = 0.0f;
CHECK(surface.ReadPixelFloat(1, 1, &fr, &fg, &fb, &fa));
CHECK((surface.PremultiplyAlpha(false) || !surface.PremultiplyAlpha(false)));
auto rotated = surface.Rotate(90.0f);
CHECK(static_cast<bool>(rotated));
auto bmpPath = temp_path("hdk_surface_test.bmp");
auto pngPath = temp_path("hdk_surface_test.png");
CHECK(surface.SaveBMP(bmpPath.string().c_str()));
(void)surface.SavePNG(pngPath.string().c_str());
auto loadedBmp = hdk::sdl::Surface::LoadBMP(bmpPath.string().c_str());
CHECK(static_cast<bool>(loadedBmp));
auto loadedPng = hdk::sdl::Surface::LoadPNG(pngPath.string().c_str());
(void)loadedPng;
auto loadedSurface = hdk::sdl::Surface::LoadSurface(bmpPath.string().c_str());
CHECK(static_cast<bool>(loadedSurface));
}
+33
View File
@@ -0,0 +1,33 @@
#include <doctest/doctest.h>
#include <SDL3/SDL.h>
#include <hdk/sdl/video.hpp>
#include "SDL_headless_fixture.hpp"
TEST_CASE("Video helper bindings are exercised") {
SDLSession sdl;
if (!sdl.IsInitialized()) {
INFO(SDL_GetError());
CHECK(false);
return;
}
auto [window, renderer] = hdk::sdl::CreateWindowAndRenderer("hdk-video-binding-test", 64, 64, SDL_WINDOW_HIDDEN);
if (window && renderer) {
auto rendererFromWindow = window.GetRenderer();
auto windowFromRenderer = renderer.GetWindow();
CHECK(static_cast<bool>(rendererFromWindow));
CHECK(static_cast<bool>(windowFromRenderer));
} else {
CHECK_FALSE(static_cast<bool>(window));
CHECK_FALSE(static_cast<bool>(renderer));
}
auto [secondWindow, secondRenderer] =
hdk::sdl::CreateWindowAndRenderer("hdk-video-binding-test-2", 1, 1, SDL_WINDOW_HIDDEN);
CHECK(static_cast<bool>(secondWindow) == static_cast<bool>(secondRenderer));
}
+38
View File
@@ -2,6 +2,9 @@
#include <SDL3/SDL.h>
#include <string>
#include <hdk/sdl/video.hpp>
#include <hdk/sdl/video/Window.hpp>
#include "SDL_headless_fixture.hpp"
@@ -87,7 +90,42 @@ TEST_CASE("Window bindings are exercised") {
(void)window.GetProgressState();
(void)window.GetProgressValue();
CHECK((window.SetProgressState(SDL_PROGRESS_STATE_NORMAL) || !window.SetProgressState(SDL_PROGRESS_STATE_NORMAL)));
CHECK((window.SetProgressValue(0.5f) || !window.SetProgressValue(0.5f)));
auto props = window.GetProperties();
CHECK((props.GetPropertyType("hdk-window-test-missing") == SDL_PROPERTY_TYPE_INVALID));
auto withProps = hdk::sdl::Window::CreateWithProperties(props);
CHECK((static_cast<bool>(withProps) || !static_cast<bool>(withProps)));
CHECK((std::string(window.GetTitle()).size() >= 0));
CHECK((window.SetTitle("renamed-window") || !window.SetTitle("renamed-window")));
CHECK((window.SetAlwaysOnTop(false) || !window.SetAlwaysOnTop(false)));
CHECK((window.SetModal(false) || !window.SetModal(false)));
CHECK((window.SetResizable(true) || !window.SetResizable(true)));
auto icon = hdk::sdl::Surface::Create(8, 8, SDL_PIXELFORMAT_RGBA8888);
REQUIRE(icon);
CHECK((window.SetIcon(icon) || !window.SetIcon(icon)));
CHECK((window.SetShape(icon) || !window.SetShape(icon)));
auto popup = window.CreatePopup(0, 0, 10, 10, SDL_WINDOW_HIDDEN | SDL_WINDOW_TOOLTIP);
CHECK((static_cast<bool>(popup) || !static_cast<bool>(popup)));
CHECK((window.DestroySurface() || !window.DestroySurface()));
CHECK((window.Flash(SDL_FLASH_BRIEFLY) || !window.Flash(SDL_FLASH_BRIEFLY)));
CHECK((window.Hide() || !window.Hide()));
CHECK((window.Maximize() || !window.Maximize()));
CHECK((window.Minimize() || !window.Minimize()));
CHECK((window.Raise() || !window.Raise()));
CHECK((window.Restore() || !window.Restore()));
CHECK((window.Show() || !window.Show()));
CHECK((window.ShowSystemMenu(0, 0) || !window.ShowSystemMenu(0, 0)));
CHECK((window.Sync() || !window.Sync()));
CHECK((window.UpdateSurface() || !window.UpdateSurface()));
CHECK((window.UpdateSurfaceRects(&safeArea, 1) || !window.UpdateSurfaceRects(&safeArea, 1)));
auto renderer = window.GetRenderer();
CHECK((static_cast<bool>(renderer) || !static_cast<bool>(renderer)));
}