reading thumbnails

This commit is contained in:
NotImplementedLife 2023-06-18 17:57:23 +03:00
parent 1b0c72e74f
commit f9b88b1223
10 changed files with 375 additions and 27 deletions

View File

@ -35,7 +35,7 @@ ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
LIBS := -lnds7
LIBS := -lfat -lnds7
LIBDIRS := $(LIBNDS)

6
arm7/include/log.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <stdarg.h>
void debug_log(const char* message, ...);

212
arm7/source/log.c Normal file
View File

@ -0,0 +1,212 @@
#include "log.h"
#include <stdarg.h>
// gcc translates inline asm "mov r7,r7" to "add r7, r7, #0"
// so we have to hardcode the intended instruction
#define MOV_R7_R7 ".BYTE 0x3f, 0x46"
#define MOV_R6_R6 ".BYTE 0x36, 0x46"
#define MOV_R5_R5 ".BYTE 0x2D, 0x46"
#define LOG_CODE(MOV_X_X, message) asm volatile \
( \
"push {r6} \r\n" \
"mov r6, %0 \r\n" \
MOV_X_X "\r\n" \
"pop {r6}\r\n" \
:: "r"(message) \
);
#define LOG_BUF 8
#define LOG_MSG 7
#define LOG_WRN 6
#define LOG_ERR 5
char* copy_str(char* dest, const char* src)
{
for(;*src;)
*(dest++) = *(src++);
*dest = '\0';
return dest;
}
__attribute__((target("thumb")))
void _log(int role, const char* message)
{
switch(role)
{
case LOG_MSG:
LOG_CODE(MOV_R7_R7, message); break;
case LOG_WRN:
LOG_CODE(MOV_R6_R6, message); break;
case LOG_ERR:
LOG_CODE(MOV_R5_R5, message); break;
case LOG_BUF:
break;
}
}
static const char* hex_lower = "0123456789abcdef";
static const char* hex_upper = "0123456789ABCDEF";
char result[128];
__attribute__((target("thumb")))
void _logv(int role, char* dest, const char* message, va_list args)
{
char* built = result;
for(const char* msg=message; *msg;)
{
if(*msg=='%')
{
++msg;
if(*msg==0) break;
switch(*msg)
{
case 'i':
{
int val = va_arg(args, int);
if(val==0)
{
*(built++)='0';
++msg;
break;
}
if(val<0)
*(built++)='-', val = -val;
int nzeros = 0;
for(;val%10==0;val/=10) nzeros++;
int temp = 0;
for(;val;val/=10) temp=temp*10 + val%10;
for(;temp;temp/=10) *(built++)='0'+temp%10;
for(;nzeros--;) *(built++)='0';
++msg;
break;
}
case 'u':
{
unsigned int val = va_arg(args, unsigned int);
if(val==0)
{
*(built++)='0';
++msg;
break;
}
int nzeros = 0;
for(;val%10==0;val/=10) nzeros++;
int temp = 0;
for(;val;val/=10) temp=temp*10 + val%10;
for(;temp;temp/=10) *(built++)='0'+temp%10;
for(;nzeros--;) *(built++)='0';
++msg;
break;
}
case 's':
{
char* val = va_arg(args, char*);
while(*val) *(built++)=*(val++);
++msg;
break;
}
case 'b':
{
int val = va_arg(args, int);
if(val)
built = copy_str(built, "T");
else
built = copy_str(built, "F");
++msg;
break;
}
case 'B':
{
int val = va_arg(args, int);
if(val)
built = copy_str(built, "True");
else
built = copy_str(built, "False");
++msg;
break;
}
case 'x':
{
unsigned val = va_arg(args, unsigned);
int num_start = 0;
for(int i=0;i<8;i++)
{
int digit = (val & 0xF0000000)>>28;
val<<=4;
if(!num_start && digit==0)
continue;
num_start = 1;
*(built++) = hex_lower[digit];
}
if(!num_start)
{
*(built++)='0';
}
++msg;
break;
}
case 'X':
{
unsigned val = va_arg(args, unsigned);
int num_start = 0;
for(int i=0;i<8;i++)
{
int digit = (val & 0xF0000000)>>28;
val<<=4;
if(!num_start && digit==0)
continue;
num_start = 1;
*(built++) = hex_upper[digit];
}
if(!num_start)
{
*(built++)='0';
}
++msg;
break;
}
}
}
else
{
*(built++)=*(msg++);
}
}
*(built)='\0';
_log(role, result);
if(role==LOG_BUF)
{
copy_str(dest, result);
}
}
void debug_log(const char* message, ...)
{
va_list args;
va_start(args, message);
_logv(LOG_MSG, 0, message, args);
va_end(args);
}

