Support for loadable Shadow Masks.

This commit is contained in:
Sorgelig
2021-11-26 14:46:38 +08:00
parent 173d23ddc7
commit 4cee9159d0
9 changed files with 345 additions and 98 deletions

View File

@@ -177,3 +177,10 @@ bt_auto_disconnect=0
; Some dongles (mostly CSR) have problem to pair with BLE if not reset in advance.
; Consequence of reset: some input devices get shutdown after reset.
bt_reset_before_pair=0
;default Shadow Mask
;shmask_default=VGA.txt
;default shadow mask mode:
; 0 - none, 1 - 1x, 2 - 2x, 3 - 1x Rotated, 4 - 2x Rotated
;shmask_mode_default=1

View File

@@ -83,6 +83,8 @@ static const ini_var_t ini_vars[] =
{ "SPINNER_THROTTLE", (void*)(&(cfg.spinner_throttle)), INT32, -10000, 10000 },
{ "AFILTER_DEFAULT", (void*)(&(cfg.afilter_default)), STRING, 0, sizeof(cfg.afilter_default) - 1 },
{ "VFILTER_DEFAULT", (void*)(&(cfg.vfilter_default)), STRING, 0, sizeof(cfg.vfilter_default) - 1 },
{ "SHMASK_DEFAULT", (void*)(&(cfg.shmask_default)), STRING, 0, sizeof(cfg.shmask_default) - 1 },
{ "SHMASK_MODE_DEFAULT", (void*)(&(cfg.shmask_mode_default)), UINT8, 0, 255 },
{ "LOG_FILE_ENTRY", (void*)(&(cfg.log_file_entry)), UINT8, 0, 1 },
{ "BT_AUTO_DISCONNECT", (void*)(&(cfg.bt_auto_disconnect)), UINT32, 0, 180 },
{ "BT_RESET_BEFORE_PAIR", (void*)(&(cfg.bt_reset_before_pair)), UINT8, 0, 1 },

2
cfg.h
View File

@@ -53,6 +53,7 @@ typedef struct {
uint8_t browse_expand;
uint8_t logo;
uint8_t log_file_entry;
uint8_t shmask_mode_default;
int bt_auto_disconnect;
int bt_reset_before_pair;
char bootcore[256];
@@ -64,6 +65,7 @@ typedef struct {
char custom_aspect_ratio[2][16];
char afilter_default[1023];
char vfilter_default[1023];
char shmask_default[1023];
} cfg_t;
extern cfg_t cfg;

View File

@@ -1769,3 +1769,65 @@ bool isMraName(char *path)
return (spl && !strcmp(spl, ".mra"));
}
fileTextReader::fileTextReader()
{
buffer = nullptr;
}
fileTextReader::~fileTextReader()
{
if( buffer != nullptr )
{
free(buffer);
}
buffer = nullptr;
}
bool FileOpenTextReader( fileTextReader *reader, const char *filename )
{
fileTYPE f;
// ensure buffer is freed if the reader is being reused
reader->~fileTextReader();
if (FileOpen(&f, filename))
{
char *buf = (char*)malloc(f.size+1);
if (buf)
{
memset(buf, 0, f.size + 1);
int size;
if ((size = FileReadAdv(&f, buf, f.size)))
{
reader->size = f.size;
reader->buffer = buf;
reader->pos = reader->buffer;
return true;
}
}
}
return false;
}
const char *FileReadLine(fileTextReader *reader)
{
const char *end = reader->buffer + reader->size;
while (reader->pos < end)
{
char *st = reader->pos;
while ((reader->pos < end) && *reader->pos && (*reader->pos != 10))
reader->pos++;
*reader->pos = 0;
while (*st == ' ' || *st == '\t' || *st == 13)
st++;
if (*st == '#' || *st == ';' || !*st)
{
reader->pos++;
}
else
{
return st;
}
}
return nullptr;
}

View File

@@ -34,6 +34,16 @@ struct direntext_t
char altname[256];
};
struct fileTextReader
{
fileTextReader();
~fileTextReader();
size_t size;
char *buffer;
char *pos;
};
int flist_nDirEntries();
int flist_iFirstEntry();
void flist_iFirstEntryInc();
@@ -120,11 +130,15 @@ const char *getFullPath(const char *name);
uint32_t getFileType(const char *name);
bool isMraName(char *path);
bool FileOpenTextReader(fileTextReader *reader, const char *path);
const char* FileReadLine(fileTextReader *reader);
#define LOADBUF_SZ (1024*1024)
#define COEFF_DIR "filters"
#define GAMMA_DIR "gamma"
#define AFILTER_DIR "filters_audio"
#define SMASK_DIR "shadow_masks"
#define GAMES_DIR "games"
#define CIFS_DIR "cifs"

