This commit is contained in:
tomcw 2014-12-21 16:43:58 -05:00
commit 1966bcb9a1
13 changed files with 608 additions and 233 deletions

View File

@ -1,7 +1,12 @@
/*
.1 Fixe: Symbolic Targets > 20 chars no longer overflow into register window
.8 Fixed: Showing/hiding the address and/or opcodes will show long symbolic targets without overflowing into the register info pane Bug #227
.7 Fixed: ASC #:# with string containing null byte wouldn't show rest of string
.6 Added: Print-Screen when in debugger will copy the debugger window as text
.5 Added: Print warnings about duplicate symbols when symbol tables are loaded
.4 Fixed: Check for buffer overflow in CmdSymbolsInfo() if _CmdSymbolsInfoHeader() returns a very long string
.3 Removed EXITBENCH from falsely being triggered with E.
.2 Cleaned up error message for syminfo on invalid symbol table.
.1 Fixed: Symbolic Targets > 20 chars no longer overflow into register window
2.8.0.0 Released with AppleWin 1.25
2.7.0.#

View File

@ -6,11 +6,65 @@
</head>
<body style="DIRECTION: ltr" lang="en-US">
<h2><a name="Symbols"></a>Symbols</h2>
<p>AppleWin supports loading of ACME, and Merlin Symbol Tables. The default
filename read into the Main Symbol Table is “APPLE2E.SYM”.</p>
<p>Looking up symbols is now easier.&nbsp; Can't remember an address of a symbol,
or can't remember the symbol for an address?&nbsp; The new symbol commands
makes it easy:</p>
<p>
When a programmer writes an assembly language program instead of directly referring to a memory address over and over again they use a <b>symbolic name</b> instead.
For example, instead of always directly hard-coding $C000 everywhere to read the keyboard they would instead write:
</p>
<p><font color="#00b8ff"><font face="courier"><b><pre style="background: rgb(0,0,0) 0% 50%;">
ORG $300
KEYBOARD EQU $C000
300:AD 00 C0 .1 LDA KEYBOARD
303:10 FB BPL .1
305:8D 00 04 STA $0400
306:60 RTS
</pre></b></font></font></p>
<p>
Let's try this out in the debugger. Make sure AppleWin is running. Press F2 (to reboot), then Ctrl-F2 (to break), and F7 (to enter the debugger.)
&nbsp; If you don't want to type in the following hex code, you can select it, copy it (Ctrl-C), and paste it into the Debugger console (Ctrl-V).
</p>
<p><font color="#00b8ff"><font face="Courier"><b><pre style="BACKGROUND: rgb(0,0,0) 0% 50%;">
300:AD 00 C0 10 FB 8D 00 04 60
300L
</pre></b></font></font></p>
<p>
Press F7 to exit the debugger, then type:
</p>
<p><font color="#00b8ff"><font face="Courier"><b><pre style="BACKGROUND: rgb(0,0,0) 0% 50%;">
HOME:CALL 768
</pre></b></font></font></p>
<p>
Press Enter.&nbsp; The emulated computer will wait for your to press a key and then echo it in the top left.
</p>
<p>
When debugging assembly programs since you typically don't have the source file availabe you can tell the debugger how to interpret a memory address as a variable name or symbol.
A <b>symbol</b> is the symbolic name and the address assigned to it.
</p>
<p>AppleWin supports loading of the assemblers ACME, and Merlin's symbol tables -- a collection of symbols, one per line, organized and collectively called a symbol table.
The semi-colon is a comment-till-end-of-line. The file format per line is: <b>ADDRESS SYMBOL</b></p>
<p>e.g.</p>
<p><font color="#00b8ff"><font face="courier"><b><pre style="background: rgb(0,0,0) 0% 50%;">
; IO Map
C000 KEYBOARD
</pre></b></font></font></p>
<p>
There are <b>9</b> symbol tables to help organize "modules"; each symbol table individually can be turned off/on independently.
<pre>
MAIN APPLE2E.SYM
BASIC A2_BASIC.SYM
ASM A2_ASM.SYM
User1 A2_USER1.SYM
User2 A2_USER2.SYM
Src1 A2_SRC1.SYM
Src2 A2_SRC2.SYM
DOS33 A2_DOS33.SYM
PRODOS A2_PRODOS.SYM
</pre></p>
<p>On startup the debugger reads 3 symbol tables by default: Main, Basic, User1.</p>
</p>
<p>Looking up symbols is easy.&nbsp; If you can't remember an address of a symbol,
or the reversse -- can't remember the symbol for an address -- you can use the following symbol commands:
(#### referes to either a hex address or a symbolic name)
</p>
<p><br>
<br>
</p>
@ -29,96 +83,96 @@
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM</span></b></font></font></p>
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYM</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Display
<p><i><span style="BACKGROUND: 0% 50%; ">Display
the number of symbols in the Main, User, and Source symbol tables.</span></i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYM
####</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Look-up
<p><i><span style="BACKGROUND: 0% 50%; ">Look-up
the Symbol or Address, and display which Symbol Table it is in.</span></i></p>
</td>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYMUSER
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYMUSER
LOAD</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Loads
the User Symbol Table.</span></i></p>
<p><i><span style="BACKGROUND: 0% 50%; ">Reloads
the User Symbol Table: <b>A2_USER1.SYM</b></span></i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYMUSER
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYMUSER
CLEAR</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Clears
the User Symbol Table!</span></i></p>
<p><i><span style="BACKGROUND: 0% 50%;">Clears
the User Symbol Table from RAM.</span></i></p>
</td>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYMMAIN
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYMMAIN
####</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Look-up
<p><i><span style="BACKGROUND: 0% 50%; ">Look-up
only in the Main symbol table.</span></i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYMUSER
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYMUSER
####</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Look-up
<p><i><span style="BACKGROUND: 0% 50%; ">Look-up
only in the User symbol table.</span></i></p>
</td>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYMSRC
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYMSRC
####</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Look-up
<p><i><span style="BACKGROUND: 0% 50%; ">Look-up
only in the Source symbol table.</span></i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYM
name = ####</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Add
<p><i><span style="BACKGROUND: 0% 50%; ">Add
(or update) a symbol in the User table with the new Address.</span></i></p>
</td>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">SYM
! name</span></b></font></font></p>
</td>
<td width="75%">
<p><i><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">Remove
<p><i><span style="BACKGROUND: 0% 50%; ">Remove
a symbol from the User table.</span></i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">E
<p><font color="#000000"><font face="Courier"><b><span style="BACKGROUND: 0% 50%; ">MEB
symbol ##</span></b></font></font></p>
</td>
<td width="75%">
@ -127,23 +181,7 @@ symbol ##</span></b></font></font></p>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000" face="Courier"><b>EB symbol ####</b></font></p>
</td>
<td width="75%">
<p><i>Alias for E.</i></p>
</td>
</tr>
<tr bgcolor="#999999">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b>E8 symbol ####</b></font></font></p>
</td>
<td width="75%">
<p><i>Alias for E.</i></p>
</td>
</tr>
<tr bgcolor="#cccccc">
<td width="25%">
<p><font color="#000000"><font face="Courier"><b>EW symbol ####</b></font></font></p>
<p><font color="#000000"><font face="Courier"><b>MEW symbol ####</b></font></font></p>
</td>
<td width="75%">
<p><i>Set memory (at the symbol Address) to the 16-Bit (word) Value.</i></p>
@ -211,16 +249,16 @@ symbol ##</span></b></font></font></p>
</tr>
<tr bgcolor="#000000">
<td bgcolor="#000000" width="276">
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%; ">SYM
HOME</span></b></font></font></p>
</td>
<td bgcolor="#000000" width="515">
<p><font color="#ffffff"><i>Look up the Address $<b><font color="#ffff00">FC58</font></b> (HOME).</i></font></p>
<p><font color="#ffffff"><i>Look up the Symbol Home ($<b><font color="#ffff00">FC58</font></b>).</i></font></p>
</td>
</tr>
<tr bgcolor="#000000">
<td bgcolor="#000000" width="276">
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">SYM
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%;">SYM
LIFE = 300</span></b></font></font></p>
</td>
<td bgcolor="#000000" width="515">
@ -229,7 +267,7 @@ LIFE = 300</span></b></font></font></p>
</tr>
<tr bgcolor="#000000">
<td bgcolor="#000000" width="276">
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">E
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%;">MEB
LIFE 64</span></b></font></font></p>
</td>
<td bgcolor="#000000" width="515">
@ -239,12 +277,12 @@ LIFE 64</span></b></font></font></p>
</tr>
<tr bgcolor="#000000">
<td bgcolor="#000000" width="276">
<p><font color="#00b8ff"><font face="Courier"><b><span style="BACKGROUND: rgb(0,0,0) 0% 50%; moz-background-clip: initial; moz-background-origin: initial; moz-background-inline-policy: initial">EW
<p><font color="#00b8ff"><font face="courier"><b><span style="background: rgb(0,0,0) 0% 50%; ">MEW
LIFE 3E8</span></b></font></font></p>
</td>
<td bgcolor="#000000" width="515">
<p><font color="#ffffff"><i>Set 16-Bit variable (@ $<b><font color="#ffff00">0300</font></b>)“Life”
to 1000 (decimal).</i></font></p>
to $3E8 = 1000 (decimal).</i></font></p>
</td>
</tr>
</tbody>

View File

@ -47,7 +47,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define ALLOW_INPUT_LOWERCASE 1
// See /docs/Debugger_Changelog.txt for full details
const int DEBUGGER_VERSION = MAKE_VERSION(2,8,0,1);
const int DEBUGGER_VERSION = MAKE_VERSION(2,8,0,8);
// Public _________________________________________________________________________________________
@ -4640,7 +4640,7 @@ Update_t CmdMemorySave (int nArgs)
#endif
char g_aTextScreen[ 24*82 + 1 ]; // (80 column + CR + LF) * 24 rows + NULL
char g_aTextScreen[ DEBUG_VIRTUAL_TEXT_HEIGHT * (DEBUG_VIRTUAL_TEXT_WIDTH + 4) ]; // (80 column + CR + LF) * 24 rows + NULL
int g_nTextScreen = 0;
/*
@ -4691,16 +4691,52 @@ int g_nTextScreen = 0;
23 17 0001_0111 -> $7D0 0111 1101 0000
*/
// Convert ctrl characters to displayable
// Note: FormatCharTxtCtrl() and RemapChar()
static char RemapChar(const char c)
{
if ( c < 0x20 )
return c + '@'; // Remap INVERSE control character to NORMAL
else if ( c == 0x7F )
return ' '; // Remap checkboard (DEL) to space
return ' '; // Remap checkboard (DEL) to space
return c;
}
size_t Util_GetDebuggerText( char* &pText_ )
{
char *pBeg = &g_aTextScreen[0];
char *pEnd = &g_aTextScreen[0];
g_nTextScreen = 0;
memset( pBeg, 0, sizeof( g_aTextScreen ) );
memset( g_aDebuggerVirtualTextScreen, 0, sizeof( g_aDebuggerVirtualTextScreen ) );
DebugDisplay(1);
for( int y = 0; y < DEBUG_VIRTUAL_TEXT_HEIGHT; y++ )
{
for( int x = 0; x < DEBUG_VIRTUAL_TEXT_WIDTH; x++ )
{
char c = g_aDebuggerVirtualTextScreen[y][x];
if( (c < 0x20) || (c >= 0x7F) )
c = ' '; // convert null to spaces to keep everything non-proptional
*pEnd++ = c;
}
#ifdef _WIN32
*pEnd++ = 0x0D; // CR // Windows inserts extra char
#endif
*pEnd++ = 0x0A; // LF // OSX, Linux
}
*pEnd = 0;
g_nTextScreen = pEnd - pBeg;
pText_ = pBeg;
return g_nTextScreen;
}
size_t Util_GetTextScreen ( char* &pText_ )
{
WORD nAddressStart = 0;

View File

@ -537,7 +537,7 @@ int _6502_GetOpmodeOpbyte ( const int nBaseAddress, int & iOpmode_, int & nOpby
*/
//iOpcode_ = NUM_OPCODES; // Don't have valid opcodes ... we have data !
// iOpcode_ = (int)( pData ); // HACK: pass pData back to caller ...
iOpcode_ = 0xEA; // OP_NOP
iOpcode_ = OPCODE_NOP;
}
#if _DEBUG

View File

@ -372,7 +372,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// DEPRECATED -- Probably should be removed in a future version
{TEXT("BENCH") , CmdBenchmarkStart , CMD_BENCHMARK },
{TEXT("EXITBENCH") , CmdBenchmarkStop , CMD_BENCHMARK },
{TEXT("EXITBENCH") , NULL , CMD_BENCHMARK }, // 2.8.03 was incorrectly alias with 'E' Bug #246. // CmdBenchmarkStop
{TEXT("MDB") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this??
// {TEXT("MEMORY") , CmdMemoryMiniDumpHex , CMD_MEM_MINI_DUMP_HEX_1 }, // MemoryDumpByte // Did anyone actually use this??
};

View File

@ -270,7 +270,7 @@ bool ConsoleBufferPush ( const char * pText )
{
while (g_nConsoleBuffer >= CONSOLE_BUFFER_HEIGHT)
{
ConsoleBufferToDisplay();
ConsoleBufferToDisplay();
}
conchar_t c;
@ -292,7 +292,7 @@ bool ConsoleBufferPush ( const char * pText )
else
{
g_nConsoleBuffer++;
}
}
pSrc++;
pDst = & g_aConsoleBuffer[ g_nConsoleBuffer ][ 0 ];
}

