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