View File

@@ -132,6 +132,7 @@ enum MENU
MENU_COEFF_FILE_SELECTED,
MENU_GAMMA_FILE_SELECTED,
MENU_AFILTER_FILE_SELECTED,
MENU_SMASK_FILE_SELECTED,
// Generic
MENU_GENERIC_MAIN1,
@@ -212,6 +213,7 @@ const char *config_uart_msg[] = { " None", " PPP", " Console", "
const char *config_midilink_mode[] = {"Local", "Local", " USB", " UDP", "-----", "-----", " USB" };
const char *config_scaler_msg[] = { "Internal","Custom" };
const char *config_afilter_msg[] = { "Internal","Custom" };
const char *config_smask_msg[] = { "None", "1x", "2x", "1x Rotated", "2x Rotated" };
const char *config_gamma_msg[] = { "Off","On" };
const char *config_scale[] = { "Normal", "V-Integer", "HV-Integer-", "HV-Integer+", "HV-Integer", "???", "???", "???" };
@@ -2244,7 +2246,7 @@ void HandleUI(void)
while(1)
{
n = 0;
menumask = 0xf80F;
menumask = 0x3800f;
if (!menusub) firstmenu = 0;
adjvisible = 0;
@@ -2325,24 +2327,40 @@ void HandleUI(void)
MenuWrite(n++, s, menusub == 10, !audio_filter_en() || !S_ISDIR(getFileType(AFILTER_DIR)));
}
if (is_minimig() || is_st())
{
menumask &= ~0x1800;
}
else
if (video_get_shadow_mask_mode() >= 0)
{
MenuWrite(n++);
MenuWrite(n++, " Reset settings", menusub == 11, is_archie());
MenuWrite(n++, " Save settings", menusub == 12, 0);
menumask |= 0x1800;
sprintf(s, " Shadow Mask - %s", config_smask_msg[video_get_shadow_mask_mode()]);
MenuWrite(n++, s, menusub == 11);
memset(s, 0, sizeof(s));
s[0] = ' ';
if (strlen(video_get_shadow_mask())) strncpy(s + 1, video_get_shadow_mask(), 25);
else strcpy(s, " < none >");
while (strlen(s) < 26) strcat(s, " ");
strcat(s, " \x16 ");
MenuWrite(n++, s, menusub == 12, !video_get_shadow_mask_mode() || !S_ISDIR(getFileType(SMASK_DIR)));
}
if (!is_minimig() && !is_st())
{
menumask |= 0x6000;
MenuWrite(n++);
MenuWrite(n++, " Reset settings", menusub == 13, is_archie());
MenuWrite(n++, " Save settings", menusub == 14, 0);
}
MenuWrite(n++);
cr = n;
MenuWrite(n++, " Reboot (hold \x16 cold reboot)", menusub == 13);
MenuWrite(n++, " About", menusub == 14);
MenuWrite(n++, " Reboot (hold \x16 cold reboot)", menusub == 15);
MenuWrite(n++, " About", menusub == 16);
while(n < OsdGetSize() - 1) MenuWrite(n++);
MenuWrite(n++, STD_EXIT, menusub == 15, 0, OSD_ARROW_LEFT);
MenuWrite(n++, STD_EXIT, menusub == 17, 0, OSD_ARROW_LEFT);
sysinfo_timer = 0;
if (!adjvisible) break;
@@ -2466,6 +2484,18 @@ void HandleUI(void)
}
break;
case 11:
video_set_shadow_mask_mode(video_get_shadow_mask_mode() + 1);
menustate = MENU_COMMON1;
break;
case 12:
if (video_get_shadow_mask_mode())
{
snprintf(Selected_tmp, sizeof(Selected_tmp), SMASK_DIR"/%s", video_get_shadow_mask());
if (!FileExists(Selected_tmp)) snprintf(Selected_tmp, sizeof(Selected_tmp), SMASK_DIR);
SelectFile(Selected_tmp, 0, SCANO_DIR | SCANO_TXT, MENU_SMASK_FILE_SELECTED, MENU_COMMON1);
}
break;
case 13:
if (!is_archie())
{
menustate = MENU_RESET1;
@@ -2478,7 +2508,7 @@ void HandleUI(void)
}
break;
case 12:
case 14:
// Save settings
menustate = MENU_GENERIC_MAIN1;
menusub = 0;
@@ -2503,7 +2533,7 @@ void HandleUI(void)
}
break;
case 13:
case 15:
{
reboot_req = 1;
@@ -2516,7 +2546,7 @@ void HandleUI(void)
}
break;
case 14:
case 16:
menustate = MENU_ABOUT1;
menusub = 0;
break;
@@ -3056,6 +3086,20 @@ void HandleUI(void)
}
break;
case MENU_SMASK_FILE_SELECTED:
{
char *p = strcasestr(selPath, SMASK_DIR"/");
if (!p) video_set_shadow_mask(selPath);
else
{
p += strlen(SMASK_DIR);
while (*p == '/') p++;
video_set_shadow_mask(p);
}
menustate = MENU_COMMON1;
}
break;
case MENU_MISC1:
OsdSetSize(16);
helptext_idx = 0;
@@ -3559,7 +3603,7 @@ void HandleUI(void)
if (menu | select | left)
{
menustate = MENU_COMMON1;
menusub = 14;
menusub = 16;
}
break;

