diff --git a/CppProperties.json b/CppProperties.json
new file mode 100644
index 0000000..659bf4e
--- /dev/null
+++ b/CppProperties.json
@@ -0,0 +1,21 @@
+{
+ "configurations": [
+ {
+ "inheritEnvironments": [
+ "msvc_x86"
+ ],
+ "name": "x86-Debug",
+ "includePath": [
+ "${env.INCLUDE}",
+ "${workspaceRoot}\\**"
+ ],
+ "defines": [
+ "WIN32",
+ "_DEBUG",
+ "UNICODE",
+ "_UNICODE"
+ ],
+ "intelliSenseMode": "windows-msvc-x86"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/SpectREM/ClassDiagram.cd b/SpectREM/ClassDiagram.cd
new file mode 100644
index 0000000..357ac6d
--- /dev/null
+++ b/SpectREM/ClassDiagram.cd
@@ -0,0 +1,586 @@
+
+
+
+
+
+ AAAQAAIAAAAAQAGQACAAAAAAAAAAAQAAAQAAAAAAAAA=
+ SpectREM\OSX\AudioQueue.hpp
+
+
+
+
+
+ AAAAgABAACAAQAIAIAAAAAEAAEEAAAEgIAASJBEAAAA=
+ SpectREM\Win32\AudioCore.hpp
+
+
+
+
+
+
+
+
+
+ 4BJQmIUvACCTAwg0YdQU4YSgEkIAiBKaABhuA3kI0Zg=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAACAQAAAAAgSAgAAABAAAACAAACAAACA=
+ SpectREM\Win32\TapeViewerWindow.hpp
+
+
+
+
+
+ ASQAICAAAAAQAIACQAAIBAAAIAAAEIIAAiAAACAAAEg=
+ SpectREM\Emulation Core\Debugger\Debug.hpp
+
+
+
+
+
+ CCAQAAAAAAIAACAAAACgAAIAAAAAIAAAAABAAAAAjAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ CAAQAAAAAAAAAAAAAAAgAAAAAAAAIAAAAAgAAAAAAAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ AAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ AAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ CAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ CAAQAAAAAAIAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+
+
+
+
+
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+ FBBIIBCgACYkJEABAQgAACQAEgTgCAAEBCGAAUCgZgA=
+ SpectREM\Emulation Core\Tape\Tape.hpp
+
+
+
+
+
+ JPgCshACMFCTN4SADiRT5IJAxSgggEQwAJiAQ8uMICE=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ ECgAAAACAAAQAAAEABEQQAAgAAAAAAAAABACAAAAAAA=
+ SpectREM\Emulation Core\ZX_Spectrum_48k\ZXSpectrum48.hpp
+
+
+
+
+
+ ECgAAAAKBAAQAAAEAAEQQAAgAAAAAAAAEAACAAAAAAA=
+ SpectREM\Emulation Core\ZX_Spectrum_128k\ZXSpectrum128.hpp
+
+
+
+
+
+ HCveBSk3Wy5esSLXtJkzwCagyJIkAxBU0SLHQDHLLik=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\ZXSpectrum.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAQABAAAAAAA=
+ SpectREM\Win32\OpenGLView.cpp
+
+
+
+
+
+ AAAgBAAwBEAAACAAAJAgAAACACAkAAoAEIAhAIIBAQA=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\MachineInfo.h
+
+
+
+
+
+ AAQAAABAAAAAAAAAAECAAAAAAAIAAAAAIAAAAAAAAAA=
+ SpectREM\Win32\PMDawn.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.cpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\AudioCore.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\OpenGLView.hpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\Z80_Core\Z80Core.h
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\MachineInfo.h
+
+
+
+
+
+ QAAAAAAAABAAAQAAAAAAAAAAAAAAAQAAAAAAAAAACAA=
+ SpectREM\Win32\WinMain.cpp
+
+
+
+
+
+ AAABAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAA=
+ SpectREM\Win32\WinMain.cpp
+
+
+
+
+
+ AAAAAAAAAAAAAIAAAgAAAAAAAIAAAAAIAAAAAAAAAAA=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\Audio.cpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAgAAAAAAAAgA=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\Display.cpp
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAIICA=
+ SpectREM\Emulation Core\ZX_Spectrum_Core\MachineInfo.h
+
+
+
+
+
+ AAAAACgAAAAAAAAAAAAAAEAQAAAAAAAAAAAAAAAAAAA=
+ SpectREM\Win32\PMDawn.hpp
+
+
+
+
\ No newline at end of file
diff --git a/SpectREM/ClassDiagram.png b/SpectREM/ClassDiagram.png
new file mode 100644
index 0000000..87e0960
Binary files /dev/null and b/SpectREM/ClassDiagram.png differ
diff --git a/SpectREM/Info.txt b/SpectREM/Info.txt
index 2580b55..525d654 100644
--- a/SpectREM/Info.txt
+++ b/SpectREM/Info.txt
@@ -19,10 +19,37 @@ SHIFT+F1 : Insert a tape
ALT+F1 : Eject currently inserted tape
F9 : Start/Stop currently inserted tape
SHIFT+F9 : Rewind tape if inserted
+ALT+F9 : Open tape viewer window
PAGEUP : Increase volume
-PAGEDOWN : Decreas volume
+PAGEDOWN : Decrease volume
+2020-01-26
+-----------
+FIXED : Incorrect reporting of tap blocks under 2 bytes :/
+FIXED : Strange filename issue causing an exception
+FIXED : AY can now be enabled on a 48k snapshot (retrieves the flag from the snapshot when loading)
+HACK : Hack added to get it to load that uspirit.z80 file, ay works with it also (48k mode)
+
+
+2020-01-24
+-----------
+FIXED : When opening the tape viewer while a tape is either already playing or is paused,
+ on any block it will update the information in the tape viewer window correctly.
+FIXED : Play/Pause from main menu now updates the tape window if visible.
+FIXED : Rewind from main menu updates the tape window if visible.
+
+2020-01-18
+-----------
+ADDED : Tape viewer window with controls and updates (minor bug found, https://github.com/polomint/SpectREMCPP/issues/28)
+FIXED : Forgot to resend the currently inserted .tap data to the tape viewer in between invocations :/
+ADDED : File loaded now displays in title bar, shows Playing/Paused if it is a .tap file
+
+2020-01-06
+-----------
+UPDATED : File loading and folder choosing now uses the new updated file open dialog
+ADDED : Can now select folder for .scr files
+ADDED : Open single .scr
2020-01-05
-----------
diff --git a/SpectREM/SpectREM.aps b/SpectREM/SpectREM.aps
index 97e3107..6774f59 100644
Binary files a/SpectREM/SpectREM.aps and b/SpectREM/SpectREM.aps differ
diff --git a/SpectREM/SpectREM.rc b/SpectREM/SpectREM.rc
index 85cbe04..014c939 100644
--- a/SpectREM/SpectREM.rc
+++ b/SpectREM/SpectREM.rc
@@ -19,20 +19,100 @@
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_PROPPAGE_DISPLAY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 228
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 149
+ END
+
+ IDD_PROPPAGE_SOUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 203
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_PROPPAGE_MISC, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 203
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
-IDD_SETTINGS_DIALOG DIALOGEX 0, 0, 309, 189
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CHILD | WS_CAPTION
-CAPTION "SpectREM Settings"
+IDD_PROPPAGE_DISPLAY DIALOGEX 0, 0, 235, 156
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Display"
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ PUSHBUTTON "Button1",IDC_BUTTON1,60,87,50,14
+END
+
+IDD_PROPPAGE_SOUND DIALOGEX 0, 0, 210, 154
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Sound"
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+END
+
+IDD_PROPPAGE_MISC DIALOGEX 0, 0, 210, 154
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Miscellaneous"
FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN
- PUSHBUTTON "Save",IDC_BTN_SETTINGS_SAVE,191,157,50,14
- PUSHBUTTON "Close",IDC_BTN_SETTINGS_CLOSE,243,157,50,14
+ LTEXT "TODO: layout property page",IDC_STATIC,60,73,90,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_PROPPAGE_DISPLAY AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_PROPPAGE_SOUND AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_PROPPAGE_MISC AFX_DIALOG_LAYOUT
+BEGIN
+ 0
END
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United Kingdom) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
@@ -42,12 +122,12 @@ END
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
- IDD_SETTINGS_DIALOG, DIALOG
+ IDD_DIALOG_SETTINGS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
- BOTTOMMARGIN, 182
+ BOTTOMMARGIN, 169
END
END
#endif // APSTUDIO_INVOKED
@@ -55,24 +135,29 @@ END
/////////////////////////////////////////////////////////////////////////////
//
-// AFX_DIALOG_LAYOUT
+// Dialog
//
-IDD_SETTINGS_DIALOG AFX_DIALOG_LAYOUT
+IDD_DIALOG_SETTINGS DIALOGEX 0, 0, 309, 176
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "SpectREM Settings"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
- 0
+ DEFPUSHBUTTON "OK",IDOK,198,155,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,252,155,50,14
END
-#endif // English (United States) resources
-/////////////////////////////////////////////////////////////////////////////
-
/////////////////////////////////////////////////////////////////////////////
-// English (United Kingdom) resources
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_DIALOG_SETTINGS AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
-#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
@@ -173,7 +258,9 @@ BEGIN
BEGIN
MENUITEM "to 48K\tShift+F5", ID_SWITCH_TO48K
MENUITEM "to 128K\tCtrl+F5", ID_SWITCH_TO128K
- MENUITEM "Flip\tF5", ID_SWITCH_FLIP
+ MENUITEM "to +2\tAlt+F5", ID_SWITCH_TOPLUS2
+ MENUITEM "to +2A\tShift+Ctrl+F5", ID_SWITCH_TOPLUS2A
+ MENUITEM "to +3\tCtrl+Alt+F5", ID_SWITCH_TOPLUS3
END
END
POPUP "&Settings"
@@ -206,6 +293,9 @@ BEGIN
VK_F5, ID_SWITCH_FLIP, VIRTKEY, NOINVERT
VK_F5, ID_SWITCH_TO128K, VIRTKEY, CONTROL, NOINVERT
VK_F5, ID_SWITCH_TO48K, VIRTKEY, SHIFT, NOINVERT
+ VK_F5, ID_SWITCH_TOPLUS2, VIRTKEY, ALT
+ VK_F5, ID_SWITCH_TOPLUS2A, VIRTKEY, SHIFT, CONTROL
+ VK_F5, ID_SWITCH_TOPLUS3, VIRTKEY, CONTROL, ALT
VK_F1, ID_TAPE_EJECTTAPE, VIRTKEY, ALT, NOINVERT
VK_F1, ID_TAPE_INSERTTAPE, VIRTKEY, SHIFT, NOINVERT
VK_F9, ID_TAPE_REWINDTAPE, VIRTKEY, SHIFT, NOINVERT
@@ -230,6 +320,26 @@ END
// remains consistent on all systems.
IDI_ICON2 ICON "SpectREM\\Win32\\SpectREM.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_FIRSTCOLUMN "Status"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_BLOCKTYPE "Block Type"
+ IDS_FILENAME "Filename"
+ IDS_AUTOSTARTLINE "Autostart"
+ IDS_ADDRESS "Address"
+ IDS_LENGTH "Length"
+END
+
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/SpectREM/SpectREM.vcxproj b/SpectREM/SpectREM.vcxproj
index 744cf5c..09359e4 100644
--- a/SpectREM/SpectREM.vcxproj
+++ b/SpectREM/SpectREM.vcxproj
@@ -91,6 +91,7 @@
SpectREM\Emulator Core\Base;SpectREM\Emulator Core\Z80 Core;SpectREM\Emulator Core\Tape;SpectREM\Win32;SpectREM\Emulator Core\ZX Spectrum +2;SpectREM\Emulator Core\ZX Spectrum 48k;SpectREM\Emulator Core\ZX Spectrum 128k;SpectREM;%(AdditionalIncludeDirectories)
4068
false
+ MultiThreadedDebug
Windows
@@ -101,7 +102,7 @@
if not exist $(TargetDir)\ROMS mkdir $(TargetDir)\ROMS
copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
- Copies the shaders and speccy roms to the output folder
+ Copying the speccy roms to the output folder
@@ -112,6 +113,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
Disabled
_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
false
+ MultiThreadedDebug
Windows
@@ -122,7 +124,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
if not exist $(TargetDir)\ROMS mkdir $(TargetDir)\ROMS
copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
- Copies the shaders and speccy roms to the output folder
+ Copying the speccy roms to the output folder
@@ -135,6 +137,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
true
WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
false
+ MultiThreadedDebug
Windows
@@ -147,7 +150,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
if not exist $(TargetDir)\ROMS mkdir $(TargetDir)\ROMS
copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
- Copies the shaders and speccy roms to the output folder
+ Copying the speccy roms to the output folder
@@ -160,6 +163,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
true
NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
false
+ MultiThreadedDebug
Windows
@@ -172,7 +176,7 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
if not exist $(TargetDir)\ROMS mkdir $(TargetDir)\ROMS
copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
- Copies the shaders and speccy roms to the output folder
+ Copying the speccy roms to the output folder
@@ -185,7 +189,9 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
+
+
@@ -213,16 +219,20 @@ copy "$(ProjectDir)SpectREM\Emulation Core\ROMS\*.*" $(TargetDir)ROMS\*.*
+
+
+
+
false
diff --git a/SpectREM/SpectREM.vcxproj.filters b/SpectREM/SpectREM.vcxproj.filters
index ecd91df..db4e6b0 100644
--- a/SpectREM/SpectREM.vcxproj.filters
+++ b/SpectREM/SpectREM.vcxproj.filters
@@ -99,6 +99,8 @@
Win32
+
+
@@ -156,6 +158,11 @@
Win32
+
+ Win32
+
+
+
@@ -166,6 +173,7 @@
+
diff --git a/SpectREM/SpectREM/Emulation Core/ROMS/plus3-0.rom b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-0.rom
new file mode 100644
index 0000000..29e047c
Binary files /dev/null and b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-0.rom differ
diff --git a/SpectREM/SpectREM/Emulation Core/ROMS/plus3-1.rom b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-1.rom
new file mode 100644
index 0000000..0f8113b
Binary files /dev/null and b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-1.rom differ
diff --git a/SpectREM/SpectREM/Emulation Core/ROMS/plus3-2.rom b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-2.rom
new file mode 100644
index 0000000..d4b02bf
Binary files /dev/null and b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-2.rom differ
diff --git a/SpectREM/SpectREM/Emulation Core/ROMS/plus3-3.rom b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-3.rom
new file mode 100644
index 0000000..e83937d
Binary files /dev/null and b/SpectREM/SpectREM/Emulation Core/ROMS/plus3-3.rom differ
diff --git a/SpectREM/SpectREM/Emulation Core/Tape/Tape.hpp b/SpectREM/SpectREM/Emulation Core/Tape/Tape.hpp
index 222f918..ecce848 100755
--- a/SpectREM/SpectREM/Emulation Core/Tape/Tape.hpp
+++ b/SpectREM/SpectREM/Emulation Core/Tape/Tape.hpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
// - Tape Block
@@ -177,7 +178,6 @@ class Tape
void eject();
// Functions used to get details of the loaded tape that can then be used in a UI to display those details
- void updateStatus(); // Called when the internal status of the current tape changes and in turn calls any registered callback function
size_t numberOfTapeBlocks();
void setCurrentBlock(uint32_t blockIndex);
diff --git a/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/Snapshot.cpp b/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/Snapshot.cpp
index 5f80a9e..f6e4472 100755
--- a/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/Snapshot.cpp
+++ b/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/Snapshot.cpp
@@ -615,6 +615,7 @@ void ZXSpectrum::snapshotExtractMemoryBlock(const char *buffer, size_t bufferSiz
{
while (memoryPtr < unpackedLength + memAddr && memoryPtr < memoryRam.size())
{
+ std::string n = std::string("memoryPtr: ") + std::to_string(memoryPtr) + std::string(" unpackedLength: ") + std::to_string(unpackedLength) + std::string(" memAddr: ") + std::to_string(memAddr) + std::string(" filePtr+1: ") + std::to_string(filePtr + 1) + " - " + std::to_string(fileBytes.size()) + "\n";
uint8_t byte1 = fileBytes[filePtr];
if (byte1 == 0xed && filePtr + 1 < fileBytes.size())
@@ -721,6 +722,8 @@ std::string ZXSpectrum::snapshotHardwareTypeForVersion(uint32_t version, uint32_
int32_t ZXSpectrum::snapshotMachineInSnapshotWithPath(const char *path)
{
+ ayEnabledSnapshot = false;
+
std::ifstream stream(path, std::ios::binary | std::ios::ate);
if (!stream.ios_base::good()) {
return -1;
@@ -763,6 +766,7 @@ int32_t ZXSpectrum::snapshotMachineInSnapshotWithPath(const char *path)
switch (version) {
case 1:
machineType = eZXSpectrum48;
+ ayEnabledSnapshot = false;
break;
case 2:
@@ -782,6 +786,8 @@ int32_t ZXSpectrum::snapshotMachineInSnapshotWithPath(const char *path)
machineType = eZXSpectrum48;
break;
}
+ IsAYSnapshot(((uint8_t*)&pFileBytes[37])[0]);
+
break;
case 3:
@@ -814,6 +820,8 @@ int32_t ZXSpectrum::snapshotMachineInSnapshotWithPath(const char *path)
default:
break;
}
+ IsAYSnapshot(((uint8_t*)&pFileBytes[37])[0]);
+
break;
}
}
@@ -821,3 +829,17 @@ int32_t ZXSpectrum::snapshotMachineInSnapshotWithPath(const char *path)
return machineType;
}
+bool ZXSpectrum::IsAYSnapshot(uint8_t infoByte)
+{
+ if (infoByte & 4)
+ {
+ ayEnabledSnapshot = true;
+ }
+ else
+ {
+ ayEnabledSnapshot = false;
+ }
+ return ayEnabledSnapshot;
+}
+
+
diff --git a/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/ZXSpectrum.hpp b/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/ZXSpectrum.hpp
index 585c669..9e55bce 100755
--- a/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/ZXSpectrum.hpp
+++ b/SpectREM/SpectREM/Emulation Core/ZX_Spectrum_Core/ZXSpectrum.hpp
@@ -168,6 +168,8 @@ class ZXSpectrum
float b;
float a;
} Color;
+ // Holds whether AY is enabled for a snapshot (handy for 48k + AY)
+ bool ayEnabledSnapshot = false;
public:
@@ -195,6 +197,7 @@ class ZXSpectrum
Tape::FileResponse snapshotSNALoadWithPath(const std::string path);
Tape::FileResponse snapshotSNALoadWithBuffer(const char *buffer, size_t size);
int snapshotMachineInSnapshotWithPath(const char *path);
+ bool IsAYSnapshot(uint8_t infoByte);
SnapshotData snapshotCreateSNA();
SnapshotData snapshotCreateZ80();
diff --git a/SpectREM/SpectREM/Win32/CSettingsDialog.cpp b/SpectREM/SpectREM/Win32/CSettingsDialog.cpp
new file mode 100644
index 0000000..d172503
--- /dev/null
+++ b/SpectREM/SpectREM/Win32/CSettingsDialog.cpp
@@ -0,0 +1,16 @@
+#include "CSettingsDialog.h"
+
+
+CSettingsDialog::CSettingsDialog()
+{
+
+}
+
+CSettingsDialog::~CSettingsDialog()
+{
+
+}
+
+
+
+
diff --git a/SpectREM/SpectREM/Win32/CSettingsDialog.h b/SpectREM/SpectREM/Win32/CSettingsDialog.h
new file mode 100644
index 0000000..7cbd7ad
--- /dev/null
+++ b/SpectREM/SpectREM/Win32/CSettingsDialog.h
@@ -0,0 +1,17 @@
+#ifndef CSettingsDialog_hpp
+#define CSettingsDialog_hpp
+
+
+#pragma once
+class CSettingsDialog
+{
+public:
+ CSettingsDialog();
+ ~CSettingsDialog();
+
+
+
+};
+
+
+#endif /* CSettingsDialog_hpp */
diff --git a/SpectREM/SpectREM/Win32/OpenGLView.cpp b/SpectREM/SpectREM/Win32/OpenGLView.cpp
index d17eb0c..fa8cee1 100644
--- a/SpectREM/SpectREM/Win32/OpenGLView.cpp
+++ b/SpectREM/SpectREM/Win32/OpenGLView.cpp
@@ -13,6 +13,8 @@
#include
#include "OpenGLView.hpp"
#include
+#include "PMDawn.hpp"
+
#ifdef _DEBUG
#define GL_CHECK(stmt) do { \
@@ -29,11 +31,13 @@
static const GLint textureUnit0 = 0;
static const GLint textureUnit1 = 1;
+static const GLint textureUnit2 = 2;
static const GLuint borderWidth = 32;
static const GLuint screenWidth = borderWidth + 256 + borderWidth;
static const GLuint screenHeight = borderWidth + 192 + borderWidth;
+static char const * reflectionFilename = "bluesbro.png";
static char const * cS_DISPLAY_TEXTURE = "s_displayTexture";
static char const * cS_CLUT_TEXTURE = "s_clutTexture";
static char const * cS_REFLECTION_TEXTURE = "s_reflectionTexture";
@@ -111,9 +115,9 @@ const Color CLUT[] = {
//-----------------------------------------------------------------------------------------
-OpenGLView::OpenGLView()
+OpenGLView::OpenGLView(std::string bpath)
{
-
+ appBasePath = bpath;
}
@@ -137,6 +141,18 @@ void OpenGLView::Deinit()
void OpenGLView::Resize(int width, int height)
{
+ GL_CHECK(glViewport(0, 0, width, height));
+ _viewWidth = width;
+ _viewHeight = height;
+}
+
+//-----------------------------------------------------------------------------------------
+
+void OpenGLView::Resize(int x, int y, int width, int height)
+{
+ GL_CHECK(glViewport(x, y, width, height));
+ _viewTop = y;
+ _viewLeft = x;
_viewWidth = width;
_viewHeight = height;
}
@@ -188,7 +204,7 @@ bool OpenGLView::Init(HWND hWnd, int width, int height, uint16_t idClutVert, uin
return false;
}
- // Set the 4.0 version of OpenGL in the attribute list.
+ // Set the 3.2 version of OpenGL in the attribute list.
int contextAL[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
@@ -202,14 +218,57 @@ bool OpenGLView::Init(HWND hWnd, int width, int height, uint16_t idClutVert, uin
return false;
}
- glClearColor(1.0f, 0.0f, 0.4f, 1.0f);
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
LoadShaders(idClutVert, idClutFrag, idDisplayVert, idDisplayFrag, idType);
+ LoadFileTextures();
SetupTexture();
SetupQuad();
return true;
}
+//-----------------------------------------------------------------------------------------
+
+void OpenGLView::LoadFileTextures()
+{
+ // bluesbro.png
+ //LoadBitmap(appBasePath + std::string("bluesbro.png"), _reflectionTexture);
+ LoadBitmap(L"C:\\Users\\polom\\source\\repos\\SpectREMCPP\\SpectREM\\x64\\Debug\\bluesbro.bmp", _reflectionTexture);
+}
+
+bool OpenGLView::LoadBitmap(LPTSTR szFileName, GLuint& texid) // Creates Texture From A Bitmap File
+{
+ HBITMAP hBMP; // Handle Of The Bitmap
+ BITMAP BMP; // Bitmap Structure
+
+ glGenTextures(1, &texid); // Create The Texture
+ hBMP = (HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
+
+ if (!hBMP) // Does The Bitmap Exist?
+ return FALSE; // If Not Return False
+
+ GetObject(hBMP, sizeof(BMP), &BMP); // Get The Object
+ // hBMP: Handle To Graphics Object
+ // sizeof(BMP): Size Of Buffer For Object Information
+ // &BMP: Buffer For Object Information
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // Pixel Storage Mode (Word Alignment / 4 Bytes)
+
+ //// Typical Texture Generation Using Data From The Bitmap
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, _reflectionTexture); // Bind To The Texture ID
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear Min Filter
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Mag Filter
+ //glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
+
+ DeleteObject(hBMP); // Delete The Object
+ //GL_CHECK(glUniform1i(s_reflectionTexture, textureUnit2));
+ return TRUE; // Loading Was Successful
+
+ //GL_CHECK(glActiveTexture(GL_TEXTURE1));
+ //GL_CHECK(glBindTexture(GL_TEXTURE_2D, _clutTexture));
+ //GL_CHECK(glUniform1i(s_clutTexture, textureUnit1));
+}
//-----------------------------------------------------------------------------------------
@@ -253,7 +312,8 @@ void OpenGLView::LoadShaders(uint16_t vertCLUT, uint16_t fragCLUT, uint16_t vert
_clutShaderProg = prepareShaderProgram(vertCLUTR, fragCLUTR);
GL_CHECK(s_displayTexture = glGetUniformLocation(_clutShaderProg, cS_DISPLAY_TEXTURE));
GL_CHECK(s_clutTexture = glGetUniformLocation(_clutShaderProg, cS_CLUT_TEXTURE));
-
+ //GL_CHECK(s_reflectionTexture = glGetUniformLocation(_displayShaderProg, cS_DISPLAY_TEXTURE));
+
// Display Shader program
std::string vertDisplayR;
hRes = FindResource(0, MAKEINTRESOURCE(vertDISPLAY), MAKEINTRESOURCE(idtype));
@@ -356,14 +416,14 @@ void OpenGLView::SetupTexture()
//-----------------------------------------------------------------------------------------
-void OpenGLView::UpdateTextureData(unsigned char *pData)
+void OpenGLView::UpdateTextureData(unsigned char *pData, GLint vX, GLint vY)
{
- glClearColor(0.0f, 1.0f, 1.0f, 0.5f);
+ glClearColor(1.0f, 0.0f, 0.0f, 0.5f); // this changes the main colour behind the texture...
glClear(GL_COLOR_BUFFER_BIT);
// Render the output to a texture which has the default dimensions of the output image
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, _clutFrameBuffer));
- GL_CHECK(glViewport(0, 0, screenWidth, screenHeight));
+ GL_CHECK(glViewport(vX, vY, screenWidth, screenHeight));
GL_CHECK(glUseProgram(_clutShaderProg));
GL_CHECK(glActiveTexture(GL_TEXTURE0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, _clutInputTexture));
@@ -374,6 +434,10 @@ void OpenGLView::UpdateTextureData(unsigned char *pData)
GL_CHECK(glBindTexture(GL_TEXTURE_2D, _clutTexture));
GL_CHECK(glUniform1i(s_clutTexture, textureUnit1));
+ //GL_CHECK(glActiveTexture(GL_TEXTURE2));
+ //GL_CHECK(glBindTexture(GL_TEXTURE_2D, _reflectionTexture));
+ //GL_CHECK(glUniform1i(s_clutTexture, textureUnit2));
+
GL_CHECK(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
paintGL();
glFlush();
@@ -514,7 +578,9 @@ void OpenGLView::paintGL()
{
// Render the texture to the actual screen, this time using the size of the screen as the viewport
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
- GL_CHECK(glViewport(0, 0, static_cast(_viewWidth), static_cast(_viewHeight)));
+ GL_CHECK(glViewport(
+ static_cast(_viewLeft), static_cast(_viewTop),
+ static_cast(_viewWidth), static_cast(_viewHeight)));
GL_CHECK(glUseProgram(_displayShaderProg));
GL_CHECK(glActiveTexture(GL_TEXTURE0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, _clutOutputTexture));
@@ -527,13 +593,13 @@ void OpenGLView::paintGL()
GL_CHECK(glProgramUniform1f(_displayShaderProg, u_brightness, 1.0f));
GL_CHECK(glProgramUniform1f(_displayShaderProg, u_scanlineSize, 960));
GL_CHECK(glProgramUniform1f(_displayShaderProg, u_scanlines, 0));
- GL_CHECK(glProgramUniform1f(_displayShaderProg, u_screenCurve, 0.3f));
- GL_CHECK(glProgramUniform1f(_displayShaderProg, u_pixelFilterValue, 0.15f));
+ GL_CHECK(glProgramUniform1f(_displayShaderProg, u_screenCurve, u_screenCurveValue));// 0.3f));
+ GL_CHECK(glProgramUniform1f(_displayShaderProg, u_pixelFilterValue, 0.15));// 0.15f));
GL_CHECK(glProgramUniform1f(_displayShaderProg, u_rgbOffset, 0));
- GL_CHECK(glProgramUniform1i(_displayShaderProg, u_showVignette, true));
- GL_CHECK(glProgramUniform1f(_displayShaderProg, u_vignetteX, 0.31f));
- GL_CHECK(glProgramUniform1f(_displayShaderProg, u_vignetteY, 6.53f));
- GL_CHECK(glProgramUniform1i(_displayShaderProg, u_showReflection, false));
+ GL_CHECK(glProgramUniform1i(_displayShaderProg, u_showVignette, u_showVignetteValue));
+ GL_CHECK(glProgramUniform1f(_displayShaderProg, u_vignetteX, 0.31f));// 0.31f));
+ GL_CHECK(glProgramUniform1f(_displayShaderProg, u_vignetteY, 7.10f));// 6.53f));
+ GL_CHECK(glProgramUniform1i(_displayShaderProg, u_showReflection, u_showReflectionValue));
//GL_CHECK(glProgramUniform1f(_displayShaderProg, u_time, static_cast(QDateTime::currentMSecsSinceEpoch())));
GL_CHECK(glProgramUniform2f(_displayShaderProg, u_screenSize, static_cast(_viewWidth), static_cast(_viewHeight)));
@@ -607,4 +673,56 @@ void OpenGLView::CheckOpenGLError(const char* stmt, const char* fname, int line)
}
+//-----------------------------------------------------------------------------------------
+void OpenGLView::ShaderSetScreenCurve(GLfloat curve)
+{
+ u_screenCurveValue = curve;
+ PMDawn::Log(PMDawn::LOG_INFO, "ShaderSetScreenCurve = " + std::to_string(curve));
+}
+
+//-----------------------------------------------------------------------------------------
+
+void OpenGLView::ShaderSetVignette(bool onoff)
+{
+ u_showVignetteValue = onoff;
+ if (onoff)
+ {
+ PMDawn::Log(PMDawn::LOG_INFO, "ShaderSetVignette = true");
+ }
+ else
+ {
+ PMDawn::Log(PMDawn::LOG_INFO, "ShaderSetVignette = false");
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+
+void OpenGLView::ShaderSetReflection(bool onoff)
+{
+ u_showReflectionValue = onoff;
+ if (onoff)
+ {
+ PMDawn::Log(PMDawn::LOG_INFO, "ShaderSetReflection = true");
+ }
+ else
+ {
+ PMDawn::Log(PMDawn::LOG_INFO, "ShaderSetReflection = false");
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------------------
+
+
//-----------------------------------------------------------------------------------------
diff --git a/SpectREM/SpectREM/Win32/OpenGLView.hpp b/SpectREM/SpectREM/Win32/OpenGLView.hpp
index 277c0b5..2342748 100644
--- a/SpectREM/SpectREM/Win32/OpenGLView.hpp
+++ b/SpectREM/SpectREM/Win32/OpenGLView.hpp
@@ -40,6 +40,7 @@
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
#define GL_BGRA 0x80E1
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
@@ -100,15 +101,23 @@ typedef void (APIENTRY * PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint locat
class OpenGLView
{
public:
- OpenGLView();
+ OpenGLView(std::string bpath);
~OpenGLView();
public:
void Deinit();
bool Init(HWND hWnd, int width, int height, const uint16_t idClutVert, uint16_t idClutFrag, uint16_t idDisplayVert, uint16_t idDisplayFrag, LPWSTR idType);
- void UpdateTextureData(unsigned char *pData);
+ void UpdateTextureData(unsigned char *pData, GLint vX, GLint vY);
void OpenGLView::Resize(int width, int height);
+ void OpenGLView::Resize(int x, int y, int width, int height);
+ void OpenGLView::ShaderSetScreenCurve(GLfloat curve);
+ void OpenGLView::ShaderSetVignette(bool onoff);
+ void OpenGLView::ShaderSetReflection(bool onoff);
+ void OpenGLView::LoadFileTextures();
+ bool OpenGLView::LoadBitmap(LPTSTR szFileName, GLuint& texid);
+
+
private:
bool InitialiseExtensions();
bool LoadExtensionList();
@@ -123,6 +132,8 @@ class OpenGLView
public:
+ std::string appBasePath;
+
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
@@ -192,7 +203,9 @@ class OpenGLView
*/
GLuint _viewWidth = 320;
- GLuint _viewHeight = 256;
+ GLuint _viewHeight = 256;
+ GLuint _viewTop = 0;
+ GLuint _viewLeft = 0;
GLuint _vertexBuffer;
GLuint _vertexArray;
@@ -204,10 +217,12 @@ class OpenGLView
GLuint _clutInputTexture;
GLuint _clutTexture;
GLuint _clutOutputTexture;
+ GLuint _reflectionTexture;
+
// Display shader uniforms/samplers
GLuint displayDepthBuffer;
- GLuint reflectionTexture;
+
GLint s_displayTexture;
GLint s_texture;
GLint s_reflectionTexture;
@@ -228,7 +243,9 @@ class OpenGLView
GLint u_time;
GLint u_screenSize;
-
+ bool u_showVignetteValue;
+ GLfloat u_screenCurveValue;
+ bool u_showReflectionValue;
diff --git a/SpectREM/SpectREM/Win32/PMDawn.cpp b/SpectREM/SpectREM/Win32/PMDawn.cpp
index f6eef75..bac94b0 100644
--- a/SpectREM/SpectREM/Win32/PMDawn.cpp
+++ b/SpectREM/SpectREM/Win32/PMDawn.cpp
@@ -6,8 +6,6 @@
//
//
-#pragma once
-
#include
#include
#include
@@ -15,37 +13,17 @@
#include
#include
#include
+#include
+#include
+#include "PMDawn.hpp"
namespace PMDawn
{
- // LogType:
- // LOG_INFO is for general info
- // LOG_DEBUG is for debugging info, note that it will also include INFO
- enum LogType
- {
- LOG_NONE, LOG_INFO, LOG_DEBUG, LOG_FULL
- };
-
- //-----------------------------------------------------------------------------------------
-
- static bool LogOpenOrCreate(std::string filename);
- static bool Log(LogType lType, std::string text);
- static bool LogClose();
- static std::string GetTimeAsString();
- static std::string GetApplicationBasePath();
- static std::string GetCurrentDirectoryAsString();
- static std::vector GetFilesInDirectory(std::string folder, std::string filter);
-
//-----------------------------------------------------------------------------------------
-
- static uint8_t logLevel = LOG_NONE;
- static const std::string logFilename = "spectrem_win32.log";
- static std::string logFullFilename = "";
- static std::ofstream logFileStream;
-
+
//-----------------------------------------------------------------------------------------
- static bool fileExists(const std::string& filename)
+ bool PMDawn::fileExists(const std::string& filename)
{
struct stat fileBuffer;
return (stat(filename.c_str(), &fileBuffer) == 0);
@@ -53,7 +31,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static std::string GetTimeAsString()
+ std::string PMDawn::GetTimeAsString()
{
time_t rawtime;
struct tm timeinfo;
@@ -67,7 +45,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static std::string GetCurrentDirectoryAsString()
+ std::string PMDawn::GetCurrentDirectoryAsString()
{
char basePT[MAX_PATH];
GetCurrentDirectoryA(MAX_PATH, basePT);
@@ -79,7 +57,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static std::string GetApplicationBasePath()
+ std::string PMDawn::GetApplicationBasePath()
{
char appDirT[MAX_PATH];
GetModuleFileNameA(NULL, appDirT, MAX_PATH);
@@ -89,7 +67,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static bool LogOpenOrCreate(std::string filename)
+ bool PMDawn::LogOpenOrCreate(std::string filename)
{
logFileStream.open(filename, std::ios::ate | std::ios::app);
if (logFileStream.is_open())
@@ -105,7 +83,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static bool Log(LogType lType, std::string text)
+ bool PMDawn::Log(LogType lType, std::string text)
{
// we will use the file and always append to it
if (logFileStream.is_open())
@@ -123,7 +101,7 @@ namespace PMDawn
lty = "[UNKNOWN]";
break;
}
- logFileStream << GetTimeAsString().c_str() << " : " << lty.c_str() << " : " << text.c_str() << std::endl;
+ logFileStream << GetTimeAsString().c_str() << " : " << lty.c_str() << " : " << text.c_str() << "\n";
return true;
}
else
@@ -134,7 +112,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static bool LogClose()
+ bool PMDawn::LogClose()
{
if (logFileStream.is_open())
{
@@ -149,7 +127,7 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
- static std::vector GetFilesInDirectory(std::string folder, std::string filter)
+ std::vector PMDawn::GetFilesInDirectory(std::string folder, std::string filter)
{
std::vector fileList;
std::string fullPath = folder + filter;
@@ -175,26 +153,216 @@ namespace PMDawn
//-----------------------------------------------------------------------------------------
+ std::string GetFolderUsingDialog(std::string initialFolder = "")
+ {
+ wchar_t* fold;
+ std::string fl;
+ bool error = true;
+
+ IFileDialog* pfd;
+ if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
+ {
+ DWORD dwOptions;
+ if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
+ {
+ pfd->SetOptions(dwOptions | FOS_PICKFOLDERS); // FOS_FORCEFILESYSTEM
+ }
+ if (SUCCEEDED(pfd->Show(NULL)))
+ {
+ IShellItem* psi;
+ if (SUCCEEDED(pfd->GetResult(&psi)))
+ {
+ if (!SUCCEEDED(psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &fold)))
+ {
+ MessageBoxA(NULL, "Failed to get folder path", "Error", NULL);
+
+ }
+ else
+ {
+ // If we get here then we should have a path :)
+ error = false;
+ }
+ psi->Release();
+ }
+ }
+ pfd->Release();
+ }
+ if (!error)
+ {
+ std::wstring fstr(fold);
+ std::string fs(fstr.begin(), fstr.end());
+ return fs;
+ }
+ else
+ {
+ return "";
+ }
+ }
//-----------------------------------------------------------------------------------------
+ std::string PMDawn::GetFilenameUsingDialog(std::string initialFolder)
+ {
+ wchar_t* fold;
+ std::string fl;
+ bool error = true;
+ IFileDialog* pfd;
+ if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd))))
+ {
+ DWORD dwOptions;
+ if (SUCCEEDED(pfd->GetOptions(&dwOptions)))
+ {
+ pfd->SetOptions(dwOptions); // FOS_FORCEFILESYSTEM
+ }
+ if (SUCCEEDED(pfd->Show(NULL)))
+ {
+ IShellItem* psi;
+ if (SUCCEEDED(pfd->GetResult(&psi)))
+ {
+ if (!SUCCEEDED(psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &fold)))
+ {
+ MessageBoxA(NULL, "Failed to get file path", "Error", NULL);
+
+ }
+ else
+ {
+ // If we get here then we should have a path :)
+ error = false;
+ }
+ psi->Release();
+ }
+ }
+ pfd->Release();
+ }
+ if (!error)
+ {
+ std::wstring fstr(fold);
+ std::string fs(fstr.begin(), fstr.end());
+
+ return fs;
+ }
+ else
+ {
+ return "";
+ }
+ }
//-----------------------------------------------------------------------------------------
+ //HWND CreateButton(HWND owner, std::string buttonText, int x, int y, int w, int h)
+ //{
+ // //LPCWSTR lpS = stdStringToLpwstr(buttonText);
+ // HWND btn = CreateWindow(
+ // L"BUTTON", // Class
+ // L"Ok",//buttonText.c_str(), // Button text
+ // WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
+ // x, // x position
+ // y, // y position
+ // w, // Button width
+ // h, // Button height
+ // owner, // Parent window
+ // NULL, // No menu.
+ // NULL, // Instance
+ // NULL); // Pointer not needed.
+ // return btn;
+ //}
+
+ ////-----------------------------------------------------------------------------------------
+
+ LPCWSTR stdStringToLpcwstr(std::string input)
+ {
+ std::wstring stemp = std::wstring(input.begin(), input.end());
+ LPCWSTR sw = stemp.c_str();
+ return sw;
+ }
//-----------------------------------------------------------------------------------------
+ std::wstring PMDawn::s2ws(const std::string& s)
+ {
+ int len;
+ int slength = (int)s.length() + 1;
+ len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
+ wchar_t* buf = new wchar_t[len];
+ MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
+ std::wstring r(buf);
+ delete[] buf;
+ return r;
+ }
+ void AddItemToListView(gTAPEBLOCK& theBlock, HWND hwndListView)
+ {
+ // Status / BlockType / Filename / AutostartLine / Address / Length
+ // TAPE block types
+ /*enum
+ {
+ ePROGRAM_HEADER = 0,
+ eNUMERIC_DATA_HEADER,
+ eALPHANUMERIC_DATA_HEADER,
+ eBYTE_HEADER,
+ eDATA_BLOCK,
+ eFRAGMENTED_DATA_BLOCK,
+ eUNKNOWN_BLOCK = 99
+ };*/
+
+ if (!ShowAlternativeTapeLengths)
+ {
+ if (theBlock.length < 2)
+ {
+ theBlock.length = 0;
+ }
+ else
+ {
+ theBlock.length -= 2;
+ }
+ }
- //-----------------------------------------------------------------------------------------
+ LVITEM lvi;
+ lvi.mask = LVIF_TEXT | LVIF_COLFMT;
+ lvi.iItem = 0;
+ lvi.iSubItem = 0;
+ std::wstring ws;
+ ws.assign(theBlock.status.begin(), theBlock.status.end());
+ lvi.pszText = &ws[0];
+ ListView_InsertItem(hwndListView, &lvi);
+ std::wstring bt;
+ bt.assign(theBlock.blocktype.begin(), theBlock.blocktype.end());
+ ListView_SetItemText(hwndListView, 0, 1, &bt[0]);
+ std::wstring fn;
+ fn.assign(theBlock.filename.begin(), theBlock.filename.end());
+ ListView_SetItemText(hwndListView, 0, 2, &fn[0]);
+ std::wstring asl;
+ if (theBlock.autostartline != 0)
+ {
+ asl = std::to_wstring(theBlock.autostartline);
+ }
+ else
+ {
+ asl = L"";
+ }
+ ListView_SetItemText(hwndListView, 0, 3, &asl[0]);
+ std::wstring addy;
+ if (theBlock.address != 0)
+ {
+ addy = std::to_wstring(theBlock.address);
+ }
+ else
+ {
+ addy = L"";
+ }
+ ListView_SetItemText(hwndListView, 0, 4, &addy[0]);
+ std::wstring length;
+ length = std::to_wstring(theBlock.length);
+ ListView_SetItemText(hwndListView, 0, 5, &length[0]);
+ }
}
\ No newline at end of file
diff --git a/SpectREM/SpectREM/Win32/PMDawn.hpp b/SpectREM/SpectREM/Win32/PMDawn.hpp
new file mode 100644
index 0000000..322ba50
--- /dev/null
+++ b/SpectREM/SpectREM/Win32/PMDawn.hpp
@@ -0,0 +1,67 @@
+//
+// PMDawn.hpp
+// This window holds the tape viewer which allows the user to interact with the tape blocks etc.
+//
+// Created by John Young on 05-01-2020
+//
+//
+
+#ifndef PMDawn_hpp
+#define PMDawn_hpp
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+namespace PMDawn
+{
+ struct gTAPEBLOCK {
+ std::string status;
+ std::string blocktype;
+ std::string filename;
+ uint16_t autostartline;
+ uint16_t address;
+ uint16_t length;
+ };
+
+ static std::vector pData;
+
+ // LogType:
+ // LOG_INFO is for general info
+ // LOG_DEBUG is for debugging info, note that it will also include INFO
+ enum LogType
+ {
+ LOG_NONE, LOG_INFO, LOG_DEBUG, LOG_FULL
+ };
+
+ static uint8_t logLevel = LOG_NONE;
+ const std::string logFilename = "spectrem_win32.log";
+ static std::string logFullFilename = "";
+ static std::ofstream logFileStream;
+ static bool ShowAlternativeTapeLengths = false;
+
+ bool Log(LogType lType, std::string text);
+ bool LogClose(void);
+ std::string GetTimeAsString(void);
+ std::string GetApplicationBasePath(void);
+ std::string GetCurrentDirectoryAsString(void);
+ std::vector GetFilesInDirectory(std::string folder, std::string filter);
+ //static HWND PMDawn::CreateButton(HWND owner, std::string buttonText, int x, int y, int w, int h);
+ LPCWSTR stdStringToLpcwstr(std::string input);
+ std::wstring s2ws(const std::string& s);
+ std::string GetFilenameUsingDialog(std::string initialFolder);
+ std::string GetFolderUsingDialog(std::string initialFolder);
+ bool fileExists(const std::string& filename);
+ bool LogOpenOrCreate(std::string filename);
+ void AddItemToListView(gTAPEBLOCK& theBlock, HWND hwndListView);
+
+
+}
+#endif /* PMDawn_hpp */
+
diff --git a/SpectREM/SpectREM/Win32/TapeViewerWindow.cpp b/SpectREM/SpectREM/Win32/TapeViewerWindow.cpp
index 9f62af2..826ea3a 100644
--- a/SpectREM/SpectREM/Win32/TapeViewerWindow.cpp
+++ b/SpectREM/SpectREM/Win32/TapeViewerWindow.cpp
@@ -1,28 +1,272 @@
//
-// TapeViewerWindow.cpp
-// This window holds the tape viewer which allows the user to interact with the tape blocks etc.
+// PMDawn.hpp
+//
//
-// Created by John Young on 05-01-2020
+// Created by John Young on 11-01-2020
//
//
#include
#include
+#include
#include "../../resource.h"
-#include "PMDawn.cpp"
+#include "PMDawn.hpp"
#include "TapeViewerWindow.hpp"
+#include "..\Emulation Core\Tape\Tape.hpp"
+#include
+#include
+#define PM_TAPE_PAUSED 60
+#define PM_TAPE_PLAYING 61
+
+#define PM_TAPEDATA_FULL 77
+#define PM_TAPE_COMMAND 79
+#define PM_TAPE_EJECTED 80
+#define PM_TAPE_ACTIVEBLOCK 81
+#define PM_TAPE_PLAY 82
+#define PM_TAPE_PAUSE 83
+#define PM_TAPE_REWIND 84
+#define PM_TAPE_INSERT 85
+#define PM_TAPE_EJECT 86
+#define PM_TAPE_SAVE 87
+#define PM_TAPE_UPDATE_PLAYPAUSEETC 88
+
+// Status / BlockType / Filename / AutostartLine / Address / Length
//-----------------------------------------------------------------------------------------
+HWND TapeViewer::tapeViewerWindowInternal = nullptr;
+HWND mHandle;
+static std::vector* myP;
+static uint16_t currentActiveBlock;
+static bool bIsPlaying = false; // false is paused, true is playing
+
+TapeViewer::~TapeViewer()
+{
+ //
+}
+
LRESULT CALLBACK TapeViewer::WndProcTV(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
+ static HWND hwndOKButton;
+ static HWND hwndCancelButton;
+ static HWND hwndPlayButton;
+ static HWND hwndPauseButton;
+ static HWND hwndRewindButton;
+ static HWND hwndInsertButton;
+ static HWND hwndEjectButton;
+ static HWND hwndSaveButton;
+ static HWND hwndListView;
+
switch (msg)
{
+ case WM_CREATE:
+ RECT rect;
+
+ GetClientRect(hwnd, &rect);
+
+ // Create buttons for tape control (Play/Pause/Rewind/Eject/Save)
+ hwndPlayButton = CreateWindow(TEXT("button"),
+ TEXT("Play"),
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer,
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_PLAY,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+ hwndPauseButton = CreateWindow(TEXT("button"),
+ TEXT("Pause"),
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer + (2 * buttonYBuffer),
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_PAUSE,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+ hwndRewindButton = CreateWindow(TEXT("button"),
+ TEXT("Rewind"),
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer + (4 * buttonYBuffer),
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_REWIND,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+ hwndInsertButton = CreateWindow(TEXT("button"),
+ TEXT("Insert"),
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer + (7 * buttonYBuffer),
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_INSERT,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+ hwndEjectButton = CreateWindow(TEXT("button"),
+ TEXT("Eject"),
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer + (9 * buttonYBuffer),
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_EJECT,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+ hwndSaveButton = CreateWindow(TEXT("button"),
+ TEXT("Save"),
+ WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
+ rect.right - 100 - windowFrameBuffer, rect.top + windowFrameBuffer + (12 * buttonYBuffer),
+ 100, 20,
+ hwnd,
+ (HMENU)IDC_BUTTON_SAVE,
+ ((LPCREATESTRUCT)lParam)->hInstance,
+ NULL);
+
+
+ // Create a listbox to hold the tape data - Status/BlockType/Filename/AutostartLine/Address/Length
+ hwndListView = CreateListView(hwnd, lParam, rect);
+ if (hwndListView == NULL)
+ {
+ MessageBox(hwnd, TEXT("Couldn't create listview!"), TEXT("LISTVIEW"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ return 0;
+ }
+ else
+ {
+ bool addItems = InitListViewColumns(hwndListView, ((LPCREATESTRUCT)lParam)->hInstance);
+ if (addItems == false)
+ {
+ MessageBox(hwnd, TEXT("Couldn't add items!"), TEXT("LISTVIEW"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ return 0;
+ }
+ else
+ {
+ LVITEM lvi;
+
+ lvi.mask = LVIF_TEXT | LVIF_COLFMT;
+ ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT);
+ }
+ }
+ return 0;
+ break;
+
+
+ case WM_USER + 2:
+ {
+ if (wParam == PM_TAPEDATA_FULL)
+ {
+ if (hwndListView != nullptr) {
+ ListView_DeleteAllItems(hwndListView);
+ size_t numBlocks = lParam;
+
+ myP = (std::vector*)lParam;
+
+ size_t nn = myP->size();
+ if (nn == 0)
+ {
+ MessageBox(hwnd, TEXT("PMDawn::pData.size() is 0 !!"), TEXT("Tape Viewer"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ return 0;
+ }
+
+ for (int i = nn - 1; i >= 0; i--)
+ {
+ PMDawn::gTAPEBLOCK theBlock = myP->at(i);
+ PMDawn::AddItemToListView(theBlock, hwndListView);
+ }
+
+ ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT);
+ currentActiveBlock = 0;
+ ListView_SetItemText(hwndListView, currentActiveBlock, 0, TEXT("PAUSED"));
+ return 0;
+ }
+ }
+ if (wParam == PM_TAPE_EJECTED)
+ {
+ if (hwndListView != nullptr) {
+ ListView_DeleteAllItems(hwndListView);
+ currentActiveBlock = -1;
+ return 0;
+ }
+ }
+ if (wParam == PM_TAPE_ACTIVEBLOCK)
+ {
+ UpdateActiveBlock(hwndListView, lParam);
+ return 0;
+ }
+ if (wParam == PM_TAPE_UPDATE_PLAYPAUSEETC)
+ {
+ if (lParam == 1)
+ {
+ // The tape is playing the current block
+ bIsPlaying = true;
+ UpdateActiveBlock(hwndListView, currentActiveBlock);
+ }
+ else
+ {
+ // The tape is paused on the current block
+ bIsPlaying = false;
+ UpdateActiveBlock(hwndListView, currentActiveBlock);
+ }
+ return 0;
+ }
+ return 0;
+ break;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_BUTTON_PLAY:
+ PostMessage(mHandle, WM_USER + 2, PM_TAPE_COMMAND, (LPARAM)PM_TAPE_PLAY);
+ ListView_SetItemText(hwndListView, currentActiveBlock, 0, TEXT("PLAYING"));
+ bIsPlaying = true;
+ break;
+ case IDC_BUTTON_PAUSE:
+ PostMessage(mHandle, WM_USER + 2, PM_TAPE_COMMAND, (LPARAM)PM_TAPE_PAUSE);
+ ListView_SetItemText(hwndListView, currentActiveBlock, 0, TEXT("PAUSED"));
+ bIsPlaying = false;
+ break;
+ case IDC_BUTTON_REWIND:
+ PostMessage(mHandle, WM_USER + 2, PM_TAPE_COMMAND, (LPARAM)PM_TAPE_REWIND);
+ ListView_SetItemText(hwndListView, currentActiveBlock, 0, TEXT(""));
+ ListView_SetItemText(hwndListView, 0, 0, TEXT("PAUSED"));
+ break;
+ case IDC_BUTTON_INSERT:
+ PostMessage(mHandle, WM_USER + 2, PM_TAPE_COMMAND, (LPARAM)PM_TAPE_INSERT);
+ bIsPlaying = false;
+ break;
+ case IDC_BUTTON_EJECT:
+ PostMessage(mHandle, WM_USER + 2, PM_TAPE_COMMAND, (LPARAM)PM_TAPE_EJECT);
+ bIsPlaying = false;
+ break;
+ case IDC_BUTTON_SAVE:
+ MessageBox(hwnd, TEXT("SAVE"), TEXT("BUTTON"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+ break;
+ }
+
+ return 0;
+ break;
+
+ case WM_NOTIFY:
+ {
+ if ((((LPNMHDR)lParam)->hwndFrom) == hwndListView)
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case NM_DBLCLK:
+ {
+ LPNMITEMACTIVATE lpNMItem = (LPNMITEMACTIVATE)lParam;
+ return 0;
+ }
+ break;
+ }
+ }
+ break;
+ }
case WM_CLOSE:
DestroyWindow(hwnd);
+ return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
+ return 0;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
@@ -32,13 +276,104 @@ LRESULT CALLBACK TapeViewer::WndProcTV(HWND hwnd, UINT msg, WPARAM wParam, LPARA
//-----------------------------------------------------------------------------------------
+void TapeViewer::UpdateActiveBlock(HWND hwndListV, LPARAM lP)
+{
+ if (hwndListV != nullptr) {
+ uint16_t blockNumber = (uint16_t)lP;
+ if (currentActiveBlock >= 0)
+ {
+ ListView_SetItemText(hwndListV, currentActiveBlock, 0, TEXT(""));
+ if (bIsPlaying)
+ {
+ ListView_SetItemText(hwndListV, blockNumber, 0, TEXT("PLAYING"));
+ }
+ else
+ {
+ ListView_SetItemText(hwndListV, blockNumber, 0, TEXT("PAUSED"));
+ }
+ currentActiveBlock = blockNumber;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+
+// InitListViewColumns: Adds columns to a list-view control.
+// hWndListView: Handle to the list-view control.
+// Returns TRUE if successful, and FALSE otherwise.
+BOOL TapeViewer::InitListViewColumns(HWND hWndListView, HINSTANCE hInst)
+{
+ WCHAR szText[256]; // Temporary buffer.
+ LVCOLUMN lvc;
+ int iCol;
+
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text,
+ // and subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+
+ // Add the columns.
+ for (iCol = 0; iCol < IDS_NUMBEROFCOLUMNS; iCol++)
+ {
+
+ lvc.iSubItem = iCol;
+ lvc.pszText = szText;
+ lvc.cx = 85; // Width of column in pixels.
+
+ //if (iCol < 2)
+ // lvc.fmt = LVCFMT_LEFT; // Left-aligned column.
+ //else
+ // lvc.fmt = LVCFMT_RIGHT; // Right-aligned column.
+
+ // Load the names of the column headings from the string resources.
+ LoadString(GetModuleHandle(NULL),
+ IDS_FIRSTCOLUMN + iCol,
+ szText,
+ sizeof(szText) / sizeof(szText[0]));
+
+ // Insert the columns into the list view.
+ auto lvCol = ListView_InsertColumn(hWndListView, iCol, &lvc);
+ if (lvCol == -1)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
-TapeViewer::TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle)
+//-----------------------------------------------------------------------------------------
+
+HWND TapeViewer::CreateListView(HWND hwnd, LPARAM lParam, RECT rect)
+{
+ // Initialize the common controls
+ INITCOMMONCONTROLSEX icex;
+ icex.dwICC = ICC_LISTVIEW_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ HWND hlv = CreateWindow(WC_LISTVIEW,
+ TEXT("ViewList"),
+ WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT | CS_DBLCLKS,
+ rect.left + windowFrameBuffer, rect.top + windowFrameBuffer,
+ rect.right - (3 * windowFrameBuffer) - 100, rect.bottom - windowFrameBuffer,
+ hwnd,
+ (HMENU)IDC_LISTVIEW_TAPEDATA,
+ GetModuleHandle(NULL),
+ NULL);
+ //ShowWindow(hlv, SW_SHOWNORMAL);
+ return hlv;
+}
+
+//-----------------------------------------------------------------------------------------
+
+TapeViewer::TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle, DWORD dwTlsIndex)
{
bool exit_tapeviewer = false;
MSG msg;
WNDCLASSEX wcextv;
+ mHandle = mainHandle;
+
memset(&wcextv, 0, sizeof(WNDCLASSEX));
wcextv.cbSize = sizeof(WNDCLASSEX);
wcextv.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
@@ -54,15 +389,23 @@ TapeViewer::TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle)
RegisterClassEx(&wcextv);
// Make sure the client size is correct
- RECT wr = { 0, 0, 640, 480 };
+ RECT wr = { 0, 0, 640, 240 };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX, FALSE);
- tapeViewerWindowInternal = CreateWindowEx(WS_EX_APPWINDOW, TEXT("SpectREM_TapeViewer"), TEXT("SpectREM - Tape Viewer"), WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX, 0, 0, wr.right - wr.left, wr.bottom - wr.top, 0, 0, mainWindowInst, 0);
+
+ // Now create the window
+ tapeViewerWindowInternal = CreateWindowEx(WS_EX_APPWINDOW, TEXT("SpectREM_TapeViewer"), TEXT("SpectREM - Tape Viewer"),
+ WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, 0, 0, mainWindowInst, 0);
if (tapeViewerWindowInternal == NULL)
{
MessageBoxA(NULL, "Tape window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return;
}
+
+ // let the main window know that we are cool for receiving updates
+ PostMessage(mainHandle, WM_USER + 1, 1, 1);
+
ShowWindow(tapeViewerWindowInternal, SW_SHOWNORMAL);
UpdateWindow(tapeViewerWindowInternal);
@@ -102,3 +445,4 @@ TapeViewer::TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle)
+
diff --git a/SpectREM/SpectREM/Win32/TapeViewerWindow.hpp b/SpectREM/SpectREM/Win32/TapeViewerWindow.hpp
index f697591..74470e4 100644
--- a/SpectREM/SpectREM/Win32/TapeViewerWindow.hpp
+++ b/SpectREM/SpectREM/Win32/TapeViewerWindow.hpp
@@ -10,16 +10,29 @@
#include
#include
+#define IDC_BUTTON_PLAY 100
+#define IDC_BUTTON_PAUSE 101
+#define IDC_BUTTON_REWIND 102
+#define IDC_BUTTON_INSERT 103
+#define IDC_BUTTON_EJECT 104
+#define IDC_BUTTON_SAVE 105
+#define IDC_LISTVIEW_TAPEDATA 106
+#define IDS_NUMBEROFCOLUMNS 006
+
+
class TapeViewer
{
public:
- TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle);
+ TapeViewer(HINSTANCE mainWindowInst, HWND mainHandle, DWORD dwTlsIndex);// , std::vectormyPTAPE);
~TapeViewer();
- static LRESULT CALLBACK WndProcTV(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
-
-
-public:
- HWND tapeViewerWindowInternal;
+ static void UpdateActiveBlock(HWND hwndListV, LPARAM lP);
+ static LRESULT CALLBACK WndProcTV(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ static HWND TapeViewer::CreateListView(HWND hwnd, LPARAM lParam, RECT rect);
+ static BOOL TapeViewer::InitListViewColumns(HWND hWndListView, HINSTANCE hInst);
+ static const uint8_t windowFrameBuffer = 8;
+ static const uint8_t buttonYBuffer = 12;
+ static HWND tapeViewerWindowInternal;
+ static HINSTANCE g_hInst;
};
\ No newline at end of file
diff --git a/SpectREM/SpectREM/Win32/WinMain.cpp b/SpectREM/SpectREM/Win32/WinMain.cpp
index f8b0540..f0f0fbd 100644
--- a/SpectREM/SpectREM/Win32/WinMain.cpp
+++ b/SpectREM/SpectREM/Win32/WinMain.cpp
@@ -10,6 +10,18 @@
#define _CRT_RAND_S
#define WIN32API_GUI
+#define PM_TAPEDATA_FULL 77
+#define PM_TAPE_VIEWER_CLOSED 78
+#define PM_TAPE_COMMAND 79
+#define PM_TAPE_EJECTED 80
+#define PM_TAPE_ACTIVEBLOCK 81
+#define PM_TAPE_PLAY 82
+#define PM_TAPE_PAUSE 83
+#define PM_TAPE_REWIND 84
+#define PM_TAPE_INSERT 85
+#define PM_TAPE_EJECT 86
+#define PM_TAPE_SAVE 87
+#define PM_TAPE_UPDATE_PLAYPAUSEETC 88
#include
#include
@@ -26,20 +38,23 @@
#include "..\Emulation Core\ZX_Spectrum_Core\ZXSpectrum.hpp"
#include "..\Emulation Core\ZX_Spectrum_48k\ZXSpectrum48.hpp"
#include "..\Emulation Core\ZX_Spectrum_128k\ZXSpectrum128.hpp"
+#include "..\Emulation Core\ZX_Spectrum_128k_2\ZXSpectrum128_2.hpp"
+#include "..\Emulation Core\ZXSpectrum_128k_2A\ZXSpectrum128_2A.hpp"
#include "..\Emulation Core\Tape\Tape.hpp"
#include "..\OSX\AudioQueue.hpp"
#include "OpenGLView.hpp"
#include "../../resource.h"
-#include "PMDawn.cpp"
+#include "PMDawn.hpp"
#include
#include "TapeViewerWindow.hpp"
+#include
#pragma comment(lib, "comctl32.lib")
// WinMain.cpp
static void audio_callback(uint32_t nNumSamples, uint8_t* pBuffer);
-static void tapeStatusCallback(int blockIndex, int bytes);
+static void tapeStatusCallback(int blockIndex, int bytes, int action);
static void LoadSnapshot();
static void HardReset();
static void SoftReset();
@@ -48,7 +63,7 @@ static void ShowHelpAbout();
static void ShowHideUI(HWND hWnd);
static void ShowUI(HWND hWnd);
static void HideUI(HWND hWnd);
-static void ResetMachineForSnapshot(uint8_t mc);
+static void ResetMachineForSnapshot(uint8_t mc, bool ayEnabled);
static void ShowSettingsDialog();
static void RunSlideshow(int secs);
void IterateSCRImages(HWND mWindow, std::vector fileList, ZXSpectrum* m_pMachine, int secs);
@@ -62,24 +77,43 @@ static void OpenTapeViewer();
static void SetOutputVolume(float vol);
static void IncreaseApplicationVolume();
static void DecreaseApplicationVolume();
+unsigned int __stdcall mythread(void* data);
+static void SendTapeBlockDataToViewer();
+static void GetTapeViewerHwnd();
+static void SetupThreadLocalStorageForTapeData();
+RECT GetWindowResizeWithUI(HWND mWin, HWND sWin, HMENU menuWin, bool visible);
ZXSpectrum* m_pMachine;
Tape* m_pTape;
AudioCore* m_pAudioCore;
AudioQueue* m_pAudioQueue;
OpenGLView* m_pOpenGLView;
+static TapeViewer* tvWindow;
+std::string loadedFile;
enum MachineType
{
- ZX48, ZX128, PLUS2, PLUS3, UNKNOWN
+ ZX48, ZX128, PLUS2, PLUS2A, PLUS3, UNKNOWN
} mType;
+//enum
+//{
+// eZXSpectrum48 = 0,
+// eZXSpectrum128 = 1,
+// eZXSpectrum128_2 = 2,
+// eZXSpectrum128_2A = 3,
+// eZXSpectrum128_3 = 4
+//};
+
enum SnapType
{
SNA, Z80
};
+// Status / BlockType / Filename / AutostartLine / Address / Length
+static DWORD dwTlsIndex;
+static int cxClient, cyClient;
const UINT PM_UPDATESPECTREM = 7777;
const std::string EXT_Z80 = "z80";
const std::string EXT_SNA = "sna";
@@ -90,7 +124,6 @@ HACCEL hAcc;
bool isResetting = false;
HWND mainWindow;
HWND statusWindow;
-//HWND tapeViewerWindow;
HMENU mainMenu;
bool TurboMode = false;
bool menuDisplayed = true;
@@ -102,74 +135,79 @@ uint8_t fileListIndex = 0;
std::thread scrDisplayThread;
bool slideshowTimerRunning = false;
bool slideshowRandom = true;
-const float volumeStep = 0.1f;
-float applicationVolume = 0.75f;
-
-std::unordered_map KeyMappings
+const float volumeStep = 0.05f;
+const float startupVolume = 0.50f;
+float applicationVolume = 0.50f;
+GLint viewportX;
+GLint viewportY;
+HANDLE tapeViewerThread;
+HWND tvHwnd;
+
+std::unordered_map KeyMappings
{
- { VK_UP, ZXSpectrum::ZXSpectrumKey::Key_ArrowUp },
- { VK_DOWN, ZXSpectrum::ZXSpectrumKey::Key_ArrowDown },
- { VK_LEFT, ZXSpectrum::ZXSpectrumKey::Key_ArrowLeft },
- { VK_RIGHT, ZXSpectrum::ZXSpectrumKey::Key_ArrowRight },
- { VK_RETURN, ZXSpectrum::ZXSpectrumKey::Key_Enter },
- { VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_Shift },
- { VK_RSHIFT, ZXSpectrum::ZXSpectrumKey::Key_Shift },
- { VK_SPACE, ZXSpectrum::ZXSpectrumKey::Key_Space },
- { VK_CONTROL, ZXSpectrum::ZXSpectrumKey::Key_SymbolShift },
- { VK_RCONTROL, ZXSpectrum::ZXSpectrumKey::Key_SymbolShift },
+ { VK_UP, ZXSpectrum::eZXSpectrumKey::Key_ArrowUp },
+ { VK_DOWN, ZXSpectrum::eZXSpectrumKey::Key_ArrowDown },
+ { VK_LEFT, ZXSpectrum::eZXSpectrumKey::Key_ArrowLeft },
+ { VK_RIGHT, ZXSpectrum::eZXSpectrumKey::Key_ArrowRight },
+ { VK_RETURN, ZXSpectrum::eZXSpectrumKey::Key_Enter },
+ { VK_SHIFT, ZXSpectrum::eZXSpectrumKey::Key_Shift },
+ { VK_RSHIFT, ZXSpectrum::eZXSpectrumKey::Key_Shift },
+ { VK_SPACE, ZXSpectrum::eZXSpectrumKey::Key_Space },
+ { VK_CONTROL, ZXSpectrum::eZXSpectrumKey::Key_SymbolShift },
+ { VK_RCONTROL, ZXSpectrum::eZXSpectrumKey::Key_SymbolShift },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_InvVideo },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_TrueVideo },
- { VK_DELETE, ZXSpectrum::ZXSpectrumKey::Key_Backspace },
- { VK_BACK, ZXSpectrum::ZXSpectrumKey::Key_Backspace },
+ { VK_DELETE, ZXSpectrum::eZXSpectrumKey::Key_Backspace },
+ { VK_BACK, ZXSpectrum::eZXSpectrumKey::Key_Backspace },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_Quote },
- { VK_OEM_1, ZXSpectrum::ZXSpectrumKey::Key_SemiColon },
- { VK_OEM_COMMA, ZXSpectrum::ZXSpectrumKey::Key_Comma },
- { VK_OEM_MINUS, ZXSpectrum::ZXSpectrumKey::Key_Minus },
- { VK_OEM_PLUS, ZXSpectrum::ZXSpectrumKey::Key_Plus },
- { VK_OEM_PERIOD, ZXSpectrum::ZXSpectrumKey::Key_Period },
+ { VK_OEM_1, ZXSpectrum::eZXSpectrumKey::Key_SemiColon },
+ { VK_OEM_COMMA, ZXSpectrum::eZXSpectrumKey::Key_Comma },
+ { VK_OEM_MINUS, ZXSpectrum::eZXSpectrumKey::Key_Minus },
+ { VK_OEM_PLUS, ZXSpectrum::eZXSpectrumKey::Key_Plus },
+ { VK_OEM_PERIOD, ZXSpectrum::eZXSpectrumKey::Key_Period },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_Edit },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_Graph },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_Break },
//{ VK_SHIFT, ZXSpectrum::ZXSpectrumKey::Key_ExtendMode },
- { VK_CAPITAL, ZXSpectrum::ZXSpectrumKey::Key_CapsLock },
+ { VK_CAPITAL, ZXSpectrum::eZXSpectrumKey::Key_CapsLock },
// Numbers
- { 0x30, ZXSpectrum::ZXSpectrumKey::Key_0 },
- { 0x31, ZXSpectrum::ZXSpectrumKey::Key_1 },
- { 0x32, ZXSpectrum::ZXSpectrumKey::Key_2 },
- { 0x33, ZXSpectrum::ZXSpectrumKey::Key_3 },
- { 0x34, ZXSpectrum::ZXSpectrumKey::Key_4 },
- { 0x35, ZXSpectrum::ZXSpectrumKey::Key_5 },
- { 0x36, ZXSpectrum::ZXSpectrumKey::Key_6 },
- { 0x37, ZXSpectrum::ZXSpectrumKey::Key_7 },
- { 0x38, ZXSpectrum::ZXSpectrumKey::Key_8 },
- { 0x39, ZXSpectrum::ZXSpectrumKey::Key_9 },
+ { 0x30, ZXSpectrum::eZXSpectrumKey::Key_0 },
+ { 0x31, ZXSpectrum::eZXSpectrumKey::Key_1 },
+ { 0x32, ZXSpectrum::eZXSpectrumKey::Key_2 },
+ { 0x33, ZXSpectrum::eZXSpectrumKey::Key_3 },
+ { 0x34, ZXSpectrum::eZXSpectrumKey::Key_4 },
+ { 0x35, ZXSpectrum::eZXSpectrumKey::Key_5 },
+ { 0x36, ZXSpectrum::eZXSpectrumKey::Key_6 },
+ { 0x37, ZXSpectrum::eZXSpectrumKey::Key_7 },
+ { 0x38, ZXSpectrum::eZXSpectrumKey::Key_8 },
+ { 0x39, ZXSpectrum::eZXSpectrumKey::Key_9 },
// Letters
- { 0x41, ZXSpectrum::ZXSpectrumKey::Key_A },
- { 0x42, ZXSpectrum::ZXSpectrumKey::Key_B },
- { 0x43, ZXSpectrum::ZXSpectrumKey::Key_C },
- { 0x44, ZXSpectrum::ZXSpectrumKey::Key_D },
- { 0x45, ZXSpectrum::ZXSpectrumKey::Key_E },
- { 0x46, ZXSpectrum::ZXSpectrumKey::Key_F },
- { 0x47, ZXSpectrum::ZXSpectrumKey::Key_G },
- { 0x48, ZXSpectrum::ZXSpectrumKey::Key_H },
- { 0x49, ZXSpectrum::ZXSpectrumKey::Key_I },
- { 0x4a, ZXSpectrum::ZXSpectrumKey::Key_J },
- { 0x4b, ZXSpectrum::ZXSpectrumKey::Key_K },
- { 0x4c, ZXSpectrum::ZXSpectrumKey::Key_L },
- { 0x4d, ZXSpectrum::ZXSpectrumKey::Key_M },
- { 0x4e, ZXSpectrum::ZXSpectrumKey::Key_N },
- { 0x4f, ZXSpectrum::ZXSpectrumKey::Key_O },
- { 0x50, ZXSpectrum::ZXSpectrumKey::Key_P },
- { 0x51, ZXSpectrum::ZXSpectrumKey::Key_Q },
- { 0x52, ZXSpectrum::ZXSpectrumKey::Key_R },
- { 0x53, ZXSpectrum::ZXSpectrumKey::Key_S },
- { 0x54, ZXSpectrum::ZXSpectrumKey::Key_T },
- { 0x55, ZXSpectrum::ZXSpectrumKey::Key_U },
- { 0x56, ZXSpectrum::ZXSpectrumKey::Key_V },
- { 0x57, ZXSpectrum::ZXSpectrumKey::Key_W },
- { 0x58, ZXSpectrum::ZXSpectrumKey::Key_X },
- { 0x59, ZXSpectrum::ZXSpectrumKey::Key_Y },
- { 0x5a, ZXSpectrum::ZXSpectrumKey::Key_Z },
+ { 0x41, ZXSpectrum::eZXSpectrumKey::Key_A },
+ { 0x42, ZXSpectrum::eZXSpectrumKey::Key_B },
+ { 0x43, ZXSpectrum::eZXSpectrumKey::Key_C },
+ { 0x44, ZXSpectrum::eZXSpectrumKey::Key_D },
+ { 0x45, ZXSpectrum::eZXSpectrumKey::Key_E },
+ { 0x46, ZXSpectrum::eZXSpectrumKey::Key_F },
+ { 0x47, ZXSpectrum::eZXSpectrumKey::Key_G },
+ { 0x48, ZXSpectrum::eZXSpectrumKey::Key_H },
+ { 0x49, ZXSpectrum::eZXSpectrumKey::Key_I },
+ { 0x4a, ZXSpectrum::eZXSpectrumKey::Key_J },
+ { 0x4b, ZXSpectrum::eZXSpectrumKey::Key_K },
+ { 0x4c, ZXSpectrum::eZXSpectrumKey::Key_L },
+ { 0x4d, ZXSpectrum::eZXSpectrumKey::Key_M },
+ { 0x4e, ZXSpectrum::eZXSpectrumKey::Key_N },
+ { 0x4f, ZXSpectrum::eZXSpectrumKey::Key_O },
+ { 0x50, ZXSpectrum::eZXSpectrumKey::Key_P },
+ { 0x51, ZXSpectrum::eZXSpectrumKey::Key_Q },
+ { 0x52, ZXSpectrum::eZXSpectrumKey::Key_R },
+ { 0x53, ZXSpectrum::eZXSpectrumKey::Key_S },
+ { 0x54, ZXSpectrum::eZXSpectrumKey::Key_T },
+ { 0x55, ZXSpectrum::eZXSpectrumKey::Key_U },
+ { 0x56, ZXSpectrum::eZXSpectrumKey::Key_V },
+ { 0x57, ZXSpectrum::eZXSpectrumKey::Key_W },
+ { 0x58, ZXSpectrum::eZXSpectrumKey::Key_X },
+ { 0x59, ZXSpectrum::eZXSpectrumKey::Key_Y },
+ { 0x5a, ZXSpectrum::eZXSpectrumKey::Key_Z },
};
@@ -193,7 +231,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
{
switch (msg)
{
-
#ifdef WIN32API_GUI
case WM_COMMAND:
switch (LOWORD(wparam))
@@ -214,13 +251,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
SoftReset();
break;
case ID_SWITCH_TO48K:
- ResetMachineForSnapshot(ZX48);
+ ResetMachineForSnapshot(ZX48, m_pMachine->ayEnabledSnapshot);
break;
case ID_SWITCH_TO128K:
- ResetMachineForSnapshot(ZX128);
+ ResetMachineForSnapshot(ZX128, true);
break;
- case ID_SWITCH_FLIP:
- SwitchMachines();
+ case ID_SWITCH_TOPLUS2:
+ ResetMachineForSnapshot(PLUS2, true);
+ break;
+ case ID_SWITCH_TOPLUS2A:
+ ResetMachineForSnapshot(PLUS2A, true);
+ break;
+ case ID_SWITCH_TOPLUS3:
+ ResetMachineForSnapshot(PLUS3, true);
break;
case ID_HELP_ABOUT:
ShowHelpAbout();
@@ -286,6 +329,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
break;
#endif
+
+
case WM_CLOSE:
PostQuitMessage(0);
return 0;
@@ -349,7 +394,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
break;
case WM_SIZE:
- glViewport(0, 0, LOWORD(lparam), HIWORD(lparam));
+ cxClient = LOWORD(lparam);
+ cyClient = HIWORD(lparam);
+ //glViewport(viewportX, viewportY, 256 * zoomLevel, 192 * zoomLevel);
+ return 0;
break;
case WM_USER:
@@ -357,12 +405,86 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
{
case PM_UPDATESPECTREM:
Sleep(50);
- m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer);
+ m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
PMDawn::Log(PMDawn::LOG_DEBUG, "Changed slideshow image");
break;
}
break;
+ case WM_USER + 1:
+ switch (LOWORD(wparam))
+ {
+ case 1:
+ GetTapeViewerHwnd();
+ if (m_pTape->numberOfTapeBlocks() > 0)
+ {
+ SendTapeBlockDataToViewer();
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_ACTIVEBLOCK, (LPARAM)m_pTape->currentBlockIndex);
+ if (m_pTape->playing)
+ {
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_UPDATE_PLAYPAUSEETC, 1); // Indicate tape is playing
+ }
+ else
+ {
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_UPDATE_PLAYPAUSEETC, 0); // Indicate tape is paused
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_USER + 2:
+ switch (LOWORD(wparam))
+ {
+ case PM_TAPE_VIEWER_CLOSED:
+ if (tapeViewerThread)
+ {
+ CloseHandle(tapeViewerThread);
+ tapeViewerThread = nullptr;
+ }
+ break;
+ case PM_TAPE_COMMAND:
+ // The tape window is sending a command to do something with the tape
+ switch (lparam)
+ {
+ case PM_TAPE_PLAY:
+ m_pTape->play();
+ break;
+
+ case PM_TAPE_PAUSE:
+ m_pTape->stop();// stopPlaying();
+ break;
+
+ case PM_TAPE_REWIND:
+ RewindTape();
+ break;
+
+ case PM_TAPE_INSERT:
+ InsertTape();
+ break;
+
+ case PM_TAPE_EJECT:
+ EjectTape();
+ break;
+
+ }
+ break;
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(mainWindow, &ps);
+ //if (m_pMachine)
+ //{
+ // m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
+ //}
+ EndPaint(mainWindow, &ps);
+ return 0;
+ break;
+ }
+
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
@@ -394,15 +516,19 @@ static void InsertTape()
if (GetOpenFileNameA(&ofn))
{
EjectTape(); // Eject the current tape if inserted
- Tape::TapResponse tR = m_pTape->loadWithPath(szFile);
+ Tape::FileResponse tR = m_pTape->insertTapeWithPath(szFile);
if (tR.success)
{
PMDawn::Log(PMDawn::LOG_INFO, "Loaded tape - " + std::string(szFile));
+ PathStripPathA(szFile);
+ loadedFile = "TAPE: " + std::string(szFile);
+ SendTapeBlockDataToViewer();
}
else
{
MessageBox(mainWindow, TEXT("Unable to load tape >> "), TEXT("Tape Loader"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
PMDawn::Log(PMDawn::LOG_INFO, "Failed to load tape - " + std::string(szFile) + " > " + tR.responseMsg);
+ loadedFile = "-empty-";
return;
}
}
@@ -416,11 +542,13 @@ static void PlayPauseTape()
{
if (m_pTape->playing)
{
- m_pTape->stopPlaying();
+ m_pTape->stop();
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_UPDATE_PLAYPAUSEETC, 0);
}
else
{
- m_pTape->startPlaying();
+ m_pTape->play();
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_UPDATE_PLAYPAUSEETC, 1);
}
}
}
@@ -431,8 +559,9 @@ static void EjectTape()
{
if (m_pTape->loaded)
{
- m_pTape->stopPlaying();
+ m_pTape->stop();
m_pTape->eject();
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_EJECTED, (LPARAM)0);
}
}
@@ -442,8 +571,10 @@ static void RewindTape()
{
if (m_pTape->loaded)
{
- m_pTape->stopPlaying();
+ m_pTape->stop();
m_pTape->rewindTape();
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_ACTIVEBLOCK, (LPARAM)0); // Let the tape viewer know we are on block number 0
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_UPDATE_PLAYPAUSEETC, 0); // Let the tape viewer know that we are paused
}
}
//-----------------------------------------------------------------------------------------
@@ -453,35 +584,21 @@ static void OpenSCR()
HardReset();
Sleep(1000);
- OPENFILENAMEA ofn;
- char szFile[_MAX_PATH];
- // Setup the ofn structure
- ZeroMemory(&ofn, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = NULL;
- ofn.lpstrFile = szFile;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = sizeof(szFile);
- ofn.lpstrFilter = "All\0*.*\0Screen File\0*.SCR\0\0";
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ std::string scrPath = PMDawn::GetFilenameUsingDialog("");
- if (GetOpenFileNameA(&ofn))
+ if (scrPath != "")
{
- ZXSpectrum::Response sR = m_pMachine->scrLoadWithPath(szFile);
+ Tape::FileResponse sR = m_pMachine->scrLoadWithPath(scrPath);
if (sR.success)
{
Sleep(1);
- m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer);
- PMDawn::Log(PMDawn::LOG_INFO, "Loaded .scr file - " + std::string(szFile));
+ m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
+ PMDawn::Log(PMDawn::LOG_INFO, "Loaded .scr file - " + std::string(scrPath));
}
else
{
MessageBox(mainWindow, TEXT("Invalid SCR file"), TEXT("Gimme SCR's !!!"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- PMDawn::Log(PMDawn::LOG_INFO, "Failed to load .scr file - " + std::string(szFile) + " > " + sR.responseMsg);
+ PMDawn::Log(PMDawn::LOG_INFO, "Failed to load .scr file - " + std::string(scrPath) + " > " + sR.responseMsg);
return;
}
}
@@ -495,7 +612,8 @@ static void RunSlideshow(int secs)
Sleep(1000);
PMDawn::Log(PMDawn::LOG_INFO, "Running slideshow (" + std::to_string(secs) + " secs) from " + PMDawn::GetApplicationBasePath() + slideshowDirectory);
fileList.clear();
- fileList = PMDawn::GetFilesInDirectory(PMDawn::GetApplicationBasePath() + slideshowDirectory, "*.scr");
+ std::string fpath = PMDawn::GetFolderUsingDialog("");
+ fileList = PMDawn::GetFilesInDirectory(fpath + "\\", "*.scr");
PMDawn::Log(PMDawn::LOG_DEBUG, "Found " + std::to_string(fileList.size()) + " matching files");
// iterate (randomly maybe) through the list of files as long as there is at least one file :)
if (fileList.size() < 1)
@@ -532,15 +650,15 @@ static void IterateSCRImagesOnTimerCallback()
if (slideshowRandom)
{
int randomIndex = (int)rand() % fileList.size();
- ZXSpectrum::Response sR = m_pMachine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[randomIndex]);
+ Tape::FileResponse sR = m_pMachine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[randomIndex]);
Sleep(1);
- m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer);
+ m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
}
else
{
- ZXSpectrum::Response sR = m_pMachine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[fileListIndex]);
+ Tape::FileResponse sR = m_pMachine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[fileListIndex]);
Sleep(1);
- m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer);
+ m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
fileListIndex++;
if (fileListIndex >= fileList.size())
{
@@ -562,7 +680,7 @@ static void IterateSCRImages(HWND mWindow, std::vector fileList, ZX
std::chrono::milliseconds msecs(delaysecs * 1000);
for (std::size_t i = 0; i < 10; i++)//< fileList.size(); i++)
{
- ZXSpectrum::Response sR = machine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[i]);
+ Tape::FileResponse sR = machine->scrLoadWithPath(PMDawn::GetApplicationBasePath() + slideshowDirectory + fileList[i]);
//SendMessageCallback(mWindow, WM_USER, PM_UPDATESPECTREM, PM_UPDATESPECTREM, nullptr, 0);
PostMessage(mWindow, WM_USER, PM_UPDATESPECTREM, PM_UPDATESPECTREM);
std::this_thread::sleep_for(msecs);
@@ -602,10 +720,13 @@ static void ShowHideUI(HWND hWnd = mainWindow)
static void ShowUI(HWND hWnd = mainWindow)
{
PMDawn::Log(PMDawn::LOG_DEBUG, "ShowUI()");
- SetMenu(hWnd, mainMenu);
menuDisplayed = true;
- ShowWindow(statusWindow, SW_SHOW);
statusDisplayed = true;
+ RECT newSize = GetWindowResizeWithUI(mainWindow, statusWindow, mainMenu, true);
+ SetMenu(hWnd, mainMenu);
+ SetWindowPos(mainWindow, HWND_NOTOPMOST, newSize.left, newSize.top, newSize.right, newSize.bottom, 0);
+ m_pOpenGLView->Resize(0, 0, 256 * zoomLevel, 192 * zoomLevel);
+ ShowWindow(statusWindow, SW_SHOW);
}
//-----------------------------------------------------------------------------------------
@@ -613,10 +734,75 @@ static void ShowUI(HWND hWnd = mainWindow)
static void HideUI(HWND hWnd = mainWindow)
{
PMDawn::Log(PMDawn::LOG_DEBUG, "HideUI()");
- SetMenu(hWnd, NULL);
menuDisplayed = false;
- ShowWindow(statusWindow, SW_HIDE);
statusDisplayed = false;
+ RECT newSize = GetWindowResizeWithUI(mainWindow, statusWindow, mainMenu, false);
+ SetMenu(hWnd, NULL);
+ SetWindowPos(mainWindow, HWND_NOTOPMOST, newSize.left, newSize.top, newSize.right, newSize.bottom, 0);
+ m_pOpenGLView->Resize(0, 0, 256 * zoomLevel, 192 * zoomLevel);
+ ShowWindow(statusWindow, SW_HIDE);
+}
+
+//-----------------------------------------------------------------------------------------
+
+RECT GetWindowResizeWithUI(HWND mWin, HWND sWin, HMENU menu, bool visible)
+{
+ // Get the new window size needed for the status bar to be below the GLView...
+ if (visible)
+ {
+ Log(PMDawn::LOG_INFO, "Resizing with UI");
+ Log(PMDawn::LOG_INFO, "Menu height == " + GetSystemMetrics(SM_CYMENU));
+ }
+ else
+ {
+ Log(PMDawn::LOG_INFO, "Resizing without UI");
+ Log(PMDawn::LOG_INFO, "Menu height == " + GetSystemMetrics(SM_CYMENU));
+ }
+ RECT m, s;
+ GetWindowRect(mWin, &m);
+ GetWindowRect(sWin, &s);
+
+ Log(PMDawn::LOG_INFO, "Main window RECT = t" +
+ std::to_string(m.top) + " l" +
+ std::to_string(m.left) + " b" +
+ std::to_string(m.bottom) + " r" +
+ std::to_string(m.right));
+ Log(PMDawn::LOG_INFO, "Status bar RECT = t" +
+ std::to_string(s.top) + " l" +
+ std::to_string(s.left) + " b" +
+ std::to_string(s.bottom) + " r" +
+ std::to_string(s.right));
+
+ if (visible)
+ {
+ RECT nWin = {
+ m.left,
+ m.top,
+ (m.right - m.left),
+ (m.bottom - m.top) + GetSystemMetrics(SM_CYMENU)// + (s.bottom - s.top)// + GetSystemMetrics(SM_CYMENU)
+ };
+ Log(PMDawn::LOG_INFO, "Output RECT = t" +
+ std::to_string(nWin.top) + " l" +
+ std::to_string(nWin.left) + " b" +
+ std::to_string(nWin.bottom) + " r" +
+ std::to_string(nWin.right));
+ return nWin;
+ }
+ else
+ {
+ RECT nWin = {
+ m.left,
+ m.top,
+ (m.right - m.left),
+ (m.bottom - m.top) - GetSystemMetrics(SM_CYMENU)// - (s.bottom - s.top)// - GetSystemMetrics(SM_CYMENU)
+ };
+ Log(PMDawn::LOG_INFO, "Output RECT = t" +
+ std::to_string(nWin.top) + " l" +
+ std::to_string(nWin.left) + " b" +
+ std::to_string(nWin.bottom) + " r" +
+ std::to_string(nWin.right));
+ return nWin;
+ }
}
//-----------------------------------------------------------------------------------------
@@ -637,14 +823,14 @@ static void SwitchMachines()
if (isResetting != true)
{
PMDawn::Log(PMDawn::LOG_DEBUG, "Flip machine requested");
- ResetMachineForSnapshot(ZX48);
+ ResetMachineForSnapshot(ZX48, m_pMachine->ayEnabledSnapshot);
}
}
else
{
if (isResetting != true)
{
- ResetMachineForSnapshot(ZX128);
+ ResetMachineForSnapshot(ZX128, true);
}
}
}
@@ -656,7 +842,7 @@ static void SoftReset()
// Soft reset
if (isResetting != true)
{
- ResetMachineForSnapshot(m_pMachine->machineInfo.machineType);
+ ResetMachineForSnapshot(m_pMachine->machineInfo.machineType, m_pMachine->ayEnabledSnapshot);
PMDawn::Log(PMDawn::LOG_INFO, "Soft reset completed");
}
}
@@ -668,7 +854,7 @@ static void HardReset()
// Hard reset
if (isResetting != true)
{
- ResetMachineForSnapshot(m_pMachine->machineInfo.machineType);
+ ResetMachineForSnapshot(m_pMachine->machineInfo.machineType, m_pMachine->ayEnabledSnapshot);
PMDawn::Log(PMDawn::LOG_INFO, "Hard reset completed");
}
}
@@ -677,82 +863,81 @@ static void HardReset()
static void LoadSnapshot()
{
- OPENFILENAMEA ofn;
- char szFile[_MAX_PATH];
+ std::string filePath = PMDawn::GetFilenameUsingDialog("");
- // Setup the ofn structure
- ZeroMemory(&ofn, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = NULL;
- ofn.lpstrFile = szFile;
- ofn.lpstrFile[0] = '\0';
- ofn.nMaxFile = sizeof(szFile);
- ofn.lpstrFilter = "All\0*.*\0Snapshot\0*.SNA\0Z80\0*.Z80\0Tapes\0*.TAP\0\0";
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
-
- if (GetOpenFileNameA(&ofn))
+ if (filePath != "")
{
- int32_t mType = m_pMachine->snapshotMachineInSnapshotWithPath(szFile);
- std::string s(szFile, sizeof(szFile));
- std::string extension = s.substr(s.find_last_of(".") + 1, s.find_last_of(".") + 4);
+ int32_t mType = m_pMachine->snapshotMachineInSnapshotWithPath(filePath.c_str());
+ size_t sizeOfFile = sizeof(filePath) - 1;
+ std::string s(filePath.c_str(), sizeOfFile);
+ std::string extension = filePath.substr(filePath.find_last_of(".") + 1, filePath.find_last_of(".") + 4);
// Check the machine type returned from the user supplied snapshot if not a tape file
if (_stricmp(extension.c_str(), EXT_TAP.c_str()) == 0)
{
EjectTape(); // Eject the current tape if inserted
- Tape::TapResponse tR = m_pTape->loadWithPath(szFile);
+ Tape::FileResponse tR = m_pTape->insertTapeWithPath(filePath);
if (tR.success)
{
- PMDawn::Log(PMDawn::LOG_INFO, "Loaded tape - " + std::string(szFile));
+ PMDawn::Log(PMDawn::LOG_INFO, "Loaded tape - " + std::string(filePath));
+ PathStripPathA(const_cast(filePath.c_str()));
+ loadedFile = "TAPE: " + filePath;
+ SendTapeBlockDataToViewer();
}
else
{
MessageBox(mainWindow, TEXT("Unable to load tape >> "), TEXT("Tape Loader"), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
- PMDawn::Log(PMDawn::LOG_INFO, "Failed to load tape - " + std::string(szFile) + " > " + tR.responseMsg);
+ loadedFile = "-empty-";
+ PMDawn::Log(PMDawn::LOG_INFO, "Failed to load tape - " + std::string(filePath) + " > " + tR.responseMsg);
}
}
else
{
+ EjectTape();
if (mType <= ZX48)
{
// 48 based
- ResetMachineForSnapshot(ZX48);
+ ResetMachineForSnapshot(ZX48, m_pMachine->ayEnabledSnapshot);
Sleep(500);
}
else
{
// 128 based
- ResetMachineForSnapshot(ZX128);
+ ResetMachineForSnapshot(ZX128, true);
Sleep(500);
}
if (_stricmp(extension.c_str(), EXT_Z80.c_str()) == 0)
{
PMDawn::Log(PMDawn::LOG_INFO, "Loading Z80 Snapshot - " + s);
- ZXSpectrum::Response sR = m_pMachine->snapshotZ80LoadWithPath(szFile);
+ Tape::FileResponse sR = m_pMachine->snapshotZ80LoadWithPath(filePath);
if (sR.success)
{
PMDawn::Log(PMDawn::LOG_INFO, "Snapshot loaded successfully");
+ PMDawn::Log(PMDawn::LOG_INFO, "Loaded snapshot - " + std::string(filePath));
+ PathStripPathA(const_cast(filePath.c_str()));
+ loadedFile = ".Z80: " + filePath;
}
else
{
PMDawn::Log(PMDawn::LOG_INFO, "Snapshot loading failed : " + sR.responseMsg);
+ loadedFile = "-empty-";
}
}
else if (_stricmp(extension.c_str(), EXT_SNA.c_str()) == 0)
{
PMDawn::Log(PMDawn::LOG_DEBUG, "Loading SNA Snapshot - " + s);
- ZXSpectrum::Response sR = m_pMachine->snapshotSNALoadWithPath(szFile);
+ Tape::FileResponse sR = m_pMachine->snapshotSNALoadWithPath(filePath);
if (sR.success)
{
PMDawn::Log(PMDawn::LOG_INFO, "Snapshot loaded successfully");
+ PMDawn::Log(PMDawn::LOG_INFO, "Loaded snapshot - " + std::string(filePath));
+ PathStripPathA(const_cast(filePath.c_str()));
+ loadedFile = ".SNA: " + filePath;
}
else
{
PMDawn::Log(PMDawn::LOG_INFO, "Snapshot loading failed : " + sR.responseMsg);
+ loadedFile = "-empty";
}
}
}
@@ -761,9 +946,11 @@ static void LoadSnapshot()
//-----------------------------------------------------------------------------------------
-static void tapeStatusCallback(int blockIndex, int bytes)
+static void tapeStatusCallback(int blockIndex, int bytes, int action)
{
- if (blockIndex < 1 && m_pTape->playing ==false) return;
+ if (blockIndex < 1 && m_pTape->playing == false) return;
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPE_ACTIVEBLOCK, (LPARAM)blockIndex);
+ //SendTapeBlockDataToViewer();
//TapeBlock* currentTBI = m_pTape->blocks[blockIndex];
//PMDawn::Log(PMDawn::LOG_DEBUG, "Tape block : " + std::to_string(blockIndex));
//PMDawn::Log(PMDawn::LOG_DEBUG, " Block name : " + currentTBI->getBlockName());
@@ -803,6 +990,7 @@ static void audio_callback(uint32_t nNumSamples, uint8_t* pBuffer)
int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
{
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Check for logging type if needed, CTRL = LOG_INFO, ALT = LOG_DEBUG
PMDawn::logLevel = PMDawn::LOG_NONE;
if (GetAsyncKeyState(VK_MENU))
@@ -815,6 +1003,7 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
// CTRL is pressed
PMDawn::logLevel = PMDawn::LOG_INFO;
}
+ PMDawn::logLevel = PMDawn::LOG_INFO;
if (PMDawn::logLevel != PMDawn::LOG_NONE)
{
if (PMDawn::LogOpenOrCreate(PMDawn::GetApplicationBasePath() + "\\" + PMDawn::logFilename))
@@ -837,9 +1026,14 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
unsigned int cThreads = std::thread::hardware_concurrency();
PMDawn::Log(PMDawn::LOG_INFO, "Maximum available threads = " + std::to_string(cThreads));
+ //SetupThreadLocalStorageForTapeData();
+
+ loadedFile = "-empty-";
slideshowTimerRunning = false;
slideshowRandom = true;
//srand((unsigned int)time(NULL));
+ viewportX = 0;
+ viewportY = 0;
bool exit_emulator = false;
LARGE_INTEGER perf_freq, time, last_time;
@@ -859,7 +1053,7 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
wcex.cbWndExtra = 0;
wcex.hInstance = inst;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.hbrBackground = NULL;
+ wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszClassName = TEXT("SpectREM");
wcex.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON2));
wcex.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 16, 16, 0);
@@ -877,32 +1071,62 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
Log(PMDawn::LOG_INFO, "Current zoom level is " + std::to_string(zoomLevel));
- mainWindow = CreateWindowEx(WS_EX_APPWINDOW, TEXT("SpectREM"), TEXT("SpectREM"), WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX, 0, 0, wr.right - wr.left, wr.bottom - wr.top, 0, 0, inst, 0);
+ mainWindow = CreateWindowEx(WS_EX_APPWINDOW, TEXT("SpectREM"), TEXT("SpectREM"),
+ WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, 0, 0, inst, 0);
#ifdef WIN32API_GUI
- statusWindow = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, TEXT("Welcome to SpyWindows"), mainWindow, 9000);
+ //statusWindow = CreateStatusWindow(WS_CHILD | WS_VISIBLE, TEXT("Welcome to SpectREM for Windows"), mainWindow, 9000);
+ statusWindow = CreateWindow(STATUSCLASSNAME, TEXT("Welcome to SpectREM for Windows"), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, mainWindow, NULL, inst, NULL);
#endif
ShowWindow(mainWindow, ncmd);
UpdateWindow(mainWindow);
mainMenu = GetMenu(mainWindow);
menuDisplayed = true;
statusDisplayed = true;
+ //ShowHideUI(mainWindow);
+#ifdef WIN32API_GUI
+ RECT newSize = GetWindowResizeWithUI(mainWindow, statusWindow, mainMenu, true);
+ SetWindowPos(mainWindow, HWND_NOTOPMOST, newSize.left, newSize.top, newSize.right, newSize.bottom, 0);
+#endif
QueryPerformanceFrequency(&perf_freq);
QueryPerformanceCounter(&last_time);
- m_pOpenGLView = new OpenGLView();
+ m_pOpenGLView = new OpenGLView(bpath);
+ // * zoomLevel
m_pOpenGLView->Init(mainWindow, 256 * zoomLevel, 192 * zoomLevel, ID_SHADER_CLUT_VERT, ID_SHADER_CLUT_FRAG, ID_SHADER_DISPLAY_VERT, ID_SHADER_DISPLAY_FRAG, RT_RCDATA);
m_pAudioQueue = new AudioQueue();
m_pAudioCore = new AudioCore();
- m_pAudioCore->Init(44100, 50, audio_callback);
+ bool rV = m_pAudioCore->Init(44100, 50, audio_callback);
+ if (!rV)
+ {
+ // AudioCore::Init failed
+ CoUninitialize();
+ return 0;
+ }
+ // Get the current application volume (if changed previously)
+ if (applicationVolume < 0.0f || applicationVolume > 1.0f)
+ {
+ m_pAudioCore->SetOutputVolume(startupVolume);
+ }
+ else
+ {
+ m_pAudioCore->SetOutputVolume(applicationVolume);
+ }
m_pTape = new Tape(tapeStatusCallback);
- m_pMachine = new ZXSpectrum128(m_pTape);
+ // Default to a Speccy 48k :)
+ m_pMachine = new ZXSpectrum48(m_pTape);// ZXSpectrum128(m_pTape);
m_pMachine->emuUseAYSound = true;
m_pMachine->emuBasePath = PMDawn::GetApplicationBasePath();
PMDawn::Log(PMDawn::LOG_INFO, "ROMs path = " + m_pMachine->emuBasePath + romPath);
m_pMachine->initialise(romPath);
m_pAudioCore->Start();
m_pMachine->resume();
+ m_pMachine->resetMachine(true);
+
+ m_pOpenGLView->ShaderSetScreenCurve((GLfloat)0.10);
+ m_pOpenGLView->ShaderSetVignette(true);
+ m_pOpenGLView->ShaderSetReflection(true);
// Do the main message loop
while (!exit_emulator)
@@ -940,7 +1164,8 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
{
last_time = time;
- m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer);
+ m_pOpenGLView->UpdateTextureData(m_pMachine->displayBuffer, viewportX, viewportY);
+
// Set the time
char specType[20];
@@ -984,12 +1209,37 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
sprintf_s(lLevel, sizeof(lLevel), " ");
}
- char buff[100];
- sprintf_s(buff, sizeof(buff), "SpectREM - %4.1f fps - [%s] - %s %s", 1.0f / delta_time, specType, zoom, lLevel);
+ char lfBuff[300];
+ if (m_pTape->playing)
+ {
+ sprintf_s(lfBuff, sizeof(lfBuff), "%s > Playing", loadedFile.c_str());
+ }
+ else
+ {
+ if (m_pTape->loaded)
+ {
+ sprintf_s(lfBuff, sizeof(lfBuff), "%s > Paused", loadedFile.c_str());
+ }
+ else
+ {
+ sprintf_s(lfBuff, sizeof(lfBuff), "%s", loadedFile.c_str());
+ }
+ }
+
+
+ char buff[512];
+ sprintf_s(buff, sizeof(buff), "SpectREM - %4.1f fps - [%s] - %s - [%s] %s", 1.0f / delta_time, specType, zoom, lfBuff, lLevel);
SetWindowTextA(mainWindow, buff);
}
}
}
+ // if tape viewer is running on it's thread then wait before closing
+ if (tapeViewerThread != nullptr)
+ {
+ WaitForSingleObject(tapeViewerThread, INFINITE);
+ CloseHandle(tapeViewerThread);
+ }
+ CoUninitialize();
return 0;
}
@@ -998,7 +1248,7 @@ int __stdcall WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int ncmd)
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
-static void ResetMachineForSnapshot(uint8_t mc)
+static void ResetMachineForSnapshot(uint8_t mc, bool ayEnabled)
{
isResetting = true;
@@ -1022,13 +1272,29 @@ static void ResetMachineForSnapshot(uint8_t mc)
case ZX48:
PMDawn::Log(PMDawn::LOG_INFO, "SpectREM changed to 48K Mode");
m_pMachine = new ZXSpectrum48(m_pTape);
- m_pMachine->emuUseAYSound = false;
+ m_pMachine->emuUseAYSound = ayEnabled;
break;
case ZX128:
PMDawn::Log(PMDawn::LOG_INFO, "SpectREM changed to 128K Mode");
m_pMachine = new ZXSpectrum128(m_pTape);
m_pMachine->emuUseAYSound = true;
break;
+ case PLUS2:
+ PMDawn::Log(PMDawn::LOG_INFO, "SpectREM changed to 128K +2 Mode");
+ m_pMachine = new ZXSpectrum128_2(m_pTape);
+ m_pMachine->emuUseAYSound = true;
+ break;
+ case PLUS2A:
+ PMDawn::Log(PMDawn::LOG_INFO, "SpectREM changed to 128K +2A Mode");
+ m_pMachine = new ZXSpectrum128_2A(m_pTape);
+ m_pMachine->emuUseAYSound = true;
+ break;
+ case PLUS3:
+ PMDawn::Log(PMDawn::LOG_INFO, "SpectREM changed to 128K +3 Mode");
+ m_pMachine = new ZXSpectrum128_2A(m_pTape);
+ //m_pMachine = new ZXSpectrum128_3(m_pTape);
+ m_pMachine->emuUseAYSound = true;
+ break;
default:
// default to 128K
PMDawn::Log(PMDawn::LOG_INFO, "UNKNOWN MACHINE TYPE, Defaulting to 128K Mode");
@@ -1040,6 +1306,15 @@ static void ResetMachineForSnapshot(uint8_t mc)
m_pMachine->emuBasePath = PMDawn::GetApplicationBasePath();
m_pMachine->initialise(romPath);
m_pAudioCore->Start();
+ // Get the current application volume (if changed previously)
+ if (applicationVolume < 0.0f || applicationVolume > 1.0f)
+ {
+ m_pAudioCore->SetOutputVolume(startupVolume);
+ }
+ else
+ {
+ m_pAudioCore->SetOutputVolume(applicationVolume);
+ }
m_pMachine->resume();
isResetting = false;
@@ -1091,18 +1366,107 @@ static void DecreaseApplicationVolume()
static void OpenTapeViewer()
{
- TapeViewer* tvWindow = new TapeViewer(GetModuleHandle(NULL), mainWindow);
- //int retval = TapeViewer::OpenTapeViewerWindow(GetModuleHandle(NULL), mainWindow);
+ if (tapeViewerThread) return;
+
+ tapeViewerThread = (HANDLE)_beginthreadex(0, 0, &mythread, 0, 0, 0);
}
+unsigned int __stdcall mythread(void* data)
+{
+
+ tvWindow = new TapeViewer(GetModuleHandle(NULL), mainWindow, dwTlsIndex);
+ tvWindow = nullptr;
+ PostMessage(mainWindow, WM_USER + 2, PM_TAPE_VIEWER_CLOSED, (LPARAM)0);
+ return 0;
+}
//-----------------------------------------------------------------------------------------
+static void SendTapeBlockDataToViewer()
+{
+ size_t numBlocks = m_pTape->numberOfTapeBlocks();
+
+ PMDawn::pData.clear();
+ for (int i = 0; i < numBlocks; i++)
+ {
+ PMDawn::gTAPEBLOCK gT;
+
+ gT.status = " ";
+ switch (m_pTape->blocks[i]->getDataType())
+ {
+ case 0: // ePROGRAM_HEADER
+ gT.blocktype = "PROGRAM:";
+ break;
+
+ case 1: // eNUMERIC_DATA_HEADER
+ gT.blocktype = "DATA():";
+ break;
+ case 2: // eALPHANUMERIC_DATA_HEADER
+ gT.blocktype = "STRING():";
+ break;
+
+ case 3: // eBYTE_HEADER
+ gT.blocktype = "CODE:";
+ break;
+
+ case 4: // eDATA_BLOCK
+ gT.blocktype = "DATA:";
+ break;
+
+ case 5: // eFRAGMENTED_DATA_BLOCK
+ gT.blocktype = "FRAGMENTED:";
+ break;
+
+ case 99: // eUNKNOWN_BLOCK
+ gT.blocktype = "UNKNOWN:";
+ break;
+
+ default: // Uh oh...
+ gT.blocktype = " DATA:";
+ break;
+ }
+
+ if (m_pTape->blocks[i]->getDataType() < 4)
+ {
+ gT.filename = m_pTape->blocks[i]->getFilename();
+ gT.autostartline = m_pTape->blocks[i]->getAutoStartLine();
+ }
+ else
+ {
+ gT.filename = "";
+ gT.autostartline = 0;
+ }
+ gT.address = m_pTape->blocks[i]->getStartAddress();
+ gT.length = m_pTape->blocks[i]->getDataLength();
+
+ PMDawn::pData.push_back(gT);
+ }
+
+ size_t num = PMDawn::pData.size();
+
+ if (tvHwnd != nullptr)
+ {
+ PostMessage(tvHwnd, WM_USER + 2, PM_TAPEDATA_FULL, (LPARAM)&PMDawn::pData);
+ }
+}
//-----------------------------------------------------------------------------------------
+static void GetTapeViewerHwnd()
+{
+ tvHwnd = TapeViewer::tapeViewerWindowInternal;
+}
//-----------------------------------------------------------------------------------------
+static void SetupThreadLocalStorageForTapeData()
+{
+ return;
+ //// Setup the thread local storage
+ //dwTlsIndex = TlsAlloc();
+ //TlsSetValue(dwTlsIndex, GlobalAlloc(GPTR, sizeof(PMDawn::THREADDATA)));
+ //PMDawn::pData = (PMDawn::PTHREADDATA)TlsGetValue(dwTlsIndex);
+ //PMDawn::pData->filename = "POLO2";
+}
//-----------------------------------------------------------------------------------------
diff --git a/SpectREM/SpectREM/Win32/display.frag b/SpectREM/SpectREM/Win32/display.frag
index 7b103e6..8c2603d 100644
--- a/SpectREM/SpectREM/Win32/display.frag
+++ b/SpectREM/SpectREM/Win32/display.frag
@@ -9,6 +9,7 @@ out vec4 out_fragColor;
// Texture to be processed
uniform sampler2D s_displayTexture;
uniform sampler2D s_reflectionTexture;
+uniform sampler2D s_poloTexture;
// Uniforms linked to different screen settings
uniform int u_borderSize;
@@ -87,7 +88,7 @@ void main()
// Anything outside the texture should be black, otherwise sample the texel in the texture
if (texCoord.x < 0 || texCoord.y < 0 || texCoord.x > 1 || texCoord.y > 1)
{
- color = vec4(0, 0, 0, 1);
+ color = vec4(0.0, 0.0, 0.0, 1);
}
else
{
@@ -119,10 +120,10 @@ void main()
// Adjust colour based on contrast, saturation and brightness
color.rgb = colorCorrection(color.rgb, u_saturation, u_contrast, u_brightness);
-// if (u_showReflection == 1)
-// {
-// color = mix(color, vec4(colorCorrection(vec3(texture( s_reflectionTexture, texCoord * vec2(-1.0, 1.0))), 0.2, 0.5, 0.8), 1.0), 0.18);
-// }
+ if (u_showReflection == 1)
+ {
+ //color = mix(color, vec4(colorCorrection(vec3(texture( s_reflectionTexture, texCoord * vec2(1.0, -0.4) ) ), 0.2, 0.5, 0.8), 1.0), 0.18);
+ }
// Add scanlines
float scanline = sin(scanTexCoord.y * u_scanlineSize) * 0.09 * u_scanlines;
diff --git a/SpectREM/SpectREM/Win32/modTZX.bas b/SpectREM/SpectREM/Win32/modTZX.bas
new file mode 100644
index 0000000..fdbbc89
--- /dev/null
+++ b/SpectREM/SpectREM/Win32/modTZX.bas
@@ -0,0 +1,569 @@
+Attribute VB_Name = "modTZX"
+' /*******************************************************************************
+' modTAP.bas within vbSpec.vbp
+'
+' Routines to handle loading of ".TZX" files (Spectrum tape images)
+'
+' Authors: Mark Woodmass
+' Paul Dunn
+'
+' This program is free software; you can redistribute it and/or
+' modify it under the terms of the GNU General Public License
+' as published by the Free Software Foundation; either version 2
+' of the License, or (at your option) any later version.
+' This program is distributed in the hope that it will be useful,
+' but WITHOUT ANY WARRANTY; without even the implied warranty of
+' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+' GNU General Public License for more details.
+'
+' You should have received a copy of the GNU General Public License
+' along with this program; if not, write to the Free Software
+' Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+'
+' *******************************************************************************/
+Option Explicit
+
+Public gbTZXInserted As Long, gbTZXPlaying As Long
+Public glEarBit As Long
+Public TZXCurBlock As Long
+Public TZXNumBlocks As Long
+
+Private TZXArray() As Long
+Private TZXOffsets() As Long
+Private TZXBlockLength() As Long
+Private BitValues(7) As Long
+
+Private TZXBlockIsStandardTiming As Boolean
+Private TZXCallList() As Long
+Private TZXCallCounter As Long, TZXNumCalls As Long, TZXCallByte As Long
+Private TZXTotalTs As Long
+
+Private TZXState As Long, TZXAimTStates As Long
+Private TZXPointer As Long, TZXCurBlockID As Long
+Private TZXPulseLen As Long, TZXSync1Len As Long, TZXSync2Len As Long
+Private TZXZeroLen As Long, TZXOneLen As Long, TZXPauseLen As Long
+Private TZXDataLen As Long, TZXROMDataLen As Long, TZXUsedBits As Long
+Private TZXByte As Long
+Private TZXDataPos As Long, TZXPulsesDone As Long
+Private TZXPulseToneLen As Long, TZXBitLimit As Long, TZXBitCounter As Long
+Private TZXLoopCounter As Long, TZXLoopPoint As Long
+
+' ////////////////////////////////////////////////////////////////////////////////
+' // GetTZXBlockInfo()
+' //
+' // Retreives information about a specific TZX block in the current file
+' //
+' // lBlockNum IN Number of block to retrieve information on (zero based)
+' // lType OUT The type of block (see the TZX specification document)
+' // sText OUT Human-readable text describing the block
+' // lLen OUT Length of the block in bytes
+Public Sub GetTZXBlockInfo(lBlockNum As Long, lType As Long, sText As String, lLen As Long)
+ Dim lPtr As Long, l As Long
+
+ lPtr = TZXOffsets(lBlockNum)
+ lType = TZXArray(lPtr)
+
+ Select Case lType
+ Case &H10
+ sText = "Standard Block"
+ Case &H11
+ sText = "Turbo Block"
+ Case &H12
+ sText = "Pure Tone"
+ Case &H13
+ sText = "Pulse Sequence"
+ Case &H14
+ sText = "Pure Data Block"
+ Case &H15
+ sText = "Direct Recording"
+ Case &H16
+ sText = "C64 Standard Block"
+ Case &H17
+ sText = "C64 Turbo Block"
+ Case &H20
+ ' // Pause/StopTape
+ l = TZXArray(lPtr + 1) + (TZXArray(lPtr + 2) * 256&)
+ If l = 0 Then
+ sText = "Stop Tape"
+ Else
+ sText = "Pause Tape for " & CStr(l) & "ms"
+ End If
+ Case &H21
+ sText = "Group Start"
+ Case &H22
+ sText = "Group End"
+ Case &H23
+ sText = "Jump to Block"
+ Case &H24
+ sText = "Loop Start"
+ Case &H25
+ sText = "Loop End"
+ Case &H2A
+ sText = "Stop Tape if 48K"
+ Case &H30
+ sText = ""
+ l = TZXArray(lPtr + 1)
+ For l = lPtr + 2 To lPtr + 1 + l
+ sText = sText & Chr(TZXArray(l))
+ Next l
+ Case &H31
+ sText = "Message Block"
+ Case &H32
+ sText = "Archive Info"
+ Case &H33
+ sText = "Hardware Type"
+ Case &H34
+ sText = "Emulation Info"
+ Case &H35
+ sText = "Custom Info Block"
+ Case &H40
+ sText = "Snapshot Block"
+ Case &H5A
+ sText = "Block Merge Marker"
+ Case &HFE
+ sText = "End of Tape"
+ End Select
+
+ lLen = TZXBlockLength(lBlockNum)
+End Sub
+
+Public Sub StartTape()
+ gbTZXPlaying = True
+ TZXTotalTs = 0
+ glEarBit = 0
+End Sub
+
+Public Sub StopTape()
+ If gbTZXPlaying Then gbTZXPlaying = False
+End Sub
+
+Public Sub StartStopTape()
+ If gbTZXPlaying Then StopTape Else StartTape
+End Sub
+
+Public Sub OpenTZXFile(sName As String)
+ Dim ReadLength As Long
+ Dim s As String, b As Long, lCounter As Long
+ Dim F As Long, BlockLen As Long, BlockID As Long, ArrayLength As Long
+ Dim BlockList(2048) As Long
+ Dim BlockListNum As Long
+ Dim BlockLengths(2048) As Long
+ Dim BlockLengthsNum As Long
+
+ Dim hTZXFile As Long
+
+ Let b = 1
+ For F = 0 To 7
+ BitValues(F) = b
+ Let b = b * 2
+ Next F
+
+ ' // If we currently have a TAP file open, then close it
+ CloseTAPFile
+
+ If Dir$(sName) = "" Then Exit Sub
+
+ hTZXFile = FreeFile
+ Open sName For Binary As hTZXFile
+
+ ReadLength = LOF(hTZXFile)
+ If ReadLength = 0 Then
+ Close #hTZXFile
+ Exit Sub
+ End If
+
+ frmMainWnd.NewCaption = App.ProductName & " - " & GetFilePart(sName)
+
+ ' Read the TZX file into TZXArray
+ ReDim TZXArray(ReadLength + 1)
+
+ On Error Resume Next
+
+ s = Input(ReadLength, #hTZXFile)
+ For lCounter = 1 To Len(s)
+ TZXArray(lCounter - 1) = Asc(Mid$(s, lCounter, 1))
+ Next lCounter
+ TZXArray(ReadLength) = &HFE& ' end-of-tape block
+
+ Close #hTZXFile
+
+ ' Now decode the TZX file into an individual blocks list
+ gbTZXPlaying = False
+ gbTZXInserted = False
+
+ s = ""
+ ArrayLength = ReadLength + 1
+
+ For F = 0 To 6
+ s = s & Chr(TZXArray(F))
+ Next F
+
+ If s <> "ZXTape!" Then
+ Close #hTZXFile
+ End If
+
+ BlockListNum = 0
+ BlockLengthsNum = 0
+ gbTZXInserted = True
+ F = 10
+
+ Do
+ BlockID = TZXArray(F)
+ BlockList(BlockListNum) = F
+ BlockListNum = BlockListNum + 1
+
+ F = F + 1
+
+ Select Case BlockID
+ Case &H10: BlockLen = 256& * TZXArray(F + 3) + TZXArray(F + 2) + 4
+ Case &H11: BlockLen = TZXArray(F + 15) + (TZXArray(F + 16) * 256&) + (TZXArray(F + 17) * 65536) + 18
+ Case &H12: BlockLen = 4
+ Case &H13: BlockLen = 1 + (TZXArray(F) * 2)
+ Case &H14: BlockLen = TZXArray(F + 7) + (TZXArray(F + 8) * 256&) + (TZXArray(F + 9) * 65536) + 10
+ Case &H15: BlockLen = TZXArray(F + 5) + (TZXArray(F + 6) * 256&) + (TZXArray(F + 7) * 65536) + 8
+ Case &H20: BlockLen = 2
+ Case &H21: BlockLen = TZXArray(F) + 1
+ Case &H22: BlockLen = 0
+ Case &H23: BlockLen = 2
+ Case &H24: BlockLen = 2
+ Case &H25: BlockLen = 0
+ Case &H26: BlockLen = (TZXArray(F) + (TZXArray(F + 1) * 256&) * 2) + 2
+ Case &H27: BlockLen = 0
+ Case &H28: BlockLen = TZXArray(F) + (TZXArray(F + 1) * 256&) + 2
+ Case &H2A: BlockLen = 4
+ Case &H30: BlockLen = TZXArray(F) + 1
+ Case &H31: BlockLen = TZXArray(F + 1) + 2
+ Case &H32: BlockLen = TZXArray(F) + (TZXArray(F + 1) * 256&) + 2
+ Case &H33: BlockLen = (TZXArray(F) * 3) + 1
+ Case &H34: BlockLen = 8
+ Case &H35: BlockLen = TZXArray(F + 16) + (TZXArray(F + 17) * 256&) + (TZXArray(F + 18) * 65536) + (TZXArray(F + 19) * 16777216) + 20
+ Case &H40: BlockLen = TZXArray(F + 1) + (TZXArray(F + 2) * 256&) + (TZXArray(F + 3) * 65536) + 4
+ Case &H5A: BlockLen = 9
+ Case &HFE: BlockLen = 0
+ Case &HFF: BlockLen = 0
+ Case Else: BlockLen = TZXArray(F) + (TZXArray(F + 1) * 256&) + (TZXArray(F + 2) * 65536) + (TZXArray(F + 3) * 16777216) + 4
+ End Select
+
+ F = F + BlockLen
+ BlockLengths(BlockLengthsNum) = BlockLen + 1
+ BlockLengthsNum = BlockLengthsNum + 1
+ Loop Until F >= ArrayLength
+
+ TZXNumBlocks = BlockListNum
+
+ ReDim TZXOffsets(TZXNumBlocks)
+ ReDim TZXBlockLength(TZXNumBlocks)
+
+ For F = 0 To TZXNumBlocks - 1
+ TZXOffsets(F) = BlockList(F)
+ TZXBlockLength(F) = BlockLengths(F)
+ Next F
+ SetCurTZXBlock 0
+
+ frmTapePlayer.UpdateTapeList
+End Sub
+
+Public Sub SetCurTZXBlock(BlockNum As Long)
+ Dim F As Long
+
+ TZXBlockIsStandardTiming = False
+ TZXState = 5
+ TZXAimTStates = 0
+ TZXPointer = TZXOffsets(BlockNum)
+ TZXCurBlockID = TZXArray(TZXPointer)
+ Select Case TZXCurBlockID
+ Case &H10: ' Standard ROM Loader block
+ TZXPulseLen = 2168
+ If TZXArray(TZXPointer + 5) = &HFF Then TZXPulseToneLen = 3220 Else TZXPulseToneLen = 8064
+ TZXSync1Len = 667
+ TZXSync2Len = 735
+ TZXZeroLen = 855
+ TZXOneLen = 1710
+ TZXPauseLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ TZXDataLen = TZXBlockLength(BlockNum) + TZXOffsets(BlockNum)
+ TZXROMDataLen = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ TZXUsedBits = 8
+ TZXState = 0 ' State 0 - playing Pulse
+ TZXAimTStates = TZXPulseLen
+ TZXByte = 0
+ TZXCurBlock = BlockNum
+ TZXDataPos = TZXPointer + 5
+ TZXPulsesDone = 2
+ TZXBlockIsStandardTiming = True
+
+ Case &H11: ' Non-Standard TAP block
+ TZXPulseLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ TZXPulseToneLen = TZXArray(TZXPointer + 11) + (TZXArray(TZXPointer + 12) * 256&)
+ TZXSync1Len = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ TZXSync2Len = TZXArray(TZXPointer + 5) + (TZXArray(TZXPointer + 6) * 256&)
+ TZXZeroLen = TZXArray(TZXPointer + 7) + (TZXArray(TZXPointer + 8) * 256&)
+ TZXOneLen = TZXArray(TZXPointer + 9) + (TZXArray(TZXPointer + 10) * 256&)
+ TZXUsedBits = TZXArray(TZXPointer + 13)
+ TZXPauseLen = TZXArray(TZXPointer + 14) + (TZXArray(TZXPointer + 15) * 256&)
+ TZXState = 0 ' State 0 - playing Pulse.
+ TZXAimTStates = TZXPulseLen
+ TZXByte = 0
+ TZXCurBlock = BlockNum
+ TZXDataPos = TZXPointer + 19
+ TZXDataLen = TZXBlockLength(BlockNum) + TZXOffsets(BlockNum)
+ TZXROMDataLen = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ If (TZXPulseLen = 2168) And ((TZXPulseToneLen = 3220) Or (TZXPulseToneLen = 8064)) And (TZXSync1Len = 667) And (TZXSync2Len = 735) And (TZXZeroLen = 855) And (TZXOneLen = 1710) Then TZXBlockIsStandardTiming = True Else TZXBlockIsStandardTiming = False
+
+ Case &H12: ' Pure Tone
+ TZXState = 0 ' playing a possible pilot tone
+ TZXPulseLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ TZXPulseToneLen = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ TZXAimTStates = TZXPulseLen
+ TZXByte = 1
+ TZXCurBlock = BlockNum
+
+ Case &H13: ' Row of Pulses
+ TZXState = 0 ' playing a possible pilot tone
+ TZXPulseToneLen = TZXArray(TZXPointer + 1) ' // NUMBER OF PULSES
+ TZXPulseLen = TZXArray(TZXPointer + 2) + (TZXArray(TZXPointer + 3) * 256&)
+ TZXPulsesDone = 1
+ TZXByte = TZXPointer + 4
+ TZXAimTStates = TZXPulseLen
+ TZXCurBlock = BlockNum
+
+ Case &H14: ' Pure Data block
+ TZXZeroLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ TZXOneLen = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ TZXUsedBits = TZXArray(TZXPointer + 5)
+ TZXPauseLen = TZXArray(TZXPointer + 6) + (TZXArray(TZXPointer + 7) * 256&)
+ TZXDataLen = TZXBlockLength(BlockNum) + TZXOffsets(BlockNum)
+ TZXState = 3 ' Set to DATA Byte(s) output.
+ ' // CC IN
+ TZXDataPos = TZXPointer + 11
+ ' // CC OUT
+ TZXByte = TZXPointer + 11
+ If (TZXArray(TZXByte) And 128) > 0 Then TZXAimTStates = TZXOneLen Else TZXAimTStates = TZXZeroLen
+ TZXPulsesDone = 2
+ If TZXByte = TZXDataLen - 1 Then TZXBitLimit = BitValues(8 - TZXUsedBits) Else TZXBitLimit = 1
+ TZXBitCounter = 128
+ TZXCurBlock = BlockNum
+
+ Case &H15: ' Direct Recording Block
+ TZXOneLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&) ' Length of Sample (Ts)
+ TZXPauseLen = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&) ' (ms)
+ TZXUsedBits = TZXArray(TZXPointer + 5) ' Samples used in last byte
+ TZXDataLen = TZXArray(TZXPointer + 6) + (TZXArray(TZXPointer + 7) * 256&) + TZXArray(TZXPointer + 8) * 65536 ' TZXBlockLength(BlockNum) + TZXOffsets(BlockNum)
+ TZXByte = TZXPointer + 9
+ TZXState = 3 ' Set to DATA bytes output
+ TZXAimTStates = TZXOneLen
+ If TZXByte = TZXDataLen - 1 Then TZXBitLimit = BitValues(8 - TZXUsedBits) Else TZXBitLimit = 1
+ TZXBitCounter = 128
+ glEarBit = 64 * (TZXArray(TZXByte) \ 128)
+ TZXCurBlock = BlockNum
+
+ Case &H20: ' Pause or STOP tape.
+ TZXCurBlock = BlockNum
+ TZXPauseLen = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ If TZXPauseLen = 0 Then
+ If gbTZXPlaying Then StartStopTape
+ Else
+ TZXAimTStates = TZXPauseLen * 3500
+ TZXState = 4 ' When the TZXTStates gets past TZXAimStates, the next block will be used
+ End If
+
+ Case &H23: ' Jump to block
+ TZXByte = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ If TZXByte < 32768 Then SetCurTZXBlock (BlockNum + TZXByte) Else SetCurTZXBlock (BlockNum - (65536 - TZXByte))
+
+ Case &H24: ' Loop Start
+ TZXLoopCounter = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&)
+ TZXLoopPoint = BlockNum + 1
+ SetCurTZXBlock (BlockNum + 1)
+
+ Case &H25: ' Loop End
+ TZXLoopCounter = TZXLoopCounter - 1
+ If TZXLoopCounter > 0 Then SetCurTZXBlock (TZXLoopPoint) Else SetCurTZXBlock (BlockNum + 1)
+
+ Case &H26: ' Call Sequence
+ TZXNumCalls = TZXArray(TZXPointer + 1) + (TZXArray(TZXPointer + 2) * 256&) - 1
+ TZXCallByte = TZXNumCalls
+ TZXCallCounter = 0
+ ReDim TZXCallList(TZXNumCalls)
+ For F = 0 To TZXNumCalls - 1
+ TZXCallList(F) = TZXArray((TZXPointer + 4) + (F * 2)) + (TZXArray((TZXPointer + 5) + (F * 2) + 1) * 256&)
+ Next F
+ TZXCallByte = BlockNum
+ TZXByte = TZXArray(TZXPointer + 3) + (TZXArray(TZXPointer + 4) * 256&)
+ If TZXByte < 32768 Then SetCurTZXBlock (BlockNum + TZXByte) Else SetCurTZXBlock (BlockNum - (65536 - TZXByte))
+
+ Case &H27: ' CALL Return
+ If TZXCallCounter < TZXNumCalls Then
+ TZXCallCounter = TZXCallCounter + 1
+ TZXByte = TZXCallList(TZXCallCounter)
+ If TZXByte < 32768 Then SetCurTZXBlock (TZXCallByte + TZXByte) Else SetCurTZXBlock (TZXCallByte - (65536 - TZXByte))
+ End If
+
+ Case &H2A: ' Stop tape in 48k Mode
+ If glEmulatedModel = 0 Then ' 48k Speccy?
+ If gbTZXPlaying Then StartStopTape
+ End If
+ TZXCurBlock = BlockNum
+
+ Case &HFE: ' End of Tape
+ TZXAimTStates = 30
+ TZXCurBlock = BlockNum
+ If gbTZXPlaying Then SetCurTZXBlock (0)
+ StopTape
+
+ Case Else: TZXCurBlock = BlockNum
+ End Select
+
+' If TZXCurBlock > TZXLastDataBlock Then TZXState = 5
+ If frmTapePlayer.Visible Then frmTapePlayer.UpdateCurBlock
+End Sub
+
+Public Sub UpdateTZXState(TapeTStates As Long)
+ Dim LastEarBit As Long, F As Long
+
+ TZXTotalTs = TZXTotalTs + TapeTStates
+ While (TZXTotalTs >= TZXAimTStates) And gbTZXPlaying
+ TZXTotalTs = TZXTotalTs - TZXAimTStates
+ Select Case TZXCurBlockID
+ Case &H10&, &H11&, &H14&
+ Select Case TZXState
+ Case 0 'Playing Pilot tone.
+ glEarBit = glEarBit Xor 64
+ If TZXByte < TZXPulseToneLen Then ' TZXByte holds number of pulses
+ TZXAimTStates = TZXPulseLen
+ TZXByte = TZXByte + 1&
+ Else
+ TZXByte = 0
+ TZXState = 1 ' Set to SYNC1 Pulse output
+ TZXAimTStates = TZXSync1Len
+ End If
+
+ Case 1 ' SYNC 1
+ glEarBit = glEarBit Xor 64
+ TZXState = 2 ' Set to SYNC2 Pulse output
+ TZXAimTStates = TZXSync2Len
+
+ Case 2 ' SYNC 2
+ glEarBit = glEarBit Xor 64
+ TZXState = 3 ' Set to DATA Byte(s) output
+ TZXByte = TZXDataPos
+ If (TZXArray(TZXByte) And 128) > 0 Then ' Set next pulse length
+ TZXAimTStates = TZXOneLen
+ Else
+ TZXAimTStates = TZXZeroLen
+ End If
+ TZXPulsesDone = 2 ' *2* edges per Data BIT, one on, one off
+ TZXBitCounter = 128 ' Start with the full byte
+ TZXBitLimit = 1
+
+ Case 3 ' DATA Bytes out
+ glEarBit = glEarBit Xor 64
+ TZXPulsesDone = TZXPulsesDone - 1
+ If TZXPulsesDone = 0 Then ' Done both pulses for this bit?
+ If TZXBitCounter > TZXBitLimit Then ' Done all the bits for this byte?
+ TZXBitCounter = TZXBitCounter \ 2 ' Bitcounter counts *down*
+ TZXPulsesDone = 2
+ If (TZXArray(TZXByte) And TZXBitCounter) > 0 Then
+ TZXAimTStates = TZXOneLen
+ Else
+ TZXAimTStates = TZXZeroLen
+ End If
+ Else ' all bits done, setup for next byte
+ TZXByte = TZXByte + 1
+ If TZXByte < TZXDataLen Then ' last byte?
+ If TZXByte = TZXDataLen - 1 Then
+ TZXBitLimit = BitValues(8 - TZXUsedBits) ' if so, set up the last bits used
+ Else
+ TZXBitLimit = 1 ' else use full 8 bits
+ End If
+ TZXBitCounter = 128
+ TZXPulsesDone = 2
+ If (TZXArray(TZXByte) And 128) > 0 Then
+ TZXAimTStates = TZXOneLen
+ Else
+ TZXAimTStates = TZXZeroLen
+ End If
+ Else
+ If (TZXPauseLen > 0) Then
+ TZXAimTStates = TZXPauseLen * 3500
+ TZXState = 4 ' Set to Pause output
+ Else
+ TZXState = 0
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End If
+ End If
+ End If
+ Else ' Not done both pulses, flip the ear bit next time
+ If (TZXArray(TZXByte) And TZXBitCounter) > 0 Then
+ TZXAimTStates = TZXOneLen
+ Else
+ TZXAimTStates = TZXZeroLen
+ End If
+ End If
+
+ Case 4: ' End Pause output
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End Select
+
+ Case &H12&
+ glEarBit = glEarBit Xor 64
+ If TZXByte < TZXPulseToneLen Then
+ TZXAimTStates = TZXPulseLen
+ TZXByte = TZXByte + 1
+ Else
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End If
+
+ Case &H13&
+ glEarBit = glEarBit Xor 64
+ If TZXPulsesDone < TZXPulseToneLen Then
+ TZXPulseLen = TZXArray(TZXByte) + (TZXArray(TZXByte + 1) * 256&)
+ TZXAimTStates = TZXPulseLen
+ TZXByte = TZXByte + 2
+ TZXPulsesDone = TZXPulsesDone + 1
+ Else
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End If
+
+ Case &H15& ' *UnTested* - any TZX actually use a DRB block?
+ LastEarBit = glEarBit
+ If TZXBitCounter > TZXBitLimit Then ' Done all the bits for this byte?
+ TZXBitCounter = TZXBitCounter \ 2 ' Bitcounter counts *down*
+ If (TZXArray(TZXByte) And TZXBitCounter) > 0 Then ' Set the ear bit
+ glEarBit = 64
+ Else
+ glEarBit = 0
+ End If
+ TZXAimTStates = TZXOneLen
+ Else ' all bits done, setup for next byte
+ TZXByte = TZXByte + 1
+ If TZXByte < TZXDataLen Then ' last byte?
+ If TZXByte = TZXDataLen - 1 Then
+ TZXBitLimit = BitValues(8 - TZXUsedBits) ' if so, set up the last bits used
+ Else
+ TZXBitLimit = 1 ' else use full 8 bits
+ End If
+ TZXBitCounter = 128
+ If (TZXArray(TZXByte) And TZXBitCounter) > 0 Then ' Set the ear bit
+ glEarBit = 64
+ Else
+ glEarBit = 0
+ End If
+ TZXAimTStates = TZXOneLen
+ Else
+ If TZXPauseLen > 0 Then
+ TZXAimTStates = TZXPauseLen * 3500
+ TZXState = 4 ' Set to Pause output
+ Else
+ TZXState = 0
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End If
+ End If
+ End If
+ Case &HFE
+ StopTape
+ Case Else
+ SetCurTZXBlock (TZXCurBlock + 1)
+ End Select
+ Wend
+End Sub
+
diff --git a/SpectREM/resource.h b/SpectREM/resource.h
index 87a0946..8879117 100644
--- a/SpectREM/resource.h
+++ b/SpectREM/resource.h
@@ -3,14 +3,23 @@
// Used by SpectREM.rc
//
#define IDR_MENU1 101
-#define IDD_SETTINGS_DIALOG 101
#define IDR_ACCELERATOR1 102
#define IDR_MENUACCELERATORS 102
#define IDI_ICON1 105
+#define IDD_PROPPAGE_SOUND 106
+#define IDD_PROPPAGE_DISPLAY 107
#define IDI_ICON2 108
+#define IDS_FIRSTCOLUMN 111
+#define IDS_BLOCKTYPE 112
+#define IDS_FILENAME 113
+#define IDD_DIALOG_SETTINGS 113
+#define IDS_AUTOSTARTLINE 114
+#define IDD_PROPPAGE_MEDIUM 114
+#define IDD_PROPPAGE_MISC 114
+#define IDS_ADDRESS 115
+#define IDS_LENGTH 116
#define ID_TEXTFILE 256
-#define IDC_BTN_SETTINGS_SAVE 1001
-#define IDC_BTN_SETTINGS_CLOSE 1002
+#define IDC_BUTTON1 1004
#define ID_FILE_OPENSNAPSHOT 40001
#define ID_FILE_EXIT 40002
#define ID_EMULATION_FULLSPEED 40003
@@ -49,6 +58,9 @@
#define ID_TAPE_REWINGTAPE 40068
#define ID_TAPE_REWINDTAPE 40069
#define ID_TAPE_TAPEVIEWER 40072
+#define ID_SWITCH_TOPLUS2 40075
+#define ID_SWITCH_TOPLUS2A 40076
+#define ID_SWITCH_TOPLUS3 40077
#define ID_SHADER_DISPLAY_FRAG 57000
#define ID_SHADER_DISPLAY_VERT 57001
#define ID_SHADER_CLUT_FRAG 57002
@@ -58,9 +70,9 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 110
-#define _APS_NEXT_COMMAND_VALUE 40075
-#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_RESOURCE_VALUE 119
+#define _APS_NEXT_COMMAND_VALUE 40078
+#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif