Files
RP412/MUNGA_L4/L4VB16.cpp
T
CydandClaude Opus 5 bfd5fa163e EXIT GAME on the console screen
,noframe takes the title bar away, and with it the only way out of the
game. The console screen now offers its own, bottom left: half width and
diagonally opposite LAUNCH GAME, because it is the one button on that
screen you cannot undo and it should not sit next to the one everybody
is aiming for.

It goes through the same door as closing the window - fe.closed, so
RPL4FrontEnd_Run returns False and the race loop breaks - rather than
opening a second shutdown path.

Two things had to move for it to make sense.

The saved placement now loads in RPL4.CPP, right after the main window
is shown, instead of only when SVGA16 builds the cockpit. That was not
until a mission started, so the console screen came up at the default
rect with its title bar still on and the window only jumped to the saved
placement once a race began - which, for a flag whose whole purpose is
to take the title bar off, meant it did nothing on the screen you land
on. RPL4.CPP now owns the main window's registration outright and
SVGA16's branches only reload; the reload after CockpitShellProc goes on
still matters, since its WM_SIZE is what re-fits the canvas.

That in turn made the exploded view's position-only registration
incoherent - the startup load had already applied the size - so the
game window is simply position and size everywhere now. The earlier
reasoning that its exploded size IS the -res render size does not hold:
the back buffer stretches to the window in either view, exactly as it
does for the cockpit.

WM_EXITSIZEMOVE moves from the cockpit subclass to RPL4.CPP's own
WndProc, which the subclass chains to anyway. In its old home it only
existed once a cockpit had been built, so dragging the window on the
console screen - the obvious moment to put it where you want it - saved
nothing. There is also a save on the way out of WinMain, for a session
that never started a race and so never ran SVGA16's teardown save.

Verified: on a bare-framed window the console screen comes up at the
saved 1280x760 with client == window rect, EXIT GAME ends the process
with code 0, and a screenshot shows it clear of the column content. A
console-only session dragged to 333,222 900x640 wrote that on the drag,
kept it through the exit, and came back to exactly it on relaunch -
without a race anywhere in the round trip. The noframe and cockpit
round trips still pass unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:01:16 -05:00

