tabs, icon & ppm metadata

This commit is contained in:
NotImplementedLife 2021-01-30 17:28:10 +02:00
parent 9aa61ff2ad
commit 6c4075ebbf
10 changed files with 523 additions and 207 deletions

4
.gitignore vendored
View File

@ -1,5 +1,7 @@
.git/
build/
flipnotes-example/
FSPDS.layout
FSPDS.elf
FSPDS.nds
FSPDS.nds
run.bat

View File

@ -33,7 +33,14 @@
<Add option="-Wall" />
</Compiler>
<Unit filename="Makefile" />
<Unit filename="source/main.c"/>
<Unit filename="include/console.h" />
<Unit filename="include/filesystem.h" />
<Unit filename="include/player.h" />
<Unit filename="include/ppm.h" />
<Unit filename="include/tabsystem.h" />
<Unit filename="source/main.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />

View File

@ -21,6 +21,7 @@ SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
@ -92,6 +93,18 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
# THX: https://devkitpro.org/viewtopic.php?t=508
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
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------

BIN
icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

109
include/console.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef FSPDS_CONSOLE_H_INCLUDED
#define FSPDS_CONSOLE_H_INCLUDED
#include <nds.h>
#include <stdio.h>
static PrintConsole consoleBG,consoleFG;
static inline void c_cls()
{
iprintf("\x1b[2J");
}
static inline void c_goto(int row, int column)
{
printf("\033[%d;%dH", row, column);
}
void c_writeFrame()
{
iprintf("\x1b[33m");
c_goto(0,0);
iprintf("\024");
for(int i=1;i<31;i++) iprintf("\004");
iprintf("\022");
for(int i=1;i<23;i++)
{
c_goto(i,0); iprintf("\003");
c_goto(i,31); iprintf("\003");
}
c_goto(23,0);
iprintf("\025");
for(int i=1;i<31;i++) iprintf("\004");
iprintf("\023");
c_goto(23,0);
//for(i=32;i--;) iprintf("\x02");
}
static inline void initConsole()
{
videoSetModeSub(MODE_0_2D);
vramSetBankH(VRAM_H_SUB_BG);
consoleInit(&consoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, false, true);
consoleInit(&consoleFG, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
// overwrite some character fonts
// thanks: https://github.com/DS-Homebrew/GodMode9i/blob/master/arm9/source/main.cpp
dmaFillWords(0xFFFFFFFF, (void*)0x6200040, 32);
dmaFillWords(0x00F00F00, (void*)0x6200060, 32);
dmaFillWords(0x00000000, (void*)0x6200080, 8);
dmaFillWords(0xFFFFFFFF, (void*)0x6200088, 4);
dmaFillWords(0x00000000, (void*)0x620008C, 8);
dmaFillWords(0xFFFFFFFF, (void*)0x6200094, 4);
dmaFillWords(0x00000000, (void*)0x6200098, 8);
dmaFillWords(0x00000000, (void*)0x6200240, 8);
dmaFillWords(0x000FFFFF, (void*)0x6200248, 4);
dmaFillWords(0x00F00000, (void*)0x620024C, 8);
dmaFillWords(0x00F00FFF, (void*)0x6200254, 4);
dmaFillWords(0x00F00F00, (void*)0x6200258, 8);
dmaFillWords(0x00F00F00, (void*)0x6200260, 8);
dmaFillWords(0x00F00FFF, (void*)0x6200268, 4);
dmaFillWords(0x00F00000, (void*)0x620026C, 8);
dmaFillWords(0x000FFFFF, (void*)0x6200274, 4);
dmaFillWords(0x00000000, (void*)0x6200278, 8);
dmaFillWords(0x00000000, (void*)0x6200280, 8);
dmaFillWords(0xFFFFF000, (void*)0x6200288, 4);
dmaFillWords(0x00000F00, (void*)0x620028C, 8);
dmaFillWords(0xFFF00F00, (void*)0x6200294, 4);
dmaFillWords(0x00F00F00, (void*)0x6200298, 8);
dmaFillWords(0x00F00F00, (void*)0x62002A0, 8);
dmaFillWords(0xFFF00F00, (void*)0x62002A8, 4);
dmaFillWords(0x00000F00, (void*)0x62002AC, 8);
dmaFillWords(0xFFFFF000, (void*)0x62002B4, 4);
dmaFillWords(0x00000000, (void*)0x62002B8, 8);
BG_PALETTE[ 0]=BG_PALETTE_SUB[ 0]=0x7FFF;
BG_PALETTE[63]=BG_PALETTE_SUB[63]=0x01DF;
}
// screen to display error messages
bool c_displayError(const char* message,bool isfatal)
{
consoleSelect(&consoleBG); c_cls();
consoleSelect(&consoleFG); c_cls();
c_writeFrame();
c_goto(0,13);
iprintf("ERROR!");
consoleSetWindow(&consoleFG,2,2,28,20);
c_goto(0,0);
iprintf(message);
if(isfatal)
{
exit(-1);
}
consoleSetWindow(&consoleFG,0,0,32,24);
return true;
}
#endif // CONSOLE_H_INCLUDED

202
include/filesystem.h Normal file
View File

@ -0,0 +1,202 @@
#ifndef FSPDS_FILESYSTEM_H_INCLUDED
#define FSPDS_FILESYSTEM_H_INCLUDED
#include <fat.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define MAXFILESCOUNT 1024
int filescount=0;
char files[MAXFILESCOUNT][29];
char sizes[MAXFILESCOUNT][7];
// Converts file size to string ( e.g. 2704 => "2.64KB" )
void long_to_size_string(char dest[7],long sz)
{
dest[5]='B';
dest[6]='\0';
for(int i=0;i<5;i++) dest[i]=' ';
if(sz==0)
{
dest[4]='0';
return;
}
if(sz<1024)
{
for(int i=4;sz>0;i--)
{
dest[i]=(sz%10)+'0';
sz/=10;
}
return;
}
if(sz<1024*1024)
{
sz>>=10;
dest[4]='K';
for(int i=3;sz>0;i--)
{
dest[i]=(sz%10)+'0';
sz/=10;
}
return;
}
dest[4]='M';
sz>>=10;
int q=sz>>10;
int r=((sz&0x3FF)*100)>>10;
if(q>=10)
{
iprintf("Fatal error: size limit exceeded. \n");
exit(-1);
}
if(r>=100) r/=10;
dest[3]=(r%10)+'0';
r/=10;
dest[2]=(r%10)+'0';
dest[1]='.';
dest[0]=q+'0';
}
void loadFiles()
{
if(!fatInitDefault())
{
c_displayError("Fatal :\n\nFAT init failed.",true);
}
DIR *root;
struct dirent *entry;
root=opendir("/flipnotes");
if (root)
{
while((entry=readdir(root))!=NULL && filescount<MAXFILESCOUNT)
{
if(strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
continue;
if(entry->d_type != DT_DIR)
{
if(strlen(entry->d_name)==28 && strcmp(".ppm",entry->d_name+24)==0)
{
strcpy(files[filescount],entry->d_name);
char fn[40]="/flipnotes/";
strcat(fn,entry->d_name);
FILE* fp=fopen(fn,"rb");
fseek(fp,0L,SEEK_END);
long_to_size_string(sizes[filescount],ftell(fp));
fclose(fp);
filescount++;
}
}
}
closedir(root);
}
else
{
c_displayError("Fatal :\n\nOpen directory failed.\n\nMake sure the /flipnotes\ndirectory exists on the rootof your SD card.",true);
}
}
// UI
void writeEntry(int i,int listpos, bool highlight)
{
if(i>=filescount)
{
consoleSelect(&consoleFG);
for(int i=0;i<3-2*(listpos==7);i++)
{
c_goto(1+3*listpos+i,1);
for(int j=1;j<31;j++) iprintf(" ");
}
consoleSelect(&consoleBG);
for(int i=0;i<3-2*(listpos==7);i++)
{
c_goto(1+3*listpos+i,1);
for(int j=1;j<31;j++) iprintf(" ");
}
return;
}
consoleSelect(&consoleBG);
iprintf(highlight?"\x1b[33m":"\x1b[39m");
for(int i=0;i<3;i++)
{
c_goto(1+3*listpos+i,1);
for(int j=0;j<30;j++) iprintf("\x02");
}
consoleSelect(&consoleFG);
c_goto(1+3*listpos,2);
iprintf(highlight?"\x1b[39m":"\x1b[33m");
iprintf(files[i]);
if(listpos==7) return;
c_goto(2+3*listpos,20);
iprintf(sizes[i]);
}
int PagesCount, PageSelection=0, CurrentPage=0;
void writePage()
{
for(int i=0;i<8;i++)
{
writeEntry(7*CurrentPage+i,i,i==PageSelection);
}
}
void nextPage()
{
if(CurrentPage+1>=PagesCount)
return;
CurrentPage++;
PageSelection=0;
writePage();
}
void prevPage()
{
if(CurrentPage==0)
return;
CurrentPage--;
PageSelection=0;
writePage();
}
void nextEntry()
{
int id=7*CurrentPage+PageSelection;
if(id+1==filescount)
return;
if(PageSelection==6)
{
CurrentPage++;
PageSelection=0;
writePage();
}
else
{
writeEntry(id++,PageSelection++,false);
writeEntry(id ,PageSelection ,true);
}
}
void prevEntry()
{
int id=7*CurrentPage+PageSelection;
if(id==0)
return;
if(PageSelection==0)
{
CurrentPage--;
PageSelection=6;
writePage();
}
else
{
writeEntry(id--,PageSelection--,false);
writeEntry(id ,PageSelection ,true);
}
}
#endif // FSPDS_FILESYSTEM_H_INCLUDED

17
include/player.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef FSPDS_PLAYER_H_INCLUDED
#define FSPDS_PLAYER_H_INCLUDED
#include <nds.h>
u16* mainGFX;
void initPlayer()
{
vramSetBankA(VRAM_A_LCD);
videoSetMode(MODE_FB0);
mainGFX = bgGetGfxPtr(bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0,0));
}
#endif // FSPDS_PLAYER_H_INCLUDED

44
include/ppm.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef FSPDS_PPM_H_INCLUDED
#define FSPDS_PPM_H_INCLUDED
#include "filesystem.h"
char ppmHead_Magic[5]="NULL";
u32 ppmHead_AnimationDataSize;
u32 ppmHead_SoundDataSize;
u16 ppmHead_FrameCount;
u16 ppmHead_FormatVersion;
u16 ppmMeta_Lock;
u16 ppmMeta_ThumbnailFrameIndex;
u8 ppmMeta_ParentAuthorId[8];
u8 ppmMeta_CurrentAuthorId[8];
u8 ppmMeta_RootAuthorId[8];
u32 ppmMeta_Timestamp;
void ppm_loadMetadata()
{
int index=7*CurrentPage+PageSelection;
char fn[40]="/flipnotes/";
strcat(fn,files[index]);
FILE* fp=fopen(fn,"rb");
// Parse head
fread(ppmHead_Magic,4,1,fp); ppmHead_Magic[4]=0;
fread(&ppmHead_AnimationDataSize,sizeof(u32),1,fp);
fread(&ppmHead_SoundDataSize,sizeof(u32),1,fp);
fread(&ppmHead_FrameCount,sizeof(u16),1,fp); ppmHead_FrameCount++;
fread(&ppmHead_FormatVersion,sizeof(u16),1,fp);
// Parse meta
fread(&ppmMeta_Lock,sizeof(u16),1,fp);
fread(&ppmMeta_ThumbnailFrameIndex,sizeof(u16),1,fp);
// skip author names until i find out how to read wide chars
fseek(fp,66,SEEK_CUR);
fread(ppmMeta_ParentAuthorId,8,1,fp);
fread(ppmMeta_CurrentAuthorId,8,1,fp);
fseek(fp,36,SEEK_CUR); // skip filenames - redundant data
fread(ppmMeta_RootAuthorId,8,1,fp);
fread(&ppmMeta_Timestamp,sizeof(u32),1,fp);
fclose(fp);
}
#endif // FSPDS_PPM_H_INCLUDED

83
include/tabsystem.h Normal file
View File

@ -0,0 +1,83 @@
#ifndef FSPDS_TABSYSTEM_H_INCLUDED
#define FSPDS_TABSYSTEM_H_INCLUDED
#include "console.h"
#include "ppm.h"
struct ConsoleTab
{
struct ConsoleTab* left;
struct ConsoleTab* right;
void (*loadingProc)();
void (*drawingProc)();
void (*keyDownProc)(uint32);
};
struct ConsoleTab* CurrentTab;
struct ConsoleTab FilesTab;
struct ConsoleTab InfoTab;
void TabNoAction() { }
void FilesTabDrawing()
{
consoleSelect(&consoleBG); c_cls();
consoleSelect(&consoleFG); c_cls();
c_writeFrame();
c_goto(0,13);
iprintf("Files");
writePage();
}
void FilesTabKeyDown(uint32 input)
{
if(input & KEY_RIGHT)
nextPage();
else if(input & KEY_LEFT)
prevPage();
else if(input & KEY_DOWN)
nextEntry();
else if(input & KEY_UP)
prevEntry();
}
void InfoTabLoading()
{
ppm_loadMetadata();
}
void InfoTabDrawing()
{
consoleSelect(&consoleBG); c_cls();
consoleSelect(&consoleFG); c_cls();
c_writeFrame();
c_goto(0,14);
iprintf("Info");
c_goto(1,2);
iprintf(files[7*CurrentPage+PageSelection]);
c_goto(2,1);
iprintf("Frames count: %i",ppmHead_FrameCount);
c_goto(3,1);
iprintf("Lock : ");
iprintf(ppmMeta_Lock==1?"YES":"NO");
}
void initTabs()
{
FilesTab.loadingProc=TabNoAction;
FilesTab.drawingProc=FilesTabDrawing;
FilesTab.keyDownProc=FilesTabKeyDown;
FilesTab.left=FilesTab.right=&InfoTab;
InfoTab.loadingProc=InfoTabLoading;
InfoTab.drawingProc=InfoTabDrawing;
InfoTab.keyDownProc=TabNoAction;
InfoTab.left=InfoTab.right=&FilesTab;
CurrentTab=&FilesTab;
}
#endif // FSPDS_TABSYSTEM_H_INCLUDED

View File

@ -1,220 +1,59 @@
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define MAXFILESCOUNT 1024
int filescount=0;
char files[MAXFILESCOUNT][29];
char sizes[MAXFILESCOUNT][7];
PrintConsole consoleBG,console;
void long_to_size_string(char dest[7],long sz)
{
dest[5]='B';
dest[6]='\0';
for(int i=0;i<5;i++) dest[i]=' ';
if(sz==0)
{
dest[4]='0';
return;
}
if(sz<1024)
{
for(int i=4;sz>0;i--)
{
dest[i]=(sz%10)+'0';
sz/=10;
}
return;
}
if(sz<1024*1024)
{
sz>>=10;
dest[4]='K';
for(int i=3;sz>0;i--)
{
dest[i]=(sz%10)+'0';
sz/=10;
}
return;
}
dest[4]='M';
sz>>=10;
int q=sz>>10;
int r=((sz&0x3FF)*100)>>10;
if(q>=10)
{
iprintf("Fatal error: size limit exceeded. \n");
exit(-1);
}
if(r>=100) r/=10;
dest[3]=(r%10)+'0';
r/=10;
dest[2]=(r%10)+'0';
dest[1]='.';
dest[0]=q+'0';
}
void loadFiles()
{
if(!fatInitDefault())
{
iprintf("Fatal error: FAT init failed.\n");
exit(-1);
}
DIR *root;
struct dirent *entry;
root=opendir("/flipnotes");
if (root)
{
while((entry=readdir(root))!=NULL && filescount<MAXFILESCOUNT)
{
if(strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
continue;
if(entry->d_type != DT_DIR)
{
if(strlen(entry->d_name)==28 && strcmp(".ppm",entry->d_name+24)==0)
{
strcpy(files[filescount],entry->d_name);
char fn[40]="/flipnotes/";
strcat(fn,entry->d_name);
FILE* fp=fopen(fn,"rb");
fseek(fp,0L,SEEK_END);
long_to_size_string(sizes[filescount],ftell(fp));
fclose(fp);
filescount++;
}
}
}
closedir(root);
}
else
{
iprintf ("Fatal error: Open directory failed.\n");
}
}
void c_cls()
{
//iprintf("\e[1;1H\e[2J");
iprintf("\x1b[2J");
}
void c_goto(int row, int column)
{
printf("\033[%d;%dH", row, column);
}
void writeFrame()
{
int i;
iprintf("\x1b[33m");
c_goto(0,0);
iprintf("\024");
for(int i=1;i<31;i++) iprintf("\004");
iprintf("\022");
for(int i=1;i<23;i++)
{
c_goto(i,0); iprintf("\003");
c_goto(i,31); iprintf("\003");
}
c_goto(23,0);
iprintf("\025");
for(int i=1;i<31;i++) iprintf("\004");
iprintf("\023");
c_goto(23,0);
//for(i=32;i--;) iprintf("\x02");
}
void writeEntry(int i,int listpos)
{
consoleSelect(&consoleBG);
for(int i=0;i<3;i++)
{
c_goto(1+3*listpos+i,1);
for(int j=0;j<30;j++) iprintf("\x1b[33m\x02");
}
consoleSelect(&console);
c_goto(1+3*listpos,2);
iprintf("\x1b[39m%s",files[i]);
c_goto(2+3*listpos,20);
iprintf("\x1b[39m%s",sizes[i]);
//iprintf(" %s\n\t\t\t\t\t\t\t%s\n",files[i],sizes[i]);
}
void init()
{
//thanks: https://github.com/DS-Homebrew/GodMode9i/blob/master/arm9/source/main.cpp
videoSetModeSub(MODE_0_2D);
vramSetBankH(VRAM_H_SUB_BG);
consoleInit(&consoleBG, 1, BgType_Text4bpp, BgSize_T_256x256, 7, 0, false, true);
consoleInit(&console, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true);
// overwrite character fonts
dmaFillWords(0xFFFFFFFF, (void*)0x6200040, 32);
dmaFillWords(0x00F00F00, (void*)0x6200060, 32);
dmaFillWords(0x00000000, (void*)0x6200080, 8);
dmaFillWords(0xFFFFFFFF, (void*)0x6200088, 4);
dmaFillWords(0x00000000, (void*)0x620008C, 8);
dmaFillWords(0xFFFFFFFF, (void*)0x6200094, 4);
dmaFillWords(0x00000000, (void*)0x6200098, 8);
dmaFillWords(0x00000000, (void*)0x6200240, 8);
dmaFillWords(0x00FFFFFF, (void*)0x6200248, 4);
dmaFillWords(0x00F00000, (void*)0x620024C, 8);
dmaFillWords(0x00F00FFF, (void*)0x6200254, 4);
dmaFillWords(0x00F00F00, (void*)0x6200258, 8);
dmaFillWords(0x00F00F00, (void*)0x6200260, 8);
dmaFillWords(0x00F00FFF, (void*)0x6200268, 4);
dmaFillWords(0x00F00000, (void*)0x620026C, 8);
dmaFillWords(0x00FFFFFF, (void*)0x6200274, 4);
dmaFillWords(0x00000000, (void*)0x6200278, 8);
dmaFillWords(0x00000000, (void*)0x6200280, 8);
dmaFillWords(0xFFFFFF00, (void*)0x6200288, 4);
dmaFillWords(0x00000F00, (void*)0x620028C, 8);
dmaFillWords(0xFFF00F00, (void*)0x6200294, 4);
dmaFillWords(0x00F00F00, (void*)0x6200298, 8);
dmaFillWords(0x00F00F00, (void*)0x62002A0, 8);
dmaFillWords(0xFFF00F00, (void*)0x62002A8, 4);
dmaFillWords(0x00000F00, (void*)0x62002AC, 8);
dmaFillWords(0xFFFFFF00, (void*)0x62002B4, 4);
dmaFillWords(0x00000000, (void*)0x62002B8, 8);
BG_PALETTE[ 0]=BG_PALETTE_SUB[ 0]=0x7FFF;
BG_PALETTE[63]=BG_PALETTE_SUB[63]=0x01DF;
}
#include "console.h"
#include "filesystem.h"
#include "player.h"
#include "tabsystem.h"
int main(int argc, char **argv)
{
init();
//loadFiles();
initConsole();
initTabs();
initPlayer();
writeFrame();
//c_cls();
filescount=2;
strcpy(files[0],"000000_0000000000000_000.ppm");
strcpy(sizes[0]," 127KB");
strcpy(files[1],"000001_0000000000000_001.ppm");
strcpy(sizes[1]," 13B");
loadFiles();
/**filescount=25;
char* fname=(char*)malloc(29*sizeof(char));
char* fsize=(char*)malloc(7*sizeof(char));
for(int i=0;i<filescount;i++)
{
writeEntry(i,i);
sprintf(fname,"000000_0000000000000_%03d.ppm",i);
long_to_size_string(fsize,rand()%(1<<20));
strcpy(files[i],fname);
strcpy(sizes[i],fsize);
}
*/
while(1) {
PagesCount=filescount/7;
if(filescount%7>0)
PagesCount++;
CurrentTab->drawingProc();
while(1)
{
swiWaitForVBlank();
scanKeys();
if(keysDown()&KEY_START) break;
uint32 input=keysDown();
if(input & KEY_L)
{
CurrentTab=CurrentTab->left;
CurrentTab->loadingProc();
CurrentTab->drawingProc();
}
else if (input & KEY_R)
{
CurrentTab=CurrentTab->right;
CurrentTab->loadingProc();
CurrentTab->drawingProc();
}
else
{
CurrentTab->keyDownProc(input);
}
}
return 0;