mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-06-18 10:55:31 -04:00
WIP: Use bitmap mode and clean up some things
This commit is contained in:
parent
2e83467ab5
commit
2ca30a9bd2
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,7 +3,7 @@
|
||||
*.nds
|
||||
*.cia
|
||||
*.elf
|
||||
data/*
|
||||
data/*.bin
|
||||
.vscode
|
||||
*.DS_Store
|
||||
|
||||
|
163
Makefile
163
Makefile
@ -9,149 +9,32 @@ endif
|
||||
|
||||
include $(DEVKITARM)/ds_rules
|
||||
|
||||
export VERSION_MAJOR := 1
|
||||
export VERSION_MINOR := 1
|
||||
export VERSION_PATCH := 0
|
||||
export TARGET := GodMode9i
|
||||
|
||||
|
||||
VERSION := $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
# DATA is a list of directories containing binary files embedded using bin2o
|
||||
# GRAPHICS is a list of directories containing image files to be converted with grit
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := GodMode9i
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
INCLUDES := include source
|
||||
DATA := data
|
||||
GRAPHICS := gfx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb -mthumb-interwork
|
||||
|
||||
CFLAGS := -g -Wall -O2 \
|
||||
-ffunction-sections -fdata-sections \
|
||||
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
|
||||
-ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM9
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=c++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g -Wl,--gc-sections $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project (order is important)
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lfat -lnds9
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp)))
|
||||
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := load.bin bootstub.bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
icons := $(wildcard *.bmp)
|
||||
|
||||
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
|
||||
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
|
||||
else
|
||||
ifneq (,$(findstring icon.bmp,$(icons)))
|
||||
export GAME_ICON := $(CURDIR)/icon.bmp
|
||||
endif
|
||||
endif
|
||||
|
||||
export GAME_TITLE := $(TARGET)
|
||||
|
||||
.PHONY: bootloader bootstub clean arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||
.PHONY: all bootloader bootstub clean dsi arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||
|
||||
all: bootloader bootstub $(TARGET).nds
|
||||
|
||||
dsi: $(TARGET).dsi
|
||||
|
||||
dist: all
|
||||
@rm -fr hbmenu
|
||||
@mkdir hbmenu
|
||||
@cp $(TARGET).nds hbmenu/BOOT.NDS
|
||||
@cp BootStrap/_BOOT_MP.NDS BootStrap/TTMENU.DAT BootStrap/_DS_MENU.DAT BootStrap/ez5sys.bin BootStrap/akmenu4.nds hbmenu
|
||||
@tar -cvjf $(TARGET)-$(VERSION).tar.bz2 hbmenu testfiles README.html COPYING hbmenu -X exclude.lst
|
||||
|
||||
$(TARGET).nds: $(TARGET).arm7 $(TARGET).arm9
|
||||
ndstool -c $(TARGET).nds -7 $(TARGET).arm7.elf -9 $(TARGET).arm9.elf \
|
||||
|
||||
$(TARGET).nds: arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||
-b icon.bmp "GodMode9i;RocketRobz" \
|
||||
-z 80040000 -u 00030004
|
||||
python fix_ndsheader.py $(CURDIR)/$(TARGET).nds
|
||||
|
||||
$(TARGET).dsi: $(TARGET).arm7 $(TARGET).arm9
|
||||
ndstool -c $(TARGET).dsi -7 $(TARGET).arm7.elf -9 $(TARGET).arm9.elf \
|
||||
|
||||
$(TARGET).dsi: arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||
ndstool -c $(TARGET).dsi -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||
-b icon.bmp "GodMode9i;RocketRobz" \
|
||||
-g HGMA 00 "GODMODE9I" -z 80040000 -u 00030004
|
||||
python fix_ndsheader.py $(CURDIR)/$(TARGET).dsi
|
||||
|
||||
$(TARGET).arm7: arm7/$(TARGET).elf
|
||||
cp arm7/$(TARGET).elf $(TARGET).arm7.elf
|
||||
|
||||
$(TARGET).arm9: arm9/$(TARGET).elf
|
||||
cp arm9/$(TARGET).elf $(TARGET).arm9.elf
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
arm7/$(TARGET).elf:
|
||||
@$(MAKE) -C arm7
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
arm9/$(TARGET).elf:
|
||||
@$(MAKE) -C arm9
|
||||
@ -163,7 +46,7 @@ arm9/$(TARGET).elf:
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr data
|
||||
@rm -fr data/*.bin
|
||||
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds
|
||||
@rm -fr $(TARGET).arm7.elf
|
||||
@rm -fr $(TARGET).arm9.elf
|
||||
@ -172,32 +55,8 @@ clean:
|
||||
@$(MAKE) -C arm9 clean
|
||||
@$(MAKE) -C arm7 clean
|
||||
|
||||
data:
|
||||
@mkdir -p data
|
||||
|
||||
bootloader: data
|
||||
@$(MAKE) -C bootloader LOADBIN=$(CURDIR)/data/load.bin
|
||||
|
||||
|
||||
bootstub: data
|
||||
@$(MAKE) -C bootstub
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
#$(OUTPUT).nds : $(OUTPUT).elf
|
||||
#$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
$(bin2o)
|
||||
|
||||
-include $(DEPSDIR)/*.d
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
@ -37,8 +37,8 @@ endif
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := GodMode9i
|
||||
BUILD := build
|
||||
SOURCES := source dldi-include ramdrive-include mbedtls
|
||||
INCLUDES := include dldi-include ramdrive-include source
|
||||
SOURCES := source source/graphics dldi-include ramdrive-include mbedtls
|
||||
INCLUDES := include dldi-include ramdrive-include source source/graphics
|
||||
DATA := ../data
|
||||
GRAPHICS := ../gfx
|
||||
|
||||
@ -53,7 +53,7 @@ CFLAGS := -g -Wall -O2\
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM9 -D_NO_BOOTSTUB_
|
||||
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=gnu++11
|
||||
CXXFLAGS := $(CFLAGS) -fno-exceptions -std=gnu++17
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=../ds_arm9_hi.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
@ -62,14 +62,13 @@ LDFLAGS = -specs=../ds_arm9_hi.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
# any extra libraries we wish to link with the project (order is important)
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lfat -lnds9
|
||||
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(CURDIR) ../ $(LIBNDS)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
@ -91,7 +90,7 @@ BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp)))
|
||||
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
@ -110,20 +109,20 @@ export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(BMPFILES:.bmp=.o) \
|
||||
$(PNGFILES:.png=.o) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
all : $(BUILD)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@ -135,38 +134,43 @@ clean:
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.frf.o : %.frf
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# This rule creates assembly source files using grit
|
||||
# grit takes an image file and a .grit describing how the file is to be processed
|
||||
# add additional rules like this for each image extension
|
||||
# you use in the graphics folders
|
||||
# you use in the graphics folders
|
||||
#---------------------------------------------------------------------------------
|
||||
%.s %.h : %.bmp %.grit
|
||||
#---------------------------------------------------------------------------------
|
||||
grit $< -fts -o$*
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.s %.h : %.png %.grit
|
||||
#---------------------------------------------------------------------------------
|
||||
grit $< -fts -o$*
|
||||
|
||||
-include $(DEPSDIR)/*.d
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
@ -1,23 +1,29 @@
|
||||
#ifndef _bmp_h_
|
||||
#define _bmp_h_
|
||||
|
||||
#include <nds/ndstypes.h>
|
||||
|
||||
typedef struct {
|
||||
u16 type; /* Magic identifier */
|
||||
u32 size; /* File size in bytes */
|
||||
u32 size; /* File size in bytes */
|
||||
u16 reserved1, reserved2;
|
||||
u32 offset; /* Offset to image data, bytes */
|
||||
u32 offset; /* Offset to image data, bytes */
|
||||
} PACKED HEADER;
|
||||
|
||||
typedef struct {
|
||||
u32 size; /* Header size in bytes */
|
||||
u32 width,height; /* Width and height of image */
|
||||
u32 width, height; /* Width and height of image */
|
||||
u16 planes; /* Number of colour planes */
|
||||
u16 bits; /* Bits per pixel */
|
||||
u32 compression; /* Compression type */
|
||||
u32 imagesize; /* Image size in bytes */
|
||||
u32 xresolution,yresolution; /* Pixels per meter */
|
||||
u32 xresolution, yresolution; /* Pixels per meter */
|
||||
u32 ncolours; /* Number of colours */
|
||||
u32 importantcolours; /* Important colours */
|
||||
u32 redBitmask; /* Red bitmask */
|
||||
u32 greenBitmask; /* Green bitmask */
|
||||
u32 blueBitmask; /* Blue bitmask */
|
||||
u32 reserved;
|
||||
} PACKED INFOHEADER;
|
||||
|
||||
#endif //_bmp_h_
|
||||
|
@ -1,2 +1,6 @@
|
||||
void screenshot(const char* filename);
|
||||
void screenshotbmp(const char* filename);
|
||||
#ifndef SCREENSHOT_H
|
||||
#define SCREENSHOT_H
|
||||
|
||||
bool screenshot(void);
|
||||
|
||||
#endif // SCREENSHOT_H
|
||||
|
@ -33,214 +33,178 @@
|
||||
#include "dumpOperations.h"
|
||||
#include "driveOperations.h"
|
||||
#include "fileOperations.h"
|
||||
#include "font.h"
|
||||
|
||||
#define SCREEN_COLS 32
|
||||
#define ENTRIES_PER_SCREEN 22
|
||||
#define ENTRIES_START_ROW 1
|
||||
#define ENTRY_PAGE_LENGTH 10
|
||||
|
||||
#define sizeOfdmAssignedOp 8
|
||||
enum class DriveMenuOperation {
|
||||
none,
|
||||
sdCard,
|
||||
flashcard,
|
||||
ramDrive1,
|
||||
ramDrive2,
|
||||
sysNand,
|
||||
nitroFs,
|
||||
fatImage,
|
||||
gbaCart,
|
||||
ndsCard,
|
||||
};
|
||||
|
||||
//static bool ramDumped = false;
|
||||
|
||||
bool flashcardMountSkipped = true;
|
||||
static bool flashcardMountRan = true;
|
||||
static bool dmTextPrinted = false;
|
||||
static int dmCursorPosition = 0;
|
||||
static int dmAssignedOp[sizeOfdmAssignedOp] = {-1};
|
||||
static int dmMaxCursors = -1;
|
||||
static std::vector<DriveMenuOperation> dmOperations;
|
||||
|
||||
static u8 gbaFixedValue = 0;
|
||||
|
||||
extern bool arm7SCFGLocked;
|
||||
extern bool expansionPakFound;
|
||||
|
||||
extern PrintConsole topConsole, bottomConsole;
|
||||
|
||||
extern void printBorderTop(void);
|
||||
extern void printBorderBottom(void);
|
||||
extern void clearBorderTop(void);
|
||||
extern void clearBorderBottom(void);
|
||||
|
||||
void dm_drawTopScreen(void) {
|
||||
/*if (!ramDumped) {
|
||||
printf ("Dumping RAM...");
|
||||
FILE* destinationFile = fopen("sd:/ramdump.bin", "wb");
|
||||
fwrite((void*)0x02000000, 1, 0x400000, destinationFile);
|
||||
fclose(destinationFile);
|
||||
consoleClear();
|
||||
ramDumped = true;
|
||||
}*/
|
||||
font->clear(true);
|
||||
|
||||
consoleClear();
|
||||
// Top bar
|
||||
font->printf(0, 0, true, Alignment::left, Palette::blackGreen, "%*c", 256 / font->width(), ' ');
|
||||
font->print(0, 0, true, "[root]", Alignment::left, Palette::blackGreen);
|
||||
|
||||
printf ("\x1B[30m"); // Print background black color
|
||||
// Print time
|
||||
printf ("\x1b[0;27H");
|
||||
printf (RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
|
||||
printf ("\x1b[0;0H");
|
||||
printf ("[root]");
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
|
||||
// Move to 2nd row
|
||||
printf ("\x1b[1;0H");
|
||||
|
||||
if (dmMaxCursors == -1) {
|
||||
printf ("No drives found!");
|
||||
if (dmOperations.size() == 0) {
|
||||
font->print(0, 1, true, "No drives found!", Alignment::left, Palette::blackGreen);
|
||||
} else
|
||||
for (int i = 0; i <= dmMaxCursors; i++) {
|
||||
iprintf ("\x1b[%d;0H", i + ENTRIES_START_ROW);
|
||||
if (dmCursorPosition == i) {
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
} else {
|
||||
printf ("\x1B[40m"); // Print foreground black color
|
||||
}
|
||||
if (dmAssignedOp[i] == 0) {
|
||||
printf ("[sd:] SDCARD");
|
||||
if (sdLabel[0] != '\0') {
|
||||
iprintf (" (%s)", sdLabel);
|
||||
}
|
||||
} else if (dmAssignedOp[i] == 1) {
|
||||
printf ("[fat:] FLASHCART");
|
||||
if (fatLabel[0] != '\0') {
|
||||
iprintf (" (%s)", fatLabel);
|
||||
}
|
||||
} else if (dmAssignedOp[i] == 2) {
|
||||
printf ("GBA GAMECART");
|
||||
if (gbaFixedValue != 0x96) {
|
||||
iprintf ("\x1b[%d;29H", i + ENTRIES_START_ROW);
|
||||
printf ("[x]");
|
||||
}
|
||||
} else if (dmAssignedOp[i] == 3) {
|
||||
printf ("[nitro:] NDS GAME IMAGE");
|
||||
if ((sdMounted && nitroCurrentDrive==0)
|
||||
|| (flashcardMounted && nitroCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && nitroCurrentDrive==2)
|
||||
|| (ramdrive2Mounted && nitroCurrentDrive==3)
|
||||
|| (nandMounted && nitroCurrentDrive==4)
|
||||
|| (imgMounted && nitroCurrentDrive==6))
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
iprintf ("\x1b[%d;29H", i + ENTRIES_START_ROW);
|
||||
printf ("[x]");
|
||||
}
|
||||
} else if (dmAssignedOp[i] == 4) {
|
||||
printf ("NDS GAMECARD");
|
||||
} else if (dmAssignedOp[i] == 5) {
|
||||
printf ("[ram1:] RAMDRIVE");
|
||||
} else if (dmAssignedOp[i] == 6) {
|
||||
printf ("[ram2:] RAMDRIVE");
|
||||
} else if (dmAssignedOp[i] == 7) {
|
||||
printf ("[nand:] SYSNAND");
|
||||
} else if (dmAssignedOp[i] == 8) {
|
||||
printf ("[img:] FAT IMAGE");
|
||||
if ((sdMounted && imgCurrentDrive==0)
|
||||
|| (flashcardMounted && imgCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && imgCurrentDrive==2)
|
||||
|| (ramdrive2Mounted && imgCurrentDrive==3)
|
||||
|| (nandMounted && imgCurrentDrive==4))
|
||||
{
|
||||
if (imgLabel[0] != '\0') {
|
||||
iprintf (" (%s)", imgLabel);
|
||||
for (int i = 0; i < (int)dmOperations.size(); i++) {
|
||||
Palette pal = dmCursorPosition == i ? Palette::white : Palette::gray;
|
||||
switch(dmOperations[i]) {
|
||||
case DriveMenuOperation::sdCard:
|
||||
font->printf(0, i + 1, true, Alignment::left, pal, "[sd:] SDCARD (%s)", sdLabel[0] == 0 ? "UNTITLED" : sdLabel);
|
||||
break;
|
||||
case DriveMenuOperation::flashcard:
|
||||
font->printf(0, i + 1, true, Alignment::left, pal, "[fat:] FLASHCARD (%s)", fatLabel[0] == 0 ? "UNTITLED" : fatLabel);
|
||||
break;
|
||||
case DriveMenuOperation::ramDrive1:
|
||||
font->print(0, i + 1, true, "[ram1:] RAMDRIVE", Alignment::left, pal);
|
||||
break;
|
||||
case DriveMenuOperation::ramDrive2:
|
||||
font->print(0, i + 1, true, "[ram2:] RAMDRIVE", Alignment::left, pal);
|
||||
break;
|
||||
case DriveMenuOperation::sysNand:
|
||||
font->print(0, i + 1, true, "[nand:] SYSNAND", Alignment::left, pal);
|
||||
break;
|
||||
case DriveMenuOperation::nitroFs:
|
||||
font->print(0, i + 1, true, "[nitro:] NDS GAME IMAGE", Alignment::left, pal);
|
||||
if (!((sdMounted && nitroCurrentDrive==0)
|
||||
|| (flashcardMounted && nitroCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && nitroCurrentDrive==2)
|
||||
|| (ramdrive2Mounted && nitroCurrentDrive==3)
|
||||
|| (nandMounted && nitroCurrentDrive==4)
|
||||
|| (imgMounted && nitroCurrentDrive==6)))
|
||||
font->print(256 - font->width(), i + 1, true, "[x]", Alignment::right, pal);
|
||||
break;
|
||||
case DriveMenuOperation::fatImage:
|
||||
if ((sdMounted && imgCurrentDrive==0)
|
||||
|| (flashcardMounted && imgCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && imgCurrentDrive==2)
|
||||
|| (ramdrive2Mounted && imgCurrentDrive==3)
|
||||
|| (nandMounted && imgCurrentDrive==4)) {
|
||||
font->printf(0, i + 1, true, Alignment::left, pal, "[nitro:] FAT IMAGE (%s)", imgLabel[0] == 0 ? "UNTITLED" : imgLabel);
|
||||
} else {
|
||||
font->print(0, i + 1, true, "[nitro:] FAT IMAGE", Alignment::left, pal);
|
||||
font->print(256 - font->width(), i + 1, true, "[x]", Alignment::right, pal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iprintf ("\x1b[%d;29H", i + ENTRIES_START_ROW);
|
||||
printf ("[x]");
|
||||
}
|
||||
break;
|
||||
case DriveMenuOperation::gbaCart:
|
||||
font->print(0, i + 1, true, "GBA GAMECART", Alignment::left, pal);
|
||||
if (gbaFixedValue != 0x96)
|
||||
font->print(256 - font->width(), i + 1, true, "[x]", Alignment::right, pal);
|
||||
break;
|
||||
case DriveMenuOperation::ndsCard:
|
||||
font->print(0, i + 1, true, "NDS GAMECARD", Alignment::left, pal);
|
||||
break;
|
||||
case DriveMenuOperation::none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
font->update(true);
|
||||
}
|
||||
|
||||
void dm_drawBottomScreen(void) {
|
||||
consoleClear();
|
||||
font->clear(false);
|
||||
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf ("\x1b[23;0H");
|
||||
printf (titleName);
|
||||
if (nitroMounted || imgMounted) {
|
||||
printf ("\n");
|
||||
printf (IMAGETEXT);
|
||||
int row = -1;
|
||||
|
||||
if (!isDSiMode() && isRegularDS) {
|
||||
font->print(0, row--, false, POWERTEXT_DS);
|
||||
} else if (is3DS) {
|
||||
font->print(0, row--, false, HOMETEXT);
|
||||
font->print(0, row--, false, POWERTEXT_3DS);
|
||||
} else {
|
||||
font->print(0, row--, false, POWERTEXT);
|
||||
}
|
||||
|
||||
if (sdMountedDone) {
|
||||
if (isRegularDS || sdMounted) {
|
||||
printf ("\n");
|
||||
printf (sdMounted ? "R+B - Unmount SD card" : "R+B - Remount SD card");
|
||||
font->print(0, row--, false, sdMounted ? "R+B - Unmount SD card" : "R+B - Remount SD card");
|
||||
}
|
||||
} else {
|
||||
printf ("\n");
|
||||
printf (flashcardMounted ? "R+B - Unmount Flashcard" : "R+B - Remount Flashcard");
|
||||
font->print(0, row--, false, flashcardMounted ? "R+B - Unmount Flashcard" : "R+B - Remount Flashcard");
|
||||
}
|
||||
if (sdMounted || flashcardMounted) {
|
||||
printf ("\n");
|
||||
printf (SCREENSHOTTEXT);
|
||||
}
|
||||
printf ("\n");
|
||||
if (!isDSiMode() && isRegularDS) {
|
||||
printf (POWERTEXT_DS);
|
||||
} else if (is3DS) {
|
||||
printf (POWERTEXT_3DS);
|
||||
printf ("\n");
|
||||
printf (HOMETEXT);
|
||||
} else {
|
||||
printf (POWERTEXT);
|
||||
font->print(0, row--, false, SCREENSHOTTEXT);
|
||||
}
|
||||
|
||||
printf ("\x1B[40m"); // Print foreground black color
|
||||
printf ("\x1b[0;0H");
|
||||
if (dmAssignedOp[dmCursorPosition] == 0) {
|
||||
printf ("[sd:] SDCARD");
|
||||
if (sdLabel[0] != '\0') {
|
||||
iprintf (" (%s)", sdLabel);
|
||||
}
|
||||
printf ("\n(SD FAT, ");
|
||||
printDriveBytes(sdSize);
|
||||
printf(")\n");
|
||||
printDriveBytes(getBytesFree("sd:/"));
|
||||
printf(" space free");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 1) {
|
||||
printf ("[fat:] FLASHCART");
|
||||
if (fatLabel[0] != '\0') {
|
||||
iprintf (" (%s)", fatLabel);
|
||||
}
|
||||
printf ("\n(Slot-1 SD FAT, ");
|
||||
printDriveBytes(fatSize);
|
||||
printf(")\n");
|
||||
printDriveBytes(getBytesFree("fat:/"));
|
||||
printf(" space free");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 2) {
|
||||
printf ("GBA GAMECART\n");
|
||||
printf ("(GBA Game)");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 3) {
|
||||
printf ("[nitro:] NDS GAME IMAGE\n");
|
||||
printf ("(Game Virtual)");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 4) {
|
||||
printf ("NDS GAMECARD\n");
|
||||
printf ("(NDS Game)");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 5) {
|
||||
printf ("[ram1:] RAMDRIVE\n");
|
||||
printf ("(RAMdrive FAT, 9 MB)");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 6) {
|
||||
printf ("[ram2:] RAMDRIVE\n");
|
||||
printf ("(RAMdrive FAT, 16 MB)");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 7) {
|
||||
printf ("[nand:] SYSNAND");
|
||||
printf ("\n(SysNAND FAT, ");
|
||||
printDriveBytes(nandSize);
|
||||
printf(")\n");
|
||||
printDriveBytes(getBytesFree("nand:/"));
|
||||
printf(" space free");
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 8) {
|
||||
printf ("[img:] FAT IMAGE");
|
||||
printf ("\n(Image FAT, ");
|
||||
printDriveBytes(imgSize);
|
||||
printf(")");
|
||||
font->print(0, row--, false, IMAGETEXT);
|
||||
font->print(0, row--, false, titleName);
|
||||
|
||||
switch(dmOperations[dmCursorPosition]) {
|
||||
case DriveMenuOperation::sdCard:
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "[sd:] SDCARD (%s)", sdLabel[0] == 0 ? "UNTITLED" : sdLabel);
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "(SD FAT, %s)", getDriveBytes(sdSize).c_str());
|
||||
font->printf(0, 2, false, Alignment::left, Palette::white, "%s free", getDriveBytes(getBytesFree("sd:/")).c_str());
|
||||
break;
|
||||
case DriveMenuOperation::flashcard:
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "[fat:] FLASHCARD (%s)", fatLabel[0] == 0 ? "UNTITLED" : fatLabel);
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "(Slot-1 SD FAT, %s)", getDriveBytes(fatSize).c_str());
|
||||
font->printf(0, 2, false, Alignment::left, Palette::white, "%s free", getDriveBytes(getBytesFree("fat:/")).c_str());
|
||||
break;
|
||||
case DriveMenuOperation::gbaCart:
|
||||
font->print(0, 0, false, "GBA GAMECART");
|
||||
font->print(0, 1, false, "(GBA Game)");
|
||||
break;
|
||||
case DriveMenuOperation::nitroFs:
|
||||
font->print(0, 0, false, "[nitro:] NDS GAME IMAGE\n");
|
||||
font->print(0, 1, false, "(Game Virtual)");
|
||||
break;
|
||||
case DriveMenuOperation::ndsCard:
|
||||
font->print(0, 0, false, "NDS GAMECARD\n");
|
||||
font->print(0, 1, false, "(NDS Game)");
|
||||
break;
|
||||
case DriveMenuOperation::ramDrive1:
|
||||
font->print(0, 0, false, "[ram1:] RAMDRIVE\n");
|
||||
font->print(0, 1, false, "(RAMdrive FAT, 9 MB)");
|
||||
break;
|
||||
case DriveMenuOperation::ramDrive2:
|
||||
font->print(0, 0, false, "[ram2:] RAMDRIVE\n");
|
||||
font->print(0, 1, false, "(RAMdrive FAT, 16 MB)");
|
||||
break;
|
||||
case DriveMenuOperation::sysNand:
|
||||
font->print(0, 0, false, "[nand:] SYSNAND");
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "(SysNAND FAT, %s)", getDriveBytes(fatSize).c_str());
|
||||
font->printf(0, 2, false, Alignment::left, Palette::white, "%s free", getDriveBytes(getBytesFree("nand:/")).c_str());
|
||||
break;
|
||||
case DriveMenuOperation::fatImage:
|
||||
font->print(0, 0, false, "[img:] FAT IMAGE");
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "(Image FAT, %s)", getDriveBytes(imgSize).c_str());
|
||||
break;
|
||||
case DriveMenuOperation::none:
|
||||
break;
|
||||
}
|
||||
|
||||
font->update(false);
|
||||
}
|
||||
|
||||
void driveMenu (void) {
|
||||
@ -252,71 +216,38 @@ void driveMenu (void) {
|
||||
gbaFixedValue = *(u8*)(0x080000B2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeOfdmAssignedOp; i++) {
|
||||
dmAssignedOp[i] = -1;
|
||||
}
|
||||
dmMaxCursors = -1;
|
||||
if (sdMounted){
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 0;
|
||||
}
|
||||
if (nandMounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 7;
|
||||
}
|
||||
if (flashcardMounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 1;
|
||||
}
|
||||
if (ramdrive1Mounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 5;
|
||||
}
|
||||
if (ramdrive2Mounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 6;
|
||||
}
|
||||
if (imgMounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 8;
|
||||
}
|
||||
dmOperations.clear();
|
||||
if (sdMounted)
|
||||
dmOperations.push_back(DriveMenuOperation::sdCard);
|
||||
if (nandMounted)
|
||||
dmOperations.push_back(DriveMenuOperation::sysNand);
|
||||
if (flashcardMounted)
|
||||
dmOperations.push_back(DriveMenuOperation::flashcard);
|
||||
if (ramdrive1Mounted)
|
||||
dmOperations.push_back(DriveMenuOperation::ramDrive1);
|
||||
if (ramdrive2Mounted)
|
||||
dmOperations.push_back(DriveMenuOperation::ramDrive2);
|
||||
if (imgMounted)
|
||||
dmOperations.push_back(DriveMenuOperation::fatImage);
|
||||
if (expansionPakFound
|
||||
|| (io_dldi_data->ioInterface.features & FEATURE_SLOT_GBA)
|
||||
|| (isDSiMode() && !arm7SCFGLocked && !(REG_SCFG_MC & BIT(0)))) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 4;
|
||||
}
|
||||
if (!isDSiMode() && isRegularDS) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 2;
|
||||
}
|
||||
if (nitroMounted) {
|
||||
dmMaxCursors++;
|
||||
dmAssignedOp[dmMaxCursors] = 3;
|
||||
}
|
||||
|| (isDSiMode() && !arm7SCFGLocked && !(REG_SCFG_MC & BIT(0))))
|
||||
dmOperations.push_back(DriveMenuOperation::ndsCard);
|
||||
if (!isDSiMode() && isRegularDS)
|
||||
dmOperations.push_back(DriveMenuOperation::gbaCart);
|
||||
if (nitroMounted)
|
||||
dmOperations.push_back(DriveMenuOperation::nitroFs);
|
||||
|
||||
if (dmCursorPosition < 0) dmCursorPosition = dmMaxCursors; // Wrap around to bottom of list
|
||||
if (dmCursorPosition > dmMaxCursors) dmCursorPosition = 0; // Wrap around to top of list
|
||||
|
||||
if (!dmTextPrinted) {
|
||||
consoleSelect(&bottomConsole);
|
||||
dm_drawBottomScreen();
|
||||
consoleSelect(&topConsole);
|
||||
dm_drawTopScreen();
|
||||
|
||||
dmTextPrinted = true;
|
||||
}
|
||||
dm_drawBottomScreen();
|
||||
dm_drawTopScreen();
|
||||
|
||||
stored_SCFG_MC = REG_SCFG_MC;
|
||||
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;27H");
|
||||
// Print time
|
||||
printf (RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -325,52 +256,53 @@ void driveMenu (void) {
|
||||
|
||||
if (!isDSiMode() && isRegularDS) {
|
||||
if (*(u8*)(0x080000B2) != gbaFixedValue) {
|
||||
dmTextPrinted = false;
|
||||
break;
|
||||
}
|
||||
} else if (isDSiMode()) {
|
||||
if (REG_SCFG_MC != stored_SCFG_MC) {
|
||||
dmTextPrinted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!(pressed & KEY_UP) && !(pressed & KEY_DOWN) && !(pressed & KEY_A) && !(held & KEY_R)
|
||||
} while (!(pressed & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT | KEY_A | KEY_R
|
||||
#ifdef SCREENSWAP
|
||||
&& !(pressed & KEY_TOUCH)
|
||||
| KEY_TOUCH
|
||||
#endif
|
||||
);
|
||||
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
)));
|
||||
|
||||
if ((pressed & KEY_UP) && dmMaxCursors != -1) {
|
||||
dmCursorPosition -= 1;
|
||||
dmTextPrinted = false;
|
||||
if(dmOperations.size() != 0) {
|
||||
if (pressed & KEY_UP) {
|
||||
dmCursorPosition -= 1;
|
||||
if(dmCursorPosition < 0)
|
||||
dmCursorPosition = dmOperations.size() - 1;
|
||||
} else if (pressed & KEY_DOWN) {
|
||||
dmCursorPosition += 1;
|
||||
if(dmCursorPosition >= (int)dmOperations.size())
|
||||
dmCursorPosition = 0;
|
||||
} else if(pressed & KEY_LEFT) {
|
||||
dmCursorPosition -= ENTRY_PAGE_LENGTH;
|
||||
if(dmCursorPosition < 0)
|
||||
dmCursorPosition = 0;
|
||||
} else if(pressed & KEY_RIGHT) {
|
||||
dmCursorPosition += ENTRY_PAGE_LENGTH;
|
||||
if(dmCursorPosition >= (int)dmOperations.size())
|
||||
dmCursorPosition = dmOperations.size() - 1;
|
||||
}
|
||||
}
|
||||
if ((pressed & KEY_DOWN) && dmMaxCursors != -1) {
|
||||
dmCursorPosition += 1;
|
||||
dmTextPrinted = false;
|
||||
}
|
||||
|
||||
if (dmCursorPosition < 0) dmCursorPosition = dmMaxCursors; // Wrap around to bottom of list
|
||||
if (dmCursorPosition > dmMaxCursors) dmCursorPosition = 0; // Wrap around to top of list
|
||||
|
||||
if (pressed & KEY_A) {
|
||||
if (dmAssignedOp[dmCursorPosition] == 0 && sdMounted) {
|
||||
dmTextPrinted = false;
|
||||
if (dmOperations[dmCursorPosition] == DriveMenuOperation::sdCard && sdMounted) {
|
||||
currentDrive = 0;
|
||||
chdir("sd:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 1 && flashcardMounted) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::flashcard && flashcardMounted) {
|
||||
currentDrive = 1;
|
||||
chdir("fat:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 2 && isRegularDS && flashcardMounted && gbaFixedValue == 0x96) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::gbaCart && isRegularDS && flashcardMounted && gbaFixedValue == 0x96) {
|
||||
gbaCartDump();
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 3 && nitroMounted) {
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::nitroFs && nitroMounted) {
|
||||
if ((sdMounted && nitroCurrentDrive==0)
|
||||
|| (flashcardMounted && nitroCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && nitroCurrentDrive==2)
|
||||
@ -378,41 +310,35 @@ void driveMenu (void) {
|
||||
|| (nandMounted && nitroCurrentDrive==4)
|
||||
|| (imgMounted && nitroCurrentDrive==6))
|
||||
{
|
||||
dmTextPrinted = false;
|
||||
currentDrive = 5;
|
||||
chdir("nitro:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
}
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 4 && (sdMounted || flashcardMounted)) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::ndsCard && (sdMounted || flashcardMounted)) {
|
||||
ndsCardDump();
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 5 && isDSiMode() && ramdrive1Mounted) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::ramDrive1 && isDSiMode() && ramdrive1Mounted) {
|
||||
currentDrive = 2;
|
||||
chdir("ram1:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 6 && isDSiMode() && ramdrive2Mounted) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::ramDrive2 && isDSiMode() && ramdrive2Mounted) {
|
||||
currentDrive = 3;
|
||||
chdir("ram2:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 7 && isDSiMode() && nandMounted) {
|
||||
dmTextPrinted = false;
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::sysNand && isDSiMode() && nandMounted) {
|
||||
currentDrive = 4;
|
||||
chdir("nand:/");
|
||||
screenMode = 1;
|
||||
break;
|
||||
} else if (dmAssignedOp[dmCursorPosition] == 8 && imgMounted) {
|
||||
} else if (dmOperations[dmCursorPosition] == DriveMenuOperation::fatImage && imgMounted) {
|
||||
if ((sdMounted && imgCurrentDrive==0)
|
||||
|| (flashcardMounted && imgCurrentDrive==1)
|
||||
|| (ramdrive1Mounted && imgCurrentDrive==2)
|
||||
|| (ramdrive2Mounted && imgCurrentDrive==3)
|
||||
|| (nandMounted && imgCurrentDrive==4))
|
||||
{
|
||||
dmTextPrinted = false;
|
||||
currentDrive = 6;
|
||||
chdir("img:/");
|
||||
screenMode = 1;
|
||||
@ -423,7 +349,6 @@ void driveMenu (void) {
|
||||
|
||||
// Unmount/Remount FAT image
|
||||
if ((held & KEY_R) && (pressed & KEY_X)) {
|
||||
dmTextPrinted = false;
|
||||
if (nitroMounted) {
|
||||
currentDrive = 5;
|
||||
chdir("nitro:/");
|
||||
@ -437,7 +362,6 @@ void driveMenu (void) {
|
||||
|
||||
// Unmount/Remount SD card
|
||||
if ((held & KEY_R) && (pressed & KEY_B)) {
|
||||
dmTextPrinted = false;
|
||||
if (isDSiMode() && sdMountedDone) {
|
||||
if (sdMounted) {
|
||||
currentDrive = 0;
|
||||
@ -467,40 +391,7 @@ void driveMenu (void) {
|
||||
|
||||
// Make a screenshot
|
||||
if ((held & KEY_R) && (pressed & KEY_L)) {
|
||||
if (sdMounted || flashcardMounted) {
|
||||
if (access((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), 0777);
|
||||
}
|
||||
if (access((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), 0777);
|
||||
}
|
||||
char timeText[8];
|
||||
snprintf(timeText, sizeof(timeText), "%s", RetTime().c_str());
|
||||
char fileTimeText[8];
|
||||
snprintf(fileTimeText, sizeof(fileTimeText), "%s", RetTimeForFilename().c_str());
|
||||
char snapPath[40];
|
||||
// Take top screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_top.bmp", (sdMounted ? "sd" : "fat"), fileTimeText);
|
||||
screenshotbmp(snapPath);
|
||||
// Seamlessly swap top and bottom screens
|
||||
lcdMainOnBottom();
|
||||
printBorderBottom();
|
||||
consoleSelect(&bottomConsole);
|
||||
dm_drawTopScreen();
|
||||
printf("\x1B[30m"); // Print black color for time text
|
||||
printf("\x1b[0;27H");
|
||||
printf(timeText);
|
||||
clearBorderTop();
|
||||
consoleSelect(&topConsole);
|
||||
dm_drawBottomScreen();
|
||||
// Take bottom screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_bot.bmp", (sdMounted ? "sd" : "fat"), fileTimeText);
|
||||
screenshotbmp(snapPath);
|
||||
dmTextPrinted = false;
|
||||
lcdMainOnTop();
|
||||
printBorderTop();
|
||||
clearBorderBottom();
|
||||
}
|
||||
screenshot();
|
||||
}
|
||||
|
||||
if (isDSiMode() && !flashcardMountSkipped && !pressed && !held) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include <nds.h>
|
||||
#include <nds/arm9/dldi.h>
|
||||
#include <fat.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "dldi-include.h"
|
||||
@ -58,19 +59,22 @@ static float getTbNumber(u64 bytes) {
|
||||
return tbNumber;
|
||||
}
|
||||
|
||||
void printDriveBytes(u64 bytes)
|
||||
std::string getDriveBytes(u64 bytes)
|
||||
{
|
||||
char buffer[12];
|
||||
if (bytes < (1024 * 1024))
|
||||
printf("%d KB", (int)bytes / 1024);
|
||||
sniprintf(buffer, sizeof(buffer), "%d KB", (int)bytes / 1024);
|
||||
|
||||
else if (bytes >= (1024 * 1024) && bytes < (1024 * 1024 * 1024))
|
||||
printf("%d MB", (int)bytes / 1024 / 1024);
|
||||
sniprintf(buffer, sizeof(buffer), "%d MB", (int)bytes / 1024 / 1024);
|
||||
|
||||
else if (bytes >= 0x40000000 && bytes < 0x10000000000)
|
||||
printf("%.1f GB", getGbNumber(bytes));
|
||||
snprintf(buffer, sizeof(buffer), "%.1f GB", getGbNumber(bytes));
|
||||
|
||||
else
|
||||
printf("%.1f TB", getTbNumber(bytes));
|
||||
snprintf(buffer, sizeof(buffer), "%.1f TB", getTbNumber(bytes));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* getDrivePath(void) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef FLASHCARD_H
|
||||
#define FLASHCARD_H
|
||||
|
||||
#include <string>
|
||||
|
||||
extern u8 stored_SCFG_MC;
|
||||
|
||||
extern bool nandMounted;
|
||||
@ -24,7 +26,7 @@ extern u32 nandSize;
|
||||
extern u64 sdSize;
|
||||
extern u64 fatSize;
|
||||
extern u64 imgSize;
|
||||
extern void printDriveBytes(u64 bytes);
|
||||
extern std::string getDriveBytes(u64 bytes);
|
||||
|
||||
extern const char* getDrivePath(void);
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
#include <nds.h>
|
||||
#include <nds/arm9/dldi.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include "dumpOperations.h"
|
||||
|
||||
#include "auxspi.h"
|
||||
#include "date.h"
|
||||
#include "driveOperations.h"
|
||||
#include "font.h"
|
||||
#include "ndsheaderbanner.h"
|
||||
#include "read_card.h"
|
||||
#include "tonccpy.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <nds.h>
|
||||
#include <nds/arm9/dldi.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern u8 copyBuf[];
|
||||
|
||||
extern bool expansionPakFound;
|
||||
|
||||
extern PrintConsole topConsole, bottomConsole;
|
||||
|
||||
static sNDSHeaderExt ndsCardHeader;
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -138,9 +138,11 @@ uint32 cardEepromGetSizeFixed() {
|
||||
void ndsCardSaveDump(const char* filename) {
|
||||
FILE *out = fopen(filename, "wb");
|
||||
if(out) {
|
||||
consoleClear();
|
||||
iprintf("Dumping save...\n");
|
||||
iprintf("Do not remove the NDS card.\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Dumping save...");
|
||||
font->print(0, 1, false, "Do not remove the NDS card.");
|
||||
font->update(false);
|
||||
|
||||
unsigned char *buffer;
|
||||
auxspi_extra card_type = auxspi_has_extra();
|
||||
if(card_type == AUXSPI_INFRARED) {
|
||||
@ -168,22 +170,17 @@ void ndsCardSaveDump(const char* filename) {
|
||||
}
|
||||
|
||||
void ndsCardSaveRestore(const char *filename) {
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
iprintf("\x1B[47m"); // Print foreground white color
|
||||
iprintf("Restore the selected save to the"); // Line is 32 chars
|
||||
iprintf("inserted game card?\n"); // Line is 32 chars
|
||||
iprintf("(<A> yes, <B> no)\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Restore the selected save to the inserted game card?");
|
||||
font->print(0, 2, false, "(<A> yes, <B> no)\n");
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
u16 pressed;
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -191,9 +188,6 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
} while (!(pressed & (KEY_A | KEY_B)));
|
||||
|
||||
if(pressed & KEY_A) {
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
|
||||
auxspi_extra card_type = auxspi_has_extra();
|
||||
bool auxspi = card_type == AUXSPI_INFRARED;
|
||||
FILE *in = fopen(filename, "rb");
|
||||
@ -228,23 +222,20 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
fseek(in, 0, SEEK_END);
|
||||
length = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
if(length != (auxspi ? (int)(LEN*num_blocks) : size)) {
|
||||
if(length != (auxspi ? (int)(LEN * num_blocks) : size)) {
|
||||
fclose(in);
|
||||
iprintf("\x1B[41m"); // Print foreground red color
|
||||
iprintf("The size of this save doesn't\n");
|
||||
iprintf("match the size of the size of\n");
|
||||
iprintf("the inserted game card.\n\n");
|
||||
iprintf("Write cancelled!\n");
|
||||
iprintf("\x1B[47m"); // Print foreground white color
|
||||
iprintf("(<A> OK)\n");
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
const std::string_view sizeError = "The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!";
|
||||
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, sizeError, Alignment::left, Palette::red);
|
||||
font->print(0, font->calcHeight(sizeError) + 1, false, "(<A> OK)");
|
||||
font->update(false);
|
||||
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -252,7 +243,13 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
} while (!(pressed & KEY_A));
|
||||
return;
|
||||
}
|
||||
iprintf("Restoring save...\nDo not remove the NDS card.\n\n\n\n\n\n\nProgress:");
|
||||
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Restoring save...");
|
||||
font->print(0, 1, false, "Do not remove the NDS card.");
|
||||
font->print(0, 4, false, "Progress:");
|
||||
font->update(false);
|
||||
|
||||
if(type == 3) {
|
||||
if(auxspi)
|
||||
auxspi_erase(card_type);
|
||||
@ -261,9 +258,12 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
}
|
||||
if(auxspi){
|
||||
buffer = new unsigned char[LEN];
|
||||
font->print(0, 5, false, "[");
|
||||
font->print(-1, 5, false, "]");
|
||||
for(unsigned int i = 0; i < num_blocks; i++) {
|
||||
iprintf ("\x1b[9;0H");
|
||||
iprintf ("%d/%d Bytes", i * LEN, length);
|
||||
font->print((i * (SCREEN_COLS - 2) / num_blocks) + 1, 5, false, "=");
|
||||
font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", i * LEN, length);
|
||||
font->update(false);
|
||||
|
||||
fread(buffer, 1, LEN, in);
|
||||
auxspi_write_data(i << shift, buffer, LEN, type, card_type);
|
||||
@ -272,9 +272,13 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
int blocks = size / 32;
|
||||
int written = 0;
|
||||
buffer = new unsigned char[blocks];
|
||||
font->print(0, 5, false, "[");
|
||||
font->print(-1, 5, false, "]");
|
||||
for(unsigned int i = 0; i < 32; i++) {
|
||||
iprintf ("\x1b[9;0H");
|
||||
iprintf ("%d/%d Bytes", i * blocks, length);
|
||||
font->print((i * (SCREEN_COLS - 2) / 32) + 1, 5, false, "=");
|
||||
font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", i * LEN, length);
|
||||
font->update(false);
|
||||
|
||||
fread(buffer, 1, blocks, in);
|
||||
cardWriteEeprom(written, buffer, blocks, type);
|
||||
written += blocks;
|
||||
@ -287,8 +291,10 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
}
|
||||
|
||||
void dumpFailMsg(void) {
|
||||
consoleClear();
|
||||
iprintf("Failed to dump the ROM.\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Failed to dump the ROM.");
|
||||
font->update(false);
|
||||
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
@ -298,49 +304,44 @@ void ndsCardDump(void) {
|
||||
int pressed = 0;
|
||||
//bool showGameCardMsgAgain = false;
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
iprintf("\x1B[47m"); // Print foreground white color
|
||||
iprintf("Dump NDS card ROM to\n");
|
||||
iprintf("\"%s:/gm9i/out\"?\n", (sdMounted ? "sd" : "fat"));
|
||||
iprintf("(<A> yes, <Y> trim, <B> no,\n");
|
||||
iprintf(" <X> save only)");
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Dump NDS card ROM to\n\"%s:/gm9i/out\"?", sdMounted ? "sd:" : "fat:");
|
||||
font->print(0, 2, false, "(<A> yes, <Y> trim, <B> no, <X> save only)");
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
swiWaitForVBlank();
|
||||
} while (!(pressed & (KEY_A | KEY_Y | KEY_B | KEY_X)));
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
iprintf ("\x1B[47m"); // Print foreground white color
|
||||
|
||||
if (pressed & KEY_X) {
|
||||
consoleClear();
|
||||
char folderPath[2][256];
|
||||
sprintf(folderPath[0], "%s:/gm9i", (sdMounted ? "sd" : "fat"));
|
||||
sprintf(folderPath[1], "%s:/gm9i/out", (sdMounted ? "sd" : "fat"));
|
||||
if (access(folderPath[0], F_OK) != 0) {
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir(folderPath[0], 0777);
|
||||
}
|
||||
if (access(folderPath[1], F_OK) != 0) {
|
||||
iprintf("\x1b[0;0H");
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir(folderPath[1], 0777);
|
||||
}
|
||||
consoleClear();
|
||||
|
||||
if (cardInit(&ndsCardHeader) != 0) {
|
||||
iprintf("Unable to dump the save.\n");
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Unable to dump the save.");
|
||||
font->update(false);
|
||||
for (int i = 0; i < 60 * 2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
return;
|
||||
@ -354,44 +355,41 @@ void ndsCardDump(void) {
|
||||
ndsCardSaveDump(destSavPath);
|
||||
} else
|
||||
if ((pressed & KEY_A) || (pressed & KEY_Y)) {
|
||||
consoleClear();
|
||||
bool trimRom = (pressed & KEY_Y);
|
||||
char folderPath[2][256];
|
||||
sprintf(folderPath[0], "%s:/gm9i", (sdMounted ? "sd" : "fat"));
|
||||
sprintf(folderPath[1], "%s:/gm9i/out", (sdMounted ? "sd" : "fat"));
|
||||
if (access(folderPath[0], F_OK) != 0) {
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir(folderPath[0], 0777);
|
||||
}
|
||||
if (access(folderPath[1], F_OK) != 0) {
|
||||
iprintf("\x1b[0;0H");
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir(folderPath[1], 0777);
|
||||
}
|
||||
/*if (expansionPakFound) {
|
||||
consoleClear();
|
||||
printf("Please switch to the\ngame card, then press A.\n");
|
||||
font->clear(false)
|
||||
font->print(0, 0, false, "Please switch to the game card, then press A.");
|
||||
font->update(false);
|
||||
//flashcardUnmount();
|
||||
io_dldi_data->ioInterface.shutdown();
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color
|
||||
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
swiWaitForVBlank();
|
||||
} while (!(pressed & KEY_A));
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
}*/
|
||||
consoleClear();
|
||||
|
||||
int cardInited = cardInit(&ndsCardHeader);
|
||||
char gameTitle[13] = {0};
|
||||
char gameCode[7] = {0};
|
||||
@ -426,10 +424,14 @@ void ndsCardDump(void) {
|
||||
sprintf(destSavPath, "%s:/gm9i/out/%s.sav", (sdMounted ? "sd" : "fat"), fileName);
|
||||
|
||||
if (cardInited == 0) {
|
||||
iprintf("%s.nds\nis dumping...\n", fileName);
|
||||
iprintf("Do not remove the NDS card.\n");
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "%s.nds\nis dumping...", fileName);
|
||||
font->print(0, 2, false, "Do not remove the NDS card.");
|
||||
font->update(false);
|
||||
} else {
|
||||
iprintf("Unable to dump the ROM.\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Unable to dump the ROM.");
|
||||
font->update(false);
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
@ -498,14 +500,11 @@ void ndsCardDump(void) {
|
||||
//flashcardUnmount();
|
||||
io_dldi_data->ioInterface.shutdown();
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -521,12 +520,9 @@ void ndsCardDump(void) {
|
||||
|
||||
// Read from game card
|
||||
for (src = src; src < currentSize; src += 0x200) {
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
iprintf ("\x1B[47m"); // Print foreground white color
|
||||
@ -537,14 +533,11 @@ void ndsCardDump(void) {
|
||||
}
|
||||
iprintf("\x1b[15;0H");
|
||||
iprintf("Please switch to the\nflashcard, then press A.\n");
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -568,12 +561,9 @@ void ndsCardDump(void) {
|
||||
destinationFileOpened = true;
|
||||
}
|
||||
for (writeSrc = writeSrc; writeSrc < currentSize; writeSrc += 0x200) {
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
@ -590,19 +580,19 @@ void ndsCardDump(void) {
|
||||
u32 currentSize = romSize;
|
||||
FILE* destinationFile = fopen(destPath, "wb");
|
||||
if (destinationFile) {
|
||||
for (u32 src = 0; src < romSize; src += 0x8000) {
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
iprintf ("\x1B[47m"); // Print foreground white color
|
||||
iprintf ("\x1b[8;0H");
|
||||
iprintf ("Progress:\n");
|
||||
iprintf ("%i/%i Bytes", (int)src, (int)romSize);
|
||||
font->print(0, 4, false, "Progress:");
|
||||
font->print(0, 5, false, "[");
|
||||
font->print(-1, 5, false, "]");
|
||||
for (u32 src = 0; src < romSize; src += 0x8000) {
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
font->print((src / (romSize / (SCREEN_COLS - 2))) + 1, 5, false, "=");
|
||||
font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, romSize);
|
||||
font->update(false);
|
||||
|
||||
for (u32 i = 0; i < 0x8000; i += 0x200) {
|
||||
cardRead (src+i, copyBuf+i);
|
||||
}
|
||||
@ -639,21 +629,16 @@ void readChange(void) {
|
||||
void gbaCartDump(void) {
|
||||
int pressed = 0;
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
iprintf("\x1B[47m"); // Print foreground white color
|
||||
iprintf("Dump GBA cart ROM to\n");
|
||||
iprintf("\"fat:/gm9i/out\"?\n");
|
||||
iprintf("(<A> yes, <B> no)");
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Dump GBA cart ROM to\n\"%s:/gm9i/out\"?", sdMounted ? "sd:" : "fat:");
|
||||
font->print(0, 2, false, "(<A> yes, <B> no)");
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -661,22 +646,23 @@ void gbaCartDump(void) {
|
||||
} while (!(pressed & KEY_A) && !(pressed & KEY_B));
|
||||
|
||||
if (pressed & KEY_A) {
|
||||
iprintf ("\x1b[0;27H");
|
||||
iprintf (" "); // Clear time
|
||||
// Clear time
|
||||
font->print(-1, 0, true, " ", Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
}
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
|
||||
if (pressed & KEY_A) {
|
||||
consoleClear();
|
||||
if (access("fat:/gm9i", F_OK) != 0) {
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("fat:/gm9i", 0777);
|
||||
}
|
||||
if (access("fat:/gm9i/out", F_OK) != 0) {
|
||||
iprintf ("\x1b[0;0H");
|
||||
iprintf("Creating directory...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("fat:/gm9i/out", 0777);
|
||||
}
|
||||
char gbaHeaderGameTitle[13] = "\0";
|
||||
@ -716,9 +702,12 @@ void gbaCartDump(void) {
|
||||
char destSavPath[256] = {0};
|
||||
sprintf(destPath, "fat:/gm9i/out/%s.gba", fileName);
|
||||
sprintf(destSavPath, "fat:/gm9i/out/%s.sav", fileName);
|
||||
consoleClear();
|
||||
iprintf("%s.gba\nis dumping...\n", fileName);
|
||||
iprintf("Do not remove the GBA cart.\n");
|
||||
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "%s.gba\nis dumping...", fileName);
|
||||
font->print(0, 2, false, "Do not remove the GBA cart.");
|
||||
font->update(false);
|
||||
|
||||
// Determine ROM size
|
||||
u32 romSize = 0x02000000;
|
||||
for (u32 i = 0x09FE0000; i > 0x08000000; i -= 0x20000) {
|
||||
@ -772,6 +761,7 @@ void gbaCartDump(void) {
|
||||
} else {
|
||||
dumpFailMsg();
|
||||
}
|
||||
|
||||
// Save file
|
||||
remove(destSavPath);
|
||||
destinationFile = fopen(destSavPath, "wb");
|
||||
|
@ -7,56 +7,38 @@
|
||||
|
||||
#include "date.h"
|
||||
#include "file_browse.h"
|
||||
#include "font.h"
|
||||
|
||||
#define copyBufSize 0x8000
|
||||
#define shaChunkSize 0x10000
|
||||
|
||||
u32 copyBuf[copyBufSize];
|
||||
|
||||
extern PrintConsole topConsole, bottomConsole;
|
||||
|
||||
std::vector<ClipboardFile> clipboard;
|
||||
bool clipboardOn = false;
|
||||
bool clipboardUsed = false;
|
||||
|
||||
void printBytes(int bytes)
|
||||
{
|
||||
std::string getBytes(int bytes) {
|
||||
char buffer[11];
|
||||
if (bytes == 1)
|
||||
iprintf("%d Byte", bytes);
|
||||
sniprintf(buffer, sizeof(buffer), "%d Byte", bytes);
|
||||
|
||||
else if (bytes < 1024)
|
||||
iprintf("%d Bytes", bytes);
|
||||
sniprintf(buffer, sizeof(buffer), "%d Bytes", bytes);
|
||||
|
||||
else if (bytes < (1024 * 1024))
|
||||
printf("%d KB", bytes / 1024);
|
||||
sniprintf(buffer, sizeof(buffer), "%d KB", bytes / 1024);
|
||||
|
||||
else if (bytes < (1024 * 1024 * 1024))
|
||||
printf("%d MB", bytes / 1024 / 1024);
|
||||
sniprintf(buffer, sizeof(buffer), "%d MB", bytes / 1024 / 1024);
|
||||
|
||||
else
|
||||
printf("%d GB", bytes / 1024 / 1024 / 1024);
|
||||
sniprintf(buffer, sizeof(buffer), "%d GB", bytes / 1024 / 1024 / 1024);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void printBytesAlign(int bytes)
|
||||
{
|
||||
if (bytes == 1)
|
||||
iprintf("%4d Byte", bytes);
|
||||
|
||||
else if (bytes < 1024)
|
||||
iprintf("%3d Bytes", bytes);
|
||||
|
||||
else if (bytes < (1024 * 1024))
|
||||
printf("%6d KB", bytes / 1024);
|
||||
|
||||
else if (bytes < (1024 * 1024 * 1024))
|
||||
printf("%6d MB", bytes / 1024 / 1024);
|
||||
|
||||
else
|
||||
printf("%6d GB", bytes / 1024 / 1024 / 1024);
|
||||
}
|
||||
|
||||
off_t getFileSize(const char *fileName)
|
||||
{
|
||||
off_t getFileSize(const char *fileName) {
|
||||
FILE* fp = fopen(fileName, "rb");
|
||||
off_t fsize = 0;
|
||||
if (fp) {
|
||||
@ -69,17 +51,24 @@ off_t getFileSize(const char *fileName)
|
||||
return fsize;
|
||||
}
|
||||
|
||||
bool calculateSHA1(const char *fileName, u8 *sha1)
|
||||
{
|
||||
bool calculateSHA1(const char *fileName, u8 *sha1) {
|
||||
off_t fsize = getFileSize(fileName);
|
||||
u8 *buf = (u8*) malloc(shaChunkSize);
|
||||
if (!buf) {
|
||||
iprintf("Could not allocate buffer\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Could not allocate buffer");
|
||||
font->update(false);
|
||||
for(int i = 0; i < 60 * 2; i++)
|
||||
swiWaitForVBlank();
|
||||
return false;
|
||||
}
|
||||
FILE* fp = fopen(fileName, "rb");
|
||||
if (!fp) {
|
||||
iprintf("Could not open file for reading\n");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Could not open file for reading");
|
||||
font->update(false);
|
||||
for(int i = 0; i < 60 * 2; i++)
|
||||
swiWaitForVBlank();
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
@ -87,6 +76,18 @@ bool calculateSHA1(const char *fileName, u8 *sha1)
|
||||
swiSHA1context_t ctx;
|
||||
ctx.sha_block=0; //this is weird but it has to be done
|
||||
swiSHA1Init(&ctx);
|
||||
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Calculating SHA1 hash of:");
|
||||
font->print(0, 1, false, fileName);
|
||||
|
||||
int nameHeight = font->calcHeight(fileName);
|
||||
font->print(0, nameHeight + 2, false, "(<START> to cancel)");
|
||||
|
||||
font->print(0, nameHeight + 4, false, "Progress:");
|
||||
font->print(0, nameHeight + 5, false, "[");
|
||||
font->print(-1, nameHeight + 5, false, "]");
|
||||
|
||||
while (true) {
|
||||
size_t ret = fread(buf, 1, shaChunkSize, fp);
|
||||
if (!ret) break;
|
||||
@ -94,26 +95,27 @@ bool calculateSHA1(const char *fileName, u8 *sha1)
|
||||
scanKeys();
|
||||
int keys = keysHeld();
|
||||
if (keys & KEY_START) return false;
|
||||
iprintf("\x1b[1;A");
|
||||
iprintf("%ld/%lld bytes processed\n", ftell(fp), fsize);
|
||||
|
||||
font->print((ftell(fp) / (fsize / (SCREEN_COLS - 2))) + 1, nameHeight + 5, false, "=");
|
||||
font->printf(0, nameHeight + 6, false, Alignment::left, Palette::white, "%d/%d bytes processed", ftell(fp), fsize);
|
||||
font->update(false);
|
||||
}
|
||||
swiSHA1Final(sha1, &ctx);
|
||||
free(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void dirCopy(DirEntry* entry, int i, const char *destinationPath, const char *sourcePath) {
|
||||
void dirCopy(const DirEntry &entry, int i, const char *destinationPath, const char *sourcePath) {
|
||||
std::vector<DirEntry> dirContents;
|
||||
dirContents.clear();
|
||||
if (entry->isDirectory) chdir((sourcePath + ("/" + entry->name)).c_str());
|
||||
if (entry.isDirectory) chdir((sourcePath + ("/" + entry.name)).c_str());
|
||||
getDirectoryContents(dirContents);
|
||||
if (((int)dirContents.size()) == 1) mkdir((destinationPath + ("/" + entry->name)).c_str(), 0777);
|
||||
if (((int)dirContents.size()) != 1) fcopy((sourcePath + ("/" + entry->name)).c_str(), (destinationPath + ("/" + entry->name)).c_str());
|
||||
if (((int)dirContents.size()) == 1) mkdir((destinationPath + ("/" + entry.name)).c_str(), 0777);
|
||||
if (((int)dirContents.size()) != 1) fcopy((sourcePath + ("/" + entry.name)).c_str(), (destinationPath + ("/" + entry.name)).c_str());
|
||||
}
|
||||
|
||||
int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
{
|
||||
DIR *isDir = opendir (sourcePath);
|
||||
int fcopy(const char *sourcePath, const char *destinationPath) {
|
||||
DIR *isDir = opendir(sourcePath);
|
||||
|
||||
if (isDir != NULL) {
|
||||
closedir(isDir);
|
||||
@ -122,17 +124,15 @@ int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
chdir(sourcePath);
|
||||
std::vector<DirEntry> dirContents;
|
||||
getDirectoryContents(dirContents);
|
||||
DirEntry* entry = NULL;
|
||||
|
||||
mkdir(destinationPath, 0777);
|
||||
for (int i = 1; i < ((int)dirContents.size()); i++) {
|
||||
chdir(sourcePath);
|
||||
entry = &dirContents.at(i);
|
||||
dirCopy(entry, i, destinationPath, sourcePath);
|
||||
dirCopy(dirContents[i], i, destinationPath, sourcePath);
|
||||
}
|
||||
|
||||
chdir (destinationPath);
|
||||
chdir ("..");
|
||||
chdir(destinationPath);
|
||||
chdir("..");
|
||||
return 1;
|
||||
} else {
|
||||
closedir(isDir);
|
||||
@ -142,26 +142,26 @@ int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
off_t fsize = 0;
|
||||
if (sourceFile) {
|
||||
fseek(sourceFile, 0, SEEK_END);
|
||||
fsize = ftell(sourceFile); // Get source file's size
|
||||
fsize = ftell(sourceFile); // Get source file's size
|
||||
fseek(sourceFile, 0, SEEK_SET);
|
||||
} else {
|
||||
fclose(sourceFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* destinationFile = fopen(destinationPath, "wb");
|
||||
//if (destinationFile) {
|
||||
fseek(destinationFile, 0, SEEK_SET);
|
||||
/*} else {
|
||||
if (!destinationFile) {
|
||||
fclose(sourceFile);
|
||||
fclose(destinationFile);
|
||||
return -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Progress:");
|
||||
font->print(0, 1, false, "[");
|
||||
font->print(-1, 1, false, "]");
|
||||
|
||||
off_t offset = 0;
|
||||
int numr;
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
scanKeys();
|
||||
if (keysHeld() & KEY_B) {
|
||||
// Cancel copying
|
||||
@ -170,18 +170,14 @@ int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf ("\x1b[16;0H");
|
||||
printf ("Progress:\n");
|
||||
printf ("%i/%i Bytes ", (int)offset, (int)fsize);
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
font->print((offset / (fsize / (SCREEN_COLS - 2))) + 1, 1, false, "=");
|
||||
font->printf(0, 2, false, Alignment::left, Palette::white, "%lld/%lld Bytes", offset, fsize);
|
||||
font->update(false);
|
||||
|
||||
// Copy file to destination path
|
||||
numr = fread(copyBuf, 1, copyBufSize, sourceFile);
|
||||
@ -192,10 +188,6 @@ int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
fclose(sourceFile);
|
||||
fclose(destinationFile);
|
||||
|
||||
printf ("\x1b[17;0H");
|
||||
printf ("%i/%i Bytes ", (int)fsize, (int)fsize);
|
||||
for (int i = 0; i < 30; i++) swiWaitForVBlank();
|
||||
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
@ -205,62 +197,29 @@ int fcopy(const char *sourcePath, const char *destinationPath)
|
||||
}
|
||||
}
|
||||
|
||||
void changeFileAttribs(DirEntry* entry) {
|
||||
consoleClear();
|
||||
void changeFileAttribs(const DirEntry *entry) {
|
||||
int pressed = 0;
|
||||
int cursorScreenPos = 0;
|
||||
int cursorScreenPos = font->calcHeight(entry->name);
|
||||
uint8_t currentAttribs = FAT_getAttr(entry->name.c_str());
|
||||
uint8_t newAttribs = currentAttribs;
|
||||
|
||||
// Position cursor, depending on how long the file name is
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (i == 33 || i == 65 || i == 97 || i == 129 || i == 161 || i == 193 || i == 225) {
|
||||
cursorScreenPos++;
|
||||
}
|
||||
if (entry->name.c_str()[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\x1b[0;0H");
|
||||
printf (entry->name.c_str());
|
||||
if (!entry->isDirectory) {
|
||||
printf ("\x1b[%i;0H", 3+cursorScreenPos);
|
||||
printf ("filesize: ");
|
||||
printBytes(entry->size);
|
||||
}
|
||||
printf ("\x1b[%i;0H", 5+cursorScreenPos);
|
||||
printf ("[ ] U read-only [ ] D hidden");
|
||||
printf ("\x1b[%i;0H", 6+cursorScreenPos);
|
||||
printf ("[ ] R system [ ] L archive");
|
||||
printf ("\x1b[%i;0H", 7+cursorScreenPos);
|
||||
printf ("[ ] virtual");
|
||||
printf ("\x1b[%i;1H", 7+cursorScreenPos);
|
||||
printf ((newAttribs & ATTR_VOLUME) ? "X" : " ");
|
||||
printf ("\x1b[%i;0H", 9+cursorScreenPos);
|
||||
printf ("(UDRL to change attributes)");
|
||||
while (1) {
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf ("\x1b[%i;1H", 5+cursorScreenPos);
|
||||
printf ((newAttribs & ATTR_READONLY) ? "X" : " ");
|
||||
printf ("\x1b[%i;18H", 5+cursorScreenPos);
|
||||
printf ((newAttribs & ATTR_HIDDEN) ? "X" : " ");
|
||||
printf ("\x1b[%i;1H", 6+cursorScreenPos);
|
||||
printf ((newAttribs & ATTR_SYSTEM) ? "X" : " ");
|
||||
printf ("\x1b[%i;18H", 6+cursorScreenPos);
|
||||
printf ((newAttribs & ATTR_ARCHIVE) ? "X" : " ");
|
||||
printf ("\x1b[%i;0H", 11+cursorScreenPos);
|
||||
printf ((currentAttribs==newAttribs) ? "(<A> to continue) " : "(<A> to apply, <B> to cancel)");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, entry->name);
|
||||
if (!entry->isDirectory)
|
||||
font->printf(0, cursorScreenPos + 1, false, Alignment::left, Palette::white, "filesize: %s", getBytes(entry->size).c_str());
|
||||
font->printf(0, cursorScreenPos + 3, false, Alignment::left, Palette::white, "[%c] ↑ read-only [%c] ↓ hidden", (newAttribs & ATTR_READONLY) ? 'X' : ' ', (newAttribs & ATTR_HIDDEN) ? 'X' : ' ');
|
||||
font->printf(0, cursorScreenPos + 4, false, Alignment::left, Palette::white, "[%c] → system [%c] ← archive", (newAttribs & ATTR_SYSTEM) ? 'X' : ' ', (newAttribs & ATTR_ARCHIVE) ? 'X' : ' ');
|
||||
font->printf(0, cursorScreenPos + 5, false, Alignment::left, Palette::white, "[%c] virtual", (newAttribs & ATTR_VOLUME) ? 'X' : ' ');
|
||||
font->printf(0, cursorScreenPos + 6, false, Alignment::left, Palette::white, "(↑↓→← to change attributes)");
|
||||
font->print(0, cursorScreenPos + 8, false, (currentAttribs == newAttribs) ? "(<A> to continue)" : "(<A> to apply, <B> to cancel)");
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
@ -269,43 +228,17 @@ void changeFileAttribs(DirEntry* entry) {
|
||||
&& !(pressed & KEY_A) && !(pressed & KEY_B));
|
||||
|
||||
if (pressed & KEY_UP) {
|
||||
if (newAttribs & ATTR_READONLY) {
|
||||
newAttribs -= ATTR_READONLY;
|
||||
} else {
|
||||
newAttribs += ATTR_READONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressed & KEY_DOWN) {
|
||||
if (newAttribs & ATTR_HIDDEN) {
|
||||
newAttribs -= ATTR_HIDDEN;
|
||||
} else {
|
||||
newAttribs += ATTR_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressed & KEY_RIGHT) {
|
||||
if (newAttribs & ATTR_SYSTEM) {
|
||||
newAttribs -= ATTR_SYSTEM;
|
||||
} else {
|
||||
newAttribs += ATTR_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (pressed & KEY_LEFT) {
|
||||
if (newAttribs & ATTR_ARCHIVE) {
|
||||
newAttribs -= ATTR_ARCHIVE;
|
||||
} else {
|
||||
newAttribs += ATTR_ARCHIVE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pressed & KEY_A) && (currentAttribs!=newAttribs)) {
|
||||
newAttribs ^= ATTR_READONLY;
|
||||
} else if (pressed & KEY_DOWN) {
|
||||
newAttribs ^= ATTR_HIDDEN;
|
||||
} else if (pressed & KEY_RIGHT) {
|
||||
newAttribs ^= ATTR_SYSTEM;
|
||||
} else if (pressed & KEY_LEFT) {
|
||||
newAttribs ^= ATTR_ARCHIVE;
|
||||
} else if ((pressed & KEY_A) && (currentAttribs != newAttribs)) {
|
||||
FAT_setAttr(entry->name.c_str(), newAttribs);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pressed & KEY_A) || (pressed & KEY_B)) {
|
||||
} else if (pressed & (KEY_A | KEY_B)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,11 @@ extern std::vector<ClipboardFile> clipboard;
|
||||
extern bool clipboardOn;
|
||||
extern bool clipboardUsed;
|
||||
|
||||
extern void printBytes(int bytes);
|
||||
extern void printBytesAlign(int bytes);
|
||||
extern std::string getBytes(int bytes);
|
||||
|
||||
extern off_t getFileSize(const char *fileName);
|
||||
extern bool calculateSHA1(const char *fileName, u8 *sha1);
|
||||
extern int fcopy(const char *sourcePath, const char *destinationPath);
|
||||
void changeFileAttribs(DirEntry* entry);
|
||||
void changeFileAttribs(const DirEntry *entry);
|
||||
|
||||
#endif // FILE_COPY
|
||||
|
@ -38,24 +38,16 @@
|
||||
#include "driveMenu.h"
|
||||
#include "driveOperations.h"
|
||||
#include "dumpOperations.h"
|
||||
#include "font.h"
|
||||
#include "hexEditor.h"
|
||||
#include "ndsInfo.h"
|
||||
#include "nitrofs.h"
|
||||
#include "inifile.h"
|
||||
#include "nds_loader_arm9.h"
|
||||
|
||||
#define SCREEN_COLS 22
|
||||
#define ENTRIES_PER_SCREEN 23
|
||||
#define ENTRIES_START_ROW 1
|
||||
#define OPTIONS_ENTRIES_START_ROW 2
|
||||
#define ENTRY_PAGE_LENGTH 10
|
||||
extern PrintConsole topConsole, bottomConsole;
|
||||
|
||||
extern void printBorderTop(void);
|
||||
extern void printBorderBottom(void);
|
||||
extern void clearBorderTop(void);
|
||||
extern void clearBorderBottom(void);
|
||||
extern void reinitConsoles(void);
|
||||
|
||||
static char path[PATH_MAX];
|
||||
|
||||
@ -84,7 +76,7 @@ bool dirEntryPredicate (const DirEntry& lhs, const DirEntry& rhs) {
|
||||
return strcasecmp(lhs.name.c_str(), rhs.name.c_str()) < 0;
|
||||
}
|
||||
|
||||
void getDirectoryContents (std::vector<DirEntry>& dirContents) {
|
||||
void getDirectoryContents(std::vector<DirEntry>& dirContents) {
|
||||
struct stat st;
|
||||
|
||||
dirContents.clear();
|
||||
@ -92,7 +84,8 @@ void getDirectoryContents (std::vector<DirEntry>& dirContents) {
|
||||
DIR *pdir = opendir (".");
|
||||
|
||||
if (pdir == NULL) {
|
||||
iprintf ("Unable to open the directory.\n");
|
||||
font->print(0, 0, true, "Unable to open the directory.");
|
||||
font->update(true);
|
||||
} else {
|
||||
|
||||
while(true) {
|
||||
@ -138,145 +131,150 @@ void getDirectoryContents (std::vector<DirEntry>& dirContents) {
|
||||
void showDirectoryContents (const std::vector<DirEntry>& dirContents, int fileOffset, int startRow) {
|
||||
getcwd(path, PATH_MAX);
|
||||
|
||||
consoleClear();
|
||||
font->clear(true);
|
||||
|
||||
// Top bar
|
||||
font->printf(0, 0, true, Alignment::left, Palette::blackGreen, "%*c", 256 / font->width(), ' ');
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
|
||||
// Print the path
|
||||
printf ("\x1B[30m"); // Print black color
|
||||
// Print time
|
||||
printf ("\x1b[0;27H");
|
||||
printf (RetTime().c_str());
|
||||
|
||||
printf ("\x1b[0;0H");
|
||||
if (strlen(path) < SCREEN_COLS) {
|
||||
iprintf ("%s", path);
|
||||
} else {
|
||||
iprintf ("%s", path + strlen(path) - SCREEN_COLS);
|
||||
}
|
||||
|
||||
// Move to 2nd row
|
||||
iprintf ("\x1b[1;0H");
|
||||
if(font->calcWidth(path) > SCREEN_COLS - 6)
|
||||
font->print(-6 - 1, 0, true, path, Alignment::right, Palette::blackGreen);
|
||||
else
|
||||
font->print(0, 0, true, path, Alignment::left, Palette::blackGreen);
|
||||
|
||||
// Print directory listing
|
||||
for (int i = 0; i < ((int)dirContents.size() - startRow) && i < ENTRIES_PER_SCREEN; i++) {
|
||||
const DirEntry* entry = &dirContents.at(i + startRow);
|
||||
const DirEntry *entry = &dirContents[i + startRow];
|
||||
|
||||
// Set row
|
||||
iprintf ("\x1b[%d;0H", i + ENTRIES_START_ROW);
|
||||
Palette pal;
|
||||
if ((fileOffset - startRow) == i) {
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
pal = Palette::white;
|
||||
} else if (entry->selected) {
|
||||
printf ("\x1B[33m"); // Print custom yellow color
|
||||
pal = Palette::yellow;
|
||||
} else if (entry->isDirectory) {
|
||||
printf ("\x1B[37m"); // Print custom blue color
|
||||
pal = Palette::blue;
|
||||
} else {
|
||||
printf ("\x1B[40m"); // Print foreground black color
|
||||
pal = Palette::gray;
|
||||
}
|
||||
|
||||
printf ("%.*s", SCREEN_COLS, entry->name.c_str());
|
||||
font->print(0, i + 1, true, entry->name, Alignment::left, pal);
|
||||
if (entry->name == "..") {
|
||||
printf ("\x1b[%d;28H", i + ENTRIES_START_ROW);
|
||||
printf ("(..)");
|
||||
font->print(-1, i + 1, true, "(..)", Alignment::right, pal);
|
||||
} else if (entry->isDirectory) {
|
||||
printf ("\x1b[%d;27H", i + ENTRIES_START_ROW);
|
||||
printf ("(dir)");
|
||||
font->print(-1, i + 1, true, "(dir)", Alignment::right, pal);
|
||||
} else {
|
||||
printf ("\x1b[%d;23H", i + ENTRIES_START_ROW);
|
||||
printBytesAlign((int)entry->size);
|
||||
font->printf(-1, i + 1, true, Alignment::right, pal, "(%s)", getBytes(entry->size).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
font->update(true);
|
||||
}
|
||||
|
||||
FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
int pressed = 0;
|
||||
FileOperation assignedOp[4] = {FileOperation::none};
|
||||
std::vector<FileOperation> operations;
|
||||
int optionOffset = 0;
|
||||
int cursorScreenPos = 0;
|
||||
int maxCursors = -1;
|
||||
std::string fullPath = path + entry->name;
|
||||
int y = font->calcHeight(fullPath) + 1;
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
char fullPath[256];
|
||||
snprintf(fullPath, sizeof(fullPath), "%s%s", path, entry->name.c_str());
|
||||
printf(fullPath);
|
||||
// Position cursor, depending on how long the full file path is
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (i == 33 || i == 65 || i == 97 || i == 129 || i == 161 || i == 193 || i == 225) {
|
||||
cursorScreenPos++;
|
||||
}
|
||||
if (fullPath[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
iprintf ("\x1b[%d;0H", cursorScreenPos + OPTIONS_ENTRIES_START_ROW);
|
||||
if (!entry->isDirectory) {
|
||||
if (entry->isApp) {
|
||||
assignedOp[++maxCursors] = FileOperation::bootFile;
|
||||
if (extension(entry->name, {"firm"})) {
|
||||
printf(" Boot file\n");
|
||||
} else {
|
||||
printf(" Boot file (Direct)\n");
|
||||
assignedOp[++maxCursors] = FileOperation::bootstrapFile;
|
||||
printf(" Bootstrap file\n");
|
||||
operations.push_back(FileOperation::bootFile);
|
||||
if (!extension(entry->name, {"firm"})) {
|
||||
operations.push_back(FileOperation::bootstrapFile);
|
||||
}
|
||||
}
|
||||
if(extension(entry->name, {"nds", "dsi", "ids", "app"}))
|
||||
{
|
||||
assignedOp[++maxCursors] = FileOperation::mountNitroFS;
|
||||
printf(" Mount NitroFS\n");
|
||||
assignedOp[++maxCursors] = FileOperation::ndsInfo;
|
||||
printf(" Show NDS file info\n");
|
||||
}
|
||||
else if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"}))
|
||||
{
|
||||
assignedOp[++maxCursors] = FileOperation::restoreSave;
|
||||
printf(" Restore save\n");
|
||||
}
|
||||
else if(extension(entry->name, {"img", "sd"}))
|
||||
{
|
||||
assignedOp[++maxCursors] = FileOperation::mountImg;
|
||||
printf(" Mount as FAT image\n");
|
||||
}
|
||||
assignedOp[++maxCursors] = FileOperation::hexEdit;
|
||||
printf(" Open in hex editor\n");
|
||||
}
|
||||
assignedOp[++maxCursors] = FileOperation::showInfo;
|
||||
printf(entry->isDirectory ? " Show directory info\n" : " Show file info\n");
|
||||
if (sdMounted && (strcmp(path, "sd:/gm9i/out/") != 0)) {
|
||||
assignedOp[++maxCursors] = FileOperation::copySdOut;
|
||||
printf(" Copy to sd:/gm9i/out\n");
|
||||
}
|
||||
if (flashcardMounted && (strcmp(path, "fat:/gm9i/out/") != 0)) {
|
||||
assignedOp[++maxCursors] = FileOperation::copyFatOut;
|
||||
printf(" Copy to fat:/gm9i/out\n");
|
||||
}
|
||||
// The bios SHA1 functions are only available on the DSi
|
||||
// https://problemkaputt.de/gbatek.htm#biossha1functionsdsionly
|
||||
if (isDSiMode()) {
|
||||
assignedOp[++maxCursors] = FileOperation::calculateSHA1;
|
||||
printf(" Calculate SHA1 hash\n");
|
||||
}
|
||||
printf("\n(<A> select, <B> cancel)");
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
while (true) {
|
||||
// Clear old cursors
|
||||
for (int i = OPTIONS_ENTRIES_START_ROW+cursorScreenPos; i < (maxCursors+1) + OPTIONS_ENTRIES_START_ROW+cursorScreenPos; i++) {
|
||||
iprintf ("\x1b[%d;0H ", i);
|
||||
}
|
||||
// Show cursor
|
||||
iprintf ("\x1b[%d;0H->", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
if(extension(entry->name, {"nds", "dsi", "ids", "app"})) {
|
||||
operations.push_back(FileOperation::mountNitroFS);
|
||||
operations.push_back(FileOperation::ndsInfo);
|
||||
} else if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) {
|
||||
operations.push_back(FileOperation::restoreSave);
|
||||
} else if(extension(entry->name, {"img", "sd"})) {
|
||||
operations.push_back(FileOperation::mountImg);
|
||||
}
|
||||
|
||||
operations.push_back(FileOperation::hexEdit);
|
||||
|
||||
// The bios SHA1 functions are only available on the DSi
|
||||
// https://problemkaputt.de/gbatek.htm#biossha1functionsdsionly
|
||||
if (isDSiMode()) {
|
||||
operations.push_back(FileOperation::calculateSHA1);
|
||||
}
|
||||
}
|
||||
|
||||
operations.push_back(FileOperation::showInfo);
|
||||
|
||||
if (sdMounted && (strcmp(path, "sd:/gm9i/out/") != 0)) {
|
||||
operations.push_back(FileOperation::copySdOut);
|
||||
}
|
||||
|
||||
if (flashcardMounted && (strcmp(path, "fat:/gm9i/out/") != 0)) {
|
||||
operations.push_back(FileOperation::copyFatOut);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
font->clear(false);
|
||||
|
||||
font->print(0, 0, false, fullPath);
|
||||
|
||||
int row = y;
|
||||
for(FileOperation operation : operations) {
|
||||
switch(operation) {
|
||||
case FileOperation::bootFile:
|
||||
font->print(3, row++, false, extension(entry->name, {"firm"}) ? "Boot file" : "Boot file (Direct)");
|
||||
break;
|
||||
case FileOperation::bootstrapFile:
|
||||
font->print(3, row++, false, "Bootstrap file");
|
||||
break;
|
||||
case FileOperation::mountNitroFS:
|
||||
font->print(3, row++, false, "Mount NitroFS");
|
||||
break;
|
||||
case FileOperation::ndsInfo:
|
||||
font->print(3, row++, false, "Show NDS file info");
|
||||
break;
|
||||
case FileOperation::restoreSave:
|
||||
font->print(3, row++, false, "Restore save");
|
||||
break;
|
||||
case FileOperation::mountImg:
|
||||
font->print(3, row++, false, "Mount as FAT image");
|
||||
break;
|
||||
case FileOperation::hexEdit:
|
||||
font->print(3, row++, false, "Open in hex editor");
|
||||
break;
|
||||
case FileOperation::showInfo:
|
||||
font->print(3, row++, false, entry->isDirectory ? "Show directory info" : "Show file info");
|
||||
break;
|
||||
case FileOperation::copySdOut:
|
||||
font->print(3, row++, false, "Copy to sd:/gm9i/out");
|
||||
break;
|
||||
case FileOperation::copyFatOut:
|
||||
font->print(3, row++, false, "Copy to fat:/gm9i/out");
|
||||
break;
|
||||
case FileOperation::calculateSHA1:
|
||||
font->print(3, row++, false, "Calculate SHA1 hash");
|
||||
break;
|
||||
case FileOperation::none:
|
||||
row++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
font->print(3, ++row, false, "(<A> select, <B> cancel)");
|
||||
|
||||
// Show cursor
|
||||
font->print(0, y + optionOffset, false, "->");
|
||||
|
||||
font->update(false);
|
||||
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -288,26 +286,26 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
#endif
|
||||
);
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
|
||||
if (pressed & KEY_UP) optionOffset -= 1;
|
||||
if (pressed & KEY_DOWN) optionOffset += 1;
|
||||
|
||||
if (optionOffset < 0) optionOffset = maxCursors; // Wrap around to bottom of list
|
||||
if (optionOffset > maxCursors) optionOffset = 0; // Wrap around to top of list
|
||||
if (optionOffset < 0) // Wrap around to bottom of list
|
||||
optionOffset = operations.size() - 1;
|
||||
|
||||
if (optionOffset >= (int)operations.size()) // Wrap around to top of list
|
||||
optionOffset = 0;
|
||||
|
||||
if (pressed & KEY_A) {
|
||||
switch(assignedOp[optionOffset]) {
|
||||
switch(operations[optionOffset]) {
|
||||
case FileOperation::bootFile: {
|
||||
applaunch = true;
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Now loading...");
|
||||
font->print(3, optionOffset + y, false, "Now loading...");
|
||||
font->update(false);
|
||||
break;
|
||||
} case FileOperation::bootstrapFile: {
|
||||
char baseFile[256], savePath[PATH_MAX]; //, bootstrapConfigPath[32];
|
||||
//snprintf(bootstrapConfigPath, 32, "%s:/_nds/nds-bootstrap.ini", isDSiMode() ? "sd" : "fat");
|
||||
strncpy(baseFile, entry->name.c_str(), 256);
|
||||
strncpy(baseFile, entry->name.c_str(), 255);
|
||||
*strrchr(baseFile, '.') = 0;
|
||||
snprintf(savePath, PATH_MAX, "%s%s%s.sav", path, !access("saves", F_OK) ? "saves/" : "", baseFile);
|
||||
CIniFile bootstrapConfig("/_nds/nds-bootstrap.ini");
|
||||
@ -327,19 +325,19 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
break;
|
||||
} case FileOperation::copySdOut: {
|
||||
if (access("sd:/gm9i", F_OK) != 0) {
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Creating directory...");
|
||||
font->print(3, optionOffset + y, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("sd:/gm9i", 0777);
|
||||
}
|
||||
if (access("sd:/gm9i/out", F_OK) != 0) {
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Creating directory...");
|
||||
font->print(3, optionOffset + y, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("sd:/gm9i/out", 0777);
|
||||
}
|
||||
char destPath[256];
|
||||
snprintf(destPath, sizeof(destPath), "sd:/gm9i/out/%s", entry->name.c_str());
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Copying... ");
|
||||
font->print(3, optionOffset + y, false, "Copying...");
|
||||
font->update(false);
|
||||
remove(destPath);
|
||||
char sourceFolder[PATH_MAX];
|
||||
getcwd(sourceFolder, PATH_MAX);
|
||||
@ -350,19 +348,19 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
break;
|
||||
} case FileOperation::copyFatOut: {
|
||||
if (access("fat:/gm9i", F_OK) != 0) {
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Creating directory...");
|
||||
font->print(3, optionOffset + y, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("fat:/gm9i", 0777);
|
||||
}
|
||||
if (access("fat:/gm9i/out", F_OK) != 0) {
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Creating directory...");
|
||||
font->print(3, optionOffset + y, false, "Creating directory...");
|
||||
font->update(false);
|
||||
mkdir("fat:/gm9i/out", 0777);
|
||||
}
|
||||
char destPath[256];
|
||||
snprintf(destPath, sizeof(destPath), "fat:/gm9i/out/%s", entry->name.c_str());
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
|
||||
printf("Copying... ");
|
||||
font->print(3, (optionOffset + y), false, "Copying...");
|
||||
font->update(false);
|
||||
remove(destPath);
|
||||
char sourceFolder[PATH_MAX];
|
||||
getcwd(sourceFolder, PATH_MAX);
|
||||
@ -397,23 +395,27 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
hexEditor(entry->name.c_str(), currentDrive);
|
||||
break;
|
||||
} case FileOperation::calculateSHA1: {
|
||||
iprintf("\x1b[2J");
|
||||
iprintf("Calculating SHA1 hash of:\n%s\n", entry->name.c_str());
|
||||
iprintf("Press <START> to cancel\n\n");
|
||||
u8 sha1[20] = {0};
|
||||
bool ret = calculateSHA1(strcat(getcwd(path, PATH_MAX), entry->name.c_str()), sha1);
|
||||
if (!ret) break;
|
||||
iprintf("SHA1 hash is: \n");
|
||||
for (int i = 0; i < 20; ++i) iprintf("%02X", sha1[i]);
|
||||
consoleSelect(&topConsole);
|
||||
iprintf ("\x1B[30m"); // Print black color
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "SHA1 hash is:");
|
||||
char sha1Str[41];
|
||||
for (int i = 0; i < 20; ++i)
|
||||
sniprintf(sha1Str + i * 2, 3, "%02X", sha1[i]);
|
||||
font->print(0, 1, false, sha1Str);
|
||||
font->print(0, font->calcHeight(sha1Str) + 2, false, "(<A> to continue)");
|
||||
font->update(false);
|
||||
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
int pressed;
|
||||
do {
|
||||
// Move to right side of screen
|
||||
iprintf ("\x1b[0;26H");
|
||||
// Print time
|
||||
iprintf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
swiWaitForVBlank();
|
||||
@ -423,7 +425,7 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return assignedOp[optionOffset];
|
||||
return operations[optionOffset];
|
||||
}
|
||||
if (pressed & KEY_B) {
|
||||
return FileOperation::none;
|
||||
@ -441,43 +443,33 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
||||
bool fileBrowse_paste(char dest[256]) {
|
||||
int pressed = 0;
|
||||
int optionOffset = 0;
|
||||
int maxCursors = -1;
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf("Paste clipboard here?");
|
||||
printf("\n\n");
|
||||
iprintf ("\x1b[%d;0H", OPTIONS_ENTRIES_START_ROW);
|
||||
maxCursors++;
|
||||
printf(" Copy files\n");
|
||||
for (auto &file : clipboard) {
|
||||
if (file.nitro)
|
||||
continue;
|
||||
maxCursors++;
|
||||
printf(" Move files\n");
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
printf("(<A> select, <B> cancel)");
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
while (true) {
|
||||
// Clear old cursors
|
||||
for (int i = OPTIONS_ENTRIES_START_ROW; i < (maxCursors+1) + OPTIONS_ENTRIES_START_ROW; i++) {
|
||||
iprintf ("\x1b[%d;0H ", i);
|
||||
}
|
||||
// Show cursor
|
||||
iprintf ("\x1b[%d;0H->", optionOffset + OPTIONS_ENTRIES_START_ROW);
|
||||
font->clear(false);
|
||||
|
||||
font->print(0, 0, false, "Paste clipboard here?");
|
||||
|
||||
int row = OPTIONS_ENTRIES_START_ROW, maxCursors = 0;
|
||||
font->print(3, row++, false, "Copy files");
|
||||
for (auto &file : clipboard) {
|
||||
if (file.nitro)
|
||||
continue;
|
||||
maxCursors++;
|
||||
font->print(3, row++, false, "Move files");
|
||||
break;
|
||||
}
|
||||
font->print(3, ++row, false, "(<A> select, <B> cancel)");
|
||||
|
||||
// Show cursor
|
||||
font->print(0, optionOffset + OPTIONS_ENTRIES_START_ROW, false, "->");
|
||||
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -489,10 +481,6 @@ bool fileBrowse_paste(char dest[256]) {
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
|
||||
if (pressed & KEY_UP) optionOffset -= 1;
|
||||
if (pressed & KEY_DOWN) optionOffset += 1;
|
||||
|
||||
@ -500,8 +488,7 @@ bool fileBrowse_paste(char dest[256]) {
|
||||
if (optionOffset > maxCursors) optionOffset = 0; // Wrap around to top of list
|
||||
|
||||
if (pressed & KEY_A) {
|
||||
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW);
|
||||
printf(optionOffset ? "Moving... " : "Copying...");
|
||||
font->print(3, optionOffset + OPTIONS_ENTRIES_START_ROW, false, optionOffset ? "Moving... " : "Copying...");
|
||||
for (auto &file : clipboard) {
|
||||
std::string destPath = dest + file.name;
|
||||
if (file.path == destPath)
|
||||
@ -537,14 +524,14 @@ bool fileBrowse_paste(char dest[256]) {
|
||||
}
|
||||
|
||||
void recRemove(const char *path, std::vector<DirEntry> dirContents) {
|
||||
DirEntry *entry = NULL;
|
||||
chdir (path);
|
||||
getDirectoryContents(dirContents);
|
||||
for (int i = 1; i < ((int)dirContents.size()); i++) {
|
||||
entry = &dirContents.at(i);
|
||||
if (entry->isDirectory) recRemove(entry->name.c_str(), dirContents);
|
||||
if (!(FAT_getAttr(entry->name.c_str()) & ATTR_READONLY)) {
|
||||
remove(entry->name.c_str());
|
||||
DirEntry &entry = dirContents[i];
|
||||
if (entry.isDirectory)
|
||||
recRemove(entry.name.c_str(), dirContents);
|
||||
if (!(FAT_getAttr(entry.name.c_str()) & ATTR_READONLY)) {
|
||||
remove(entry.name.c_str());
|
||||
}
|
||||
}
|
||||
chdir ("..");
|
||||
@ -552,51 +539,52 @@ void recRemove(const char *path, std::vector<DirEntry> dirContents) {
|
||||
}
|
||||
|
||||
void fileBrowse_drawBottomScreen(DirEntry* entry) {
|
||||
consoleClear();
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf ("\x1b[22;0H");
|
||||
printf ("%s\n", titleName);
|
||||
printf ("X - DELETE/[+R] RENAME file\n");
|
||||
printf ("L - %s files (with \x18\x19\x1A\x1B)\n", entry->selected ? "DESELECT" : "SELECT");
|
||||
printf ("Y - %s file/[+R] CREATE entry%s", clipboardOn ? "PASTE" : "COPY", clipboardOn ? "" : "\n");
|
||||
printf ("R+A - Directory options\n");
|
||||
if (sdMounted || flashcardMounted) {
|
||||
printf ("%s\n", SCREENSHOTTEXT);
|
||||
}
|
||||
printf ("%s\n", clipboardOn ? "SELECT - Clear Clipboard" : "SELECT - Restore Clipboard");
|
||||
font->clear(false);
|
||||
|
||||
int row = -1;
|
||||
|
||||
if (!isDSiMode() && isRegularDS) {
|
||||
printf (POWERTEXT_DS);
|
||||
font->print(0, row--, false, POWERTEXT_DS);
|
||||
} else if (is3DS) {
|
||||
printf ("%s\n%s", POWERTEXT_3DS, HOMETEXT);
|
||||
font->print(0, row--, false, HOMETEXT);
|
||||
font->print(0, row--, false, POWERTEXT_3DS);
|
||||
} else {
|
||||
printf (POWERTEXT);
|
||||
font->print(0, row--, false, POWERTEXT);
|
||||
}
|
||||
printf (entry->selected ? "\x1B[33m" : (entry->isDirectory ? "\x1B[37m" : "\x1B[40m")); // Print custom blue color or foreground black color
|
||||
printf ("\x1b[0;0H");
|
||||
printf ("%s\n", entry->name.c_str());
|
||||
font->print(0, row--, false, clipboardOn ? "SELECT - Clear Clipboard" : "SELECT - Restore Clipboard");
|
||||
if (sdMounted || flashcardMounted) {
|
||||
font->print(0, row--, false, SCREENSHOTTEXT);
|
||||
}
|
||||
font->print(0, row--, false, "R+A - Directory options\n");
|
||||
font->printf(0, row--, false, Alignment::left, Palette::white, "Y - %s file/[+R] CREATE entry", clipboardOn ? "PASTE" : "COPY");
|
||||
font->printf(0, row--, false, Alignment::left, Palette::white, "L - %s files (with ↑↓→←)\n", entry->selected ? "DESELECT" : "SELECT");
|
||||
font->print(0, row--, false, "X - DELETE/[+R] RENAME file\n");
|
||||
font->print(0, row--, false, titleName);
|
||||
|
||||
Palette pal = entry->selected ? Palette::yellow : (entry->isDirectory ? Palette::blue : Palette::gray);
|
||||
font->print(0, 0, false, entry->name, Alignment::left, pal);
|
||||
if (entry->name != "..") {
|
||||
if (entry->isDirectory) {
|
||||
printf ("(dir)");
|
||||
font->print(0, font->calcHeight(entry->name), false, "(dir)", Alignment::left, pal);
|
||||
} else if (entry->size == 1) {
|
||||
printf ("%i Byte", (int)entry->size);
|
||||
font->printf(0, font->calcHeight(entry->name), false, Alignment::left, pal, "%i Byte", entry->size);
|
||||
} else {
|
||||
printf ("%i Bytes", (int)entry->size);
|
||||
font->printf(0, font->calcHeight(entry->name), false, Alignment::left, pal, "%i Bytes", entry->size);
|
||||
}
|
||||
}
|
||||
if (clipboardOn) {
|
||||
printf ("\x1b[9;0H");
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
printf ("[CLIPBOARD]\n");
|
||||
font->print(0, 6, false, "[CLIPBOARD]");
|
||||
for (size_t i = 0; i < clipboard.size(); ++i) {
|
||||
printf (clipboard[i].folder ? "\x1B[37m" : "\x1B[40m"); // Print custom blue color or foreground black color
|
||||
if (i < 4) {
|
||||
printf ("%s\n", clipboard[i].name.c_str());
|
||||
font->print(0, 7 + i, false, clipboard[i].name, Alignment::left, clipboard[i].folder ? Palette::blue : Palette::gray);
|
||||
} else {
|
||||
printf ("%d more files...\n", clipboard.size() - 4);
|
||||
font->printf(0, 7 + i, false, Alignment::left, Palette::gray, "%d more files...", clipboard.size() - 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font->update(false);
|
||||
}
|
||||
|
||||
std::string browseForFile (void) {
|
||||
@ -609,23 +597,18 @@ std::string browseForFile (void) {
|
||||
getDirectoryContents (dirContents);
|
||||
|
||||
while (true) {
|
||||
DirEntry* entry = &dirContents.at(fileOffset);
|
||||
DirEntry* entry = &dirContents[fileOffset];
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
fileBrowse_drawBottomScreen(entry);
|
||||
consoleSelect(&topConsole);
|
||||
showDirectoryContents (dirContents, fileOffset, screenOffset);
|
||||
showDirectoryContents(dirContents, fileOffset, screenOffset);
|
||||
|
||||
stored_SCFG_MC = REG_SCFG_MC;
|
||||
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
|
||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -639,16 +622,7 @@ std::string browseForFile (void) {
|
||||
if ((held & KEY_R) && (pressed & KEY_L)) {
|
||||
break;
|
||||
}
|
||||
} while (!(pressed & KEY_UP) && !(pressed & KEY_DOWN) && !(pressed & KEY_LEFT) && !(pressed & KEY_RIGHT)
|
||||
&& !(pressed & KEY_A) && !(pressed & KEY_B) && !(pressed & KEY_X) && !(pressed & KEY_Y)
|
||||
&& !(pressed & KEY_L) && !(pressed & KEY_SELECT)
|
||||
#ifdef SCREENSWAP
|
||||
&& !(pressed & KEY_TOUCH)
|
||||
#endif
|
||||
);
|
||||
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
iprintf ("\x1b[%d;0H", fileOffset - screenOffset + ENTRIES_START_ROW);
|
||||
} while (!pressed);
|
||||
|
||||
if (isDSiMode() && !pressed && currentDrive == 1 && REG_SCFG_MC == 0x11 && flashcardMounted) {
|
||||
flashcardUnmount();
|
||||
@ -692,10 +666,11 @@ std::string browseForFile (void) {
|
||||
screenMode = 0;
|
||||
return "null";
|
||||
} else if (entry->isDirectory) {
|
||||
iprintf("Entering directory ");
|
||||
font->printf(0, fileOffset - screenOffset + ENTRIES_START_ROW, true, Alignment::left, Palette::white, "%-*s", SCREEN_COLS - 5, "Entering directory");
|
||||
font->update(true);
|
||||
// Enter selected directory
|
||||
chdir (entry->name.c_str());
|
||||
getDirectoryContents (dirContents);
|
||||
getDirectoryContents(dirContents);
|
||||
screenOffset = 0;
|
||||
fileOffset = 0;
|
||||
} else {
|
||||
@ -748,8 +723,10 @@ std::string browseForFile (void) {
|
||||
|
||||
// Rename file/folder
|
||||
if ((held & KEY_R) && (pressed & KEY_X) && (entry->name != ".." && strncmp(path, "nitro:/", 7) != 0)) {
|
||||
printf ("\x1b[0;27H");
|
||||
printf (" "); // Clear time
|
||||
// Clear time
|
||||
font->print(-1, 0, true, " ", Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
pressed = 0;
|
||||
consoleDemoInit();
|
||||
Keyboard *kbd = keyboardDemoInit();
|
||||
@ -757,13 +734,13 @@ std::string browseForFile (void) {
|
||||
kbd->OnKeyPressed = OnKeyPressed;
|
||||
|
||||
keyboardShow();
|
||||
printf("Rename to: \n");
|
||||
iprintf("Rename to:\n");
|
||||
fgets(newName, 256, stdin);
|
||||
newName[strlen(newName)-1] = 0;
|
||||
keyboardHide();
|
||||
consoleClear();
|
||||
|
||||
reinitConsoles();
|
||||
videoSetModeSub(MODE_5_2D);
|
||||
bgShow(bgInitSub(2, BgType_Bmp8, BgSize_B8_256x256, 3, 0));
|
||||
|
||||
if (newName[0] != '\0') {
|
||||
// Check for unsupported characters
|
||||
@ -782,49 +759,44 @@ std::string browseForFile (void) {
|
||||
}
|
||||
}
|
||||
if (rename(entry->name.c_str(), newName) == 0) {
|
||||
getDirectoryContents (dirContents);
|
||||
getDirectoryContents(dirContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete action
|
||||
if ((pressed & KEY_X) && (entry->name != ".." && strncmp(path, "nitro:/", 7) != 0)) {
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
font->clear(false);
|
||||
int selections = std::count_if(dirContents.begin(), dirContents.end(), [](const DirEntry &x){ return x.selected; });
|
||||
if (entry->selected && selections > 1) {
|
||||
iprintf("Delete %d paths?\n", selections);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Delete %d paths?", selections);
|
||||
for (uint i = 0, printed = 0; i < dirContents.size() && printed < 5; i++) {
|
||||
if (dirContents[i].selected) {
|
||||
iprintf("\x1B[41m- %s\n", dirContents[i].name.c_str());
|
||||
font->printf(0, printed + 2, false, Alignment::left, Palette::red, "- %s", dirContents[i].name.c_str());
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
if(selections > 5)
|
||||
iprintf("\x1B[41m- and %d more...\n", selections - 5);
|
||||
iprintf("\x1B[47m");
|
||||
font->printf(0, 7, false, Alignment::left, Palette::red, "- and %d more...", selections - 5);
|
||||
} else {
|
||||
iprintf("Delete \"%s\"?\n", entry->name.c_str());
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Delete \"%s\"?", entry->name.c_str());
|
||||
}
|
||||
printf ("(<A> yes, <B> no)");
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
font->print(0, (!entry->selected || selections == 1) ? 2 : (selections > 5 ? 9 : selections + 3), false, "(<A> yes, <B> no)");
|
||||
font->update(false);
|
||||
|
||||
while (true) {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
swiWaitForVBlank();
|
||||
if (pressed & KEY_A) {
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
printf ("\x1B[47m"); // Print foreground white color
|
||||
if (entry->selected) {
|
||||
printf ("Deleting files, please wait...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Deleting files, please wait...");
|
||||
font->update(false);
|
||||
struct stat st;
|
||||
for (auto &item : dirContents) {
|
||||
if(item.selected) {
|
||||
@ -839,19 +811,16 @@ std::string browseForFile (void) {
|
||||
}
|
||||
fileOffset = 0;
|
||||
} else if (FAT_getAttr(entry->name.c_str()) & ATTR_READONLY) {
|
||||
printf ("Failed deleting:\n");
|
||||
printf (entry->name.c_str());
|
||||
printf ("\n");
|
||||
printf ("\n");
|
||||
printf ("(<A> to continue)");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Failed deleting:");
|
||||
font->print(0, 1, false, entry->name);
|
||||
font->print(0, 3, false, "(<A> to continue)");
|
||||
pressed = 0;
|
||||
consoleSelect(&topConsole);
|
||||
printf ("\x1B[30m"); // Print black color for time text
|
||||
|
||||
while (!(pressed & KEY_A)) {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
@ -860,10 +829,14 @@ std::string browseForFile (void) {
|
||||
for (int i = 0; i < 15; i++) swiWaitForVBlank();
|
||||
} else {
|
||||
if (entry->isDirectory) {
|
||||
printf ("Deleting folder, please wait...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Deleting folder, please wait...");
|
||||
font->update(false);
|
||||
recRemove(entry->name.c_str(), dirContents);
|
||||
} else {
|
||||
printf ("Deleting file, please wait...");
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Deleting folder, please wait...");
|
||||
font->update(false);
|
||||
remove(entry->name.c_str());
|
||||
}
|
||||
fileOffset--;
|
||||
@ -881,8 +854,10 @@ std::string browseForFile (void) {
|
||||
|
||||
// Create new folder
|
||||
if ((held & KEY_R) && (pressed & KEY_Y) && (strncmp(path, "nitro:/", 7) != 0)) {
|
||||
printf ("\x1b[0;27H");
|
||||
printf (" "); // Clear time
|
||||
// Clear time
|
||||
font->print(-1, 0, true, " ", Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
pressed = 0;
|
||||
consoleDemoInit();
|
||||
Keyboard *kbd = keyboardDemoInit();
|
||||
@ -890,13 +865,13 @@ std::string browseForFile (void) {
|
||||
kbd->OnKeyPressed = OnKeyPressed;
|
||||
|
||||
keyboardShow();
|
||||
printf("Name for new folder: \n");
|
||||
iprintf("Name for new folder:\n");
|
||||
fgets(newName, 256, stdin);
|
||||
newName[strlen(newName)-1] = 0;
|
||||
keyboardHide();
|
||||
consoleClear();
|
||||
|
||||
reinitConsoles();
|
||||
videoSetModeSub(MODE_5_2D);
|
||||
bgShow(bgInitSub(2, BgType_Bmp8, BgSize_B8_256x256, 3, 0));
|
||||
|
||||
if (newName[0] != '\0') {
|
||||
// Check for unsupported characters
|
||||
@ -921,17 +896,14 @@ std::string browseForFile (void) {
|
||||
}
|
||||
|
||||
// Add to selection
|
||||
if (pressed & KEY_L && entry->name != "..") {
|
||||
if ((pressed & KEY_L && !(held & KEY_R)) && entry->name != "..") {
|
||||
bool select = !entry->selected;
|
||||
entry->selected = select;
|
||||
while(held & KEY_L) {
|
||||
do {
|
||||
// Move to right side of screen
|
||||
printf ("\x1b[0;26H");
|
||||
// Print black color for time text
|
||||
printf ("\x1B[30m");
|
||||
// Print time
|
||||
printf (" %s" ,RetTime().c_str());
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
scanKeys();
|
||||
pressed = keysDownRepeat();
|
||||
@ -980,10 +952,8 @@ std::string browseForFile (void) {
|
||||
}
|
||||
}
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
fileBrowse_drawBottomScreen(entry);
|
||||
consoleSelect(&topConsole);
|
||||
showDirectoryContents (dirContents, fileOffset, screenOffset);
|
||||
showDirectoryContents(dirContents, fileOffset, screenOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1025,48 +995,8 @@ std::string browseForFile (void) {
|
||||
|
||||
// Make a screenshot
|
||||
if ((held & KEY_R) && (pressed & KEY_L)) {
|
||||
if (sdMounted || flashcardMounted) {
|
||||
if (access((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), 0777);
|
||||
if (strcmp(path, (sdMounted ? "sd:/" : "fat:/")) == 0) {
|
||||
getDirectoryContents (dirContents);
|
||||
}
|
||||
}
|
||||
if (access((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), 0777);
|
||||
if (strcmp(path, (sdMounted ? "sd:/gm9i/" : "fat:/gm9i/")) == 0) {
|
||||
getDirectoryContents (dirContents);
|
||||
}
|
||||
}
|
||||
char timeText[8];
|
||||
snprintf(timeText, sizeof(timeText), "%s", RetTime().c_str());
|
||||
char fileTimeText[8];
|
||||
snprintf(fileTimeText, sizeof(fileTimeText), "%s", RetTimeForFilename().c_str());
|
||||
char snapPath[40];
|
||||
// Take top screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_top.bmp", (sdMounted ? "sd" : "fat"), fileTimeText);
|
||||
screenshotbmp(snapPath);
|
||||
// Seamlessly swap top and bottom screens
|
||||
lcdMainOnBottom();
|
||||
printBorderBottom();
|
||||
consoleSelect(&bottomConsole);
|
||||
showDirectoryContents (dirContents, fileOffset, screenOffset);
|
||||
printf("\x1B[30m"); // Print black color for time text
|
||||
printf ("\x1b[0;26H");
|
||||
printf (" %s" ,timeText);
|
||||
clearBorderTop();
|
||||
consoleSelect(&topConsole);
|
||||
fileBrowse_drawBottomScreen(entry);
|
||||
// Take bottom screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_bot.bmp", (sdMounted ? "sd" : "fat"), fileTimeText);
|
||||
screenshotbmp(snapPath);
|
||||
if (strcmp(path, (sdMounted ? "sd:/gm9i/out/" : "fat:/gm9i/out/")) == 0) {
|
||||
getDirectoryContents (dirContents);
|
||||
}
|
||||
lcdMainOnTop();
|
||||
printBorderTop();
|
||||
clearBorderBottom();
|
||||
}
|
||||
if(screenshot())
|
||||
getDirectoryContents(dirContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
369
arm9/source/font.cpp
Normal file
369
arm9/source/font.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
#include "font.h"
|
||||
|
||||
#include "font_default_frf.h"
|
||||
#include "tonccpy.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include<nds.h>
|
||||
u8 Font::textBuf[2][256 * 192];
|
||||
bool Font::mainScreen = false;
|
||||
|
||||
Font *font = nullptr;
|
||||
|
||||
bool Font::isStrongRTL(char16_t c) {
|
||||
return (c >= 0x0590 && c <= 0x05FF) || c == 0x200F;
|
||||
}
|
||||
|
||||
bool Font::isWeak(char16_t c) {
|
||||
return c < 'A' || (c > 'Z' && c < 'a') || (c > 'z' && c < 127);
|
||||
}
|
||||
|
||||
bool Font::isNumber(char16_t c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
Font::Font(const char *path) {
|
||||
FILE *file = fopen(path, "rb");
|
||||
|
||||
const u8 *fileBuffer = font_default_frf;
|
||||
if(file) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
|
||||
fileBuffer = new u8[size];
|
||||
if(!fileBuffer) {
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread((void *)fileBuffer, 1, size, file);
|
||||
}
|
||||
const u8 *ptr = fileBuffer;
|
||||
|
||||
// Check header magic, then skip over
|
||||
if(memcmp(ptr, "RIFF", 4) != 0)
|
||||
goto cleanup;
|
||||
|
||||
ptr += 8;
|
||||
|
||||
// check for and load META section
|
||||
if(memcmp(ptr, "META", 4) == 0) {
|
||||
tileWidth = ptr[8];
|
||||
tileHeight = ptr[9];
|
||||
tonccpy(&tileCount, ptr + 10, sizeof(u16));
|
||||
|
||||
if(tileWidth > TILE_MAX_WIDTH || tileHeight > TILE_MAX_HEIGHT)
|
||||
goto cleanup;
|
||||
|
||||
u32 section_size;
|
||||
tonccpy(§ion_size, ptr + 4, sizeof(u32));
|
||||
ptr += 8 + section_size;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Character data
|
||||
if(memcmp(ptr, "CDAT", 4) == 0) {
|
||||
fontTiles = new u8[tileHeight * tileCount];
|
||||
if(!fontTiles)
|
||||
goto cleanup;
|
||||
|
||||
tonccpy(fontTiles, ptr + 8, tileHeight * tileCount);
|
||||
|
||||
u32 section_size;
|
||||
tonccpy(§ion_size, ptr + 4, sizeof(u32));
|
||||
ptr += 8 + section_size;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// character map
|
||||
if(memcmp(ptr, "CMAP", 4) == 0) {
|
||||
fontMap = new u16[tileCount];
|
||||
if(!fontMap)
|
||||
goto cleanup;
|
||||
|
||||
tonccpy(fontMap, ptr + 8, sizeof(u16) * tileCount);
|
||||
|
||||
u32 section_size;
|
||||
tonccpy(§ion_size, ptr + 4, sizeof(u32));
|
||||
ptr += 8 + section_size;
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
questionMark = getCharIndex('?');
|
||||
|
||||
// Copy palette to VRAM
|
||||
for(uint i = 0; i < sizeof(palette) / sizeof(palette[0]); i++) {
|
||||
tonccpy(BG_PALETTE + i * 0x10, palette[i], 4);
|
||||
tonccpy(BG_PALETTE_SUB + i * 0x10, palette[i], 4);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if(fileBuffer != font_default_frf)
|
||||
delete[] fileBuffer;
|
||||
}
|
||||
|
||||
Font::~Font(void) {
|
||||
if(fontTiles)
|
||||
delete[] fontTiles;
|
||||
|
||||
if(fontMap)
|
||||
delete[] fontMap;
|
||||
}
|
||||
|
||||
u16 Font::getCharIndex(char16_t c) {
|
||||
// Try a binary search
|
||||
int left = 0;
|
||||
int right = tileCount;
|
||||
|
||||
while(left <= right) {
|
||||
int mid = left + ((right - left) / 2);
|
||||
if(fontMap[mid] == c) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
if(fontMap[mid] < c) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return questionMark;
|
||||
}
|
||||
|
||||
std::u16string Font::utf8to16(std::string_view text) {
|
||||
std::u16string out;
|
||||
for(uint i = 0; i < text.size();) {
|
||||
char16_t c;
|
||||
if(!(text[i] & 0x80)) {
|
||||
c = text[i++];
|
||||
} else if((text[i] & 0xE0) == 0xC0) {
|
||||
c = (text[i++] & 0x1F) << 6;
|
||||
c |= text[i++] & 0x3F;
|
||||
} else if((text[i] & 0xF0) == 0xE0) {
|
||||
c = (text[i++] & 0x0F) << 12;
|
||||
c |= (text[i++] & 0x3F) << 6;
|
||||
c |= text[i++] & 0x3F;
|
||||
} else {
|
||||
i++; // out of range or something (This only does up to U+FFFF since it goes to a U16 anyways)
|
||||
}
|
||||
out += c;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int Font::calcHeight(std::u16string_view text, int xPos) {
|
||||
int lines = 1, chars = xPos + 1;
|
||||
for(char16_t c : text) {
|
||||
if(c == '\n' || chars > 256 / tileWidth) {
|
||||
nocashMessage(c == '\n' ? "line" : "cha");
|
||||
lines++;
|
||||
chars = xPos + 1;
|
||||
} else {
|
||||
chars++;
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
void Font::printf(int xPos, int yPos, bool top, Alignment align, Palette palette, const char *format, ...) {
|
||||
char str[0x100];
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vsniprintf(str, 0x100, format, va);
|
||||
va_end(va);
|
||||
|
||||
print(xPos, yPos, top, str, align, palette);
|
||||
}
|
||||
|
||||
ITCM_CODE void Font::print(int xPos, int yPos, bool top, std::u16string_view text, Alignment align, Palette palette, bool rtl) {
|
||||
int x = xPos * tileWidth, y = yPos * tileHeight;
|
||||
if(x < 0 && align != Alignment::center)
|
||||
x += 255;
|
||||
if(y < 0)
|
||||
y += 191;
|
||||
|
||||
// If RTL isn't forced, check for RTL text
|
||||
if(!rtl) {
|
||||
for(const auto c : text) {
|
||||
if(isStrongRTL(c)) {
|
||||
rtl = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto ltrBegin = text.end(), ltrEnd = text.end();
|
||||
|
||||
// Adjust x for alignment
|
||||
switch(align) {
|
||||
case Alignment::left: {
|
||||
break;
|
||||
} case Alignment::center: {
|
||||
size_t newline = text.find('\n');
|
||||
while(newline != text.npos) {
|
||||
print(xPos, yPos, top, text.substr(0, newline), align, palette, rtl);
|
||||
text = text.substr(newline + 1);
|
||||
newline = text.find('\n');
|
||||
yPos++;
|
||||
y += tileHeight;
|
||||
}
|
||||
|
||||
x = ((256 - (text.length() * tileWidth)) / 2) + x;
|
||||
break;
|
||||
} case Alignment::right: {
|
||||
size_t newline = text.find('\n');
|
||||
while(newline != text.npos) {
|
||||
print(xPos, yPos, top, text.substr(0, newline), Alignment::left, palette, rtl);
|
||||
text = text.substr(newline + 1);
|
||||
newline = text.find('\n');
|
||||
yPos++;
|
||||
y += tileHeight;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(align == Alignment::right)
|
||||
x -= (text.length() - 1) * tileWidth;
|
||||
|
||||
// Align to grid
|
||||
x -= x % tileWidth;
|
||||
y -= y % tileHeight;
|
||||
x += (256 % tileWidth) / 2;
|
||||
y += (192 % tileHeight) / 2;
|
||||
|
||||
const int xStart = x;
|
||||
|
||||
// Loop through string and print it
|
||||
for(auto it = (rtl ? text.end() - 1 : text.begin()); true; it += (rtl ? -1 : 1)) {
|
||||
// If we hit the end of the string in an LTR section of an RTL
|
||||
// string, it may not be done, if so jump back to printing RTL
|
||||
if(it == (rtl ? text.begin() - 1 : text.end())) {
|
||||
if(ltrBegin == text.end() || (ltrBegin == text.begin() && ltrEnd == text.end())) {
|
||||
break;
|
||||
} else {
|
||||
it = ltrBegin;
|
||||
ltrBegin = text.end();
|
||||
rtl = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If at the end of an LTR section within RTL, jump back to the RTL
|
||||
if(it == ltrEnd && ltrBegin != text.end()) {
|
||||
if(ltrBegin == text.begin() && (!isWeak(*ltrBegin) || isNumber(*ltrBegin)))
|
||||
break;
|
||||
|
||||
it = ltrBegin;
|
||||
ltrBegin = text.end();
|
||||
rtl = true;
|
||||
// If in RTL and hit a non-RTL character that's not punctuation, switch to LTR
|
||||
} else if(rtl && !isStrongRTL(*it) && (!isWeak(*it) || isNumber(*it))) {
|
||||
// Save where we are as the end of the LTR section
|
||||
ltrEnd = it + 1;
|
||||
|
||||
// Go back until an RTL character or the start of the string
|
||||
bool allNumbers = true;
|
||||
while(!isStrongRTL(*it) && it != text.begin()) {
|
||||
// Check for if the LTR section is only numbers,
|
||||
// if so they won't be removed from the end
|
||||
if(allNumbers && !isNumber(*it) && !isWeak(*it))
|
||||
allNumbers = false;
|
||||
it--;
|
||||
}
|
||||
|
||||
// Save where we are to return to after printing the LTR section
|
||||
ltrBegin = it;
|
||||
|
||||
// If on an RTL char right now, add one
|
||||
if(isStrongRTL(*it)) {
|
||||
it++;
|
||||
}
|
||||
|
||||
// Remove all punctuation and, if the section isn't only numbers,
|
||||
// numbers from the end of the LTR section
|
||||
if(allNumbers) {
|
||||
while(isWeak(*it) && !isNumber(*it)) {
|
||||
if(it != text.begin())
|
||||
ltrBegin++;
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
while(isWeak(*it)) {
|
||||
if(it != text.begin())
|
||||
ltrBegin++;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// But then allow all numbers directly touching the strong LTR or with 1 weak between
|
||||
while((it - 1 >= text.begin() && isNumber(*(it - 1))) || (it - 2 >= text.begin() && isWeak(*(it - 1)) && isNumber(*(it - 2)))) {
|
||||
if(it - 1 != text.begin())
|
||||
ltrBegin--;
|
||||
it--;
|
||||
}
|
||||
|
||||
rtl = false;
|
||||
}
|
||||
|
||||
if(*it == '\n') {
|
||||
x = xStart;
|
||||
y += tileHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Brackets are flipped in RTL
|
||||
u16 index;
|
||||
if(rtl) {
|
||||
switch(*it) {
|
||||
case '(':
|
||||
index = getCharIndex(')');
|
||||
break;
|
||||
case ')':
|
||||
index = getCharIndex('(');
|
||||
break;
|
||||
case '[':
|
||||
index = getCharIndex(']');
|
||||
break;
|
||||
case ']':
|
||||
index = getCharIndex('[');
|
||||
break;
|
||||
case '<':
|
||||
index = getCharIndex('>');
|
||||
break;
|
||||
case '>':
|
||||
index = getCharIndex('<');
|
||||
break;
|
||||
default:
|
||||
index = getCharIndex(*it);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
index = getCharIndex(*it);
|
||||
}
|
||||
|
||||
// Wrap at right edge if not center aligning
|
||||
if(x + tileWidth > 256 && align != Alignment::center) {
|
||||
x = xStart;
|
||||
y += tileHeight;
|
||||
}
|
||||
|
||||
// Don't draw off screen chars
|
||||
if(x >= 0 && y >= 0 && y + tileHeight <= 192) {
|
||||
u8 *dst = textBuf[top] + x;
|
||||
for(int i = 0; i < tileHeight; i++) {
|
||||
u8 px = fontTiles[(index * tileHeight) + i];
|
||||
for(int j = 0; j < tileWidth; j++) {
|
||||
dst[(y + i) * 256 + j] = u8(palette) * 0x10 + ((px >> (7 - j)) & 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += tileWidth;
|
||||
}
|
||||
}
|
94
arm9/source/font.h
Normal file
94
arm9/source/font.h
Normal file
@ -0,0 +1,94 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include "tonccpy.h"
|
||||
|
||||
#include <nds/arm9/background.h>
|
||||
#include <nds/dma.h>
|
||||
#include <nds/ndstypes.h>
|
||||
#include <string>
|
||||
|
||||
#define TILE_MAX_WIDTH 8
|
||||
#define TILE_MAX_HEIGHT 10
|
||||
|
||||
#define SCREEN_COLS (256 / font->width())
|
||||
#define ENTRIES_PER_SCREEN ((192 - font->height()) / font->height())
|
||||
|
||||
enum class Alignment {
|
||||
left,
|
||||
center,
|
||||
right,
|
||||
};
|
||||
|
||||
enum class Palette : u8 {
|
||||
white = 0,
|
||||
gray,
|
||||
red,
|
||||
green,
|
||||
greenAlt,
|
||||
blue,
|
||||
yellow,
|
||||
blackRed,
|
||||
blackGreen,
|
||||
blackBlue,
|
||||
};
|
||||
|
||||
class Font {
|
||||
static bool isStrongRTL(char16_t c);
|
||||
static bool isWeak(char16_t c);
|
||||
static bool isNumber(char16_t c);
|
||||
|
||||
static constexpr u16 palette[16][2] = {
|
||||
{0x0000, 0x7FFF}, // White
|
||||
{0x0000, 0x3DEF}, // Gray
|
||||
{0x0000, 0x001F}, // Red
|
||||
{0x0000, 0x03E0}, // Green
|
||||
{0x0000, 0x02E0}, // Green (alt)
|
||||
{0x0000, 0x656A}, // Blue
|
||||
{0x0000, 0x3339}, // Yellow
|
||||
{0x001F, 0x0000}, // Black on red
|
||||
{0x03E0, 0x0000}, // Black on green
|
||||
{0x656A, 0x0000}, // Black on blue
|
||||
};
|
||||
|
||||
static u8 textBuf[2][256 * 192];
|
||||
static bool mainScreen;
|
||||
|
||||
u8 tileWidth = 0, tileHeight = 0;
|
||||
u16 tileCount = 0;
|
||||
u16 questionMark = 0;
|
||||
u8 *fontTiles = nullptr;
|
||||
u16 *fontMap = nullptr;
|
||||
|
||||
u16 getCharIndex(char16_t c);
|
||||
public:
|
||||
static std::u16string utf8to16(std::string_view text);
|
||||
|
||||
static void update(bool top) { tonccpy(bgGetGfxPtr(top ? 2 : 6), Font::textBuf[top ^ mainScreen], 256 * 192); }
|
||||
static void clear(bool top) { dmaFillWords(0, Font::textBuf[top ^ mainScreen], 256 * 192); }
|
||||
|
||||
static void mainOnTop(bool top) { mainScreen = !top; }
|
||||
|
||||
Font(const char *path);
|
||||
|
||||
~Font(void);
|
||||
|
||||
u8 width(void) { return tileWidth; }
|
||||
u8 height(void) { return tileHeight; }
|
||||
|
||||
int calcWidth(std::string_view text) { return utf8to16(text).length(); }
|
||||
int calcWidth(std::u16string_view text) { return text.length(); };
|
||||
|
||||
int calcHeight(std::string_view text, int xPos = 0) { return calcHeight(utf8to16(text)); }
|
||||
int calcHeight(std::u16string_view text, int xPos = 0);
|
||||
|
||||
void printf(int xPos, int yPos, bool top, Alignment align, Palette palette, const char *format, ...);
|
||||
|
||||
void print(int xPos, int yPos, bool top, int value, Alignment align = Alignment::left, Palette palette = Palette::white) { print(xPos, yPos, top, std::to_string(value), align, palette); }
|
||||
void print(int xPos, int yPos, bool top, std::string_view text, Alignment align = Alignment::left, Palette palette = Palette::white) { print(xPos, yPos, top, utf8to16(text), align, palette); }
|
||||
void print(int xPos, int yPos, bool top, std::u16string_view text, Alignment align = Alignment::left, Palette palette = Palette::white, bool rtl = false);
|
||||
};
|
||||
|
||||
extern Font *font;
|
||||
|
||||
#endif // FONT_H
|
@ -1,41 +1,37 @@
|
||||
#include "hexEditor.h"
|
||||
|
||||
#include "date.h"
|
||||
#include "tonccpy.h"
|
||||
#include "file_browse.h"
|
||||
#include "font.h"
|
||||
#include "tonccpy.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <nds.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern PrintConsole bottomConsole, bottomConsoleBG, topConsole;
|
||||
|
||||
extern void reinitConsoles(void);
|
||||
|
||||
u32 jumpToOffset(u32 offset) {
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
consoleClear();
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
|
||||
u8 cursorPosition = 0;
|
||||
u16 pressed = 0, held = 0;
|
||||
while(1) {
|
||||
printf("\x1B[9;6H\x1B[47m-------------------");
|
||||
printf("\x1B[10;8H\x1B[47mJump to Offset");
|
||||
printf("\x1B[12;11H\x1B[37m%08lX", offset);
|
||||
printf("\x1B[12;%dH\x1B[41m%lX", 17 - cursorPosition, (offset >> ((cursorPosition + 1) * 4)) & 0xF);
|
||||
printf("\x1B[13;6H\x1B[47m-------------------");
|
||||
int y = (ENTRIES_PER_SCREEN - 4) / 2;
|
||||
font->clear(false);
|
||||
font->print(0, y, false, "--------------------", Alignment::center);
|
||||
font->print(0, y + 1, false, "Jump to Offset", Alignment::center);
|
||||
font->printf(0, y + 3, false, Alignment::center, Palette::blue, "%08lX", offset);
|
||||
font->printf(3 - cursorPosition, y + 3, false, Alignment::center, Palette::red, "%lX", (offset >> ((cursorPosition + 1) * 4)) & 0xF);
|
||||
font->print(0, y + 4, false, "--------------------", Alignment::center);
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
held = keysDownRepeat();
|
||||
printf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
} while(!held);
|
||||
consoleSelect(&bottomConsole);
|
||||
|
||||
if(held & KEY_UP) {
|
||||
offset = (offset & ~(0xF0 << cursorPosition * 4)) | ((offset + (0x10 << (cursorPosition * 4))) & (0xF0 << cursorPosition * 4));
|
||||
@ -54,28 +50,27 @@ u32 jumpToOffset(u32 offset) {
|
||||
}
|
||||
|
||||
u32 search(u32 offset, FILE *file) {
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
consoleClear();
|
||||
consoleSelect(&bottomConsole);
|
||||
consoleClear();
|
||||
|
||||
u8 cursorPosition = 0;
|
||||
u16 pressed = 0, held = 0;
|
||||
while(1) {
|
||||
printf("\x1B[9;4H\x1B[47m-----------------------");
|
||||
printf("\x1B[10;5H%c Search for String %c", cursorPosition == 0 ? '>' : ' ', cursorPosition == 0 ? '<' : ' ');
|
||||
printf("\x1B[11;5H%c Search for Data %c", cursorPosition == 1 ? '>' : ' ', cursorPosition == 1 ? '<' : ' ');
|
||||
printf("\x1B[12;4H-----------------------");
|
||||
int y = (ENTRIES_PER_SCREEN - 3) / 2;
|
||||
font->clear(false);
|
||||
font->print(0, y, false, "--------------------", Alignment::center);
|
||||
font->printf(0, y + 1, false, Alignment::center, Palette::white, "%c Search for String %c", cursorPosition == 0 ? '>' : ' ', cursorPosition == 0 ? '<' : ' ');
|
||||
font->printf(0, y + 2, false, Alignment::center, Palette::white, "%c Search for Data %c", cursorPosition == 1 ? '>' : ' ', cursorPosition == 1 ? '<' : ' ');
|
||||
font->print(0, y + 3, false, "--------------------", Alignment::center);
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
held = keysDownRepeat();
|
||||
printf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
} while(!held);
|
||||
consoleSelect(&bottomConsole);
|
||||
|
||||
if(held & (KEY_UP | KEY_DOWN)) {
|
||||
cursorPosition ^= 1;
|
||||
@ -98,10 +93,9 @@ u32 search(u32 offset, FILE *file) {
|
||||
printf("Search for:\n");
|
||||
fgets(str, sizeof(str), stdin);
|
||||
keyboardHide();
|
||||
consoleClear();
|
||||
|
||||
reinitConsoles();
|
||||
consoleSelect(&bottomConsole);
|
||||
videoSetModeSub(MODE_5_2D);
|
||||
bgShow(bgInitSub(2, BgType_Bmp8, BgSize_B8_256x256, 3, 0));
|
||||
|
||||
BG_PALETTE_SUB[0x1F] = 0x9CF7;
|
||||
BG_PALETTE_SUB[0x2F] = 0xB710;
|
||||
@ -114,27 +108,27 @@ u32 search(u32 offset, FILE *file) {
|
||||
|
||||
str[strLen] = 0; // Remove ending \n that fgets has
|
||||
} else {
|
||||
consoleClear();
|
||||
|
||||
cursorPosition = 0;
|
||||
while(1) {
|
||||
printf("\x1B[9;6H\x1B[47m------------------");
|
||||
printf("\x1B[10;9HEnter value:");
|
||||
u8 pos = 15 - strLen;
|
||||
for(size_t i = 0; i < strLen * 2; i++) {
|
||||
printf("\x1B[12;%dH\x1B[%dm%X", pos + i, (i == cursorPosition ? 31 : ((i / 2 % 2) ? 33 : 32)), str[i / 2] >> (!(i % 2) * 4) & 0xF);
|
||||
}
|
||||
printf("\x1B[13;6H\x1B[47m------------------");
|
||||
int y = (ENTRIES_PER_SCREEN - 4) / 2;
|
||||
font->clear(false);
|
||||
font->print(0, y, false, "--------------------", Alignment::center);
|
||||
font->print(0, y + 1, false, "Enter value:", Alignment::center);
|
||||
for(size_t i = 0; i < strLen * 2; i++)
|
||||
font->printf(-strLen + i + 1, y + 3, false, Alignment::center, i == cursorPosition ? Palette::red : ((i / 2 % 2) ? Palette::greenAlt : Palette::green), "%X", str[i / 2] >> (!(i % 2) * 4) & 0xF);
|
||||
font->print(0, y + 4, false, "--------------------", Alignment::center);
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
held = keysDownRepeat();
|
||||
printf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
} while(!held);
|
||||
consoleSelect(&bottomConsole);
|
||||
|
||||
if(held & KEY_UP) {
|
||||
char val = str[cursorPosition / 2];
|
||||
@ -164,17 +158,20 @@ u32 search(u32 offset, FILE *file) {
|
||||
strLen--;
|
||||
if(cursorPosition > strLen * 2 - 1)
|
||||
cursorPosition -= 2;
|
||||
consoleClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
consoleClear();
|
||||
printf("\x1B[9;6H\x1B[47m---------------------");
|
||||
printf("\x1B[10;12HSearching");
|
||||
printf("\x1B[14;8HPress B to cancel");
|
||||
printf("\x1B[15;6H---------------------");
|
||||
int y = (ENTRIES_PER_SCREEN - 7) / 2;
|
||||
font->clear(false);
|
||||
font->print(0, y, false, "--------------------", Alignment::center);
|
||||
font->print(0, y + 1, false, "Searching", Alignment::center);
|
||||
font->print(0, y + 6, false, "Press B to cancel", Alignment::center);
|
||||
font->print(0, y + 7, false, "--------------------", Alignment::center);
|
||||
font->update(false);
|
||||
|
||||
char progressBar[21] = "[ ]";
|
||||
|
||||
size_t len = 32 << 10, pos = offset;
|
||||
fseek(file, 0, SEEK_END);
|
||||
@ -187,7 +184,10 @@ u32 search(u32 offset, FILE *file) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
printf("\x1B[12;6H%10d/%d", pos, fileLen);
|
||||
progressBar[pos / (fileLen / 18) + 1] = '=';
|
||||
font->print(0, y + 3, false, progressBar, Alignment::center);
|
||||
font->printf(0, y + 4, false, Alignment::center, Palette::white, "%d/%d", pos, fileLen);
|
||||
font->update(false);
|
||||
|
||||
if(fseek(file, pos, SEEK_SET) != 0)
|
||||
break;
|
||||
@ -204,64 +204,53 @@ u32 search(u32 offset, FILE *file) {
|
||||
} while(len == 32 << 10);
|
||||
delete[] buf;
|
||||
|
||||
consoleClear();
|
||||
printf("\x1B[9;5H\x1B[47m---------------------");
|
||||
printf("\x1B[10;6HReached end of file");
|
||||
printf("\x1B[11;8Hwith no results");
|
||||
printf("\x1B[12;5H---------------------");
|
||||
y = (ENTRIES_PER_SCREEN - 3) / 2;
|
||||
font->clear(false);
|
||||
font->print(0, y, false, "--------------------", Alignment::center);
|
||||
font->print(0, y + 1, false, "Reached end of file", Alignment::center);
|
||||
font->print(0, y + 2, false, "with no results", Alignment::center);
|
||||
font->print(0, y + 3, false, "--------------------", Alignment::center);
|
||||
font->update(false);
|
||||
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
printf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
} while(!keysDown());
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void hexEditor(const char *path, int drive) {
|
||||
// Custom palettes
|
||||
BG_PALETTE_SUB[0x1F] = 0x9CF7;
|
||||
BG_PALETTE_SUB[0x2F] = 0xB710;
|
||||
BG_PALETTE_SUB[0x3F] = 0xAE8D;
|
||||
BG_PALETTE_SUB[0x7F] = 0xEA2D;
|
||||
|
||||
FILE *file = fopen(path, drive < 4 ? "rb+" : "rb");
|
||||
|
||||
if(!file)
|
||||
return;
|
||||
|
||||
consoleClear();
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
u32 fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
u8 maxLines = std::min(23lu, fileSize / 8 + (fileSize % 8 != 0));
|
||||
u8 maxLines = std::min((u32)ENTRIES_PER_SCREEN, fileSize / 8 + (fileSize % 8 != 0));
|
||||
u32 maxSize = ((fileSize - 8 * maxLines) & ~7) + (fileSize & 7 ? 8 : 0);
|
||||
|
||||
u8 cursorPosition = 0, mode = 0;
|
||||
u16 pressed = 0, held = 0;
|
||||
u32 offset = 0;
|
||||
u32 offset = 0, cursorPosition = 0, mode = 0;
|
||||
|
||||
char data[8 * maxLines];
|
||||
fseek(file, offset, SEEK_SET);
|
||||
fread(data, 1, sizeof(data), file);
|
||||
|
||||
while(1) {
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
printf ("\x1B[0;0H\x1B[46m"); // Blue
|
||||
for(int i = 0; i < 4; i++)
|
||||
printf ("\2");
|
||||
printf ("\x1B[42m"); // Green
|
||||
for(int i = 0; i < 32 - 4; i++)
|
||||
printf ("\2");
|
||||
font->clear(false);
|
||||
|
||||
consoleSelect(&bottomConsole);
|
||||
font->printf(4, 0, false, Alignment::left, Palette::blackGreen, "%*c", SCREEN_COLS - 4, ' ');
|
||||
font->print(0, 0, false, "Hex Editor", Alignment::center, Palette::blackGreen);
|
||||
|
||||
printf("\x1B[0;11H\x1B[30mHex Editor");
|
||||
|
||||
printf("\x1B[0;0H\x1B[30m%04lX", offset >> 0x10);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::blackBlue, "%04lX", offset >> 0x10);
|
||||
|
||||
if(mode < 2) {
|
||||
fseek(file, offset, SEEK_SET);
|
||||
@ -269,36 +258,38 @@ void hexEditor(const char *path, int drive) {
|
||||
fread(data, 1, std::min((u32)sizeof(data), fileSize - offset), file);
|
||||
}
|
||||
|
||||
for(int i = 0; i < maxLines; i++) {
|
||||
printf("\x1B[%d;0H\x1B[37m%04lX", i + 1, (offset + i * 8) & 0xFFFF);
|
||||
for(u32 i = 0; i < maxLines; i++) {
|
||||
font->printf(0, i + 1, false, Alignment::left, Palette::blue, "%04lX", (offset + i * 8) & 0xFFFF);
|
||||
for(int j = 0; j < 4; j++)
|
||||
printf("\x1B[%d;%dH\x1B[%dm%02X", i + 1, 5 + (j * 2), (mode > 0 && i * 8 + j == cursorPosition) ? (mode > 1 ? 30 : 31) : (offset + i * 8 + j >= fileSize ? 38 : 32 + (j % 2)), data[i * 8 + j]);
|
||||
font->printf(5 + (j * 2), i + 1, false, Alignment::left, (mode > 0 && i * 8 + j == cursorPosition) ? (mode > 1 ? Palette::blackRed : Palette::red) : (offset + i * 8 + j >= fileSize ? Palette::gray : (j % 2 ? Palette::greenAlt : Palette::green)), "%02X", data[i * 8 + j]);
|
||||
for(int j = 0; j < 4; j++)
|
||||
printf("\x1B[%d;%dH\x1B[%dm%02X", i + 1, 14 + (j * 2), (mode > 0 && i * 8 + 4 + j == cursorPosition) ? (mode > 1 ? 30 : 31) : (offset + i * 8 + 4 + j >= fileSize ? 38 : 32 + (j % 2)), data[i * 8 + 4 + j]);
|
||||
font->printf(14 + (j * 2), i + 1, false, Alignment::left, (mode > 0 && i * 8 + 4 + j == cursorPosition) ? (mode > 1 ? Palette::blackRed : Palette::red) : (offset + i * 8 + 4 + j >= fileSize ? Palette::gray : (j % 2 ? Palette::greenAlt : Palette::green)), "%02X", data[i * 8 + 4 + j]);
|
||||
char line[9] = {0};
|
||||
for(int j = 0; j < 8; j++) {
|
||||
char c = data[i * 8 + j];
|
||||
if(c < ' ' || c > 127)
|
||||
line[j] = ' ';
|
||||
line[j] = '.';
|
||||
else
|
||||
line[j] = c;
|
||||
}
|
||||
printf("\x1B[%d;23H\x1B[47m%.8s", i + 1, line);
|
||||
font->print(23, i + 1, false, line);
|
||||
if(mode > 0 && cursorPosition / 8 == i) {
|
||||
printf("\x1B[%d;%dH\x1B[%dm%c", i + 1, 23 + cursorPosition % 8, mode > 1 ? 30 : 31, line[cursorPosition % 8]);
|
||||
font->printf(23 + cursorPosition % 8, i + 1, false, Alignment::left, mode > 1 ? Palette::blackRed : Palette::red, "%c", line[cursorPosition % 8]);
|
||||
}
|
||||
}
|
||||
|
||||
font->update(false);
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
held = keysDownRepeat();
|
||||
printf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
} while(!held);
|
||||
consoleSelect(&bottomConsole);
|
||||
|
||||
if(mode == 0) {
|
||||
if(keysHeld() & KEY_R && held & (KEY_UP | KEY_DOWN | KEY_LEFT | KEY_RIGHT)) {
|
||||
@ -323,49 +314,42 @@ void hexEditor(const char *path, int drive) {
|
||||
offset = std::min(offset + 8 * maxLines, maxSize);
|
||||
} else if(pressed & KEY_A) {
|
||||
mode = 1;
|
||||
cursorPosition = std::min(cursorPosition, fileSize - offset - 1);
|
||||
} else if(pressed & KEY_B) {
|
||||
break;
|
||||
} else if(pressed & KEY_X) {
|
||||
offset = std::min(search(offset, file), maxSize);
|
||||
consoleClear();
|
||||
} else if(pressed & KEY_Y) {
|
||||
offset = std::min(jumpToOffset(offset), maxSize);
|
||||
consoleClear();
|
||||
}
|
||||
} else if(mode == 1) {
|
||||
if(held & KEY_UP) {
|
||||
if(cursorPosition >= 8)
|
||||
cursorPosition -= 8;
|
||||
else if(offset > 8)
|
||||
else if(offset >= 8)
|
||||
offset -= 8;
|
||||
} else if(held & KEY_DOWN) {
|
||||
if(cursorPosition < 8 * 22)
|
||||
if(cursorPosition < 8u * (maxLines - 1))
|
||||
cursorPosition += 8;
|
||||
else if(offset < fileSize - 8 * maxLines && fileSize > 8 * maxLines)
|
||||
offset += 8;
|
||||
cursorPosition = std::min(cursorPosition, (u8)(fileSize - offset - 1));
|
||||
cursorPosition = std::min(cursorPosition, fileSize - offset - 1);
|
||||
} else if(held & KEY_LEFT) {
|
||||
if(cursorPosition > 0)
|
||||
cursorPosition--;
|
||||
} else if(held & KEY_RIGHT) {
|
||||
if(cursorPosition < 8 * maxLines - 1)
|
||||
cursorPosition = std::min((u8)(cursorPosition + 1), (u8)(fileSize - offset - 1));
|
||||
if(cursorPosition < 8u * maxLines - 1)
|
||||
cursorPosition = std::min(cursorPosition + 1, fileSize - offset - 1);
|
||||
} else if(pressed & KEY_A) {
|
||||
if(drive < 4) {
|
||||
mode = 2;
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
printf("\x1B[%d;%dH\x1B[%dm\2\2", 1 + cursorPosition / 8, 5 + (cursorPosition % 8 * 2) + (cursorPosition % 8 / 4), 31);
|
||||
printf("\x1B[%d;%dH\x1B[%dm\2", 1 + cursorPosition / 8, 23 + cursorPosition % 8, 31);
|
||||
consoleSelect(&bottomConsole);
|
||||
}
|
||||
} else if(pressed & KEY_B) {
|
||||
mode = 0;
|
||||
} else if(pressed & KEY_X) {
|
||||
offset = std::min(search(offset, file), maxSize);
|
||||
consoleClear();
|
||||
} else if(pressed & KEY_Y) {
|
||||
offset = std::min(jumpToOffset(offset), maxSize);
|
||||
consoleClear();
|
||||
}
|
||||
} else if(mode == 2) {
|
||||
if(held & KEY_UP) {
|
||||
@ -380,23 +364,9 @@ void hexEditor(const char *path, int drive) {
|
||||
mode = 1;
|
||||
fseek(file, offset + cursorPosition, SEEK_SET);
|
||||
fwrite(data + cursorPosition, 1, 1, file);
|
||||
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
printf("\x1B[%d;%dH\x1B[%dm\2\2", 1 + cursorPosition / 8, 5 + (cursorPosition % 8 * 2) + (cursorPosition % 8 / 4), 30);
|
||||
printf("\x1B[%d;%dH\x1B[%dm\2", 1 + cursorPosition / 8, 23 + cursorPosition % 8, 30);
|
||||
consoleSelect(&bottomConsole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Restore color palette
|
||||
BG_PALETTE_SUB[0x1F] = 0x000F;
|
||||
BG_PALETTE_SUB[0x2F] = 0x01E0;
|
||||
BG_PALETTE_SUB[0x3F] = 0x3339;
|
||||
BG_PALETTE_SUB[0x7F] = 0x656A;
|
||||
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
consoleClear();
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "driveOperations.h"
|
||||
#include "file_browse.h"
|
||||
#include "fileOperations.h"
|
||||
#include "font.h"
|
||||
#include "tonccpy.h"
|
||||
#include "version.h"
|
||||
|
||||
@ -57,8 +58,6 @@ bool applaunch = false;
|
||||
|
||||
static int bg3;
|
||||
|
||||
PrintConsole topConsoleBG, topConsole, bottomConsoleBG, bottomConsole;
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void stop (void) {
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -69,60 +68,6 @@ void stop (void) {
|
||||
|
||||
char filePath[PATH_MAX];
|
||||
|
||||
void printBorderTop(void) {
|
||||
consoleSelect(&topConsoleBG);
|
||||
printf ("\x1B[42m"); // Print green color
|
||||
for (int i = 0; i < 32; i++) {
|
||||
printf ("\x02"); // Print top border
|
||||
}
|
||||
}
|
||||
|
||||
void printBorderBottom(void) {
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
printf ("\x1B[42m"); // Print green color
|
||||
for (int i = 0; i < 32; i++) {
|
||||
printf ("\x02"); // Print top border
|
||||
}
|
||||
}
|
||||
|
||||
void clearBorderTop(void) {
|
||||
consoleSelect(&topConsoleBG);
|
||||
consoleClear();
|
||||
}
|
||||
|
||||
void clearBorderBottom(void) {
|
||||
consoleSelect(&bottomConsoleBG);
|
||||
consoleClear();
|
||||
}
|
||||
|
||||
void reinitConsoles(void) {
|
||||
// Subscreen as a console
|
||||
videoSetModeSub(MODE_0_2D);
|
||||
vramSetBankH(VRAM_H_SUB_BG);
|
||||
consoleInit(&bottomConsoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, false, true);
|
||||
consoleInit(&bottomConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
|
||||
|
||||
// Top screen as a console
|
||||
videoSetMode(MODE_0_2D);
|
||||
vramSetBankG(VRAM_G_MAIN_BG);
|
||||
consoleInit(&topConsoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, true, true);
|
||||
consoleInit(&topConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true);
|
||||
|
||||
// Overwrite background white color
|
||||
BG_PALETTE[15+(7*16)] = 0x656A;
|
||||
BG_PALETTE_SUB[15+(7*16)] = 0x656A;
|
||||
|
||||
// Custom yellow color
|
||||
BG_PALETTE[15+(3*16)] = 0x3339;
|
||||
BG_PALETTE_SUB[15+(3*16)] = 0x3339;
|
||||
|
||||
// Overwrite 2nd smiley face with filled tile
|
||||
dmaFillWords(0xFFFFFFFF, (void*)0x6000040, 8*8); // Top screen
|
||||
dmaFillWords(0xFFFFFFFF, (void*)0x6200040, 8*8); // Bottom screen
|
||||
|
||||
printBorderTop();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
int main(int argc, char **argv) {
|
||||
//---------------------------------------------------------------------------------
|
||||
@ -141,34 +86,29 @@ int main(int argc, char **argv) {
|
||||
sprintf(titleName, "GodMode9i %s", VER_NUMBER);
|
||||
|
||||
// initialize video mode
|
||||
videoSetMode(MODE_4_2D);
|
||||
videoSetMode(MODE_5_2D);
|
||||
videoSetModeSub(MODE_5_2D);
|
||||
|
||||
// initialize VRAM banks
|
||||
vramSetPrimaryBanks(VRAM_A_MAIN_BG,
|
||||
VRAM_B_MAIN_SPRITE,
|
||||
VRAM_C_LCD,
|
||||
VRAM_C_SUB_BG,
|
||||
VRAM_D_LCD);
|
||||
|
||||
// Subscreen as a console
|
||||
videoSetModeSub(MODE_0_2D);
|
||||
vramSetBankH(VRAM_H_SUB_BG);
|
||||
vramSetBankI(VRAM_I_SUB_SPRITE);
|
||||
consoleInit(&bottomConsoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, false, true);
|
||||
consoleInit(&bottomConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
|
||||
|
||||
// Init built-in font
|
||||
font = new Font("/font.frf");
|
||||
|
||||
// Display GM9i logo
|
||||
bg3 = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0);
|
||||
bg3 = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
|
||||
bgInit(2, BgType_Bmp8, BgSize_B8_256x256, 3, 0);
|
||||
bgInitSub(2, BgType_Bmp8, BgSize_B8_256x256, 3, 0);
|
||||
decompress(gm9i_logoBitmap, bgGetGfxPtr(bg3), LZ77Vram);
|
||||
tonccpy(BG_PALETTE, gm9i_logoPal, gm9i_logoPalLen);
|
||||
|
||||
printf ("\x1b[1;1H");
|
||||
printf(titleName);
|
||||
printf ("\x1b[2;1H");
|
||||
printf ("------------------------------");
|
||||
printf ("\x1b[3;1H");
|
||||
printf ("https:/github.com/");
|
||||
printf ("\x1b[4;10H");
|
||||
printf ("DS-Homebrew/GodMode9i");
|
||||
font->print(1, 1, false, titleName);
|
||||
font->print(1, 2, false, "---------------------------------------");
|
||||
font->print(1, 3, false, "https:/github.com/DS-Homebrew/GodMode9i");
|
||||
|
||||
fifoWaitValue32(FIFO_USER_06);
|
||||
if (fifoGetValue32(FIFO_USER_03) == 0) arm7SCFGLocked = true;
|
||||
@ -178,36 +118,27 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (isDSiMode()) {
|
||||
if (!arm7SCFGLocked) {
|
||||
printf ("\x1b[20;1H");
|
||||
printf ("X Held - Disable NAND access");
|
||||
printf ("\x1b[21;1H");
|
||||
printf ("Y Held - Disable cart access");
|
||||
printf ("\x1b[22;4H");
|
||||
printf ("Do these if it crashes here");
|
||||
font->print(-2, -4, false, "X Held - Disable NAND access", Alignment::right);
|
||||
font->print(-2, -3, false, "Y Held - Disable cart access", Alignment::right);
|
||||
font->print(-2, -2, false, "Do these if it crashes here", Alignment::right);
|
||||
} else {
|
||||
printf ("\x1b[21;1H");
|
||||
printf ("X Held - Disable NAND access");
|
||||
printf ("\x1b[22;5H");
|
||||
printf ("Do this if it crashes here");
|
||||
font->print(-2, -3, false, "X Held - Disable NAND access", Alignment::right);
|
||||
font->print(-2, -2, false, "Do this if it crashes here", Alignment::right);
|
||||
}
|
||||
}
|
||||
|
||||
// Display for 2 seconds
|
||||
font->update(false);
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
|
||||
if (isDSiMode()) {
|
||||
printf ("\x1b[20;1H");
|
||||
printf (" ");
|
||||
printf ("\x1b[21;1H");
|
||||
printf (" ");
|
||||
printf ("\x1b[22;4H");
|
||||
printf (" "); // Clear "Y Held" text
|
||||
}
|
||||
printf ("\x1b[22;11H");
|
||||
printf ("mounting drive(s)...");
|
||||
//printf ("%X %X", *(u32*)0x2FFFD00, *(u32*)0x2FFFD04);
|
||||
font->clear(false);
|
||||
font->print(1, 1, false, titleName);
|
||||
font->print(1, 2, false, "---------------------------------------");
|
||||
font->print(1, 3, false, "https:/github.com/DS-Homebrew/GodMode9i");
|
||||
font->print(-2, -2, false, "Mounting drive(s)...", Alignment::right);
|
||||
font->update(false);
|
||||
|
||||
sysSetCartOwner (BUS_OWNER_ARM9); // Allow arm9 to access GBA ROM
|
||||
|
||||
@ -243,11 +174,11 @@ int main(int argc, char **argv) {
|
||||
flashcardMountSkipped = false;
|
||||
}
|
||||
|
||||
// Top screen as a console
|
||||
videoSetMode(MODE_0_2D);
|
||||
vramSetBankG(VRAM_G_MAIN_BG);
|
||||
consoleInit(&topConsoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, true, true);
|
||||
consoleInit(&topConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, true, true);
|
||||
bgHide(bg3);
|
||||
|
||||
// TODO: better
|
||||
delete font;
|
||||
font = new Font("/font.frf");
|
||||
|
||||
// Overwrite background white color
|
||||
BG_PALETTE[15+(7*16)] = 0x656A;
|
||||
@ -261,8 +192,6 @@ int main(int argc, char **argv) {
|
||||
dmaFillWords(0xFFFFFFFF, (void*)0x6000040, 8*8); // Top screen
|
||||
dmaFillWords(0xFFFFFFFF, (void*)0x6200040, 8*8); // Bottom screen
|
||||
|
||||
printBorderTop();
|
||||
|
||||
keysSetRepeat(25,5);
|
||||
|
||||
appInited = true;
|
||||
@ -302,34 +231,34 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
fclose(argfile);
|
||||
filename = argarray.at(0);
|
||||
filename = argarray[0];
|
||||
} else {
|
||||
argarray.push_back(strdup(filename.c_str()));
|
||||
}
|
||||
|
||||
if (extension(filename, {"nds", "dsi", "ids", "app", "srl"})) {
|
||||
char *name = argarray.at(0);
|
||||
char *name = argarray[0];
|
||||
strcpy (filePath + pathLen, name);
|
||||
free(argarray.at(0));
|
||||
argarray.at(0) = filePath;
|
||||
consoleClear();
|
||||
iprintf ("Running %s with %d parameters\n", argarray[0], argarray.size());
|
||||
int err = runNdsFile (argarray[0], argarray.size(), (const char **)&argarray[0]);
|
||||
iprintf ("\x1b[31mStart failed. Error %i\n", err);
|
||||
free(argarray[0]);
|
||||
argarray[0] = filePath;
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Running %s with %d parameters\n", argarray[0], argarray.size());
|
||||
int err = runNdsFile(argarray[0], argarray.size(), (const char **)&argarray[0]);
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "Start failed. Error %i\n", err);
|
||||
}
|
||||
|
||||
if (extension(filename, {"firm"})) {
|
||||
char *name = argarray.at(0);
|
||||
char *name = argarray[0];
|
||||
strcpy (filePath + pathLen, name);
|
||||
free(argarray.at(0));
|
||||
argarray.at(0) = filePath;
|
||||
free(argarray[0]);
|
||||
argarray[0] = filePath;
|
||||
fcopy(argarray[0], "sd:/bootonce.firm");
|
||||
fifoSendValue32(FIFO_USER_02, 1); // Reboot into selected .firm payload
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
|
||||
while(argarray.size() !=0 ) {
|
||||
free(argarray.at(0));
|
||||
free(argarray[0]);
|
||||
argarray.erase(argarray.begin());
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
#include "ndsInfo.h"
|
||||
|
||||
#include "date.h"
|
||||
#include "font.h"
|
||||
#include "tonccpy.h"
|
||||
|
||||
#include <nds.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern PrintConsole bottomConsole, bottomConsoleBG, topConsole;
|
||||
|
||||
constexpr const char *langNames[8] {
|
||||
"Japanese",
|
||||
"English",
|
||||
@ -19,8 +18,6 @@ constexpr const char *langNames[8] {
|
||||
"Korean"
|
||||
};
|
||||
|
||||
extern void reinitConsoles(void);
|
||||
|
||||
void ndsInfo(const char *path) {
|
||||
FILE *file = fopen(path, "rb");
|
||||
if(!file)
|
||||
@ -35,7 +32,10 @@ void ndsInfo(const char *path) {
|
||||
u32 ofs;
|
||||
fseek(file, 0x68, SEEK_SET);
|
||||
fread(&ofs, sizeof(u32), 1, file);
|
||||
fseek(file, ofs, SEEK_SET);
|
||||
if(ofs < 0x8000 || fseek(file, ofs, SEEK_SET) != 0) {
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
u16 version;
|
||||
fread(&version, sizeof(u16), 1, file);
|
||||
@ -51,10 +51,13 @@ void ndsInfo(const char *path) {
|
||||
fread(iconAnimation, 2, 0x40, file);
|
||||
|
||||
fseek(file, ofs + 0x240, SEEK_SET);
|
||||
} else { // DS
|
||||
} else if((version & ~3) == 0) { // DS
|
||||
fseek(file, 0x20 - 2, SEEK_CUR);
|
||||
fread(iconBitmap, 1, 0x200, file);
|
||||
fread(iconPalette, 2, 0x10, file);
|
||||
} else {
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
int languages = 5 + (version & 0x3);
|
||||
@ -76,26 +79,23 @@ void ndsInfo(const char *path) {
|
||||
u16 pressed = 0, held = 0;
|
||||
int animationFrame = 0, frameDelay = 0, lang = 1;
|
||||
while(1) {
|
||||
consoleClear();
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Header Title: %s", headerTitle);
|
||||
font->printf(0, 1, false, Alignment::left, Palette::white, "Title ID: %s", tid);
|
||||
font->printf(0, 2, false, Alignment::left, Palette::white, "Title: (%s)", langNames[lang]);
|
||||
font->print(2, 3, false, titles + lang * 0x80);
|
||||
font->update(false);
|
||||
|
||||
iprintf("Header Title: %s\n", headerTitle);
|
||||
iprintf("Title ID: %s\n", tid);
|
||||
iprintf("Title: (%s)\n ", langNames[lang]);
|
||||
for(int j = 0; j < 0x80 && titles[lang * 0x80 + j]; j++) {
|
||||
if(titles[lang * 0x80 + j] == '\n')
|
||||
iprintf("\n ");
|
||||
else
|
||||
iprintf("%c", titles[lang * 0x80 + j]);
|
||||
}
|
||||
iprintf("\n");
|
||||
|
||||
consoleSelect(&topConsole);
|
||||
do {
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
pressed = keysDown();
|
||||
held = keysDownRepeat();
|
||||
iprintf("\x1B[30m\x1B[0;26H %s", RetTime().c_str()); // Print time
|
||||
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
if(iconAnimation[animationFrame] && animationFrame < 0x40) {
|
||||
if(frameDelay < (iconAnimation[animationFrame] & 0xFF) - 1) {
|
||||
frameDelay++;
|
||||
@ -111,7 +111,6 @@ void ndsInfo(const char *path) {
|
||||
}
|
||||
}
|
||||
} while(!held);
|
||||
consoleSelect(&bottomConsole);
|
||||
|
||||
if(held & KEY_UP) {
|
||||
if(lang > 0)
|
||||
|
@ -1,117 +1,129 @@
|
||||
#include <nds.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fat.h>
|
||||
|
||||
#include "screenshot.h"
|
||||
|
||||
#include "bmp.h"
|
||||
#include "driveOperations.h"
|
||||
#include "file_browse.h"
|
||||
#include "font.h"
|
||||
#include "date.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fat.h>
|
||||
#include <nds.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void wait();
|
||||
|
||||
void screenshot(u8* buffer) {
|
||||
void write16(void *address, u16 value) {
|
||||
|
||||
u8 vram_cr_temp=VRAM_A_CR;
|
||||
VRAM_A_CR=VRAM_A_LCD;
|
||||
u8* first = (u8*)address;
|
||||
u8* second = first + 1;
|
||||
|
||||
u8* vram_temp=(u8*)malloc(128*1024);
|
||||
dmaCopy(VRAM_A, vram_temp, 128*1024);
|
||||
*first = value & 0xff;
|
||||
*second = value >> 8;
|
||||
}
|
||||
|
||||
REG_DISPCAPCNT=DCAP_BANK(0)|DCAP_ENABLE|DCAP_SIZE(3);
|
||||
void write32(void *address, u32 value) {
|
||||
|
||||
u8* first = (u8*)address;
|
||||
u8* second = first + 1;
|
||||
u8* third = first + 2;
|
||||
u8* fourth = first + 3;
|
||||
|
||||
*first = value & 0xff;
|
||||
*second = (value >> 8) & 0xff;
|
||||
*third = (value >> 16) & 0xff;
|
||||
*fourth = (value >> 24) & 0xff;
|
||||
}
|
||||
|
||||
bool screenshotbmp(const char* filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
|
||||
if(!file)
|
||||
return false;
|
||||
|
||||
REG_DISPCAPCNT = DCAP_BANK(DCAP_BANK_VRAM_D) | DCAP_SIZE(DCAP_SIZE_256x192) | DCAP_ENABLE;
|
||||
while(REG_DISPCAPCNT & DCAP_ENABLE);
|
||||
|
||||
dmaCopy(VRAM_A, buffer, 256*192*2);
|
||||
dmaCopy(vram_temp, VRAM_A, 128*1024);
|
||||
|
||||
VRAM_A_CR=vram_cr_temp;
|
||||
|
||||
free(vram_temp);
|
||||
u8* temp = new u8[256 * 192 * 2 + sizeof(INFOHEADER) + sizeof(HEADER)];
|
||||
|
||||
}
|
||||
if(!temp) {
|
||||
fclose(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void screenshot(char* filename) {
|
||||
|
||||
//fatInitDefault();
|
||||
FILE* file=fopen(filename, "w");
|
||||
|
||||
u8* temp=(u8*)malloc(256*192*2);
|
||||
dmaCopy(VRAM_B, temp, 256*192*2);
|
||||
fwrite(temp, 1, 256*192*2, file);
|
||||
fclose(file);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
void write16(u16* address, u16 value) {
|
||||
|
||||
u8* first=(u8*)address;
|
||||
u8* second=first+1;
|
||||
|
||||
*first=value&0xff;
|
||||
*second=value>>8;
|
||||
}
|
||||
|
||||
void write32(u32* address, u32 value) {
|
||||
|
||||
u8* first=(u8*)address;
|
||||
u8* second=first+1;
|
||||
u8* third=first+2;
|
||||
u8* fourth=first+3;
|
||||
|
||||
*first=value&0xff;
|
||||
*second=(value>>8)&0xff;
|
||||
*third=(value>>16)&0xff;
|
||||
*fourth=(value>>24)&0xff;
|
||||
}
|
||||
|
||||
void screenshotbmp(const char* filename) {
|
||||
|
||||
//fatInitDefault();
|
||||
FILE* file=fopen(filename, "wb");
|
||||
|
||||
REG_DISPCAPCNT=DCAP_BANK(3)|DCAP_ENABLE|DCAP_SIZE(3);
|
||||
while(REG_DISPCAPCNT & DCAP_ENABLE);
|
||||
|
||||
u8* temp=(u8*)malloc(256*192*3+sizeof(INFOHEADER)+sizeof(HEADER));
|
||||
|
||||
HEADER* header=(HEADER*)temp;
|
||||
INFOHEADER* infoheader=(INFOHEADER*)(temp+sizeof(HEADER));
|
||||
HEADER *header= (HEADER*)temp;
|
||||
INFOHEADER *infoheader = (INFOHEADER*)(temp + sizeof(HEADER));
|
||||
|
||||
write16(&header->type, 0x4D42);
|
||||
write32(&header->size, 256*192*3+sizeof(INFOHEADER)+sizeof(HEADER));
|
||||
write32(&header->offset, sizeof(INFOHEADER)+sizeof(HEADER));
|
||||
write16(&header->reserved1, 0);
|
||||
write16(&header->reserved2, 0);
|
||||
write32(&header->size, 256 * 192 * 2 + sizeof(INFOHEADER) + sizeof(HEADER));
|
||||
write32(&header->reserved1, 0);
|
||||
write32(&header->reserved2, 0);
|
||||
write32(&header->offset, sizeof(INFOHEADER) + sizeof(HEADER));
|
||||
|
||||
write16(&infoheader->bits, 24);
|
||||
write32(&infoheader->size, sizeof(INFOHEADER));
|
||||
write32(&infoheader->compression, 0);
|
||||
write32(&infoheader->width, 256);
|
||||
write32(&infoheader->height, 192);
|
||||
write16(&infoheader->planes, 1);
|
||||
write32(&infoheader->imagesize, 256*192*3);
|
||||
write32(&infoheader->xresolution, 0);
|
||||
write32(&infoheader->yresolution, 0);
|
||||
write32(&infoheader->importantcolours, 0);
|
||||
write16(&infoheader->bits, 16);
|
||||
write32(&infoheader->compression, 3);
|
||||
write32(&infoheader->imagesize, 256 * 192 * 2);
|
||||
write32(&infoheader->xresolution, 2835);
|
||||
write32(&infoheader->yresolution, 2835);
|
||||
write32(&infoheader->ncolours, 0);
|
||||
write32(&infoheader->importantcolours, 0);
|
||||
write32(&infoheader->redBitmask, 0xF800);
|
||||
write32(&infoheader->greenBitmask, 0x07E0);
|
||||
write32(&infoheader->blueBitmask, 0x001F);
|
||||
write32(&infoheader->reserved, 0);
|
||||
|
||||
for(int y=0;y<192;y++)
|
||||
{
|
||||
for(int x=0;x<256;x++)
|
||||
{
|
||||
u16 color=VRAM_D[256*191-y*256+x];
|
||||
|
||||
u8 b=(color&31)<<3;
|
||||
u8 g=((color>>5)&31)<<3;
|
||||
u8 r=((color>>10)&31)<<3;
|
||||
|
||||
temp[((y*256)+x)*3+sizeof(INFOHEADER)+sizeof(HEADER)]=r;
|
||||
temp[((y*256)+x)*3+1+sizeof(INFOHEADER)+sizeof(HEADER)]=g;
|
||||
temp[((y*256)+x)*3+2+sizeof(INFOHEADER)+sizeof(HEADER)]=b;
|
||||
u16 *ptr = (u16*)(temp + sizeof(HEADER) + sizeof(INFOHEADER));
|
||||
for(int y = 0; y < 192; y++) {
|
||||
for(int x = 0; x < 256; x++) {
|
||||
u16 color = VRAM_D[256 * 191 - y * 256 + x];
|
||||
*(ptr++) = ((color >> 10) & 0x1F) | (color & (0x1F << 5)) << 1 | ((color & 0x1F) << 11);
|
||||
}
|
||||
}
|
||||
|
||||
DC_FlushAll();
|
||||
fwrite(temp, 1, 256*192*3+sizeof(INFOHEADER)+sizeof(HEADER), file);
|
||||
fwrite(temp, 1, 256 * 192 * 2 + sizeof(INFOHEADER) + sizeof(HEADER), file);
|
||||
fclose(file);
|
||||
free(temp);
|
||||
delete[] temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool screenshot(void) {
|
||||
if (!(sdMounted || flashcardMounted))
|
||||
return false;
|
||||
|
||||
if (access((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i" : "fat:/gm9i"), 0777);
|
||||
}
|
||||
if (access((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), F_OK) != 0) {
|
||||
mkdir((sdMounted ? "sd:/gm9i/out" : "fat:/gm9i/out"), 0777);
|
||||
}
|
||||
|
||||
std::string fileTimeText = RetTimeForFilename();
|
||||
char snapPath[40];
|
||||
// Take top screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_top.bmp", (sdMounted ? "sd" : "fat"), fileTimeText.c_str());
|
||||
if(!screenshotbmp(snapPath))
|
||||
return false;
|
||||
|
||||
// Seamlessly swap top and bottom screens
|
||||
font->mainOnTop(false);
|
||||
font->update(false);
|
||||
font->update(true);
|
||||
lcdMainOnBottom();
|
||||
|
||||
// Take bottom screenshot
|
||||
snprintf(snapPath, sizeof(snapPath), "%s:/gm9i/out/snap_%s_bot.bmp", (sdMounted ? "sd" : "fat"), fileTimeText.c_str());
|
||||
if(!screenshotbmp(snapPath))
|
||||
return false;
|
||||
|
||||
font->mainOnTop(true);
|
||||
font->update(true);
|
||||
font->update(false);
|
||||
lcdMainOnTop();
|
||||
|
||||
return true;
|
||||
}
|
BIN
data/font_default.frf
Normal file
BIN
data/font_default.frf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user