Skip to content

Commit

Permalink
-capture on click, save on release
Browse files Browse the repository at this point in the history
-go single threaded
-discard capture on hold
-reduce buffer size
  • Loading branch information
HookedBehemoth committed Apr 28, 2020
1 parent ac10ae6 commit cf10ccc
Showing 1 changed file with 82 additions and 92 deletions.
174 changes: 82 additions & 92 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ extern u32 __start__;

u32 __nx_applet_type = AppletType_None;

/* TODO: Reduce this to effectively 0 */
#define INNER_HEAP_SIZE 0x4000
#define INNER_HEAP_SIZE 0x0
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
char nx_inner_heap[INNER_HEAP_SIZE];

Expand Down Expand Up @@ -44,7 +43,8 @@ void __libnx_initheap(void) {
bool initialized = false;

void __attribute__((weak)) __appInit(void) {
svcSleepThread(5'000'000'000);
if ((armGetSystemTick() / armGetSystemTickFreq()) < 10)
svcSleepThread(5'000'000'000);

R_ABORT_UNLESS(smInitialize());
{
Expand All @@ -56,7 +56,7 @@ void __attribute__((weak)) __appInit(void) {
setsysExit();
}

if (hosversionAtLeast(3,0,0)) {
if (hosversionAtLeast(3, 0, 0)) {
R_ABORT_UNLESS(hidsysInitialize());
R_ABORT_UNLESS(capsscInitialize());
R_ABORT_UNLESS(fsInitialize());
Expand Down Expand Up @@ -103,7 +103,7 @@ constexpr const u32 InSize = InLineSize * Height;
constexpr const u32 OutSize = OutLineSize * Height;
constexpr const u32 FileSize = OutSize + 0x36;

constexpr const u64 divider = 20;
constexpr const u64 divider = 10;
constexpr const u32 InBufferSize = InLineSize * divider;
constexpr const u32 OutBufferSize = OutLineSize * divider;

Expand All @@ -129,9 +129,6 @@ constexpr const bmp_t bmp = {
static u8 in_buffer[InBufferSize];
static u8 out_buffer[OutBufferSize];

bool should_run;
bool request_capture;

char path_buffer[FS_MAX_PATH];

#include <functional>
Expand All @@ -147,121 +144,114 @@ class ScopeGuard {
void Cancel() { m_f = nullptr; };
};

#define R_CONTINUE(res_expr) \
#define R_TRY(res_expr) \
({ \
auto res = (res_expr); \
if (R_FAILED(res)) \
continue; \
return res; \
})

void CaptureFunction(void *) {
Result Capture() {
/* Get filesystem handle. */
FsFileSystem sdmc;
if (R_FAILED(fsOpenSdCardFileSystem(&sdmc))) {
should_run = false;
return;
}

while (should_run) {
/* Sleep thread until prompted */
if (!request_capture) {
svcSleepThread(100'000'000);
continue;
}

ScopeGuard flag_guard([] { request_capture = false; });

/* Open read stream */
u64 size, width, height;
R_CONTINUE(capsscOpenRawScreenShotReadStream(&size, &width, &height, ViLayerStack_Default, 100'000'000));
ScopeGuard stream_guard([] { capsscCloseRawScreenShotReadStream(); });

/* Notify capture. */
/* TODO! */
/* ScopeGuard notify_guard([] { capsscNotifyTakingScreenShotFailed(); }) */

/* Make unique path. */
u64 tick = armGetSystemTick();
std::snprintf(path_buffer, 0x20, "/%ld.bmp", tick);

/* Create file. */
R_CONTINUE(fsFsCreateFile(&sdmc, path_buffer, FileSize, 0));
ScopeGuard rm_guard([&sdmc] { fsFsDeleteFile(&sdmc, path_buffer); });

FsFile file;
R_CONTINUE(fsFsOpenFile(&sdmc, path_buffer, FsOpenMode_Write, &file));
ScopeGuard file_guard([&file] { fsFileClose(&file); });

off_t offset = 0;
fsFileWrite(&file, 0, &bmp, 54, FsWriteOption_None);
offset += 54;

u64 written = 0;
for (int y = (Height / divider) - 1; y >= 0; y--) {
/* Read raw image data */
R_CONTINUE(capsscReadRawScreenShotReadStream(&written, in_buffer, sizeof(in_buffer), y * sizeof(in_buffer)));

/* Resample buffer bottom up. */
for (int div_y = (divider - 1); div_y >= 0; div_y--) {
u8 *out = out_buffer + (div_y * OutLineSize);
u8 *in = in_buffer + ((divider - div_y - 1) * InLineSize);

/* RGBX to RGB bitmap */
for (u32 x = 0; x < Width; x++) {
out[0] = in[2];
out[1] = in[1];
out[2] = in[0];
in += 4;
out += 3;
}
R_TRY(fsOpenSdCardFileSystem(&sdmc));
ScopeGuard fs_guard([&sdmc] { fsFsClose(&sdmc); });

/* Make unique path. */
u64 tick = armGetSystemTick();
std::snprintf(path_buffer, 0x20, "/%ld.bmp", tick);

/* Create file. */
R_TRY(fsFsCreateFile(&sdmc, path_buffer, FileSize, 0));
ScopeGuard rm_guard([&sdmc] { fsFsDeleteFile(&sdmc, path_buffer); });

/* Open file. */
FsFile file;
R_TRY(fsFsOpenFile(&sdmc, path_buffer, FsOpenMode_Write, &file));
ScopeGuard file_guard([&file] { fsFileClose(&file); });

/* Write bitmap header. */
off_t offset = 0;
fsFileWrite(&file, 0, &bmp, 54, FsWriteOption_None);
offset += 54;

u64 written = 0;
for (int y = (Height / divider) - 1; y >= 0; y--) {
/* Read raw image data */
R_TRY(capsscReadRawScreenShotReadStream(&written, in_buffer, sizeof(in_buffer), y * sizeof(in_buffer)));

/* Resample buffer bottom up. */
for (int div_y = (divider - 1); div_y >= 0; div_y--) {
u8 *out = out_buffer + (div_y * OutLineSize);
u8 *in = in_buffer + ((divider - div_y - 1) * InLineSize);

/* RGBX to RGB bitmap */
for (u32 x = 0; x < Width; x++) {
out[0] = in[2];
out[1] = in[1];
out[2] = in[0];
in += 4;
out += 3;
}

/* Write to file. */
fsFileWrite(&file, offset, out_buffer, sizeof(out_buffer), FsWriteOption_None);
offset += sizeof(out_buffer);
}

rm_guard.Cancel();
/* notify_guard.Cancel(); */
/* Write to file. */
R_TRY(fsFileWrite(&file, offset, out_buffer, sizeof(out_buffer), FsWriteOption_None));
offset += sizeof(out_buffer);
}
/* Close filesystem. */
fsFsClose(&sdmc);

rm_guard.Cancel();

return 0;
}

int main(int argc, char *argv[]) {
/* Quietly exit on unsupported versions. */
if (!initialized)
return 0;

should_run = true;
request_capture = false;

bool held = false;

Thread capture_thread;
R_ABORT_UNLESS(threadCreate(&capture_thread, CaptureFunction, nullptr, nullptr, 0x1000, 0x20, -2));
R_ABORT_UNLESS(threadStart(&capture_thread));
u64 start_tick = 0;

/* Obtain capture button event. */
Event event;
R_ABORT_UNLESS(hidsysAcquireCaptureButtonEventHandle(&event));
eventClear(&event);

/* Loop forever. */
while (true) {
if (R_SUCCEEDED(eventWait(&event, UINT64_MAX))) {
held = !held;
if (held) {
request_capture = true;
}
if (R_SUCCEEDED(eventWait(&event, 17'000'000))) {
eventClear(&event);
if (!held) {
/* Capture screen in VI. */
if (R_SUCCEEDED(capsscOpenRawScreenShotReadStream(nullptr, nullptr, nullptr, ViLayerStack_Default, 100'000'000))) {
held = true;
start_tick = armGetSystemTick();
}
} else if (start_tick != 0) {
/* Capture bitmap in file. */
Capture();
/* Discard capture. */
capsscCloseRawScreenShotReadStream();
start_tick = 0;
held = false;
} else {
held = false;
}
} else {
/* Something went horribly wrong! */
break;
if (start_tick != 0) {
/* If held for more than half a second we discard the capture. */
if ((armGetSystemTick() - start_tick) >= (armGetSystemTickFreq() / 2)) {
capsscCloseRawScreenShotReadStream();
start_tick = 0;
}
}
}
}

/* Close button event. */
eventClose(&event);
should_run = false;

R_ABORT_UNLESS(threadWaitForExit(&capture_thread));
R_ABORT_UNLESS(threadClose(&capture_thread));
return 0;
}

0 comments on commit cf10ccc

Please sign in to comment.