View File

@ -38,7 +38,7 @@
CONSOLE_COLOR_W, // 7 White
CONSOLE_COLOR_O, // 8 Orange
CONSOLE_COLOR_k, // 9 Grey
CONSOLE_COLOR_b, // : Lite Blue
CONSOLE_COLOR_b, // : Light Blue
NUM_CONSOLE_COLORS
};
extern COLORREF g_anConsoleColor[ NUM_CONSOLE_COLORS ];
@ -62,7 +62,7 @@
#define CHC_USAGE "`3"
#define CHC_CATEGORY "`6"
#define CHC_COMMAND "`2" // Green
#define CHC_KEY "`1"
#define CHC_KEY "`1" // Red
#define CHC_ARG_MAND "`7" // < >
#define CHC_ARG_OPT "`4" // [ ]
#define CHC_ARG_SEP "`9" // | grey
@ -70,10 +70,12 @@
#define CHC_NUM_HEX "`3"
#define CHC_SYMBOL "`2" // Symbols
#define CHC_ADDRESS "`8" // Hex Address
#define CHC_ERROR "`1"
#define CHC_WARNING "`5"
#define CHC_STRING "`6"
#define CHC_ERROR "`1" // Red
#define CHC_WARNING "`5" // Purple
#define CHC_INFO "`3" // Yellow
#define CHC_STRING "`6" //
#define CHC_EXAMPLE "`:"
#define CHC_PATH "`:" // Light Blue
#else
#define CHC_DEFAULT ""
#define CHC_USAGE ""
@ -184,6 +186,27 @@
return g;
}
// Return the string length without the markup
inline int ConsoleColor_StringLength( const char *pText )
{
const char *pSrc = pText;
/* */ int nLen = 0;
if( pText )
{
while( *pSrc )
{
if( ConsoleColor_IsCharMeta( *pSrc ) )
pSrc++;
else
nLen++;
pSrc++;
}
}
return nLen;
}
// Globals __________________________________________________________________
// Buffer

