Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Andrea Odetti 2020-10-02 21:07:49 +01:00
commit 14fdc2520b
18 changed files with 630 additions and 185 deletions

View file

@ -109,14 +109,14 @@ When running AppleWin from Visual Studio (eg. F5), then F12 will trigger a break
This is undesirable, since F12 is used to load a save-state.
AppleWin doesn't support CTRL+F12 to load a save-state too (for this very reason), but it's possible to disable F12 triggering the breakpoint.
AppleWin does also support CTRL+F12 to load a save-state too (for this very reason), but it's possible to disable F12 triggering the breakpoint.
Background:
F12 is the OS's default UserDebuggerHotKey:
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc786263(v=ws.10)
Fix:
. Change this Registry key: "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug" to 0x07 (*)
. Change this Registry key: "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug" -> UserDebuggerHotKey to 0x07 (*)
. And restart the PC for it to take effect.
(*) Where 0x07 = Undefined

View file

@ -90,11 +90,11 @@ CAPTION "Configuration"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
LTEXT "&Model:",IDC_STATIC,5,7,40,8
COMBOBOX IDC_COMPUTER,45,5,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_COMPUTER,45,5,91,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Confirm reboot",IDC_CHECK_CONFIRM_REBOOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,8,62,10
GROUPBOX "Video",IDC_STATIC,5,22,200,56
LTEXT "Mo&de:",IDC_STATIC,12,33,33,8
COMBOBOX IDC_VIDEOTYPE,45,30,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_VIDEOTYPE,33,30,103,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Monochrome &Color...",IDC_MONOCOLOR,12,46,80,14
CONTROL "50% Scan lines",IDC_CHECK_HALF_SCAN_LINES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,33,62,10
CONTROL "Vertical blend",IDC_CHECK_VERTICAL_BLEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,48,62,10

View file

@ -1751,6 +1751,10 @@ static bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_cmdLine.newVideoType = VT_COLOR_MONITOR_RGB;
}
else if (strcmp(lpCmdLine, "-video-mode=rgb-videocard") == 0)
{
g_cmdLine.newVideoType = VT_COLOR_VIDEOCARD_RGB;
}
else if (strcmp(lpCmdLine, "-video-mode=composite-monitor") == 0) // GH#763
{
g_cmdLine.newVideoType = VT_COLOR_MONITOR_NTSC;
@ -2041,6 +2045,9 @@ static void RepeatInitialization(void)
FrameCreateWindow(); // g_hFrameWindow is now valid
LogFileOutput("Main: FrameCreateWindow() - post\n");
// Init palette color
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType());
// Allow the 4 hardcoded slots to be configurated as empty
// NB. this state is not persisted to the Registry/conf.ini (just as '-s7 empty' isn't)
// TODO: support bSlotEmpty[] for slots: 0,4,5

View file