6948 lines
168 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4vb16.h"
#include "l4mfdview.h"
#include "l4plasmascreen.h"
#include "../munga/gaugrend.h"
#include "L4VIDEO.h"
#include "DXUtils.h"
#if defined(TRACE_SCREEN_COPY)
static BitTrace Screen_Copy("Screen Copy");
#define SET_SCREEN_COPY() Screen_Copy.Set()
#define CLEAR_SCREEN_COPY() Screen_Copy.Clear()
#else
#define SET_SCREEN_COPY()
#define CLEAR_SCREEN_COPY()
#endif
#define BLIT_STATISTICS
#if defined(BLIT_STATISTICS)
static int
dirtyPixelCount,
transferPixelCount,
overflowPixelCount;
#endif
//#define DEBUG
#if defined(DEBUG)
static Logical
printFlag=True;
# define Diag_on printFlag=True
# define Diag_off printFlag=False
# define Diag_Tell(stuff) if(printFlag){std::cout << stuff;}
#else
# define Diag_on
# define Diag_off
# define Diag_Tell(n)
#endif
//STUBBED: VIDEO RB 1/15/07
//extern "C" void
// SVGASetMode(
// int mode,
// LWord pageFlipFcnpointer
// );
//
//extern "C" void
// SVGASetPage(
// int page
// );
//
//extern "C" int
// SVGATransfer32(
// int dest_offset,
// Word *source_pointer,
// LWord changed_bits
// );
//
//extern "C" int
// SVGATransfer32x(
// int dest_offset,
// Word *source_pointer,
// LWord changed_bits
// );
//
//extern "C" void
// SVGASetSplitterClock(
// Logical state
// );
//
//extern "C" void
// SVGAZeroPalette(
// Word DAC_port
// );
//
//extern "C" void
// SVGAWriteFullPalette(
// Byte *firstColorByte,
// Word DAC_port
// );
//
//extern "C" void
// SVGAReadFullPalette(
// Byte *firstColorByte,
// Word DAC_port
// );
//
//extern "C" void
// SVGAWritePaletteMask(
// Word DAC_port,
// Byte new_mask
// );
//
//extern "C" void
// SVGAFunkyVideo(
// Logical on_off
// );
void SVGA16::BuildWindows(unsigned int width, unsigned int height, bool windowed, int *secondaryIndex, int *aux1Index, int *aux2Index)
{
NUMGAUGEWINDOWS = 0;
if (secondaryIndex != NULL)
{
NUMGAUGEWINDOWS++;
}
if (aux1Index != NULL)
{
NUMGAUGEWINDOWS++;
}
if (aux2Index != NULL)
{
NUMGAUGEWINDOWS++;
}
if (NUMGAUGEWINDOWS == 0)
{
return;
}
gaugeWindows = new HWND[NUMGAUGEWINDOWS];
mDevice = new LPDIRECT3DDEVICE9[NUMGAUGEWINDOWS];
mVertBuffers = new LPDIRECT3DVERTEXBUFFER9[NUMGAUGEWINDOWS];
mSurfaces = new LPDIRECT3DTEXTURE9[NUMGAUGEWINDOWS * 2];
mLockFlags = new DWORD[NUMGAUGEWINDOWS];
mPresentParams = new D3DPRESENT_PARAMETERS[NUMGAUGEWINDOWS];
mSurfaceRects = new RECT[NUMGAUGEWINDOWS];
for (int j=0; j < NUMGAUGEWINDOWS; j++)
{
int desiredAdapter = -1;
int adapterIndex = j;
if (secondaryIndex != NULL && adapterIndex >= 0)
{
desiredAdapter = *secondaryIndex;
adapterIndex--;
}
if (aux1Index != NULL && adapterIndex >= 0)
{
desiredAdapter = *aux1Index;
adapterIndex--;
}
if (aux2Index != NULL && adapterIndex >= 0)
{
desiredAdapter = *aux2Index;
adapterIndex--;
}
if (adapterIndex >= 0 || desiredAdapter < 0)
{
break;
}
RECT r;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(gD3D->GetAdapterMonitor(desiredAdapter),&info);
r = info.rcMonitor;
mSurfaceRects[j].left = r.left;
mSurfaceRects[j].top = r.top;
mSurfaceRects[j].right = r.left + ((j==0 || aux2Index != NULL)?width:width*2);
mSurfaceRects[j].bottom = r.top + height;
RECT surfaceWindowRect = mSurfaceRects[j];
AdjustWindowRectEx(&surfaceWindowRect, WS_BORDER, false, 0);
gaugeWindows[j] = CreateWindowEx(0, L"MainWndClass", L"RPL4", WS_BORDER, surfaceWindowRect.left, surfaceWindowRect.top, surfaceWindowRect.right-surfaceWindowRect.left, surfaceWindowRect.bottom-surfaceWindowRect.top, (HWND)NULL, (HMENU)NULL, L4Application::GetAppInstance(), (LPVOID)NULL);
if (gaugeWindows[j])
{
// In split-view mode the packed windows are only kept as D3D
// device targets; the split windows are what the player sees.
if (!splitViews)
{
ShowWindow(gaugeWindows[j], SW_SHOW);
}
memset(&mPresentParams[j], 0, sizeof(D3DPRESENT_PARAMETERS));
mPresentParams[j].BackBufferCount = 1;
mPresentParams[j].SwapEffect = D3DSWAPEFFECT_DISCARD;
mPresentParams[j].hDeviceWindow = gaugeWindows[j];
mPresentParams[j].Flags = 0;
mPresentParams[j].FullScreen_RefreshRateInHz = (windowed)?D3DPRESENT_RATE_DEFAULT:60;
mPresentParams[j].PresentationInterval = D3DPRESENT_RATE_DEFAULT;
mPresentParams[j].BackBufferFormat = D3DFMT_R5G6B5;
//pp.EnableAutoDepthStencil = TRUE;
//pp.AutoDepthStencilFormat = D3DFMT_D24X8;
mPresentParams[j].Windowed = windowed;
if (!windowed)
{
mPresentParams[j].BackBufferWidth = mSurfaceRects[j].right - mSurfaceRects[j].left;
mPresentParams[j].BackBufferHeight = mSurfaceRects[j].bottom - mSurfaceRects[j].top;
}
HRESULT hr = gD3D->CreateDevice(desiredAdapter, D3DDEVTYPE_HAL, ghWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &mPresentParams[j], &mDevice[j]);
if (FAILED(hr))
{
DEBUG_STREAM<<"Couldn't create Direct3D device!"<<std::endl<<std::flush;
PostQuitMessage(1);
}
D3DCAPS9 caps;
DWORD usage = 0;
D3DPOOL pool = D3DPOOL_MANAGED;
hr = mDevice[j]->GetDeviceCaps(&caps);
mLockFlags[j] = 0;
hr = mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_SYSTEMMEM, &mSurfaces[j * 2], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create dynamic texture for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
hr = mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[j * 2 + 1], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create dynamic texture for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
hr = mDevice[j]->CreateVertexBuffer(sizeof(float) * 6 * 4, NULL, D3DFVF_XYZRHW | D3DFVF_TEX1, D3DPOOL_MANAGED, &mVertBuffers[j], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create vertex buffer for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
float *buffer;
hr = mVertBuffers[j]->Lock(0, 0, (void**)&buffer, 0);
buffer[0] = 0.0f; // top left, x
buffer[1] = 0.0f; // y
buffer[2] = 0.0f; // z
buffer[3] = 1.0f; // rhw
buffer[4] = 0.0f; // u
buffer[5] = 0.0f; // v
buffer[6] = mSurfaceRects[j].right - mSurfaceRects[j].left; // top right, x
buffer[7] = 0.0f; // y
buffer[8] = 0.0f; // z
buffer[9] = 1.0f; // rhw
buffer[10] = 1.0f; // u
buffer[11] = 0.0f; // v
buffer[12] = mSurfaceRects[j].right - mSurfaceRects[j].left; // bottom right, x
buffer[13] = height; // y
buffer[14] = 0.0f; // z
buffer[15] = 1.0f; // rhw
buffer[16] = 1.0f; // u
buffer[17] = 1.0f, // v
buffer[18] = 0.0f; // bottom left, x
buffer[19] = height; // y
buffer[20] = 0.0f; // z
buffer[21] = 1.0f; // rhw
buffer[22] = 0.0f; // u
buffer[23] = 1.0f; // v
hr = mVertBuffers[j]->Unlock();
mDevice[j]->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
mDevice[j]->SetStreamSource(0, mVertBuffers[j], 0, sizeof(float) * 6);
mDevice[j]->SetTexture(0, mSurfaces[j * 2 + 1]);
mDevice[j]->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 0.0f, 0);
V( mDevice[j]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[j].BackBufferCount;
int bbWidth = mPresentParams[j].BackBufferWidth;
int bbHeight = mPresentParams[j].BackBufferHeight;
mSurfaces[j * 2 + 1]->Release();
V(mDevice[j]->Reset(&mPresentParams[j]));
V(mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[j * 2 + 1], NULL));
mPresentParams[j].BackBufferCount = bbCount;
mPresentParams[j].BackBufferWidth = bbWidth;
mPresentParams[j].BackBufferHeight = bbHeight;
}
}
}
}
//########################################################################
//############################# BitWrangler ##############################
//########################################################################
//
// A "bitwrangler" manages a group of bits by segregating them into two groups:
// "active", and "inactive". Active bits are those specified within a given
// bit mask as "ones", and inactive bits are those specified as "zeros".
//
// Once initialized, the bitwrangler may be requested to increment either
// the active bit field or the inactive bit field: the "carry" is propagated
// from the least significant bit through the most significant bit, and if
// an overflow is generated it is returned as "False".
//
// Why in the world would anyone want such a bizarre object?
// It's used here to generate palettes and translation tables according
// to bit allocations for a GraphicsPort. "Unused" colors are easily
// found and set to proper values.
//
class BitWrangler
{
public:
BitWrangler(int bit_mask, int total_length);
~BitWrangler()
{}
void ResetActive();
void ResetInactive();
Logical IncrementActive();
Logical IncrementInactive();
int NumberOfActiveBits();
int NumberOfInactiveBits();
int Value;
protected:
int length;
int bitMask;
};
//
// Bitwrangler initialization
//
BitWrangler::BitWrangler(int bit_mask, int total_length)
{
Verify(bit_mask != 0);
bitMask = bit_mask;
length = total_length;
Value = 0;
Check_Fpu();
}
//
// Reset all "active" bits to zero
//
void
BitWrangler::ResetActive()
{
Value &= ~ bitMask;
Check_Fpu();
}
//
// Reset all "inactive" bits to zero
//
void
BitWrangler::ResetInactive()
{
Value &= bitMask;
Check_Fpu();
}
//
// Increment the "active" bit field, and return "false" if overflow
//
Logical
BitWrangler::IncrementActive()
{
int single_bit;
int count(length);
for(single_bit=1; count>0; --count, single_bit <<= 1)
{
//
// If it's an active bit, process it
//
if (bitMask & single_bit)
{
//
// Invert the bit
//
Value ^= single_bit;
//
// If the bit is now set, it was zero, so exit
//
if (Value & single_bit)
{
Check_Fpu();
return True;
}
}
}
//
// All the active bits are set, so return false
//
Check_Fpu();
return False;
}
//
// Increment the "inactive" bit field, and return "false" if overflow
//
Logical
BitWrangler::IncrementInactive()
{
int single_bit;
int count(length);
int inverse_mask(~bitMask);
for(single_bit=1; count>0; --count, single_bit <<= 1)
{
//
// If it's an inactive bit, process it
//
if (inverse_mask & single_bit)
{
//
// Invert the bit
//
Value ^= single_bit;
//
// If the bit is now set, it was zero, so exit
//
if (Value & single_bit)
{
Check_Fpu();
return True;
}
}
}
//
// All the inactive bits are set, so return false
//
Check_Fpu();
return False;
}
//
// Return the number of "active" bits
//
int
BitWrangler::NumberOfActiveBits()
{
int count(0), temp(bitMask);
while(temp != 0)
{
++count;
temp = temp & (temp-1);
}
Check_Fpu();
return count;
}
//
// Return the number of "inactive" bits
//
int
BitWrangler::NumberOfInactiveBits()
{
Check_Fpu();
return length-NumberOfActiveBits();
}
//########################################################################
//######################### Video16BitBuffered ###########################
//########################################################################
//
//NOTE: the application assumes that the origin is in the lower left
// corner of the display, and all parameters passed to these routines
// use the application's coordinate system.
//
// All of the methods here convert these values to the SCREEN
// coordinate system, with the origin in the UPPER LEFT corner of
// the display.
//
//===================================================================
// Creator
//===================================================================
Video16BitBuffered::Video16BitBuffered(int x, int y):
GraphicsDisplay(x, y),
pixelBuffer(x, y)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::Video16BitBuffered()\n"
);
# endif
int
i,
changed_size;
Verify(pixelBuffer.Data.MapPointer != NULL);
height = y;
width = x;
changedBitWidth = (width >> 5);
changed_size = height * changedBitWidth;
maximumY = height-1;
maximumX = width-1;
//---------------------------------------------------------
// Create 'changedLine' and 'changedBit' arrays
//---------------------------------------------------------
changedLine = new Byte[height];
changedBit = new LWord[changed_size];
if (changedLine == NULL || changedBit == NULL)
{
# if defined(DEBUG)
Tell("INVALID!\n");
# endif
valid = False;
return;
}
else
{
Register_Pointer(changedLine);
Register_Pointer(changedBit);
valid = True;
}
# if defined(DEBUG)
Tell("changedLine=" << changedLine << "\n");
Tell("changedBit=" << changedBit << "\n");
# endif
//---------------------------------------------------------
// Clear the 'changedBit' array
//---------------------------------------------------------
memset(changedLine, 0, height);
//---------------------------------------------------------
// Clear the 'changedBit' array
//---------------------------------------------------------
LWord
*bit_dest;
for (i=changed_size,bit_dest=changedBit; i>0; --i,++bit_dest)
{
*bit_dest = (LWord) 0;
}
Check_Fpu();
}
//===================================================================
// Destructor
//===================================================================
Video16BitBuffered::~Video16BitBuffered()
{
Check(this);
if (changedLine != NULL)
{
Unregister_Pointer(changedLine);
delete changedLine;
changedLine = NULL;
}
if (changedBit != NULL)
{
Unregister_Pointer(changedBit);
delete changedBit;
changedBit = NULL;
}
Check_Fpu();
}
//===================================================================
// TestInstance
//===================================================================
Logical
Video16BitBuffered::TestInstance() const
{
return True;
}
//===================================================================
// ShowInstance
//===================================================================
void
Video16BitBuffered::ShowInstance(
char *indent
)
{
std::cout << indent << "Video16BitBuffered:\n";
Check(this);
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "width =" << width << "\n";
std::cout << temp << "height =" << height << "\n";
std::cout << temp << "maximumX =" << maximumX << "\n";
std::cout << temp << "maximumY =" << maximumY << "\n";
std::cout << temp << "changedLine=" << changedLine << "\n";
std::cout << temp << "changedBit =" << changedBit << "\n";
pixelBuffer.ShowInstance(temp);
GraphicsDisplay::ShowInstance(temp);
Check_Fpu();
}
//===================================================================
// buildDestPointer
//===================================================================
void
Video16BitBuffered::buildDestPointer(
int screenX,
int screenY,
Word **pixel_pointer,
LWord **changed_bit_pointer,
LWord *changed_bit
)
{
Verify(valid);
Verify(pixel_pointer != NULL);
Verify(changed_bit_pointer != NULL);
Verify(changed_bit != NULL);
Verify(screenX >= 0);
Verify(screenX < width);
Verify(screenY >= 0);
Verify(screenY < height);
*pixel_pointer = pixelBuffer.Data.MapPointer +
screenX +
(screenY * width);
Verify(*pixel_pointer >= pixelBuffer.Data.MapPointer);
Verify(*pixel_pointer < &pixelBuffer.Data.MapPointer[height*width]);
*changed_bit_pointer = changedBit +
(screenX >> 5) +
(screenY * changedBitWidth);
Verify(*changed_bit_pointer >= changedBit);
Verify(*changed_bit_pointer < &changedBit[height*changedBitWidth]);
*changed_bit = 1L << (0x1F - (screenX & 0x1F));
Verify(*changed_bit != 0L);
Diag_Tell(
"Video16BitBuffered::buildDestPointer(" << screenX <<
", " << screenY << std::hex <<
") = pix " << *pixel_pointer <<
", cbp " << *changed_bit_pointer <<
", cb " << *changed_bit << std::dec <<
"\n"
);
Diag_Tell("changedBitWidth=" << changedBitWidth << "\n");
Check_Fpu();
}
//===================================================================
// MarkChangedLines
//===================================================================
#if defined(BLIT_STATISTICS)
# define SET_CHANGED(pointer, bits) *pointer |= bits; ++dirtyPixelCount
#else
# define SET_CHANGED(pointer, bits) *pointer |= bits
#endif
#define LEFT_CHANGED(pointer, bits) \
bits <<= 1; \
if (bits == 0) { --pointer; bits=0x00000001L; }
#define RIGHT_CHANGED(pointer, bits) \
bits >>= 1; \
if (bits == 0) { ++pointer; bits=0x80000000L; }
#define UP_CHANGED(pointer, bits) pointer -= changedBitWidth
#define DOWN_CHANGED(pointer, bits) pointer += changedBitWidth
#define LEFT_DEST(pointer) --pointer
#define RIGHT_DEST(pointer) ++pointer
#define UP_DEST(pointer) pointer -= width
#define DOWN_DEST(pointer) pointer += width
#define LEFT_SOURCE(pointer,map) --pointer
#define RIGHT_SOURCE(pointer,map) ++pointer
#define UP_SOURCE(pointer,map) pointer -= map->Data.Size.x
#define DOWN_SOURCE(pointer,map) pointer += map->Data.Size.x
#define LEFT_BITMAP(pointer,bits) \
bits <<= 1; \
if (bits == 0) { --pointer; bits=0x0001; }
#define RIGHT_BITMAP(pointer, bits) \
bits >>= 1; \
if (bits == 0) { ++pointer; bits=0x8000; }
#define UP_BITMAP(pointer,map) pointer -= map->Data.WidthInWords
#define DOWN_BITMAP(pointer,map) pointer += map->Data.WidthInWords
//
// Inputs are in DISPLAY COORDINATES, i.e., (0,0) in top left corner!
//
void
Video16BitBuffered::MarkChangedLines(
int start,
int stop
)
{
Check(this);
Diag_Tell(
"Video16BitBuffered::MarkChangedLines(" << start <<
", " << stop <<
")\n"
);
if (start > stop)
{
# if defined(DEBUG)
Tell("MarkChangedLines FLIPPING\n");
# endif
int temp;
temp = start;
start = stop;
stop = temp;
}
Verify(start >= 0);
Verify(start <= maximumY);
Verify(stop >= 0);
Verify(stop <= maximumY);
//------------------------------------------------
// Set the flag for each changed line
//------------------------------------------------
Verify(stop >= start);
memset(&changedLine[start], 1, stop-start+1);
Check_Fpu();
}
//===================================================================
// DrawPoint
//===================================================================
void
Video16BitBuffered::DrawPoint(
int color,
int bitmask,
Enumeration operation,
int x, int y
)
{
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
Word
*dest_pointer;
LWord
*changed_pointer;
LWord
changed_bit;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
# endif
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y, y);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Create pointers
//---------------------------------------------------------
buildDestPointer(
x, y,
&dest_pointer,
&changed_pointer,
&changed_bit
);
//---------------------------------------------------------
// Write the point
//---------------------------------------------------------
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
Check_Fpu();
}
//===================================================================
// DrawLine
//===================================================================
void
Video16BitBuffered::DrawLine(
int color,
int bitmask,
Enumeration operation,
int x1, int y1,
int x2, int y2,
Logical include_last_pixel
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawLine(" << color <<
", " << bitmask <<
", " << operation <<
", " << x1 << "," << y1 << "," << x2 << "," << y2 <<
", " << include_last_pixel <<
"\n"
);
# endif
Check(this);
Verify(x1 >= bounds.bottomLeft.x);
Verify(x1 <= bounds.topRight.x);
Verify(y1 >= bounds.bottomLeft.y);
Verify(y1 <= bounds.topRight.y);
Verify(x2 >= bounds.bottomLeft.x);
Verify(x2 <= bounds.topRight.x);
Verify(y2 >= bounds.bottomLeft.y);
Verify(y2 <= bounds.topRight.y);
enum
{
negative_delta_x = 1,
negative_delta_y = 2,
delta_y_greater = 0,
delta_x_greater = 4
};
long
length,
rate,
accumulator;
int
octant,
delta_x,
delta_y;
Word
*dest_pointer;
LWord
*changed_pointer;
LWord
changed_bit;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Route to DrawPoint if single pixel
//---------------------------------------------------------
if (x1 == x2 && y1 == y2)
{
if (include_last_pixel)
{
DrawPoint(color, bitmask, operation, x1, y1);
}
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y1 = maximumY - y1;
y2 = maximumY - y2;
//---------------------------------------------------------
// Ensure that endpoints are legitimate
//---------------------------------------------------------
Verify(x1 >= 0);
Verify(x1 < width);
Verify(x2 >= 0);
Verify(x2 < width);
Verify(y1 >= 0);
Verify(y1 < height);
Verify(y2 >= 0);
Verify(y2 < height);
# if defined(DEBUG)
Tell(
"Transformed coordinates=" << x1 << "," << y1 <<
"," << x2 << "," << y2 <<
"\n"
);
# endif
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y1, y2);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Determine which octant to use
//---------------------------------------------------------
octant = 0;
delta_x = x2 - x1;
if (delta_x < 0)
{
# if defined(DEBUG)
Tell("negative dx\n");
# endif
octant |= negative_delta_x;
delta_x = - delta_x;
}
delta_y = y2 - y1;
if (delta_y < 0)
{
# if defined(DEBUG)
Tell("negative dy\n");
# endif
octant |= negative_delta_y;
delta_y = - delta_y;
}
if (delta_x > delta_y)
{
# if defined(DEBUG)
Tell("dx > dy\n");
# endif
octant |= delta_x_greater;
}
# if defined(DEBUG)
Tell(
"dx=" << delta_x <<
", dy=" << delta_y <<
", octant=" << octant <<
", color=" << color <<
"\n"
);
# endif
//---------------------------------------------------------
// Prepare to draw line
//---------------------------------------------------------
buildDestPointer(
x1, y1,
&dest_pointer,
&changed_pointer,
&changed_bit
);
accumulator = 1024L; // preset accumulator to 1/2 full
//---------------------------------------------------------
// Draw the line!
//---------------------------------------------------------
switch (octant)
{
case delta_y_greater:
//-------------------------------------
// delta y greater
// positive delta x
// positive delta y
//
// +
// \ &
// \ &
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
Verify(delta_y > 0);
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_x:
//-------------------------------------
// delta y greater
// negative delta x
// positive delta y
//
// +
// /
// /
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_x, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_y:
//-------------------------------------
// delta y greater
// positive delta x
// negative delta y
//
// /
// /
// +
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_y, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_x+negative_delta_y:
//-------------------------------------
// delta y greater
// negative delta x
// negative delta y
//
// \ &
// \ &
// +
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_x+negative_delta_y, length=" <<
length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater:
//-------------------------------------
// delta x greater
// positive delta x
// positive delta y
//
// +---___
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_x:
//-------------------------------------
// delta x greater
// negative delta x
// positive delta y
//
// ___---+
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_x, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_y:
//-------------------------------------
// delta x greater
// positive delta x
// negative delta y
//
// +___---
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_y, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_x+negative_delta_y:
//-------------------------------------
// delta x greater
// negative delta x
// negative delta y
//
// ---___+
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_x+negative_delta_y, length=" <<
length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
}
}
break;
}
Check_Fpu();
}
//===================================================================
// DrawFilledRectangle
//===================================================================
void
Video16BitBuffered::DrawFilledRectangle(
int color,
int bitmask,
Enumeration operation,
int x1, int y1,
int x2, int y2
)
{
# if defined(DEBUG)
Tell("Video16BitBuffered::DrawFilledRectangle(" <<
color << ", " <<
std::hex << bitmask << ", " << std::dec <<
operation << ", " <<
x1 << ", " <<
y1 << ", " <<
x2 << ", " <<
y2 << ", " <<
")\n");
# endif
Check(this);
Verify(x1 >= bounds.bottomLeft.x);
Verify(x1 <= bounds.topRight.x);
Verify(y1 >= bounds.bottomLeft.y);
Verify(y1 <= bounds.topRight.y);
Verify(x2 >= bounds.bottomLeft.x);
Verify(x2 <= bounds.topRight.x);
Verify(y2 >= bounds.bottomLeft.y);
Verify(y2 <= bounds.topRight.y);
Word
*dest_pointer;
LWord
*init_changed_pointer,
*changed_pointer;
LWord
init_changed_bit,
changed_bit;
int
x,
dest_fixup,
rect_width,
rect_height;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y1 = maximumY - y1;
y2 = maximumY - y2;
//---------------------------------------------------------
// Ensure that rectangle is properly specified
//---------------------------------------------------------
if (x2 < x1)
{
int temp;
temp = x1;
x1 = x2;
x2 = temp;
}
if (y2 < y1)
{
int temp;
temp = y1;
y1 = y2;
y2 = temp;
}
//---------------------------------------------------------
// Verify that values are legitimate
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
Verify(x1 >= 0);
Verify(x1 <= x2);
Verify(x2 < width);
Verify(y1 >= 0);
Verify(y1 <= y2);
Verify(y2 < height);
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y1, y2);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to fill
//---------------------------------------------------------
# if defined(DEBUG)
Tell(
"x1=" << x1 << ", " << "y1=" << y1 << "\n" <<
"x2=" << x2 << ", " << "y2=" << y2 << "\n" <<
std::flush
);
# endif
buildDestPointer(
x1, y1,
&dest_pointer,
&init_changed_pointer,
&init_changed_bit
);
rect_height = y2 - y1 + 1;
rect_width = x2 - x1 + 1;
dest_fixup = width - rect_width;
# if defined(DEBUG)
Tell(
"rect_height=" << rect_height << "\n" <<
"rect_width=" << rect_width << "\n" <<
"dest_fixup=" << dest_fixup << "\n" <<
std::flush
);
# endif
//---------------------------------------------------------
// Fill the rectangle
//---------------------------------------------------------
switch(operation)
{
case GraphicsDisplay::Replace:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
dest_pointer++;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::And:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ &= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::Or:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ |= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::Xor:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ ^= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
}
Check_Fpu();
}
void
Video16BitBuffered::DrawText(
int /*color*/,
int /*bitmask*/,
Enumeration /*operation*/,
Logical /*opaque*/,
int /*rotation*/,
Enumeration /*fontNumber*/,
Logical /*vertical*/,
GraphicsDisplay::Justification /*justification*/,
Rectangle2D */*clippingRectanglepointer*/,
char */*stringPointer*/
)
{
# if defined(DEBUG)
Tell("Video16BitBuffered::DrawText()\n");
# endif
Check(this);
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
Check_Fpu();
if (!valid)
{
return;
}
}
//===================================================================
// DrawBitMap
//===================================================================
void
Video16BitBuffered::DrawBitMap(
int color,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawBitMap(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y,
bits,
bit_test,
first_bit_test;
Word
*source_pointer_begin,
*source_pointer,
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(bitmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < bitmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < bitmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = bitmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= bitmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= bitmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
bitmap->Data.MapPointer +
(sLeft >> 4) +
(sBottom * bitmap->Data.WidthInWords);
first_bit_test = 1 << (15-(sLeft & 15));
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
switch (rotation)
{
default:
//--------------------------------------------
// transparent bitmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"zero: xp=" << (x+map_width-1) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width-1 >= 0);
Verify(x+map_width-1 < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Transparent bitmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Transparent bitmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Transparent bitmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_height) << ", yp=" << (y-(map_width-1)) << "\n");
# endif
if (x-map_height < 0)
{
Tell("x-map_height = " << (x - map_height) << "\n");
return;
}
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
Check_Fpu();
}
//===================================================================
// DrawBitMapOpaque
//===================================================================
void
Video16BitBuffered::DrawBitMapOpaque(
int foreground,
int background,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
Diag_on;
Diag_Tell(
"Video16BitBuffered::DrawBitMapOpaque(<" << x <<
", " << y <<
">,<" << sLeft <<
", " << sBottom <<
", " << sRight <<
", " << sTop <<
">)\n"
);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y,
bits,
bit_test,
first_bit_test;
Word
*source_pointer_begin,
*source_pointer,
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
Word
color;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(bitmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < bitmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < bitmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = bitmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
Diag_off;
Diag_Tell("x=" << x << ", y=" << y << "\n");
Diag_Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Diag_Tell(
"map_width=" << map_width <<
", map_height=" << map_height <<
"\n"
);
Diag_on;
Verify(map_width > 0);
Verify(map_width <= bitmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= bitmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
bitmap->Data.MapPointer +
(sLeft >> 4) +
(sBottom * bitmap->Data.WidthInWords);
first_bit_test = 1 << (15-(sLeft & 15));
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
//---------------------------------------------------------
// The bitmap is always read left-to-right, bottom-to-top.
// We write it to the screen in different directions
// based on the rotation.
//---------------------------------------------------------
switch (rotation)
{
default:
//--------------------------------------------
// opaque bitmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width <= width); // HACK? <, or <=?
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// opaque bitmap, 90 degrees
// #--Y--.
// | |
// X |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// opaque bitmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// opaque bitmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell(
"xp=" << (x-map_height+1) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
Diag_Tell(
"(y-(map_width-1))=" << (y-(map_width-1)) <<
", y=" << y <<
","
);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
Diag_Tell(
"changed_pointer=" << changed_pointer << std::dec <<
"\n"
);
break;
}
Check_Fpu();
Diag_off;
}
//===================================================================
// DrawPixelMap8
//===================================================================
void
Video16BitBuffered::DrawPixelMap8(
int *translation_table,
int bitmask,
Enumeration operation,
Logical opaque,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawPixelMap8(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y;
Byte
source_data,
*source_pointer_begin,
*source_pointer;
Word
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
Word
color;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(pixelmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < pixelmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < pixelmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = pixelmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= pixelmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= pixelmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
pixelmap->Data.MapPointer +
sLeft +
(sBottom * pixelmap->Data.Size.x);
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
if (opaque)
{
switch (rotation)
{
default:
//--------------------------------------------
// Opaque pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Opaque pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Opaque pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Opaque pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("Opaque 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-map_height-1 >= 0);
Verify(x-map_height-1 < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
else
{
switch (rotation)
{
default:
//--------------------------------------------
// Transparent pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Transparent pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Transparent pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Transparent pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("transparent 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-(map_height-1) >= 0);
Verify(x-(map_height-1) < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
Check_Fpu();
}
//===================================================================
// DrawPixelMap8SingleColor
//===================================================================
void
Video16BitBuffered::DrawPixelMap8SingleColor(
int color,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawPixelMap8SingleColor(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y;
Byte
source_data,
*source_pointer_begin,
*source_pointer;
Word
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(pixelmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < pixelmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < pixelmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = pixelmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= pixelmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= pixelmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
pixelmap->Data.MapPointer +
sLeft +
(sBottom * pixelmap->Data.Size.x);
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
{
switch (rotation)
{
default:
//--------------------------------------------
// Single-color pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Single-color pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Single-color pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Single-color pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("Single-color 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-map_width) <<
"\n"
);
# endif
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-map_width >= 0);
Verify(y-map_width < height);
MarkChangedLines(y-map_width, y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
Check_Fpu();
}
//########################################################################
//############################ SVGA640x480x16 ############################
//########################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Single-window cockpit: the viewscreen child erases true black
// (SS_BLACKRECT paints the system window-frame gray on modern Windows).
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static WNDPROC gViewscreenBaseProc = NULL;
static LRESULT CALLBACK
ViewscreenBlackProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_ERASEBKGND)
{
RECT client;
GetClientRect(hwnd, &client);
FillRect((HDC) wParam, &client, (HBRUSH) GetStockObject(BLACK_BRUSH));
return 1;
}
return CallWindowProcA(gViewscreenBaseProc, hwnd, message, wParam, lParam);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The cockpit shell: re-fit the canvas whenever the window changes size
// (maximise, restore, drag). The game window's own proc handles the
// rest, so chain to it.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static WNDPROC gCockpitBaseProc = NULL;
static LRESULT CALLBACK
CockpitShellProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_SIZE && wParam != SIZE_MINIMIZED)
{
SVGA16 *cockpit = SVGA16::GetCockpit();
if (cockpit != NULL)
{
cockpit->LayoutCockpit(LOWORD(lParam), HIWORD(lParam));
}
}
//
// WM_EXITSIZEMOVE is not handled here: RPL4.CPP's own WndProc takes
// it, and this chains straight through to that, so the shell saves on
// every finished drag whether or not a cockpit has been built.
//
return CallWindowProcA(gCockpitBaseProc, hwnd, message, wParam, lParam);
}
SVGA16 *SVGA16::activeCockpit = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The six secondary displays at their pod sizes, in canvas units.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static const int cockpitMfdBaseW = 320;
static const int cockpitMfdBaseH = 240;
// the radar reads best big: 1.35x the compact glass
// (1.5x proved a touch too large in playtest)
static const int cockpitRadarBaseW = 324;
static const int cockpitRadarBaseH = 432;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// A percentage from the environment, falling back to the given default
// when the variable is unset, unreadable or nonsense. That fallback is
// how a per-display setting inherits the group one.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int
DisplayScalePercent(const char *variable, int fallback)
{
const char *text = getenv(variable);
if (text == NULL)
{
return fallback;
}
int percent = atoi(text);
if (percent <= 0)
{
return fallback;
}
if (percent < 25) percent = 25;
if (percent > 200) percent = 200;
return percent;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shrink a display to fit a limit, uniformly. Clamping one axis alone
// would stretch the glass out of shape, and these are photographs of
// real instruments - they have to keep their proportions.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static void
ClampGlass(SVGA16::GlassSize *glass, int max_w, int max_h)
{
if (max_w < 1) max_w = 1;
if (max_h < 1) max_h = 1;
if (glass->w > max_w)
{
glass->h = (glass->h * max_w) / glass->w;
glass->w = max_w;
}
if (glass->h > max_h)
{
glass->w = (glass->w * max_h) / glass->h;
glass->h = max_h;
}
if (glass->w < 1) glass->w = 1;
if (glass->h < 1) glass->h = 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Where the radar sits. The pod had it dead centre under the
// viewscreen, which on a wide panel is exactly where the road is, so
// L4RADARPOS moves it out of the way: either bottom corner, or halfway
// up either side.
//
// On the bottom row it is one of three panes and the lower MFD whose
// corner it takes slides inboard beside it. Halfway up a side it leaves
// the bottom row altogether and sits between that side's two MFDs.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum RadarPlacement
{
RadarBottomCenter = 0,
RadarBottomLeft,
RadarBottomRight,
RadarMidLeft,
RadarMidRight
};
static Logical
RadarOnASide(RadarPlacement placement)
{
return (placement == RadarMidLeft || placement == RadarMidRight)
? True : False;
}
static Logical
RadarOnTheLeft(RadarPlacement placement)
{
return (placement == RadarBottomLeft || placement == RadarMidLeft)
? True : False;
}
static RadarPlacement
RadarPosition()
{
static int cached = -1;
if (cached < 0)
{
//---------------------------------------------------------------
// Two spellings each: the short ones were here first, the long
// ones say which edge out loud now that there are five.
//---------------------------------------------------------------
static const struct
{
const char *name;
int placement;
}
names[] =
{
{ "CENTER", RadarBottomCenter },
{ "CENTRE", RadarBottomCenter },
{ "BOTTOM", RadarBottomCenter },
{ "LEFT", RadarBottomLeft },
{ "BOTTOMLEFT", RadarBottomLeft },
{ "RIGHT", RadarBottomRight },
{ "BOTTOMRIGHT", RadarBottomRight },
{ "MIDLEFT", RadarMidLeft },
{ "LEFTCENTER", RadarMidLeft },
{ "LEFTCENTRE", RadarMidLeft },
{ "MIDRIGHT", RadarMidRight },
{ "RIGHTCENTER", RadarMidRight },
{ "RIGHTCENTRE", RadarMidRight }
};
cached = RadarBottomCenter;
const char *text = getenv("L4RADARPOS");
if (text != NULL)
{
for (int i = 0; i < (int) (sizeof(names) / sizeof(names[0])); ++i)
{
if (!stricmp(text, names[i].name))
{
cached = names[i].placement;
break;
}
}
}
static const char *described[] =
{
"bottom centre",
"bottom left",
"bottom right",
"left side, centred",
"right side, centred"
};
DEBUG_STREAM << "SVGA16: radar on the " << described[cached]
<< "\n" << std::flush;
}
return (RadarPlacement) cached;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// The six secondary displays sized for a given canvas scale.
//
// The pod bolted these down at fixed sizes; a desktop panel has room to
// trade viewscreen for instrument, so the player scales them. Each has
// its own setting, falling back to the group one - L4MFDSCALE sets all
// five MFDs, L4MFDSCALE_UL and friends override individually, and
// L4RADARSCALE the radar.
//
// Scaling happens in canvas units, before the canvas is fitted to the
// window, so a given number means the same thing on every monitor.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
SVGA16::CockpitGlassSizes(int scale, GlassSize sizes[SplitViewCount])
{
static Logical settings_read = False;
static int percent[SplitViewCount];
if (!settings_read)
{
settings_read = True;
int group = DisplayScalePercent("L4MFDSCALE", 100);
percent[SplitMFDUpperLeft] =
DisplayScalePercent("L4MFDSCALE_UL", group);
percent[SplitMFDUpperCenter] =
DisplayScalePercent("L4MFDSCALE_UC", group);
percent[SplitMFDUpperRight] =
DisplayScalePercent("L4MFDSCALE_UR", group);
percent[SplitMFDLowerLeft] =
DisplayScalePercent("L4MFDSCALE_LL", group);
percent[SplitMFDLowerRight] =
DisplayScalePercent("L4MFDSCALE_LR", group);
percent[SplitMap] = DisplayScalePercent("L4RADARSCALE", 100);
DEBUG_STREAM << "SVGA16: secondary displays at UL "
<< percent[SplitMFDUpperLeft] << "% UC "
<< percent[SplitMFDUpperCenter] << "% UR "
<< percent[SplitMFDUpperRight] << "% LL "
<< percent[SplitMFDLowerLeft] << "% LR "
<< percent[SplitMFDLowerRight] << "% radar "
<< percent[SplitMap] << "%\n" << std::flush;
}
GlassSize glass[SplitViewCount];
for (int view = 0; view < SplitViewCount; ++view)
{
int base_w = (view == SplitMap) ? cockpitRadarBaseW : cockpitMfdBaseW;
int base_h = (view == SplitMap) ? cockpitRadarBaseH : cockpitMfdBaseH;
glass[view].w = (base_w * percent[view]) / 100;
glass[view].h = (base_h * percent[view]) / 100;
}
//-------------------------------------------------------------------
// Keep the pod arrangement legal in canvas units. Sizing each
// display on its own means these limits can be exact rather than one
// conservative rule covering all five: what constrains a display is
// its actual neighbour, not the largest a neighbour might have been.
//
// The panes overlap the viewscreen by design, as the pod's bezels
// did - each other, never.
//-------------------------------------------------------------------
const int canvas_w = 1920;
const int canvas_h = 1080;
const int half_w = canvas_w / 2;
// nothing may exceed the canvas on its own
for (int view = 0; view < SplitViewCount; ++view)
{
ClampGlass(&glass[view], canvas_w, canvas_h);
}
//-------------------------------------------------------------------
// The radar shares its column with the MFDs above and below it, so
// their heights share the canvas. Which MFDs those are, and how much
// room they leave, depends on where the radar was put. It yields,
// being the one that grows into the view.
//-------------------------------------------------------------------
RadarPlacement placement = RadarPosition();
if (RadarOnASide(placement))
{
//---------------------------------------------------------------
// Halfway up a side it has an MFD above AND below, and it grows
// from the middle in both directions - so it must clear the
// taller of the two twice over. That is a real constraint: two
// big MFDs on one side leave a centred radar very little.
//---------------------------------------------------------------
Logical left = RadarOnTheLeft(placement);
int upper = left
? glass[SplitMFDUpperLeft].h : glass[SplitMFDUpperRight].h;
int lower = left
? glass[SplitMFDLowerLeft].h : glass[SplitMFDLowerRight].h;
int tallest = (upper > lower) ? upper : lower;
ClampGlass(&glass[SplitMap], canvas_w, canvas_h - 2 * tallest);
}
else
{
//---------------------------------------------------------------
// On the bottom edge it only has to clear the MFD hanging from
// the top of its column.
//---------------------------------------------------------------
int above =
(placement == RadarBottomLeft) ? glass[SplitMFDUpperLeft].h :
(placement == RadarBottomRight) ? glass[SplitMFDUpperRight].h :
glass[SplitMFDUpperCenter].h;
ClampGlass(&glass[SplitMap], canvas_w, canvas_h - above);
}
//-------------------------------------------------------------------
// The top row is a centred display with one anchored to either edge,
// so a side display gets whatever the centre one leaves of its half.
//-------------------------------------------------------------------
int top_side = half_w - glass[SplitMFDUpperCenter].w / 2;
ClampGlass(&glass[SplitMFDUpperLeft], top_side, canvas_h);
ClampGlass(&glass[SplitMFDUpperRight], top_side, canvas_h);
//-------------------------------------------------------------------
// What the bottom row looks like depends on the radar as well:
// centred it is the middle of that row, in a corner it is a third
// pane along it, and on a side it has left the row entirely and the
// two MFDs have the whole bottom edge to share.
//-------------------------------------------------------------------
if (RadarOnASide(placement))
{
ClampGlass(&glass[SplitMFDLowerLeft], half_w, canvas_h);
ClampGlass(&glass[SplitMFDLowerRight], half_w, canvas_h);
}
else if (placement == RadarBottomCenter)
{
int bottom_side = half_w - glass[SplitMap].w / 2;
ClampGlass(&glass[SplitMFDLowerLeft], bottom_side, canvas_h);
ClampGlass(&glass[SplitMFDLowerRight], bottom_side, canvas_h);
}
else
{
int bottom_share = (canvas_w - glass[SplitMap].w) / 2;
ClampGlass(&glass[SplitMFDLowerLeft], bottom_share, canvas_h);
ClampGlass(&glass[SplitMFDLowerRight], bottom_share, canvas_h);
}
//-------------------------------------------------------------------
// An upper and a lower MFD share a column, anchored to opposite
// edges, so their heights must not sum past the canvas. The lower
// one yields - it is the one the radar sits beside.
//-------------------------------------------------------------------
ClampGlass(&glass[SplitMFDLowerLeft], canvas_w,
canvas_h - glass[SplitMFDUpperLeft].h);
ClampGlass(&glass[SplitMFDLowerRight], canvas_w,
canvas_h - glass[SplitMFDUpperRight].h);
//-------------------------------------------------------------------
// Only now to device pixels: clamping in canvas units keeps every
// limit above independent of the monitor.
//-------------------------------------------------------------------
for (int view = 0; view < SplitViewCount; ++view)
{
sizes[view].w = (glass[view].w * scale) / 100;
sizes[view].h = (glass[view].h * scale) / 100;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clear the glass off the screen for the Winners Circle.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
SVGA16::HideSecondaryDisplays()
{
Check_Pointer(this);
if (!splitViews)
{
return;
}
for (int view = 0; view < SplitViewCount; ++view)
{
if (splitView[view] != NULL)
{
splitView[view]->Hide();
}
}
DEBUG_STREAM << "SVGA16: secondary displays hidden for the podium\n"
<< std::flush;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Fit the 1920x1080 cockpit canvas into the given client area: one
// uniform scale (so the canvas never stretches - a wider desktop just
// letterboxes), centred, with every pane re-scaled and re-placed.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
SVGA16::LayoutCockpit(int client_w, int client_h)
{
Check_Pointer(this);
if (!splitViews || client_w <= 0 || client_h <= 0)
{
return;
}
const int canvas_w = 1920;
const int canvas_h = 1080;
int fit_w = (client_w * 100) / canvas_w;
int fit_h = (client_h * 100) / canvas_h;
int scale = (fit_w < fit_h) ? fit_w : fit_h;
if (scale < 25) scale = 25;
int view_w = (canvas_w * scale) / 100;
int view_h = (canvas_h * scale) / 100;
// centre the canvas: the leftover is black on the long axis
int origin_x = (client_w - view_w) / 2;
int origin_y = (client_h - view_h) / 2;
//---------------------------------------------------------------
// The viewscreen fills the canvas; the 3D presents into it and
// D3D stretches the back buffer to fit, so -res only decides how
// sharp the scene is, not how big the cockpit is.
//---------------------------------------------------------------
if (cockpitViewscreen != NULL)
{
SetWindowPos(cockpitViewscreen, NULL,
origin_x, origin_y, view_w, view_h,
SWP_NOZORDER | SWP_NOACTIVATE);
}
GlassSize glass[SplitViewCount];
CockpitGlassSizes(scale, glass);
for (int view = 0; view < SplitViewCount; ++view)
{
if (splitView[view] == NULL)
{
continue;
}
splitView[view]->Resize(glass[view].w, glass[view].h);
}
//---------------------------------------------------------------
// Top row edge to edge across the canvas, bottom cluster on the
// bottom edge - all relative to the centred canvas origin.
//---------------------------------------------------------------
if (splitView[SplitMFDUpperLeft] != NULL)
{
splitView[SplitMFDUpperLeft]->SetPosition(origin_x, origin_y);
}
if (splitView[SplitMFDUpperCenter] != NULL)
{
splitView[SplitMFDUpperCenter]->SetPosition(
origin_x + (view_w - splitView[SplitMFDUpperCenter]->ClientWidth()) / 2,
origin_y);
}
if (splitView[SplitMFDUpperRight] != NULL)
{
splitView[SplitMFDUpperRight]->SetPosition(
origin_x + view_w - splitView[SplitMFDUpperRight]->ClientWidth(),
origin_y);
}
//---------------------------------------------------------------
// The radar: bottom centre, either bottom corner, or halfway up
// either side. Only when it takes a bottom corner does a lower MFD
// have to move - on a side it is out of that row's way already.
//---------------------------------------------------------------
RadarPlacement placement = RadarPosition();
int radar_w = (splitView[SplitMap] != NULL)
? splitView[SplitMap]->ClientWidth() : 0;
if (splitView[SplitMap] != NULL)
{
int radar_h = splitView[SplitMap]->ClientHeight();
int radar_x, radar_y;
switch (placement)
{
case RadarBottomLeft:
radar_x = origin_x;
radar_y = origin_y + view_h - radar_h;
break;
case RadarBottomRight:
radar_x = origin_x + view_w - radar_w;
radar_y = origin_y + view_h - radar_h;
break;
case RadarMidLeft:
radar_x = origin_x;
radar_y = origin_y + (view_h - radar_h) / 2;
break;
case RadarMidRight:
radar_x = origin_x + view_w - radar_w;
radar_y = origin_y + (view_h - radar_h) / 2;
break;
default:
radar_x = origin_x + (view_w - radar_w) / 2;
radar_y = origin_y + view_h - radar_h;
break;
}
splitView[SplitMap]->SetPosition(radar_x, radar_y);
}
int slide_left = (placement == RadarBottomLeft) ? radar_w : 0;
int slide_right = (placement == RadarBottomRight) ? radar_w : 0;
if (splitView[SplitMFDLowerLeft] != NULL)
{
splitView[SplitMFDLowerLeft]->SetPosition(
origin_x + slide_left,
origin_y + view_h - splitView[SplitMFDLowerLeft]->ClientHeight());
}
if (splitView[SplitMFDLowerRight] != NULL)
{
splitView[SplitMFDLowerRight]->SetPosition(
origin_x + view_w - splitView[SplitMFDLowerRight]->ClientWidth()
- slide_right,
origin_y + view_h - splitView[SplitMFDLowerRight]->ClientHeight());
}
// The panes go OVER the main display (pod bezel occlusion): pin
// the viewscreen to the bottom of the sibling z-order so the 3D
// present clips around every pane.
if (cockpitViewscreen != NULL)
{
SetWindowPos(cockpitViewscreen, HWND_BOTTOM, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
DEBUG_STREAM << "SVGA16: cockpit fitted " << view_w << "x" << view_h
<< " at " << scale << "% in a " << client_w << "x" << client_h
<< " client\n" << std::flush;
}
SVGA16::SVGA16(
int mode,
int init_width,
int init_height,
int mem_page_size,
int mem_granularity,
int bytes_per_line,
int page_function_pointer,
int special_interface,
bool windowed,
int *secondaryIndex,
int *aux1Index,
int *aux2Index
):Video16BitBuffered(init_width, init_height)
{
//------------------------------------------------------------------
// Split-view mode: decide before BuildWindows so the packed gauge
// windows can stay hidden.
//------------------------------------------------------------------
splitViews = False;
cockpitViewscreen = NULL;
Logical explodedViews = False;
{
const char *split_string = getenv("L4MFDSPLIT");
if (split_string != NULL && atoi(split_string) != 0)
{
splitViews = True;
// L4MFDSPLIT=2+ : exploded diagnostic view - each display
// in its own native-resolution desktop window instead of
// the composited glass cockpit.
if (atoi(split_string) >= 2)
{
explodedViews = True;
}
}
}
for (int view = 0; view < SplitViewCount; ++view)
{
splitView[view] = NULL;
}
BuildWindows(init_width,init_height,windowed, secondaryIndex, aux1Index, aux2Index);
if (splitViews && explodedViews)
{
//---------------------------------------------------------------
// Exploded diagnostic view: every display in its own full-size
// desktop window (MFDs native 640x480, map 480x640 rotated),
// decoded exactly as the pod's VDB split them from the single
// gauge canvas - no cockpit compositing, no downscale. Each MFD
// can be read and screenshotted at full resolution, matching the
// emulator's per-channel reference windows. Laid out in the pod
// arrangement (top row / bottom row) across the work area; the
// windows are draggable (dragging a title bar briefly pauses the
// game's single-per-frame message pump, as expected).
//---------------------------------------------------------------
RECT work;
work.left = 0; work.top = 0; work.right = 1920; work.bottom = 1080;
SystemParametersInfoA(SPI_GETWORKAREA, 0, &work, 0);
int work_w = work.right - work.left;
int work_h = work.bottom - work.top;
//---------------------------------------------------------------
// Each display carries its own button bank here too, at native
// size: the banks reach under the glass with their indicator
// strips clearing the edge, exactly as in the composited
// cockpit - so the buttons can be read and pressed full size.
//---------------------------------------------------------------
splitView[SplitMFDUpperLeft] = new MFDSplitView(
"MFD upper left", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::MFDStrips, 0x2F, 0, 0);
splitView[SplitMFDUpperCenter] = new MFDSplitView(
"MFD upper center", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::MFDStrips, 0x27, 0, 0);
splitView[SplitMFDUpperRight] = new MFDSplitView(
"MFD upper right", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::MFDStrips, 0x37, 0, 0);
splitView[SplitMFDLowerLeft] = new MFDSplitView(
"MFD lower left", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::MFDStrips, 0x0F, 0, 0);
splitView[SplitMFDLowerRight] = new MFDSplitView(
"MFD lower right", init_width, init_height,
init_width, init_height, work.left, work.top,
MFDSplitView::MFDStrips, 0x07, 0, 0);
// map is portrait-mounted: source rotated to 480x640
splitView[SplitMap] = new MFDSplitView(
"Map", init_height, init_width,
init_height, init_width, work.left, work.top,
MFDSplitView::SideColumns, 0x10, 0x18, 0);
//---------------------------------------------------------------
// Lay them out in the pod arrangement from their measured sizes
// (the banks make each window bigger than its glass).
//---------------------------------------------------------------
RECT probe;
probe.left = 0; probe.top = 0; probe.right = 100; probe.bottom = 100;
AdjustWindowRect(&probe,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE);
int chrome_w = (probe.right - probe.left) - 100;
int chrome_h = (probe.bottom - probe.top) - 100;
int mfd_w = splitView[SplitMFDUpperLeft]->ClientWidth() + chrome_w;
int mfd_h = splitView[SplitMFDUpperLeft]->ClientHeight() + chrome_h;
int map_w = splitView[SplitMap]->ClientWidth() + chrome_w;
int map_h = splitView[SplitMap]->ClientHeight() + chrome_h;
int mid_x = (work_w - mfd_w) / 2; if (mid_x < 0) mid_x = 0;
int right_x = work_w - mfd_w; if (right_x < 0) right_x = 0;
int bottom_y = work_h - mfd_h; if (bottom_y < 0) bottom_y = 0;
int map_x = (work_w - map_w) / 2; if (map_x < 0) map_x = 0;
int map_y = work_h - map_h; if (map_y < 0) map_y = 0;
splitView[SplitMFDUpperLeft]->SetPosition(work.left, work.top);
splitView[SplitMFDUpperCenter]->SetPosition(work.left + mid_x, work.top);
splitView[SplitMFDUpperRight]->SetPosition(work.left + right_x, work.top);
splitView[SplitMFDLowerLeft]->SetPosition(work.left, work.top + bottom_y);
splitView[SplitMFDLowerRight]->SetPosition(
work.left + right_x, work.top + bottom_y);
splitView[SplitMap]->SetPosition(work.left + map_x, work.top + map_y);
//
// ...and then let RP412MFDLAYOUT put everything back where it was
// dragged to last time. Windows the file does not mention keep the
// arrangement just computed above. The game window is registered
// already - RPL4.CPP does that before the console screen ever
// shows - so this picks it up alongside the panes.
//
RPWindowLayout_Load();
}
else if (splitViews)
{
//---------------------------------------------------------------
// The 1920x1080 internal cockpit canvas.
//
// [ MFD UL 640 ][ MFD UC 640 ][ MFD UR 640 ] <- native glass,
// exactly 1920
// [ viewscreen 800x600, centered ]
// [ MFD LL ] [ Map ] [ MFD LR ] <- bottom edge
//
// The panes layer OVER the viewscreen like the pod's bezels -
// the MFDs partially occlude the main display by design, just
// as in the original cockpit. The whole canvas scales down
// uniformly on monitors smaller than 1920x1080.
//---------------------------------------------------------------
const int canvas_w = 1920;
const int canvas_h = 1080;
HWND cockpit = ApplicationManager::GetCurrentManager()->GetHWnd();
//---------------------------------------------------------------
// -fit takes the whole monitor rather than the work area, and
// pays no chrome: the shell goes borderless below. Otherwise
// stay inside the work area so the taskbar is still reachable.
//---------------------------------------------------------------
bool fit_display = L4Application::GetFitDisplay();
int chrome_w = 16, chrome_h = 40;
if (fit_display)
{
chrome_w = 0;
chrome_h = 0;
}
else if (cockpit != NULL)
{
RECT outer, inner;
GetWindowRect(cockpit, &outer);
GetClientRect(cockpit, &inner);
chrome_w = (outer.right - outer.left) - inner.right;
chrome_h = (outer.bottom - outer.top) - inner.bottom;
}
RECT work;
work.left = 0; work.top = 0; work.right = 1920; work.bottom = 1080;
if (fit_display)
{
MONITORINFO monitor;
memset(&monitor, 0, sizeof(monitor));
monitor.cbSize = sizeof(monitor);
HMONITOR handle = MonitorFromWindow(
(cockpit != NULL) ? cockpit : GetDesktopWindow(),
MONITOR_DEFAULTTOPRIMARY);
if (GetMonitorInfoA(handle, &monitor))
{
work = monitor.rcMonitor;
}
else
{
work.right = GetSystemMetrics(SM_CXSCREEN);
work.bottom = GetSystemMetrics(SM_CYSCREEN);
}
}
else
{
SystemParametersInfoA(SPI_GETWORKAREA, 0, &work, 0);
}
int avail_w = (work.right - work.left) - chrome_w;
int avail_h = (work.bottom - work.top) - chrome_h;
//-----------------------------------------------------------
// One uniform scale, up or down: the canvas keeps its 16:9
// shape whatever the monitor is, so a wider-than-16:9 desktop
// letterboxes instead of stretching. Scaling UP is free
// quality on the MFDs - their glass is a downscale of a
// native 640x480 channel until about 200%.
//-----------------------------------------------------------
int fit_w = (avail_w * 100) / canvas_w;
int fit_h = (avail_h * 100) / canvas_h;
int scale_num = (fit_w < fit_h) ? fit_w : fit_h;
if (scale_num < 25) scale_num = 25;
DEBUG_STREAM << "SVGA16: cockpit canvas at " << scale_num
<< "% for the " << (work.right - work.left) << "x"
<< (work.bottom - work.top) << " work area\n" << std::flush;
#define COCKPIT_CANVAS(v) (((v) * scale_num) / 100)
int client_w = COCKPIT_CANVAS(canvas_w);
int client_h = COCKPIT_CANVAS(canvas_h);
//---------------------------------------------------------------
// Grow the main window into the cockpit shell
//---------------------------------------------------------------
if (cockpit != NULL)
{
LONG_PTR style = GetWindowLongPtrA(cockpit, GWL_STYLE);
if (fit_display)
{
//-------------------------------------------------------
// Borderless over the whole monitor. The window is the
// full panel, wider than 16:9 or not - LayoutCockpit
// centres the canvas inside it and the leftover stays
// black, so this letterboxes exactly like a resize.
//-------------------------------------------------------
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_BORDER |
WS_DLGFRAME);
style |= WS_POPUP | WS_CLIPCHILDREN;
SetWindowLongPtrA(cockpit, GWL_STYLE, style);
SetWindowPos(cockpit, NULL, work.left, work.top,
work.right - work.left, work.bottom - work.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
else
{
SetWindowLongPtrA(cockpit, GWL_STYLE,
style | WS_CLIPCHILDREN);
SetWindowPos(cockpit, NULL, work.left, work.top,
client_w + chrome_w, client_h + chrome_h,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
}
//---------------------------------------------------------------
// The viewscreen: created FIRST so every pane sits above it in
// the z-order, and clipped by those siblings so the 3D present
// never draws over them. STATIC hit-tests transparent, so mouse
// input over the 3D view reaches the game window as before.
// Fills the whole canvas - launch with -res 1920 1080 for
// native 1:1 pixels.
//---------------------------------------------------------------
int view_w = client_w;
int view_h = client_h;
if (cockpit != NULL)
{
// plain STATIC (SS_BLACKRECT actually paints the system
// window-frame GRAY on modern Windows), subclassed below to
// erase true black
cockpitViewscreen = CreateWindowExA(
0, "STATIC", "",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
0, 0,
view_w, view_h,
cockpit, NULL, GetModuleHandleA(NULL), NULL);
if (cockpitViewscreen != NULL)
{
gViewscreenBaseProc = (WNDPROC) SetWindowLongPtrA(
cockpitViewscreen, GWLP_WNDPROC,
(LONG_PTR) ViewscreenBlackProc);
gMainPresentWindow = cockpitViewscreen;
}
}
//---------------------------------------------------------------
// Button banks per display (addresses per vRIO CockpitLayout,
// bank-to-display placement per the pod cockpit):
// upper left MFD 0x2F.. / upper center 0x27.. / upper right
// 0x37.. / lower left 0x0F.. / lower right 0x07.. and the map
// flanked by Secondary 0x10-0x15 / Screen 0x18-0x1D.
//---------------------------------------------------------------
// each display at whatever the player asked for it
GlassSize glass[SplitViewCount];
CockpitGlassSizes(scale_num, glass);
splitView[SplitMFDUpperLeft] = new MFDSplitView(
"MFD upper left", init_width, init_height,
glass[SplitMFDUpperLeft].w, glass[SplitMFDUpperLeft].h, 0, 0,
MFDSplitView::MFDStrips, 0x2F, 0, cockpit);
splitView[SplitMFDUpperCenter] = new MFDSplitView(
"MFD upper center", init_width, init_height,
glass[SplitMFDUpperCenter].w, glass[SplitMFDUpperCenter].h, 0, 0,
MFDSplitView::MFDStrips, 0x27, 0, cockpit);
splitView[SplitMFDUpperRight] = new MFDSplitView(
"MFD upper right", init_width, init_height,
glass[SplitMFDUpperRight].w, glass[SplitMFDUpperRight].h, 0, 0,
MFDSplitView::MFDStrips, 0x37, 0, cockpit);
splitView[SplitMFDLowerLeft] = new MFDSplitView(
"MFD lower left", init_width, init_height,
glass[SplitMFDLowerLeft].w, glass[SplitMFDLowerLeft].h, 0, 0,
MFDSplitView::MFDStrips, 0x0F, 0, cockpit);
splitView[SplitMFDLowerRight] = new MFDSplitView(
"MFD lower right", init_width, init_height,
glass[SplitMFDLowerRight].w, glass[SplitMFDLowerRight].h, 0, 0,
MFDSplitView::MFDStrips, 0x07, 0, cockpit);
// map is portrait: source rotated 90 degrees clockwise
splitView[SplitMap] = new MFDSplitView(
"Map", init_height, init_width,
glass[SplitMap].w, glass[SplitMap].h, 0, 0,
MFDSplitView::SideColumns, 0x10, 0x18, cockpit);
//---------------------------------------------------------------
// Everything above built the panes at a starting size; the
// layout itself lives in LayoutCockpit so a resized window can
// re-run it. Track the instance for the WM_SIZE hook below.
//---------------------------------------------------------------
activeCockpit = this;
if (cockpit != NULL)
{
RECT inner;
GetClientRect(cockpit, &inner);
LayoutCockpit(inner.right, inner.bottom);
// catch maximise / restore / drag-resize and re-fit
gCockpitBaseProc = (WNDPROC) SetWindowLongPtrA(
cockpit, GWLP_WNDPROC, (LONG_PTR) CockpitShellProc);
//
// Sticky placement for the shell. Position AND size: nothing
// derives that size here - -res only decides how sharp the
// scene is - so a window sized to suit a monitor should come
// back that way. RPL4.CPP registered it before the console
// screen; this reload undoes the sizing just done above, and
// runs after the subclass on purpose so its WM_SIZE puts
// LayoutCockpit over the restored client area.
//
// -fit sits it borderless over the whole monitor, so there is
// no placement of the player's to remember.
//
if (!fit_display)
{
RPWindowLayout_Load();
}
}
else
{
LayoutCockpit(client_w, client_h);
}
// the plasma glass sits out for now
PlasmaScreen::Hide();
#undef COCKPIT_CANVAS
}
//STUBBED: VIDEO RB 1/15/07
# if defined(DEBUG)
Tell("SVGA16::SVGA16()\n");
# endif
pageSize = mem_page_size * 1024;
Verify(mem_granularity > 0);
pageDelta = mem_page_size/mem_granularity;
widthInBytes = bytes_per_line;
pageFcnPtr = page_function_pointer;
specialInterface = special_interface; // currently unused
currentPageNumber = -1;
//
// Set video mode
//
//SVGASetMode(mode, pageFcnPtr);
//
// Set VWE video splitter clock divider
//
//SVGASetSplitterClock(True);
//------------------------------------------------------------------------
// Initialize palettes
//------------------------------------------------------------------------
FadeToWhite(0.0);
//------------------------------------------------------------------------
// Initialize palette data
//------------------------------------------------------------------------
// The +2 causes Adam's std::decoded Palette addresses to "match up"
// with the address definitions used by the standard VGA palette port.
// Adam's port std::decoder design uses:
// xx00 = write address port
// xx01 = data port
// xx10 = pixel mask port
// xx11 = read address port
// The standard VGA/SVGA ports are:
// 03C6 = ......0110 = xx10 = pixel mask port
// 03C7 = ......0111 = xx11 = read address port
// 03C8 = ......1000 = xx00 = write address port
// 03C9 = ......1001 = xx01 = data port
// Adam's ports are:
// 0300 = secondary palette
// 0308 = auxiliary palette 1
// 0310 = auxiliary palette 2
// By adding 2 to "Adam's" port assignments, they match with a VGA:
// 0302/030A/0312 = xx10 = pixel mask port
// 0303/030B/0313 = xx11 = read address port
// 0304/030C/0314 = xx00 = write address port
// 0305/030D/0315 = xx01 = data port
// See L4VB16.hpp, class SVGA16 for an enumeration of palettes
// matching this table.
static Word port_addr[PaletteCount] = {
0x3C6, // NativePalette
0x300+2, // SecondaryPalette
0x308+2, // AuxiliaryPalette1
0x310+2 // AuxiliaryPalette2
};
SVGA16Palette
*palette_pointer = &palette[0];
for(int i=0; i<PaletteCount; ++i,++palette_pointer)
{
int j;
palette_pointer->hardwarePort = port_addr[i];
palette_pointer->modified = False;
palette_pointer->flashAccumulator = 0.0;
palette_pointer->flashRate = 0.0;
palette_pointer->previousMaskState = -1;
for(j=0; j<SVGA16Palette::maskStates; ++j)
{
palette_pointer->mask[j] = 0xFF;
}
/*if (port_addr[i] != 0x3C6)
{
SVGAZeroPalette(port_addr[i]);
}*/
}
//---------------------------------------------------------
// Prepare update values
//---------------------------------------------------------
currentPageNumber = -1;
ResetUpdatePosition();
# if defined(BLIT_STATISTICS)
dirtyPixelCount = 0;
transferPixelCount = 0;
overflowPixelCount = 0;
# endif
//---------------------------------------------------------
// Clear the display
//---------------------------------------------------------
# if defined(DEBUG)
Tell("Valid, drawing rectangle-\n" << std::flush);
# endif
DrawFilledRectangle(
0,
0xFFFF,
GraphicsDisplay::Replace,
0, 0,
maximumX, maximumY
);
# if defined(DEBUG)
Tell("About to update-\n" << std::flush);
# endif
Update(False);
Check_Fpu();
mDisplayToUpdate = 0;
}
SVGA16::~SVGA16()
{
for (int i=0; i < NUMGAUGEWINDOWS; i++)
{
if (mSurfaces[i * 2] != NULL)
{
mSurfaces[i * 2]->Release();
mSurfaces[i * 2] = NULL;
}
if (mSurfaces[i * 2 + 1] != NULL)
{
mSurfaces[i * 2 + 1]->Release();
mSurfaces[i * 2 + 1] = NULL;
}
if (mDevice[i] != NULL)
{
mDevice[i]->Release();
mSurfaces[i] = NULL;
}
DestroyWindow(gaugeWindows[i]);
}
//STUBBED: VIDEO RB 1/15/07
# if defined(DEBUG)
Tell("SVGA16::~SVGA16()\n");
# endif
Check(this);
//---------------------------------------------------------
// Eventually wait for fade (if any) to complete??
//---------------------------------------------------------
//---------------------------------------------------------
// Set video mode
//---------------------------------------------------------
//SVGASetMode(3, 0);
# if defined(BLIT_STATISTICS)
double
ratio;
if (transferPixelCount == 0)
{
ratio = (double) 0;
}
else
{
ratio = ((double) dirtyPixelCount) / transferPixelCount;
}
//------------------------------------------------------
// Print statistics
//------------------------------------------------------
DEBUG_STREAM <<
"SVGA16::~SVGA16: pixel management statistics ------------" <<
"\nNumber of dirty pixels =" << dirtyPixelCount <<
"\nNumber of transferred pixels=" << transferPixelCount <<
"\nTimes overflowed =" << overflowPixelCount <<
"\nRatio =" << ratio <<
"\n-------------------------------------------------------\n";
# endif
//---------------------------------------------------------
// Set VWE video splitter clock divider
//---------------------------------------------------------
//SVGASetSplitterClock(False);
//
// Backstop for the sticky placement: every finished drag has already
// been written, but a window moved and then closed straight away would
// otherwise be missed. Must run before the panes go - it reads their
// live window rects, and the game window's.
//
RPWindowLayout_Save();
for (int view = 0; view < SplitViewCount; ++view)
{
delete splitView[view];
splitView[view] = NULL;
}
if (cockpitViewscreen != NULL)
{
if (gMainPresentWindow == cockpitViewscreen)
{
gMainPresentWindow = NULL;
}
DestroyWindow(cockpitViewscreen);
cockpitViewscreen = NULL;
}
Check_Fpu();
}
Logical
SVGA16::TestInstance() const
{
return Video16BitBuffered::TestInstance();
}
void
SVGA16::ShowInstance(char *indent)
{
std::cout << indent << "SVGA16:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "SVGA16:\n";
Video16BitBuffered::ShowInstance(temp);
Check_Fpu();
}
int GetShiftAmount(DWORD mask)
{
int amount = -1;
while (mask)
{
mask >>= 1;
amount++;
}
return amount;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Render one MFD's bit-slice of the shared canvas into its split-view
// window as a green screen. The mask arrives in the duplicated
// (mask | mask<<16) form the packed path uses.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void SVGA16::FillSplitMFD(
SplitViewID view,
DWORD mask,
int shift
)
{
if (splitView[view] == NULL)
{
return;
}
Word mask16 = (Word)(mask & 0xFFFF);
Word max_value = (Word)(mask16 >> shift);
if (max_value == 0)
{
return;
}
Word *source = pixelBuffer.Data.MapPointer;
unsigned long *dest = splitView[view]->Pixels();
int count = pixelBuffer.Data.Size.x * pixelBuffer.Data.Size.y;
for (int i = 0; i < count; ++i)
{
unsigned long value = (unsigned long)((*source++ & mask16) >> shift);
unsigned long green = (value * 255ul) / max_value;
*dest++ = green << 8;
}
splitView[view]->Repaint();
}
Logical SVGA16::Update(Logical forceAll)
{
HRESULT hr;
GaugeRenderer *renderer = application->GetGaugeRenderer();
if (!valid || renderer == NULL)
{
CLEAR_SCREEN_COPY();
return False; // Do no more!
}
if (++mDisplayToUpdate >= NUMGAUGEWINDOWS)
mDisplayToUpdate = 0;
//Top MFD's
L4GraphicsPort *UL = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxUL2"));
L4GraphicsPort *Cent = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxC"));
L4GraphicsPort *UR = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxUR2"));
//Bottom MFD's
L4GraphicsPort *LL = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxLL"));
L4GraphicsPort *LR = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxLR"));
//Secondary
L4GraphicsPort *secPort = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("sec"));
DWORD ulMask = 0, ucMask = 0, urMask = 0, llMask = 0, lrMask = 0;
int ulMask_sh = 0, ucMask_sh = 0, urMask_sh = 0, llMask_sh = 0, lrMask_sh = 0;
int secMask = 0;
SVGA16Palette *secPalette = NULL;
if (this->mDisplayToUpdate == 1 || this->mDisplayToUpdate == 2)
{
//Drawing MFD's... make sure we have MFDs to draw
if (UL != NULL && Cent != NULL && UR != NULL && LL != NULL && LR != NULL)
{
ulMask = UL->GetBitMask();
ulMask_sh = GetShiftAmount(ulMask);
ulMask |= (ulMask << 16);
ucMask = Cent->GetBitMask();
ucMask_sh = GetShiftAmount(ucMask);
ucMask |= (ucMask << 16);
urMask = UR->GetBitMask();
urMask_sh = GetShiftAmount(urMask);
urMask |= (urMask << 16);
llMask = LL->GetBitMask();
llMask_sh = GetShiftAmount(llMask);
llMask |= (llMask << 16);
lrMask = LR->GetBitMask();
lrMask_sh = GetShiftAmount(lrMask);
lrMask |= (lrMask << 16);
} else
{
//No MFDs to draw, break out early
return False;
}
} else
{
//Drawing secondary, make sure we got secondary
if (secPort != NULL)
{
secMask = secPort->GetBitMask();
secPalette = &((SVGA16 *) secPort->graphicsDisplay)->palette[secPort->paletteID];
} else
{
//No secondary, skip
return False;
}
}
//------------------------------------------------------------------
// Split views: render this window's displays into their own desktop
// windows, straight from the shared canvas (CPU-side, no D3D).
//------------------------------------------------------------------
if (splitViews)
{
if (mDisplayToUpdate == 0)
{
if (splitView[SplitMap] != NULL)
{
// Map is portrait-mounted: rotate 90 degrees clockwise.
// dest(x,y) = source(row = srcH-1-x, col = y)
Word *source_base = pixelBuffer.Data.MapPointer;
unsigned long *dest = splitView[SplitMap]->Pixels();
int src_w = pixelBuffer.Data.Size.x;
int src_h = pixelBuffer.Data.Size.y;
for (int dy = 0; dy < src_w; ++dy)
{
for (int dx = 0; dx < src_h; ++dx)
{
Word pixel = source_base[(src_h - 1 - dx) * src_w + dy];
PaletteTriplet *entry =
&secPalette->paletteData.Color[pixel & secMask];
*dest++ = ((unsigned long) entry->Red << 16) |
((unsigned long) entry->Green << 8) |
((unsigned long) entry->Blue);
}
}
splitView[SplitMap]->Repaint();
}
}
else if (mDisplayToUpdate == 1)
{
FillSplitMFD(SplitMFDUpperLeft, ulMask, ulMask_sh);
FillSplitMFD(SplitMFDUpperCenter, ucMask, ucMask_sh);
FillSplitMFD(SplitMFDUpperRight, urMask, urMask_sh);
if (NUMGAUGEWINDOWS < 3)
{
// spanning mode: the lower MFDs ride this window too
FillSplitMFD(SplitMFDLowerLeft, llMask, llMask_sh);
FillSplitMFD(SplitMFDLowerRight, lrMask, lrMask_sh);
}
}
else
{
FillSplitMFD(SplitMFDLowerLeft, llMask, llMask_sh);
FillSplitMFD(SplitMFDLowerRight, lrMask, lrMask_sh);
}
}
Word *data = pixelBuffer.Data.MapPointer;
D3DLOCKED_RECT rect;
if (FAILED(mSurfaces[mDisplayToUpdate * 2]->LockRect(0, &rect, NULL, mLockFlags[mDisplayToUpdate])))
{
DEBUG_STREAM << "Failed to lock texture for display " << mDisplayToUpdate << "!" << std::endl << std::flush;
}
else
{
switch(mDisplayToUpdate)
{
case 0:
{
//Secondary
Word *source = data;
Word *dest = (Word*)rect.pBits;
int postRowIncrement = (rect.Pitch / 2) - pixelBuffer.Data.Size.x;
for (int y = 0; y < pixelBuffer.Data.Size.y; y++)
{
for (int x = 0; x < pixelBuffer.Data.Size.x; x++)
{
PaletteTriplet *paletteEntry = &(secPalette->paletteData.Color[*source & secMask]);
*dest = ((paletteEntry->Red >> 3) << 11) |
((paletteEntry->Green >> 2) << 5) |
((paletteEntry->Blue >> 3));
dest++;
source++;
}
dest += postRowIncrement;
}
}
break;
case 2:
{
//HACK - set the upper mask to be the lower mask (so that we draw the lower MFDs to the window)
//and then drop through and draw like the upper stuff
ulMask = llMask;
ucMask = lrMask;
urMask = 0;
ulMask_sh = llMask_sh;
ucMask_sh = lrMask_sh;
urMask_sh = 0;
}
case 1:
{
DWORD *sourceData = (DWORD*)data;
DWORD *destData = (DWORD*)rect.pBits;
int leftWidth = pixelBuffer.Data.Size.x/2;
int postRowIncrement = (rect.Pitch / sizeof(DWORD)) - leftWidth;
for (int y = 0; y < pixelBuffer.Data.Size.y; y++)
{
for (int x=0; x < leftWidth; x++)
{
*destData = (((*sourceData & ulMask) >> ulMask_sh) * 0xF800) |
(((*sourceData & ucMask) >> ucMask_sh) * 0x07E0) |
(((*sourceData & urMask) >> urMask_sh) * 0x001F);
if (NUMGAUGEWINDOWS < 3)
{
//Only draw if we are in spanning mode
*(destData + leftWidth) = (((*sourceData & llMask) >> llMask_sh) * 0xF800) |
(((*sourceData & lrMask) >> lrMask_sh) * 0x07E0);
}
sourceData++;
destData++;
}
destData += postRowIncrement;
}
break;
}
}
V( mSurfaces[mDisplayToUpdate * 2]->UnlockRect(0) );
V( mDevice[mDisplayToUpdate]->UpdateTexture(mSurfaces[mDisplayToUpdate * 2], mSurfaces[mDisplayToUpdate * 2 + 1]) );
}
V( mDevice[mDisplayToUpdate]->BeginScene() );
V( mDevice[mDisplayToUpdate]->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1) );
V( mDevice[mDisplayToUpdate]->SetStreamSource(0, mVertBuffers[mDisplayToUpdate], 0, sizeof(float) * 6) );
V( mDevice[mDisplayToUpdate]->SetTexture(0, mSurfaces[mDisplayToUpdate * 2 + 1]) );
V( mDevice[mDisplayToUpdate]->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2) );
V( mDevice[mDisplayToUpdate]->EndScene() );
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[mDisplayToUpdate].BackBufferCount;
int bbWidth = mPresentParams[mDisplayToUpdate].BackBufferWidth;
int bbHeight = mPresentParams[mDisplayToUpdate].BackBufferHeight;
mSurfaces[mDisplayToUpdate * 2 + 1]->Release();
V(mDevice[mDisplayToUpdate]->Reset(&mPresentParams[mDisplayToUpdate]));
hr = mDevice[mDisplayToUpdate]->CreateTexture(mSurfaceRects[mDisplayToUpdate].right - mSurfaceRects[mDisplayToUpdate].left, height, 1, 0, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[mDisplayToUpdate * 2 + 1], NULL);
mPresentParams[mDisplayToUpdate].BackBufferCount = bbCount;
mPresentParams[mDisplayToUpdate].BackBufferWidth = bbWidth;
mPresentParams[mDisplayToUpdate].BackBufferHeight = bbHeight;
}
// Time end = Now();
// if (end.ticks - start.ticks > 100)
// end = start;
return False; // True == 'more to do'
}
void SVGA16::Refresh()
{
HRESULT hr;
V( mDevice[mDisplayToUpdate]->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0) );
V( mDevice[mDisplayToUpdate]->BeginScene() );
V( mDevice[mDisplayToUpdate]->EndScene() );
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[mDisplayToUpdate].BackBufferCount;
int bbWidth = mPresentParams[mDisplayToUpdate].BackBufferWidth;
int bbHeight = mPresentParams[mDisplayToUpdate].BackBufferHeight;
mSurfaces[mDisplayToUpdate * 2 + 1]->Release();
V(mDevice[mDisplayToUpdate]->Reset(&mPresentParams[mDisplayToUpdate]));
hr = mDevice[mDisplayToUpdate]->CreateTexture(mSurfaceRects[mDisplayToUpdate].right - mSurfaceRects[mDisplayToUpdate].left, height, 1, 0, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[mDisplayToUpdate * 2 + 1], NULL);
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL));
mPresentParams[mDisplayToUpdate].BackBufferCount = bbCount;
mPresentParams[mDisplayToUpdate].BackBufferWidth = bbWidth;
mPresentParams[mDisplayToUpdate].BackBufferHeight = bbHeight;
}
mDisplayToUpdate++;
if (mDisplayToUpdate >= NUMGAUGEWINDOWS)
{
mDisplayToUpdate = 0;
}
}
//STUBBED: VIDEO RB 1/15/07
// SET_SCREEN_COPY();
// Diag_Tell("SVGA16::Update(" << forceAll << ")\n");
// Check(this);
//
// //---------------------------------------------------------
// // If pixelbuffer is invalid, do nothing
// //---------------------------------------------------------
// if (!valid)
// {
// CLEAR_SCREEN_COPY();
// return False; // Do no more!
// }
// //---------------------------------------------------------
// // Mark all lines as changed if commanded
// //---------------------------------------------------------
// if (forceAll)
// {
// memset(changedLine, 1, height);
// }
//
// int
// previous_line_number = lineNumber;
//
// long
// dest_size,
// dest_line_size;
//
// //---------------------------------------------------------
// // Calculate sizes based on specialInterface
// //---------------------------------------------------------
// if (specialInterface)
// {
// dest_size = 32L; // BYTE offset!
// dest_line_size = width;
// }
// else
// {
// dest_size = 32L << 1; // WORD offset!
// dest_line_size = width << 1;
// }
// //---------------------------------------------------------
// // Process lines for as long as we can
// //---------------------------------------------------------
//#if 0 // Let's process just a few lines for background loop processing...
// while (Get_Frame_Percent_Used() < .65f)
//#endif
// {
// //---------------------------------------------------------
// // Do a couple of lines before checking time again
// //---------------------------------------------------------
// for(int line_limit=15; line_limit > 0; )
// {
// //---------------------------------------------------------
// // Check for changed line, clear the flag
// //---------------------------------------------------------
// Verify(changedLinePointer < &changedLine[height]);
//
// int
// changed_line = *changedLinePointer;
// *changedLinePointer++ = 0;
//
// if (changed_line)
// {
// Diag_Tell(height << ":");
// //---------------------------------------------------------
// // Pixels on this line have been changed
// //---------------------------------------------------------
// --line_limit;
// //---------------------------------------------------------
// // Check 'dirty' LWords: if set, scan for changed pixels
// //---------------------------------------------------------
// for(int x=0; x<changedBitWidth; ++x)
// {
// //---------------------------------------------------------
// // Check for changed pixels in LWord, clear flag
// //---------------------------------------------------------
// Verify(
// changedBitPointer < &changedBit[height*changedBitWidth]
// );
//
// LWord
// changed_bits = *changedBitPointer;
// *changedBitPointer++ = 0L;
//
// if (changed_bits)
// {
// Diag_Tell( (changed_bits & 0xFFFF0000L) ? "#" : "." );
// Diag_Tell( (changed_bits & 0x0000FFFFL) ? "#" : "." );
// //---------------------------------------------------------
// // Changed pixels! Make sure display page is correct
// //---------------------------------------------------------
// if (currentPageNumber != nextPageNumber)
// {
// SVGASetPage(nextPageNumber);
// currentPageNumber = nextPageNumber;
// }
// //---------------------------------------------------------
// // Then transfer changed pixels
// //---------------------------------------------------------
// if (specialInterface)
// {
//# if defined(BLIT_STATISTICS)
// transferPixelCount +=
//# endif
// SVGATransfer32x(destOffset, sourcePointer, changed_bits);
// }
// else
// {
//# if defined(BLIT_STATISTICS)
// transferPixelCount +=
//# endif
// SVGATransfer32(destOffset, sourcePointer, changed_bits);
// }
// }
//# if defined(DEBUG)
// else
// {
// //---------------------------------------------------------
// // No pixels in this LWord, move to next one
// //---------------------------------------------------------
// Tell("--");
// }
//# endif
// //---------------------------------------------------------
// // Update remaining pixel count
// //---------------------------------------------------------
// sourcePointer += 32;
// destOffset += dest_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
// }
// Diag_Tell("\n");
// }
// else
// {
// //---------------------------------------------------------
// // Line has not changed, skip over it
// //---------------------------------------------------------
//#if defined(CHECK_FOR_DIRT)
// Logical
// dirty_flag = False;
//
// for(int x=0; x<changedBitWidth; ++x)
// {
// //---------------------------------------------------------
// // Check for changed pixels in LWord
// //---------------------------------------------------------
// Verify(
// changedBitPointer < &changedBit[height*changedBitWidth]
// );
//
// LWord
// changed_bits = *changedBitPointer;
// *changedBitPointer++ = 0L;
//
// if (changed_bits)
// {
// dirty_flag = True;
// }
// //---------------------------------------------------------
// // Update remaining pixel count
// //---------------------------------------------------------
// sourcePointer += 32;
// destOffset += dest_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
// }
// if (dirty_flag)
// {
// Tell(
// "SVGA16::Update: Unexpected dirty bits in line " <<
// lineNumber <<
// "\n!"
// );
// }
//#else
// changedBitPointer += changedBitWidth;
// sourcePointer += width;
// destOffset += dest_line_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
//#endif
// }
//
//# if defined(BLIT_STATISTICS)
// //---------------------------------
// // Keep values within a sane range
// //---------------------------------
// if (
// (transferPixelCount > 0x10000000)
// ||
// (dirtyPixelCount > 0x10000000)
// )
// {
// transferPixelCount >>= 1;
// dirtyPixelCount >>= 1;
// ++overflowPixelCount;
// }
//# endif
// //---------------------------------------------------------
// // Check for wrap
// //---------------------------------------------------------
// if (++lineNumber >= height)
// {
// ResetUpdatePosition();
// }
// //---------------------------------------------------------
// // If back to beginning, exit loop
// //---------------------------------------------------------
// if (lineNumber == previous_line_number)
// {
// Check_Fpu();
// CLEAR_SCREEN_COPY();
// return False; // All done
// }
// }
// }
// Check_Fpu();
// CLEAR_SCREEN_COPY();
void
SVGA16::ResetUpdatePosition()
{
lineNumber = 0;
sourcePointer = pixelBuffer.Data.MapPointer;
changedLinePointer = changedLine;
changedBitPointer = changedBit;
nextPageNumber = 0;
destOffset = 0L;
}
void
SVGA16::FadeToPalettes(Scalar fade_time)
{
Check(this);
previousFadeTime = Now();
paletteFadeState = fadeToColor;
if(Small_Enough(fade_time))
{
fadeUnitsPerSecond = 0.0;
fadeAlpha = 1.0;
}
else
{
fadeUnitsPerSecond = (1.0/fade_time);
}
Check_Fpu();
}
void
SVGA16::FadeToWhite(Scalar fade_time)
{
Check(this);
previousFadeTime = Now();
paletteFadeState = fadeToWhite;
if(Small_Enough(fade_time))
{
fadeUnitsPerSecond = 0.0;
fadeAlpha = 0.0;
}
else
{
fadeUnitsPerSecond = (1.0/fade_time);
}
Check_Fpu();
}
void
generateFade(
SVGA16Palette *source,
Scalar alpha
)
{
//STUBBED: VIDEO RB 1/15/07
Check_Pointer(source);
if (alpha < 0.0)
{
alpha = 0.0;
}
else if (alpha > 1.0)
{
alpha = 1.0;
}
Palette8
temp;
// Scalar
// inverse_alpha = (1.0 - alpha) * 255.0;
int
i;
for(i=0; i<256; ++i)
{
temp.Color[i].Red = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Red * alpha));
((source->paletteData.Color[i].Red * alpha));
temp.Color[i].Green = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Green * alpha));
((source->paletteData.Color[i].Green * alpha));
temp.Color[i].Blue = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Blue * alpha));
((source->paletteData.Color[i].Blue * alpha));
}
// SVGAWriteFullPalette( // in L4SVGA16.ASM
// &temp.Color[0].Red,
// source->hardwarePort
// );
Check_Fpu();
}
void
SVGA16::FlashPalette(
int palette_number,
Scalar rate,
unsigned char *stateList
)
{
Check(this);
Verify(palette_number >= 0);
Verify(palette_number < PaletteCount);
SVGA16Palette
*palette_pointer = &palette[palette_number];
//-------------------------------------------------
// Adjust rate so value becomes "cycles per second"
//-------------------------------------------------
palette_pointer->flashRate = rate * (Scalar) SVGA16Palette::maskStates;
//-------------------------------------------------
// Copy the mask values
//-------------------------------------------------
for (int i=0; i<SVGA16Palette::maskStates; ++i)
{
palette_pointer->mask[i] = *stateList++;
}
Check_Fpu();
}
void
SVGA16::UnflashPalette(
int palette_number
)
{
//STUBBED: VIDEO RB 1/15/07
//Check(this);
//Verify(palette_number >= 0);
//Verify(palette_number < PaletteCount);
//SVGA16Palette
// *palette_pointer = &palette[palette_number];
//palette_pointer->flashRate = 0.0;
//palette_pointer->flashAccumulator = 0.0;
//palette_pointer->previousMaskState = -1;
//SVGAWritePaletteMask(palette_pointer->hardwarePort, 0xFF);
//Check_Fpu();
}
void
SVGA16::UpdatePalette()
{
//STUBBED: VIDEO RB 1/15/07
Check(this);
int
i,
mask_state;
SVGA16Palette
*palette_pointer;
//--------------------------------------------------------
// Update time values
//--------------------------------------------------------
Time
right_now = Now();
Scalar
delta_t = (Scalar) (right_now - previousFadeTime);
previousFadeTime = right_now;
if (delta_t <= 0.0)
{
return;
}
//--------------------------------------------------------
// Set palette masks
//--------------------------------------------------------
palette_pointer = &palette[0];
for(i=0; i<PaletteCount; ++i,++palette_pointer)
{
if (palette_pointer->flashRate != 0.0)
{
palette_pointer->flashAccumulator +=
palette_pointer->flashRate * delta_t;
while (palette_pointer->flashAccumulator >=
(Scalar) SVGA16Palette::maskStates)
{
palette_pointer->flashAccumulator -=
(Scalar) SVGA16Palette::maskStates;
}
mask_state = (int) palette_pointer->flashAccumulator;
if (mask_state != palette_pointer->previousMaskState)
{
palette_pointer->previousMaskState = mask_state;
// SVGAWritePaletteMask(
// palette_pointer->hardwarePort,
// palette_pointer->mask[mask_state]
// );
}
}
}
//--------------------------------------------------------
// Fade palettes
//--------------------------------------------------------
palette_pointer = &palette[0];
for(i=0; i<PaletteCount; ++i,++palette_pointer)
{
//--------------------------------------------------------
// Only the secondary palette (i==1) is allowed to fade!
// All other palettes are merely copied.
//--------------------------------------------------------
if ((i != 1) || (paletteFadeState == staticPalette))
{
if (palette_pointer->modified)
{
palette_pointer->modified = False;
// SVGAWriteFullPalette(
// &palette_pointer->paletteData.Color[0].Red,
// palette_pointer->hardwarePort
// );
}
}
else
{
//--------------------------------------------------------
// Discard 'modified' flag (we use the local values for
// fade in/out, and in the 'white' state we don't care,
// because we'll have to fade back in anyway)
//--------------------------------------------------------
palette_pointer->modified = False;
//--------------------------------------------------------
// Perform fade (or stay white)
//--------------------------------------------------------
switch(paletteFadeState)
{
case fadeToWhite:
fadeAlpha -= (delta_t * fadeUnitsPerSecond);
generateFade(palette_pointer, fadeAlpha);
if (fadeAlpha <= 0.0)
{
fadeAlpha = 0.0;
paletteFadeState = whitePalette;
}
break;
case whitePalette:
break;
case fadeToColor:
fadeAlpha += (delta_t * fadeUnitsPerSecond);
generateFade(palette_pointer, fadeAlpha);
if (fadeAlpha >= 1.0)
{
fadeAlpha = 1.0;
paletteFadeState = staticPalette;
}
break;
}
}
}
Check_Fpu();
}
void
SVGA16::FunkyVideo(Logical on_off)
{
//STUBBED: VIDEO RB 1/15/07
//Check(this);
//SVGAFunkyVideo(on_off);
//Check_Fpu();
}
//########################################################################
//########################### L4GraphicsPort #############################
//########################################################################
L4GraphicsPort::L4GraphicsPort(
Video16BitBuffered *graphics_display,
const char *name,
int rotation,
int bit_mask,
SVGA16::PaletteID palette_ID,
L4GraphicsPort::ChannelEnableID channel_enable
):GraphicsPort(graphics_display, name)
{
int
bit_test;
//
// Save the base rotation value
//
baseRotation = rotation;
//
// Save the paletteID and channel enable
//
paletteID = palette_ID;
channelEnable = channel_enable;
//
// Save the bitMask
//
bitMask = bit_mask;
Verify (bitMask != 0);
//
// Count the number of active bits in the bitMask
//
for(bit_test=0x8000,numberOfBits=0; bit_test!=0; bit_test>>=1)
{
if (bit_test & bitMask)
{
++numberOfBits;
}
}
//
// Initialize conversion constants
//
maximumX = bounds.topRight.x - bounds.bottomLeft.x;
maximumY = bounds.topRight.y - bounds.bottomLeft.y;
//
// Overwrite the GraphicsPort::bounds data with rotated values
// for GraphView's benefit
//
switch(baseRotation)
{
default:
// do nothing
break;
case 90:
case 270:
if (graphics_display != NULL)
{
Check(graphics_display);
bounds.bottomLeft.x = graphics_display->bounds.bottomLeft.y;
bounds.bottomLeft.y = graphics_display->bounds.bottomLeft.x;
bounds.topRight.x = graphics_display->bounds.topRight.y;
bounds.topRight.y = graphics_display->bounds.topRight.x;
}
break;
}
for(int j=0; j<256; ++j)
{
myColor[j] = NULL;
}
Check_Fpu();
}
L4GraphicsPort::~L4GraphicsPort()
{
Check(this);
Check_Fpu();
}
Logical
L4GraphicsPort::TestInstance() const
{
return True;
}
void
L4GraphicsPort::ShowInstance(char *indent)
{
Check(this);
std::cout << indent << "L4GraphicsPort:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "bitMask =" << bitMask << "\n";
std::cout << temp << "baseRotation =" << baseRotation << "\n";
std::cout << temp << "maximumX =" << maximumX << "\n";
std::cout << temp << "maximumY =" << maximumY << "\n";
std::cout << temp << "bounds =" << bounds << "\n";
std::cout << std::flush;
GraphicsPort::ShowInstance(temp);
Check_Fpu();
}
void
L4GraphicsPort::SetColor(
PaletteTriplet *source_triplet,
int color_index
)
{
Check(this);
Check_Pointer(source_triplet);
Verify(color_index >= 0);
Verify(color_index < 256);
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
case L4GraphicsPort::BlankColor:
break;
default:
BuildSecondaryColor(source_triplet, color_index);
break;
}
Check_Fpu();
}
void
L4GraphicsPort::SetSecondaryPalette(
Palette8 *source_palette
)
{
Check(this);
Check(source_palette);
if (graphicsDisplay == NULL)
{
return;
}
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
BuildDirectTranslation(source_palette);
break;
case L4GraphicsPort::BlankColor:
BlankPalette();
BuildSecondaryTranslation();
break;
default:
BuildSecondaryPalette(source_palette);
BuildSecondaryTranslation();
break;
}
Check_Fpu();
}
void
L4GraphicsPort::SetAuxiliaryPalette()
{
Check(this);
if (graphicsDisplay == NULL)
{
return;
}
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
//---------------------------------------------------------------
// Set translation table for direct color mode
//---------------------------------------------------------------
{
Palette8
monochrome_palette;
PaletteTriplet
black,
white;
black.Red = 0;
black.Green = 0;
black.Blue = 0;
white.Red = 255;
white.Green = 255;
white.Blue = 255;
monochrome_palette.BuildColorRange(0,255,black, white);
BuildDirectTranslation(&monochrome_palette);
}
break;
case L4GraphicsPort::BlankColor:
BlankPalette();
BuildAuxiliaryTranslation();
break;
default:
BuildAuxiliaryPalette();
BuildAuxiliaryTranslation();
break;
}
Check_Fpu();
}
void
L4GraphicsPort::DrawPoint(
int color,
Enumeration operation,
int x, int y
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
graphicsDisplay->
DrawPoint(
translationTable[color],
bitMask,
operation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y
);
Check_Fpu();
}
void
L4GraphicsPort::DrawLine(
int color,
Enumeration operation,
int x1, int y1,
int x2, int y2,
Logical include_last_pixel
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
x1p, y1p,
x2p, y2p;
convertPortPair(&x1p, &y1p, x1, y1);
convertPortPair(&x2p, &y2p, x2, y2);
graphicsDisplay->
DrawLine(
translationTable[color],
bitMask,
operation,
x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y,
include_last_pixel
);
Check_Fpu();
}
void
L4GraphicsPort::DrawFilledRectangle(
int color,
Enumeration operation,
int x1, int y1,
int x2, int y2
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
x1p, y1p,
x2p, y2p;
convertPortPair(&x1p, &y1p, x1, y1);
convertPortPair(&x2p, &y2p, x2, y2);
graphicsDisplay->
DrawFilledRectangle(
translationTable[color],
bitMask,
operation,
x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y
);
Check_Fpu();
}
void
L4GraphicsPort::DrawText(
int /*color*/,
Enumeration /*operation*/,
Logical /*opaque*/,
int /*rotation*/,
Enumeration /*fontNumber*/,
Logical /*vertical*/,
GraphicsDisplay::Justification /*justification*/,
Rectangle2D */*clippingRectanglepointer*/,
char */*stringPointer*/
)
{
}
void
L4GraphicsPort::DrawBitMap(
int color,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (bitmap == NULL)
{
Check_Fpu();
return;
}
if (bitmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(bitmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawBitMap(
translationTable[color],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
bitmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::DrawBitMapOpaque(
int color,
int background,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (bitmap == NULL)
{
Check_Fpu();
return;
}
if (bitmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(bitmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawBitMapOpaque(
translationTable[color],
translationTable[background],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
bitmap,
sLeft, sBottom, sRight, sTop
);
}
void
L4GraphicsPort::DrawPixelMap8(
Enumeration operation,
Logical opaque,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (pixelmap == NULL)
{
Check_Fpu();
return;
}
if (pixelmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(pixelmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawPixelMap8(
translationTable,
bitMask,
operation,
opaque,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
pixelmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::DrawPixelMap8SingleColor(
int color,
Enumeration operation,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (pixelmap == NULL)
{
Check_Fpu();
return;
}
if (pixelmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(pixelmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawPixelMap8SingleColor(
translationTable[color],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
pixelmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::convertPortPair(
int *xp,
int *yp,
int x,
int y
)
{
switch(baseRotation)
{
default:
*xp = x;
*yp = y;
break;
case 90:
*xp = y;
*yp = maximumY - x;
break;
case 180:
*xp = maximumX - x;
*yp = maximumY - y;
break;
case 270:
*xp = maximumX - y;
*yp = x;
break;
}
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table specifically for writing
// to a "direct" color mode display, in which colors are represented
// as 5 red bits, 6 green bits, and 5 blue bits in a display word.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildDirectTranslation(
Palette8 *source_palette
)
{
PaletteTriplet
*source_data(source_palette->Color);
int
*dest(translationTable);
int
red_bits,
green_bits,
blue_bits,
i;
//
// Force to all bits (just to be sure)
//
bitMask = 0xFFFF;
for(i=256; i>0; --i,++source_data)
{
red_bits = source_data->Red >> 3;
green_bits = source_data->Green >> 2;
blue_bits = source_data->Blue >> 3;
*dest++ = (red_bits << 11)|(green_bits << 5) | blue_bits;
}
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped onto the same RGB display, then
// the most recently built palette has precedence over the previous one(s).
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryPalette(
Palette8 *source_palette
)
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
Check(source_palette);
int
byte_mask(bitMask & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
PaletteTriplet
*source_triplet,
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
source_triplet = &source_palette->Color[0];
//-------------------------------------------
// Clear the 'owned color' flags
//-------------------------------------------
for(int j=0; j<256; ++j)
{
myColor[wrangler.Value] = 0;
}
//
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
//
if (channelEnable & 0x80)
{
++source_triplet;
wrangler.IncrementActive();
}
//
// Fill in the color table for this palette set
//
do
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
do
{
//-------------------------------------------
// Set the 'owned color' flag
//-------------------------------------------
myColor[wrangler.Value] = 1;
//-------------------------------------------
// Get destination pointer
//-------------------------------------------
destination_triplet =
&svga_palette->paletteData.Color[wrangler.Value];
//-------------------------------------------
// Copy color data
//-------------------------------------------
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = source_triplet->Red;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = source_triplet->Green;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = source_triplet->Blue;
break;
case AllChannels:
case AllChannelsTransparentZero:
*destination_triplet = *source_triplet;
break;
}
}
while (wrangler.IncrementInactive());
//-------------------------------------------
// Bump the source pointer
//-------------------------------------------
++source_triplet;
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped onto the same RGB display, then
// the most recently built palette has precedence over the previous one(s).
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryColor(
PaletteTriplet *source_triplet,
int dest_color_number
)
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
Check_Pointer(source_triplet);
int
byte_mask(bitMask & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
destination_color = 0;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
//-------------------------------------------
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
//-------------------------------------------
if (channelEnable & 0x80)
{
++destination_color;
wrangler.IncrementActive();
}
//-------------------------------------------
// Set the color value
//-------------------------------------------
do
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
if (destination_color == dest_color_number)
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
do
{
//-------------------------------------------
// Do we own this color? Skip if unowned
//-------------------------------------------
if (myColor[wrangler.Value])
{
//-------------------------------------------
// Copy color data
//-------------------------------------------
destination_triplet =
&svga_palette->paletteData.Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = source_triplet->Red;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = source_triplet->Green;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = source_triplet->Blue;
break;
case AllChannels:
case AllChannelsTransparentZero:
*destination_triplet = *source_triplet;
break;
}
}
}
while (wrangler.IncrementInactive());
//-------------------------------------------
// Only doing one color, so exit the loop
//-------------------------------------------
break;
}
//-------------------------------------------
// Bump the color counter
//-------------------------------------------
++destination_color;
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped on top of another, then
// the most recently built palette has precedence over the previous one(s).
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildAuxiliaryPalette()
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
rate,
accumulator;
Byte
color_value;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
Verify(((1<<wrangler.NumberOfActiveBits())-1) > 0);
rate = (255<<5)/((1<<wrangler.NumberOfActiveBits())-1);
accumulator = 0;
//
//-----------------------------------------------------------------------
// Generate palette
//-----------------------------------------------------------------------
//
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
if (channelEnable & 0x80)
{
accumulator += rate;
wrangler.IncrementActive();
}
do
{
color_value = (Byte) (accumulator >> 5);
accumulator += rate;
do
{
destination_triplet = &svga_palette->paletteData.
Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = color_value;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = color_value;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = color_value;
break;
case AllChannels:
case AllChannelsTransparentZero:
destination_triplet->Red = color_value;
destination_triplet->Green = color_value;
destination_triplet->Blue = color_value;
break;
}
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
# if defined(TESTPALETTE)
std::cout << "L4GraphicsPort::BuildAuxiliaryPalette for port " <<
std::hex << svga_palette->hardwarePort << "\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x03) == 0)
{
std::cout << std::dec << "\n" << i << ":" << std::hex;
}
std::cout << svga_palette->paletteData.Color[i] << " ";
}
std::cout << "\n";
{
Palette8
temp;
SVGAReadFullPalette(
&temp.Color[0].Red,
svga_palette->hardwarePort
);
std::cout << "L4GraphicsPort::BuildAuxiliaryPalette, read back\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x03) == 0)
{
std::cout << std::dec << "\n" << i << ":" << std::hex;
}
std::cout << temp.Color[i] << " ";
}
std::cout << "\n";
}
# endif
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This sets 'owned' color values in a palette to zero.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BlankPalette()
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
Byte
color_value;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
Verify(((1<<wrangler.NumberOfActiveBits())-1) > 0);
color_value = 0;
do
{
do
{
destination_triplet = &svga_palette->paletteData.
Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = color_value;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = color_value;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = color_value;
break;
case AllChannels:
case AllChannelsTransparentZero:
destination_triplet->Red = color_value;
destination_triplet->Green = color_value;
destination_triplet->Blue = color_value;
break;
}
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table for the secondary display,
// using a previously set palette and channel.
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryTranslation()
{
Verify((bitMask & 0xFF) != 0);
BitWrangler
wrangler(bitMask & 0xFF, 8);
int
*destination(translationTable);
do
{
*destination++ = wrangler.Value;
}
while (wrangler.IncrementActive());
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table for the auxiliary displays.
//
// Palettes are assumed to always have 256 colors (0=black, 255=white).
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildAuxiliaryTranslation()
{
Verify(numberOfBits != 0);
Verify(numberOfBits <= 8);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify(byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
*destination(translationTable);
int
currentValue;
//
// Generate lookup table
//
do
{
currentValue = wrangler.Value << 8;
do
{
*destination++ = currentValue;
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
# if defined(TESTPALETTE)
std::cout << "L4GraphicsPort::BuildAuxiliaryTranslation\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x07) == 0)
{
std::cout << "\n" << std::dec << i << ":" << std::hex;
}
std::cout << translationTable[i] << " ";
}
std::cout << "\n";
# endif
Check_Fpu();
}