Initial commit: FT812 Viewer (reworked - no .XM/.XMZ)
Wild Commander plugin for JPG/PNG/DLS/DXP/AVI via the FT812 (EVE) chip. XM/XMZ support (and the ESP32 audio-playback code it needed) has been removed here so this plugin can be installed alongside xmplay (https://git.alexkorochinskiy.ru/alex/xmplayer.git) without both registering for the same extensions - see README.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+456
@@ -0,0 +1,456 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <defs.h>
|
||||
#include <sdklib.h>
|
||||
#include <ft812.h>
|
||||
#include <ft812lib.h>
|
||||
#include <tslib.h>
|
||||
#include <wc_api.h>
|
||||
#include "tsconf.h"
|
||||
|
||||
#include <wc_api.c>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 sig[3];
|
||||
u8 type;
|
||||
u16 xs;
|
||||
u16 ys;
|
||||
} DXP;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 sig;
|
||||
u16 len;
|
||||
u8 prec;
|
||||
u8 ys[2];
|
||||
u8 xs[2];
|
||||
} SOF;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 sig;
|
||||
u8 xs[4];
|
||||
u8 ys[4];
|
||||
u8 bits;
|
||||
u8 ctype;
|
||||
} IHDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 len;
|
||||
u32 sig;
|
||||
} tRNS;
|
||||
|
||||
// const is to get rid of vars runtime init - const located in RAM anyway
|
||||
const u8 state_ft = 0;
|
||||
|
||||
#define FS_BUF_SIZE 0x1000
|
||||
u8 fs_buf[FS_BUF_SIZE]; // at 0xAE00 (_PAGE2 to get page)
|
||||
u8 cmdl[0x180];
|
||||
|
||||
u16 ret_sp;
|
||||
u32 filesize;
|
||||
u8 file_ext;
|
||||
u8 call_type;
|
||||
|
||||
// --- Extensions ---------------------------
|
||||
enum
|
||||
{
|
||||
EXT_JPG,
|
||||
EXT_PNG,
|
||||
EXT_DLS,
|
||||
EXT_DXP,
|
||||
EXT_AVI,
|
||||
};
|
||||
|
||||
// --- Windows ------------------------------
|
||||
const WC_TX_WINDOW err_no_ft =
|
||||
{
|
||||
/* window with header and text */ WC_WIND_HDR_TXT,
|
||||
/* cursor color mask */ 0,
|
||||
/* X,Y (position) */ 24, 10,
|
||||
/* W,H (size) */ 32, 5,
|
||||
/* paper/ink (window color) */ 0x2F,
|
||||
/* -reserved- */ 0,
|
||||
/* window restore buffer address */ 0,
|
||||
/* separators */ 0, 0,
|
||||
/* header text */ "\x0E" " Error! ",
|
||||
/* footer text */ "",
|
||||
/* window text */ "\x0E\x0C\x01" "No VDAC2 detected!",
|
||||
};
|
||||
|
||||
const WC_TX_WINDOW win_about =
|
||||
{
|
||||
/* window with header and text */ WC_WIND_HDR_TXT,
|
||||
/* cursor color mask */ 0,
|
||||
/* X,Y (position) */ 22, 10,
|
||||
/* W,H (size) */ 36, 5,
|
||||
/* paper/ink (window color) */ 0x4F,
|
||||
/* -reserved- */ 0,
|
||||
/* window restore buffer address */ 0,
|
||||
/* separators */ 0, 0,
|
||||
/* header text */ "\x0E" " About ",
|
||||
/* footer text */ "",
|
||||
/* window text */ "\x0E\x0C\x01" "FT812 Viewer v1.2, (c)2024 TSL"
|
||||
};
|
||||
|
||||
// --- FT812 --------------------------------
|
||||
bool vdac2_init()
|
||||
{
|
||||
if ((ts_rreg(TS_STATUS) & 7) != 7)
|
||||
return false;
|
||||
|
||||
ft_init(FT_MODE_1024_768_59);
|
||||
return ft_rreg8(FT_REG_ID) == 0x7C;
|
||||
}
|
||||
|
||||
void show_jpg_png(u8 is_jpg)
|
||||
{
|
||||
u32 sz = filesize;
|
||||
u16 xs = 1024; u16 ys = 768;
|
||||
u8 fmt = FT_RGB565;
|
||||
u16 ofs = 0;
|
||||
|
||||
wc_vmode(0x87);
|
||||
wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
|
||||
if (is_jpg) // JPEG
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (FS_BUF_SIZE - sizeof(SOF)); i++)
|
||||
{
|
||||
SOF *sof = (SOF*)&fs_buf[i];
|
||||
|
||||
if ((sof->sig & 0xF0FF) == 0xC0FF) // SOFn
|
||||
{
|
||||
xs = ((u16)sof->xs[0] << 8) + sof->xs[1];
|
||||
ys = ((u16)sof->ys[0] << 8) + sof->ys[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // PNG
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (FS_BUF_SIZE - sizeof(IHDR)); i++)
|
||||
{
|
||||
IHDR *ihdr = (IHDR*)&fs_buf[i];
|
||||
|
||||
if (ihdr->sig == 0x52444849)
|
||||
{
|
||||
xs = ((u16)ihdr->xs[2] << 8) + ihdr->xs[3];
|
||||
ys = ((u16)ihdr->ys[2] << 8) + ihdr->ys[3];
|
||||
|
||||
switch (ihdr->ctype)
|
||||
{
|
||||
case 0:
|
||||
fmt = FT_L8;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fmt = FT_PALETTED565;
|
||||
ofs = 512;
|
||||
|
||||
for (i = 0; i < (FS_BUF_SIZE - sizeof(tRNS)); i++)
|
||||
{
|
||||
tRNS *trns = (tRNS*)&fs_buf[i];
|
||||
|
||||
if ((trns->len == 0x01000000) && (trns->sig == 0x534E5274))
|
||||
{
|
||||
fmt = FT_PALETTED4444;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
fmt = FT_ARGB4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ft_ccmd_start(cmdl);
|
||||
ft_Dlstart();
|
||||
ft_Clear(1, 1, 1);
|
||||
if (ofs) ft_PaletteSource(FT_RAM_G);
|
||||
ft_SetBitmap(FT_RAM_G + ofs, fmt, xs, ys);
|
||||
ft_Begin(FT_BITMAPS);
|
||||
ft_Vertex2ii((1024 - min(1024, xs)) >> 1, (768 - min(768, ys)) >> 1, 0, 0);
|
||||
ft_Display();
|
||||
ft_ccmd(FT_CCMD_SWAP);
|
||||
ft_LoadImage(FT_RAM_G, FT_OPT_NODL);
|
||||
ft_ccmd_write();
|
||||
|
||||
while (sz)
|
||||
{
|
||||
u16 s;
|
||||
s = min(sz, FS_BUF_SIZE);
|
||||
if (!ft_load_cfifo(fs_buf, s)) return;
|
||||
sz -= s;
|
||||
if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
}
|
||||
ft_cp_wait();
|
||||
}
|
||||
|
||||
void show_dxp()
|
||||
{
|
||||
u32 sz, o;
|
||||
u16 xo, yo;
|
||||
DXP *d;
|
||||
|
||||
wc_vmode(0x87);
|
||||
wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
|
||||
sz = filesize - sizeof(DXP);
|
||||
d = (DXP*)fs_buf;
|
||||
o = (u32)d->xs * ((u32)d->ys >> 2);
|
||||
xo = (1024 - d->xs) >> 1;
|
||||
yo = (768 - d->ys) >> 1;
|
||||
|
||||
ft_ccmd_start(cmdl);
|
||||
ft_Dlstart();
|
||||
ft_Clear(1, 1, 1);
|
||||
// ft_ccmd(ft_SaveContext());
|
||||
|
||||
ft_BitmapHandle(0);
|
||||
ft_SetBitmap(FT_RAM_G + o, FT_L2, d->xs, d->ys);
|
||||
ft_BitmapHandle(1);
|
||||
ft_SetBitmap(FT_RAM_G, FT_RGB565, d->xs >> 2, d->ys >> 2);
|
||||
ft_BitmapSize(FT_NEAREST, FT_BORDER, FT_BORDER, d->xs, d->ys);
|
||||
|
||||
ft_Begin(FT_BITMAPS);
|
||||
ft_ColorA(255);
|
||||
ft_BlendFunc(FT_ONE, FT_ZERO);
|
||||
ft_Vertex2ii(xo, yo, 0, 0);
|
||||
|
||||
ft_ColorMask(1, 1, 1, 0);
|
||||
ft_BitmapTransformA(64);
|
||||
ft_BitmapTransformE(64);
|
||||
ft_BlendFunc(FT_ONE_MINUS_DST_ALPHA, FT_ZERO);
|
||||
ft_Vertex2ii(xo, yo, 1, 0);
|
||||
ft_BlendFunc(FT_DST_ALPHA, FT_ONE);
|
||||
ft_Vertex2ii(xo, yo, 1, 1);
|
||||
|
||||
// ft_RestoreContext();
|
||||
// ft_SetBase(10);
|
||||
// ft_Number(0, 0, 18, 0, filesize);
|
||||
|
||||
ft_Display();
|
||||
ft_ccmd(FT_CCMD_SWAP);
|
||||
ft_ccmd_write();
|
||||
ft_cp_wait();
|
||||
|
||||
{
|
||||
u8 *bptr = fs_buf + sizeof(DXP);
|
||||
u16 bsz = FS_BUF_SIZE - sizeof(DXP);
|
||||
|
||||
if (d->type == 0)
|
||||
{
|
||||
u32 gptr = FT_RAM_G;
|
||||
|
||||
while (sz)
|
||||
{
|
||||
u16 s = min(sz, bsz);
|
||||
ft_write(bptr, gptr, s);
|
||||
gptr += s, sz -= s, bptr = fs_buf, bsz = FS_BUF_SIZE;
|
||||
|
||||
if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ft_ccmd_start(cmdl);
|
||||
ft_Inflate(FT_RAM_G);
|
||||
ft_ccmd_write();
|
||||
|
||||
while (sz)
|
||||
{
|
||||
u16 s = min(sz, bsz);
|
||||
if (!ft_load_cfifo(bptr, s)) return;
|
||||
sz -= s, bptr = fs_buf, bsz = FS_BUF_SIZE;
|
||||
|
||||
if (sz) wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
}
|
||||
|
||||
ft_cp_wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_dls()
|
||||
{
|
||||
wc_vmode(0x87);
|
||||
wc_load512(fs_buf, FS_BUF_SIZE >> 9);
|
||||
ft_write_dl(fs_buf, filesize >> 2);
|
||||
ft_wreg8(FT_REG_DLSWAP, FT_DLSWAP_FRAME);
|
||||
}
|
||||
|
||||
void show_avi()
|
||||
{
|
||||
u32 sz = filesize;
|
||||
|
||||
wc_vmode(0x87);
|
||||
|
||||
ft_wreg32(FT_REG_FREQUENCY, 64000000UL);
|
||||
|
||||
ft_ccmd_start(cmdl);
|
||||
ft_Dlstart();
|
||||
ft_ClearColorRGB(128, 128, 160);
|
||||
ft_Clear(1, 1, 1);
|
||||
ft_Display();
|
||||
ft_ccmd(FT_CCMD_SWAP);
|
||||
ft_ccmd_write();
|
||||
ft_cp_wait();
|
||||
// delay(50000);
|
||||
|
||||
#define CHUNK_SIZE 4096
|
||||
#define FIFO_ADDR 0x080000
|
||||
#define FIFO_SIZE 0x080000
|
||||
|
||||
ft_MediaFifo(FIFO_ADDR, FIFO_SIZE);
|
||||
ft_ccmd_write();
|
||||
ft_cp_wait();
|
||||
|
||||
u32 waddr = FIFO_ADDR;
|
||||
while (waddr < (FIFO_ADDR + FIFO_SIZE - CHUNK_SIZE))
|
||||
{
|
||||
wc_load512(fs_buf, CHUNK_SIZE >> 9);
|
||||
ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, waddr, CHUNK_SIZE);
|
||||
waddr += CHUNK_SIZE;
|
||||
}
|
||||
|
||||
ft_PlayVideo(OPT_FULLSCREEN | OPT_SOUND | OPT_MEDIAFIFO | OPT_NOTEAR);
|
||||
ft_ccmd_write();
|
||||
|
||||
while (sz)
|
||||
{
|
||||
ft_wreg32(REG_MEDIAFIFO_WRITE, waddr);
|
||||
|
||||
wc_load512(fs_buf, CHUNK_SIZE >> 9);
|
||||
|
||||
while (1)
|
||||
{
|
||||
u32 raddr = ft_rreg32(REG_MEDIAFIFO_READ);
|
||||
u32 free = FIFO_SIZE - ((waddr >= raddr) ? (waddr - raddr) : (FIFO_SIZE - (raddr - waddr)));
|
||||
if (free >= CHUNK_SIZE) break;
|
||||
}
|
||||
|
||||
ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, waddr, CHUNK_SIZE);
|
||||
waddr += CHUNK_SIZE;
|
||||
if (waddr >= (FIFO_ADDR + FIFO_SIZE)) waddr = FIFO_ADDR;
|
||||
}
|
||||
|
||||
// ft_cp_wait_free(CHUNK_SIZE);
|
||||
// u16 s = min(sz, CHUNK_SIZE);
|
||||
// wc_load512(fs_buf, CHUNK_SIZE >> 9);
|
||||
// ft_load_ram_dma(fs_buf, *(u8*)_PAGE2, s);
|
||||
// sz -= s;
|
||||
}
|
||||
|
||||
// --- Aux functions ------------------------
|
||||
void wait_esc_key()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
__asm
|
||||
halt
|
||||
__endasm;
|
||||
|
||||
if (wc_api__bool(_ESC))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void about()
|
||||
{
|
||||
wc_api_u16(_PRWOW, (u16)&win_about);
|
||||
wait_esc_key();
|
||||
wc_api_u16(_RRESB, (u16)&win_about);
|
||||
wc_exit(WC_EXIT);
|
||||
}
|
||||
|
||||
void error_ft()
|
||||
{
|
||||
wc_api_u16(_PRWOW, (u16)&err_no_ft);
|
||||
wait_esc_key();
|
||||
wc_api_u16(_RRESB, (u16)&err_no_ft);
|
||||
wc_exit(WC_EXIT);
|
||||
}
|
||||
|
||||
void main_start()
|
||||
{
|
||||
if (!state_ft)
|
||||
*(u8*)&state_ft = vdac2_init() ? 1 : 2;
|
||||
|
||||
if (state_ft != 1)
|
||||
error_ft();
|
||||
|
||||
else switch (file_ext)
|
||||
{
|
||||
case EXT_JPG:
|
||||
case EXT_PNG:
|
||||
show_jpg_png(file_ext == EXT_JPG);
|
||||
break;
|
||||
|
||||
case EXT_DXP:
|
||||
show_dxp();
|
||||
break;
|
||||
|
||||
case EXT_DLS:
|
||||
show_dls();
|
||||
break;
|
||||
|
||||
case EXT_AVI:
|
||||
show_avi();
|
||||
break;
|
||||
}
|
||||
|
||||
// poll keys
|
||||
while (1)
|
||||
{
|
||||
__asm
|
||||
halt
|
||||
__endasm;
|
||||
|
||||
if (wc_api__bool(_PGD)) // PgDn - next file
|
||||
wc_exit(WC_NEXT_FILE);
|
||||
|
||||
if (wc_api__bool(_PGU)) // PgUp - previous file
|
||||
wc_exit(WC_PREV_FILE);
|
||||
|
||||
if (wc_api__bool(_ESC)) // Esc - exit
|
||||
wc_exit(WC_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
void main()
|
||||
{
|
||||
__asm
|
||||
ld (_ret_sp), sp
|
||||
ld (_call_type), a
|
||||
ex af, af
|
||||
ld (_file_ext), a
|
||||
ld (_filesize), hl
|
||||
ld (_filesize + 2), de
|
||||
__endasm;
|
||||
|
||||
switch (call_type)
|
||||
{
|
||||
case WC_CALL_EXT:
|
||||
main_start();
|
||||
break;
|
||||
|
||||
case WC_CALL_MENU:
|
||||
about();
|
||||
break;
|
||||
|
||||
default:
|
||||
wc_exit(WC_EXIT);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user