@ -440,10 +440,10 @@ bool DebugGetVideoMode(UINT* pVideoMode)
// File _______________________________________________________________________
int _GetFileSize( FILE *hFile )
size_t _GetFileSize( FILE *hFile )
{
fseek( hFile, 0, SEEK_END );
int nFileBytes = ftell( hFile );
size_t nFileBytes = ftell( hFile );
fseek( hFile, 0, SEEK_SET );
return nFileBytes;
@ -701,8 +701,6 @@ Update_t CmdBookmarkList (int nArgs)
//===========================================================================
Update_t CmdBookmarkLoad (int nArgs)
{
char sFilePath[ MAX_PATH ] = "";
if (nArgs == 1)
{
// strcpy( sMiniFileName, pFileName );
@ -1457,8 +1455,6 @@ Update_t CmdBreakpointAddPC (int nArgs)
g_aArgs[1].nValue = g_nDisasmCurAddress;
}
bool bHaveCmp = false;
// int iParamSrc;
int iParamCmp;
@ -1476,12 +1472,12 @@ Update_t CmdBreakpointAddPC (int nArgs)
{
switch (iParamCmp)
{
case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; bHaveCmp = true; break;
case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; bHaveCmp = true; break;
case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; bHaveCmp = true; break;
case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; bHaveCmp = true; break;
case PARAM_BP_LESS_EQUAL : iCmp = BP_OP_LESS_EQUAL ; break;
case PARAM_BP_LESS_THAN : iCmp = BP_OP_LESS_THAN ; break;
case PARAM_BP_EQUAL : iCmp = BP_OP_EQUAL ; break;
case PARAM_BP_NOT_EQUAL : iCmp = BP_OP_NOT_EQUAL ; break;
case PARAM_BP_GREATER_THAN : iCmp = BP_OP_GREATER_THAN ; break;
case PARAM_BP_GREATER_EQUAL: iCmp = BP_OP_GREATER_EQUAL; break;
default:
break;
}
@ -1816,8 +1812,6 @@ Update_t CmdBreakpointSave (int nArgs)
//===========================================================================
Update_t _CmdAssemble( WORD nAddress, int iArg, int nArgs )
{
bool bHaveLabel = false;
// if AlphaNumeric
ArgToken_e iTokenSrc = NO_TOKEN;
ParserFindToken( g_pConsoleInput, g_aTokens, NUM_TOKENS, &iTokenSrc );
@ -1825,8 +1819,6 @@ Update_t _CmdAssemble( WORD nAddress, int iArg, int nArgs )
if (iTokenSrc == NO_TOKEN) // is TOKEN_ALPHANUMERIC
if (g_pConsoleInput[0] != CHAR_SPACE)
{
bHaveLabel = true;
// Symbol
char *pSymbolName = g_aArgs[ iArg ].sArg; // pArg->sArg;
SymbolUpdate( SYMBOLS_ASSEMBLY, pSymbolName, nAddress, false, true ); // bool bRemoveSymbol, bool bUpdateSymbol )
@ -4505,7 +4497,7 @@ Update_t CmdMemoryLoad (int nArgs)
FILE *hFile = fopen( sLoadSaveFilePath.c_str(), "rb" );
if (hFile)
{
int nFileBytes = _GetFileSize( hFile );
size_t nFileBytes = _GetFileSize( hFile );
if (nFileBytes > _6502_MEM_END)
nFileBytes = _6502_MEM_END + 1; // Bank-switched RAM/ROM is only 16-bit
@ -5378,7 +5370,7 @@ Update_t CmdNTSC (int nArgs)
*pDst++ = pTmp[3];
}
}
/*
// we duplicate phase 0 a total of 4 times
const size_t nBytesPerScanLine = 4096 * nBPP;
for( int iPhase = 1; iPhase < 4; iPhase++ )
@ -5939,11 +5931,6 @@ Update_t _CmdMemorySearch (int nArgs, bool bTextIsAscii = true )
return ConsoleDisplayError( TEXT("Error: Missing address seperator (comma or colon)" ) );
int iArgFirstByte = 4;
// S start,len #
int nMinLen = nArgs - (iArgFirstByte - 1);
bool bHaveWildCards = false;
int iArg;
MemorySearchValues_t vMemorySearchValues;
@ -6240,8 +6227,6 @@ Update_t CmdOutputCalc (int nArgs)
//===========================================================================
Update_t CmdOutputEcho (int nArgs)
{
TCHAR sText[ CONSOLE_WIDTH ] = TEXT("");
if (g_aArgs[1].bType & TYPE_QUOTED_2)
{
ConsoleDisplayPush( g_aArgs[1].sArg );
@ -6534,7 +6519,6 @@ Update_t CmdOutputRun (int nArgs)
if (script.Read( sFileName ))
{
int iLine = 0;
int nLine = script.GetNumLines();
Update_t bUpdateDisplay = UPDATE_NOTHING;
@ -6653,10 +6637,6 @@ bool ParseAssemblyListing( bool bBytesToMemory, bool bAddSymbols )
const DWORD INVALID_ADDRESS = _6502_MEM_END + 1;
bool bPrevSymbol = false;
bool bFourBytes = false;
BYTE nByte4 = 0;
int nLines = g_AssemblerSourceBuffer.GetNumLines();
for( int iLine = 0; iLine < nLines; iLine++ )
{
@ -8154,6 +8134,9 @@ Update_t ExecuteCommand (int nArgs)
//===========================================================================
void OutputTraceLine ()
{
if (!g_hTraceFile)
return;
DisasmLine_t line;
GetDisassemblyLine( regs.pc, line );
@ -8172,9 +8155,6 @@ void OutputTraceLine ()
nRegFlags >>= 1;
}
if (!g_hTraceFile)
return;
if (g_bTraceHeader)
{
g_bTraceHeader = false;

View file

@ -787,8 +787,6 @@ bool _6502_GetTargetAddress ( const WORD & nAddress, WORD & nTarget_ )
iOpcode = _6502_GetOpmodeOpbyte( nAddress, iOpmode, nOpbytes );
// Composite string that has the target nAddress
// WORD nTarget = 0;
int nTargetOffset_ = 0;
if ((iOpmode != AM_IMPLIED) &&
(iOpmode != AM_1) &&
@ -796,10 +794,10 @@ bool _6502_GetTargetAddress ( const WORD & nAddress, WORD & nTarget_ )
(iOpmode != AM_3))
{
int nTargetPartial;
int nTargetPartial2;
int nTargetPointer;
WORD nTargetValue = 0; // de-ref
int nTargetBytes;
_6502_GetTargets( nAddress, &nTargetPartial, &nTargetPointer, &nTargetBytes, false );
_6502_GetTargets( nAddress, &nTargetPartial, &nTargetPartial2, &nTargetPointer, &nTargetBytes, false );
// if (nTargetPointer == NO_6502_TARGET)
// {
@ -870,9 +868,8 @@ int AssemblerHashMnemonic ( const TCHAR * pMnemonic )
const int NUM_MSK_BITS = 5; // 4 -> 5 prime
const Hash_t BIT_MSK_HIGH = ((1 << NUM_MSK_BITS) - 1) << NUM_LOW_BITS;
int nLen = strlen( pMnemonic );
#if DEBUG_ASSEMBLER
int nLen = strlen( pMnemonic );
static int nMaxLen = 0;
if (nMaxLen < nLen) {
nMaxLen = nLen;
@ -961,7 +958,7 @@ void _CmdAssembleHashDump ()
std::sort( vHashes.begin(), vHashes.end(), HashOpcode_t() );
Hash_t nPrevHash = vHashes.at( 0 ).m_nValue;
// Hash_t nPrevHash = vHashes.at( 0 ).m_nValue;
Hash_t nThisHash = 0;
for( iOpcode = 0; iOpcode < NUM_OPCODES; iOpcode++ )
@ -1097,7 +1094,7 @@ bool AssemblerGetArgs( int iArg, int nArgs, WORD nBaseAddress )
while (iArg < g_nArgRaw)
{
int iToken = pArg->eToken;
int iType = pArg->bType;
// int iType = pArg->bType;
if (iToken == TOKEN_HASH)
{

View file

@ -354,7 +354,6 @@ void ConsoleBufferToDisplay ()
//===========================================================================
void ConsoleConvertFromText ( conchar_t * sText, const char * pText )
{
int x = 0;
const char *pSrc = pText;
conchar_t *pDst = sText;
while (pSrc && *pSrc)
@ -523,13 +522,6 @@ void ConsoleInputReset ()
g_aConsoleInput[0] = g_sConsolePrompt[0];
g_nConsolePromptLen = 1;
// int nLen = strlen( g_aConsoleInput );
#if CONSOLE_INPUT_CHAR16
int nLen = ConsoleLineLength( g_aConsoleInput );
#else
int nLen = strlen( g_aConsoleInput );
#endif
g_pConsoleInput = &g_aConsoleInput[ g_nConsolePromptLen ];
g_nConsoleInputChars = 0;
}

View file

@ -197,7 +197,7 @@ Update_t CmdDisasmDataList (int nArgs)
// Need to iterate through all blocks
DisasmData_t* pData = NULL;
while( pData = Disassembly_Enumerate( pData ) )
while( (pData = Disassembly_Enumerate( pData )) )
{
if (pData->iDirective != _NOP_REMOVED)
{

View file

@ -1061,7 +1061,6 @@ char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iView,
const int iCtrlBackground /*= BG_INFO_CHAR*/, const int iCtrlForeground /*= FG_INFO_CHAR_LO*/ )
{
bool bHighBit = false;
bool bAsciBit = false;
bool bCtrlBit = false;
int iTextBG = iAsciBackground;
@ -1154,7 +1153,6 @@ void DrawBreakpoints ( int line )
rect.right = DISPLAY_WIDTH;
rect.bottom = rect.top + g_nFontHeight;
const int MAX_BP_LEN = 16;
char sText[16] = "Breakpoints"; // TODO: Move to BP1
#if DISPLAY_BREAKPOINT_TITLE
@ -1499,7 +1497,7 @@ int GetDisassemblyLine ( WORD nBaseAddress, DisasmLine_t & line_ )
(iOpmode != AM_3))
{
// Assume target address starts after the opcode ...
// BUT in the Assembler Directve / Data Disassembler case for define addr/word
// BUT in the Assembler Directive / Data Disassembler case for define addr/word
// the opcode literally IS the target address!
if( pData )
{
@ -1763,10 +1761,10 @@ void FormatOpcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ )
void FormatNopcodeBytes ( WORD nBaseAddress, DisasmLine_t & line_ )
{
char *pDst = line_.sTarget;
const char *pSrc = 0;
const char *pSrc = 0;
DWORD nStartAddress = line_.pDisasmData->nStartAddress;
DWORD nEndAddress = line_.pDisasmData->nEndAddress ;
int nDataLen = nEndAddress - nStartAddress + 1 ;
// int nDataLen = nEndAddress - nStartAddress + 1 ;
int nDisplayLen = nEndAddress - nBaseAddress + 1 ; // *inclusive* KEEP IN SYNC: _CmdDefineByteRange() CmdDisasmDataList() _6502_GetOpmodeOpbyte() FormatNopcodeBytes()
int len = nDisplayLen;
@ -1920,7 +1918,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
if (! ((g_iWindowThis == WINDOW_CODE) || ((g_iWindowThis == WINDOW_DATA))))
return 0;
int iOpcode;
// int iOpcode;
int iOpmode;
int nOpbyte;
DisasmLine_t line;
@ -1931,7 +1929,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
int bDisasmFormatFlags = GetDisassemblyLine( nBaseAddress, line );
const DisasmData_t *pData = line.pDisasmData;
iOpcode = line.iOpcode;
// iOpcode = line.iOpcode;
iOpmode = line.iOpmode;
nOpbyte = line.nOpbyte;
@ -1984,7 +1982,6 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
aTabs[ TS_IMMEDIATE ] -= 1;
}
#endif
const int OPCODE_TO_LABEL_SPACE = static_cast<int>( aTabs[ TS_INSTRUCTION ] - aTabs[ TS_LABEL ] );
int iTab = 0;
int nSpacer = 11; // 9
@ -2010,12 +2007,6 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
aTabs[ iTab ] *= nDefaultFontWidth;
}
#if USE_APPLE_FONT
const int DISASM_SYMBOL_LEN = 12;
#else
const int DISASM_SYMBOL_LEN = 9;
#endif
int nFontHeight = g_aFontConfig[ FONT_DISASM_DEFAULT ]._nLineHeight; // _nFontHeight; // g_nFontHeight
RECT linerect;
@ -2563,7 +2554,6 @@ void DrawMemory ( int line, int iMemDump )
const int MAX_MEM_VIEW_TXT = 16;
char sText[ MAX_MEM_VIEW_TXT * 2 ];
char sData[ MAX_MEM_VIEW_TXT * 2 ];
char sType [ 6 ] = "Mem";
char sAddress[ 8 ] = "";
@ -2610,8 +2600,6 @@ void DrawMemory ( int line, int iMemDump )
rect.top = rect2.top;
rect.bottom = rect2.bottom;
sData[0] = 0;
WORD iAddress = nAddr;
int nLines = g_nDisplayMemoryLines;
@ -2648,9 +2636,6 @@ void DrawMemory ( int line, int iMemDump )
for (int iCol = 0; iCol < nCols; iCol++)
{
bool bHiBit = false;
bool bLoBit = false;
DebuggerSetColorBG( DebuggerGetColor( iBackground ));
DebuggerSetColorFG( DebuggerGetColor( iForeground ));
@ -2682,8 +2667,6 @@ void DrawMemory ( int line, int iMemDump )
BYTE nData = (unsigned)*(LPBYTE)(mem+iAddress);
sText[0] = 0;
char c = nData;
if (iView == MEM_VIEW_HEX)
{
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
@ -2712,7 +2695,6 @@ void DrawMemory ( int line, int iMemDump )
rect.top += g_nFontHeight;
rect.bottom += g_nFontHeight;
sData[0] = 0;
}
}
@ -2857,7 +2839,6 @@ void _DrawSoftSwitchAddress( RECT & rect, int nAddress, int bg_default = BG_INFO
void _DrawSoftSwitch( RECT & rect, int nAddress, bool bSet, char *sPrefix, char *sOn, char *sOff, const char *sSuffix = NULL, int bg_default = BG_INFO )
{
RECT temp = rect;
char sText[ 4 ] = "";
_DrawSoftSwitchAddress( temp, nAddress, bg_default );
@ -3104,9 +3085,8 @@ void DrawSoftSwitches( int iSoftSwitch )
DebuggerSetColorBG( DebuggerGetColor( BG_INFO ));
DebuggerSetColorFG( DebuggerGetColor( FG_INFO_TITLE ));
char sText[16] = "";
#if SOFTSWITCH_OLD
char sText[16] = "";
// $C050 / $C051 = TEXTOFF/TEXTON = SW.TXTCLR/SW.TXTSET
// GR / TEXT
// GRAPH/TEXT
@ -3411,7 +3391,6 @@ void DrawWatches (int line)
PrintTextCursorX( ":", rect2 );
BYTE nTarget8 = 0;
BYTE nValue8 = 0;
nTarget8 = (unsigned)*(LPBYTE)(mem+g_aWatches[iWatch].nAddress);
sprintf(sText,"%02X", nTarget8 );
@ -3717,7 +3696,7 @@ void DrawSubWindow_Data (Update_t bUpdate)
rect.left = X_CHAR;
// Seperator
// Separator
DebuggerSetColorFG( DebuggerGetColor( FG_DISASM_OPERATOR ));
PrintTextCursorX( " | ", rect );
@ -3733,12 +3712,12 @@ void DrawSubWindow_Data (Update_t bUpdate)
for (iByte = 0; iByte < nMaxOpcodes; iByte++ )
{
BYTE nImmediate = (unsigned)*(LPBYTE)(mem + iAddress);
int iTextBackground = iBackground;
/*int iTextBackground = iBackground;
if ((iAddress >= _6502_IO_BEGIN) && (iAddress <= _6502_IO_END))
{
iTextBackground = BG_INFO_IO_BYTE;
}
*/
ColorizeSpecialChar( sImmediate, (BYTE) nImmediate, eView, iBackground );
PrintTextCursorX( (LPCSTR) sImmediate, rect );
@ -3975,7 +3954,6 @@ void DrawSubWindow_Source2 (Update_t bUpdate)
DebuggerSetColorFG( DebuggerGetColor( FG_SOURCE ));
int iSource = g_iSourceDisplayStart;
int nLines = g_nDisasmWinHeight;
int y = g_nDisasmWinHeight;

View file

@ -85,7 +85,7 @@
{
public:
VideoScannerDisplayInfo(void) : isDecimal(false), isHorzReal(false), cycleMode(rel),
lastCumulativeCycles(0), cycleDelta(0) {}
lastCumulativeCycles(0), savedCumulativeCycles(0), cycleDelta(0) {}
void Reset(void) { lastCumulativeCycles = savedCumulativeCycles = g_nCumulativeCycles; cycleDelta = 0; }
bool isDecimal;

View file

@ -60,7 +60,6 @@ bool TestStringCat ( TCHAR * pDst, LPCSTR pSrc, const int nDstSize )
int nLenDst = _tcslen( pDst );
int nLenSrc = _tcslen( pSrc );
int nSpcDst = nDstSize - nLenDst;
int nChars = MIN( nLenSrc, nSpcDst );
bool bOverflow = (nSpcDst <= nLenSrc); // 2.5.6.25 BUGFIX
if (bOverflow)
@ -390,7 +389,6 @@ bool Colorize( char * pDst, const char * pSrc )
const char sExamples[] = "Examples:";
const int nExamples = sizeof( sExamples ) - 1;
int nLen = 0;
while (*pSrc)
{
if (strncmp( sUsage, pSrc, nUsage) == 0)
@ -1530,10 +1528,6 @@ Update_t CmdHelpList (int nArgs)
char sText[ nBuf ] = "";
int nLenLine = strlen( sText );
int y = 0;
int nLinesScrolled = 0;
int nMaxWidth = g_nConsoleDisplayWidth - 1;
int iCommand;
@ -1547,7 +1541,6 @@ Update_t CmdHelpList (int nArgs)
}
std::sort( g_vSortedCommands.begin(), g_vSortedCommands.end(), commands_functor_compare() );
}
int nCommands = g_vSortedCommands.size();
int nLen = 0;
// Colorize( sText, "Commands: " );

View file

@ -418,7 +418,6 @@ void ArgsRawParse ( void )
WORD nAddressArg;
WORD nAddressSymbol;
WORD nAddressValue;
int nParamLen = 0;
while (iArg <= nArg)
{
@ -869,8 +868,6 @@ const TCHAR * FindTokenOrAlphaNumeric ( const TCHAR *pSrc, const TokenTable_t *a
//===========================================================================
void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDstSize, int nTabStop )
{
int nLen = _tcslen( pText );
int TAB_SPACING = 8;
int TAB_SPACING_1 = 16;
int TAB_SPACING_2 = 21;
@ -881,7 +878,6 @@ void TextConvertTabsToSpaces( TCHAR *pDeTabified_, LPCTSTR pText, const int nDst
LPCTSTR pSrc = pText;
LPTSTR pDst = pDeTabified_;
int iTab = 0; // number of tabs seen
int nTab = 0; // gap left to next tab
int nGap = 0; // actual gap
int nCur = 0; // current cursor position

View file

@ -443,6 +443,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static void updateScreenText80 ( long cycles6502 );
static void updateScreenText40RGB ( long cycles6502 );
static void updateScreenText80RGB ( long cycles6502 );
static void updateScreenDoubleHires80Simplified(long cycles6502);
static void updateScreenDoubleHires80RGB(long cycles6502);
//===========================================================================
static void set_csbits()
@ -830,7 +832,7 @@ inline void updateVideoScannerAddress()
(g_pFuncUpdateGraphicsScreen == updateScreenText80) ||
(g_pFuncUpdateGraphicsScreen == updateScreenText80RGB) ||
(g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && (g_pFuncUpdateTextScreen == updateScreenText80 || g_pFuncUpdateGraphicsScreen == updateScreenText80RGB)))
&& (g_eVideoType != VT_COLOR_MONITOR_RGB)) // Fix for "Ansi Story" (Turn the disk over) - Top row of TEXT80 is shifted by 1 pixel
&& (g_eVideoType != VT_COLOR_MONITOR_RGB) && (g_eVideoType != VT_COLOR_VIDEOCARD_RGB)) // Fix for "Ansi Story" (Turn the disk over) - Top row of TEXT80 is shifted by 1 pixel
{
g_pVideoAddress -= 1;
}
@ -1235,7 +1237,41 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0
//===========================================================================
void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblHires
void updateScreenDoubleHires80Simplified(long cycles6502) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen(cycles6502);
return;
}
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
uint8_t a = *MemGetAuxPtr(addr);
uint8_t m = *MemGetMainPtr(addr);
UpdateDHiResCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true, true);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
void updateScreenDoubleHires80RGB (long cycles6502 ) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
@ -1270,31 +1306,16 @@ void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblH
int width = UpdateDHiRes160Cell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += width;
}
else if (RGB_Is560Mode() || (RGB_IsMixMode() && !((a | m) & 0x80)))
else if (RGB_Is560Mode())// || (RGB_IsMixMode() && !((a | m) & 0x80)))
{
update7MonoPixels(a);
update7MonoPixels(m);
}
else if (!RGB_IsMixMode() || (RGB_IsMixMode() && (a & m & 0x80)))
else
{
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true, true);
UpdateDHiResCellRGB(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, RGB_IsMixMode(), RGB_IsMixModeInvertBit7());
g_pVideoAddress += 14;
}
else // RGB_IsMixMode() && ((a ^ m) & 0x80)
{
if (a & 0x80) // RGB color, then monochrome
{
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, true ,false);
g_pVideoAddress += 7;
update7MonoPixels(m);
}
else // monochrome, then RGB color
{
update7MonoPixels(a);
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, false, true);
g_pVideoAddress += 7;
}
}
}
}
updateVideoScannerHorzEOLSimple();
@ -1514,6 +1535,36 @@ static void updateScreenSingleHires40Duochrome(long cycles6502)
}
}
//===========================================================================
static void updateScreenSingleHires40RGB(long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen(cycles6502);
return;
}
for (; cycles6502 > 0; --cycles6502)
{
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
UpdateHiResRGBCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
//===========================================================================
void updateScreenSingleHires40 (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1670,7 +1721,7 @@ void updateScreenText40RGB(long cycles6502)
if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
c ^= g_nTextFlashMask;
UpdateText40ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, c);
UpdateText40ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, c, m);
g_pVideoAddress += 14;
}
@ -1712,7 +1763,8 @@ void updateScreenText80 (long cycles6502)
aux ^= g_nTextFlashMask;
uint16_t bits = (main << 7) | (aux & 0x7f);
if (g_eVideoType != VT_COLOR_MONITOR_RGB) // No extra 14M bit needed for VT_COLOR_MONITOR_RGB
if ((g_eVideoType != VT_COLOR_MONITOR_RGB) // No extra 14M bit needed for VT_COLOR_MONITOR_RGB
&& (g_eVideoType != VT_COLOR_VIDEOCARD_RGB))
bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR
updatePixels( bits );
@ -1754,9 +1806,9 @@ void updateScreenText80RGB(long cycles6502)
if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) // Flash only if mousetext not active
aux ^= g_nTextFlashMask;
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)aux);
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)aux, a);
g_pVideoAddress += 7;
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)main);
UpdateText80ColorCell(g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress, (uint8_t)main, m);
g_pVideoAddress += 7;
uint16_t bits = (main << 7) | (aux & 0x7f);
@ -1846,7 +1898,7 @@ uint16_t NTSC_VideoGetScannerAddressForDebugger(void)
//===========================================================================
void NTSC_SetVideoTextMode( int cols )
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
{
if (cols == 40)
g_pFuncUpdateTextScreen = updateScreenText40RGB;
@ -1921,7 +1973,7 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
}
// Video7_SL7 extra RGB modes handling
if (g_eVideoType == VT_COLOR_MONITOR_RGB
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB
&& RGB_GetVideocard() == RGB_Videocard_e::Video7_SL7
// Exclude following modes (fallback through regular NTSC rendering with RGB text)
// VF_DHIRES = 1 -> regular Apple IIe modes
@ -1976,12 +2028,12 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (uVideoModeFlags & VF_80COL)
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenText80RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenText80;
}
else if (g_eVideoType == VT_COLOR_MONITOR_RGB)
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenText40RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenText40;
@ -1994,6 +2046,8 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80Simplified;
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80;
}
@ -2006,6 +2060,8 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40Simplified;
else if (g_eVideoType == VT_COLOR_VIDEOCARD_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40RGB;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40;
}
@ -2016,7 +2072,7 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (uVideoModeFlags & VF_80COL)
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if ((g_eVideoType == VT_COLOR_MONITOR_RGB) || (g_eVideoType == VT_COLOR_VIDEOCARD_RGB))
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80;
@ -2028,7 +2084,7 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
}
else
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
if ((g_eVideoType == VT_COLOR_MONITOR_RGB) || (g_eVideoType == VT_COLOR_VIDEOCARD_RGB))
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40;
@ -2105,6 +2161,7 @@ void NTSC_SetVideoStyle(void)
goto _mono;
case VT_COLOR_MONITOR_RGB:
case VT_COLOR_VIDEOCARD_RGB:
case VT_MONO_WHITE:
r = 0xFF;
g = 0xFF;

