Skip to content

Commit

Permalink
v1.01
Browse files Browse the repository at this point in the history
new: PZX support
chg: animate flash attributes in gallery
chg: switch default AY core back to floooh's
chg: ZXDB bumped up to latest
chg: ZXDB display version within About dialog
chg: moved titlebar logic to a separate file
fix: added U+011A Ě, U+011B ě czech glyphs
fix: allow alt-enter to switch fullscreen on linux/osx (3rd_tigr)
fix: allow ini fields to be read in any order
fix: loading settings from ini
fix: window was being prevented from being closed by SCR viewer
fix: window was being prevented from being closed while 128 menu was in HALT state (see: cursor right key)
fix: ZXDB browser was always disabled after local browser was used
fix: ZXDB picked wrong II/III titles sometimesr (see: dan dare 3 vs 2, "*2">"*II*" patch)
  • Loading branch information
r-lyeh committed Jul 14, 2024
1 parent 4f67871 commit b1c8844
Show file tree
Hide file tree
Showing 36 changed files with 266 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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file added bin/Spectral101.dmg
Binary file not shown.
Binary file added bin/Spectral101.linux
Binary file not shown.
Binary file added bin/Spectral101.zip
Binary file not shown.
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"

#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"
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 && git add Spectral.db

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

git diff Spectral.db >> Spectral.db.diff && git add Spectral.db.diff && git rm 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 b1c8844

Please sign in to comment.