Compare commits
34 Commits
rewrite
...
issue-temp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85d09107ed | ||
|
|
b16df2607c | ||
|
|
7745530764 | ||
|
|
0bab0f6700 | ||
|
|
38ab370cf1 | ||
|
|
5cea6c8df4 | ||
|
|
e4e0118c1a | ||
|
|
accdaaed2a | ||
|
|
3fb90e8197 | ||
|
|
aba2cd5f18 | ||
|
|
e5ea18e81a | ||
|
|
4720a49923 | ||
|
|
7871225999 | ||
|
|
1e5d09e85a | ||
|
|
a647494306 | ||
|
|
c801e28523 | ||
|
|
c9e1420a00 | ||
|
|
bc2f4ec581 | ||
|
|
9592d76c2c | ||
|
|
a266203a92 | ||
|
|
17afdbaae2 | ||
|
|
f6d7446eba | ||
|
|
c49129d408 | ||
|
|
f9a2ae5190 | ||
|
|
573b7d35e6 | ||
| a2b6eb94e4 | |||
|
|
95ff2dd3ba | ||
|
|
1c2e562dd6 | ||
|
|
9cb13f6be1 | ||
| 6a51b4eae5 | |||
| 14d9e99b7d | |||
| 36e8104dbb | |||
| 6bafa6a22e | |||
|
|
408b2903f2 |
Binary file not shown.
BIN
.flask/icon.t3x
BIN
.flask/icon.t3x
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"user": "astronautlevel2",
|
||||
"name": "Anemone3DS",
|
||||
"description": "A theme and boot splash manager for the Nintendo 3DS console"
|
||||
}
|
||||
39
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
39
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Found a bug? Report it here
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Steps to reproduce**
|
||||
***If you cannot reproduce the bug, please describe what you were doing in as much detail as possible***
|
||||
*If you were scanning using the QR scanner, ensure you include a link to the theme you were attempting to download.*
|
||||
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
Add screenshots of any error screens you encountered. Bug reports without screenshots will take longer to solve, so we recommend you get some!
|
||||
|
||||
|
||||
**Crash dumps**
|
||||
If your bug causes a crash in Luma3DS, please upload any crash dumps generated. You can find these in `SD:/luma/dumps/armX` (`X = 9 or 11`) with the name Luma3DS's exception handlers give you.
|
||||
|
||||
|
||||
**System information**
|
||||
*System model* e.g. new3DS XL
|
||||
|
||||
*System firmware version* e.g. 11.14.0 (this can be found in the System Settings applet by default)
|
||||
|
||||
*Anemone3DS version* e.g. v2.2.0 (found in the bottom-left of Anemone3DS)
|
||||
|
||||
*Luma3DS version* e.g. v10.2.1 (found in the menu when you hold Select on boot)
|
||||
|
||||
|
||||
**If you are not on the [latest version of Anemone3DS](https://github.com/astronautlevel2/Anemone3DS/releases/latest), your bug report will likely be closed. Ensure the bug occurs in the latest build!**
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -4,7 +4,7 @@
|
||||
* Dawid Eckert ([@daedreth](https://github.com/daedreth))
|
||||
* Dylan G. ([@helloman892](https://github.com/helloman892))
|
||||
* Nils P. ([@ZetaDesigns](https://github.com/ZetaDesigns))
|
||||
* Matt Kenny ([@8kenn](https://github.com/8kenn))
|
||||
* Matt Kenny ([@KennLDN](https://github.com/KennLDN))
|
||||
|
||||
# Minor Contributors
|
||||
* Nic ([@Wizzrobes](https://github.com/Wizzrobes))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||

|
||||
|
||||
A Theme and Splashscreen Manager for the Nintendo 3DS, written in C.\
|
||||
To-do list here: https://trello.com/b/F1YSa1VK
|
||||
|
||||
# Dependencies
|
||||
* devkitARM, which can be installed following the instructions [here](https://devkitpro.org/wiki/Getting_Started).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,22 +30,24 @@
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
u16 *camera_buffer;
|
||||
C2D_Image image;
|
||||
C3D_Tex *tex;
|
||||
Handle mutex;
|
||||
volatile bool finished;
|
||||
volatile bool closed;
|
||||
volatile bool success;
|
||||
Handle cancel;
|
||||
Handle started;
|
||||
u16* camera_buffer;
|
||||
|
||||
Handle event_stop;
|
||||
Thread cam_thread, ui_thread;
|
||||
|
||||
LightEvent event_cam_info, event_ui_info;
|
||||
|
||||
CondVar cond;
|
||||
LightLock mut;
|
||||
u32 num_readers_active;
|
||||
bool writer_waiting;
|
||||
bool writer_active;
|
||||
|
||||
bool any_update;
|
||||
|
||||
bool capturing;
|
||||
struct quirc* context;
|
||||
} qr_data;
|
||||
|
||||
bool init_qr(void);
|
||||
void exit_qr(qr_data *data);
|
||||
void take_picture(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -55,6 +55,8 @@ typedef enum {
|
||||
INSTALL_LOADING_REMOTE_PREVIEW,
|
||||
INSTALL_LOADING_REMOTE_BGM,
|
||||
|
||||
INSTALL_DUMPING_THEME,
|
||||
|
||||
INSTALL_NONE,
|
||||
} InstallType;
|
||||
|
||||
@@ -81,6 +83,8 @@ typedef enum {
|
||||
TEXT_INSTALL_LOADING_REMOTE_PREVIEW,
|
||||
TEXT_INSTALL_LOADING_REMOTE_BGM,
|
||||
|
||||
TEXT_INSTALL_DUMPING_THEME,
|
||||
|
||||
// Other text
|
||||
TEXT_VERSION,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -39,6 +39,8 @@ Result close_archives(void);
|
||||
u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf);
|
||||
u32 zip_memory_to_buf(char *file_name, void * zip_memory, size_t zip_size, char ** buf);
|
||||
u32 zip_file_to_buf(char *file_name, u16 *zip_path, char **buf);
|
||||
u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf);
|
||||
u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char *in_buf, u32 size);
|
||||
|
||||
Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf);
|
||||
void remake_file(FS_Path path, FS_Archive archive, u32 size);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -128,7 +128,7 @@ Instructions_s extra_instructions[3] = {
|
||||
},
|
||||
{
|
||||
"\uE07B Browse ThemePlaza",
|
||||
NULL,
|
||||
"\uE07C Dump Current Theme"
|
||||
},
|
||||
{
|
||||
"\uE004 Sorting menu",
|
||||
@@ -142,4 +142,4 @@ Instructions_s extra_instructions[3] = {
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -127,4 +127,4 @@ void handle_scrolling(Entry_List_s * list);
|
||||
void load_icons_thread(void * void_arg);
|
||||
u32 load_data(char * filename, Entry_s entry, char ** buf);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "draw.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define THEMEPLAZA_BASE_URL "https://themeplaza.eu"
|
||||
#define THEMEPLAZA_BASE_URL "https://themeplaza.art"
|
||||
#define THEMEPLAZA_API_URL "/api/anemone/v1"
|
||||
#define THEMEPLAZA_BASE_API_URL THEMEPLAZA_BASE_URL THEMEPLAZA_API_URL
|
||||
|
||||
@@ -52,6 +52,6 @@
|
||||
#define CACHE_PATH_FORMAT "/3ds/" APP_TITLE "/cache/%" JSON_INTEGER_FORMAT
|
||||
|
||||
bool themeplaza_browser(EntryMode mode);
|
||||
u32 http_get(const char *url, char ** filename, char ** buf, InstallType install_type);
|
||||
Result http_get(const char *url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -75,6 +75,8 @@ Result bgm_install(Entry_s theme);
|
||||
|
||||
Result shuffle_install(Entry_List_s themes);
|
||||
|
||||
Result dump_theme(void);
|
||||
|
||||
void themes_check_installed(void * void_arg);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
485
source/camera.c
485
source/camera.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,28 +36,63 @@
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
void exit_qr(qr_data *data)
|
||||
static void start_read(qr_data *data)
|
||||
{
|
||||
DEBUG("Exiting QR\n");
|
||||
svcSignalEvent(data->cancel);
|
||||
while(!data->finished)
|
||||
svcSleepThread(1000000);
|
||||
svcCloseHandle(data->cancel);
|
||||
data->capturing = false;
|
||||
LightLock_Lock(&data->mut);
|
||||
while(data->writer_waiting || data->writer_active)
|
||||
{
|
||||
CondVar_WaitTimeout(&data->cond, &data->mut, 1000000);
|
||||
}
|
||||
|
||||
free(data->camera_buffer);
|
||||
free(data->tex);
|
||||
quirc_destroy(data->context);
|
||||
AtomicIncrement(&data->num_readers_active);
|
||||
LightLock_Unlock(&data->mut);
|
||||
}
|
||||
static void stop_read(qr_data *data)
|
||||
{
|
||||
LightLock_Lock(&data->mut);
|
||||
AtomicDecrement(&data->num_readers_active);
|
||||
if(data->num_readers_active == 0)
|
||||
{
|
||||
CondVar_Signal(&data->cond);
|
||||
}
|
||||
LightLock_Unlock(&data->mut);
|
||||
}
|
||||
static void start_write(qr_data *data)
|
||||
{
|
||||
LightLock_Lock(&data->mut);
|
||||
data->writer_waiting = true;
|
||||
|
||||
while(data->num_readers_active)
|
||||
{
|
||||
CondVar_WaitTimeout(&data->cond, &data->mut, 1000000);
|
||||
}
|
||||
|
||||
data->writer_waiting = false;
|
||||
data->writer_active = true;
|
||||
|
||||
LightLock_Unlock(&data->mut);
|
||||
}
|
||||
static void stop_write(qr_data *data)
|
||||
{
|
||||
LightLock_Lock(&data->mut);
|
||||
|
||||
data->writer_active = false;
|
||||
CondVar_Broadcast(&data->cond);
|
||||
|
||||
LightLock_Unlock(&data->mut);
|
||||
}
|
||||
|
||||
void capture_cam_thread(void *arg)
|
||||
static void capture_cam_thread(void *arg)
|
||||
{
|
||||
qr_data *data = (qr_data *) arg;
|
||||
Handle events[3] = {0};
|
||||
events[0] = data->cancel;
|
||||
u32 transferUnit;
|
||||
|
||||
u16 *buffer = calloc(1, 400 * 240 * sizeof(u16));
|
||||
Handle cam_events[3] = {0};
|
||||
cam_events[0] = data->event_stop;
|
||||
|
||||
u32 transferUnit;
|
||||
const u32 bufsz = 400 * 240 * sizeof(u16);
|
||||
u16 *buffer = linearAlloc(bufsz);
|
||||
|
||||
camInit();
|
||||
CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A);
|
||||
CAMU_SetOutputFormat(SELECT_OUT1, OUTPUT_RGB_565, CONTEXT_A);
|
||||
@@ -66,38 +101,42 @@ void capture_cam_thread(void *arg)
|
||||
CAMU_SetAutoExposure(SELECT_OUT1, true);
|
||||
CAMU_SetAutoWhiteBalance(SELECT_OUT1, true);
|
||||
CAMU_Activate(SELECT_OUT1);
|
||||
CAMU_GetBufferErrorInterruptEvent(&events[2], PORT_CAM1);
|
||||
CAMU_GetBufferErrorInterruptEvent(&cam_events[2], PORT_CAM1);
|
||||
CAMU_SetTrimming(PORT_CAM1, false);
|
||||
CAMU_GetMaxBytes(&transferUnit, 400, 240);
|
||||
CAMU_SetTransferBytes(PORT_CAM1, transferUnit, 400, 240);
|
||||
CAMU_ClearBuffer(PORT_CAM1);
|
||||
CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), (s16) transferUnit);
|
||||
CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit);
|
||||
CAMU_StartCapture(PORT_CAM1);
|
||||
svcSignalEvent(data->started);
|
||||
|
||||
bool cancel = false;
|
||||
while (!cancel)
|
||||
|
||||
while (!cancel)
|
||||
{
|
||||
s32 index = 0;
|
||||
svcWaitSynchronizationN(&index, events, 3, false, U64_MAX);
|
||||
svcWaitSynchronizationN(&index, cam_events, 3, false, U64_MAX);
|
||||
switch(index) {
|
||||
case 0:
|
||||
DEBUG("Cancel event received\n");
|
||||
cancel = true;
|
||||
break;
|
||||
case 1:
|
||||
svcCloseHandle(events[1]);
|
||||
events[1] = 0;
|
||||
svcWaitSynchronization(data->mutex, U64_MAX);
|
||||
memcpy(data->camera_buffer, buffer, 400 * 240 * sizeof(u16));
|
||||
GSPGPU_FlushDataCache(data->camera_buffer, 400 * 240 * sizeof(u16));
|
||||
svcReleaseMutex(data->mutex);
|
||||
CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit);
|
||||
svcCloseHandle(cam_events[1]);
|
||||
cam_events[1] = 0;
|
||||
|
||||
start_write(data);
|
||||
memcpy(data->camera_buffer, buffer, bufsz);
|
||||
data->any_update = true;
|
||||
stop_write(data);
|
||||
|
||||
CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit);
|
||||
break;
|
||||
case 2:
|
||||
svcCloseHandle(events[1]);
|
||||
events[1] = 0;
|
||||
svcCloseHandle(cam_events[1]);
|
||||
cam_events[1] = 0;
|
||||
|
||||
CAMU_ClearBuffer(PORT_CAM1);
|
||||
CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit);
|
||||
CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit);
|
||||
CAMU_StartCapture(PORT_CAM1);
|
||||
break;
|
||||
default:
|
||||
@@ -115,219 +154,273 @@ void capture_cam_thread(void *arg)
|
||||
CAMU_ClearBuffer(PORT_CAM1);
|
||||
CAMU_Activate(SELECT_NONE);
|
||||
camExit();
|
||||
free(buffer);
|
||||
for(int i = 0; i < 3; i++) {
|
||||
if(events[i] != 0) {
|
||||
svcCloseHandle(events[i]);
|
||||
events[i] = 0;
|
||||
|
||||
linearFree(buffer);
|
||||
for(int i = 1; i < 3; i++)
|
||||
{
|
||||
if(cam_events[i] != 0) {
|
||||
svcCloseHandle(cam_events[i]);
|
||||
cam_events[i] = 0;
|
||||
}
|
||||
}
|
||||
svcCloseHandle(data->mutex);
|
||||
data->finished = true;
|
||||
|
||||
LightEvent_Signal(&data->event_cam_info);
|
||||
}
|
||||
|
||||
void update_ui(void *arg)
|
||||
static void update_ui(void *arg)
|
||||
{
|
||||
qr_data* data = (qr_data*) arg;
|
||||
C3D_Tex tex;
|
||||
|
||||
while (!data->finished)
|
||||
static const Tex3DS_SubTexture subt3x = { 400, 240, 0.0f, 1.0f, 400.0f/512.0f, 1.0f - (240.0f/256.0f) };
|
||||
C3D_TexInit(&tex, 512, 256, GPU_RGB565);
|
||||
|
||||
C3D_TexSetFilter(&tex, GPU_LINEAR, GPU_LINEAR);
|
||||
|
||||
while(svcWaitSynchronization(data->event_stop, 2 * 1000 * 1000ULL) == 0x09401BFE) // timeout of 2ms occured, still have 14 for copy and render
|
||||
{
|
||||
draw_base_interface();
|
||||
|
||||
// Untiled texture loading code adapted from FBI
|
||||
svcWaitSynchronization(data->mutex, U64_MAX);
|
||||
for(u32 x = 0; x < 400 && !data->finished; x++) {
|
||||
for(u32 y = 0; y < 256 && !data->finished; y++) {
|
||||
u32 dstPos = ((((y >> 3) * (512 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) * sizeof(u16);
|
||||
u32 srcPos = (y * 400 + x) * sizeof(u16);
|
||||
|
||||
memcpy(&((u8*) data->image.tex->data)[dstPos], &((u8*) data->camera_buffer)[srcPos], sizeof(u16));
|
||||
}
|
||||
}
|
||||
|
||||
svcReleaseMutex(data->mutex);
|
||||
|
||||
if (data->finished)
|
||||
start_read(data);
|
||||
if(data->any_update)
|
||||
{
|
||||
end_frame();
|
||||
break;
|
||||
}
|
||||
for(u32 y = 0; y < 240; y++) {
|
||||
const u32 srcPos = y * 400;
|
||||
for(u32 x = 0; x < 400; x++) {
|
||||
const u32 dstPos = ((((y >> 3) * (512 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3)));
|
||||
|
||||
C2D_DrawImageAt(data->image, 0.0f, 0.0f, 0.4f, NULL, 1.0f, 1.0f);
|
||||
((u16*)tex.data)[dstPos] = data->camera_buffer[srcPos + x];
|
||||
}
|
||||
}
|
||||
data->any_update = false;
|
||||
}
|
||||
stop_read(data);
|
||||
|
||||
C2D_DrawImageAt((C2D_Image){ &tex, &subt3x }, 0.0f, 0.0f, 0.4f, NULL, 1.0f, 1.0f);
|
||||
|
||||
set_screen(bottom);
|
||||
draw_text_center(GFX_BOTTOM, 4, 0.5, 0.5, 0.5, colors[COLOR_WHITE], "Press \uE005 To Quit");
|
||||
end_frame();
|
||||
}
|
||||
data->closed = true;
|
||||
|
||||
C3D_TexDelete(&tex);
|
||||
LightEvent_Signal(&data->event_ui_info);
|
||||
}
|
||||
|
||||
bool start_capture_cam(qr_data *data)
|
||||
static bool start_capture_cam(qr_data *data)
|
||||
{
|
||||
data->mutex = 0;
|
||||
data->cancel = 0;
|
||||
svcCreateEvent(&data->cancel, RESET_STICKY);
|
||||
svcCreateMutex(&data->mutex, false);
|
||||
if(threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, true) == NULL)
|
||||
return false;
|
||||
svcWaitSynchronization(data->started, U64_MAX);
|
||||
if(threadCreate(update_ui, data, 0x10000, 0x1A, 1, true) == NULL)
|
||||
if((data->cam_thread = threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, false)) == NULL)
|
||||
{
|
||||
exit_qr(data);
|
||||
throw_error("Capture cam thread creation failed\nPlease report this to the developers", ERROR_LEVEL_ERROR);
|
||||
LightEvent_Signal(&data->event_cam_info);
|
||||
LightEvent_Signal(&data->event_ui_info);
|
||||
return false;
|
||||
}
|
||||
if((data->ui_thread = threadCreate(update_ui, data, 0x10000, 0x1A, 1, false)) == NULL)
|
||||
{
|
||||
LightEvent_Signal(&data->event_ui_info);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_qr(qr_data *data)
|
||||
static bool update_qr(qr_data *data, struct quirc_data* scan_data)
|
||||
{
|
||||
hidScanInput();
|
||||
if (hidKeysDown() & (KEY_R | KEY_B | KEY_TOUCH)) {
|
||||
exit_qr(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data->capturing) {
|
||||
if(start_capture_cam(data))
|
||||
data->capturing = true;
|
||||
else {
|
||||
exit_qr(data);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (data->finished) {
|
||||
exit_qr(data);
|
||||
return;
|
||||
}
|
||||
|
||||
int w;
|
||||
int h;
|
||||
u8 *image = (u8*) quirc_begin(data->context, &w, &h);
|
||||
for (ssize_t x = 0; x < w; x++) {
|
||||
for (ssize_t y = 0; y < h; y++) {
|
||||
u16 px = data->camera_buffer[y * 400 + x];
|
||||
image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3);
|
||||
|
||||
start_read(data);
|
||||
for (int y = 0; y < h; y++) {
|
||||
const int actual_y = y * w;
|
||||
for (int x = 0; x < w; x++) {
|
||||
const int actual_off = actual_y + x;
|
||||
const u16 px = data->camera_buffer[actual_off];
|
||||
image[actual_off] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3);
|
||||
}
|
||||
}
|
||||
stop_read(data);
|
||||
|
||||
quirc_end(data->context);
|
||||
if(quirc_count(data->context) > 0)
|
||||
{
|
||||
struct quirc_code code;
|
||||
struct quirc_data scan_data;
|
||||
quirc_extract(data->context, 0, &code);
|
||||
if (!quirc_decode(&code, &scan_data))
|
||||
if (!quirc_decode(&code, scan_data))
|
||||
{
|
||||
exit_qr(data);
|
||||
|
||||
while (!data->finished) svcSleepThread(1000000);
|
||||
|
||||
draw_install(INSTALL_DOWNLOAD);
|
||||
char * zip_buf = NULL;
|
||||
char * filename = NULL;
|
||||
u32 zip_size = http_get((char*)scan_data.payload, &filename, &zip_buf, INSTALL_DOWNLOAD);
|
||||
|
||||
if(zip_size != 0)
|
||||
{
|
||||
draw_install(INSTALL_CHECKING_DOWNLOAD);
|
||||
|
||||
struct archive *a = archive_read_new();
|
||||
archive_read_support_format_zip(a);
|
||||
|
||||
int r = archive_read_open_memory(a, zip_buf, zip_size);
|
||||
archive_read_free(a);
|
||||
|
||||
if(r == ARCHIVE_OK)
|
||||
{
|
||||
EntryMode mode = MODE_AMOUNT;
|
||||
|
||||
char * buf = NULL;
|
||||
do {
|
||||
if(zip_memory_to_buf("body_LZ.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_THEMES;
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if(zip_memory_to_buf("splash.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_SPLASHES;
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if(zip_memory_to_buf("splashbottom.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_SPLASHES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(false);
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
if(mode != MODE_AMOUNT)
|
||||
{
|
||||
char path_to_file[0x107] = {0};
|
||||
sprintf(path_to_file, "%s%s", main_paths[mode], filename);
|
||||
char * extension = strrchr(path_to_file, '.');
|
||||
if (extension == NULL || strcmp(extension, ".zip"))
|
||||
strcat(path_to_file, ".zip");
|
||||
|
||||
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
|
||||
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
|
||||
data->success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("Zip downloaded is neither\na splash nor a theme.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("File downloaded isn't a zip.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
free(zip_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("Download failed.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
|
||||
free(filename);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void start_qr(qr_data *data)
|
||||
{
|
||||
svcCreateEvent(&data->event_stop, RESET_STICKY);
|
||||
LightEvent_Init(&data->event_cam_info, RESET_STICKY);
|
||||
LightEvent_Init(&data->event_ui_info, RESET_STICKY);
|
||||
LightLock_Init(&data->mut);
|
||||
CondVar_Init(&data->cond);
|
||||
|
||||
data->cam_thread = NULL;
|
||||
data->ui_thread = NULL;
|
||||
data->any_update = false;
|
||||
|
||||
data->context = quirc_new();
|
||||
quirc_resize(data->context, 400, 240);
|
||||
data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16));
|
||||
}
|
||||
static void exit_qr(qr_data *data)
|
||||
{
|
||||
svcSignalEvent(data->event_stop);
|
||||
|
||||
LightEvent_Wait(&data->event_ui_info);
|
||||
LightEvent_Clear(&data->event_ui_info);
|
||||
if(data->ui_thread != NULL)
|
||||
{
|
||||
threadJoin(data->ui_thread, U64_MAX);
|
||||
threadFree(data->ui_thread);
|
||||
data->ui_thread = NULL;
|
||||
}
|
||||
|
||||
LightEvent_Wait(&data->event_cam_info);
|
||||
LightEvent_Clear(&data->event_cam_info);
|
||||
if(data->cam_thread != NULL)
|
||||
{
|
||||
threadJoin(data->cam_thread, U64_MAX);
|
||||
threadFree(data->cam_thread);
|
||||
data->cam_thread = NULL;
|
||||
}
|
||||
|
||||
free(data->camera_buffer);
|
||||
data->camera_buffer = NULL;
|
||||
svcCloseHandle(data->event_stop);
|
||||
data->event_stop = 0;
|
||||
}
|
||||
|
||||
bool init_qr(void)
|
||||
{
|
||||
qr_data *data = calloc(1, sizeof(qr_data));
|
||||
data->capturing = false;
|
||||
data->finished = false;
|
||||
data->closed = false;
|
||||
svcCreateEvent(&data->started, RESET_STICKY);
|
||||
|
||||
data->context = quirc_new();
|
||||
quirc_resize(data->context, 400, 240);
|
||||
qr_data data;
|
||||
|
||||
data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16));
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
data->tex = (C3D_Tex*)malloc(sizeof(C3D_Tex));
|
||||
static const Tex3DS_SubTexture subt3x = { 512, 256, 0.0f, 1.0f, 1.0f, 0.0f };
|
||||
data->image = (C2D_Image){ data->tex, &subt3x };
|
||||
C3D_TexInit(data->image.tex, 512, 256, GPU_RGB565);
|
||||
C3D_TexSetFilter(data->image.tex, GPU_LINEAR, GPU_LINEAR);
|
||||
start_qr(&data);
|
||||
|
||||
while (!data->finished) update_qr(data);
|
||||
bool success = data->success;
|
||||
while (!data->closed) svcSleepThread(1000000);
|
||||
free(data);
|
||||
struct quirc_data* scan_data = calloc(1, sizeof(struct quirc_data));
|
||||
const bool ready = start_capture_cam(&data);
|
||||
bool finished = !ready;
|
||||
|
||||
while(!finished)
|
||||
{
|
||||
hidScanInput();
|
||||
if (hidKeysDown() & (KEY_R | KEY_B | KEY_TOUCH))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
finished = update_qr(&data, scan_data);
|
||||
svcSleepThread(50 * 1000 * 1000ULL); // only scan every 50ms
|
||||
}
|
||||
|
||||
exit_qr(&data);
|
||||
|
||||
bool success = false;
|
||||
if(finished && ready)
|
||||
{
|
||||
draw_install(INSTALL_DOWNLOAD);
|
||||
char * zip_buf = NULL;
|
||||
char * filename = NULL;
|
||||
u32 zip_size;
|
||||
Result res = http_get((char*)scan_data->payload, &filename, &zip_buf, &zip_size, INSTALL_DOWNLOAD, "application/zip");
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
free(filename);
|
||||
free(zip_buf);
|
||||
return false;
|
||||
}
|
||||
else if (R_DESCRIPTION(res) == RD_NO_DATA || R_DESCRIPTION(res) == RD_CANCEL_REQUESTED)
|
||||
{
|
||||
free(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(zip_size != 0)
|
||||
{
|
||||
draw_install(INSTALL_CHECKING_DOWNLOAD);
|
||||
|
||||
struct archive *a = archive_read_new();
|
||||
archive_read_support_format_zip(a);
|
||||
|
||||
int r = archive_read_open_memory(a, zip_buf, zip_size);
|
||||
archive_read_free(a);
|
||||
|
||||
if(r == ARCHIVE_OK)
|
||||
{
|
||||
EntryMode mode = MODE_AMOUNT;
|
||||
|
||||
char * buf = NULL;
|
||||
do {
|
||||
if(zip_memory_to_buf("body_LZ.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_THEMES;
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if(zip_memory_to_buf("splash.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_SPLASHES;
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if(zip_memory_to_buf("splashbottom.bin", zip_buf, zip_size, &buf) != 0)
|
||||
{
|
||||
mode = MODE_SPLASHES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(false);
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
if(mode != MODE_AMOUNT)
|
||||
{
|
||||
char path_to_file[0x107] = {0};
|
||||
sprintf(path_to_file, "%s%s", main_paths[mode], filename);
|
||||
char * extension = strrchr(path_to_file, '.');
|
||||
if (extension == NULL || strcmp(extension, ".zip"))
|
||||
strcat(path_to_file, ".zip");
|
||||
|
||||
remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size);
|
||||
buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf);
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("Zip downloaded is neither\na splash nor a theme.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("File downloaded isn't a zip.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
free(zip_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw_error("Download failed.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
|
||||
free(filename);
|
||||
}
|
||||
|
||||
free(scan_data);
|
||||
quirc_destroy(data.context);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -125,6 +125,7 @@ void init_screens(void)
|
||||
C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_SPLASHES], staticBuf, "Downloading splash list, please wait...");
|
||||
C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_PREVIEW], staticBuf, "Downloading preview, please wait...");
|
||||
C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_BGM], staticBuf, "Downloading BGM, please wait...");
|
||||
C2D_TextParse(&text[TEXT_INSTALL_DUMPING_THEME], staticBuf, "Dumping theme, please wait...");
|
||||
|
||||
for(int i = 0; i < TEXT_AMOUNT; i++)
|
||||
C2D_TextOptimize(&text[i]);
|
||||
@@ -300,7 +301,7 @@ void throw_error(char* error, ErrorLevel level)
|
||||
|
||||
draw_base_interface();
|
||||
draw_text_center(GFX_TOP, 100, 0.5f, 0.6f, 0.6f, colors[text_color], error);
|
||||
draw_c2d_text_center(GFX_TOP, 150, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], &text[bottom_text]);
|
||||
draw_c2d_text_center(GFX_TOP, 170, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], &text[bottom_text]);
|
||||
end_frame();
|
||||
|
||||
if(kDown & KEY_A) break;
|
||||
@@ -552,13 +553,18 @@ void draw_grid_interface(Entry_List_s* list, Instructions_s instructions)
|
||||
vertical_offset += 24;
|
||||
horizontal_offset += 16;
|
||||
|
||||
// theoretically impossible to have no icon when from the api
|
||||
/*
|
||||
if(!current_entry->placeholder_color)
|
||||
{
|
||||
*/
|
||||
C2D_Image * image = list->icons[i];
|
||||
C2D_DrawImageAt(*image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f);
|
||||
/*
|
||||
}
|
||||
else
|
||||
C2D_DrawRectSolid(horizontal_offset, vertical_offset, 0.5f, list->entry_size, list->entry_size, current_entry->placeholder_color);
|
||||
*/
|
||||
|
||||
if(i == selected_entry)
|
||||
{
|
||||
|
||||
174
source/fs.c
174
source/fs.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -25,29 +25,29 @@
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
|
||||
#include "fs.h"
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
FS_Archive ArchiveSD;
|
||||
FS_Archive ArchiveHomeExt;
|
||||
FS_Archive ArchiveThemeExt;
|
||||
|
||||
|
||||
Result open_archives(void)
|
||||
{
|
||||
romfsInit();
|
||||
u8 regionCode;
|
||||
u32 archive1;
|
||||
u32 archive2;
|
||||
|
||||
|
||||
Result res = 0;
|
||||
|
||||
|
||||
FS_Path home;
|
||||
FS_Path theme;
|
||||
|
||||
|
||||
CFGU_SecureInfoGetRegion(®ionCode);
|
||||
switch(regionCode)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ Result open_archives(void)
|
||||
archive1 = 0x00;
|
||||
archive2 = 0x00;
|
||||
}
|
||||
|
||||
|
||||
if(R_FAILED(res = FSUSER_OpenArchive(&ArchiveSD, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))) return res;
|
||||
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/Themes"), FS_ATTRIBUTE_DIRECTORY);
|
||||
@@ -75,43 +75,43 @@ Result open_archives(void)
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds"), FS_ATTRIBUTE_DIRECTORY);
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE), FS_ATTRIBUTE_DIRECTORY);
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_ASCII, "/3ds/" APP_TITLE "/cache"), FS_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
|
||||
u32 homeMenuPath[3] = {MEDIATYPE_SD, archive2, 0};
|
||||
home.type = PATH_BINARY;
|
||||
home.size = 0xC;
|
||||
home.data = homeMenuPath;
|
||||
if(R_FAILED(res = FSUSER_OpenArchive(&ArchiveHomeExt, ARCHIVE_EXTDATA, home))) return res;
|
||||
|
||||
|
||||
u32 themePath[3] = {MEDIATYPE_SD, archive1, 0};
|
||||
theme.type = PATH_BINARY;
|
||||
theme.size = 0xC;
|
||||
theme.data = themePath;
|
||||
if(R_FAILED(res = FSUSER_OpenArchive(&ArchiveThemeExt, ARCHIVE_EXTDATA, theme))) return res;
|
||||
|
||||
|
||||
Handle test_handle;
|
||||
if(R_FAILED(res = FSUSER_OpenFile(&test_handle, ArchiveThemeExt, fsMakePath(PATH_ASCII, "/ThemeManage.bin"), FS_OPEN_READ, 0))) return res;
|
||||
FSFILE_Close(test_handle);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result close_archives(void)
|
||||
{
|
||||
Result res;
|
||||
|
||||
|
||||
if(R_FAILED(res = FSUSER_CloseArchive(ArchiveSD))) return res;
|
||||
if(R_FAILED(res = FSUSER_CloseArchive(ArchiveHomeExt))) return res;
|
||||
if(R_FAILED(res = FSUSER_CloseArchive(ArchiveThemeExt))) return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 file_to_buf(FS_Path path, FS_Archive archive, char** buf)
|
||||
{
|
||||
Handle file;
|
||||
Result res = 0;
|
||||
if (R_FAILED(res = FSUSER_OpenFile(&file, archive, path, FS_OPEN_READ, 0))) return 0;
|
||||
|
||||
|
||||
u64 size;
|
||||
FSFILE_GetSize(file, &size);
|
||||
if(size != 0)
|
||||
@@ -195,7 +195,149 @@ Result buf_to_file(u32 size, FS_Path path, FS_Archive archive, char *buf)
|
||||
if (R_FAILED(res = FSFILE_Close(handle))) return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 decompress_lz_file(FS_Path file_name, FS_Archive archive, char **buf)
|
||||
{
|
||||
Handle handle;
|
||||
Result res = 0;
|
||||
if (R_FAILED(res = FSUSER_OpenFile(&handle, archive, file_name, FS_OPEN_READ, 0))) {
|
||||
DEBUG("%lu\n", res);
|
||||
return 0;
|
||||
}
|
||||
u64 size;
|
||||
FSFILE_GetSize(handle, &size);
|
||||
|
||||
char *temp_buf = NULL;
|
||||
|
||||
if(size != 0)
|
||||
{
|
||||
temp_buf = calloc(1, size);
|
||||
FSFILE_Read(handle, NULL, 0, temp_buf, size);
|
||||
}
|
||||
FSFILE_Close(handle);
|
||||
|
||||
if (temp_buf[0] != 0x11) {
|
||||
free(temp_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 output_size = temp_buf[1] | ((temp_buf[2] << 8) & 0xFF00) | ((temp_buf[3] << 16) & 0xFF0000);
|
||||
printf("%ld\n", output_size);
|
||||
|
||||
|
||||
*buf = calloc(1, output_size);
|
||||
|
||||
u32 pos = 4;
|
||||
u32 cur_written = 0;
|
||||
u8 counter = 0;
|
||||
u8 mask = 0;
|
||||
|
||||
while (cur_written < output_size)
|
||||
{
|
||||
if (counter == 0) // read mask
|
||||
{
|
||||
mask = temp_buf[pos++];
|
||||
counter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mask >> (8 - counter)) & 0x01) // compressed block
|
||||
{
|
||||
int len = 0;
|
||||
int disp = 0;
|
||||
switch (temp_buf[pos] >> 4)
|
||||
{
|
||||
case 0:
|
||||
len = temp_buf[pos++] << 4;
|
||||
len |= temp_buf[pos] >> 4;
|
||||
len += 0x11;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
len = (temp_buf[pos++] & 0x0F) << 12;
|
||||
len |= temp_buf[pos++] << 4;
|
||||
len |= temp_buf[pos] >> 4;
|
||||
len += 0x111;
|
||||
break;
|
||||
|
||||
default:
|
||||
len = (temp_buf[pos] >> 4) + 1;
|
||||
}
|
||||
|
||||
disp = (temp_buf[pos++] & 0x0F) << 8;
|
||||
disp |= temp_buf[pos++];
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
*(*buf + cur_written + i) = *(*buf + cur_written - disp - 1 + i);
|
||||
}
|
||||
|
||||
cur_written += len;
|
||||
}
|
||||
else // byte literal
|
||||
{
|
||||
*(*buf + cur_written) = temp_buf[pos++];
|
||||
cur_written++;
|
||||
}
|
||||
|
||||
if (++counter > 8) counter = 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
free(temp_buf);
|
||||
|
||||
return cur_written;
|
||||
}
|
||||
|
||||
// This is an awful algorithm to "compress" LZ11 data.
|
||||
// We do this instead of actual LZ11 compression because of time -
|
||||
// LZ11 requires a lot of mem searching which is painfully slow on 3DS.
|
||||
// This process is nearly instant but means the resulting file is actually larger
|
||||
// than the input file. I don't think this is a problem as the only file we compress like this
|
||||
// is the theme data installed to extdata in some rare cases, which means only 1 file at most
|
||||
// is ever compressed like this. I don't think 400 KB is that big a sacrifice for probably
|
||||
// half a minute or so of time save - I may change my mind on this in the future, especially
|
||||
// if i figure out a dynamic programming algorithm which ends up being significantly
|
||||
// faster. Otherwise, I think this is probably a fine implementation.
|
||||
|
||||
u32 compress_lz_file_fast(FS_Path path, FS_Archive archive, char *in_buf, u32 size)
|
||||
{
|
||||
char *output_buf = calloc(1, size * 2);
|
||||
u32 output_size = 0;
|
||||
u32 mask_pos = 0;
|
||||
u32 bytes_processed = 0;
|
||||
u8 counter = 0;
|
||||
|
||||
if (output_buf == NULL) return 0;
|
||||
|
||||
// Set header data for the LZ11 file - 0x11 is version (LZ11), next 3 bytes are size
|
||||
output_buf[0] = 0x11;
|
||||
output_buf[3] = (size & 0xFF0000) >> 16;
|
||||
output_buf[2] = (size & 0xFF00) >> 8;
|
||||
output_buf[1] = (size & 0xFF);
|
||||
|
||||
output_size += 4;
|
||||
|
||||
while (bytes_processed < size)
|
||||
{
|
||||
if (counter == 0)
|
||||
{
|
||||
mask_pos = output_size++;
|
||||
output_buf[mask_pos] = 0;
|
||||
}
|
||||
|
||||
output_buf[output_size++] = in_buf[bytes_processed++];
|
||||
|
||||
if (++counter == 8) counter = 0;
|
||||
}
|
||||
|
||||
buf_to_file(output_size, path, archive, output_buf);
|
||||
free(output_buf);
|
||||
|
||||
return output_size;
|
||||
}
|
||||
|
||||
void remake_file(FS_Path path, FS_Archive archive, u32 size)
|
||||
{
|
||||
Handle handle;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -83,6 +83,7 @@ C2D_Image * loadTextureIcon(Icon_s *icon)
|
||||
|
||||
void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name)
|
||||
{
|
||||
|
||||
if(icon == NULL)
|
||||
{
|
||||
memcpy(entry->name, fallback_name, 0x80);
|
||||
@@ -92,27 +93,12 @@ void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
memcpy(entry->name, icon->name, 0x40*sizeof(u16));
|
||||
memcpy(entry->desc, icon->desc, 0x80*sizeof(u16));
|
||||
memcpy(entry->author, icon->author, 0x40*sizeof(u16));
|
||||
}
|
||||
|
||||
static void parse_entry_smdh(Entry_s * entry, const u16 * fallback_name)
|
||||
{
|
||||
char *info_buffer = NULL;
|
||||
u64 size = load_data("/info.smdh", *entry, &info_buffer);
|
||||
|
||||
if(!size)
|
||||
{
|
||||
free(info_buffer);
|
||||
info_buffer = NULL;
|
||||
}
|
||||
|
||||
Icon_s * smdh = (Icon_s *)info_buffer;
|
||||
|
||||
parse_smdh(smdh, entry, fallback_name);
|
||||
}
|
||||
|
||||
static C2D_Image * load_entry_icon(Entry_s entry)
|
||||
{
|
||||
char *info_buffer = NULL;
|
||||
@@ -120,7 +106,9 @@ static C2D_Image * load_entry_icon(Entry_s entry)
|
||||
if(!size) return NULL;
|
||||
|
||||
Icon_s * smdh = (Icon_s *)info_buffer;
|
||||
return loadTextureIcon(smdh);
|
||||
C2D_Image* out = loadTextureIcon(smdh);
|
||||
free(info_buffer);
|
||||
return out;
|
||||
}
|
||||
|
||||
typedef int (*sort_comparator)(const void *, const void *);
|
||||
@@ -197,25 +185,24 @@ Result load_entries(const char * loading_path, Entry_List_s * list)
|
||||
|
||||
if (!strcmp(dir_entry.shortExt, "ZIP"))
|
||||
{
|
||||
u32 size = zip_file_to_buf("info.smdh", path, &buf);
|
||||
if (size == 0) continue;
|
||||
zip_file_to_buf("info.smdh", path, &buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ssize_t len = strulen(path, 0x106);
|
||||
struacat(path, "/info.smdh");
|
||||
u32 size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &buf);
|
||||
if (size == 0) continue;
|
||||
file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &buf);
|
||||
memset(&path[len], 0, (0x106 - len) * sizeof(u16));
|
||||
}
|
||||
|
||||
free(buf);
|
||||
list->entries_count++;
|
||||
Entry_s * new_list = realloc(list->entries, list->entries_count * sizeof(Entry_s));
|
||||
if(new_list == NULL)
|
||||
{
|
||||
free(list->entries);
|
||||
list->entries = NULL;
|
||||
res = -1;
|
||||
DEBUG("break\n");
|
||||
// out of memory: still allow use of currently loaded entries.
|
||||
// Many things might die, depending on the heap layout after
|
||||
list->entries_count--;
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -223,12 +210,11 @@ Result load_entries(const char * loading_path, Entry_List_s * list)
|
||||
|
||||
Entry_s * current_entry = &(list->entries[list->entries_count-1]);
|
||||
memset(current_entry, 0, sizeof(Entry_s));
|
||||
parse_smdh((Icon_s *)buf, current_entry, dir_entry.name);
|
||||
free(buf);
|
||||
|
||||
struacat(current_entry->path, loading_path);
|
||||
strucat(current_entry->path, dir_entry.name);
|
||||
|
||||
memcpy(current_entry->path, path, 0x106 * sizeof(u16));
|
||||
current_entry->is_zip = !strcmp(dir_entry.shortExt, "ZIP");
|
||||
parse_entry_smdh(current_entry, dir_entry.name);
|
||||
}
|
||||
|
||||
FSDIR_Close(dir_handle);
|
||||
@@ -424,9 +410,12 @@ static bool load_icons(Entry_List_s * current_list, Handle mutex)
|
||||
int index = indexes[i];
|
||||
|
||||
C2D_Image * image = icons[index];
|
||||
C3D_TexDelete(image->tex);
|
||||
free(image->tex);
|
||||
free(image);
|
||||
if (icons[index] != NULL)
|
||||
{
|
||||
C3D_TexDelete(image->tex);
|
||||
free(image->tex);
|
||||
free(image);
|
||||
}
|
||||
|
||||
icons[index] = load_entry_icon(*current_entry);
|
||||
|
||||
@@ -509,7 +498,7 @@ bool load_preview_from_buffer(void * buf, u32 size, C2D_Image * preview_image, i
|
||||
if(color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||
png_set_add_alpha(png, 0xFF, PNG_FILLER_BEFORE);
|
||||
|
||||
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -132,6 +132,7 @@ static void free_icons(Entry_List_s * list)
|
||||
|
||||
for(int i = 0; i < amount; i++)
|
||||
{
|
||||
if (list->icons[i] == NULL) continue;
|
||||
C3D_TexDelete(list->icons[i]->tex);
|
||||
free(list->icons[i]->tex);
|
||||
free(list->icons[i]);
|
||||
@@ -239,6 +240,7 @@ static void load_lists(Entry_List_s * lists)
|
||||
|
||||
static SwkbdCallbackResult jump_menu_callback(void* entries_count, const char** ppMessage, const char* text, size_t textlen)
|
||||
{
|
||||
(void)textlen;
|
||||
int typed_value = atoi(text);
|
||||
if(typed_value > *(int*)entries_count)
|
||||
{
|
||||
@@ -316,7 +318,7 @@ static void toggle_shuffle(Entry_List_s * list)
|
||||
current_entry->no_bgm_shuffle = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
current_entry->in_shuffle = true;
|
||||
list->shuffle_count++;
|
||||
@@ -358,7 +360,6 @@ int main(void)
|
||||
bool preview_mode = false;
|
||||
int preview_offset = 0;
|
||||
|
||||
bool qr_mode = false;
|
||||
bool install_mode = false;
|
||||
bool extra_mode = false;
|
||||
C2D_Image preview = {0};
|
||||
@@ -406,8 +407,7 @@ int main(void)
|
||||
instructions = extra_instructions[index];
|
||||
}
|
||||
|
||||
if(qr_mode) take_picture();
|
||||
else if(preview_mode)
|
||||
if(preview_mode)
|
||||
{
|
||||
draw_preview(preview, preview_offset);
|
||||
}
|
||||
@@ -439,14 +439,14 @@ int main(void)
|
||||
|
||||
if(!install_mode && !extra_mode)
|
||||
{
|
||||
if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes
|
||||
if(!preview_mode && kDown & KEY_L) //toggle between splashes and themes
|
||||
{
|
||||
switch_mode:
|
||||
current_mode++;
|
||||
current_mode %= MODE_AMOUNT;
|
||||
continue;
|
||||
}
|
||||
else if(!qr_mode && !preview_mode && kDown & KEY_R) //toggle QR mode
|
||||
else if(!preview_mode && kDown & KEY_R) //toggle QR mode
|
||||
{
|
||||
enable_qr:
|
||||
draw_base_interface();
|
||||
@@ -479,7 +479,7 @@ int main(void)
|
||||
|
||||
continue;
|
||||
}
|
||||
else if(!qr_mode && kDown & KEY_Y && current_list->entries != NULL) //toggle preview mode
|
||||
else if(kDown & KEY_Y && current_list->entries != NULL) //toggle preview mode
|
||||
{
|
||||
toggle_preview:
|
||||
if(!preview_mode)
|
||||
@@ -524,7 +524,7 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
if(qr_mode || preview_mode || current_list->entries == NULL)
|
||||
if(preview_mode || current_list->entries == NULL)
|
||||
goto touch;
|
||||
|
||||
int selected_entry = current_list->selected_entry;
|
||||
@@ -648,6 +648,13 @@ int main(void)
|
||||
{
|
||||
load_icons_first(current_list, false);
|
||||
}
|
||||
else if((kDown | kHeld) & KEY_DRIGHT)
|
||||
{
|
||||
draw_install(INSTALL_DUMPING_THEME);
|
||||
Result res = dump_theme();
|
||||
if (R_FAILED(res)) DEBUG("Dump theme result: %lx\n", res);
|
||||
else load_lists(lists);
|
||||
}
|
||||
}
|
||||
else if(key_l)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
807
source/remote.c
807
source/remote.c
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
124
source/themes.c
124
source/themes.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -184,16 +184,30 @@ static Result install_theme_internal(Entry_List_s themes, int installmode)
|
||||
if(installmode & THEME_INSTALL_BGM)
|
||||
{
|
||||
music_size = load_data("/bgm.bcstm", current_theme, &music);
|
||||
if(music_size > BGM_MAX_SIZE)
|
||||
if (music_size > BGM_MAX_SIZE)
|
||||
{
|
||||
free(music);
|
||||
DEBUG("bgm too big\n");
|
||||
return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE);
|
||||
}
|
||||
|
||||
remake_file(fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, BGM_MAX_SIZE);
|
||||
res = buf_to_file(music_size, fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, music);
|
||||
free(music);
|
||||
if (music_size != 0)
|
||||
{
|
||||
remake_file(fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, BGM_MAX_SIZE);
|
||||
res = buf_to_file(music_size, fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, music);
|
||||
free(music);
|
||||
|
||||
char *body_buf = NULL;
|
||||
u32 uncompressed_size = decompress_lz_file(fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, &body_buf);
|
||||
if (body_buf[5] != 1)
|
||||
{
|
||||
installmode |= THEME_INSTALL_BODY;
|
||||
body_buf[5] = 1;
|
||||
body_size = compress_lz_file_fast(fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, body_buf, uncompressed_size);
|
||||
}
|
||||
|
||||
free(body_buf);
|
||||
}
|
||||
|
||||
if(R_FAILED(res)) return res;
|
||||
} else
|
||||
@@ -301,6 +315,106 @@ inline Result shuffle_install(Entry_List_s themes)
|
||||
return install_theme_internal(themes, THEME_INSTALL_SHUFFLE | THEME_INSTALL_BODY | THEME_INSTALL_BGM);
|
||||
}
|
||||
|
||||
static SwkbdCallbackResult
|
||||
dir_name_callback(void *data, const char ** ppMessage, const char * text, size_t textlen)
|
||||
{
|
||||
(void)textlen;
|
||||
(void)data;
|
||||
if(strpbrk(text, "><\"?;:/\\+,.|[=]"))
|
||||
{
|
||||
*ppMessage = "Illegal character used.";
|
||||
return SWKBD_CALLBACK_CONTINUE;
|
||||
}
|
||||
return SWKBD_CALLBACK_OK;
|
||||
}
|
||||
|
||||
Result dump_theme(void)
|
||||
{
|
||||
const int max_chars = 255;
|
||||
char * output_dir = calloc(max_chars + 1, sizeof(char));
|
||||
|
||||
SwkbdState swkbd;
|
||||
|
||||
swkbdInit(&swkbd, SWKBD_TYPE_WESTERN, 2, max_chars);
|
||||
swkbdSetHintText(&swkbd, "Name of output folder");
|
||||
|
||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false);
|
||||
swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Done", true);
|
||||
swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, max_chars);
|
||||
swkbdSetFilterCallback(&swkbd, dir_name_callback, NULL);
|
||||
|
||||
SwkbdButton button = swkbdInputText(&swkbd, output_dir, max_chars);
|
||||
|
||||
if (button != SWKBD_BUTTON_CONFIRM)
|
||||
{
|
||||
DEBUG("<dump_theme> Something went wrong with getting swkbd\n");
|
||||
return MAKERESULT(RL_FATAL, RS_CANCELED, RM_UTIL, RD_CANCEL_REQUESTED);
|
||||
}
|
||||
|
||||
u16 path[0x107] = { 0 };
|
||||
struacat(path, "/themes/");
|
||||
struacat(path, output_dir);
|
||||
FSUSER_CreateDirectory(ArchiveSD, fsMakePath(PATH_UTF16, path), FS_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
char *thememanage_buf = NULL;
|
||||
file_to_buf(fsMakePath(PATH_ASCII, "/ThemeManage.bin"), ArchiveThemeExt, &thememanage_buf);
|
||||
ThemeManage_bin_s * theme_manage = (ThemeManage_bin_s *)thememanage_buf;
|
||||
u32 theme_size = theme_manage->body_size;
|
||||
u32 bgm_size = theme_manage->music_size;
|
||||
free(thememanage_buf);
|
||||
|
||||
char *temp_buf = NULL;
|
||||
file_to_buf(fsMakePath(PATH_ASCII, "/BodyCache.bin"), ArchiveThemeExt, &temp_buf);
|
||||
u16 path_output[0x107] = { 0 };
|
||||
memcpy(path_output, path, 0x107);
|
||||
struacat(path_output, "/body_LZ.bin");
|
||||
remake_file(fsMakePath(PATH_UTF16, path_output), ArchiveSD, theme_size);
|
||||
buf_to_file(theme_size, fsMakePath(PATH_UTF16, path_output), ArchiveSD, temp_buf);
|
||||
free(temp_buf);
|
||||
temp_buf = NULL;
|
||||
|
||||
file_to_buf(fsMakePath(PATH_ASCII, "/BgmCache.bin"), ArchiveThemeExt, &temp_buf);
|
||||
memcpy(path_output, path, 0x107);
|
||||
struacat(path_output, "/bgm.bcstm");
|
||||
remake_file(fsMakePath(PATH_UTF16, path_output), ArchiveSD, bgm_size);
|
||||
buf_to_file(bgm_size, fsMakePath(PATH_UTF16, path_output), ArchiveSD, temp_buf);
|
||||
free(temp_buf);
|
||||
temp_buf = NULL;
|
||||
|
||||
char *smdh_file = calloc(1, 0x36c0);
|
||||
smdh_file[0] = 0x53; // SMDH magic
|
||||
smdh_file[1] = 0x4d;
|
||||
smdh_file[2] = 0x44;
|
||||
smdh_file[3] = 0x48;
|
||||
|
||||
struacat((u16 *) (smdh_file + 0x8), output_dir);
|
||||
struacat((u16 *) (smdh_file + 0x88), "No description");
|
||||
struacat((u16 *) (smdh_file + 0x188), "Unknown Author");
|
||||
|
||||
free(output_dir);
|
||||
|
||||
u8 r = rand() % 255;
|
||||
u8 g = rand() % 255;
|
||||
u8 b = rand() % 255;
|
||||
|
||||
u16 color = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
|
||||
|
||||
for (int i = 0x2040; i < 0x36c0; i += 2)
|
||||
{
|
||||
*(smdh_file + i) = (color & 0xFF00) >> 8;
|
||||
*(smdh_file + i + 1) = color & 0x00FF;
|
||||
}
|
||||
|
||||
memcpy(path_output, path, 0x107);
|
||||
struacat(path_output, "/info.smdh");
|
||||
remake_file(fsMakePath(PATH_UTF16, path_output), ArchiveSD, 0x36c0);
|
||||
buf_to_file(0x36c0, fsMakePath(PATH_UTF16, path_output), ArchiveSD, smdh_file);
|
||||
|
||||
free(smdh_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void themes_check_installed(void * void_arg)
|
||||
{
|
||||
Thread_Arg_s * arg = (Thread_Arg_s *)void_arg;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Anemone3DS
|
||||
* Copyright (C) 2016-2018 Contributors in CONTRIBUTORS.md
|
||||
* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
Reference in New Issue
Block a user