View file

@ -117,7 +117,9 @@ const BYTE DoubleHiresPalIndex[16] = {
#define SETRGBCOLOR(r,g,b) {b,g,r,0xFF}
static RGBQUAD PalIndex2RGB[] =
static RGBQUAD* g_pPaletteRGB;
static RGBQUAD PaletteRGB_NTSC[] =
{
// hires
#if DO_OPT_PALETTE
@ -128,6 +130,7 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
#else
// Note: this is a placeholder. This palette is overwritten by VideoInitializeOriginal()
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
SETRGBCOLOR(/*BLUE, */ 0x0D,0xA1,0xFF), // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
@ -145,6 +148,7 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*HGR_PINK, */ 0xFF,0x32,0xB5), // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5
// lores & dhires
// Note: this is a placeholder. This palette is overwritten by VideoInitializeOriginal()
SETRGBCOLOR(/*BLACK,*/ 0x00,0x00,0x00), // 0
SETRGBCOLOR(/*DEEP_RED,*/ 0x9D,0x09,0x66), // 0xD0,0x00,0x30 -> Linards Tweaked 0x9D,0x09,0x66
SETRGBCOLOR(/*DARK_BLUE,*/ 0x2A,0x2A,0xE5), // 4 // Linards Tweaked 0x00,0x00,0x80 -> 0x2A,0x2A,0xE5
@ -163,6 +167,44 @@ static RGBQUAD PalIndex2RGB[] =
SETRGBCOLOR(/*WHITE,*/ 0xFF,0xFF,0xFF),
};
// Le Chat Mauve Feline's palette
// extracted from a white-balanced RGB video capture
static RGBQUAD PaletteRGB_Feline[] =
{
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00),
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
SETRGBCOLOR(/*BLUE, */ 0x00,0x8A,0xB5),
SETRGBCOLOR(/*ORANGE, */ 0xFF,0x72,0x47),
SETRGBCOLOR(/*GREEN, */ 0x6F,0xE6,0x2C),
SETRGBCOLOR(/*MAGENTA, */ 0xAA,0x1A,0xD1),
// TV emu
SETRGBCOLOR(/*HGR_GREY1, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_GREY2, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_YELLOW,*/ 0x9E,0x9E,0x00),
SETRGBCOLOR(/*HGR_AQUA, */ 0x00,0xCD,0x4A),
SETRGBCOLOR(/*HGR_PURPLE,*/ 0x61,0x61,0xFF),
SETRGBCOLOR(/*HGR_PINK, */ 0xFF,0x32,0xB5),
// Feline
SETRGBCOLOR(/*BLACK,*/ 0x00,0x00,0x00),
SETRGBCOLOR(/*DEEP_RED,*/ 0xAC,0x12,0x4C),
SETRGBCOLOR(/*DARK_BLUE,*/ 0x00,0x07,0x83),
SETRGBCOLOR(/*MAGENTA,*/ 0xAA,0x1A,0xD1),
SETRGBCOLOR(/*DARK_GREEN,*/ 0x00,0x83,0x2F),
SETRGBCOLOR(/*DARK_GRAY,*/ 0x9F,0x97,0x7E),
SETRGBCOLOR(/*BLUE,*/ 0x00,0x8A,0xB5),
SETRGBCOLOR(/*LIGHT_BLUE,*/ 0x9F,0x9E,0xFF),
SETRGBCOLOR(/*BROWN,*/ 0x7A,0x5F,0x00),
SETRGBCOLOR(/*ORANGE,*/ 0xFF,0x72,0x47),
SETRGBCOLOR(/*LIGHT_GRAY,*/ 0x78,0x68,0x7F),
SETRGBCOLOR(/*PINK,*/ 0xFF,0x7A,0xCF),
SETRGBCOLOR(/*GREEN,*/ 0x6F,0xE6,0x2C),
SETRGBCOLOR(/*YELLOW,*/ 0xFF,0xF6,0x7B),
SETRGBCOLOR(/*AQUA,*/ 0x6C,0xEE,0xB2),
SETRGBCOLOR(/*WHITE,*/ 0xFF,0xFF,0xFF),
};
//===========================================================================
static void V_CreateLookup_DoubleHires ()
@ -501,8 +543,8 @@ static void CopyMixedSource(int x, int y, int sx, int sy, bgra_t *pVideoAddress)
}
else
{
_ASSERT( colormixbuffer[h] < (sizeof(PalIndex2RGB)/sizeof(PalIndex2RGB[0])) );
const RGBQUAD& rRGB = PalIndex2RGB[ colormixbuffer[h] ];
_ASSERT( colormixbuffer[h] < (sizeof(PaletteRGB_NTSC)/sizeof(PaletteRGB_NTSC[0])) );
const RGBQUAD& rRGB = g_pPaletteRGB[ colormixbuffer[h] ];
*(pDst+nBytes) = *reinterpret_cast<const UINT32 *>(&rRGB);
}
@ -533,8 +575,8 @@ static void CopySource(int w, int h, int sx, int sy, bgra_t *pVideoAddress, cons
{
for (int nBytes=0; nBytes<w; ++nBytes)
{
_ASSERT( *(pSrc+nBytes+nSrcAdjustment) < (sizeof(PalIndex2RGB)/sizeof(PalIndex2RGB[0])) );
const RGBQUAD& rRGB = PalIndex2RGB[ *(pSrc+nBytes+nSrcAdjustment) ];
_ASSERT( *(pSrc+nBytes+nSrcAdjustment) < (sizeof(PaletteRGB_NTSC)/sizeof(PaletteRGB_NTSC[0])) );
const RGBQUAD& rRGB = g_pPaletteRGB[ *(pSrc+nBytes+nSrcAdjustment) ];
*(pDst+nBytes) = *reinterpret_cast<const UINT32 *>(&rRGB);
}
}
@ -569,17 +611,17 @@ void UpdateHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
#define COLOR ((xpixel + PIXEL) & 3)
#define VALUE (dwordval >> (4 + PIXEL - COLOR))
void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool updateAux, bool updateMain)
void UpdateDHiResCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool updateAux, bool updateMain)
{
const int xpixel = x*14;
const int xpixel = x * 14;
uint8_t *pAux = MemGetAuxPtr(addr);
uint8_t *pMain = MemGetMainPtr(addr);
uint8_t* pAux = MemGetAuxPtr(addr);
uint8_t* pMain = MemGetMainPtr(addr);
BYTE byteval1 = (x > 0) ? *(pMain-1) : 0;
BYTE byteval1 = (x > 0) ? *(pMain - 1) : 0;
BYTE byteval2 = *pAux;
BYTE byteval3 = *pMain;
BYTE byteval4 = (x < 39) ? *(pAux+1) : 0;
BYTE byteval4 = (x < 39) ? *(pAux + 1) : 0;
DWORD dwordval = (byteval1 & 0x70) | ((byteval2 & 0x7F) << 7) |
((byteval3 & 0x7F) << 14) | ((byteval4 & 0x07) << 21);
@ -587,7 +629,7 @@ void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool
#define PIXEL 0
if (updateAux)
{
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE), pVideoAddress);
CopySource(7, 2, SRCOFFS_DHIRES + 10 * HIBYTE(VALUE) + COLOR, LOBYTE(VALUE), pVideoAddress);
pVideoAddress += 7;
}
#undef PIXEL
@ -595,11 +637,323 @@ void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool
#define PIXEL 7
if (updateMain)
{
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE), pVideoAddress);
CopySource(7, 2, SRCOFFS_DHIRES + 10 * HIBYTE(VALUE) + COLOR, LOBYTE(VALUE), pVideoAddress);
}
#undef PIXEL
}
//===========================================================================
// RGB videocards HGR
void UpdateHiResRGBCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress)
{
const int xpixel = x * 14;
int xoffset = x & 1; // offset to start of the 2 bytes
addr -= xoffset;
uint8_t* pMain = MemGetMainPtr(addr);
// We need all 28 bits because each pixel needs a three bit evaluation
uint8_t byteval1 = (x < 2 ? 0 : *(pMain - 1));
uint8_t byteval2 = *pMain;
uint8_t byteval3 = *(pMain + 1);
uint8_t byteval4 = (x >= 38 ? 0 : *(pMain + 2));
// all 28 bits chained
DWORD dwordval = (byteval1 & 0x7F) | ((byteval2 & 0x7F) << 7) | ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x7F) << 21);
// Extraction of 14 color pixels
UINT32 colors[14];
int color = 0;
DWORD dwordval_tmp = dwordval;
dwordval_tmp = dwordval_tmp >> 7;
bool offset = (byteval2 & 0x80) ? true : false;
for (int i = 0; i < 14; i++)
{
if (i == 7) offset = (byteval3 & 0x80) ? true : false;
color = dwordval_tmp & 0x3;
// Two cases because AppleWin's palette is in a strange order
if (offset)
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[1 + color]);
else
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[6 - color]);
if (i%2) dwordval_tmp >>= 2;
}
// Black and White
UINT32 bw[2];
bw[0] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[0]);
bw[1] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[1]);
DWORD mask = 0x01C0; // 00|000001 1|1000000
DWORD chck1 = 0x0140; // 00|000001 0|1000000
DWORD chck2 = 0x0080; // 00|000000 1|0000000
// HIRES render in RGB works on a pixel-basis (1-bit data in framebuffer)
// The pixel can be 'color', if it makes a 101 or 010 pattern with the two neighbour bits
// In all other cases, it's black if 0 and white if 1
// The value of 'color' is defined on a 2-bits basis
UINT32* pDst = (UINT32*)pVideoAddress;
if (xoffset)
{
// Second byte of the 14 pixels block
dwordval = dwordval >> 7;
xoffset = 7;
}
for (int i = xoffset; i < xoffset+7; i++)
{
if (((dwordval & mask) == chck1) || ((dwordval & mask) == chck2))
{
// Color pixel
*(pDst) = colors[i];
*(pDst + 1) = *(pDst);
pDst += 2;
}
else
{
// B&W pixel
*(pDst) = bw[(dwordval & chck2 ? 1 : 0)];
*(pDst + 1) = *(pDst);
pDst += 2;
}
// Next pixel
dwordval = dwordval >> 1;
}
const bool bIsHalfScanLines = IsVideoStyle(VS_HALF_SCANLINES);
// Second line
UINT32* pSrc = (UINT32*)pVideoAddress;
pDst = pSrc - GetFrameBufferWidth();
if (bIsHalfScanLines)
{
// Scanlines
std::fill(pDst, pDst + 14, 0);
}
else
{
for (int i = 0; i < 14; i++)
*(pDst + i) = *(pSrc + i);
}
}
static bool g_dhgrLastCellIsColor = true;
static int g_dhgrLastBit = 0;
void UpdateDHiResCellRGB(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool isMixMode, bool isBit7Inversed)
{
const int xpixel = x * 14;
int xoffset = x & 1; // offset to start of the 2 bytes
addr -= xoffset;
uint8_t* pAux = MemGetAuxPtr(addr);
uint8_t* pMain = MemGetMainPtr(addr);
// We need all 28 bits because one 4-bits pixel overlaps two 14-bits cells
uint8_t byteval1 = *pAux;
uint8_t byteval2 = *pMain;
uint8_t byteval3 = *(pAux + 1);
uint8_t byteval4 = *(pMain + 1);
// all 28 bits chained
DWORD dwordval = (byteval1 & 0x7F) | ((byteval2 & 0x7F) << 7) | ((byteval3 & 0x7F) << 14) | ((byteval4 & 0x7F) << 21);
// Extraction of 7 color pixels and 7x4 bits
int bits[7];
UINT32 colors[7];
int color = 0;
DWORD dwordval_tmp = dwordval;
for (int i = 0; i < 7; i++)
{
bits[i] = dwordval_tmp & 0xF;
color = ((bits[i] & 7) << 1) | ((bits[i] & 8) >> 3); // DHGR colors are rotated 1 bit to the right
colors[i] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + color]);
dwordval_tmp >>= 4;
}
UINT32 bw[2];
bw[0] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + 0]);
bw[1] = *reinterpret_cast<const UINT32*>(&g_pPaletteRGB[12 + 15]);
if (isBit7Inversed)
{
// Invert mixed mode detection
byteval1 = ~byteval1;
byteval2 = ~byteval2;
byteval3 = ~byteval3;
byteval4 = ~byteval4;
}
// RGB DHGR is quite a mess:
// Color mode is a real 140x192 RGB mode with no color fringe (ref. patent US4631692, "THE 140x192 VIDEO MODE")
// BW mode is a real 560x192 monochrome mode
// Mixed mode seems easy but has a few traps since it's based on 4-bits cells coded into 7-bits bytes:
// - Bit 7 of each byte defines the mode of the following 7 bits (BW or Color);
// - BW pixels are 1 bit wide, color pixels are usually 4 bits wide;
// - A color pixel can be less than 4 bits wide if it crosses a byte boundary and falls into a BW byte;
// - If a 4-bit cell of BW bits crosses a byte boundary and falls into a Color byte, then the last BW bit is repeated until the next color pixel starts.
//
// (Tested on Le Chat Mauve IIc adapter, which was made under patent of Video-7)
UINT32* pDst = (UINT32*)pVideoAddress;
if (xoffset == 0) // First cell
{
if ((byteval1 & 0x80) || !isMixMode)
{
// Color
// Color cell 0
*(pDst++) = colors[0];
*(pDst++) = colors[0];
*(pDst++) = colors[0];
*(pDst++) = colors[0];
// Color cell 1
*(pDst++) = colors[1];
*(pDst++) = colors[1];
*(pDst++) = colors[1];
dwordval >>= 7;
g_dhgrLastCellIsColor = true;
}
else
{
// BW
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
if ((byteval2 & 0x80) || !isMixMode)
{
// Remaining of color cell 1
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[1];
}
else
{
// Repeat last BW bit once
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 2
*(pDst++) = colors[2];
*(pDst++) = colors[2];
*(pDst++) = colors[2];
*(pDst++) = colors[2];
// Color cell 3
*(pDst++) = colors[3];
*(pDst++) = colors[3];
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
}
else // Second cell
{
dwordval >>= 14;
if ((byteval3 & 0x80) || !isMixMode)
{
// Remaining of color cell 3
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[3];
*(pDst++) = colors[3];
}
else
{
// Repeat last BW bit twice
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 4
*(pDst++) = colors[4];
*(pDst++) = colors[4];
*(pDst++) = colors[4];
*(pDst++) = colors[4];
// Color cell 5
*(pDst++) = colors[5];
dwordval >>= 7;
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
if ((byteval4 & 0x80) || !isMixMode)
{
// Remaining of color cell 5
if (g_dhgrLastCellIsColor)
{
*(pDst++) = colors[5];
*(pDst++) = colors[5];
*(pDst++) = colors[5];
}
else
{
// Repeat last BW bit three times
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
*(pDst++) = bw[g_dhgrLastBit];
}
// Color cell 6
*(pDst++) = colors[6];
*(pDst++) = colors[6];
*(pDst++) = colors[6];
*(pDst++) = colors[6];
g_dhgrLastCellIsColor = true;
}
else
{
for (int i = 0; i < 7; i++)
{
g_dhgrLastBit = dwordval & 1;
*(pDst++) = bw[g_dhgrLastBit];
dwordval >>= 1;
}
g_dhgrLastCellIsColor = false;
}
}
const bool bIsHalfScanLines = IsVideoStyle(VS_HALF_SCANLINES);
// Second line
UINT32* pSrc = (UINT32*)pVideoAddress ;
pDst = pSrc - GetFrameBufferWidth();
if (bIsHalfScanLines)
{
// Scanlines
std::fill(pDst, pDst + 14, 0);
}
else
{
for (int i = 0; i < 14; i++)
*(pDst + i) = *(pSrc + i);
}
}
#if 1
// Squash the 640 pixel image into 560 pixels
int UpdateDHiRes160Cell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
@ -708,7 +1062,7 @@ void UpdateDLoResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
//===========================================================================
// Color TEXT (some RGB cards only)
// Default BG and FG are usually defined by hardware switches, defaults to black/white
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits)
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character)
{
uint8_t foreground = g_nRegularTextFG;
uint8_t background = g_nRegularTextBG;
@ -718,12 +1072,24 @@ void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, u
foreground = val >> 4;
background = val & 0x0F;
}
else if (g_RGBVideocard == RGB_Videocard_e::Video7_SL7 && character < 0x80)
{
// in regular 40COL mode, the SL7 videocard renders inverse characters as B&W
foreground = 15;
background = 0;
}
UpdateDuochromeCell(2, 14, pVideoAddress, bits, foreground, background);
}
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits)
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character)
{
if (g_RGBVideocard == RGB_Videocard_e::Video7_SL7 && character < 0x80)
{
// in all 80COL modes, the SL7 videocard renders inverse characters as B&W
UpdateDuochromeCell(2, 7, pVideoAddress, bits, 15, 0);
}
else
UpdateDuochromeCell(2, 7, pVideoAddress, bits, g_nRegularTextFG, g_nRegularTextBG);
}
@ -755,8 +1121,8 @@ void UpdateDuochromeCell(int h, int w, bgra_t* pVideoAddress, uint8_t bits, uint
background += 12;
foreground += 12;
// get bg/fg colors
colors[0] = PalIndex2RGB[background];
colors[1] = PalIndex2RGB[foreground];
colors[0] = g_pPaletteRGB[background];
colors[1] = g_pPaletteRGB[foreground];
int nbits = bits;
int doublepixels = (w == 14); // Double pixel (HiRes or Text40)
@ -815,11 +1181,24 @@ void VideoInitializeOriginal(baseColors_t pBaseNtscColors)
// CREATE THE SOURCE IMAGE AND DRAW INTO THE SOURCE BIT BUFFER
V_CreateDIBSections();
memcpy(&PalIndex2RGB[BLACK], *pBaseNtscColors, sizeof(RGBQUAD)*kNumBaseColors);
PalIndex2RGB[HGR_BLUE] = PalIndex2RGB[BLUE];
PalIndex2RGB[HGR_ORANGE] = PalIndex2RGB[ORANGE];
PalIndex2RGB[HGR_GREEN] = PalIndex2RGB[GREEN];
PalIndex2RGB[HGR_VIOLET] = PalIndex2RGB[MAGENTA];
// Replace the default palette with true NTSC-generated colors
memcpy(&PaletteRGB_NTSC[BLACK], *pBaseNtscColors, sizeof(RGBQUAD) * kNumBaseColors);
PaletteRGB_NTSC[HGR_BLUE] = PaletteRGB_NTSC[BLUE];
PaletteRGB_NTSC[HGR_ORANGE] = PaletteRGB_NTSC[ORANGE];
PaletteRGB_NTSC[HGR_GREEN] = PaletteRGB_NTSC[GREEN];
PaletteRGB_NTSC[HGR_VIOLET] = PaletteRGB_NTSC[MAGENTA];
}
//===========================================================================
// RGB videocards may use a different palette thant the NTSC-generated one
void VideoSwitchVideocardPalette(RGB_Videocard_e videocard, VideoType_e type)
{
g_pPaletteRGB = PaletteRGB_NTSC;
if (type==VideoType_e::VT_COLOR_VIDEOCARD_RGB && videocard == RGB_Videocard_e::LeChatMauve_Feline)
{
g_pPaletteRGB = PaletteRGB_Feline;
}
}
//===========================================================================
@ -837,13 +1216,14 @@ static bool g_rgbInvertBit7 = false;
// . NB. There's a final 5th AN3 transition to set DHGR mode
void RGB_SetVideoMode(WORD address)
{
if ((address&~1) == 0x0C) // 0x0C or 0x0D? (80COL)
if ((address & ~1) == 0x0C) // 0x0C or 0x0D? (80COL)
{
g_rgbSet80COL = true;
return;
}
if ((address&~1) != 0x5E) // 0x5E or 0x5F? (DHIRES)
if ((address & ~1) != 0x5E) // 0x5E or 0x5F? (DHIRES)
return;
// Precondition before toggling AN3:
@ -853,33 +1233,37 @@ void RGB_SetVideoMode(WORD address)
// . Apple II desktop sets DHGR B&W mode with HIRES off! (GH#631)
// Maybe there is no video-mode precondition?
// . After setting 80COL on/off then need a 0x5E->0x5F toggle. So if we see a 0x5F then reset (GH#633)
if ((g_uVideoMode & VF_MIXED) || (g_rgbSet80COL && address == 0x5F))
{
g_rgbMode = 0;
g_rgbPrevAN3Addr = 0;
g_rgbSet80COL = false;
return;
}
if (address == 0x5F && g_rgbPrevAN3Addr == 0x5E) // Check for AN3 clock transition
// From Video7 patent and Le Chat Mauve manuals (under patent of Video7), no precondition is needed.
// In Prince of Persia, in the game demo, the RGB card switches to BW DHIRES after the HGR animation with Jaffar.
// It's actually the same on real hardware (tested on IIc RGB adapter).
if (address == 0x5F)
{
g_rgbFlags = (g_rgbFlags<<1) & 3;
if ((g_rgbPrevAN3Addr == 0x5E) && g_rgbSet80COL)
{
g_rgbFlags = (g_rgbFlags << 1) & 3;
g_rgbFlags |= ((g_uVideoMode & VF_80COL) ? 0 : 1); // clock in !80COL
g_rgbMode = g_rgbFlags; // latch F2,F1
}
g_rgbPrevAN3Addr = address;
g_rgbSet80COL = false;
}
g_rgbPrevAN3Addr = address;
}
bool RGB_Is140Mode(void) // Extended 80-Column Text/AppleColor Card's Mode 2
{
return g_rgbMode == 0;
// Feline falls back to this mode instead of 160
return g_rgbMode == 0 || (g_RGBVideocard == RGB_Videocard_e::LeChatMauve_Feline && g_rgbMode == 1);
}
bool RGB_Is160Mode(void) // Extended 80-Column Text/AppleColor Card: N/A
{
return g_rgbMode == 1;
// Unsupported by Feline
return g_rgbMode == 1 && (g_RGBVideocard != RGB_Videocard_e::LeChatMauve_Feline);
}
bool RGB_IsMixMode(void) // Extended 80-Column Text/AppleColor Card's Mode 3

