Files
RP412/MUNGA_L4/L4VB16.cpp
T
CydandClaude Fable 5 16ce4dfbea Exploded view remembers where you drag its windows
Ported from BT411's BT_GLASS_LAYOUT (29c502d).

The exploded view's panes are draggable desktop windows, but the
arrangement is recomputed on every launch, so dragging one somewhere
useful never survived the menu-race-menu loop.

RP412MFDLAYOUT persists it to mfd_layout.cfg beside bindings.txt:

  off / 0 / unset   computed arrangement only, no file (default)
  load / restore    restore saved positions at startup, never write
  save / adjust     restore, then rewrite on each finished drag
                    (WM_EXITSIZEMOVE) and on teardown

One "<title>=x,y,w,h" line per pane. Position is restored and the size
read and discarded: a pane's size follows its content and its button
banks, so letting an old size back in would misshape it after any
geometry change - and this port has changed that geometry twice already.

Load runs after the computed arrangement rather than instead of it, so a
pane the file does not mention simply keeps its computed spot. Only the
exploded view registers: the composited cockpit's panes are chrome-less
children with nothing to drag, so they have no position worth keeping.

RP412 needs no equivalent of BT411's "restored" flag. Its re-snap is
LayoutCockpit on WM_SIZE, which only runs in cockpit mode, so nothing
comes back later to overwrite a hand-placed window.

Verified by round trip: dragged Map to 777,333 in save mode, the file
took all six panes, and a fresh launch in load mode put it physically
back at 777,333. The harness also resized the window while moving it,
which incidentally proved the saved size really is ignored - the pane
came back correctly sized from a cfg that recorded 136x39.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 08:28:44 -05:00

6924 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));
}
}
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 back anywhere they were
// dragged to last time. Panes the file does not mention keep the
// arrangement just computed above.
//
MFDSplitView_LoadLayout();
}
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);
}
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 exploded-view placement: every finished drag
// has already been written, but a pane moved and then closed straight
// away would otherwise be missed. Must run before the panes go - it
// reads their live window rects.
//
MFDSplitView_SaveLayout();
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();
}