Skip to content

Commit

Permalink
v1.01 wip
Browse files Browse the repository at this point in the history
new: PZX support
chg: display animated flash attributes in gallery
fix: ZXDB picking wrong titles after "*2">"*II*" patch  (dan dare 3 vs 2)
fix: loading settings from ini
fix: bug that prevented window from being closed while 128 menu was in HALT state (see: cursor right key)
chg: switch AY core back to floooh's
chg: display zxdb version within About dialog
chg: bumped up zxdb to latest
chg: moved titlebar logic to a separate file
fix: added U+011A Ě, U+011B ě czech glyphs
fix: window was being prevented from being closed by SCR viewer

fix: alt-enter not going fullscreen on linux/osx (3rd_tigr)
fix: allow ini fields to be read in any order
fix: local browser setting was preventing ZXDB browser to show up in fresh restarts
  • Loading branch information
r-lyeh committed Jul 14, 2024
1 parent 4f67871 commit ac0b23b
Show file tree
Hide file tree
Showing 18 changed files with 269 additions and 78 deletions.
9 changes: 5 additions & 4 deletions MAKE.bat
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ if "%1"=="" (
)

if "%1"=="-h" (
echo make [dbg^|dev^|opt^|rel] [compiler-flags]
echo make [deb^|dev^|opt^|rel] [compiler-flags]
exit /b
)

Expand Down Expand Up @@ -124,13 +124,14 @@ if "%1"=="dev" (
src\res\embed Spectral.exe src\res\zxdb\Spectral.db.gz
src\res\embed Spectral.exe @SpectralEmBeDdEd

tasklist /fi "ImageName eq remedybg.exe" 2>NUL | find /I "exe">NUL || (where /q remedybg.exe && start remedybg -q -g Spectral.exe)

exit /b
)

if "%1"=="dbg" (
if "%1"=="deb" (
call make dev /fsanitize=address %ALL_FROM_2ND% || goto error

tasklist /fi "ImageName eq remedybg.exe" 2>NUL | find /I "exe">NUL || (where /q remedybg.exe && start remedybg -q -g Spectral.exe)

exit /b
)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Code is highly experimental and prone to change in the future. I will keep alter
- [x] Kempston mouse. <!-- @todo: AMX mouse.-->
- [x] Kempston/Fuller/Cursor/Sinclair joysticks.
- [x] RF/CRT experience (not physically accurate though).
- [x] TAP/TZX/CSW tapes. Z80/SNA snaps. ROM/IF2 roms. <!-- @todo: tzx info on window title -->
- [x] TAP/TZX/PZX/CSW tapes. Z80/SNA snaps. ROM/IF2 roms. <!-- @todo: tzx info on window title -->
- [x] DSK/EDSK/TRD/SCL/FDI/MGT/IMG/HOBETA disks.
- [x] SCR/PNG screenshots. <!-- @todo: ulaplus screenshots. video recording -->
- [x] ZIP/RAR/GZ archives.
Expand Down
1 change: 1 addition & 0 deletions src/3rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "3rd_tigrobjc.h"
#include "3rd_tigrmousecursor.h"
#include "3rd_tigrdragndrop.h"
#include "3rd_tigrtitle.h"
#undef border
#undef run

Expand Down
38 changes: 38 additions & 0 deletions src/3rd_tigr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4042,6 +4042,11 @@ void _tigrOnCocoaEvent(id event, id window) {
}
}

#if 1 // @r-lyeh
if( win->keys[TK_ALT] && win->keys[TK_RETURN] && !win->prev[TK_RETURN] )
objc_msgSend_void_id(window, sel("toggleFullScreen:"), window);
#endif

// Pass through cmd+key
if (win->keys[TK_LWIN]) {
break;
Expand Down Expand Up @@ -5283,6 +5288,32 @@ static void tigrInterpretChar(TigrInternal* win, Window root, unsigned int keyco
}
}

