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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
#include <algorithm>
#include <print>
#include <format>
#include <filesystem>
#include <fstream>
#include <vector>
#include <hyprgraphics/resource/AsyncResourceGatherer.hpp>
#include <hyprgraphics/resource/resources/TextResource.hpp>
#include <hyprgraphics/resource/resources/ImageResource.hpp>
#include <hyprutils/memory/UniquePtr.hpp>
#include <hyprutils/memory/Atomic.hpp>
#include <hyprutils/math/Vector2D.hpp>
#include "shared.hpp"
using namespace Hyprutils::Memory;
using namespace Hyprutils::Math;
using namespace Hyprgraphics;
#define UP CUniquePointer
static UP<CAsyncResourceGatherer> g_asyncResourceGatherer;
static struct {
std::mutex wakeupMutex;
std::condition_variable wakeup;
bool exit = false;
bool needsToProcess = false;
int loadedAssets = 0;
std::mutex resourcesMutex;
std::vector<CAtomicSharedPointer<IAsyncResource>> resources;
} state;
//
static bool renderText(const std::string& text, Vector2D max = {}) {
// this stinks a bit but it's due to our ASP impl.
auto resource =
makeAtomicShared<CTextResource>(CTextResource::STextResourceData{.text = text, .fontSize = 72, .maxSize = max.x == 0 ? std::nullopt : std::optional<Vector2D>(max)});
CAtomicSharedPointer<IAsyncResource> resourceGeneric(resource);
g_asyncResourceGatherer->enqueue(resourceGeneric);
state.resourcesMutex.lock();
state.resources.emplace_back(std::move(resourceGeneric));
state.resourcesMutex.unlock();
resource->m_events.finished.listenStatic([]() {
state.needsToProcess = true;
state.wakeup.notify_all();
});
std::println("Enqueued \"{}\" successfully.", text);
return true;
}
static bool renderImage(const std::string& path) {
// this stinks a bit but it's due to our ASP impl.
auto resource = makeAtomicShared<CImageResource>(path);
CAtomicSharedPointer<IAsyncResource> resourceGeneric(resource);
g_asyncResourceGatherer->enqueue(resourceGeneric);
state.resourcesMutex.lock();
state.resources.emplace_back(std::move(resourceGeneric));
state.resourcesMutex.unlock();
resource->m_events.finished.listenStatic([]() {
state.needsToProcess = true;
state.wakeup.notify_all();
});
std::println("Enqueued \"{}\" successfully.", path);
return true;
}
int main(int argc, char** argv, char** envp) {
int ret = 0;
g_asyncResourceGatherer = makeUnique<CAsyncResourceGatherer>();
EXPECT(renderText("Hello World"), true);
EXPECT(renderText("<b><i>Test markup</i></b>"), true);
EXPECT(renderText("Test ellipsis!!!!!", {512, 190}),
true);
EXPECT(renderImage("./resource/images/hyprland.png"), true);
while (!state.exit) {
std::unique_lock lk(state.wakeupMutex);
if (!state.needsToProcess) // avoid a lock if a thread managed to request something already since we .unlock()ed
state.wakeup.wait_for(lk, std::chrono::seconds(5), [] { return state.needsToProcess; }); // wait for events
if (state.exit)
break;
state.needsToProcess = false;
state.resourcesMutex.lock();
const bool SHOULD_EXIT = std::ranges::all_of(state.resources, [](const auto& e) { return !!e->m_ready; });
state.resourcesMutex.unlock();
if (SHOULD_EXIT)
break;
lk.unlock();
}
// all assets should be done, let's render them
size_t idx = 0;
for (const auto& r : state.resources) {
const auto TEST_DIR = std::filesystem::current_path().string() + "/test_output";
// try to write it for inspection
if (!std::filesystem::exists(TEST_DIR))
std::filesystem::create_directory(TEST_DIR);
std::string name = std::format("render-arg-{}", idx);
EXPECT(!!r->m_asset.cairoSurface->cairo(), true);
//NOLINTNEXTLINE
if (!r->m_asset.cairoSurface->cairo())
continue;
EXPECT(cairo_surface_write_to_png(r->m_asset.cairoSurface->cairo(), (TEST_DIR + "/" + name + ".png").c_str()), CAIRO_STATUS_SUCCESS);
idx++;
}
g_asyncResourceGatherer.reset();
return ret;
}
|