View File

@ -30,6 +30,7 @@
/// Removed wifi
#include <nds.h>
#include "bottom_screen_power.h"
#include "log.h"
void VblankHandler(void) { }
@ -47,6 +48,10 @@ void powerButtonCB()
int main()
{
/*debug_log("ARM7 EZ");
debug_log("ARM7 EZ");
debug_log("Hello world from ARM7 %i",47);*/
// clear sound registers
dmaFillWords(0, (void*)0x04000400, 0x100);

View File

@ -0,0 +1 @@
-tiles -8bpp -mw8 -mh8

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

View File

@ -10,6 +10,8 @@ private:
int getSoundHeaderOffset() const;
public:
static int peek_only_metadata(const char* filename, void* dest);
unsigned char buffer[1<<20];
int getAnimationDataSize() const;
@ -50,5 +52,6 @@ public:
inline static constexpr int ERR_NULL_ARGUMENT = -1;
inline static constexpr int ERR_FOPEN = -2;
inline static constexpr int ERR_SIZE_EXCEEDED = -3;
inline static constexpr int ERR_READ_COUNT = -4;
};

View File

@ -5,6 +5,7 @@
#include "back_arrow.h"
#include "error_thumbnail.h"
#include "thumbnail_selector.h"
constexpr short torgb15(int rgb24)
{
@ -20,6 +21,7 @@ class LocationViewerScene : public SimpleScene
private:
VwfEngine* vwf = new VwfEngine(Resources::Fonts::default_8x16);
Sprite* back_arrow = nullptr;
Sprite* thumbnail_selector = nullptr;
int dir_len;
char* flipnote_path;
@ -36,6 +38,8 @@ private:
strcpy(file_part_path+j, ".ppm");
}
char ppm_metadata[9][0x6A0];
public:
void init() override
{
@ -51,6 +55,10 @@ public:
back_arrow->add_frame(new ObjFrame(&ROA_back_arrow8,0,0));
back_arrow->set_position(0, 0);
thumbnail_selector = create_sprite(new Sprite(SIZE_64x64, Engine::Main));
thumbnail_selector->add_frame(new ObjFrame(&ROA_thumbnail_selector8,0,0));
thumbnail_selector->set_position(16, 16);
end_sprites_init();
dir_len = strlen(selected_location->path);
@ -64,19 +72,131 @@ public:
{
load_path(i);
Debug::log(flipnote_path);
}
}
total_pages_count = (selected_location->filenames.size()+8)/9;
key_down.add_event(&LocationViewerScene::on_key_down, this);
}
int crt_page=0;
void display_page()
void on_key_down(void*, void* _keys)
{
int keys = (int)_keys;
if(keys & KEY_UP)
{
if(thumbnail_sel_row>0)
thumbnail_sel_row--;
}
else if(keys & KEY_DOWN)
{
if(thumbnail_sel_row<2 && 9*crt_page+3*thumbnail_sel_row+thumbnail_sel_col+3<selected_location->filenames.size())
thumbnail_sel_row++;
}
else if(keys & KEY_LEFT)
{
if(thumbnail_sel_col>0)
thumbnail_sel_col--;
else
{
if(crt_page>0)
{
crt_page--;
thumbnail_sel_col=2;
thumbnail_selector->hide();
frame();
display_page();
thumbnail_selector->show();
}
}
}
else if(keys & KEY_RIGHT)
{
if(thumbnail_sel_col<2 && 9*crt_page+3*thumbnail_sel_row+thumbnail_sel_col+1<selected_location->filenames.size())
thumbnail_sel_col++;
else
{
if(crt_page+1<total_pages_count)
{
crt_page++;
thumbnail_sel_col=0;
while(thumbnail_sel_row>0 && 9*crt_page+3*thumbnail_sel_row+thumbnail_sel_col>=selected_location->filenames.size())
thumbnail_sel_row--;
thumbnail_selector->hide();
frame();
display_page();
thumbnail_selector->show();
}
}
}
}
inline static constexpr int THUMBNAIL_NONE = 0;
inline static constexpr int THUMBNAIL_CORRUPT = 1;
inline static constexpr int THUMBNAIL_READER = 2;
void display_thumbnail(int index, int mode)
{
unsigned short* gfx = bgGetGfxPtr(1) + 16*2 + 48*16*index;
switch(mode)
{
case THUMBNAIL_NONE:
{
volatile short zero = 0;
for(int i=0;i<6*8*16;i++) gfx[i]=zero;
break;
}
case THUMBNAIL_CORRUPT:
{
ROA_error_thumbnail4.extract_gfx(gfx);
break;
}
case THUMBNAIL_READER:
{
volatile short* src = (volatile short*)&ppm_metadata[index][0xA0];
for(int i=0;i<6*8*16;i++) gfx[i]=*(src++);
break;
}
}
}
int total_pages_count = 0;
int crt_page=0;
void display_page()
{
Debug::log("Display page");
int index = crt_page*9;
for(int i=0;i<9;i++)
{
if(index < selected_location->filenames.size())
{
load_path(index++);
Debug::log(flipnote_path);
int status = PPMReader::peek_only_metadata(flipnote_path, &ppm_metadata[i][0]);
Debug::log("Status = %i", status);
if(status<0)
display_thumbnail(i, THUMBNAIL_CORRUPT);
else
display_thumbnail(i, THUMBNAIL_READER);
}
else
{
Debug::log("None %i", i);
display_thumbnail(i, THUMBNAIL_NONE);
}
}
vwf->clear_row(1, Pal4bit);
vwf->set_cursor(1, 90);
vwf->put_text(str_print(page_label, "Page %i of %i", crt_page+1, total_pages_count+1), Pal4bit, SolidColorBrush(0x1));
}
char page_label[32];
int thumbnail_sel_row = 0;
int thumbnail_sel_col = 0;
void frame() override
{
thumbnail_selector->set_position(16+thumbnail_sel_col*80, 16+thumbnail_sel_row*56);
SimpleScene::frame();
}
@ -121,31 +241,16 @@ public:
VwfEngine::prepare_map(*vwf, SUB_BG2, 32, 0, 0, 0x9);
vwf->clear(Pal4bit);
vwf->set_cursor(6, 90);
vwf->put_text("Please wait", Pal4bit, SolidColorBrush(0x1));
volatile short zero = 0;
for(int i=0;i<32*24;i++)
bgGetMapPtr(1)[i]=zero;
bgGetMapPtr(1)[i]=zero;
unsigned short* gfx = bgGetGfxPtr(1);
for(int i=0;i<32*24*16;i++)
{
gfx[i]=zero;
}
gfx+=16*2;
volatile int xx=0x1111;
for(int i=0;i<6*8*9*16;i++)
{
gfx[i]=xx;
}
for(int ty=0;ty<3;ty++)
for(int tx=0;tx<3;tx++)
ROA_error_thumbnail4.extract_gfx(gfx+48*16*(3*ty+tx));
}
int gfxq=2;
@ -163,9 +268,9 @@ public:
}
}
}
}
display_page();
Hardware::MainEngine::objEnable(128, true); // set to 128
Hardware::SubEngine::objEnable(128, true); // set to 128
@ -176,7 +281,9 @@ public:
~LocationViewerScene()
{
key_down.remove_event(&LocationViewerScene::on_key_down, this);
delete vwf;
delete ppm_reader;
}
};

View File

@ -339,8 +339,8 @@ public:
{
soundDisable();
delete[] buffer1;
delete[] buffer2;
delete ppm_reader;
delete[] buffer2;
delete ppm_reader;
free(sound_buffer);
}

View File

@ -6,6 +6,20 @@
static constexpr int frames[] = { 2, 120, 60, 30, 15, 10, 5, 3, 2 };
int PPMReader::peek_only_metadata(const char* filename, void* dest)
{
if(filename==nullptr) return ERR_NULL_ARGUMENT;
FILE* fp=fopen(filename,"rb");
if(fp==nullptr) return ERR_FOPEN;
fseek(fp, 0L, SEEK_SET);
if(fread(dest, sizeof(char), 0x6A0, fp) != 0x6A0)
return ERR_READ_COUNT;
fclose(fp);
return 0;
}
int PPMReader::read_metadata(const char* filename)
{
if(filename==nullptr) return ERR_NULL_ARGUMENT;