Button banks The exploded diagnostic view was still display-only - it predates the button work - so it now builds the same banks as the cockpit, with the pod arrangement laid out from the panes measured sizes rather than a hardcoded 640/480 grid (the banks make each window bigger than its glass, and the bottom row hung off the work area otherwise). The map side columns were spread height/6 from the top, but the maps own legend grid is not sixths: measured off the bitmap it starts 13 rows down with six 102-tall cells on a 105 pitch. Every button sat high of its label, worst at the bottom. Each buttons top and bottom now come off that grid separately and are subtracted - scaling a height directly would let rounding drift them back out of step on a resized cockpit. Depth 100 to 240: against the 480 glass the two banks meet in the middle bar the strips, so practically the whole display is a press target. This mattered most in the cockpit, where the panes are small enough that the halfway clamp governs - at 100 the MFDs had a 110px dead band straight through the middle of the glass. -fit (also spelled -windowed-fullscreen) Borderless over the whole monitor, with the render size chosen to match. The cockpit presents the 3D into a viewscreen that fills its canvas, so the right -res is that canvas at the scale the cockpit will settle on; computing it with identical arithmetic makes the stretch a copy. On the 3440x1440 panel that is 133% and -res 2553 1436, against 125% for the windowed path that pays for the taskbar. The pick runs after the whole command line, so an explicit -res wins from either side of -fit. Capped at 3840x2160. Cockpit mode only - mode 0 has to stay playable on real pod hardware and mode 2 is a dev view - so those get the resolution and keep their windows. Display layout, in environ.ini L4MFDSCALE sizes all five MFDs, L4MFDSCALE_UL and friends override any one of them, L4RADARSCALE the radar, and L4RADARPOS puts the radar bottom centre, in either bottom corner, or halfway up either side. Scaling is applied in canvas units before the canvas is fitted to the window, so a number means the same thing on every monitor. Sizing each display separately let the clamps become exact rather than one conservative rule for all five: what limits a display is its actual neighbour. Which neighbour that is depends on the radar, so the clamps follow it - on the bottom edge it clears the one MFD above its column, but centred on a side it has one above AND below and grows from the middle both ways, so it must clear the taller twice over. Clamping shrinks uniformly; these are photographs of real instruments and a one-axis clamp would squash them. Verified on the ultrawide: all five radar positions, per-display and group scaling with the clamps biting, -fit with and without an explicit -res, and the button geometry measured back off the screen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6886 lines
167 KiB
C++
6886 lines
167 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;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// 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);
|
|
}
|
|
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);
|
|
|
|
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();
|
|
}
|