View File

@@ -69,6 +69,7 @@
#define UIO_SET_UART 0x3B
#define UIO_CHK_UPLOAD 0x3C
#define UIO_ASTICK_2 0x3D
#define UIO_SHADOWMASK 0x3E
// codes as used by 8bit for file loading from OSD
#define FIO_FILE_TX 0x53

276
video.cpp
View File

@@ -203,7 +203,7 @@ static char new_scaler = 0;
static void setScaler()
{
fileTYPE f = {};
fileTextReader reader = {};
static char filename[1024];
uint32_t arc[4] = {};
@@ -234,52 +234,32 @@ static void setScaler()
DisableIO();
snprintf(filename, sizeof(filename), COEFF_DIR"/%s", scaler_flt_cfg + 1);
if (FileOpen(&f, filename))
if (FileOpenTextReader(&reader, filename))
{
//printf("Read scaler coefficients\n");
char *buf = (char*)malloc(f.size+1);
if (buf)
spi_uio_cmd_cont(UIO_SET_FLTCOEF);
int phase = 0;
const char *line;
while ((line = FileReadLine(&reader)))
{
memset(buf, 0, f.size + 1);
int size;
if ((size = FileReadAdv(&f, buf, f.size)))
int c0, c1, c2, c3;
int n = sscanf(line, "%d,%d,%d,%d", &c0, &c1, &c2, &c3);
if (n == 4)
{
spi_uio_cmd_cont(UIO_SET_FLTCOEF);
//printf(" phase %c-%02d: %4d,%4d,%4d,%4d\n", (phase >= 16) ? 'V' : 'H', phase % 16, c0, c1, c2, c3);
//printf("%03X: %03X %03X %03X %03X;\n",phase*4, c0 & 0x1FF, c1 & 0x1FF, c2 & 0x1FF, c3 & 0x1FF);
char *end = buf + size;
char *pos = buf;
int phase = 0;
while (pos < end)
{
char *st = pos;
while ((pos < end) && *pos && (*pos != 10)) pos++;
*pos = 0;
while (*st == ' ' || *st == '\t' || *st == 13) st++;
if (*st == '#' || *st == ';' || !*st) pos++;
else
{
int c0, c1, c2, c3;
int n = sscanf(st, "%d,%d,%d,%d", &c0, &c1, &c2, &c3);
if (n == 4)
{
//printf(" phase %c-%02d: %4d,%4d,%4d,%4d\n", (phase >= 16) ? 'V' : 'H', phase % 16, c0, c1, c2, c3);
//printf("%03X: %03X %03X %03X %03X;\n",phase*4, c0 & 0x1FF, c1 & 0x1FF, c2 & 0x1FF, c3 & 0x1FF);
spi_w((c0 & 0x1FF) | (((phase * 4) + 0) << 9));
spi_w((c1 & 0x1FF) | (((phase * 4) + 1) << 9));
spi_w((c2 & 0x1FF) | (((phase * 4) + 2) << 9));
spi_w((c3 & 0x1FF) | (((phase * 4) + 3) << 9));
spi_w((c0 & 0x1FF) | (((phase * 4) + 0) << 9));
spi_w((c1 & 0x1FF) | (((phase * 4) + 1) << 9));
spi_w((c2 & 0x1FF) | (((phase * 4) + 2) << 9));
spi_w((c3 & 0x1FF) | (((phase * 4) + 3) << 9));
phase++;
if (phase >= 32) break;
}
}
}
DisableIO();
phase++;
if (phase >= 32) break;
}
free(buf);
}
DisableIO();
}
}
@@ -330,7 +310,7 @@ static char has_gamma = 0;
static void setGamma()
{
fileTYPE f = {};
fileTextReader reader = {};
static char filename[1024];
if (!spi_uio_cmd_cont(UIO_SET_GAMMA))
@@ -344,57 +324,38 @@ static void setGamma()
DisableIO();
snprintf(filename, sizeof(filename), GAMMA_DIR"/%s", gamma_cfg + 1);
if (FileOpen(&f, filename))
if (FileOpenTextReader(&reader, filename))
{
char *buf = (char*)malloc(f.size+1);
if (buf)
spi_uio_cmd_cont(UIO_SET_GAMCURV);
const char *line;
int index = 0;
while ((line = FileReadLine(&reader)))
{
memset(buf, 0, f.size + 1);
int size;
if ((size = FileReadAdv(&f, buf, f.size)))
int c0, c1, c2;
int n = sscanf(line, "%d,%d,%d", &c0, &c1, &c2);
if (n == 1)
{
spi_uio_cmd_cont(UIO_SET_GAMCURV);
char *end = buf + size;
char *pos = buf;
int index = 0;
while (pos < end)
{
char *st = pos;
while ((pos < end) && *pos && (*pos != 10)) pos++;
*pos = 0;
while (*st == ' ' || *st == '\t' || *st == 13) st++;
if (*st == '#' || *st == ';' || !*st) pos++;
else
{
int c0, c1, c2;
int n = sscanf(st, "%d,%d,%d", &c0, &c1, &c2);
if (n == 1)
{
c1 = c0;
c2 = c0;
n = 3;
}
if (n == 3)
{
spi_w((index << 8) | (c0 & 0xFF));
spi_w((index << 8) | (c1 & 0xFF));
spi_w((index << 8) | (c2 & 0xFF));
index++;
if (index >= 256) break;
}
}
}
DisableIO();
spi_uio_cmd8(UIO_SET_GAMMA, gamma_cfg[0]);
c1 = c0;
c2 = c0;
n = 3;
}
free(buf);
if (n == 3)
{
spi_w((index << 8) | (c0 & 0xFF));
spi_w((index << 8) | (c1 & 0xFF));
spi_w((index << 8) | (c2 & 0xFF));
index++;
if (index >= 256) break;
}
}
DisableIO();
spi_uio_cmd8(UIO_SET_GAMMA, gamma_cfg[0]);
}
}
int video_get_gamma_en()
{
return has_gamma ? gamma_cfg[0] : -1;
@@ -431,6 +392,152 @@ static void loadGammaCfg()
}
}
static char shadow_mask_cfg[1024] = { 0 };
static bool has_shadow_mask = false;
#define SM_FLAG_ENABLED ( 1 << 0 )
#define SM_FLAG_2X ( 1 << 1 )
#define SM_FLAG_ROTATED ( 1 << 2 )
#define SM_FLAG(v) ( ( 0x0 << 13 ) | ( (v) & 0x7 ) )
#define SM_VMAX(v) ( ( 0x1 << 13 ) | ( (v) & 0xf ) )
#define SM_HMAX(v) ( ( 0x2 << 13 ) | ( (v) & 0xf ) )
#define SM_LUT(o,v) ( ( 0x3 << 13 ) | ( ( (o) & 0x3f ) << 4 ) | ( (v) & 0x7 ) )
enum
{
SM_MODE_NONE = 0,
SM_MODE_1X,
SM_MODE_2X,
SM_MODE_1X_ROTATED,
SM_MODE_2X_ROTATED,
SM_MODE_COUNT
};
static void setShadowMask()
{
static char filename[1024];
if (!spi_uio_cmd_cont(UIO_SHADOWMASK))
{
DisableIO();
has_shadow_mask = false;
return;
}
has_shadow_mask = true;
switch( video_get_shadow_mask_mode() )
{
default: spi_w(SM_FLAG(0)); break;
case SM_MODE_1X: spi_w(SM_FLAG(SM_FLAG_ENABLED)); break;
case SM_MODE_2X: spi_w(SM_FLAG(SM_FLAG_ENABLED | SM_FLAG_2X)); break;
case SM_MODE_1X_ROTATED: spi_w(SM_FLAG(SM_FLAG_ENABLED | SM_FLAG_ROTATED)); break;
case SM_MODE_2X_ROTATED: spi_w(SM_FLAG(SM_FLAG_ENABLED | SM_FLAG_ROTATED | SM_FLAG_2X)); break;
}
snprintf(filename, sizeof(filename), SMASK_DIR"/%s", shadow_mask_cfg + 1);
fileTextReader reader;
if( FileOpenTextReader( &reader, filename ) )
{
int w = -1, h = -1;
int y = 0;
const char *line;
while ((line = FileReadLine( &reader )))
{
if( w == -1 )
{
int n = sscanf(line, "%d,%d", &w, &h);
if( (n != 2) || (w <= 0) || ( w <= 0 ) )
{
spi_w(SM_FLAG(0));
break;
}
}
else
{
unsigned int p[8];
int n = sscanf(line, "%u,%u,%u,%u,%u,%u,%u,%u", p+0, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
if( n != w )
{
spi_w(SM_FLAG(0));
break;
}
for( int x = 0; x < w; x++ )
{
int offset = x + ( y * 8 );
spi_w( SM_LUT(offset, p[x]) );
}
y += 1;
if( y == h ) break;
}
}
if( y == h )
{
spi_w(SM_HMAX(w - 1));
spi_w(SM_VMAX(h - 1));
}
}
DisableIO();
}
int video_get_shadow_mask_mode()
{
return has_shadow_mask ? shadow_mask_cfg[0] : -1;
}
char* video_get_shadow_mask()
{
return shadow_mask_cfg + 1;
}
static char shadow_mask_cfg_path[1024] = { 0 };
void video_set_shadow_mask_mode(int n)
{
if( n >= SM_MODE_COUNT )
{
n = 0;
}
shadow_mask_cfg[0] = (char)n;
FileSaveConfig(shadow_mask_cfg_path, &shadow_mask_cfg, sizeof(shadow_mask_cfg));
setShadowMask();
}
void video_set_shadow_mask(char *name)
{
strcpy(shadow_mask_cfg + 1, name);
FileSaveConfig(shadow_mask_cfg_path, &shadow_mask_cfg, sizeof(shadow_mask_cfg));
setShadowMask();
user_io_send_buttons(1);
}
static void loadShadowMaskCfg()
{
sprintf(shadow_mask_cfg_path, "%s_shmask.cfg", user_io_get_core_name());
if (!FileLoadConfig(shadow_mask_cfg_path, &shadow_mask_cfg, sizeof(shadow_mask_cfg) - 1))
{
memset(shadow_mask_cfg, 0, sizeof(shadow_mask_cfg));
if (cfg.shmask_default[0])
{
strcpy(shadow_mask_cfg + 1, cfg.shmask_default);
shadow_mask_cfg[0] = cfg.shmask_mode_default;
}
}
if( shadow_mask_cfg[0] >= SM_MODE_COUNT )
{
shadow_mask_cfg[0] = 0;
}
}
static char fb_reset_cmd[128] = {};
static void set_video(vmode_custom_t *v, double Fpix)
@@ -441,6 +548,9 @@ static void set_video(vmode_custom_t *v, double Fpix)
loadScalerCfg();
setScaler();
loadShadowMaskCfg();
setShadowMask();
v_cur = *v;
vmode_custom_t v_fix = v_cur;

View File

@@ -11,6 +11,11 @@ void video_set_gamma_en(int n);
char* video_get_gamma_curve();
void video_set_gamma_curve(char *name);
int video_get_shadow_mask_mode();
void video_set_shadow_mask_mode(int n);
char* video_get_shadow_mask();
void video_set_shadow_mask(char *name);
void video_mode_load();
void video_mode_adjust();