View file

@ -10,18 +10,21 @@ enum RGB_Videocard_e
void UpdateHiResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress, bool updateAux, bool updateMain);
void UpdateDHiResCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool updateAux, bool updateMain);
void UpdateDHiResCellRGB(int x, int y, uint16_t addr, bgra_t* pVideoAddress, bool isMixMode, bool isBit7Inversed);
int UpdateDHiRes160Cell (int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits);
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits);
void UpdateText40ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character);
void UpdateText80ColorCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress, uint8_t bits, uint8_t character);
void UpdateHiResDuochromeCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress);
void UpdateDuochromeCell(int h, int w, bgra_t* pVideoAddress, uint8_t bits, uint8_t foreground, uint8_t background);
void UpdateHiResRGBCell(int x, int y, uint16_t addr, bgra_t* pVideoAddress);
const UINT kNumBaseColors = 16;
typedef bgra_t (*baseColors_t)[kNumBaseColors];
void VideoInitializeOriginal(baseColors_t pBaseNtscColors);
void VideoSwitchVideocardPalette(RGB_Videocard_e videocard, VideoType_e type);
void RGB_SetVideoMode(WORD address);
bool RGB_Is140Mode(void);

View file

@ -101,8 +101,9 @@ static LPDIRECTDRAW g_lpDD = NULL;
// NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc
TCHAR g_aVideoChoices[] =
TEXT("Monochrome (Custom)\0")
TEXT("Color (RGB Monitor)\0")
TEXT("Color (NTSC Monitor)\0")
TEXT("Color (Composite Idealized)\0") // newly added
TEXT("Color (RGB Card/Monitor)\0") // was "Color (RGB Monitor)"
TEXT("Color (Composite Monitor)\0") // was "Color (NTSC Monitor)"
TEXT("Color TV\0")
TEXT("B&W TV\0")
TEXT("Monochrome (Amber)\0")
@ -114,14 +115,15 @@ static LPDIRECTDRAW g_lpDD = NULL;
// The window title will be set to this.
const char *g_apVideoModeDesc[ NUM_VIDEO_MODES ] =
{
"Monochrome Monitor (Custom)"
, "Color (RGB Monitor)"
, "Color (NTSC/PAL Monitor)"
"Monochrome (Custom)"
, "Color (Composite Idealized)"
, "Color (RGB Card/Monitor)"
, "Color (Composite Monitor)"
, "Color TV"
, "B&W TV"
, "Amber Monitor"
, "Green Monitor"
, "White Monitor"
, "Monochrome (Amber)"
, "Monochrome (Green)"
, "Monochrome (White)"
};
// Prototypes (Private) _____________________________________________
@ -615,6 +617,7 @@ void VideoReinitialize (bool bInitVideoScannerAddress /*= true*/)
NTSC_SetVideoStyle();
NTSC_SetVideoTextMode( g_uVideoMode & VF_80COL ? 80 : 40 );
NTSC_SetVideoMode( g_uVideoMode ); // Pre-condition: g_nVideoClockHorz (derived from g_dwCyclesThisFrame)
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType());
}
//===========================================================================

