TASK #17 -- AUTHENTIC RADAR SYMBOLOGY (the cross-blip stand-in retired). The recon proved the 'missing pip raster set' never existed as BT game code: pips are the ENGINE's L4GaugeImage vector-stroke system (T0 source in tree, L4GAUIMA.cpp == FUN_0046f0c0 line-for-line), the 'pip table' is L4Warehouse:: gaugeImageBin keyed by Entity::resourceID, and BTL4.RES ships 110 type-0x12 shapes (every mech/vehicle/building/tree). The six btl4rdr stubs are wired to the real facilities: contacts draw their authentic model silhouettes with LOD selection, the target gets the binary's 4px-inflated box highlight, and player-name labels resolve via Mission::GetSmallNameBitmap (the prebuilt 64x16 egg rasters keyed by the player's bitmapindex). DECODED: the invented 'VideoObject' was Entity::owningPlayer all along (+0x190; nameID = playerBitmapIndex@0x1E0, target = BTPlayer::objectiveMech@0x284 -- new bridge BTPlayerObjectiveMechOf); the 'LabelledEntity' class is Landmark (cultural.h; label path dormant -- no landmark content ships, no runtime landmarkID writer). The L4GREND BT_DEV_GAUGES warehouse guard is removed (its AV had a different culprit, below); resource type 18 corrected to GaugeImageStream in decomp-reference (was mislabeled 'ModelList'). TASK #14 -- the Myomers ODR duplicate ELIMINATED: the powersub.cpp/hpp 'Myomers' (classID 0xBC3 -- actually Sensor) is retired whole; it duplicated ?DefaultData@Myomers@@ against the real class (dumpbin-verified) and /FORCE picked the winner by link order. The real Myomers (0xBC6) now chains PoweredSubsystem's handler set (ids 4-8) and publishes its SEVEN binary attributes (@00511588: SpeedEffect/Current/Recommended/Min/MaxSeekVoltage- Index/SeekVoltage/OutputVoltage) -- the old empty unchained index starved the Myomer engineering panel of every resolve. TASK #16 -- attribute parity: MechWeapon publishes the FULL binary table @0x511890 (11 entries; ids renumbered to binary truth -- the port aliases had squatted the binary's DistanceToTarget/TargetWithinRange ids; the streamed TriggerState 0x13 binding unchanged). Binary names resolved two TODO members: pipState -> estimatedReadyTime (attr 0x1A), and the EXT-model flag is the binary's RearFiring (0x1B). ThermalSight LightState published. HUD (offset conflicts) + missile-side tables (id encoding suspect) documented for a re-dump instead of publishing blind. THE CRASH THIS EXPOSED [T2, cdb-verified]: gotcha #11's dense-table gap is a LATENT AV, not a guaranteed one -- the old table's 0x0D..0x12 gap (task #5) survived on heap luck; the renumber reshuffled allocations and Find() AV'd on a garbage entryName in WeaponCluster's PercentDone resolve. Fixed with five named PAD entries (the mech.cpp attrPad idiom) + a static_assert locking the pad base to PoweredSubsystem::NextAttributeID. Gotcha #11 amended with the proof. TASK #15 -- stale-ledger sweep: GAUGE_COMPOSITE ('composite not yet built', Reservoir shadow, PlayerStatus/vehicleSubSystems 'remaining', valve-dormant- until-0xBD3, sensor guard, the superseded 'Heat MFD near-static' reframe -- all banner-corrected), gauges-hud frontmatter, L4VB16 + powersub comments. Verified live: 50/50 config attribute bindings resolve, 0 NULLs, 0 parse skips, mech spawns and simulates 31/31 subsystems, no cross-blip fallbacks, the pip cache fills through entity registration without the old guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6280 lines
148 KiB
C++
6280 lines
148 KiB
C++
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4vb16.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
|
|
// );
|
|
|
|
|
|
// DEV-COMPOSITE (option B): opt-in via BT_DEV_GAUGES. When set, SVGA16 does NO
|
|
// per-surface D3D output (no per-adapter devices/windows/present) -- it only holds
|
|
// the CPU pixelBuffer the gauge widgets raster into; the MAIN renderer composites
|
|
// that buffer as a window inset. The pod multi-surface path is left untouched.
|
|
static bool DevGaugeComposite()
|
|
{
|
|
static int v = -1;
|
|
if (v < 0) v = (getenv("BT_DEV_GAUGES") != NULL) ? 1 : 0;
|
|
return v != 0;
|
|
}
|
|
|
|
// DEV-COMPOSITE: BT_DEV_GAUGES_DOCK=1 docks the 6-surface panel INTO the main 800x600
|
|
// window (occludes the 3D view); default (unset) presents them in a SEPARATE window.
|
|
static bool DevGaugeDocked()
|
|
{
|
|
static int v = -1;
|
|
if (v < 0) v = (getenv("BT_DEV_GAUGES_DOCK") != NULL) ? 1 : 0;
|
|
return v != 0;
|
|
}
|
|
|
|
//===========================================================================//
|
|
// DEV-COMPOSITE (option B) -- draw the woken gauge renderer's SECONDARY/radar
|
|
// surface as an inset in the MAIN window. The gauge widgets have already
|
|
// rastered into the shared CPU pixelBuffer; here we palette-expand the secondary
|
|
// plane into a texture on the MAIN device (mirrors SVGA16::Update case 0) and blit
|
|
// a quad. Called by the main renderer as the LAST draw before EndScene, so no
|
|
// render-state save/restore is needed (the next frame resets device state).
|
|
//===========================================================================//
|
|
void SVGA16::DrawDevSurface(LPDIRECT3DDEVICE9 device, int slot, int mask, int paletteID,
|
|
int monoTint, float dstX, float dstY, float dstW, float dstH)
|
|
{
|
|
int w = pixelBuffer.Data.Size.x; // 640
|
|
int h = pixelBuffer.Data.Size.y; // 480
|
|
if (device == NULL || slot < 0 || slot >= 8 || w <= 0 || h <= 0) return;
|
|
|
|
// Lazily create this surface's texture on the MAIN device (MANAGED -> lockable +
|
|
// survives device reset).
|
|
if (mDevSurfaceTex[slot] == NULL)
|
|
device->CreateTexture(w, h, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, &mDevSurfaceTex[slot], NULL);
|
|
LPDIRECT3DTEXTURE9 tex = mDevSurfaceTex[slot];
|
|
if (tex == NULL) return;
|
|
|
|
// Extract this surface's bit-plane from the ONE shared pixelBuffer into the texture.
|
|
D3DLOCKED_RECT rect;
|
|
if (SUCCEEDED(tex->LockRect(0, &rect, NULL, 0)))
|
|
{
|
|
Word *source = pixelBuffer.Data.MapPointer;
|
|
Word *dest = (Word*)rect.pBits;
|
|
int postRowIncrement = (rect.Pitch / 2) - w;
|
|
if (monoTint < 0)
|
|
{
|
|
// PALETTE surface (sec/radar) -- palette-LUT expand (== SVGA16::Update case 0).
|
|
SVGA16Palette *pal = &palette[paletteID];
|
|
for (int y = 0; y < h; y++)
|
|
{
|
|
for (int x = 0; x < w; x++)
|
|
{
|
|
PaletteTriplet *pe = &(pal->paletteData.Color[*source & mask]);
|
|
*dest = ((pe->Red >> 3) << 11) | ((pe->Green >> 2) << 5) | (pe->Blue >> 3);
|
|
dest++; source++;
|
|
}
|
|
dest += postRowIncrement;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// MONO MFD surface -- single-bit-plane expand to a tint (the reduced core of
|
|
// SVGA16::Update cases 1/2; MFD masks are single bits, so no DWORD SIMD/pack).
|
|
Word tint = (Word) monoTint;
|
|
for (int y = 0; y < h; y++)
|
|
{
|
|
for (int x = 0; x < w; x++)
|
|
{
|
|
*dest = (*source & mask) ? tint : 0;
|
|
dest++; source++;
|
|
}
|
|
dest += postRowIncrement;
|
|
}
|
|
}
|
|
tex->UnlockRect(0);
|
|
}
|
|
|
|
// Draw the surface quad at (dstX,dstY,dstW,dstH) in the current render target.
|
|
struct InsetVert { float x, y, z, rhw, u, v; };
|
|
InsetVert quad[4] =
|
|
{
|
|
{ dstX, dstY, 0.0f, 1.0f, 0.0f, 0.0f },
|
|
{ dstX + dstW, dstY, 0.0f, 1.0f, 1.0f, 0.0f },
|
|
{ dstX + dstW, dstY + dstH, 0.0f, 1.0f, 1.0f, 1.0f },
|
|
{ dstX, dstY + dstH, 0.0f, 1.0f, 0.0f, 1.0f },
|
|
};
|
|
device->SetTexture(0, tex);
|
|
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
|
|
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
|
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
device->SetRenderState(D3DRS_ZENABLE, FALSE);
|
|
device->SetRenderState(D3DRS_LIGHTING, FALSE);
|
|
device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
|
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, sizeof(InsetVert));
|
|
}
|
|
|
|
//
|
|
// The pod's SIX instrument surfaces, all bit-plane views of the ONE shared 640x480
|
|
// gauge buffer (masks/positions from content/GAUGE/L4GAUGE.CFG MechInit @4395):
|
|
// sec = radar/secondary (palette) Heat = UL Mfd2 = UC Comm = UR
|
|
// Mfd1 = LL Mfd3 = LR
|
|
// monoTint < 0 -> palette-expand; else the mono tint for that MFD plane.
|
|
// (2026-07-12: the "widgets not yet reconstructed / parse-skipped" note that
|
|
// lived here is long superseded -- every config widget is registered and
|
|
// built, 0 parse-skips; see docs/GAUGE_COMPOSITE.md.)
|
|
//
|
|
struct BTGaugeSurfaceDesc
|
|
{
|
|
const char *portName;
|
|
int monoTint; // -1 = palette (sec); else R5G6B5 tint
|
|
float cellX, cellY; // normalized cell origin within the panel (y down)
|
|
float cellW, cellH; // normalized cell size
|
|
};
|
|
|
|
static const BTGaugeSurfaceDesc kBTGaugeSurfaces[6] =
|
|
{
|
|
// top row: Heat (UL) | Mfd2 (UC) | Comm (UR)
|
|
{ "Heat", 0xFFFF, 0.0f / 3, 0.0f, 1.0f / 3, 0.5f },
|
|
{ "Mfd2", 0xFFFF, 1.0f / 3, 0.0f, 1.0f / 3, 0.5f },
|
|
{ "Comm", 0xFFFF, 2.0f / 3, 0.0f, 1.0f / 3, 0.5f },
|
|
// bottom row: Mfd1 (LL) | sec/radar (center) | Mfd3 (LR)
|
|
{ "Mfd1", 0xFFFF, 0.0f / 3, 0.5f, 1.0f / 3, 0.5f },
|
|
{ "sec", -1, 1.0f / 3, 0.5f, 1.0f / 3, 0.5f },
|
|
{ "Mfd3", 0xFFFF, 2.0f / 3, 0.5f, 1.0f / 3, 0.5f },
|
|
};
|
|
|
|
//
|
|
// Composite ALL SIX gauge surfaces into the CURRENT render target, tiled within the
|
|
// panel rect (px,py,pw,ph). Reaches the ONE shared SVGA16 via any resolvable port and
|
|
// extracts each surface by its own bit-plane mask. Ports that don't resolve are skipped.
|
|
//
|
|
void BTDrawGaugeSurfaces(LPDIRECT3DDEVICE9 device, float px, float py, float pw, float ph)
|
|
{
|
|
if (device == NULL) return;
|
|
GaugeRenderer *gr = application ? application->GetGaugeRenderer() : NULL;
|
|
if (gr == NULL) return;
|
|
|
|
// Reach the shared display once (any present port shares the same SVGA16/pixelBuffer).
|
|
SVGA16 *svga = NULL;
|
|
for (int i = 0; i < 6 && svga == NULL; i++)
|
|
{
|
|
L4GraphicsPort *p = static_cast<L4GraphicsPort*>(gr->GetGraphicsPort(kBTGaugeSurfaces[i].portName));
|
|
if (p != NULL) svga = (SVGA16*) p->graphicsDisplay;
|
|
}
|
|
if (svga == NULL) return;
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
const BTGaugeSurfaceDesc &d = kBTGaugeSurfaces[i];
|
|
L4GraphicsPort *port = static_cast<L4GraphicsPort*>(gr->GetGraphicsPort(d.portName));
|
|
if (port == NULL) continue; // this surface's port isn't configured -> skip
|
|
svga->DrawDevSurface(
|
|
device, i, port->GetBitMask(), port->paletteID, d.monoTint,
|
|
px + d.cellX * pw, py + d.cellY * ph, d.cellW * pw, d.cellH * ph);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free entry point the MAIN renderer calls (L4VIDEO DPLRenderer::ExecuteImplementation,
|
|
// just before EndScene). No-op unless BT_DEV_GAUGES is set. Docks the 6-surface panel
|
|
// in the bottom-left of the 800x600 main window (a second dedicated window is the goal;
|
|
// see BTGaugeWindow* below).
|
|
//
|
|
void BTDrawGaugeInset(LPDIRECT3DDEVICE9 device)
|
|
{
|
|
if (!DevGaugeComposite() || !DevGaugeDocked() || device == NULL) return;
|
|
// DOCKED mode only: draw into the main backbuffer (this runs before EndScene).
|
|
BTDrawGaugeSurfaces(device, 2.0f, 300.0f, 540.0f, 296.0f);
|
|
}
|
|
|
|
//===========================================================================//
|
|
// DEV-COMPOSITE -- the SEPARATE cockpit-MFD window (the default under BT_DEV_GAUGES).
|
|
// A second top-level window fed by an ADDITIONAL SWAP CHAIN on the existing main
|
|
// device (no second D3D device needed -- textures/vertex data are shared). The pod's
|
|
// own per-surface fullscreen-device path (SVGA16::BuildWindows) is untouched; this is
|
|
// the dev-box analog of the pod's separate instrument monitors, collapsed into one
|
|
// tiled window. BTGaugeWindowRenderAndPresent is called AFTER the main EndScene.
|
|
//===========================================================================//
|
|
static HWND s_gaugeHwnd = NULL;
|
|
static IDirect3DSwapChain9 *s_gaugeSwap = NULL;
|
|
static const int s_gaugeW = 960;
|
|
static const int s_gaugeH = 384;
|
|
|
|
static LRESULT CALLBACK BTGaugeWndProc(HWND h, UINT m, WPARAM w, LPARAM l)
|
|
{
|
|
if (m == WM_CLOSE) { ShowWindow(h, SW_HIDE); return 0; } // hide, never quit the app
|
|
return DefWindowProc(h, m, w, l);
|
|
}
|
|
|
|
// Lazily create the window + its additional swap chain (on the MAIN device).
|
|
static bool BTGaugeWindowEnsure(LPDIRECT3DDEVICE9 device)
|
|
{
|
|
if (s_gaugeSwap != NULL) return true;
|
|
if (device == NULL) return false;
|
|
|
|
HINSTANCE hInst = GetModuleHandle(NULL);
|
|
static bool s_classReg = false;
|
|
if (!s_classReg)
|
|
{
|
|
WNDCLASSA wc;
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.lpfnWndProc = BTGaugeWndProc;
|
|
wc.hInstance = hInst;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
|
|
wc.lpszClassName = "BTGaugeWnd";
|
|
RegisterClassA(&wc);
|
|
s_classReg = true;
|
|
}
|
|
if (s_gaugeHwnd == NULL)
|
|
{
|
|
RECT r = { 0, 0, s_gaugeW, s_gaugeH };
|
|
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
|
|
s_gaugeHwnd = CreateWindowExA(
|
|
0, "BTGaugeWnd", "BattleTech - Cockpit MFDs", WS_OVERLAPPEDWINDOW,
|
|
40, 40, r.right - r.left, r.bottom - r.top, NULL, NULL, hInst, NULL);
|
|
if (s_gaugeHwnd == NULL) return false;
|
|
ShowWindow(s_gaugeHwnd, SW_SHOWNOACTIVATE);
|
|
}
|
|
|
|
// Match the main swap chain's backbuffer format so the additional chain is compatible.
|
|
D3DFORMAT bbFormat = D3DFMT_X8R8G8B8;
|
|
IDirect3DSwapChain9 *mainSwap = NULL;
|
|
if (SUCCEEDED(device->GetSwapChain(0, &mainSwap)) && mainSwap != NULL)
|
|
{
|
|
D3DPRESENT_PARAMETERS mpp;
|
|
if (SUCCEEDED(mainSwap->GetPresentParameters(&mpp)))
|
|
bbFormat = mpp.BackBufferFormat;
|
|
mainSwap->Release();
|
|
}
|
|
|
|
D3DPRESENT_PARAMETERS pp;
|
|
memset(&pp, 0, sizeof(pp));
|
|
pp.Windowed = TRUE;
|
|
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
pp.hDeviceWindow = s_gaugeHwnd;
|
|
pp.BackBufferFormat = bbFormat;
|
|
pp.BackBufferWidth = s_gaugeW;
|
|
pp.BackBufferHeight = s_gaugeH;
|
|
pp.BackBufferCount = 1;
|
|
if (FAILED(device->CreateAdditionalSwapChain(&pp, &s_gaugeSwap)))
|
|
{
|
|
s_gaugeSwap = NULL;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Render the 6 surfaces into the gauge window's swap chain and present it. Called AFTER
|
|
// the main EndScene, BEFORE the main Present (so it can BeginScene/EndScene on its own).
|
|
void BTGaugeWindowRenderAndPresent(LPDIRECT3DDEVICE9 device)
|
|
{
|
|
if (!DevGaugeComposite() || DevGaugeDocked() || device == NULL) return;
|
|
if (!BTGaugeWindowEnsure(device)) return;
|
|
|
|
IDirect3DSurface9 *gaugeBB = NULL;
|
|
if (FAILED(s_gaugeSwap->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &gaugeBB)) || gaugeBB == NULL)
|
|
{
|
|
// device likely lost -> drop the chain so it recreates next frame
|
|
s_gaugeSwap->Release();
|
|
s_gaugeSwap = NULL;
|
|
return;
|
|
}
|
|
|
|
IDirect3DSurface9 *mainRT = NULL;
|
|
device->GetRenderTarget(0, &mainRT);
|
|
IDirect3DSurface9 *mainDS = NULL;
|
|
device->GetDepthStencilSurface(&mainDS); // may be NULL
|
|
|
|
device->SetRenderTarget(0, gaugeBB);
|
|
// Unbind the main depth-stencil: it is 800x600 but the gauge backbuffer is 960x384
|
|
// (wider) -- a bound depth surface smaller than the render target is INVALID and makes
|
|
// every draw silently fail. We don't need depth here (Z is disabled per surface quad).
|
|
device->SetDepthStencilSurface(NULL);
|
|
device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(12, 12, 16), 1.0f, 0);
|
|
if (SUCCEEDED(device->BeginScene()))
|
|
{
|
|
BTDrawGaugeSurfaces(device, 0.0f, 0.0f, (float) s_gaugeW, (float) s_gaugeH);
|
|
device->EndScene();
|
|
}
|
|
|
|
if (mainRT != NULL) // restore the main render target + depth for the next frame
|
|
{
|
|
device->SetRenderTarget(0, mainRT);
|
|
mainRT->Release();
|
|
}
|
|
device->SetDepthStencilSurface(mainDS); // NULL is valid (restores "no depth")
|
|
if (mainDS != NULL)
|
|
mainDS->Release();
|
|
gaugeBB->Release();
|
|
|
|
if (s_gaugeSwap->Present(NULL, NULL, s_gaugeHwnd, NULL, 0) == D3DERR_DEVICELOST)
|
|
{
|
|
s_gaugeSwap->Release();
|
|
s_gaugeSwap = NULL;
|
|
}
|
|
}
|
|
|
|
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 (DevGaugeComposite())
|
|
{
|
|
// DEV COMPOSITE (option B): force the "no D3D output surfaces" path. Do NOT
|
|
// create per-surface devices/windows -- FindBestAdapterIndices hands us the
|
|
// primary adapter (up to 3x) on a dev box, but a 2nd/3rd fullscreen device
|
|
// can't be created there. The base Video16BitBuffered pixelBuffer still
|
|
// exists and the widgets raster into it; the main renderer composites it.
|
|
NUMGAUGEWINDOWS = 0;
|
|
}
|
|
|
|
if (NUMGAUGEWINDOWS == 0)
|
|
{
|
|
// (defensive) NULL the per-surface arrays so ~SVGA16 delete[] is safe on the
|
|
// no-surface path (they are not allocated below).
|
|
gaugeWindows = NULL; mDevice = NULL; mVertBuffers = NULL;
|
|
mSurfaces = NULL; mLockFlags = NULL; mPresentParams = NULL; mSurfaceRects = NULL;
|
|
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])
|
|
{
|
|
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);
|
|
// GUARD (platform profile): mDevice[j] is null/uninitialised on
|
|
// failure, and the code below (GetDeviceCaps @next line, CreateTexture,
|
|
// CreateVertexBuffer) derefs it -> segfault. This is hit when the POD
|
|
// profile runs on a box WITHOUT the pod's extra adapters/monitors (a
|
|
// second fullscreen gauge device can't be created). PostQuitMessage
|
|
// already asked to bail; break so we exit the surface loop cleanly
|
|
// instead of crashing. INERT on real pod hardware (CreateDevice
|
|
// succeeds there) -- does not change the pod multi-surface behavior.
|
|
break;
|
|
}
|
|
|
|
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 ############################
|
|
//########################################################################
|
|
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)
|
|
{
|
|
BuildWindows(init_width,init_height,windowed, secondaryIndex, aux1Index, aux2Index);
|
|
for (int _i = 0; _i < 8; _i++) // DEV-COMPOSITE: lazily created on first surface draw
|
|
mDevSurfaceTex[_i] = NULL;
|
|
//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);
|
|
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;
|
|
}
|
|
|
|
Logical SVGA16::Update(Logical forceAll)
|
|
{
|
|
HRESULT hr;
|
|
|
|
GaugeRenderer *renderer = application->GetGaugeRenderer();
|
|
if (!valid || renderer == NULL)
|
|
{
|
|
CLEAR_SCREEN_COPY();
|
|
return False; // Do no more!
|
|
}
|
|
|
|
// DEV-COMPOSITE GUARD (option B): dev-composite SVGA16 does NO per-surface D3D
|
|
// (BuildWindows forced NUMGAUGEWINDOWS=0 + allocated nothing); the mSurfaces[0]
|
|
// path below would index an absent array. The main renderer composites the shared
|
|
// CPU pixelBuffer as a window inset instead. Inert on the pod.
|
|
if (DevGaugeComposite() || NUMGAUGEWINDOWS <= 0)
|
|
return False;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
// DEV-COMPOSITE GUARD (option B): dev-composite does NO per-surface D3D; skip the
|
|
// per-surface clear/present (the main renderer composites the CPU pixelBuffer
|
|
// inset). Inert on the pod.
|
|
if (DevGaugeComposite() || NUMGAUGEWINDOWS <= 0)
|
|
return;
|
|
|
|
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();
|
|
}
|