Files
BT411/engine/MUNGA_L4/L4VB16.cpp
T
arcattackandClaude Opus 4.8 7052d9e5bb Cockpit: pull the MFD red lamps fully outside the screens; drop the flight blocks clear
Playtest feedback: the red MFD lamp buttons were obstructed (only a thin sliver
showed under the surface, crammed against the DISPLAY/PROGRAM legends), and the blue
THROTTLE/JOYSTICK flight blocks overlapped the bottom MFDs.

- Red lamps now sit FULLY OUTSIDE the MFD (kCkRedGap=3 off the edge, kCkRedH=24 tall)
  instead of reaching kCkRedCell into the display -- nothing occludes them and they
  read as real buttons, clear of the DISPLAY/PROGRAM legends. topBand grows to 223.
- Flight blocks drop below the MFD's bottom red lamps (belowLamp) -- no overlap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 21:35:51 -05:00

7088 lines
179 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4vb16.h"
#include "../munga/gaugrend.h"
#include "L4VIDEO.h"
#include "DXUtils.h"
#ifdef BT_GLASS
#include "l4glasswin.h" // BTGlassPanelsActive(): the per-display windows own the surfaces
#include "l4padrio.h" // PadRIO::GetLampState / SetScreenButton (cockpit lamps + clicks)
#endif
// BTResolveGaugeRenderer()/BTResolveMainWindow() (l4vb16.h) are DEFINED in
// game/btl4main.cpp off the real app/window pointers -- NOT here: an engine TU
// can bind the NULL /FORCE-duplicate copy of `application`/`ghWnd`, and which
// copy an obj binds is non-deterministic per link.
#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;
}
// DOCK-BOTTOM (2026-07-12, single-window mode): the gauge strip is APPENDED to
// the main window's bottom band -- the world renders in the top region via a
// restricted viewport, the strip in the remainder, everything scales with the
// window. Enabled by btl4main when BT_DEV_GAUGES is set (BT_DEV_GAUGES_WINDOW=1
// restores the separate-window mode). Strip height = width x (480/1320), the
// panel's design aspect.
int gBTGaugeDockBottom = 0;
static const float kBTDockStripRatio = 480.0f / 1320.0f;
// The strip's height for a given window width: proportional to width at the
// panel's design aspect, CAPPED at the design height (480) -- a very wide
// window renders the strip at native 1:1 instead of upscaling it.
int BTGaugeStripHeightFor(int width)
{
int h = (int)((float)width * kBTDockStripRatio);
return (h > 480) ? 480 : h;
}
// Restrict rasterization to the WORLD region (target minus the bottom strip).
// Called by the main renderer right after BeginScene; no-op unless dock-bottom.
void BTApplyWorldViewport(LPDIRECT3DDEVICE9 device)
{
if (device == NULL) return;
if (!gBTGaugeDockBottom && !gBTGaugeCockpit) return;
IDirect3DSurface9 *rt = NULL;
if (FAILED(device->GetRenderTarget(0, &rt)) || rt == NULL) return;
D3DSURFACE_DESC d;
rt->GetDesc(&d);
rt->Release();
if (gBTGaugeCockpit)
{
// COCKPIT: the world renders in the CENTERED view rect; the surround
// bands + panels draw on top afterwards (BTDrawCockpitPanels). The
// reticle/HUD dpl2d pass maps through this viewport for free.
BTCockpitLayout L;
BTCockpitComputeLayout((int)d.Width, (int)d.Height, &L);
if (L.viewW <= 0 || L.viewH <= 0) return;
D3DVIEWPORT9 vp = { (DWORD)L.viewX, (DWORD)L.viewY, (DWORD)L.viewW, (DWORD)L.viewH, 0.0f, 1.0f };
device->SetViewport(&vp);
return;
}
DWORD stripH = (DWORD)BTGaugeStripHeightFor((int)d.Width);
if (stripH == 0 || stripH >= d.Height) return;
D3DVIEWPORT9 vp = { 0, 0, d.Width, d.Height - stripH, 0.0f, 1.0f };
device->SetViewport(&vp);
}
// DEV-COMPOSITE: BT_DEV_GAUGES_DOCK=1 docks the 6-surface panel INTO the main 800x600
// window (occludes the 3D view); dock-bottom (above) also counts as docked --
// both suppress the separate gauge window and draw via the main-window inset.
static bool DevGaugeDocked()
{
static int v = -1;
if (v < 0) v = (getenv("BT_DEV_GAUGES_DOCK") != NULL) ? 1 : 0;
return v != 0 || gBTGaugeDockBottom != 0 || gBTGaugeCockpit != 0;
}
// GLASS per-display windows (L4GLASSWIN) own the instrument surfaces in their OWN
// GDI windows -- when active, the whole D3D dev-composite path (dock / separate
// window / overlay) must stand down so nothing double-draws into the main window.
static bool GlassPanelsOwnSurfaces()
{
#ifdef BT_GLASS
return BTGlassPanelsActive() != 0;
#else
return false;
#endif
}
//===========================================================================//
// COCKPIT SURROUND (BT_COCKPIT) -- layout single source of truth.
//===========================================================================//
int gBTGaugeCockpit = 0; // mode select (resolved once by btl4main)
int gBTCockpitCanvasW = 0; // backbuffer canvas dims (set by btl4main; the
int gBTCockpitCanvasH = 0; // aspect calc needs them after a client resize)
// Layout constants (backbuffer px). MFD = 640x480 native x 0.5; radar = 480x640
// portrait x 0.5. The lamp EDGE (kCkLamp) protrudes past the surface; the FULL
// button rect reaches kCkRedCell INTO the display (hit-only, covered by the
// surface). User asked for larger/more-clickable buttons than the glass windows'
// 10px edge -> kCkLamp 16.
enum {
kCkMFDW = 320, kCkMFDH = 240,
kCkRADW = 240, kCkRADH = 320,
kCkOVL = 44, // (int)(0.14f * 320): corner overlap into the view
kCkLamp = 16, // radar rail / bottom-cell protrusion
kCkRedH = 24, // MFD red lamp height -- sits fully OUTSIDE the surface
kCkRedGap = 3, // gap between the red lamp and the MFD screen edge
kCkRailW = 26, // radar side-rail width
kCkGap = 2,
kCkSideBand = kCkMFDW - kCkOVL, // 276
kCkTopBand = (kCkMFDH - kCkOVL) + kCkRedGap + kCkRedH, // 223 (fits the top red lamps)
kCkBotBand = kCkRADH + kCkLamp // 336 (radar flush below view)
};
// Canvas = view region + the surround bands.
void BTCockpitCanvasFor(int viewW, int viewH, int *canvasW, int *canvasH)
{
if (canvasW) *canvasW = viewW + 2 * kCkSideBand;
if (canvasH) *canvasH = viewH + kCkTopBand + kCkBotBand;
}
// The five MFD banks: {cockpit surface slot, high address}. Top row = bankHi-i
// (descending), bottom row = bankHi-4-i (L4GLASSWIN BuildMfd order + the
// BTGlassPanels_Create address assignment).
static const struct { int slot, bankHi; } kCkMfdBank[5] =
{
{ 0, 0x2F }, // Heat (UL)
{ 1, 0x27 }, // Mfd2 (UC)
{ 5, 0x37 }, // Comm (UR)
{ 2, 0x0F }, // Mfd1 (LL)
{ 3, 0x07 }, // Mfd3 (LR)
};
static void CkPushBtn(BTCockpitLayout *L, int addr, int x, int y, int w, int h,
int colorClass, int inert, const char *label)
{
if (L->buttonCount >= (int)(sizeof(L->buttons) / sizeof(L->buttons[0]))) return;
BTCockpitBtn &b = L->buttons[L->buttonCount++];
b.address = addr; b.x = x; b.y = y; b.w = w; b.h = h;
b.colorClass = colorClass; b.inert = inert; b.label = label;
}
void BTCockpitComputeLayout(int canvasW, int canvasH, BTCockpitLayout *out)
{
BTCockpitLayout *L = out;
memset(L, 0, sizeof(*L));
L->canvasW = canvasW;
L->canvasH = canvasH;
int viewW = canvasW - 2 * kCkSideBand;
int viewH = canvasH - kCkTopBand - kCkBotBand;
if (viewW < 64) viewW = 64;
if (viewH < 64) viewH = 64;
int vx = kCkSideBand, vy = kCkTopBand;
L->viewX = vx; L->viewY = vy; L->viewW = viewW; L->viewH = viewH;
// Surface dest rects (slots: 0 Heat, 1 Mfd2, 2 Mfd1, 3 Mfd3, 4 sec, 5 Comm).
// Corner MFDs overlap the view corner by kCkOVL both axes; Mfd2 drops 25% of
// its height into the top; sec is flush below (view bottom edge clean).
int cx = vx + viewW / 2;
// Heat TL
L->surfX[0] = vx - kCkMFDW + kCkOVL; L->surfY[0] = vy - kCkMFDH + kCkOVL;
L->surfW[0] = kCkMFDW; L->surfH[0] = kCkMFDH;
// Mfd2 top-center (25% into view)
L->surfX[1] = cx - kCkMFDW / 2; L->surfY[1] = vy - (int)(0.75f * kCkMFDH);
L->surfW[1] = kCkMFDW; L->surfH[1] = kCkMFDH;
// Mfd1 BL
L->surfX[2] = vx - kCkMFDW + kCkOVL; L->surfY[2] = vy + viewH - kCkOVL;
L->surfW[2] = kCkMFDW; L->surfH[2] = kCkMFDH;
// Mfd3 BR
L->surfX[3] = vx + viewW - kCkOVL; L->surfY[3] = vy + viewH - kCkOVL;
L->surfW[3] = kCkMFDW; L->surfH[3] = kCkMFDH;
// sec center, flush below
L->surfX[4] = cx - kCkRADW / 2; L->surfY[4] = vy + viewH;
L->surfW[4] = kCkRADW; L->surfH[4] = kCkRADH;
// Comm TR
L->surfX[5] = vx + viewW - kCkOVL; L->surfY[5] = vy - kCkMFDH + kCkOVL;
L->surfW[5] = kCkMFDW; L->surfH[5] = kCkMFDH;
// --- MFD red buttons: 4 top (bankHi-i) + 4 bottom (bankHi-4-i) ---
int slotW = kCkMFDW / 4; // 80
for (int m = 0; m < 5; m++)
{
int s = kCkMfdBank[m].slot, hi = kCkMfdBank[m].bankHi;
int sx = L->surfX[s], sy = L->surfY[s];
for (int i = 0; i < 4; i++)
{
int bx = sx + i * slotW;
// Lamps sit fully OUTSIDE the MFD (a small gap off the edge) so nothing
// occludes them or the DISPLAY/PROGRAM legends -- 4 above, 4 below.
CkPushBtn(L, hi - i, bx, sy - kCkRedGap - kCkRedH, slotW - kCkGap, kCkRedH, 0, 0, 0);
CkPushBtn(L, hi - 4 - i, bx, sy + kCkMFDH + kCkRedGap, slotW - kCkGap, kCkRedH, 0, 0, 0);
}
}
// --- radar yellow rails (6/side) + 4 bottom cells ---
{
int rx = L->surfX[4], ry = L->surfY[4];
int slotH = kCkRADH / 6;
for (int i = 0; i < 6; i++)
{
int y = ry + i * slotH;
CkPushBtn(L, 0x10 + i, rx - kCkLamp, y, kCkLamp + kCkRailW, slotH - kCkGap, 1, 0, 0);
CkPushBtn(L, 0x18 + i, rx + kCkRADW - kCkRailW, y, kCkRailW + kCkLamp, slotH - kCkGap, 1, 0, 0);
}
static const int bottomAddr[4] = { 0x16, 0x17, 0x1F, 0x1E };
int botLeft = rx + kCkRailW, botSpan = kCkRADW - 2 * kCkRailW, botW = botSpan / 4;
for (int i = 0; i < 4; i++)
CkPushBtn(L, bottomAddr[i], botLeft + i * botW, ry + kCkRADH - 14, botW - kCkGap, 14 + kCkLamp, 1, 0, 0);
}
// --- flight blue blocks: THROTTLE/AUX (0x38-0x3F) under Mfd1, JOYSTICK
// (0x40-0x47) under Mfd3 -- two 4x2 grids, fully visible + labeled ---
{
static const char *thrLabel[8] = { 0, 0, 0, 0, 0, "Panic", 0, "Throttle" }; // 0x38..0x3F
static const int thrInert[8] = { 1, 1, 1, 1, 1, 0, 1, 0 };
static const char *joyLabel[8] = { "Main", "Hat Bk", "Hat Up", "Hat R",
"Hat L", "Pinky", "Middle", "Upper" }; // 0x40..0x47
const int cw = 68, ch = 30, g = 4;
int blockW = 4 * cw + 3 * g; // 284
int belowLamp = kCkMFDH + kCkRedGap + kCkRedH + 8; // clear the MFD's bottom red lamps
int thrX = L->surfX[2], thrY = L->surfY[2] + belowLamp;
int joyX = L->surfX[3] + kCkMFDW - blockW, joyY = L->surfY[3] + belowLamp;
for (int i = 0; i < 8; i++)
{
int c = i % 4, r = i / 4;
CkPushBtn(L, 0x38 + i, thrX + c * (cw + g), thrY + r * (ch + g), cw, ch, 2,
thrInert[i], thrLabel[i] ? thrLabel[i] : "");
CkPushBtn(L, 0x40 + i, joyX + c * (cw + g), joyY + r * (ch + g), cw, ch, 2,
0, joyLabel[i]);
}
}
}
//===========================================================================//
// 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 rotateCCW)
{
int w = pixelBuffer.Data.Size.x; // 640
int h = pixelBuffer.Data.Size.y; // 480
if (device == NULL || slot < 0 || slot >= 10 || 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.
// rotateCCW: the pod's SECONDARY screen was a physically ROTATED portrait
// CRT -- the game authors its content sideways in the landscape buffer and
// the cabinet monitor unrotated it. On the dev panel WE unrotate: display
// the texture turned 90 degrees so the radar/secondary reads upright.
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 },
};
if (rotateCCW == 1) // screen corner <- texture corner, turned CCW
{
quad[0].u = 1.0f; quad[0].v = 0.0f; // TL <- TR
quad[1].u = 1.0f; quad[1].v = 1.0f; // TR <- BR
quad[2].u = 0.0f; quad[2].v = 1.0f; // BR <- BL
quad[3].u = 0.0f; quad[3].v = 0.0f; // BL <- TL
}
else if (rotateCCW == 3) // the other direction (CW), env-selectable
{
quad[0].u = 0.0f; quad[0].v = 1.0f; // TL <- BL
quad[1].u = 0.0f; quad[1].v = 0.0f; // TR <- TL
quad[2].u = 1.0f; quad[2].v = 0.0f; // BR <- TR
quad[3].u = 1.0f; quad[3].v = 1.0f; // BL <- BR
}
device->SetTexture(0, tex);
device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
// LINEAR sampling: the cells scale the 8-bit surfaces (sec runs 0.75x at
// scale 1.0); point sampling drops the radar's 1px strokes entirely.
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
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));
}
//===========================================================================//
// GLASS per-display windows -- the CPU (no-D3D) analog of DrawDevSurface: expand
// one bit-plane of the shared gauge pixelBuffer into a 32-bit BGRA image that the
// GDI window blits with StretchDIBits (L4GLASSWIN.cpp). The rotation the D3D path
// did via texture-UV remap is baked in here by transposing into `dst`.
//===========================================================================//
void SVGA16::ExpandPlaneToBGRA(int mask, int paletteID, int monoTint, int rotateQuadrant,
unsigned long *dst, int *outW, int *outH)
{
int w = pixelBuffer.Data.Size.x; // 640
int h = pixelBuffer.Data.Size.y; // 480
if (dst == NULL || w <= 0 || h <= 0)
{
if (outW) *outW = 0;
if (outH) *outH = 0;
return;
}
Word *base = pixelBuffer.Data.MapPointer;
SVGA16Palette *pal = &palette[paletteID];
if (rotateQuadrant == 0)
{
// Native orientation, top-down straight copy.
for (int y = 0; y < h; y++)
{
Word *src = base + y * w;
unsigned long *d = dst + y * w;
for (int x = 0; x < w; x++)
{
Word s = src[x];
if (monoTint < 0)
{
PaletteTriplet *pe = &(pal->paletteData.Color[s & mask]);
d[x] = ((unsigned long)pe->Red << 16) |
((unsigned long)pe->Green << 8) | (unsigned long)pe->Blue;
}
else
{
d[x] = (s & mask) ? (unsigned long)monoTint : 0UL;
}
}
}
if (outW) *outW = w;
if (outH) *outH = h;
return;
}
// 90-degree rotation: output is transposed (ow = h, oh = w). rotate 3 = CW,
// rotate 1 = CCW (the DrawDevSurface convention; BT_GAUGE_SEC_ROT picks it).
int ow = h, oh = w;
for (int oy = 0; oy < oh; oy++)
{
unsigned long *d = dst + oy * ow;
for (int ox = 0; ox < ow; ox++)
{
int sx, sy;
if (rotateQuadrant == 3) // 90 CW: out(ox,oy) = src(oy, h-1-ox)
{
sx = oy;
sy = h - 1 - ox;
}
else // 90 CCW: out(ox,oy) = src(w-1-oy, ox)
{
sx = w - 1 - oy;
sy = ox;
}
Word s = base[sy * w + sx];
if (monoTint < 0)
{
PaletteTriplet *pe = &(pal->paletteData.Color[s & mask]);
d[ox] = ((unsigned long)pe->Red << 16) |
((unsigned long)pe->Green << 8) | (unsigned long)pe->Blue;
}
else
{
d[ox] = (s & mask) ? (unsigned long)monoTint : 0UL;
}
}
}
if (outW) *outW = ow;
if (outH) *outH = oh;
}
//
// 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
int rotateCCW; // 1 = unrotate (portrait secondary CRT)
};
// PANEL LAYOUT (2026-07-12 rework): the old 3x2 equal grid DOWNSCALED every
// 640x480 surface into a 320x192 cell (blurry) and showed the SECONDARY
// (radar) sideways -- on the pod that screen was a physically ROTATED
// portrait CRT. New layout, logical 1320x480: a 2x2 block of mono MFDs on
// the left at 320x240 (correct 4:3), the secondary UNROTATED in a portrait
// 360x480 cell in the middle, Comm top-right. Scale the whole window with
// BT_GAUGE_SCALE (e.g. 1.5) for more pixels -- content is a 1995 8-bit
// buffer, so past ~1.5x you magnify, not sharpen.
static const float kBTPanelW = 1320.0f;
static const float kBTPanelH = 480.0f;
// Gitea #9: each preset-able MFD is TWO bit-planes sharing one physical
// monitor -- the base Quad plane (Mfd1/2/3) and the engineering-page plane
// (Eng1/2/3). The mode-driven `reconfigure` swaps which of the pair is
// channel-enabled and which is BlankColor; the draw loop below skips the
// blanked plane, so the dev cell shows exactly what the pod monitor shows.
// The Eng entries share their sibling's cell rect and FOLLOW it in the list.
static const BTGaugeSurfaceDesc kBTGaugeSurfaces[9] =
{
{ "Heat", 0xFFFF, 0.0f / kBTPanelW, 0.0f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Mfd2", 0xFFFF, 320.0f / kBTPanelW, 0.0f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Mfd1", 0xFFFF, 0.0f / kBTPanelW, 0.5f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Mfd3", 0xFFFF, 320.0f / kBTPanelW, 0.5f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "sec", -1, 640.0f / kBTPanelW, 0.0f, 360.0f / kBTPanelW, 1.0f, 1 },
{ "Comm", 0xFFFF, 1000.0f / kBTPanelW, 0.0f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Eng2", 0xFFFF, 320.0f / kBTPanelW, 0.0f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Eng1", 0xFFFF, 0.0f / kBTPanelW, 0.5f, 320.0f / kBTPanelW, 0.5f, 0 },
{ "Eng3", 0xFFFF, 320.0f / kBTPanelW, 0.5f, 320.0f / kBTPanelW, 0.5f, 0 },
};
//
// 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;
// DEVICE-STATE ISOLATION (the "floating cavern rocks" bug): the per-surface
// quad draw disables Z (D3DRS_ZENABLE=FALSE), culling and lighting, binds a
// pre-transformed FVF and rewrites texture stage 0 -- and the world pass
// does NOT re-assert these each frame, so the NEXT frame's world rendered
// WITHOUT DEPTH TESTING (geometry resolved in submission order; rock
// columns drew "floating / unconnected"). Snapshot the whole device state
// and restore it after the composite -- dev-only path, cost irrelevant.
IDirect3DStateBlock9 *stateBlock = NULL;
device->CreateStateBlock(D3DSBT_ALL, &stateBlock);
// DOCK-BOTTOM: the world pass restricted the viewport to the top region;
// the strip's pretransformed quads land BELOW it and would be clipped.
// Draw with the FULL target viewport (the captured state block restores
// the world viewport afterwards).
{
IDirect3DSurface9 *rt = NULL;
if (SUCCEEDED(device->GetRenderTarget(0, &rt)) && rt != NULL)
{
D3DSURFACE_DESC d;
rt->GetDesc(&d);
rt->Release();
D3DVIEWPORT9 vp = { 0, 0, d.Width, d.Height, 0.0f, 1.0f };
device->SetViewport(&vp);
}
}
// 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 < 9; 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
// Gitea #9: honor the live mode-driven `reconfigure` -- a mono plane
// whose channel is currently BlankColor contributes nothing on the pod
// monitor (its palette bits translate to black), so skip it; its
// non-blank sibling (Mfd<n> or Eng<n>, same cell rect) draws instead.
if (d.monoTint >= 0 && port->GetEnableID() == L4GraphicsPort::BlankColor)
continue;
// Secondary-CRT unrotation direction is env-flippable (BT_GAUGE_SEC_ROT=3
// for the other way) in case the assumed pod mounting is mirrored.
int rot = d.rotateCCW;
if (rot != 0)
{
static int s_secRot = -1;
if (s_secRot < 0)
{
// Default 3 (CW): user-verified upright (the first guess, 1,
// showed the secondary upside down). Env still overrides.
const char *rv = getenv("BT_GAUGE_SEC_ROT");
s_secRot = (rv != NULL && rv[0] == '1') ? 1 : 3;
}
rot = s_secRot;
}
svga->DrawDevSurface(
device, i, port->GetBitMask(), port->paletteID, d.monoTint,
px + d.cellX * pw, py + d.cellY * ph, d.cellW * pw, d.cellH * ph, rot);
}
if (stateBlock != NULL)
{
stateBlock->Apply();
stateBlock->Release();
}
}
//===========================================================================//
// COCKPIT SURROUND -- draw the surround bands + gauge panels + button lamps over
// the CENTERED world view. Hooked into BTDrawGaugeInset (before BT_SHOT), so it
// draws into the main backbuffer and screenshots include it. Mirrors
// BTDrawGaugeSurfaces' device-state isolation (the "floating cavern rocks" trap).
//===========================================================================//
// Shared click state (also written by BTCockpitMouseDown/Up below).
static int gCkPressed = -1;
static unsigned char gCkLatched[128] = { 0 };
// The mono MFD phosphor tint (R5G6B5); default green, env BT_COCKPIT_TINT=RRGGBB.
static int CkTint()
{
static int t = -1;
if (t < 0)
{
const char *e = getenv("BT_COCKPIT_TINT");
if (e != NULL && strlen(e) >= 6)
{
unsigned int rgb = (unsigned int)strtoul(e, NULL, 16);
int r = (rgb >> 16) & 0xFF, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
t = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
}
else
t = 0x27E8; // ~rgb(33,255,66) phosphor green
}
return t;
}
// Glass-only RIO seam: lamp state feeds the draw; a click emits a button. No-op
// (dim / ignored) in a pod build, where PadRIO isn't compiled.
static int CkLampState(int addr)
{
#ifdef BT_GLASS
return PadRIO::GetLampState(addr);
#else
(void)addr; return 0;
#endif
}
// Colored-quad (untextured DIFFUSE) draw state -- set once, then CkFill per rect.
static void CkColorState(LPDIRECT3DDEVICE9 dev)
{
dev->SetTexture(0, NULL);
dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
dev->SetRenderState(D3DRS_ZENABLE, FALSE);
dev->SetRenderState(D3DRS_LIGHTING, FALSE);
dev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
}
static void CkFill(LPDIRECT3DDEVICE9 dev, int x, int y, int w, int h, D3DCOLOR c)
{
if (w <= 0 || h <= 0) return;
struct V { float x, y, z, rhw; D3DCOLOR c; };
float fx = (float)x, fy = (float)y, fw = (float)w, fh = (float)h;
V q[4] = {
{ fx, fy, 0.0f, 1.0f, c },
{ fx + fw, fy, 0.0f, 1.0f, c },
{ fx + fw, fy + fh, 0.0f, 1.0f, c },
{ fx, fy + fh, 0.0f, 1.0f, c },
};
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, q, sizeof(V));
}
// Lamp fill + border for a button, from the glass PaintGlass color ramps.
static void CkLampColors(int colorClass, int shade, int inert, D3DCOLOR *fill, D3DCOLOR *border)
{
if (colorClass == 1) // yellow (radar)
{
*border = D3DCOLOR_XRGB(245, 210, 60);
*fill = (shade == 3) ? D3DCOLOR_XRGB(245, 210, 60)
: (shade != 0) ? D3DCOLOR_XRGB(140, 118, 38)
: D3DCOLOR_XRGB(70, 60, 24);
}
else if (colorClass == 2) // blue (flight)
{
if (inert)
{
*border = D3DCOLOR_XRGB(90, 100, 122);
*fill = D3DCOLOR_XRGB(44, 48, 58);
return;
}
*border = D3DCOLOR_XRGB(205, 228, 255);
*fill = (shade == 3) ? D3DCOLOR_XRGB(205, 228, 255)
: (shade != 0) ? D3DCOLOR_XRGB(110, 135, 180)
: D3DCOLOR_XRGB(70, 86, 120);
}
else // red (MFD)
{
*border = D3DCOLOR_XRGB(230, 70, 70);
*fill = (shade == 3) ? D3DCOLOR_XRGB(230, 70, 70)
: (shade != 0) ? D3DCOLOR_XRGB(120, 50, 50)
: D3DCOLOR_XRGB(64, 40, 40);
}
}
// Lazy GDI-baked label textures (MANAGED A8R8G8B8, survive device reset) for the
// blue flight blocks -- keyed by string. ~16 short strings.
struct CkLabelTex { char str[16]; LPDIRECT3DTEXTURE9 tex; int w, h; };
static CkLabelTex gCkLabels[32];
static int gCkLabelCount = 0;
static HFONT gCkFont = NULL;
static LPDIRECT3DTEXTURE9 CkGetLabel(LPDIRECT3DDEVICE9 dev, const char *str, int *ow, int *oh)
{
for (int i = 0; i < gCkLabelCount; i++)
if (strcmp(gCkLabels[i].str, str) == 0)
{ if (ow) *ow = gCkLabels[i].w; if (oh) *oh = gCkLabels[i].h; return gCkLabels[i].tex; }
if (gCkLabelCount >= 32) return NULL;
if (gCkFont == NULL)
gCkFont = CreateFontA(-11, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET,
0, 0, ANTIALIASED_QUALITY, 0, "Segoe UI");
HDC dc = CreateCompatibleDC(NULL);
HFONT oldFont = (HFONT)SelectObject(dc, gCkFont);
SIZE sz; GetTextExtentPoint32A(dc, str, (int)strlen(str), &sz);
int tw = sz.cx + 2, th = sz.cy + 2;
if (tw < 1) tw = 1;
if (th < 1) th = 1;
BITMAPINFO bmi; memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = tw; bmi.bmiHeader.biHeight = -th; // top-down
bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB;
void *bits = NULL;
HBITMAP dib = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
HBITMAP oldBm = (HBITMAP)SelectObject(dc, dib);
RECT r = { 0, 0, tw, th };
FillRect(dc, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
SetBkMode(dc, TRANSPARENT);
SetTextColor(dc, RGB(255, 255, 255));
TextOutA(dc, 1, 1, str, (int)strlen(str));
GdiFlush();
LPDIRECT3DTEXTURE9 tex = NULL;
dev->CreateTexture(tw, th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &tex, NULL);
if (tex != NULL && bits != NULL)
{
D3DLOCKED_RECT lr;
if (SUCCEEDED(tex->LockRect(0, &lr, NULL, 0)))
{
for (int y = 0; y < th; y++)
{
unsigned long *s = (unsigned long*)bits + y * tw;
unsigned long *d = (unsigned long*)((char*)lr.pBits + y * lr.Pitch);
for (int x = 0; x < tw; x++)
d[x] = ((s[x] & 0xFF) << 24) | 0x00FFFFFF; // A = text luminance, RGB white
}
tex->UnlockRect(0);
}
}
SelectObject(dc, oldBm);
DeleteObject(dib);
SelectObject(dc, oldFont);
DeleteDC(dc);
CkLabelTex &e = gCkLabels[gCkLabelCount++];
strncpy(e.str, str, 15); e.str[15] = 0; e.tex = tex; e.w = tw; e.h = th;
if (ow) *ow = tw; if (oh) *oh = th;
return tex;
}
static void CkDrawLabel(LPDIRECT3DDEVICE9 dev, int cx, int cy, const char *str, D3DCOLOR color)
{
if (str == NULL || str[0] == 0) return;
int tw = 0, th = 0;
LPDIRECT3DTEXTURE9 tex = CkGetLabel(dev, str, &tw, &th);
if (tex == NULL) return;
float x = (float)(cx - tw / 2), y = (float)(cy - th / 2);
struct V { float x, y, z, rhw; D3DCOLOR c; float u, v; };
V q[4] = {
{ x, y, 0.0f, 1.0f, color, 0.0f, 0.0f },
{ x + (float)tw, y, 0.0f, 1.0f, color, 1.0f, 0.0f },
{ x + (float)tw, y + (float)th, 0.0f, 1.0f, color, 1.0f, 1.0f },
{ x, y + (float)th, 0.0f, 1.0f, color, 0.0f, 1.0f },
};
dev->SetTexture(0, tex);
dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
dev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
dev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); // label color
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); // text mask
dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, q, sizeof(V));
}
void BTDrawCockpitPanels(LPDIRECT3DDEVICE9 device)
{
if (device == NULL) return;
IDirect3DSurface9 *rt = NULL;
if (FAILED(device->GetRenderTarget(0, &rt)) || rt == NULL) return;
D3DSURFACE_DESC dsc; rt->GetDesc(&dsc); rt->Release();
BTCockpitLayout L;
BTCockpitComputeLayout((int)dsc.Width, (int)dsc.Height, &L);
// DEVICE-STATE ISOLATION (floating cavern rocks): snapshot + restore.
IDirect3DStateBlock9 *sb = NULL;
device->CreateStateBlock(D3DSBT_ALL, &sb);
// Full-target viewport (the world viewport was centered; our quads span the canvas).
D3DVIEWPORT9 vp = { 0, 0, dsc.Width, dsc.Height, 0.0f, 1.0f };
device->SetViewport(&vp);
// 1) Surround bands (dark) AROUND the view -- the engine Clear never covers
// them, and the gauge renderer may not be up yet, so fill unconditionally.
CkColorState(device);
D3DCOLOR band = D3DCOLOR_XRGB(6, 7, 9);
CkFill(device, 0, 0, L.canvasW, L.viewY, band); // top
CkFill(device, 0, L.viewY + L.viewH, L.canvasW, L.canvasH - (L.viewY + L.viewH), band); // bottom
CkFill(device, 0, L.viewY, L.viewX, L.viewH, band); // left
CkFill(device, L.viewX + L.viewW, L.viewY, L.canvasW - (L.viewX + L.viewW), L.viewH, band); // right
// 2) Button lamp faces (UNDER the surfaces -- only the protruding edge shows).
unsigned long tick = GetTickCount();
for (int i = 0; i < L.buttonCount; i++)
{
const BTCockpitBtn &b = L.buttons[i];
int shade = BTLampBrightnessOf(CkLampState(b.address), tick);
if (gCkPressed == b.address || gCkLatched[b.address & 0x7F]) shade = 3;
D3DCOLOR fill, border;
CkLampColors(b.colorClass, shade, b.inert, &fill, &border);
CkFill(device, b.x, b.y, b.w, b.h, border);
CkFill(device, b.x + 1, b.y + 1, b.w - 2, b.h - 2, fill);
}
// 3) Gauge surfaces on top (green-tinted mono / palette sec). Reuses the
// 9-entry loop shape + BlankColor skip of BTDrawGaugeSurfaces; the Eng1-3
// planes share their sibling's dest cell (ckSlotOf).
GaugeRenderer *gr = BTResolveGaugeRenderer();
if (gr != NULL)
{
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)
{
static const int ckSlotOf[9] = { 0, 1, 2, 3, 4, 5, 1, 2, 3 };
int tint = CkTint();
for (int i = 0; i < 9; i++)
{
const BTGaugeSurfaceDesc &d = kBTGaugeSurfaces[i];
L4GraphicsPort *port = static_cast<L4GraphicsPort*>(gr->GetGraphicsPort(d.portName));
if (port == NULL) continue;
if (d.monoTint >= 0 && port->GetEnableID() == L4GraphicsPort::BlankColor) continue;
int rot = d.rotateCCW;
if (rot != 0)
{
static int s_secRot = -1;
if (s_secRot < 0) { const char *rv = getenv("BT_GAUGE_SEC_ROT"); s_secRot = (rv != NULL && rv[0] == '1') ? 1 : 3; }
rot = s_secRot;
}
int surf = ckSlotOf[i];
int useTint = (d.monoTint < 0) ? -1 : tint;
svga->DrawDevSurface(device, i, port->GetBitMask(), port->paletteID, useTint,
(float)L.surfX[surf], (float)L.surfY[surf], (float)L.surfW[surf], (float)L.surfH[surf], rot);
}
}
}
// 4) Flight-block labels (on top; the blue faces aren't covered by surfaces).
for (int i = 0; i < L.buttonCount; i++)
{
const BTCockpitBtn &b = L.buttons[i];
if (b.label == NULL || b.label[0] == 0) continue;
D3DCOLOR lc = b.inert ? D3DCOLOR_ARGB(255, 120, 128, 145) : D3DCOLOR_ARGB(255, 0, 0, 0);
CkDrawLabel(device, b.x + b.w / 2, b.y + b.h / 2, b.label, lc);
}
if (sb != NULL) { sb->Apply(); sb->Release(); }
}
// Glass-only RIO emit: a cockpit click injects a button edge through PadRIO's
// static entry (safe no-op if no PadRIO -- pod build never links it).
static void CkEmit(int addr, int pressed)
{
#ifdef BT_GLASS
PadRIO::SetScreenButton(addr, pressed);
#else
(void)addr; (void)pressed;
#endif
}
// Mouse routing (main-window WndProc -> here). Client coords are mapped into the
// fixed backbuffer canvas; hit-test the FULL button rects; mirror the L4GLASSWIN
// GlassWndProc contract (left = press / unlatch-if-latched; right = latch toggle).
// Returns 1 when a button was hit (the caller SetCaptures on a left press).
int BTCockpitMouseDown(int cx, int cy, int clientW, int clientH, int rightButton)
{
if (!gBTGaugeCockpit) return 0;
int bbW = gBTCockpitCanvasW, bbH = gBTCockpitCanvasH;
if (bbW <= 0 || bbH <= 0 || clientW <= 0 || clientH <= 0) return 0;
int bx = cx * bbW / clientW;
int by = cy * bbH / clientH;
BTCockpitLayout L;
BTCockpitComputeLayout(bbW, bbH, &L);
int a = -1;
for (int i = 0; i < L.buttonCount; i++)
{
const BTCockpitBtn &b = L.buttons[i];
if (bx >= b.x && bx < b.x + b.w && by >= b.y && by < b.y + b.h) { a = b.address; break; }
}
if (a < 0) return 0;
// Crash forensics (always-on, flushed BEFORE dispatch): a click that kills the
// process leaves its address as the last log line (the Gitea #18 pattern).
DEBUG_STREAM << "[cockpit] CLICK addr=0x" << std::hex << a << std::dec
<< " at(" << bx << "," << by << ")"
<< (rightButton ? " latch-toggle"
: (gCkLatched[a & 0x7F] ? " unlatch" : " press"))
<< "\n" << std::flush;
if (rightButton)
{
gCkLatched[a & 0x7F] = gCkLatched[a & 0x7F] ? 0 : 1;
CkEmit(a, gCkLatched[a & 0x7F]);
return 1;
}
if (gCkLatched[a & 0x7F])
{
gCkLatched[a & 0x7F] = 0;
CkEmit(a, 0);
return 0; // released -- no capture needed
}
gCkPressed = a;
CkEmit(a, 1);
return 1; // pressed -- caller SetCaptures for release-outside
}
void BTCockpitMouseUp(void)
{
if (gCkPressed >= 0)
{
CkEmit(gCkPressed, 0);
gCkPressed = -1;
}
}
//
// 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;
if (GlassPanelsOwnSurfaces()) return; // the per-display glass windows draw the surfaces
if (gBTGaugeCockpit)
{
// COCKPIT SURROUND: draw the surround bands + panels + button lamps over
// the centered world view (captured before BT_SHOT, so shots include it).
BTDrawCockpitPanels(device);
return;
}
if (gBTGaugeDockBottom)
{
// DOCK-BOTTOM: the strip owns the bottom band of the target (the world
// viewport excludes it) -- full width, design-aspect height.
IDirect3DSurface9 *rt = NULL;
if (FAILED(device->GetRenderTarget(0, &rt)) || rt == NULL) return;
D3DSURFACE_DESC d;
rt->GetDesc(&d);
rt->Release();
float stripH = (float)BTGaugeStripHeightFor((int)d.Width);
if (stripH <= 0.0f || stripH >= (float)d.Height) return;
BTDrawGaugeSurfaces(device, 0.0f, (float)d.Height - stripH,
(float)d.Width, stripH);
return;
}
// Legacy overlay dock (BT_DEV_GAUGES_DOCK): fixed inset over the 3D view.
// Keep the panel's 1320:480 aspect (2.75) so nothing distorts.
BTDrawGaugeSurfaces(device, 2.0f, 400.0f, 540.0f, 540.0f / 2.75f);
}
//===========================================================================//
// 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;
// Window = the logical 1320x480 panel (see kBTGaugeSurfaces) x BT_GAUGE_SCALE.
// Resolved once at first ensure; default 1.0 (surfaces at/near native pixels).
static int s_gaugeW = 1320;
static int s_gaugeH = 480;
static bool s_gaugeSized = false;
static void BTGaugeResolveSize()
{
if (s_gaugeSized) return;
s_gaugeSized = true;
const char *sv = getenv("BT_GAUGE_SCALE");
float scale = (sv != NULL) ? (float)atof(sv) : 1.0f;
if (scale < 0.5f || scale > 3.0f) scale = 1.0f;
s_gaugeW = (int)(1320.0f * scale);
s_gaugeH = (int)(480.0f * scale);
}
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
// Fully-WIDE window (class + create + proc all W; the class/create below
// are RegisterClassW/CreateWindowExW): mixed A/W pairings mangled the
// title -- A-class + W-proc painted the ANSI bytes as UTF-16 (CJK-looking
// mojibake), W-class + A-proc truncated at the first thunked NUL ("B").
// One consistent character set ends the thunk roulette.
return DefWindowProcW(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;
BTGaugeResolveSize(); // BT_GAUGE_SCALE -> window dims
HINSTANCE hInst = GetModuleHandle(NULL);
static bool s_classReg = false;
if (!s_classReg)
{
// WIDE APIs throughout: this TU compiles UNICODE, so BTGaugeWndProc's
// DefWindowProc resolves to the W variant -- registering the class
// with RegisterClassA made Windows reinterpret the ANSI title bytes
// as UTF-16 (the "Korean garbage title" bug: byte-pairs of
// "BattleTech - Cockpit MFDs" land in the CJK plane, only the
// trailing 's'+NUL survives readable).
WNDCLASSW 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 = L"BTGaugeWnd";
RegisterClassW(&wc);
s_classReg = true;
}
if (s_gaugeHwnd == NULL)
{
RECT r = { 0, 0, s_gaugeW, s_gaugeH };
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
// Window identity (MP dev): tag with the -net port so two side-by-side
// nodes' MFD windows are distinguishable (matches the main window tag).
wchar_t gaugeTitle[64];
{
int netPort = 0;
const char *cmd = GetCommandLineA();
const char *np = (cmd != NULL) ? strstr(cmd, "-net") : NULL;
if (np != NULL)
sscanf(np + 4, " %d", &netPort);
if (netPort > 0)
swprintf(gaugeTitle, 64, L"BattleTech MFDs \x2014 node %d", netPort);
else
wcscpy(gaugeTitle, L"BattleTech - Cockpit MFDs");
}
s_gaugeHwnd = CreateWindowExW(
0, L"BTGaugeWnd", gaugeTitle, 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 (GlassPanelsOwnSurfaces()) return; // the per-display glass windows draw the surfaces
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 < 10; _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();
}