View file

@ -8,6 +8,7 @@
{
VT_MONO_CUSTOM
, VT_COLOR_MONITOR_RGB // Color rendering from AppleWin 1.25 (GH#357)
, VT_COLOR_VIDEOCARD_RGB // Real RGB card rendering
, VT_COLOR_MONITOR_NTSC // NTSC or PAL
, VT_COLOR_TV
, VT_MONO_TV

View file

@ -57,8 +57,10 @@ void YamlHelper::GetNextEvent(bool bInMap /*= false*/)
{
if (!yaml_parser_parse(&m_parser, &m_newEvent))
{
//printf("Parser error %d\n", m_parser.error);
throw std::string("Parser error");
std::string error = std::string("Save-state parser error: ");
if (m_parser.problem != NULL) error += std::string(m_parser.problem);
else error += std::string("unknown");
throw error;
}
}
@ -451,7 +453,46 @@ void YamlSaveHelper::SaveBool(const char* key, bool value)
void YamlSaveHelper::SaveString(const char* key, const char* value)
{
Save("%s: %s\n", key, (value[0] != 0) ? value : "\"\"");
if (value[0] == 0)
value = "\"\"";
// libyaml supports UTF-8 and not accented ANSI characters (GH#838)
// . So convert ANSI to UTF-8, which is a 2-step process:
// 1) ANSI -> unicode
{
int size = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, value, -1, NULL, 0);
if (size == 0)
throw std::string("Unable to convert to unicode: ") + std::string(value);
if (size > m_wcStrSize)
{
delete[] m_pWcStr;
m_pWcStr = new WCHAR[size];
m_wcStrSize = size;
}
int res = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, value, -1, m_pWcStr, m_wcStrSize);
if (!res)
throw std::string("Unable to convert to unicode: ") + std::string(value);
}
// 2) unicode -> UTF-8
{
// NB. WC_ERR_INVALID_CHARS only defined when WIN_VER >= 0x600 - but stdafx.h defines it as 0x500
int size = WideCharToMultiByte(CP_UTF8, 0/*WC_ERR_INVALID_CHARS*/, m_pWcStr, -1, NULL, 0, NULL, NULL);
if (size == 0)
throw std::string("Unable to convert to UTF-8: ") + std::string(value);
if (size > m_mbStrSize)
{
delete[] m_pMbStr;
m_pMbStr = new char[size];
m_mbStrSize = size;
}
int res = WideCharToMultiByte(CP_UTF8, 0/*WC_ERR_INVALID_CHARS*/, m_pWcStr, -1, m_pMbStr, m_mbStrSize, NULL, NULL);
if (!res)
throw std::string("Unable to convert to UTF-8: ") + std::string(value);
}
Save("%s: %s\n", key, m_pMbStr);
}
void YamlSaveHelper::SaveString(const char* key, const std::string & value)

View file

@ -29,6 +29,7 @@ public:
YamlHelper(void) :
m_hFile(NULL)
{
memset(&m_parser, 0, sizeof(m_parser));
MakeAsciiToHexTable();
}
@ -171,7 +172,11 @@ class YamlSaveHelper
public:
YamlSaveHelper(std::string pathname) :
m_hFile(NULL),
m_indent(0)
m_indent(0),
m_pWcStr(NULL),
m_wcStrSize(0),
m_pMbStr(NULL),
m_mbStrSize(0)
{
m_hFile = fopen(pathname.c_str(), "wt");
@ -202,6 +207,9 @@ public:
fprintf(m_hFile, "...\n");
fclose(m_hFile);
}
delete[] m_pWcStr;
delete[] m_pMbStr;
}
void Save(const char* format, ...);
@ -270,4 +278,9 @@ private:
int m_indent;
static const UINT kMaxIndent = 50*2;
char m_szIndent[kMaxIndent];
LPWSTR m_pWcStr;
int m_wcStrSize;
LPSTR m_pMbStr;
int m_mbStrSize;
};