Merge branch 'port/3ds'

This commit is contained in:
Jeffrey Pfau 2015-08-25 21:12:11 -07:00
commit 8460a1eea9
11 changed files with 623 additions and 4 deletions

View File

@ -28,7 +28,6 @@ file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)
file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c)
file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c)
file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c)
file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/gui/*.c)
file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs])
file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c)
file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)
@ -176,6 +175,21 @@ elseif(WII)
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/*.c)
list(APPEND OS_LIB wiiuse bte fat ogc)
source_group("Wii-specific code" FILES ${OS_SRC})
elseif(3DS)
set(M_LIBRARY m)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format")
add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5)
execute_process(COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw)
include_directories(${CMAKE_BINARY_DIR})
list(APPEND OS_LIB sf2d ctru)
file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/3ds/*.c ${CMAKE_BINARY_DIR}/font.c)
if(USE_VFS_3DS)
add_definitions(-DUSE_VFS_3DS)
else()
add_definitions(-DUSE_VFS_FILE)
list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c)
endif()
source_group("3DS-specific code" FILES ${OS_SRC})
endif()
if(APPLE)
@ -461,6 +475,12 @@ if(PSP2)
add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2)
endif()
if(3DS)
add_executable(${BINARY_NAME}.elf ${GUI_SRC})
target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} m ${OS_LIB})
add_custom_command(TARGET ${BINARY_NAME}.elf POST_BUILD COMMAND ${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx)
endif()
if(BUILD_PERF)
set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c)
if(UNIX AND NOT APPLE)

View File

@ -187,11 +187,13 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
return true;
}
#ifndef _3DS
struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) {
char suffix[5] = { '\0' };
snprintf(suffix, sizeof(suffix), ".ss%d", slot);
return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
}
#endif
#ifdef USE_PNG
static bool _savePNGState(struct GBA* gba, struct VFile* vf) {
@ -268,6 +270,7 @@ static bool _loadPNGState(struct GBA* gba, struct VFile* vf) {
}
#endif
#ifndef _3DS
bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, bool screenshot) {
struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, true);
if (!vf) {
@ -298,6 +301,7 @@ bool GBALoadState(struct GBAThread* threadContext, struct VDir* dir, int slot) {
}
return success;
}
#endif
bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot) {
if (!screenshot) {

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2013-2014 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/memory.h"
#define asm __asm__
#include <3ds.h>
void* anonymousMemoryMap(size_t size) {
return linearAlloc(size);
}
void mappedMemoryFree(void* memory, size_t size) {
UNUSED(size);
linearFree(memory);
}

248
src/platform/3ds/3ds-vfs.c Normal file
View File

@ -0,0 +1,248 @@
/* Copyright (c) 2013-2014 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "3ds-vfs.h"
#ifdef USE_VFS_3DS
#include "util/memory.h"
#include "util/string.h"
struct VFile3DS {
struct VFile d;
Handle handle;
u64 offset;
};
struct VDirEntry3DS {
struct VDirEntry d;
FS_dirent ent;
char* utf8Name;
};
struct VDir3DS {
struct VDir d;
char* path;
Handle handle;
struct VDirEntry3DS vde;
};
static bool _vf3dClose(struct VFile* vf);
static off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence);
static ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size);
static ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size);
static void* _vf3dMap(struct VFile* vf, size_t size, int flags);
static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size);
static void _vf3dTruncate(struct VFile* vf, size_t size);
static ssize_t _vf3dSize(struct VFile* vf);
static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size);
static bool _vd3dClose(struct VDir* vd);
static void _vd3dRewind(struct VDir* vd);
static struct VDirEntry* _vd3dListNext(struct VDir* vd);
static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode);
static const char* _vd3deName(struct VDirEntry* vde);
struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags) {
struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS));
if (!vf3d) {
return 0;
}
FS_path newPath = FS_makePath(PATH_CHAR, path);
Result res = FSUSER_OpenFile(0, &vf3d->handle, *archive, newPath, flags, FS_ATTRIBUTE_NONE);
if (res & 0xFFFC03FF) {
free(vf3d);
return 0;
}
vf3d->offset = 0;
vf3d->d.close = _vf3dClose;
vf3d->d.seek = _vf3dSeek;
vf3d->d.read = _vf3dRead;
vf3d->d.readline = 0;
vf3d->d.write = _vf3dWrite;
vf3d->d.map = _vf3dMap;
vf3d->d.unmap = _vf3dUnmap;
vf3d->d.truncate = _vf3dTruncate;
vf3d->d.size = _vf3dSize;
vf3d->d.sync = _vf3dSync;
return &vf3d->d;
}
bool _vf3dClose(struct VFile* vf) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
FSFILE_Close(vf3d->handle);
svcCloseHandle(vf3d->handle);
return true;
}
off_t _vf3dSeek(struct VFile* vf, off_t offset, int whence) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
u64 size;
switch (whence) {
case SEEK_SET:
vf3d->offset = offset;
break;
case SEEK_END:
FSFILE_GetSize(vf3d->handle, &size);
vf3d->offset = size;
// Fall through
case SEEK_CUR:
vf3d->offset += offset;
break;
}
return vf3d->offset;
}
ssize_t _vf3dRead(struct VFile* vf, void* buffer, size_t size) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
u32 sizeRead;
Result res = FSFILE_Read(vf3d->handle, &sizeRead, vf3d->offset, buffer, size);
if (res) {
return -1;
}
vf3d->offset += sizeRead;
return sizeRead;
}
ssize_t _vf3dWrite(struct VFile* vf, const void* buffer, size_t size) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
u32 sizeWritten;
Result res = FSFILE_Write(vf3d->handle, &sizeWritten, vf3d->offset, buffer, size, FS_WRITE_FLUSH);
if (res) {
return -1;
}
vf3d->offset += sizeWritten;
return sizeWritten;
}
static void* _vf3dMap(struct VFile* vf, size_t size, int flags) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
UNUSED(flags);
void* buffer = anonymousMemoryMap(size);
if (buffer) {
u32 sizeRead;
FSFILE_Read(vf3d->handle, &sizeRead, 0, buffer, size);
}
return buffer;
}
static void _vf3dUnmap(struct VFile* vf, void* memory, size_t size) {
UNUSED(vf);
mappedMemoryFree(memory, size);
}
static void _vf3dTruncate(struct VFile* vf, size_t size) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
FSFILE_SetSize(vf3d->handle, size);
}
ssize_t _vf3dSize(struct VFile* vf) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
u64 size;
FSFILE_GetSize(vf3d->handle, &size);
return size;
}
static bool _vf3dSync(struct VFile* vf, const void* buffer, size_t size) {
struct VFile3DS* vf3d = (struct VFile3DS*) vf;
if (buffer) {
u32 sizeWritten;
Result res = FSFILE_Write(vf3d->handle, &sizeWritten, 0, buffer, size, FS_WRITE_FLUSH);
if (res) {
return false;
}
}
FSFILE_Flush(vf3d->handle);
return true;
}
struct VDir* VDirOpen(const char* path) {
struct VDir3DS* vd3d = malloc(sizeof(struct VDir3DS));
if (!vd3d) {
return 0;
}
FS_path newPath = FS_makePath(PATH_CHAR, path);
Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
if (res & 0xFFFC03FF) {
free(vd3d);
return 0;
}
vd3d->path = strdup(path);
vd3d->d.close = _vd3dClose;
vd3d->d.rewind = _vd3dRewind;
vd3d->d.listNext = _vd3dListNext; //// Crashes here for no good reason
vd3d->d.openFile = _vd3dOpenFile;
vd3d->vde.d.name = _vd3deName;
vd3d->vde.utf8Name = 0;
return &vd3d->d;
}
static bool _vd3dClose(struct VDir* vd) {
struct VDir3DS* vd3d = (struct VDir3DS*) vd;
FSDIR_Close(vd3d->handle);
free(vd3d->path);
if (vd3d->vde.utf8Name) {
free(vd3d->vde.utf8Name);
}
free(vd3d);
return true;
}
static void _vd3dRewind(struct VDir* vd) {
struct VDir3DS* vd3d = (struct VDir3DS*) vd;
FSDIR_Close(vd3d->handle);
FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path);
FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath);
}
static struct VDirEntry* _vd3dListNext(struct VDir* vd) {
struct VDir3DS* vd3d = (struct VDir3DS*) vd;
u32 n = 0;
memset(&vd3d->vde.ent, 0, sizeof(vd3d->vde.ent));
if (vd3d->vde.utf8Name) {
free(vd3d->vde.utf8Name);
vd3d->vde.utf8Name = 0;
};
FSDIR_Read(vd3d->handle, &n, 1, &vd3d->vde.ent);
if (!n) {
return 0;
}
return &vd3d->vde.d;
}
static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode) {
struct VDir3DS* vd3d = (struct VDir3DS*) vd;
if (!path) {
return 0;
}
const char* dir = vd3d->path;
char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2));
sprintf(combined, "%s/%s", dir, path);
struct VFile* file = VFileOpen(combined, mode);
free(combined);
return file;
}
static const char* _vd3deName(struct VDirEntry* vde) {
struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde;
if (!vd3de->utf8Name) {
vd3de->utf8Name = utf16to8(vd3de->ent.name, sizeof(vd3de->ent.name) / 2);
}
return vd3de->utf8Name;
}
#endif

View File

@ -0,0 +1,19 @@
/* Copyright (c) 2013-2014 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef N3DS_VFS_H
#define N3DS_VFS_H
#include "util/vfs.h"
#define asm __asm__
#include <3ds.h>
extern FS_archive sdmcArchive;
struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags);
#endif

View File

@ -0,0 +1,40 @@
if(DEFINED ENV{DEVKITPRO})
set(DEVKITPRO $ENV{DEVKITPRO})
else()
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
endif()
if(DEFINED ENV{DEVKITARM})
set(DEVKITARM $ENV{DEVKITARM})
else()
set(DEVKITARM ${DEVKITPRO}/devkitARM)
endif()
set(toolchain_bin_dir ${DEVKITARM}/bin)
set(cross_prefix ${toolchain_bin_dir}/arm-none-eabi-)
set(inc_flags -I${DEVKITPRO}/libctru/include)
set(arch_flags "-march=armv6k -mtune=mpcore -mfpu=vfp -mfloat-abi=hard")
set(link_flags "-L${DEVKITPRO}/libctru/lib -lctru -lm -specs=3dsx.specs ${arch_flags}")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")
set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi CACHE INTERNAL "abi")
set(CMAKE_AR ${cross_prefix}ar CACHE INTERNAL "archiver")
set(CMAKE_C_COMPILER ${cross_prefix}gcc CACHE INTERNAL "c compiler")
set(CMAKE_CXX_COMPILER ${cross_prefix}g++ CACHE INTERNAL "cxx compiler")
set(CMAKE_ASM_COMPILER ${cross_prefix}gcc CACHE INTERNAL "assembler")
set(common_flags "${arch_flags} -mword-relocations ${inc_flags}")
set(CMAKE_C_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${common_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_CXX_FLAGS ${common_flags} CACHE INTERNAL "cxx compiler flags")
set(CMAKE_LINKER ${cross_prefix}ld CACHE INTERNAL "linker")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
set(3DSXTOOL ${toolchain_bin_dir}/3dsxtool)
set(RAW2C ${toolchain_bin_dir}/raw2c)
set(3DS ON)
add_definitions(-D_3DS -DARM11)

BIN
src/platform/3ds/font.raw Normal file

Binary file not shown.

View File

@ -0,0 +1,67 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/gui/font.h"
#include "util/gui/font-metrics.h"
#include "util/png-io.h"
#include "util/vfs.h"
#include "font.h"
#include <sf2d.h>
#define CELL_HEIGHT 16
#define CELL_WIDTH 16
#define GLYPH_HEIGHT 12
struct GUIFont {
sf2d_texture* tex;
};
struct GUIFont* GUIFontCreate(void) {
struct GUIFont* guiFont = malloc(sizeof(struct GUIFont));
if (!guiFont) {
return 0;
}
guiFont->tex = sf2d_create_texture(256, 128, TEXFMT_RGB5A1, SF2D_PLACE_RAM);
memcpy(guiFont->tex->data, font, font_size);
guiFont->tex->tiled = 1;
return guiFont;
}
void GUIFontDestroy(struct GUIFont* font) {
sf2d_free_texture(font->tex);
free(font);
}
int GUIFontHeight(const struct GUIFont* font) {
UNUSED(font);
return GLYPH_HEIGHT;
}
void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text, ...) {
UNUSED(align); // TODO
char buffer[256];
va_list args;
va_start(args, text);
int len = vsnprintf(buffer, sizeof(buffer), text, args);
va_end(args);
int i;
for (i = 0; i < len; ++i) {
char c = buffer[i];
if (c > 0x7F) {
c = 0;
}
struct GUIFontGlyphMetric metric = defaultFontMetrics[c];
sf2d_draw_texture_part_blend(font->tex,
x - metric.padding.left,
y - GLYPH_HEIGHT,
(c & 15) * CELL_WIDTH,
(c >> 4) * CELL_HEIGHT,
CELL_WIDTH,
CELL_HEIGHT,
color);
x += metric.width;
}
}

171
src/platform/3ds/main.c Normal file
View File

@ -0,0 +1,171 @@
/* Copyright (c) 2013-2015 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gba/renderers/video-software.h"
#include "gba/supervisor/context.h"
#include "gba/video.h"
#include "util/gui.h"
#include "util/gui/file-select.h"
#include "util/gui/font.h"
#include "util/memory.h"
#include "3ds-vfs.h"
#include <3ds.h>
#include <sf2d.h>
FS_archive sdmcArchive;
static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args);
static Handle logFile;
static void _drawStart(void) {
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
}
static void _drawEnd(void) {
sf2d_end_frame();
sf2d_swapbuffers();
}
static int _pollInput(void) {
hidScanInput();
int keys = 0;
int activeKeys = hidKeysHeld();
if (activeKeys & KEY_X) {
keys |= 1 << GUI_INPUT_CANCEL;
}
if (activeKeys & KEY_B) {
keys |= 1 << GUI_INPUT_BACK;
}
if (activeKeys & KEY_A) {
keys |= 1 << GUI_INPUT_SELECT;
}
if (activeKeys & KEY_LEFT) {
keys |= 1 << GUI_INPUT_LEFT;
}
if (activeKeys & KEY_RIGHT) {
keys |= 1 << GUI_INPUT_RIGHT;
}
if (activeKeys & KEY_UP) {
keys |= 1 << GUI_INPUT_UP;
}
if (activeKeys & KEY_DOWN) {
keys |= 1 << GUI_INPUT_DOWN;
}
return keys;
}
int main() {
struct GBAContext context;
srvInit();
aptInit();
hidInit(0);
fsInit();
sdmcInit();
sf2d_init();
sf2d_set_clear_color(0);
sf2d_texture* tex = sf2d_create_texture(256, 256, TEXFMT_RGB565, SF2D_PLACE_RAM);
memset(tex->data, 0, 256 * 256 * 2);
sdmcArchive = (FS_archive) {
ARCH_SDMC,
(FS_path) { PATH_EMPTY, 1, (const u8*)"" },
0, 0
};
FSUSER_OpenArchive(0, &sdmcArchive);
FSUSER_OpenFile(0, &logFile, sdmcArchive, FS_makePath(PATH_CHAR, "/mgba.log"), FS_OPEN_WRITE | FS_OPEN_CREATE, FS_ATTRIBUTE_NONE);
struct GUIFont* font = GUIFontCreate();
GBAContextInit(&context, 0);
struct GBAOptions opts = {
.useBios = true,
.logLevel = 0,
.idleOptimization = IDLE_LOOP_REMOVE
};
GBAConfigLoadDefaults(&context.config, &opts);
context.gba->logHandler = GBA3DSLog;
context.gba->logLevel = 0;
struct GBAVideoSoftwareRenderer renderer;
GBAVideoSoftwareRendererCreate(&renderer);
renderer.outputBuffer = anonymousMemoryMap(256 * VIDEO_VERTICAL_PIXELS * 2);
renderer.outputBufferStride = 256;
GBAVideoAssociateRenderer(&context.gba->video, &renderer.d);
if (!font) {
goto cleanup;
}
struct GUIParams params = {
320, 240,
font, _drawStart, _drawEnd, _pollInput
};
while (aptMainLoop()) {
char path[256];
if (!selectFile(&params, "/", path, sizeof(path), "gba")) {
break;
}
_drawStart();
GUIFontPrintf(font, 130, (GUIFontHeight(font) + 240) / 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "Loading...");
_drawEnd();
if (!GBAContextLoadROM(&context, path, true)) {
continue;
}
if (!GBAContextStart(&context)) {
continue;
}
while (aptMainLoop()) {
hidScanInput();
int activeKeys = hidKeysHeld() & 0x3FF;
if (hidKeysDown() & KEY_X) {
break;
}
GBAContextFrame(&context, activeKeys);
GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202);
GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2);
gspWaitForPPF();
_drawStart();
sf2d_draw_texture_scale(tex, 40, 296, 1, -1);
_drawEnd();
}
GBAContextStop(&context);
}
GBAContextDeinit(&context);
cleanup:
mappedMemoryFree(renderer.outputBuffer, 0);
FSFILE_Close(logFile);
sf2d_free_texture(tex);
sf2d_fini();
sdmcExit();
fsExit();
gfxExit();
hidExit();
aptExit();
srvExit();
return 0;
}
static void GBA3DSLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) {
UNUSED(thread);
UNUSED(level);
char out[256];
u64 size;
u32 written;
size_t len = vsnprintf(out, sizeof(out), format, args);
if (len >= 256) {
len = 255;
}
out[len] = '\n';
FSFILE_GetSize(logFile, &size);
FSFILE_Write(logFile, &written, size, out, len + 1, FS_WRITE_FLUSH);
}

View File

@ -12,7 +12,7 @@
DECLARE_VECTOR(FileList, char*);
DEFINE_VECTOR(FileList, char*);
void _cleanFiles(struct FileList* currentFiles) {
static void _cleanFiles(struct FileList* currentFiles) {
size_t size = FileListSize(currentFiles);
size_t i;
for (i = 0; i < size; ++i) {
@ -21,7 +21,7 @@ void _cleanFiles(struct FileList* currentFiles) {
FileListClear(currentFiles);
}
void _upDirectory(char* currentPath) {
static void _upDirectory(char* currentPath) {
char* end = strrchr(currentPath, '/');
if (!end) {
return;
@ -37,7 +37,7 @@ void _upDirectory(char* currentPath) {
// TODO: What if there was a trailing slash?
}
bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) {
static bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) {
_cleanFiles(currentFiles);
struct VDir* dir = VDirOpen(currentPath);

View File

@ -8,6 +8,9 @@
#ifdef PSP2
#include "platform/psp2/sce-vfs.h"
#endif
#ifdef _3DS
#include "platform/3ds/3ds-vfs.h"
#endif
struct VFile* VFileOpen(const char* path, int flags) {
#ifdef USE_VFS_FILE
@ -58,6 +61,34 @@ struct VFile* VFileOpen(const char* path, int flags) {
sceFlags |= PSP2_O_CREAT;
}
return VFileOpenSce(path, sceFlags, 0666);
#elif defined(USE_VFS_3DS)
int ctrFlags = FS_OPEN_READ;
switch (flags & O_ACCMODE) {
case O_WRONLY:
ctrFlags = FS_OPEN_WRITE;
break;
case O_RDWR:
ctrFlags = FS_OPEN_READ | FS_OPEN_WRITE;
break;
case O_RDONLY:
ctrFlags = FS_OPEN_READ;
break;
}
if (flags & O_CREAT) {
ctrFlags |= FS_OPEN_CREATE;
}
struct VFile* vf = VFileOpen3DS(&sdmcArchive, path, ctrFlags);
if (!vf) {
return 0;
}
if (flags & O_TRUNC) {
vf->truncate(vf, 0);
}
if (flags & O_APPEND) {
vf->seek(vf, vf->size(vf), SEEK_SET);
}
return vf;
#else
return VFileOpenFD(path, flags);
#endif