View File

@ -61,6 +61,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// #define DISPLAY_BREAKPOINT_TITLE 1
// #define DISPLAY_WATCH_TITLE 1
// Public _________________________________________________________________________________________
// Font
@ -68,6 +69,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Private ________________________________________________________________________________________
char g_aDebuggerVirtualTextScreen[ DEBUG_VIRTUAL_TEXT_HEIGHT ][ DEBUG_VIRTUAL_TEXT_WIDTH ];
// HACK HACK HACK
//g_nDisasmWinHeight
@ -150,7 +152,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
const int DISPLAY_STACK_COLUMN = INFO_COL_1;
const int DISPLAY_TARGETS_COLUMN = INFO_COL_1;
const int DISPLAY_ZEROPAGE_COLUMN = INFO_COL_1;
const int DISPLAY_SOFTSWITCH_COLUMN = INFO_COL_1 - (CONSOLE_FONT_WIDTH/2) + 1;;
const int DISPLAY_SOFTSWITCH_COLUMN = INFO_COL_1 - (CONSOLE_FONT_WIDTH/2) + 1; // 1/2 char width padding around soft switches
// Horizontal Column (pixels) of BPs, Watches & Mem
const int INFO_COL_2 = (62 * 7); // nFontWidth
@ -214,6 +216,11 @@ static char ColorizeSpecialChar( char * sText, BYTE nData, const MemoryView_e iV
void DrawWindowBottom ( Update_t bUpdate, int iWindow );
char* FormatCharCopy( char *pDst, const char *pSrc, const int nLen );
char FormatCharTxtAsci( const BYTE b, bool * pWasAsci_ = NULL );
char FormatCharTxtCtrl( const BYTE b, bool * pWasCtrl_ = NULL );
char FormatCharTxtHigh( const BYTE b, bool *pWasHi_ = NULL );
char FormatChar4Font ( const BYTE b, bool *pWasHi_, bool *pWasLo_ );
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_6n77.asp
enum WinROP4_e
@ -617,6 +624,27 @@ void PrintGlyph( const int x, const int y, const char glyph )
int xSrc = (glyph & 0x0F) * CONSOLE_FONT_GRID_X;
int ySrc = (glyph >> 4) * CONSOLE_FONT_GRID_Y;
// BUG #239 - (Debugger) Save debugger "text screen" to clipboard / file
// if( g_bDebuggerVirtualTextCapture )
//
{
#if _DEBUG
if ((x < 0) || (y < 0))
MessageBox( g_hFrameWindow, "X or Y out of bounds!", "PrintGlyph()", MB_OK );
#endif
int col = x / CONSOLE_FONT_WIDTH ;
int row = y / CONSOLE_FONT_HEIGHT;
// if( !g_bDebuggerCopyInfoPane )
// if( col < 50
if (x > DISPLAY_DISASM_RIGHT) // INFO_COL_2 // DISPLAY_CPU_INFO_LEFT_COLUMN
col++;
if ((col < DEBUG_VIRTUAL_TEXT_WIDTH)
&& (row < DEBUG_VIRTUAL_TEXT_HEIGHT))
g_aDebuggerVirtualTextScreen[ row ][ col ] = glyph;
}
#if !DEBUG_FONT_NO_BACKGROUND_CHAR
// Background color
if (g_hConsoleBrushBG)
@ -817,6 +845,15 @@ int PrintTextCursorY ( const char * pText, RECT & rRect )
return nChars;
}
//===========================================================================
char* FormatCharCopy( char *pDst, const char *pSrc, const int nLen )
{
for( int i = 0; i < nLen; i++ )
*pDst++ = FormatCharTxtCtrl( *pSrc++ );
return pDst;
}
//===========================================================================
char FormatCharTxtAsci ( const BYTE b, bool * pWasAsci_ )
{
@ -834,6 +871,7 @@ char FormatCharTxtAsci ( const BYTE b, bool * pWasAsci_ )
return c;
}
// Note: FormatCharTxtCtrl() and RemapChar()
//===========================================================================
char FormatCharTxtCtrl ( const BYTE b, bool * pWasCtrl_ )
{
@ -1663,8 +1701,7 @@ const char *pSrc = 0;
len = (MAX_IMMEDIATE_LEN - 3); // ellipsis = true
// DISPLAY: text_longer_18...
for( int i = 0; i < len; i++ )
*pDst++ = (*pSrc++) & 0x7F;
FormatCharCopy( pDst, pSrc, len ); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly
if( nDisplayLen > len ) // ellipsis
{
@ -1674,8 +1711,7 @@ const char *pSrc = 0;
}
} else { // DISPLAY: "max_18_char"
*pDst++ = '"';
for( int i = 0; i < len; i++ )
*pDst++ = (*pSrc++) & 0x7F;
pDst = FormatCharCopy( pDst, pSrc, len ); // BUG: #251 v2.8.0.7: ASC #:# with null byte doesn't mark up properly
*pDst++ = '"';
}
@ -2043,7 +2079,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
char *pTarget = line.sTarget;
int nLen = strlen( pTarget );
if (*pTarget == '$')
if (*pTarget == '$') // BUG? if ASC #:# starts with '$' ? // && (iOpcode != OPCODE_NOP)
{
pTarget++;
if (! bCursorLine)
@ -2079,7 +2115,14 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
// SYM COPY.FAC.TO.ARG.ROUNDED = EB63
// If opcodes aren't showing then length can be longer!
// FormatOpcodeBytes() uses 3 chars/MAX_OPCODES. i.e. "## "
int nMaxLen = g_bConfigDisasmOpcodesView ? MAX_TARGET_LEN : MAX_TARGET_LEN + (MAX_OPCODES*3);
int nMaxLen = MAX_TARGET_LEN;
// 2.8.0.8: Bug #227: AppleSoft symbol: COPY.FAC.TO.ARG.ROUNDED overflows into registers
if ( !g_bConfigDisasmAddressView )
nMaxLen += 4;
if ( !g_bConfigDisasmOpcodesView )
nMaxLen += (MAX_OPCODES*3);
if( nLen >= nMaxLen )
{
#if _DEBUG
@ -2088,6 +2131,7 @@ WORD DrawDisassemblyLine ( int iLine, const WORD nBaseAddress )
pTarget[ nMaxLen ] = 0;
}
// TODO: FIXME: 2.8.0.7: Allow ctrl characters to show as inverse; i.e. ASC 400:40F
PrintTextCursorX( pTarget, linerect );
// PrintTextCursorX( " ", linerect );

View File

@ -96,3 +96,12 @@
extern HDC GetDebuggerMemDC(void);
extern void ReleaseDebuggerMemDC(void);
extern void StretchBltMemToFrameDC(void);
enum DebugVirtualTextScreen_e
{
DEBUG_VIRTUAL_TEXT_WIDTH = 80,
DEBUG_VIRTUAL_TEXT_HEIGHT = 43
};
extern char g_aDebuggerVirtualTextScreen[ DEBUG_VIRTUAL_TEXT_HEIGHT ][ DEBUG_VIRTUAL_TEXT_WIDTH ];
extern size_t Util_GetDebuggerText( char* &pText_ ); // Same API as Util_GetTextScreen()

View File

@ -74,7 +74,54 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Utils _ ________________________________________________________________________________________
void _CmdSymbolsInfoHeader( int iTable, char * pText, int nDisplaySize = 0 );
void _CmdSymbolsInfoHeader( int iTable, char * pText, int nDisplaySize = 0 );
void _PrintCurrentPath();
Update_t _PrintSymbolInvalidTable();
// Private ________________________________________________________________________________________
//===========================================================================
void _PrintCurrentPath()
{
ConsoleDisplayError( g_sProgramDir );
}
Update_t _PrintSymbolInvalidTable()
{
char sText[ CONSOLE_WIDTH * 2 ];
char sTemp[ CONSOLE_WIDTH * 2 ];
// TODO: display the user specified file name
ConsoleBufferPush( "Invalid symbol table." );
sprintf( sText, "Only %s%d%s symbol tables are supported:"
, CHC_NUM_DEC, NUM_SYMBOL_TABLES
, CHC_DEFAULT
);
ConsolePrint( sText );
// Similar to _CmdSymbolsInfoHeader()
sText[0] = 0;
for( int iTable = 0; iTable < NUM_SYMBOL_TABLES; iTable++ )
{
sprintf( sTemp, "%s%s%s%c " // %s"
, CHC_USAGE, g_aSymbolTableNames[ iTable ]
, CHC_ARG_SEP
, (iTable != (NUM_SYMBOL_TABLES-1))
? ','
: '.'
);
strcat( sText, sTemp );
}
// return ConsoleDisplayError( sText );
ConsolePrint( sText );
return ConsoleUpdate();
}
// Public _________________________________________________________________________________________
//===========================================================================
@ -238,24 +285,7 @@ void _CmdSymbolsInfoHeader( int iTable, char * pText, int nDisplaySize /* = 0 */
bool bActive = (g_bDisplaySymbolTables & (1 << iTable)) ? true : false;
int nSymbols = nDisplaySize ? nDisplaySize : g_aSymbols[ iTable ].size();
// Long Desc: `MAIN`: `1000 `symbols`, `on`
// full
#if 0
sprintf( pText, " %s%s%s: %s# %s%d %ssymbols%s, (%s%s%s)%s"
// , CHC_SYMBOL, g_aSymbolTableNames[ iTable ]
, CHC_STRING, g_aSymbolTableNames[ iTable ]
, CHC_ARG_SEP
CHC_DEFAULT
, CHC_NUM_DEC, nSymbols
, CHC_DEFAULT, CHC_ARG_SEP,
, CHC_STRING,
, CHC_ARG_SEP, CHC_DEFAULT
);
#endif
// sprintf( pText, " %s: %s%d%s"
// Short Desc: `MAIN`: `1000`
// // 2.6.2.19 Color for name of symbol table: _CmdPrintSymbol() "SYM HOME" _CmdSymbolsInfoHeader "SYM"
// CHC_STRING and CHC_NUM_DEC are both cyan, using CHC_USAGE instead of CHC_STRING
sprintf( pText, "%s%s%s:%s%d " // %s"
@ -269,11 +299,14 @@ void _CmdSymbolsInfoHeader( int iTable, char * pText, int nDisplaySize /* = 0 */
//===========================================================================
Update_t CmdSymbolsInfo (int nArgs)
{
char sText[ CONSOLE_WIDTH * 4 ] = " ";
const char sIndent[] = " ";
char sText[ CONSOLE_WIDTH * 4 ] = "";
char sTemp[ CONSOLE_WIDTH * 2 ] = "";
int bDisplaySymbolTables = 0;
strcpy( sText, sIndent ); // Indent new line
if (! nArgs)
{
// default to all tables
@ -284,11 +317,7 @@ Update_t CmdSymbolsInfo (int nArgs)
int iWhichTable = GetSymbolTableFromCommand();
if ((iWhichTable < 0) || (iWhichTable >= NUM_SYMBOL_TABLES))
{
sprintf( sText, "Only %s%d%s symbol tables supported!"
, CHC_NUM_DEC, NUM_SYMBOL_TABLES
, CHC_DEFAULT
);
return ConsoleDisplayError( sText );
return _PrintSymbolInvalidTable();
}
bDisplaySymbolTables = (1 << iWhichTable);
@ -299,9 +328,20 @@ Update_t CmdSymbolsInfo (int nArgs)
int bTable = 1;
int iTable = 0;
for( ; bTable <= bDisplaySymbolTables; iTable++, bTable <<= 1 ) {
if( bDisplaySymbolTables & bTable ) {
for( ; bTable <= bDisplaySymbolTables; iTable++, bTable <<= 1 )
{
if( bDisplaySymbolTables & bTable )
{
_CmdSymbolsInfoHeader( iTable, sTemp ); // 15 chars per table
// 2.8.0.4 BUGFIX: Check for buffer overflow and wrap text
int nLen = ConsoleColor_StringLength( sTemp );
int nDst = ConsoleColor_StringLength( sText );
if((nDst + nLen) > CONSOLE_WIDTH )
{
ConsolePrint( sText );
strcpy( sText, sIndent ); // Indent new line
}
strcat( sText, sTemp );
}
}
@ -514,17 +554,15 @@ Update_t _CmdSymbolsListTables (int nArgs, int bSymbolTables )
}
void Print_Current_Path()
{
ConsoleDisplayError( g_sProgramDir );
}
//===========================================================================
int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, int nSymbolOffset )
int ParseSymbolTable( TCHAR *pPathFileName, SymbolTable_Index_e eSymbolTableWrite, int nSymbolOffset )
{
char sText[ CONSOLE_WIDTH * 3 ];
bool bFileDisplayed = false;
int nSymbolsLoaded = 0;
if (! pFileName)
if (! pPathFileName)
return nSymbolsLoaded;
//#if _UNICODE
@ -538,12 +576,13 @@ int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, i
sprintf( sFormat1, "%%x %%%ds", MAX_SYMBOLS_LEN ); // i.e. "%x %13s"
sprintf( sFormat2, "%%%ds %%x", MAX_SYMBOLS_LEN ); // i.e. "%13s %x"
FILE *hFile = fopen(pFileName,"rt");
FILE *hFile = fopen( pPathFileName, "rt" );
if( !hFile && g_bSymbolsDisplayMissingFile )
{
// TODO: print filename! Bug #242 Help file (.chm) description for "Symbols" #242
ConsoleDisplayError( "Symbol File not found:" );
Print_Current_Path();
_PrintCurrentPath();
nSymbolsLoaded = -1; // HACK: ERROR: FILE NOT EXIST
}
@ -599,14 +638,72 @@ int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, i
if( (nAddress > _6502_MEM_END) || (sName[0] == 0) )
continue;
#if 1 // _DEBUG
// If updating symbol, print duplicate symbols
WORD nAddressPrev;
int iTable;
bool bExists = FindAddressFromSymbol( sName, &nAddressPrev, &iTable );
// 2.8.0.5 Bug #244 (Debugger) Duplicate symbols for identical memory addresses in APPLE2E.SYM
const char *pSymbolPrev = FindSymbolFromAddress( (WORD)nAddress, &iTable ); // don't care which table it is in
if( pSymbolPrev )
{
if( !bFileDisplayed )
{
bFileDisplayed = true;
// TODO: Must check for buffer overflow !
sprintf( sText, "%s%s"
, CHC_PATH
, pPathFileName
);
ConsolePrint( sText );
}
sprintf( sText, " %sWarning: %s%-16s %saliases %s$%s%04X %s%-12s%s (%s%s%s)"
, CHC_WARNING
, CHC_SYMBOL
, sName
, CHC_INFO
, CHC_ARG_SEP
, CHC_ADDRESS
, nAddress
, CHC_SYMBOL
, pSymbolPrev
, CHC_DEFAULT
, CHC_STRING
, g_aSymbolTableNames[ iTable ]
, CHC_DEFAULT
);
ConsolePrint( sText );
ConsoleUpdate(); // Flush buffered output so we don't ask the user to pause
/*
sprintf( sText, " %sWarning: %sAddress already has symbol Name%s (%s%s%s): %s%s"
, CHC_WARNING
, CHC_INFO
, CHC_ARG_SEP
, CHC_STRING
, g_aSymbolTableNames[ iTable ]
, CHC_DEFAULT
, CHC_SYMBOL
, pSymbolPrev
);
ConsolePrint( sText );
sprintf( sText, " %s$%s%04X %s%-31s%s"
, CHC_ARG_SEP
, CHC_ADDRESS
, nAddress
, CHC_SYMBOL
, sName
, CHC_DEFAULT
);
ConsolePrint( sText );
*/
}
bool bExists = FindAddressFromSymbol( sName, &nAddressPrev, &iTable );
if( bExists )
{
char sText[ CONSOLE_WIDTH * 3 ];
if( !bDupSymbolHeader )
{
bDupSymbolHeader = true;
@ -616,7 +713,7 @@ int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, i
, CHC_STRING
, g_aSymbolTableNames[ iTable ]
, CHC_DEFAULT
, pFileName
, pPathFileName
);
ConsolePrint( sText );
}
@ -631,9 +728,11 @@ int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, i
);
ConsolePrint( sText );
}
#endif
// else // It is not a bug to have duplicate addresses by different names
g_aSymbols[ eSymbolTableWrite ] [ (WORD) nAddress ] = sName;
nSymbolsLoaded++;
nSymbolsLoaded++; // TODO: FIXME: BUG: This is the total symbols read, not added
}
fclose(hFile);
}
@ -641,7 +740,6 @@ int ParseSymbolTable( TCHAR *pFileName, SymbolTable_Index_e eSymbolTableWrite, i
return nSymbolsLoaded;
}
//===========================================================================
Update_t CmdSymbolsLoad (int nArgs)
{
@ -651,26 +749,14 @@ Update_t CmdSymbolsLoad (int nArgs)
int iSymbolTable = GetSymbolTableFromCommand();
if ((iSymbolTable < 0) || (iSymbolTable >= NUM_SYMBOL_TABLES))
{
wsprintf( sFileName, "Only %d symbol tables supported!", NUM_SYMBOL_TABLES );
return ConsoleDisplayError( sFileName );
return _PrintSymbolInvalidTable();
}
int nSymbols = 0;
// Debugger will call us with 0 args on startup as a way to pre-load symbol tables
if (! nArgs)
{
// Default to main table
// if (g_iCommand == CMD_SYMBOLS_MAIN)
// _tcscat(sFileName, g_sFileNameSymbolsMain );
// else
// {
// if (! _tcslen( g_sFileNameSymbolsUser ))
// {
// return ConsoleDisplayError(TEXT("No user symbol file to reload."));
// }
// // load user symbols
// _tcscat( sFileName, g_sFileNameSymbolsUser );
// }
_tcscat(sFileName, g_sFileNameSymbols[ iSymbolTable ]);
nSymbols = ParseSymbolTable( sFileName, (SymbolTable_Index_e) iSymbolTable );
}

View File

@ -1050,6 +1050,8 @@ const DisasmData_t* pDisasmData; // If != NULL then bytes are marked up as data
OPCODE_JMP_A = 0x4C, // Absolute
OPCODE_JMP_NA = 0x6C, // Indirect Absolute
OPCODE_JMP_IAX = 0x7C, // Indexed (Absolute Indirect, X)
OPCODE_NOP = 0xEA, // No operation
};
// Note: "int" causes overflow when profiling for any amount of time.

View File

@ -1102,7 +1102,13 @@ LRESULT CALLBACK FrameWndProc (
if (wparam == VK_SNAPSHOT_TEXT) // ( lparam & MOD_CONTROL )
{
char *pText;
size_t nSize = Util_GetTextScreen( pText );
size_t nSize = 0;
// if viewing the debugger, get the last virtual debugger screen
if ((g_nAppMode == MODE_DEBUG) && !g_bDebuggerViewingAppleOutput)
nSize = Util_GetDebuggerText( pText );
else
nSize = Util_GetTextScreen( pText );
Util_CopyTextToClipboard( nSize, pText );
}
break;

View File

@ -43,31 +43,37 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define HALF_PIXEL_SOLID 1
#define HALF_PIXEL_BLEED 0
#define COLORS_TWEAKED 1
#define HALF_DIM_SUPPORT 0
/* reference: technote tn-iigs-063 "Master Color Values"
/*
Reference: Technote TN-IIGS-063 "Master Color Values"
Note:The IIGS colors do NOT map correctly to _accurate_ //e colors.
Color Color Register LR HR DHR Master Color R,G,B
Name Value # # # Value
----------------------------------------------------
Black 0 0 0,4 0 $0000 (0,0,0) -> (00,00,00) Windows
(Magenta) Deep Red 1 1 1 $0D03 (D,0,3) -> (D0,00,30) Custom
Dark Blue 2 2 8 $0009 (0,0,9) -> (00,00,80) Windows
(Violet) Purple 3 3 2 9 $0D2D (D,2,D) -> (FF,00,FF) Windows
Dark Green 4 4 4 $0072 (0,7,2) -> (00,80,00) Windows
(Gray 1) Dark Gray 5 5 5 $0555 (5,5,5) -> (80,80,80) Windows
(Blue) Medium Blue 6 6 6 C $022F (2,2,F) -> (00,00,FF) Windows
(Cyan) Light Blue 7 7 D $06AF (6,A,F) -> (60,A0,FF) Custom
Brown 8 8 2 $0850 (8,5,0) -> (80,50,00) Custom
Orange 9 9 5 3 $0F60 (F,6,0) -> (FF,80,00) Custom (modified to match better with the other Hi-Res Colors)
(Gray 2) Light Gray A A A $0AAA (A,A,A) -> (C0,C0,C0) Windows
Pink B B B $0F98 (F,9,8) -> (FF,90,80) Custom
(Green) Light Green C C 1 6 $01D0 (1,D,0) -> (00,FF,00) Windows
Yellow D D 7 $0FF0 (F,F,0) -> (FF,FF,00) Windows
(Aqua) Aquamarine E E E $04F9 (4,F,9) -> (40,FF,90) Custom
White F F 3,7 F $0FFF (F,F,F) -> (FF,FF,FF) Windows
Color LO HI DHR Master Color R,G,B HGR
Name # # # Value Bytes
-----------------------------------------------------------------------
Black 0 0,4 0 $0000 (0,0,0) -> (00,00,00) Windows
(Magenta) Deep Red 1 1 $0D03 (D,0,3) -> (D0,00,30) Custom
Dark Blue 2 8 $0009 (0,0,9) -> (00,00,80) Windows
(Violet) Purple 3 2 9 $0D2D (D,2,D) -> (FF,00,FF) Windows 55 2A
Dark Green 4 4 $0072 (0,7,2) -> (00,80,00) Windows
(Gray 1) Dark Gray 5 5 $0555 (5,5,5) -> (80,80,80) Windows
(Blue) Medium Blue 6 6 C $022F (2,2,F) -> (00,00,FF) Windows D5 AA
(Cyan) Light Blue 7 D $06AF (6,A,F) -> (60,A0,FF) Custom
Brown 8 2 $0850 (8,5,0) -> (80,50,00) Custom
Orange 9 5 3 $0F60 (F,6,0) -> (FF,80,00) Custom AA D5 (modified to match better with the other Hi-Res Colors)
(Gray 2) Light Gray A A $0AAA (A,A,A) -> (C0,C0,C0) Windows
Pink B B $0F98 (F,9,8) -> (FF,90,80) Custom
(Green) Light Green C 1 6 $01D0 (1,D,0) -> (00,FF,00) Windows 2A 55
Yellow D 7 $0FF0 (F,F,0) -> (FF,FF,00) Windows
(Aqua) Aquamarine E E $04F9 (4,F,9) -> (40,FF,90) Custom
White F 3,7 F $0FFF (F,F,F) -> (FF,FF,FF) Windows
LR: Lo-Res HR: Hi-Res DHR: Double Hi-Res */
Legend:
LO: Lo-Res
HI: Hi-Res
DHR: Double Hi-Res
*/
#define FLASH_80_COL 1 // Bug #7238
@ -100,10 +106,10 @@ enum Color_Palette_Index_e
// CUSTOM HGR COLORS (don't change order) - For tv emulation HGR Video Mode
, HGR_BLACK
, HGR_WHITE
, HGR_BLUE // HCOLOR=6 BLUE , $81
, HGR_RED // HCOLOR=5 ORANGE , $82
, HGR_GREEN // HCOLOR=1 GREEN , $01
, HGR_MAGENTA // HCOLOR=2 MAGENTA, $02
, HGR_BLUE // HCOLOR=6 BLUE , 3000: 81 00 D5 AA
, HGR_ORANGE // HCOLOR=5 ORANGE , 2C00: 82 00 AA D5
, HGR_GREEN // HCOLOR=1 GREEN , 2400: 02 00 2A 55
, HGR_VIOLET // HCOLOR=2 VIOLET , 2800: 01 00 55 2A
, HGR_GREY1
, HGR_GREY2
, HGR_YELLOW
@ -147,30 +153,26 @@ enum Color_Palette_Index_e
// __ Map HGR color index to Palette index
enum ColorMapping
{
CM_Magenta
CM_Violet
, CM_Blue
, CM_Green
, CM_Orange
, CM_Black
, CM_White
, CM_Black // Used
, CM_White // Used
, NUM_COLOR_MAPPING
};
const BYTE HiresToPalIndex[ NUM_COLOR_MAPPING ] =
{
HGR_MAGENTA
HGR_VIOLET
, HGR_BLUE
, HGR_GREEN
, HGR_RED
, HGR_ORANGE
, HGR_BLACK
, HGR_WHITE
};
const BYTE LoresResColors[16] = {
// BLACK, DEEP_RED, DARK_BLUE, MAGENTA,
// DARK_GREEN,DARK_GRAY,BLUE, LIGHT_BLUE,
// BROWN, ORANGE, LIGHT_GRAY,PINK,
// GREEN, YELLOW, AQUA, WHITE
BLACK, DEEP_RED, DARK_BLUE, MAGENTA,
DARK_GREEN,DARK_GRAY,BLUE, LIGHT_BLUE,
BROWN, ORANGE, LIGHT_GRAY,PINK,
@ -179,10 +181,6 @@ const BYTE LoresResColors[16] = {
const BYTE DoubleHiresPalIndex[16] = {
// BLACK, DARK_BLUE, DARK_GREEN,BLUE,
// BROWN, LIGHT_GRAY,GREEN, AQUA,
// DEEP_RED,MAGENTA, DARK_GRAY, LIGHT_BLUE,
// ORANGE, PINK, YELLOW, WHITE
BLACK, DARK_BLUE, DARK_GREEN,BLUE,
BROWN, LIGHT_GRAY, GREEN, AQUA,
DEEP_RED,MAGENTA, DARK_GRAY, LIGHT_BLUE,
@ -330,7 +328,7 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
void V_CreateLookup_DoubleHires ();
void V_CreateLookup_Hires (); // Old "Full-Pixel" support only: STANDARD, TEXT_OPTIMIZED, TVEMU
void V_CreateLookup_HiResHalfPixel_Authentic (); // New "Half_Pixel" support: STANDARD, TEXT_OPTIMIZED
void V_CreateLookup_HiresHalfShiftFull ();
void V_CreateLookup_HiresHalfShiftDim();
void V_CreateLookup_Lores ();
void V_CreateLookup_Text (HDC dc);
// Monochrome Full-Pixel Support
@ -537,10 +535,10 @@ void V_CreateIdentityPalette ()
g_hPalette = (HPALETTE)0;
SETFRAMECOLOR(BLACK, 0x00,0x00,0x00); // 0
SETFRAMECOLOR(DARK_RED, 0x80,0x00,0x00); // 1 // used by TV
SETFRAMECOLOR(DARK_GREEN, 0x00,0x80,0x00); // 2
SETFRAMECOLOR(DARK_RED, 0x80,0x00,0x00); // 1 // not used
SETFRAMECOLOR(DARK_GREEN, 0x00,0x80,0x00); // 2 // not used
SETFRAMECOLOR(DARK_YELLOW, 0x80,0x80,0x00); // 3
SETFRAMECOLOR(DARK_BLUE, 0x00,0x00,0x80); // 4
SETFRAMECOLOR(DARK_BLUE, 0x00,0x00,0x80); // 4 // not used
SETFRAMECOLOR(DARK_MAGENTA,0x80,0x00,0x80); // 5
SETFRAMECOLOR(DARK_CYAN, 0x00,0x80,0x80); // 6
SETFRAMECOLOR(LIGHT_GRAY, 0xC0,0xC0,0xC0); // 7 // GR: COLOR=10
@ -548,10 +546,9 @@ void V_CreateIdentityPalette ()
SETFRAMECOLOR(SKY_BLUE, 0xA6,0xCA,0xF0); // 9 // not used
// SET FRAME BUFFER TABLE ENTRIES TO CUSTOM COLORS
#if COLORS_TWEAKED
SETFRAMECOLOR(DARK_RED, 0x9D,0x09,0x66); // 1 // Linards Tweaked
SETFRAMECOLOR(DARK_GREEN, 0x00,0x76,0x1A); // 2 // Linards Tweaked
SETFRAMECOLOR(DARK_BLUE, 0x2A,0x2A,0xE5); // 4 // Linards Tweaked
// SETFRAMECOLOR(DARK_RED, 0x9D,0x09,0x66); // 1 // Linards Tweaked 0x80,0x00,0x00 -> 0x9D,0x09,0x66
// SETFRAMECOLOR(DARK_GREEN, 0x00,0x76,0x1A); // 2 // Linards Tweaked 0x00,0x80,0x00 -> 0x00,0x76,0x1A
// SETFRAMECOLOR(DARK_BLUE, 0x2A,0x2A,0xE5); // 4 // Linards Tweaked 0x00,0x00,0x80 -> 0x2A,0x2A,0xE5
SETFRAMECOLOR(DEEP_RED, 0x9D,0x09,0x66); // 0xD0,0x00,0x30 -> Linards Tweaked 0x9D,0x09,0x66
SETFRAMECOLOR(LIGHT_BLUE,0xAA,0xAA,0xFF); // 0x60,0xA0,0xFF -> Linards Tweaked 0xAA,0xAA,0xFF
@ -562,37 +559,18 @@ void V_CreateIdentityPalette ()
SETFRAMECOLOR(HGR_BLACK, 0x00,0x00,0x00); // For TV emulation HGR Video Mode
SETFRAMECOLOR(HGR_WHITE, 0xFF,0xFF,0xFE); // BUG: PALETTE COLLAPSE! NOT white!? Win32 collapses the palette if you have duplicate colors!
SETFRAMECOLOR(HGR_BLUE, 0x0D,0xA1,0xFF); // 0x00,0x80,0xFF -> Linards Tweaked 0x0D,0xA1,0xFF
SETFRAMECOLOR(HGR_RED, 0xF2,0x5E,0x00); // 0xF0,0x50,0x00 -> Linards Tweaked 0xF2,0x5E,0x00
SETFRAMECOLOR(HGR_GREEN, 0x38,0xCB,0x00); // 0x20,0xC0,0x00 -> Linards Tweaked 0x38,0xCB,0x00
SETFRAMECOLOR(HGR_MAGENTA,0xC7,0x34,0xFF); // 0xA0,0x00,0xFF -> Linards Tweaked 0xC7,0x34,0xFF
// 20 207 253 = 0x14 0xCF 0xFD
SETFRAMECOLOR(HGR_BLUE, 24, 115, 229); // HCOLOR=6 BLUE 3000: 81 00 D5 AA // 0x00,0x80,0xFF -> Linards Tweaked 0x0D,0xA1,0xFF
SETFRAMECOLOR(HGR_ORANGE, 247, 64, 30); // HCOLOR=5 ORANGE 2C00: 82 00 AA D5 // 0xF0,0x50,0x00 -> Linards Tweaked 0xF2,0x5E,0x00
SETFRAMECOLOR(HGR_GREEN, 27, 211, 79); // HCOLOR=1 GREEN 2400: 02 00 2A 55 // 0x20,0xC0,0x00 -> Linards Tweaked 0x38,0xCB,0x00
SETFRAMECOLOR(HGR_VIOLET, 227, 20, 255); // HCOLOR=2 VIOLET 2800: 01 00 55 2A // 0xA0,0x00,0xFF -> Linards Tweaked 0xC7,0x34,0xFF
SETFRAMECOLOR(HGR_GREY1, 0x80,0x80,0x80);
SETFRAMECOLOR(HGR_GREY2, 0x80,0x80,0x80);
SETFRAMECOLOR(HGR_YELLOW, 0x9E,0x9E,0x00); // 0xD0,0xB0,0x10 -> 0x9E,0x9E,0x00
SETFRAMECOLOR(HGR_AQUA, 0x00,0xCD,0x4A); // 0x20,0xB0,0xB0 -> 0x00,0xCD,0x4A
SETFRAMECOLOR(HGR_PURPLE, 0x61,0x61,0xFF); // 0x60,0x50,0xE0 -> 0x61,0x61,0xFF
SETFRAMECOLOR(HGR_PINK, 0xFF,0x32,0xB5); // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5
#else
SETFRAMECOLOR(DEEP_RED, 0xD0,0x00,0x30); // 0xD0,0x00,0x30
SETFRAMECOLOR(LIGHT_BLUE,0x60,0xA0,0xFF); // 0x60,0xA0,0xFF
SETFRAMECOLOR(BROWN, 0x80,0x50,0x00); // 0x80,0x50,0x00
SETFRAMECOLOR(ORANGE, 0xFF,0x80,0x00); // 0xFF,0x80,0x00
SETFRAMECOLOR(PINK, 0xFF,0x90,0x80); // 0xFF,0x90,0x80
SETFRAMECOLOR(AQUA, 0x40,0xFF,0x90); // 0x40,0xFF,0x90
SETFRAMECOLOR(HGR_BLACK, 0x00,0x00,0x00); // For TV emulation HGR Video Mode
SETFRAMECOLOR(HGR_WHITE, 0xFF,0xFF,0xFE); // BUG: PALETTE COLLAPSE! NOT white!? Win32 collapses the palette if you have duplicate colors!
SETFRAMECOLOR(HGR_BLUE, 0x00,0x80,0xFF); // 0x00,0x80,0xFF
SETFRAMECOLOR(HGR_RED, 0xF0,0x50,0x00); // 0xF0,0x50,0x00
SETFRAMECOLOR(HGR_GREEN, 0x20,0xC0,0x00); // 0x20,0xC0,0x00
SETFRAMECOLOR(HGR_MAGENTA,0xA0,0x00,0xFF); // 0xA0,0x00,0xFF
SETFRAMECOLOR(HGR_GREY1, 0x80,0x80,0x80);
SETFRAMECOLOR(HGR_GREY2, 0x80,0x80,0x80);
SETFRAMECOLOR(HGR_YELLOW, 0xD0,0xB0,0x10); // 0xD0,0xB0,0x10
SETFRAMECOLOR(HGR_AQUA, 0x20,0xB0,0xB0); // 0x20,0xB0,0xB0
SETFRAMECOLOR(HGR_PURPLE, 0x60,0x50,0xE0); // 0x60,0x50,0xE0
SETFRAMECOLOR(HGR_PINK, 0xD0,0x40,0xA0); // 0xD0,0x40,0xA0
#endif
SETFRAMECOLOR( MONOCHROME_CUSTOM
, GetRValue(monochrome)
@ -613,29 +591,16 @@ void V_CreateIdentityPalette ()
// Windows is collapsing the palette!!!
//SETFRAMECOLOR( MONOCHROME_WHITE , 0xFE,0xFE,0xFE); // Used for Monochrome Hi-Res graphics not text!
#if COLORS_TWEAKED
SETFRAMECOLOR(CREAM, 0xFF,0xFB,0xF0); // F6
SETFRAMECOLOR(MEDIUM_GRAY, 0xA0,0xA0,0xA4); // F7
SETFRAMECOLOR(DARK_GRAY, 0x80,0x80,0x80); // F8
SETFRAMECOLOR(RED, 0xFF,0x00,0x00); // F9
SETFRAMECOLOR(GREEN, 0x38,0xCB,0x00); // FA Linards Tweaked
SETFRAMECOLOR(YELLOW, 0xD5,0xD5,0x1A); // FB Linards Tweaked
SETFRAMECOLOR(BLUE, 0x0D,0xA1,0xFF); // FC Linards Tweaked
SETFRAMECOLOR(MAGENTA, 0xC7,0x34,0xFF); // FD Linards Tweaked
SETFRAMECOLOR(GREEN, 0x38,0xCB,0x00); // FA Linards Tweaked 0x00,0xFF,0x00 -> 0x38,0xCB,0x00
SETFRAMECOLOR(YELLOW, 0xD5,0xD5,0x1A); // FB Linards Tweaked 0xFF,0xFF,0x00 -> 0xD5,0xD5,0x1A
SETFRAMECOLOR(BLUE, 0x0D,0xA1,0xFF); // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
SETFRAMECOLOR(MAGENTA, 0xC7,0x34,0xFF); // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF
SETFRAMECOLOR(CYAN, 0x00,0xFF,0xFF); // FE
SETFRAMECOLOR(WHITE, 0xFF,0xFF,0xFF); // FF
#else
SETFRAMECOLOR(CREAM, 0xFF,0xFB,0xF0); // F6
SETFRAMECOLOR(MEDIUM_GRAY, 0xA0,0xA0,0xA4); // F7
SETFRAMECOLOR(DARK_GRAY, 0x80,0x80,0x80); // F8
SETFRAMECOLOR(RED, 0xFF,0x00,0x00); // F9
SETFRAMECOLOR(GREEN, 0x00,0xFF,0x00); // FA
SETFRAMECOLOR(YELLOW, 0xFF,0xFF,0x00); // FB
SETFRAMECOLOR(BLUE, 0x00,0x00,0xFF); // FC
SETFRAMECOLOR(MAGENTA, 0xFF,0x00,0xFF); // FD
SETFRAMECOLOR(CYAN, 0x00,0xFF,0xFF); // FE
SETFRAMECOLOR(WHITE, 0xFF,0xFF,0xFF); // FF
#endif
// IF WE ARE IN A PALETTIZED VIDEO MODE, CREATE AN IDENTITY PALETTE
HWND window = GetDesktopWindow();
@ -827,7 +792,11 @@ void V_CreateDIBSections ()
if ( g_eVideoType == VT_COLOR_TVEMU )
V_CreateLookup_Hires();
else
#if HALF_DIM_SUPPORT
V_CreateLookup_HiresHalfShiftDim();
#else
V_CreateLookup_HiResHalfPixel_Authentic();
#endif
V_CreateLookup_DoubleHires();
}
else
@ -906,7 +875,7 @@ void V_CreateLookup_Hires ()
int iMonochrome = GetMonochromeIndex();
// BYTE colorval[6] = {MAGENTA,BLUE,GREEN,ORANGE,BLACK,WHITE};
// BYTE colorval[6] = {HGR_MAGENTA,HGR_BLUE,HGR_GREEN,HGR_RED,HGR_BLACK,HGR_WHITE};
// BYTE colorval[6] = {HGR_VIOLET,HGR_BLUE,HGR_GREEN,HGR_ORANGE,HGR_BLACK,HGR_WHITE};
for (int iColumn = 0; iColumn < 16; iColumn++)
{
int coloffs = iColumn << 5;
@ -1125,8 +1094,8 @@ Legend:
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_WHITE );
} else { // Optimization: odd = (iPixel & 1); if (!odd) case is same as if(odd) !!! // Reference: Gumball - Gumball Machine
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_RED ); // left half of orange pixels
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_RED );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_ORANGE ); // left half of orange pixels
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_ORANGE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_BLUE ); // right half of blue pixels 4, 11, 18, ...
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_BLUE );
}
@ -1169,16 +1138,16 @@ Legend:
} else {
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_RED ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_RED );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE );
}
#else
if ((g_eVideoType == VT_COLOR_STANDARD) || ( !aPixels[3] ))
{ // "Text optimized" IF this pixel on, and adjacent right pixel off, then colorize first half-pixel of this byte
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_RED ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_RED );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE );
}
#endif // HALF_PIXEL_BLEED
}
@ -1230,6 +1199,163 @@ Legend:
}
}
//===========================================================================
void V_CreateLookup_HiresHalfShiftDim ()
{
// BYTE colorval[6] = {HGR_MAGENTA,HGR_BLUE,HGR_GREEN,HGR_RED,HGR_BLACK,HGR_WHITE};
for (int iColumn = 0; iColumn < 16; iColumn++)
{
int coloffs = iColumn << 5;
for (unsigned iByte = 0; iByte < 256; iByte++)
{
int aPixels[11];
aPixels[ 0] = iColumn & 4;
aPixels[ 1] = iColumn & 8;
aPixels[ 9] = iColumn & 1;
aPixels[10] = iColumn & 2;
int nBitMask = 1;
int iPixel;
for (iPixel = 2; iPixel < 9; iPixel++) {
aPixels[iPixel] = ((iByte & nBitMask) != 0);
nBitMask <<= 1;
}
int hibit = ((iByte & 0x80) != 0);
int x = 0;
int y = iByte << 1;
while (x < 28)
{
int adj = (x >= 14) << 1;
int odd = (x >= 14);
for (iPixel = 2; iPixel < 9; iPixel++)
{
int color = CM_Black;
if (aPixels[iPixel])
{
if (aPixels[iPixel-1] || aPixels[iPixel+1])
{
color = CM_White;
}
else
color = ((odd ^ (iPixel&1)) << 1) | hibit;
}
else if (aPixels[iPixel-1] && aPixels[iPixel+1])
{
/*
activate for fringe reduction on white hgr text -
drawback: loss of color mix patterns in HGR mode.
select g_eVideoType by index exclusion
*/
if (
(g_eVideoType == VT_COLOR_STANDARD) // Fill in colors in between white pixels
|| (g_eVideoType == VT_COLOR_TVEMU) // Fill in colors in between white pixels (Post Processing will mix/merge colors)
|| !(aPixels[iPixel-2] && aPixels[iPixel+2]) ) // VT_COLOR_TEXT_OPTIMIZED -> Don't fill in colors in between white
color = ((odd ^ !(iPixel&1)) << 1) | hibit;
}
/*
Address Binary -> Displayed
2000:01 0---0001 -> 1 0 0 0 column 1
2400:81 1---0001 -> 1 0 0 0 half-pixel shift right
2800:02 1---0010 -> 0 1 0 0 column 2
2000:02 column 2
2400:82 half-pixel shift right
2800:04 column 3
2000:03 0---0011 -> 1 1 0 0 column 1 & 2
2400:83 1---0011 -> 1 1 0 0 half-pixel shift right
2800:06 1---0110 -> 0 1 1 0 column 2 & 3
@reference: see Beagle Bro's Disk: "Silicon Salad", File: DOUBLE HI-RES
Fortunately double-hires is supported via pixel doubling, so we can do half-pixel shifts ;-)
*/
switch (color)
{
case CM_Violet:
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_VIOLET ); // HiresToPalIndex
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_MAGENTA ); // HiresDimmedIndex
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_VIOLET ); // HiresToPalIndex
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_MAGENTA ); // HiresDimmedIndex
break;
case CM_Blue :
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , DARK_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, DARK_BLUE );
// Prevent column gaps
if (hibit)
{
if (iPixel <= 2)
{
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , DARK_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, DARK_BLUE );
}
}
break;
case CM_Green :
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_GREEN );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_GREEN );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_GREEN );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_GREEN );
break;
case CM_Orange:
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_ORANGE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , BROWN ); // DARK_RED is a bit "too" red
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_ORANGE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, BROWN ); // DARK_RED is a bit "too" red
// Prevent column gaps
if (hibit)
{
if (iPixel <= 2)
{
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , BROWN ); // DARK_RED is a bit "too" red
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, BROWN ); // DARK_RED is a bit "too" red
}
}
break;
case CM_Black :
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_BLACK );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLACK );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_BLACK );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLACK );
break;
case CM_White :
// Don't dither / half-shift white, since DROL cutscene looks bad :(
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look
// Prevent column gaps
if (hibit)
{
if (iPixel <= 2)
{
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE ); // LIGHT_GRAY HGR_GREY1
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY HGR_GREY1
}
}
break;
default:
break;
}
x += 2;
}
}
}
}
}
//===========================================================================
void V_CreateLookup_MonoHiResHalfPixel_Real ()
{
@ -1282,7 +1408,7 @@ void V_CreateLookup_MonoHiResHalfPixel_Real ()
SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y ,iMono); // first 7 HGR_BLUE
SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y+1,iMono); // first 7
SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y ,iMono); // second 7 HGR_RED
SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y ,iMono); // second 7 HGR_ORANGE
SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y+1,iMono); // second 7
}
}
@ -1601,11 +1727,11 @@ bool UpdateDHiResCell (int x, int y, int xpixel, int ypixel, int offset)
Color Reference Tests:
2000:D5 AA D5 AA D5 AA // blue blue blue
2400:AA D5 2A 55 55 2A //+ red green magenta
// //= grey aqua purple
2400:AA D5 2A 55 55 2A //+ red green violet
// //= grey aqua violet
2C00:AA D5 AA D5 2A 55 // red red green
3000:2A 55 55 2A 55 2A //+ green magenta magenta
3000:2A 55 55 2A 55 2A //+ green violet violet
// //= yellow pink grey
*/
@ -1618,17 +1744,17 @@ BYTE MixColors(BYTE c1, BYTE c2)
if (c1 == c2)
return c1;
if (COMBINATION(c1,c2,HGR_BLUE,HGR_RED))
if (COMBINATION(c1,c2,HGR_BLUE,HGR_ORANGE))
return HGR_GREY1;
else if (COMBINATION(c1,c2,HGR_GREEN,HGR_MAGENTA))
else if (COMBINATION(c1,c2,HGR_GREEN,HGR_VIOLET))
return HGR_GREY2;
else if (COMBINATION(c1,c2,HGR_RED,HGR_GREEN))
else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_GREEN))
return HGR_YELLOW;
else if (COMBINATION(c1,c2,HGR_BLUE,HGR_GREEN))
return HGR_AQUA;
else if (COMBINATION(c1,c2,HGR_BLUE,HGR_MAGENTA))
else if (COMBINATION(c1,c2,HGR_BLUE,HGR_VIOLET))
return HGR_PURPLE;
else if (COMBINATION(c1,c2,HGR_RED,HGR_MAGENTA))
else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_VIOLET))
return HGR_PINK;
else
return MONOCHROME_CUSTOM; // visible failure indicator