#if 1 // @r-lyeh
#ifndef _NET_WM_STATE_TOGGLE
#define _NET_WM_STATE_TOGGLE 2
#endif
static int tigrToggleFullscreen(TigrInternal* win)
{
XEvent xev;
long evmask = SubstructureRedirectMask | SubstructureNotifyMask;

xev.type = ClientMessage;
xev.xclient.window = win->win;
xev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False); //_NET_WM_STATE;
xev.xclient.format = 32;
xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; /* action */
xev.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); /* first property to toggle */
xev.xclient.data.l[2] = 0; /* no second property to toggle */
xev.xclient.data.l[3] = 1; /* source indication: application */
xev.xclient.data.l[4] = 0; /* unused */

if(!XSendEvent(win->dpy, DefaultRootWindow(win->dpy), 0, evmask, &xev)) {
return -1;
}
return 0;
}
#endif

static void tigrProcessInput(TigrInternal* win, int winWidth, int winHeight) {
{
Window focused;
Expand Down Expand Up @@ -5348,6 +5379,13 @@ static void tigrProcessInput(TigrInternal* win, int winWidth, int winHeight) {
}
memcpy(prevKeys, keys, 32);

#if 1 // @r-lyeh
if( win->keys[TK_LALT] || win->keys[TK_RALT] )
if( win->keys[TK_RETURN] && !win->prev[TK_RETURN] ) {
tigrToggleFullscreen(win);
}
#endif

XEvent event;
while (XCheckTypedWindowEvent(win->dpy, win->win, ClientMessage, &event)) {
if (event.xclient.data.l[0] == wmDeleteMessage) {
Expand Down
20 changes: 20 additions & 0 deletions src/3rd_tigrtitle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
char* tigrTitle(Tigr *win, const char *title) {
static char copy[128] = {0};
if( title ) {
#ifdef __APPLE__

#elif defined _WIN32
SetWindowTextA((HWND)(win->handle), title);
#else
XTextProperty prop;
int result = Xutf8TextListToTextProperty(dpy, (char**)&title, 1, XUTF8StringStyle, &prop);
if (result == Success) {
Atom wmName = XInternAtom(dpy, "_NET_WM_NAME", 0);
XSetTextProperty(tigrInternal(win)->dpy, tigrInternal(win)->win, &prop, wmName);
XFree(prop.value);
}
#endif
snprintf(copy, 128, "%s", title);
}
return copy;
}
32 changes: 25 additions & 7 deletions src/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
// key2/3, +2a/+3, fdc, dsk, autotape, gui, KL modes, load "" code, +3 fdc sounds, +3 speedlock, issue 2/3,
// pentagon, trdos, trdos (boot), translate game menus, 50/60 hz, game2exe,
// zxdb, custom tiny zxdb fmt, embedded zxdb, zxdb cache, zxdb download on demand, zxdb gallery
// ay player,
// ay player, pzx,
// glue sequential tzx/taps in zips (side A) -> side 1 etc)
// sequential tzx/taps/dsks do not reset model

#define SPECTRAL "v1.0"
#define SPECTRAL "v1.01 wip"

#define README \
"Spectral can be configured with a mouse.\n\n" \
Expand Down Expand Up @@ -58,6 +58,11 @@
// [ ] db interface (F2 to rename)
// on hover: show animated state if exists. show loading screen otherwise.
// [ ] embed torrent server/client to mirror the WOS/ZXDB/NVG/Archive.org distros
// http://www.kristenwidman.com/blog/33/how-to-write-a-bittorrent-client-part-1/
// https://wiki.theory.org/BitTorrentSpecification
// http://bittorrent.org/beps/bep_0003.html
// https://github.com/willemt/yabtorrent
// https://github.com/jech/dht
//
// idea: when stop-block is off
// - turn autoplay=off
Expand Down Expand Up @@ -167,8 +172,11 @@ int screenshot(const char *filename) {
int load_config() {
int errors = 0;
if( !ZX_PLAYER ) for( FILE *fp = fopen(".Spectral/Spectral.ini", "rt"); fp; fclose(fp), fp = 0 ) {
#define INI_LOAD(opt) errors += fscanf(fp, "%*[^=]=%d\n", &opt) > 1;
INI_OPTIONS(INI_LOAD)
while( !feof(fp) ) {
int tmp; char buf[128]; errors += fscanf(fp, "%[^=]=%d ", buf, &tmp) > 1;
#define INI_LOAD(opt) if( strcmpi(buf, #opt) == 0 ) opt = tmp; else
INI_OPTIONS(INI_LOAD) {}
}
}
return !errors;
}
Expand Down Expand Up @@ -216,6 +224,11 @@ void input() {
if(window_pressed(app, TK_ALT)) ZXKey(ZX_CTRL);
}

// z80_opdone() returns 0 indefinitely while z80 is in halt state, often seen during BASIC sessions.
// hack: force a benign keypress when user wants to close window; so z80_opdone() returns 1 hopefully.
if( !window_alive(app) ) {
static int flip = 0; if( flip ^= 1 ) ZXKey(ZX_SHIFT);
}

// prepare command keys
if( window_trigger(app, TK_ESCAPE) ) cmdkey = 'ESC';
Expand Down Expand Up @@ -255,8 +268,9 @@ void help() {
char *help = va(
"Spectral " SPECTRAL " (Public Domain).\n"
"https://github.com/r-lyeh/Spectral\n\n"
"Library: %d games found (%d%%)\n\n"
README "\n", numgames, 100 - (numerr * 100 / (total + !total)));
"ZXDB %s: %d entries\n"
"Local Library: %d games found (%d%%)\n\n"
README "\n", ZXDB_VERSION, zxdb_count(), numgames, 100 - (numerr * 100 / (total + !total)));
(alert)("Spectral " SPECTRAL, help);
}

Expand Down Expand Up @@ -1123,7 +1137,11 @@ if( do_runahead == 0 ) {
active *= window_alive(app);

#if NEWCORE
} while( !z80_opdone(&cpu) );
// ensure there is no pending opcode before exiting main loop: spectral.sav would be corrupt otherwise.
// also, do not loop indefinitely on invalid DI+HALT combo, which we use in our .SCR viewer.
// update: moved logic that bypasses z80_opdone(&cpu) in HALT state. rewritten as a forced/benign ZX_Key(ZX_SHIFT) operation; see: input() function.
// printf("%d %018llx %d %d %d\n", z80_opdone(&cpu), cpu.pins, cpu.step, IFF1(cpu), IFF2(cpu));
} while( z80_opdone(&cpu) ? 0 : 1 ); // (cpu.pins & Z80_HALT) && (cpu.step == 1) ? 0 : 1 ); // (cpu.pins & Z80_HALT) && (cpu.step == 1 || cpu.step==_z80_special_optable[4] || cpu.step==_z80_special_optable[5]) ? 0 : 1 );
#endif

} while( window_alive(app) );
Expand Down
41 changes: 26 additions & 15 deletions src/app_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

zxdb ZXDB2;

rgba* thumbnail(const byte *VRAM_, int len, unsigned downfactor) {
rgba* thumbnail(const byte *VRAM_, int len, unsigned downfactor, int ZXFlashFlag) {
int w = 256 / downfactor, h = 192 / downfactor;

rgba *texture = malloc( w * h * 4 ), *cpy = texture;
Expand Down Expand Up @@ -220,7 +220,9 @@ uint16_t cache_set(unsigned zxdb, uint16_t v) {
return v;
}

const byte* screens[65536][4]; // as-is, 2:1 shrink, 4:1 shrink, 8:1 shrink
// screens + thumbnails
// 64K ZXDB entries max, x2 flash versions (on/off) each, x4 versions each (1:1,2:1,4:1,8:1 shrinks)
const byte* screens[65536][2][4];
unsigned short screens_len[65536];


Expand Down Expand Up @@ -259,23 +261,32 @@ int worker_fn( void* userdata ) {
}

{
screens[id][0] =
screens[id][1] =
screens[id][2] =
screens[id][3] = (const byte*)bin;
screens[id][0][0] =
screens[id][0][1] =
screens[id][0][2] =
screens[id][0][3] =
screens[id][1][0] =
screens[id][1][1] =
screens[id][1][2] =
screens[id][1][3] = (const byte*)bin;

int ix,iy,in;
rgba *bitmap = (rgba*)stbi_load_from_memory(bin, len, &ix, &iy, &in, 4);
if( bitmap ) {
screens[id][1] = (const byte*)ui_resize(bitmap, ix, iy, 256/2, 192/2, 1);
screens[id][2] = (const byte*)ui_resize(bitmap, ix, iy, 256/4, 192/4, 1);
screens[id][3] = (const byte*)ui_resize(bitmap, ix, iy, 256/8, 192/8, 1);
screens[id][0][1] = screens[id][1][1] = (const byte*)ui_resize(bitmap, ix, iy, 256/2, 192/2, 1);
screens[id][0][2] = screens[id][1][2] = (const byte*)ui_resize(bitmap, ix, iy, 256/4, 192/4, 1);
screens[id][0][3] = screens[id][1][3] = (const byte*)ui_resize(bitmap, ix, iy, 256/8, 192/8, 1);
stbi_image_free(bitmap);
} else {
bitmap = thumbnail(bin, len, 1); ix = 256, iy = 192;
screens[id][1] = (const byte*)ui_resize(bitmap, ix, iy, 256/2, 192/2, 1);
screens[id][2] = (const byte*)ui_resize(bitmap, ix, iy, 256/4, 192/4, 1);
screens[id][3] = (const byte*)ui_resize(bitmap, ix, iy, 256/8, 192/8, 1);
bitmap = thumbnail(bin, len, 1, 0); ix = 256, iy = 192;
screens[id][0][1] = (const byte*)ui_resize(bitmap, ix, iy, 256/2, 192/2, 1);
screens[id][0][2] = (const byte*)ui_resize(bitmap, ix, iy, 256/4, 192/4, 1);
screens[id][0][3] = (const byte*)ui_resize(bitmap, ix, iy, 256/8, 192/8, 1);
free(bitmap);
bitmap = thumbnail(bin, len, 1, 1); ix = 256, iy = 192;
screens[id][1][1] = (const byte*)ui_resize(bitmap, ix, iy, 256/2, 192/2, 1);
screens[id][1][2] = (const byte*)ui_resize(bitmap, ix, iy, 256/4, 192/4, 1);
screens[id][1][3] = (const byte*)ui_resize(bitmap, ix, iy, 256/8, 192/8, 1);
free(bitmap);
}

Expand Down Expand Up @@ -316,7 +327,7 @@ char *zxdb_screen_async(const char *id, int *len, int factor) {
screens_len[zxdb_id] = 1;
}
if( screens_len[zxdb_id] > 1 ) {
return *len = screens_len[zxdb_id], screens[zxdb_id][factor & 3];
return *len = screens_len[zxdb_id], screens[zxdb_id][ZXFlashFlag][factor & 3];
}
}
}
Expand Down Expand Up @@ -834,7 +845,7 @@ char* game_browser_v2() {
background_texture = ui_resize(bitmap, ix, iy, 256/1, 192/1, 1);
stbi_image_free(bitmap);
} else {
background_texture = thumbnail(data, len, 1);
background_texture = thumbnail(data, len, 1, ZXFlashFlag);
}
}
}
Expand Down
Binary file modified src/res/zxdb/Spectral.db.gz
Binary file not shown.
1 change: 1 addition & 0 deletions src/res/zxdb/ZXDB_version.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#define ZXDB_VERSION "Version 1.0.198"
3 changes: 3 additions & 0 deletions src/res/zxdb/diff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import difflib
import sys
for line in difflib.unified_diff(open(sys.argv[1]).readlines(), open(sys.argv[2]).readlines(), fromfile=sys.argv[1], tofile=sys.argv[2], lineterm=''): print(line)
7 changes: 6 additions & 1 deletion src/res/zxdb/make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
rem checks. compile if needed
where /q python.exe || (echo cannot find python.exe in path && exit /b)
where /q sqlite3.exe || (cl sqlite3.c shell.c /MT || exit /b)
where /q zxdb2txt.exe || (cl zxdb2txt.c sqlite3.c /MT /Ox /Oy || exit /b)
where /q zxdb2txt.exe || (cl zxdb2txt.c sqlite3.c -DDEV=0 /MT /Ox /Oy || exit /b)
if exist *.obj del *.obj
if exist Z*.sql* del Z*.sql*

rem clone
rd /q /s ZXDB >nul 2>nul
git clone --depth 1 https://github.com/ZXDB/ZXDB && ^
pushd ZXDB && (git log --oneline --pretty="#define ZXDB_VERSION \"%%s\"" ZXDB_mysql.sql.zip > ..\ZXDB_version.h) && popd && ^
python -m zipfile -e ZXDB\ZXDB_mysql.sql.zip . && ^
python ZXDB\scripts\ZXDB_to_SQLite.py && ^
rd /q /s ZXDB >nul 2>nul
Expand All @@ -33,5 +34,9 @@ choice /C YN /M "Convert? "

rem convert if requested
if "%errorlevel%"=="1" (
python -m gzip -d Spectral.db.gz && copy /y Spectral.db Spectral.db.old

zxdb2txt 0..65535 > Spectral.db && python -m gzip --best Spectral.db && echo Ok!

python diff.py Spectral.db.old Spectral.db
)
5 changes: 3 additions & 2 deletions src/sys_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ CUSTOM_GLYPHS,
{0x007c,0x1818181818181800},{0x007d,0x3018180e18183000},{0x007e,0x316b460000000000},
#endif
{0x00a0,0x0000000000000000},
#if 1 // USE_BESCII. added U+010C Č, U+010D č
#if 1 // USE_BESCII. added U+010C Č, U+010D č, U+011A Ě, U+011B ě
{0x00a1,0x0018001818181818},{0x00a2,0x00083e6868683e08},{0x00a3,0x3c6660f86060fe00},{0x00a4,0x00423c66663c4200},
{0x00a5,0x66663c183c181800},{0x00a6,0x1818180000181818},{0x00a7,0x3c607c663e063c00},{0x00a8,0x2400000000000000},
{0x00a9,0x38449aa29a443800},{0x00aa,0x060a060000000000},{0x00ab,0x0000366cd86c3600},{0x00ac,0x0000007e06060000},
Expand All @@ -384,7 +384,8 @@ CUSTOM_GLYPHS,
{0x00f9,0x1008666666663e00},{0x00fa,0x0810666666663e00},{0x00fb,0x1028666666663e00},{0x00fc,0x2400666666663e00},
{0x00fd,0x08106666663e063c},{0x00fe,0x0000303c363c3000},{0x00ff,0x24006666663e063c},

{0x010c,0x3c3c666060663c00},{0x010d,0x28103c6660663c00}, // @fixme
{0x010c,0x3c3c666060663c00},{0x010d,0x28103c6660663c00}, // @fixme: replace with better glyphs
{0x011a,0x3c7e607c60607e00},{0x011b,0x28103c667e603c00}, // @fixme: replace with better glyphs

{0x0131,0x0000181818180c00},
{0x0141,0x606078e060607e00},{0x0142,0x18181c3818180c00},{0x0152,0x7ed8d8dcd8d87e00},{0x0153,0x00006c929e906c00},
Expand Down
25 changes: 1 addition & 24 deletions src/sys_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#define window_pressed(win, keycode) (!!(tigrKeyDown(win, keycode) || tigrKeyHeld(win, keycode)))
#define window_trigger(win, keycode) (!!tigrKeyDown(win, keycode))
void window_override_icons();
char* window_title(window *win, const char *title);
#define window_title(win, title) tigrTitle(win,title)


int window_keyrepeat(window *app, unsigned char vk) {
Expand Down Expand Up @@ -82,28 +82,6 @@ char* prompt(const char *title, const char *body, const char *defaults ) {

#endif


char* window_title(window *win, const char *title) {
static char copy[128] = {0};
if( title ) {
#ifdef __APPLE__

#elif defined _WIN32
SetWindowTextA((HWND)(((Tigr*)win)->handle), title);
#else
XTextProperty prop;
int result = Xutf8TextListToTextProperty(dpy, (char**)&title, 1, XUTF8StringStyle, &prop);
if (result == Success) {
Atom wmName = XInternAtom(dpy, "_NET_WM_NAME", 0);
XSetTextProperty(tigrInternal(win)->dpy, tigrInternal(win)->win, &prop, wmName);
XFree(prop.value);
}
#endif
snprintf(copy, 128, "%s", title);
}
return copy;
}

int (alert)(const char *title, const char *body) {
#ifdef _WIN32
MessageBoxA(0, body, title, MB_OK);
Expand All @@ -126,4 +104,3 @@ void die(const char *msg) {
#endif
exit(-1);
}

Loading

0 comments on commit ac0b23b

Please sign in to comment.