Files
BT411/engine/MUNGA_L4/L4VB16.cpp
T
arcattackandClaude Fable 5 48c9c8444f Fire VISUALS wave: the authored firesmoke sheet, vertex-alpha effect cards, the case-4 wreck dressing
The "fireballs like the demo vids" arc, decomp/content-grounded end to end,
plus the live-play UX batch verified over the same sessions:

FIRESMOKE SHEET (the PFX fireball fix): every firesmokeN_scr_tex in BTFX.VMF
maps the SAME 64x64 tileable noise image bintA (variants differ only in SCROLL
rate) and firesmoke1_mtl colours it through the "fiery" ramp (0.3,0.1,0.1)->
(0.9,0.7,0.3).  The particle layer now bakes ramp(lum(bintA)) as its sprite
colour (noise detail in alpha) and SCROLLS it at firesmoke1's authored rate
via a texture-transform; the port's radial soft-edge mask moved to a second
CLAMPed stage so the WRAPPED scroll rolls flame through the sprite without
scrolling the edge away.  Old grit x radial bake kept as the no-BINTA fallback.
Impact hits, damage-band smoke and death booms all ride this layer.

AUTHORED TEXTURE SCROLL in the model path: the BMF TEXTURE records carry
SPECIAL " SCROLL u0 v0 du dv" (tag 0x2037); the draw path always supported
per-op scrolling (SetTextureScrolling) but the BGF loader never parsed it, so
every scrolling material rendered frozen.  Wired TexRef -> MatInfo -> batch ->
L4TEXOP.doScroll: the flame cards (flamebig/fire5) now roll fire noise.

VERTEX-ALPHA EFFECT CARDS (the "twisted drill bit of fire" fix): FLAMEBIG's
verts carry authored float RGBA -- white-hot base (1.0,0.99,0.97) -> dark-red
tip fading to alpha -0.2 (the DPL clamp convention).  The loader kept a flat
batch colour and drew it OPAQUE = a solid orange spike.  Corpus sweep: exactly
14 shipped BGFs carry vertex alpha, ALL effect cards (flames, MUZFLASH,
EXDISK_A/B/C, TMST_A/B/C, beam models, DECLOUDS).  Such batches now keep the
authored per-vertex gradient and route to the alpha-blend pass, unlit,
colour = texture x gradient, alpha = the vertex fade; sky objects excluded
(drawAsSky + alphaTest passes NEITHER pass filter -- DECLOUDS stays in the
sky pass).  MUZFLASH/EXDISK render correctly for free when the muzzle-model
work lands.

WRECK DRESSING (the 1996 ExplosionScripts case-4 transcription): pieces spawn
HIDDEN and reveal 0.25s after the boom (the InstanceSwitch delay, behind the
dnboom flash); flamebig hangs over the pile, Y-BILLBOARDED at the camera
(SetOffsetYaw + a camera-pos getter -- the dpl_SetDCSReorientAxes analog);
the MakeDCSFall settle arms at the reveal with the two authored rates (hulk/
debris -0.025 t^2, fires -0.01 t^2 -- the flames ride above the sinking pile
and die with it at burial).  EMPTY-PLACEHOLDER hulk guard: THRDBR.BGF is a
153-byte zero-geometry stub that "loads fine" -- vertex-count check now routes
it to the gendbr fallback (a Thor wreck was invisible).  Hulk content census
recorded: AVADBR==MADDBR==VULDBR geometry (palette-only prefix diffs),
RAPDBR==SNDDBR==STIDBR byte-identical -- wreck variety is materials + the
dressing, not unique piles.

LIVE-PLAY BATCH: muzzle resolve uses the named segmentIndex (raw +0xdc read
was layout garbage); forward launch frame (authored MuzzleVelocity +Z vs the
mech's -Z facing); dock-bottom single window (gauge strip appended below the
world viewport, 1100x600 default, BT_DEV_GAUGES_WINDOW=1 restores the separate
window); portrait sec surface unrotated CW; ammo counters live via typed
bridges (BTAmmoBinCountPtr/BTAmmoBinFeeding/BTWeaponAmmoBin -- raw bin+0x180
and a hand-rolled link walk were garbage); fourth fire key ('4' = Pinky);
panel/arc probes de-aliased (%61 prime).

KB: rendering.md (vertex-alpha card family + scroll), combat-damage.md (hulk
census + THRDBR stub), gauges-hud.md (ammo bridges).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 20:04:29 -05:00

6450 lines
155 KiB
C++

#include "mungal4.h"
#pragma hdrstop
#include "l4vb16.h"
#include "../munga/gaugrend.h"
#include "L4VIDEO.h"
#include "DXUtils.h"
#if defined(TRACE_SCREEN_COPY)
static BitTrace Screen_Copy("Screen Copy");
#define SET_SCREEN_COPY() Screen_Copy.Set()
#define CLEAR_SCREEN_COPY() Screen_Copy.Clear()
#else
#define SET_SCREEN_COPY()
#define CLEAR_SCREEN_COPY()
#endif
#define BLIT_STATISTICS
#if defined(BLIT_STATISTICS)
static int
dirtyPixelCount,
transferPixelCount,
overflowPixelCount;
#endif
//#define DEBUG
#if defined(DEBUG)
static Logical
printFlag=True;
# define Diag_on printFlag=True
# define Diag_off printFlag=False
# define Diag_Tell(stuff) if(printFlag){std::cout << stuff;}
#else
# define Diag_on
# define Diag_off
# define Diag_Tell(n)
#endif
//STUBBED: VIDEO RB 1/15/07
//extern "C" void
// SVGASetMode(
// int mode,
// LWord pageFlipFcnpointer
// );
//
//extern "C" void
// SVGASetPage(
// int page
// );
//
//extern "C" int
// SVGATransfer32(
// int dest_offset,
// Word *source_pointer,
// LWord changed_bits
// );
//
//extern "C" int
// SVGATransfer32x(
// int dest_offset,
// Word *source_pointer,
// LWord changed_bits
// );
//
//extern "C" void
// SVGASetSplitterClock(
// Logical state
// );
//
//extern "C" void
// SVGAZeroPalette(
// Word DAC_port
// );
//
//extern "C" void
// SVGAWriteFullPalette(
// Byte *firstColorByte,
// Word DAC_port
// );
//
//extern "C" void
// SVGAReadFullPalette(
// Byte *firstColorByte,
// Word DAC_port
// );
//
//extern "C" void
// SVGAWritePaletteMask(
// Word DAC_port,
// Byte new_mask
// );
//
//extern "C" void
// SVGAFunkyVideo(
// Logical on_off
// );
// DEV-COMPOSITE (option B): opt-in via BT_DEV_GAUGES. When set, SVGA16 does NO
// per-surface D3D output (no per-adapter devices/windows/present) -- it only holds
// the CPU pixelBuffer the gauge widgets raster into; the MAIN renderer composites
// that buffer as a window inset. The pod multi-surface path is left untouched.
static bool DevGaugeComposite()
{
static int v = -1;
if (v < 0) v = (getenv("BT_DEV_GAUGES") != NULL) ? 1 : 0;
return v != 0;
}
// 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 (!gBTGaugeDockBottom || device == NULL) return;
IDirect3DSurface9 *rt = NULL;
if (FAILED(device->GetRenderTarget(0, &rt)) || rt == NULL) return;
D3DSURFACE_DESC d;
rt->GetDesc(&d);
rt->Release();
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;
}
//===========================================================================//
// 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 >= 8 || w <= 0 || h <= 0) return;
// Lazily create this surface's texture on the MAIN device (MANAGED -> lockable +
// survives device reset).
if (mDevSurfaceTex[slot] == NULL)
device->CreateTexture(w, h, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, &mDevSurfaceTex[slot], NULL);
LPDIRECT3DTEXTURE9 tex = mDevSurfaceTex[slot];
if (tex == NULL) return;
// Extract this surface's bit-plane from the ONE shared pixelBuffer into the texture.
D3DLOCKED_RECT rect;
if (SUCCEEDED(tex->LockRect(0, &rect, NULL, 0)))
{
Word *source = pixelBuffer.Data.MapPointer;
Word *dest = (Word*)rect.pBits;
int postRowIncrement = (rect.Pitch / 2) - w;
if (monoTint < 0)
{
// PALETTE surface (sec/radar) -- palette-LUT expand (== SVGA16::Update case 0).
SVGA16Palette *pal = &palette[paletteID];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
PaletteTriplet *pe = &(pal->paletteData.Color[*source & mask]);
*dest = ((pe->Red >> 3) << 11) | ((pe->Green >> 2) << 5) | (pe->Blue >> 3);
dest++; source++;
}
dest += postRowIncrement;
}
}
else
{
// MONO MFD surface -- single-bit-plane expand to a tint (the reduced core of
// SVGA16::Update cases 1/2; MFD masks are single bits, so no DWORD SIMD/pack).
Word tint = (Word) monoTint;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
*dest = (*source & mask) ? tint : 0;
dest++; source++;
}
dest += postRowIncrement;
}
}
tex->UnlockRect(0);
}
// Draw the surface quad at (dstX,dstY,dstW,dstH) in the current render target.
// 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));
}
//
// 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;
static const BTGaugeSurfaceDesc kBTGaugeSurfaces[6] =
{
{ "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 },
};
//
// 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 < 6; i++)
{
const BTGaugeSurfaceDesc &d = kBTGaugeSurfaces[i];
L4GraphicsPort *port = static_cast<L4GraphicsPort*>(gr->GetGraphicsPort(d.portName));
if (port == NULL) continue; // this surface's port isn't configured -> skip
// 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();
}
}
//
// 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 (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 (!BTGaugeWindowEnsure(device)) return;
IDirect3DSurface9 *gaugeBB = NULL;
if (FAILED(s_gaugeSwap->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &gaugeBB)) || gaugeBB == NULL)
{
// device likely lost -> drop the chain so it recreates next frame
s_gaugeSwap->Release();
s_gaugeSwap = NULL;
return;
}
IDirect3DSurface9 *mainRT = NULL;
device->GetRenderTarget(0, &mainRT);
IDirect3DSurface9 *mainDS = NULL;
device->GetDepthStencilSurface(&mainDS); // may be NULL
device->SetRenderTarget(0, gaugeBB);
// Unbind the main depth-stencil: it is 800x600 but the gauge backbuffer is 960x384
// (wider) -- a bound depth surface smaller than the render target is INVALID and makes
// every draw silently fail. We don't need depth here (Z is disabled per surface quad).
device->SetDepthStencilSurface(NULL);
device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(12, 12, 16), 1.0f, 0);
if (SUCCEEDED(device->BeginScene()))
{
BTDrawGaugeSurfaces(device, 0.0f, 0.0f, (float) s_gaugeW, (float) s_gaugeH);
device->EndScene();
}
if (mainRT != NULL) // restore the main render target + depth for the next frame
{
device->SetRenderTarget(0, mainRT);
mainRT->Release();
}
device->SetDepthStencilSurface(mainDS); // NULL is valid (restores "no depth")
if (mainDS != NULL)
mainDS->Release();
gaugeBB->Release();
if (s_gaugeSwap->Present(NULL, NULL, s_gaugeHwnd, NULL, 0) == D3DERR_DEVICELOST)
{
s_gaugeSwap->Release();
s_gaugeSwap = NULL;
}
}
void SVGA16::BuildWindows(unsigned int width, unsigned int height, bool windowed, int *secondaryIndex, int *aux1Index, int *aux2Index)
{
NUMGAUGEWINDOWS = 0;
if (secondaryIndex != NULL)
{
NUMGAUGEWINDOWS++;
}
if (aux1Index != NULL)
{
NUMGAUGEWINDOWS++;
}
if (aux2Index != NULL)
{
NUMGAUGEWINDOWS++;
}
if (DevGaugeComposite())
{
// DEV COMPOSITE (option B): force the "no D3D output surfaces" path. Do NOT
// create per-surface devices/windows -- FindBestAdapterIndices hands us the
// primary adapter (up to 3x) on a dev box, but a 2nd/3rd fullscreen device
// can't be created there. The base Video16BitBuffered pixelBuffer still
// exists and the widgets raster into it; the main renderer composites it.
NUMGAUGEWINDOWS = 0;
}
if (NUMGAUGEWINDOWS == 0)
{
// (defensive) NULL the per-surface arrays so ~SVGA16 delete[] is safe on the
// no-surface path (they are not allocated below).
gaugeWindows = NULL; mDevice = NULL; mVertBuffers = NULL;
mSurfaces = NULL; mLockFlags = NULL; mPresentParams = NULL; mSurfaceRects = NULL;
return;
}
gaugeWindows = new HWND[NUMGAUGEWINDOWS];
mDevice = new LPDIRECT3DDEVICE9[NUMGAUGEWINDOWS];
mVertBuffers = new LPDIRECT3DVERTEXBUFFER9[NUMGAUGEWINDOWS];
mSurfaces = new LPDIRECT3DTEXTURE9[NUMGAUGEWINDOWS * 2];
mLockFlags = new DWORD[NUMGAUGEWINDOWS];
mPresentParams = new D3DPRESENT_PARAMETERS[NUMGAUGEWINDOWS];
mSurfaceRects = new RECT[NUMGAUGEWINDOWS];
for (int j=0; j < NUMGAUGEWINDOWS; j++)
{
int desiredAdapter = -1;
int adapterIndex = j;
if (secondaryIndex != NULL && adapterIndex >= 0)
{
desiredAdapter = *secondaryIndex;
adapterIndex--;
}
if (aux1Index != NULL && adapterIndex >= 0)
{
desiredAdapter = *aux1Index;
adapterIndex--;
}
if (aux2Index != NULL && adapterIndex >= 0)
{
desiredAdapter = *aux2Index;
adapterIndex--;
}
if (adapterIndex >= 0 || desiredAdapter < 0)
{
break;
}
RECT r;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(gD3D->GetAdapterMonitor(desiredAdapter),&info);
r = info.rcMonitor;
mSurfaceRects[j].left = r.left;
mSurfaceRects[j].top = r.top;
mSurfaceRects[j].right = r.left + ((j==0 || aux2Index != NULL)?width:width*2);
mSurfaceRects[j].bottom = r.top + height;
RECT surfaceWindowRect = mSurfaceRects[j];
AdjustWindowRectEx(&surfaceWindowRect, WS_BORDER, false, 0);
gaugeWindows[j] = CreateWindowEx(0, L"MainWndClass", L"RPL4", WS_BORDER, surfaceWindowRect.left, surfaceWindowRect.top, surfaceWindowRect.right-surfaceWindowRect.left, surfaceWindowRect.bottom-surfaceWindowRect.top, (HWND)NULL, (HMENU)NULL, L4Application::GetAppInstance(), (LPVOID)NULL);
if (gaugeWindows[j])
{
ShowWindow(gaugeWindows[j], SW_SHOW);
memset(&mPresentParams[j], 0, sizeof(D3DPRESENT_PARAMETERS));
mPresentParams[j].BackBufferCount = 1;
mPresentParams[j].SwapEffect = D3DSWAPEFFECT_DISCARD;
mPresentParams[j].hDeviceWindow = gaugeWindows[j];
mPresentParams[j].Flags = 0;
mPresentParams[j].FullScreen_RefreshRateInHz = (windowed)?D3DPRESENT_RATE_DEFAULT:60;
mPresentParams[j].PresentationInterval = D3DPRESENT_RATE_DEFAULT;
mPresentParams[j].BackBufferFormat = D3DFMT_R5G6B5;
//pp.EnableAutoDepthStencil = TRUE;
//pp.AutoDepthStencilFormat = D3DFMT_D24X8;
mPresentParams[j].Windowed = windowed;
if (!windowed)
{
mPresentParams[j].BackBufferWidth = mSurfaceRects[j].right - mSurfaceRects[j].left;
mPresentParams[j].BackBufferHeight = mSurfaceRects[j].bottom - mSurfaceRects[j].top;
}
HRESULT hr = gD3D->CreateDevice(desiredAdapter, D3DDEVTYPE_HAL, ghWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &mPresentParams[j], &mDevice[j]);
if (FAILED(hr))
{
DEBUG_STREAM<<"Couldn't create Direct3D device!"<<std::endl<<std::flush;
PostQuitMessage(1);
// GUARD (platform profile): mDevice[j] is null/uninitialised on
// failure, and the code below (GetDeviceCaps @next line, CreateTexture,
// CreateVertexBuffer) derefs it -> segfault. This is hit when the POD
// profile runs on a box WITHOUT the pod's extra adapters/monitors (a
// second fullscreen gauge device can't be created). PostQuitMessage
// already asked to bail; break so we exit the surface loop cleanly
// instead of crashing. INERT on real pod hardware (CreateDevice
// succeeds there) -- does not change the pod multi-surface behavior.
break;
}
D3DCAPS9 caps;
DWORD usage = 0;
D3DPOOL pool = D3DPOOL_MANAGED;
hr = mDevice[j]->GetDeviceCaps(&caps);
mLockFlags[j] = 0;
hr = mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_SYSTEMMEM, &mSurfaces[j * 2], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create dynamic texture for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
hr = mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[j * 2 + 1], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create dynamic texture for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
hr = mDevice[j]->CreateVertexBuffer(sizeof(float) * 6 * 4, NULL, D3DFVF_XYZRHW | D3DFVF_TEX1, D3DPOOL_MANAGED, &mVertBuffers[j], NULL);
if (FAILED(hr))
{
DEBUG_STREAM << "Couldn't create vertex buffer for display " << j << "!" << std::endl << std::flush;
PostQuitMessage(1);
}
float *buffer;
hr = mVertBuffers[j]->Lock(0, 0, (void**)&buffer, 0);
buffer[0] = 0.0f; // top left, x
buffer[1] = 0.0f; // y
buffer[2] = 0.0f; // z
buffer[3] = 1.0f; // rhw
buffer[4] = 0.0f; // u
buffer[5] = 0.0f; // v
buffer[6] = mSurfaceRects[j].right - mSurfaceRects[j].left; // top right, x
buffer[7] = 0.0f; // y
buffer[8] = 0.0f; // z
buffer[9] = 1.0f; // rhw
buffer[10] = 1.0f; // u
buffer[11] = 0.0f; // v
buffer[12] = mSurfaceRects[j].right - mSurfaceRects[j].left; // bottom right, x
buffer[13] = height; // y
buffer[14] = 0.0f; // z
buffer[15] = 1.0f; // rhw
buffer[16] = 1.0f; // u
buffer[17] = 1.0f, // v
buffer[18] = 0.0f; // bottom left, x
buffer[19] = height; // y
buffer[20] = 0.0f; // z
buffer[21] = 1.0f; // rhw
buffer[22] = 0.0f; // u
buffer[23] = 1.0f; // v
hr = mVertBuffers[j]->Unlock();
mDevice[j]->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
mDevice[j]->SetStreamSource(0, mVertBuffers[j], 0, sizeof(float) * 6);
mDevice[j]->SetTexture(0, mSurfaces[j * 2 + 1]);
mDevice[j]->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 0.0f, 0);
V( mDevice[j]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[j].BackBufferCount;
int bbWidth = mPresentParams[j].BackBufferWidth;
int bbHeight = mPresentParams[j].BackBufferHeight;
mSurfaces[j * 2 + 1]->Release();
V(mDevice[j]->Reset(&mPresentParams[j]));
V(mDevice[j]->CreateTexture(mSurfaceRects[j].right - mSurfaceRects[j].left, height, 1, usage, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[j * 2 + 1], NULL));
mPresentParams[j].BackBufferCount = bbCount;
mPresentParams[j].BackBufferWidth = bbWidth;
mPresentParams[j].BackBufferHeight = bbHeight;
}
}
}
}
//########################################################################
//############################# BitWrangler ##############################
//########################################################################
//
// A "bitwrangler" manages a group of bits by segregating them into two groups:
// "active", and "inactive". Active bits are those specified within a given
// bit mask as "ones", and inactive bits are those specified as "zeros".
//
// Once initialized, the bitwrangler may be requested to increment either
// the active bit field or the inactive bit field: the "carry" is propagated
// from the least significant bit through the most significant bit, and if
// an overflow is generated it is returned as "False".
//
// Why in the world would anyone want such a bizarre object?
// It's used here to generate palettes and translation tables according
// to bit allocations for a GraphicsPort. "Unused" colors are easily
// found and set to proper values.
//
class BitWrangler
{
public:
BitWrangler(int bit_mask, int total_length);
~BitWrangler()
{}
void ResetActive();
void ResetInactive();
Logical IncrementActive();
Logical IncrementInactive();
int NumberOfActiveBits();
int NumberOfInactiveBits();
int Value;
protected:
int length;
int bitMask;
};
//
// Bitwrangler initialization
//
BitWrangler::BitWrangler(int bit_mask, int total_length)
{
Verify(bit_mask != 0);
bitMask = bit_mask;
length = total_length;
Value = 0;
Check_Fpu();
}
//
// Reset all "active" bits to zero
//
void
BitWrangler::ResetActive()
{
Value &= ~ bitMask;
Check_Fpu();
}
//
// Reset all "inactive" bits to zero
//
void
BitWrangler::ResetInactive()
{
Value &= bitMask;
Check_Fpu();
}
//
// Increment the "active" bit field, and return "false" if overflow
//
Logical
BitWrangler::IncrementActive()
{
int single_bit;
int count(length);
for(single_bit=1; count>0; --count, single_bit <<= 1)
{
//
// If it's an active bit, process it
//
if (bitMask & single_bit)
{
//
// Invert the bit
//
Value ^= single_bit;
//
// If the bit is now set, it was zero, so exit
//
if (Value & single_bit)
{
Check_Fpu();
return True;
}
}
}
//
// All the active bits are set, so return false
//
Check_Fpu();
return False;
}
//
// Increment the "inactive" bit field, and return "false" if overflow
//
Logical
BitWrangler::IncrementInactive()
{
int single_bit;
int count(length);
int inverse_mask(~bitMask);
for(single_bit=1; count>0; --count, single_bit <<= 1)
{
//
// If it's an inactive bit, process it
//
if (inverse_mask & single_bit)
{
//
// Invert the bit
//
Value ^= single_bit;
//
// If the bit is now set, it was zero, so exit
//
if (Value & single_bit)
{
Check_Fpu();
return True;
}
}
}
//
// All the inactive bits are set, so return false
//
Check_Fpu();
return False;
}
//
// Return the number of "active" bits
//
int
BitWrangler::NumberOfActiveBits()
{
int count(0), temp(bitMask);
while(temp != 0)
{
++count;
temp = temp & (temp-1);
}
Check_Fpu();
return count;
}
//
// Return the number of "inactive" bits
//
int
BitWrangler::NumberOfInactiveBits()
{
Check_Fpu();
return length-NumberOfActiveBits();
}
//########################################################################
//######################### Video16BitBuffered ###########################
//########################################################################
//
//NOTE: the application assumes that the origin is in the lower left
// corner of the display, and all parameters passed to these routines
// use the application's coordinate system.
//
// All of the methods here convert these values to the SCREEN
// coordinate system, with the origin in the UPPER LEFT corner of
// the display.
//
//===================================================================
// Creator
//===================================================================
Video16BitBuffered::Video16BitBuffered(int x, int y):
GraphicsDisplay(x, y),
pixelBuffer(x, y)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::Video16BitBuffered()\n"
);
# endif
int
i,
changed_size;
Verify(pixelBuffer.Data.MapPointer != NULL);
height = y;
width = x;
changedBitWidth = (width >> 5);
changed_size = height * changedBitWidth;
maximumY = height-1;
maximumX = width-1;
//---------------------------------------------------------
// Create 'changedLine' and 'changedBit' arrays
//---------------------------------------------------------
changedLine = new Byte[height];
changedBit = new LWord[changed_size];
if (changedLine == NULL || changedBit == NULL)
{
# if defined(DEBUG)
Tell("INVALID!\n");
# endif
valid = False;
return;
}
else
{
Register_Pointer(changedLine);
Register_Pointer(changedBit);
valid = True;
}
# if defined(DEBUG)
Tell("changedLine=" << changedLine << "\n");
Tell("changedBit=" << changedBit << "\n");
# endif
//---------------------------------------------------------
// Clear the 'changedBit' array
//---------------------------------------------------------
memset(changedLine, 0, height);
//---------------------------------------------------------
// Clear the 'changedBit' array
//---------------------------------------------------------
LWord
*bit_dest;
for (i=changed_size,bit_dest=changedBit; i>0; --i,++bit_dest)
{
*bit_dest = (LWord) 0;
}
Check_Fpu();
}
//===================================================================
// Destructor
//===================================================================
Video16BitBuffered::~Video16BitBuffered()
{
Check(this);
if (changedLine != NULL)
{
Unregister_Pointer(changedLine);
delete changedLine;
changedLine = NULL;
}
if (changedBit != NULL)
{
Unregister_Pointer(changedBit);
delete changedBit;
changedBit = NULL;
}
Check_Fpu();
}
//===================================================================
// TestInstance
//===================================================================
Logical
Video16BitBuffered::TestInstance() const
{
return True;
}
//===================================================================
// ShowInstance
//===================================================================
void
Video16BitBuffered::ShowInstance(
char *indent
)
{
std::cout << indent << "Video16BitBuffered:\n";
Check(this);
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "width =" << width << "\n";
std::cout << temp << "height =" << height << "\n";
std::cout << temp << "maximumX =" << maximumX << "\n";
std::cout << temp << "maximumY =" << maximumY << "\n";
std::cout << temp << "changedLine=" << changedLine << "\n";
std::cout << temp << "changedBit =" << changedBit << "\n";
pixelBuffer.ShowInstance(temp);
GraphicsDisplay::ShowInstance(temp);
Check_Fpu();
}
//===================================================================
// buildDestPointer
//===================================================================
void
Video16BitBuffered::buildDestPointer(
int screenX,
int screenY,
Word **pixel_pointer,
LWord **changed_bit_pointer,
LWord *changed_bit
)
{
Verify(valid);
Verify(pixel_pointer != NULL);
Verify(changed_bit_pointer != NULL);
Verify(changed_bit != NULL);
Verify(screenX >= 0);
Verify(screenX < width);
Verify(screenY >= 0);
Verify(screenY < height);
*pixel_pointer = pixelBuffer.Data.MapPointer +
screenX +
(screenY * width);
Verify(*pixel_pointer >= pixelBuffer.Data.MapPointer);
Verify(*pixel_pointer < &pixelBuffer.Data.MapPointer[height*width]);
*changed_bit_pointer = changedBit +
(screenX >> 5) +
(screenY * changedBitWidth);
Verify(*changed_bit_pointer >= changedBit);
Verify(*changed_bit_pointer < &changedBit[height*changedBitWidth]);
*changed_bit = 1L << (0x1F - (screenX & 0x1F));
Verify(*changed_bit != 0L);
Diag_Tell(
"Video16BitBuffered::buildDestPointer(" << screenX <<
", " << screenY << std::hex <<
") = pix " << *pixel_pointer <<
", cbp " << *changed_bit_pointer <<
", cb " << *changed_bit << std::dec <<
"\n"
);
Diag_Tell("changedBitWidth=" << changedBitWidth << "\n");
Check_Fpu();
}
//===================================================================
// MarkChangedLines
//===================================================================
#if defined(BLIT_STATISTICS)
# define SET_CHANGED(pointer, bits) *pointer |= bits; ++dirtyPixelCount
#else
# define SET_CHANGED(pointer, bits) *pointer |= bits
#endif
#define LEFT_CHANGED(pointer, bits) \
bits <<= 1; \
if (bits == 0) { --pointer; bits=0x00000001L; }
#define RIGHT_CHANGED(pointer, bits) \
bits >>= 1; \
if (bits == 0) { ++pointer; bits=0x80000000L; }
#define UP_CHANGED(pointer, bits) pointer -= changedBitWidth
#define DOWN_CHANGED(pointer, bits) pointer += changedBitWidth
#define LEFT_DEST(pointer) --pointer
#define RIGHT_DEST(pointer) ++pointer
#define UP_DEST(pointer) pointer -= width
#define DOWN_DEST(pointer) pointer += width
#define LEFT_SOURCE(pointer,map) --pointer
#define RIGHT_SOURCE(pointer,map) ++pointer
#define UP_SOURCE(pointer,map) pointer -= map->Data.Size.x
#define DOWN_SOURCE(pointer,map) pointer += map->Data.Size.x
#define LEFT_BITMAP(pointer,bits) \
bits <<= 1; \
if (bits == 0) { --pointer; bits=0x0001; }
#define RIGHT_BITMAP(pointer, bits) \
bits >>= 1; \
if (bits == 0) { ++pointer; bits=0x8000; }
#define UP_BITMAP(pointer,map) pointer -= map->Data.WidthInWords
#define DOWN_BITMAP(pointer,map) pointer += map->Data.WidthInWords
//
// Inputs are in DISPLAY COORDINATES, i.e., (0,0) in top left corner!
//
void
Video16BitBuffered::MarkChangedLines(
int start,
int stop
)
{
Check(this);
Diag_Tell(
"Video16BitBuffered::MarkChangedLines(" << start <<
", " << stop <<
")\n"
);
if (start > stop)
{
# if defined(DEBUG)
Tell("MarkChangedLines FLIPPING\n");
# endif
int temp;
temp = start;
start = stop;
stop = temp;
}
Verify(start >= 0);
Verify(start <= maximumY);
Verify(stop >= 0);
Verify(stop <= maximumY);
//------------------------------------------------
// Set the flag for each changed line
//------------------------------------------------
Verify(stop >= start);
memset(&changedLine[start], 1, stop-start+1);
Check_Fpu();
}
//===================================================================
// DrawPoint
//===================================================================
void
Video16BitBuffered::DrawPoint(
int color,
int bitmask,
Enumeration operation,
int x, int y
)
{
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
Word
*dest_pointer;
LWord
*changed_pointer;
LWord
changed_bit;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
# endif
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y, y);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Create pointers
//---------------------------------------------------------
buildDestPointer(
x, y,
&dest_pointer,
&changed_pointer,
&changed_bit
);
//---------------------------------------------------------
// Write the point
//---------------------------------------------------------
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
Check_Fpu();
}
//===================================================================
// DrawLine
//===================================================================
void
Video16BitBuffered::DrawLine(
int color,
int bitmask,
Enumeration operation,
int x1, int y1,
int x2, int y2,
Logical include_last_pixel
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawLine(" << color <<
", " << bitmask <<
", " << operation <<
", " << x1 << "," << y1 << "," << x2 << "," << y2 <<
", " << include_last_pixel <<
"\n"
);
# endif
Check(this);
Verify(x1 >= bounds.bottomLeft.x);
Verify(x1 <= bounds.topRight.x);
Verify(y1 >= bounds.bottomLeft.y);
Verify(y1 <= bounds.topRight.y);
Verify(x2 >= bounds.bottomLeft.x);
Verify(x2 <= bounds.topRight.x);
Verify(y2 >= bounds.bottomLeft.y);
Verify(y2 <= bounds.topRight.y);
enum
{
negative_delta_x = 1,
negative_delta_y = 2,
delta_y_greater = 0,
delta_x_greater = 4
};
long
length,
rate,
accumulator;
int
octant,
delta_x,
delta_y;
Word
*dest_pointer;
LWord
*changed_pointer;
LWord
changed_bit;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Route to DrawPoint if single pixel
//---------------------------------------------------------
if (x1 == x2 && y1 == y2)
{
if (include_last_pixel)
{
DrawPoint(color, bitmask, operation, x1, y1);
}
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y1 = maximumY - y1;
y2 = maximumY - y2;
//---------------------------------------------------------
// Ensure that endpoints are legitimate
//---------------------------------------------------------
Verify(x1 >= 0);
Verify(x1 < width);
Verify(x2 >= 0);
Verify(x2 < width);
Verify(y1 >= 0);
Verify(y1 < height);
Verify(y2 >= 0);
Verify(y2 < height);
# if defined(DEBUG)
Tell(
"Transformed coordinates=" << x1 << "," << y1 <<
"," << x2 << "," << y2 <<
"\n"
);
# endif
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y1, y2);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Determine which octant to use
//---------------------------------------------------------
octant = 0;
delta_x = x2 - x1;
if (delta_x < 0)
{
# if defined(DEBUG)
Tell("negative dx\n");
# endif
octant |= negative_delta_x;
delta_x = - delta_x;
}
delta_y = y2 - y1;
if (delta_y < 0)
{
# if defined(DEBUG)
Tell("negative dy\n");
# endif
octant |= negative_delta_y;
delta_y = - delta_y;
}
if (delta_x > delta_y)
{
# if defined(DEBUG)
Tell("dx > dy\n");
# endif
octant |= delta_x_greater;
}
# if defined(DEBUG)
Tell(
"dx=" << delta_x <<
", dy=" << delta_y <<
", octant=" << octant <<
", color=" << color <<
"\n"
);
# endif
//---------------------------------------------------------
// Prepare to draw line
//---------------------------------------------------------
buildDestPointer(
x1, y1,
&dest_pointer,
&changed_pointer,
&changed_bit
);
accumulator = 1024L; // preset accumulator to 1/2 full
//---------------------------------------------------------
// Draw the line!
//---------------------------------------------------------
switch (octant)
{
case delta_y_greater:
//-------------------------------------
// delta y greater
// positive delta x
// positive delta y
//
// +
// \ &
// \ &
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
Verify(delta_y > 0);
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_x:
//-------------------------------------
// delta y greater
// negative delta x
// positive delta y
//
// +
// /
// /
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_x, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_y:
//-------------------------------------
// delta y greater
// positive delta x
// negative delta y
//
// /
// /
// +
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_y, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_y_greater+negative_delta_x+negative_delta_y:
//-------------------------------------
// delta y greater
// negative delta x
// negative delta y
//
// \ &
// \ &
// +
//-------------------------------------
length = delta_y;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_x*2048L)/delta_y;
# if defined(DEBUG)
Tell(
"delta_y_greater+negative_delta_x+negative_delta_y, length=" <<
length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater:
//-------------------------------------
// delta x greater
// positive delta x
// positive delta y
//
// +---___
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_x:
//-------------------------------------
// delta x greater
// negative delta x
// positive delta y
//
// ___---+
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_x, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
DOWN_DEST(dest_pointer);
DOWN_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_y:
//-------------------------------------
// delta x greater
// positive delta x
// negative delta y
//
// +___---
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_y, length=" << length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
RIGHT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
}
}
break;
case delta_x_greater+negative_delta_x+negative_delta_y:
//-------------------------------------
// delta x greater
// negative delta x
// negative delta y
//
// ---___+
//
//
//-------------------------------------
length = delta_x;
if (!include_last_pixel)
{
-- length;
}
rate = (delta_y*2048L)/delta_x;
# if defined(DEBUG)
Tell(
"delta_x_greater+negative_delta_x+negative_delta_y, length=" <<
length <<
", rate=" << rate <<
"\n"
);
# endif
Verify(rate >= 0L);
Verify(rate <= 2048L);
Verify(length >= 0);
for ( ; length>0; --length)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
# if defined(DEBUG)
Tell(
length <<
", accum=" << accumulator <<
", dest_pointer=" << dest_pointer <<
"\n"
);
# endif
SET_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
LEFT_CHANGED(changed_pointer, changed_bit);
accumulator += rate;
if (accumulator > 2048L)
{
# if defined(DEBUG)
Tell("OVERFLOW\n");
# endif
accumulator -= 2048L;
UP_DEST(dest_pointer);
UP_CHANGED(changed_pointer, changed_bit);
}
}
break;
}
Check_Fpu();
}
//===================================================================
// DrawFilledRectangle
//===================================================================
void
Video16BitBuffered::DrawFilledRectangle(
int color,
int bitmask,
Enumeration operation,
int x1, int y1,
int x2, int y2
)
{
# if defined(DEBUG)
Tell("Video16BitBuffered::DrawFilledRectangle(" <<
color << ", " <<
std::hex << bitmask << ", " << std::dec <<
operation << ", " <<
x1 << ", " <<
y1 << ", " <<
x2 << ", " <<
y2 << ", " <<
")\n");
# endif
Check(this);
Verify(x1 >= bounds.bottomLeft.x);
Verify(x1 <= bounds.topRight.x);
Verify(y1 >= bounds.bottomLeft.y);
Verify(y1 <= bounds.topRight.y);
Verify(x2 >= bounds.bottomLeft.x);
Verify(x2 <= bounds.topRight.x);
Verify(y2 >= bounds.bottomLeft.y);
Verify(y2 <= bounds.topRight.y);
Word
*dest_pointer;
LWord
*init_changed_pointer,
*changed_pointer;
LWord
init_changed_bit,
changed_bit;
int
x,
dest_fixup,
rect_width,
rect_height;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y1 = maximumY - y1;
y2 = maximumY - y2;
//---------------------------------------------------------
// Ensure that rectangle is properly specified
//---------------------------------------------------------
if (x2 < x1)
{
int temp;
temp = x1;
x1 = x2;
x2 = temp;
}
if (y2 < y1)
{
int temp;
temp = y1;
y1 = y2;
y2 = temp;
}
//---------------------------------------------------------
// Verify that values are legitimate
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
Verify(x1 >= 0);
Verify(x1 <= x2);
Verify(x2 < width);
Verify(y1 >= 0);
Verify(y1 <= y2);
Verify(y2 < height);
//---------------------------------------------------------
// Update changedLine array
//---------------------------------------------------------
MarkChangedLines(y1, y2);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to fill
//---------------------------------------------------------
# if defined(DEBUG)
Tell(
"x1=" << x1 << ", " << "y1=" << y1 << "\n" <<
"x2=" << x2 << ", " << "y2=" << y2 << "\n" <<
std::flush
);
# endif
buildDestPointer(
x1, y1,
&dest_pointer,
&init_changed_pointer,
&init_changed_bit
);
rect_height = y2 - y1 + 1;
rect_width = x2 - x1 + 1;
dest_fixup = width - rect_width;
# if defined(DEBUG)
Tell(
"rect_height=" << rect_height << "\n" <<
"rect_width=" << rect_width << "\n" <<
"dest_fixup=" << dest_fixup << "\n" <<
std::flush
);
# endif
//---------------------------------------------------------
// Fill the rectangle
//---------------------------------------------------------
switch(operation)
{
case GraphicsDisplay::Replace:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
dest_pointer++;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::And:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ &= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::Or:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ |= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
case GraphicsDisplay::Xor:
for( ; rect_height>0; --rect_height)
{
changed_bit = init_changed_bit;
changed_pointer = init_changed_pointer;
DOWN_CHANGED(init_changed_pointer, init_changed_bit);
for(x=rect_width; x>0; --x)
{
*dest_pointer++ ^= (Word) color;
SET_CHANGED(changed_pointer, changed_bit);
RIGHT_CHANGED(changed_pointer, changed_bit);
}
dest_pointer += dest_fixup;
}
break;
}
Check_Fpu();
}
void
Video16BitBuffered::DrawText(
int /*color*/,
int /*bitmask*/,
Enumeration /*operation*/,
Logical /*opaque*/,
int /*rotation*/,
Enumeration /*fontNumber*/,
Logical /*vertical*/,
GraphicsDisplay::Justification /*justification*/,
Rectangle2D */*clippingRectanglepointer*/,
char */*stringPointer*/
)
{
# if defined(DEBUG)
Tell("Video16BitBuffered::DrawText()\n");
# endif
Check(this);
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
Check_Fpu();
if (!valid)
{
return;
}
}
//===================================================================
// DrawBitMap
//===================================================================
void
Video16BitBuffered::DrawBitMap(
int color,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawBitMap(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y,
bits,
bit_test,
first_bit_test;
Word
*source_pointer_begin,
*source_pointer,
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(bitmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < bitmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < bitmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = bitmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= bitmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= bitmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
bitmap->Data.MapPointer +
(sLeft >> 4) +
(sBottom * bitmap->Data.WidthInWords);
first_bit_test = 1 << (15-(sLeft & 15));
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
switch (rotation)
{
default:
//--------------------------------------------
// transparent bitmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"zero: xp=" << (x+map_width-1) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width-1 >= 0);
Verify(x+map_width-1 < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Transparent bitmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Transparent bitmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Transparent bitmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_height) << ", yp=" << (y-(map_width-1)) << "\n");
# endif
if (x-map_height < 0)
{
Tell("x-map_height = " << (x - map_height) << "\n");
return;
}
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
Check_Fpu();
}
//===================================================================
// DrawBitMapOpaque
//===================================================================
void
Video16BitBuffered::DrawBitMapOpaque(
int foreground,
int background,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
Diag_on;
Diag_Tell(
"Video16BitBuffered::DrawBitMapOpaque(<" << x <<
", " << y <<
">,<" << sLeft <<
", " << sBottom <<
", " << sRight <<
", " << sTop <<
">)\n"
);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y,
bits,
bit_test,
first_bit_test;
Word
*source_pointer_begin,
*source_pointer,
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
Word
color;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(bitmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < bitmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < bitmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = bitmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
Diag_off;
Diag_Tell("x=" << x << ", y=" << y << "\n");
Diag_Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Diag_Tell(
"map_width=" << map_width <<
", map_height=" << map_height <<
"\n"
);
Diag_on;
Verify(map_width > 0);
Verify(map_width <= bitmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= bitmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
bitmap->Data.MapPointer +
(sLeft >> 4) +
(sBottom * bitmap->Data.WidthInWords);
first_bit_test = 1 << (15-(sLeft & 15));
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
//---------------------------------------------------------
// The bitmap is always read left-to-right, bottom-to-top.
// We write it to the screen in different directions
// based on the rotation.
//---------------------------------------------------------
switch (rotation)
{
default:
//--------------------------------------------
// opaque bitmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width <= width); // HACK? <, or <=?
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// opaque bitmap, 90 degrees
// #--Y--.
// | |
// X |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// opaque bitmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// opaque bitmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell(
"xp=" << (x-map_height+1) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
Diag_Tell(
"(y-(map_width-1))=" << (y-(map_width-1)) <<
", y=" << y <<
","
);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_BITMAP(source_pointer_begin, bitmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
bit_test = first_bit_test;
bits = *source_pointer++;
for(x=map_width; x>0; --x,bit_test>>=1)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
if (bit_test == 0)
{
bit_test = 0x8000;
bits = *source_pointer++;
}
if (bits & bit_test)
{
color = (Word) foreground;
}
else
{
color = (Word) background;
}
{
switch (operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
Diag_Tell(
"changed_pointer=" << changed_pointer << std::dec <<
"\n"
);
break;
}
Check_Fpu();
Diag_off;
}
//===================================================================
// DrawPixelMap8
//===================================================================
void
Video16BitBuffered::DrawPixelMap8(
int *translation_table,
int bitmask,
Enumeration operation,
Logical opaque,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawPixelMap8(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y;
Byte
source_data,
*source_pointer_begin,
*source_pointer;
Word
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
Word
color;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(pixelmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < pixelmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < pixelmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = pixelmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= pixelmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= pixelmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
pixelmap->Data.MapPointer +
sLeft +
(sBottom * pixelmap->Data.Size.x);
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
if (opaque)
{
switch (rotation)
{
default:
//--------------------------------------------
// Opaque pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Opaque pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Opaque pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Opaque 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Opaque pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("Opaque 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-map_height-1 >= 0);
Verify(x-map_height-1 < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
else
{
switch (rotation)
{
default:
//--------------------------------------------
// Transparent pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Transparent pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Transparent pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"transparent 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Transparent pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("transparent 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-(map_width-1)) <<
"\n"
);
# endif
Verify(x-(map_height-1) >= 0);
Verify(x-(map_height-1) < width);
Verify(y-(map_width-1) >= 0);
Verify(y-(map_width-1) < height);
MarkChangedLines(y-(map_width-1), y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
color = (Word) translation_table[source_data];
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
Check_Fpu();
}
//===================================================================
// DrawPixelMap8SingleColor
//===================================================================
void
Video16BitBuffered::DrawPixelMap8SingleColor(
int color,
int bitmask,
Enumeration operation,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
# if defined(DEBUG)
Tell(
"Video16BitBuffered::DrawPixelMap8SingleColor(<" <<
x << ", " <<
y << ">,<" <<
sLeft << ", " <<
sBottom << ", " <<
sRight << ", " <<
sTop << ">" <<
")\n"
);
# endif
Check(this);
Verify(x >= bounds.bottomLeft.x);
Verify(x <= bounds.topRight.x);
Verify(y >= bounds.bottomLeft.y);
Verify(y <= bounds.topRight.y);
int
map_width,
map_height,
map_max_y;
Byte
source_data,
*source_pointer_begin,
*source_pointer;
Word
*dest_pointer_begin,
*dest_pointer;
LWord
changed_bit_begin,
changed_bit,
*changed_pointer_begin,
*changed_pointer;
//---------------------------------------------------------
// If pixelbuffer is invalid, do nothing
//---------------------------------------------------------
if (!valid)
{
Check_Fpu();
return;
}
//---------------------------------------------------------
// Ensure that source rectangle is properly specified
//---------------------------------------------------------
Verify(pixelmap != NULL);
Verify(sLeft >= 0);
Verify(sLeft <= sRight);
Verify(sRight < pixelmap->Data.Size.x);
Verify(sBottom >= 0);
Verify(sBottom <= sTop);
Verify(sTop < pixelmap->Data.Size.y);
//---------------------------------------------------------
// Convert to screen co-ordinates
//---------------------------------------------------------
y = maximumY - y;
map_max_y = pixelmap->Data.Size.y-1;
sTop = map_max_y - sTop;
sBottom = map_max_y - sBottom;
map_width = sRight - sLeft + 1;
map_height = sBottom - sTop + 1;
# if defined(DEBUG)
Tell("x=" << x << ", y=" << y << "\n");
Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
# endif
Verify(map_width > 0);
Verify(map_width <= pixelmap->Data.Size.x);
Verify(map_height > 0);
Verify(map_height <= pixelmap->Data.Size.y);
Verify(x >= 0);
Verify(x < width);
Verify(y >= 0);
Verify(y < height);
//---------------------------------------------------------
// We really need inverse bitmap here
//---------------------------------------------------------
bitmask = ~bitmask;
//---------------------------------------------------------
// Prepare to draw bitmap
//---------------------------------------------------------
Verify(pixelBuffer.Data.MapPointer != NULL);
source_pointer_begin =
pixelmap->Data.MapPointer +
sLeft +
(sBottom * pixelmap->Data.Size.x);
buildDestPointer(
x, y,
&dest_pointer_begin,
&changed_pointer_begin,
&changed_bit_begin
);
{
switch (rotation)
{
default:
//--------------------------------------------
// Single-color pixelmap, zero degrees
// .-----.
// | |
// | |
// Y |
// #X----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color zero: xp=" << (x+map_width) <<
", yp=" << (y-map_height+1) <<
"\n"
);
# endif
Verify(x+map_width >= 0);
Verify(x+map_width < width);
Verify(y-map_height+1 >= 0);
Verify(y-map_height+1 < height);
MarkChangedLines(y-map_height+1, y);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
UP_CHANGED(changed_pointer_begin, changed_bit_begin);
UP_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
RIGHT_CHANGED(changed_pointer, changed_bit);
RIGHT_DEST(dest_pointer);
}
}
break;
case 90:
//--------------------------------------------
// Single-color pixelmap, 90 degrees
// #Y----.
// X |
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color 90: xp=" << (x+map_height) <<
", yp=" << (y+map_width) <<
"\n"
);
# endif
Verify(x+map_height >= 0);
Verify(x+map_height < width);
Verify(y+map_width >= 0);
Verify(y+map_width < height);
MarkChangedLines(y, y+map_width);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
RIGHT_CHANGED(changed_pointer_begin, changed_bit_begin);
RIGHT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word) ((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
DOWN_CHANGED(changed_pointer, changed_bit);
DOWN_DEST(dest_pointer);
}
}
break;
case 180:
//--------------------------------------------
// Single-color pixelmap, 180 degrees
// .----X#
// | Y
// | |
// | |
// .-----.
//--------------------------------------------
# if defined(DEBUG)
Tell(
"Single-color 180: xp=" << (x-map_width+1) <<
", yp=" << (y+map_height) <<
"\n"
);
# endif
Verify(x-map_width+1 >= 0);
Verify(x-map_width+1 < width);
Verify(y+map_height >= 0);
Verify(y+map_height < height);
MarkChangedLines(y, y+map_height);
for(y=map_height; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
DOWN_CHANGED(changed_pointer_begin, changed_bit_begin);
DOWN_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
LEFT_CHANGED(changed_pointer, changed_bit);
LEFT_DEST(dest_pointer);
}
}
break;
case 270:
//--------------------------------------------
// Single-color pixelmap, 270 degrees
// .-----.
// | |
// | X
// | |
// .--Y--#
//--------------------------------------------
# if defined(DEBUG)
Tell("Single-color 270: x=" << x << ", y=" << y << "\n");
Tell(
"xp=" << (x-map_height) <<
", yp=" << (y-map_width) <<
"\n"
);
# endif
Verify(x-map_height >= 0);
Verify(x-map_height < width);
Verify(y-map_width >= 0);
Verify(y-map_width < height);
MarkChangedLines(y-map_width, y);
for(y=map_height ; y>0; --y)
{
source_pointer = source_pointer_begin;
changed_pointer = changed_pointer_begin;
changed_bit = changed_bit_begin;
dest_pointer = dest_pointer_begin;
UP_SOURCE(source_pointer_begin, pixelmap);
LEFT_CHANGED(changed_pointer_begin, changed_bit_begin);
LEFT_DEST(dest_pointer_begin);
for(x=map_width; x>0; --x)
{
Verify(dest_pointer >= pixelBuffer.Data.MapPointer);
Verify(dest_pointer < pixelBuffer.Data.MapPointer+
(width*height));
Verify(changed_pointer >= changedBit);
Verify(changed_pointer < changedBit+(changedBitWidth*height));
source_data = *source_pointer++; //SOURCE_RIGHT
if (source_data)
{
switch(operation)
{
case GraphicsDisplay::Replace:
*dest_pointer = (Word)((*dest_pointer & bitmask) | color);
break;
case GraphicsDisplay::And:
*dest_pointer &= (Word) color;
break;
case GraphicsDisplay::Or:
*dest_pointer |= (Word) color;
break;
case GraphicsDisplay::Xor:
*dest_pointer ^= (Word) color;
break;
}
SET_CHANGED(changed_pointer, changed_bit);
}
UP_CHANGED(changed_pointer, changed_bit_begin);
UP_DEST(dest_pointer);
}
}
break;
}
}
Check_Fpu();
}
//########################################################################
//############################ SVGA640x480x16 ############################
//########################################################################
SVGA16::SVGA16(
int mode,
int init_width,
int init_height,
int mem_page_size,
int mem_granularity,
int bytes_per_line,
int page_function_pointer,
int special_interface,
bool windowed,
int *secondaryIndex,
int *aux1Index,
int *aux2Index
):Video16BitBuffered(init_width, init_height)
{
BuildWindows(init_width,init_height,windowed, secondaryIndex, aux1Index, aux2Index);
for (int _i = 0; _i < 8; _i++) // DEV-COMPOSITE: lazily created on first surface draw
mDevSurfaceTex[_i] = NULL;
//STUBBED: VIDEO RB 1/15/07
# if defined(DEBUG)
Tell("SVGA16::SVGA16()\n");
# endif
pageSize = mem_page_size * 1024;
Verify(mem_granularity > 0);
pageDelta = mem_page_size/mem_granularity;
widthInBytes = bytes_per_line;
pageFcnPtr = page_function_pointer;
specialInterface = special_interface; // currently unused
currentPageNumber = -1;
//
// Set video mode
//
//SVGASetMode(mode, pageFcnPtr);
//
// Set VWE video splitter clock divider
//
//SVGASetSplitterClock(True);
//------------------------------------------------------------------------
// Initialize palettes
//------------------------------------------------------------------------
FadeToWhite(0.0);
//------------------------------------------------------------------------
// Initialize palette data
//------------------------------------------------------------------------
// The +2 causes Adam's std::decoded Palette addresses to "match up"
// with the address definitions used by the standard VGA palette port.
// Adam's port std::decoder design uses:
// xx00 = write address port
// xx01 = data port
// xx10 = pixel mask port
// xx11 = read address port
// The standard VGA/SVGA ports are:
// 03C6 = ......0110 = xx10 = pixel mask port
// 03C7 = ......0111 = xx11 = read address port
// 03C8 = ......1000 = xx00 = write address port
// 03C9 = ......1001 = xx01 = data port
// Adam's ports are:
// 0300 = secondary palette
// 0308 = auxiliary palette 1
// 0310 = auxiliary palette 2
// By adding 2 to "Adam's" port assignments, they match with a VGA:
// 0302/030A/0312 = xx10 = pixel mask port
// 0303/030B/0313 = xx11 = read address port
// 0304/030C/0314 = xx00 = write address port
// 0305/030D/0315 = xx01 = data port
// See L4VB16.hpp, class SVGA16 for an enumeration of palettes
// matching this table.
static Word port_addr[PaletteCount] = {
0x3C6, // NativePalette
0x300+2, // SecondaryPalette
0x308+2, // AuxiliaryPalette1
0x310+2 // AuxiliaryPalette2
};
SVGA16Palette
*palette_pointer = &palette[0];
for(int i=0; i<PaletteCount; ++i,++palette_pointer)
{
int j;
palette_pointer->hardwarePort = port_addr[i];
palette_pointer->modified = False;
palette_pointer->flashAccumulator = 0.0;
palette_pointer->flashRate = 0.0;
palette_pointer->previousMaskState = -1;
for(j=0; j<SVGA16Palette::maskStates; ++j)
{
palette_pointer->mask[j] = 0xFF;
}
/*if (port_addr[i] != 0x3C6)
{
SVGAZeroPalette(port_addr[i]);
}*/
}
//---------------------------------------------------------
// Prepare update values
//---------------------------------------------------------
currentPageNumber = -1;
ResetUpdatePosition();
# if defined(BLIT_STATISTICS)
dirtyPixelCount = 0;
transferPixelCount = 0;
overflowPixelCount = 0;
# endif
//---------------------------------------------------------
// Clear the display
//---------------------------------------------------------
# if defined(DEBUG)
Tell("Valid, drawing rectangle-\n" << std::flush);
# endif
DrawFilledRectangle(
0,
0xFFFF,
GraphicsDisplay::Replace,
0, 0,
maximumX, maximumY
);
# if defined(DEBUG)
Tell("About to update-\n" << std::flush);
# endif
Update(False);
Check_Fpu();
mDisplayToUpdate = 0;
}
SVGA16::~SVGA16()
{
for (int i=0; i < NUMGAUGEWINDOWS; i++)
{
if (mSurfaces[i * 2] != NULL)
{
mSurfaces[i * 2]->Release();
mSurfaces[i * 2] = NULL;
}
if (mSurfaces[i * 2 + 1] != NULL)
{
mSurfaces[i * 2 + 1]->Release();
mSurfaces[i * 2 + 1] = NULL;
}
if (mDevice[i] != NULL)
{
mDevice[i]->Release();
mSurfaces[i] = NULL;
}
DestroyWindow(gaugeWindows[i]);
}
//STUBBED: VIDEO RB 1/15/07
# if defined(DEBUG)
Tell("SVGA16::~SVGA16()\n");
# endif
Check(this);
//---------------------------------------------------------
// Eventually wait for fade (if any) to complete??
//---------------------------------------------------------
//---------------------------------------------------------
// Set video mode
//---------------------------------------------------------
//SVGASetMode(3, 0);
# if defined(BLIT_STATISTICS)
double
ratio;
if (transferPixelCount == 0)
{
ratio = (double) 0;
}
else
{
ratio = ((double) dirtyPixelCount) / transferPixelCount;
}
//------------------------------------------------------
// Print statistics
//------------------------------------------------------
DEBUG_STREAM <<
"SVGA16::~SVGA16: pixel management statistics ------------" <<
"\nNumber of dirty pixels =" << dirtyPixelCount <<
"\nNumber of transferred pixels=" << transferPixelCount <<
"\nTimes overflowed =" << overflowPixelCount <<
"\nRatio =" << ratio <<
"\n-------------------------------------------------------\n";
# endif
//---------------------------------------------------------
// Set VWE video splitter clock divider
//---------------------------------------------------------
//SVGASetSplitterClock(False);
Check_Fpu();
}
Logical
SVGA16::TestInstance() const
{
return Video16BitBuffered::TestInstance();
}
void
SVGA16::ShowInstance(char *indent)
{
std::cout << indent << "SVGA16:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "SVGA16:\n";
Video16BitBuffered::ShowInstance(temp);
Check_Fpu();
}
int GetShiftAmount(DWORD mask)
{
int amount = -1;
while (mask)
{
mask >>= 1;
amount++;
}
return amount;
}
Logical SVGA16::Update(Logical forceAll)
{
HRESULT hr;
GaugeRenderer *renderer = application->GetGaugeRenderer();
if (!valid || renderer == NULL)
{
CLEAR_SCREEN_COPY();
return False; // Do no more!
}
// DEV-COMPOSITE GUARD (option B): dev-composite SVGA16 does NO per-surface D3D
// (BuildWindows forced NUMGAUGEWINDOWS=0 + allocated nothing); the mSurfaces[0]
// path below would index an absent array. The main renderer composites the shared
// CPU pixelBuffer as a window inset instead. Inert on the pod.
if (DevGaugeComposite() || NUMGAUGEWINDOWS <= 0)
return False;
if (++mDisplayToUpdate >= NUMGAUGEWINDOWS)
mDisplayToUpdate = 0;
//Top MFD's
L4GraphicsPort *UL = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxUL2"));
L4GraphicsPort *Cent = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxC"));
L4GraphicsPort *UR = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxUR2"));
//Bottom MFD's
L4GraphicsPort *LL = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxLL"));
L4GraphicsPort *LR = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("auxLR"));
//Secondary
L4GraphicsPort *secPort = static_cast<L4GraphicsPort*>(renderer->GetGraphicsPort("sec"));
DWORD ulMask = 0, ucMask = 0, urMask = 0, llMask = 0, lrMask = 0;
int ulMask_sh = 0, ucMask_sh = 0, urMask_sh = 0, llMask_sh = 0, lrMask_sh = 0;
int secMask = 0;
SVGA16Palette *secPalette = NULL;
if (this->mDisplayToUpdate == 1 || this->mDisplayToUpdate == 2)
{
//Drawing MFD's... make sure we have MFDs to draw
if (UL != NULL && Cent != NULL && UR != NULL && LL != NULL && LR != NULL)
{
ulMask = UL->GetBitMask();
ulMask_sh = GetShiftAmount(ulMask);
ulMask |= (ulMask << 16);
ucMask = Cent->GetBitMask();
ucMask_sh = GetShiftAmount(ucMask);
ucMask |= (ucMask << 16);
urMask = UR->GetBitMask();
urMask_sh = GetShiftAmount(urMask);
urMask |= (urMask << 16);
llMask = LL->GetBitMask();
llMask_sh = GetShiftAmount(llMask);
llMask |= (llMask << 16);
lrMask = LR->GetBitMask();
lrMask_sh = GetShiftAmount(lrMask);
lrMask |= (lrMask << 16);
} else
{
//No MFDs to draw, break out early
return False;
}
} else
{
//Drawing secondary, make sure we got secondary
if (secPort != NULL)
{
secMask = secPort->GetBitMask();
secPalette = &((SVGA16 *) secPort->graphicsDisplay)->palette[secPort->paletteID];
} else
{
//No secondary, skip
return False;
}
}
Word *data = pixelBuffer.Data.MapPointer;
D3DLOCKED_RECT rect;
if (FAILED(mSurfaces[mDisplayToUpdate * 2]->LockRect(0, &rect, NULL, mLockFlags[mDisplayToUpdate])))
{
DEBUG_STREAM << "Failed to lock texture for display " << mDisplayToUpdate << "!" << std::endl << std::flush;
}
else
{
switch(mDisplayToUpdate)
{
case 0:
{
//Secondary
Word *source = data;
Word *dest = (Word*)rect.pBits;
int postRowIncrement = (rect.Pitch / 2) - pixelBuffer.Data.Size.x;
for (int y = 0; y < pixelBuffer.Data.Size.y; y++)
{
for (int x = 0; x < pixelBuffer.Data.Size.x; x++)
{
PaletteTriplet *paletteEntry = &(secPalette->paletteData.Color[*source & secMask]);
*dest = ((paletteEntry->Red >> 3) << 11) |
((paletteEntry->Green >> 2) << 5) |
((paletteEntry->Blue >> 3));
dest++;
source++;
}
dest += postRowIncrement;
}
}
break;
case 2:
{
//HACK - set the upper mask to be the lower mask (so that we draw the lower MFDs to the window)
//and then drop through and draw like the upper stuff
ulMask = llMask;
ucMask = lrMask;
urMask = 0;
ulMask_sh = llMask_sh;
ucMask_sh = lrMask_sh;
urMask_sh = 0;
}
case 1:
{
DWORD *sourceData = (DWORD*)data;
DWORD *destData = (DWORD*)rect.pBits;
int leftWidth = pixelBuffer.Data.Size.x/2;
int postRowIncrement = (rect.Pitch / sizeof(DWORD)) - leftWidth;
for (int y = 0; y < pixelBuffer.Data.Size.y; y++)
{
for (int x=0; x < leftWidth; x++)
{
*destData = (((*sourceData & ulMask) >> ulMask_sh) * 0xF800) |
(((*sourceData & ucMask) >> ucMask_sh) * 0x07E0) |
(((*sourceData & urMask) >> urMask_sh) * 0x001F);
if (NUMGAUGEWINDOWS < 3)
{
//Only draw if we are in spanning mode
*(destData + leftWidth) = (((*sourceData & llMask) >> llMask_sh) * 0xF800) |
(((*sourceData & lrMask) >> lrMask_sh) * 0x07E0);
}
sourceData++;
destData++;
}
destData += postRowIncrement;
}
break;
}
}
V( mSurfaces[mDisplayToUpdate * 2]->UnlockRect(0) );
V( mDevice[mDisplayToUpdate]->UpdateTexture(mSurfaces[mDisplayToUpdate * 2], mSurfaces[mDisplayToUpdate * 2 + 1]) );
}
V( mDevice[mDisplayToUpdate]->BeginScene() );
V( mDevice[mDisplayToUpdate]->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1) );
V( mDevice[mDisplayToUpdate]->SetStreamSource(0, mVertBuffers[mDisplayToUpdate], 0, sizeof(float) * 6) );
V( mDevice[mDisplayToUpdate]->SetTexture(0, mSurfaces[mDisplayToUpdate * 2 + 1]) );
V( mDevice[mDisplayToUpdate]->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2) );
V( mDevice[mDisplayToUpdate]->EndScene() );
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[mDisplayToUpdate].BackBufferCount;
int bbWidth = mPresentParams[mDisplayToUpdate].BackBufferWidth;
int bbHeight = mPresentParams[mDisplayToUpdate].BackBufferHeight;
mSurfaces[mDisplayToUpdate * 2 + 1]->Release();
V(mDevice[mDisplayToUpdate]->Reset(&mPresentParams[mDisplayToUpdate]));
hr = mDevice[mDisplayToUpdate]->CreateTexture(mSurfaceRects[mDisplayToUpdate].right - mSurfaceRects[mDisplayToUpdate].left, height, 1, 0, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[mDisplayToUpdate * 2 + 1], NULL);
mPresentParams[mDisplayToUpdate].BackBufferCount = bbCount;
mPresentParams[mDisplayToUpdate].BackBufferWidth = bbWidth;
mPresentParams[mDisplayToUpdate].BackBufferHeight = bbHeight;
}
// Time end = Now();
// if (end.ticks - start.ticks > 100)
// end = start;
return False; // True == 'more to do'
}
void SVGA16::Refresh()
{
// DEV-COMPOSITE GUARD (option B): dev-composite does NO per-surface D3D; skip the
// per-surface clear/present (the main renderer composites the CPU pixelBuffer
// inset). Inert on the pod.
if (DevGaugeComposite() || NUMGAUGEWINDOWS <= 0)
return;
HRESULT hr;
V( mDevice[mDisplayToUpdate]->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0) );
V( mDevice[mDisplayToUpdate]->BeginScene() );
V( mDevice[mDisplayToUpdate]->EndScene() );
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL) );
if (hr == D3DERR_DEVICELOST)
{
int bbCount = mPresentParams[mDisplayToUpdate].BackBufferCount;
int bbWidth = mPresentParams[mDisplayToUpdate].BackBufferWidth;
int bbHeight = mPresentParams[mDisplayToUpdate].BackBufferHeight;
mSurfaces[mDisplayToUpdate * 2 + 1]->Release();
V(mDevice[mDisplayToUpdate]->Reset(&mPresentParams[mDisplayToUpdate]));
hr = mDevice[mDisplayToUpdate]->CreateTexture(mSurfaceRects[mDisplayToUpdate].right - mSurfaceRects[mDisplayToUpdate].left, height, 1, 0, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &mSurfaces[mDisplayToUpdate * 2 + 1], NULL);
V( mDevice[mDisplayToUpdate]->Present(NULL, NULL, NULL, NULL));
mPresentParams[mDisplayToUpdate].BackBufferCount = bbCount;
mPresentParams[mDisplayToUpdate].BackBufferWidth = bbWidth;
mPresentParams[mDisplayToUpdate].BackBufferHeight = bbHeight;
}
mDisplayToUpdate++;
if (mDisplayToUpdate >= NUMGAUGEWINDOWS)
{
mDisplayToUpdate = 0;
}
}
//STUBBED: VIDEO RB 1/15/07
// SET_SCREEN_COPY();
// Diag_Tell("SVGA16::Update(" << forceAll << ")\n");
// Check(this);
//
// //---------------------------------------------------------
// // If pixelbuffer is invalid, do nothing
// //---------------------------------------------------------
// if (!valid)
// {
// CLEAR_SCREEN_COPY();
// return False; // Do no more!
// }
// //---------------------------------------------------------
// // Mark all lines as changed if commanded
// //---------------------------------------------------------
// if (forceAll)
// {
// memset(changedLine, 1, height);
// }
//
// int
// previous_line_number = lineNumber;
//
// long
// dest_size,
// dest_line_size;
//
// //---------------------------------------------------------
// // Calculate sizes based on specialInterface
// //---------------------------------------------------------
// if (specialInterface)
// {
// dest_size = 32L; // BYTE offset!
// dest_line_size = width;
// }
// else
// {
// dest_size = 32L << 1; // WORD offset!
// dest_line_size = width << 1;
// }
// //---------------------------------------------------------
// // Process lines for as long as we can
// //---------------------------------------------------------
//#if 0 // Let's process just a few lines for background loop processing...
// while (Get_Frame_Percent_Used() < .65f)
//#endif
// {
// //---------------------------------------------------------
// // Do a couple of lines before checking time again
// //---------------------------------------------------------
// for(int line_limit=15; line_limit > 0; )
// {
// //---------------------------------------------------------
// // Check for changed line, clear the flag
// //---------------------------------------------------------
// Verify(changedLinePointer < &changedLine[height]);
//
// int
// changed_line = *changedLinePointer;
// *changedLinePointer++ = 0;
//
// if (changed_line)
// {
// Diag_Tell(height << ":");
// //---------------------------------------------------------
// // Pixels on this line have been changed
// //---------------------------------------------------------
// --line_limit;
// //---------------------------------------------------------
// // Check 'dirty' LWords: if set, scan for changed pixels
// //---------------------------------------------------------
// for(int x=0; x<changedBitWidth; ++x)
// {
// //---------------------------------------------------------
// // Check for changed pixels in LWord, clear flag
// //---------------------------------------------------------
// Verify(
// changedBitPointer < &changedBit[height*changedBitWidth]
// );
//
// LWord
// changed_bits = *changedBitPointer;
// *changedBitPointer++ = 0L;
//
// if (changed_bits)
// {
// Diag_Tell( (changed_bits & 0xFFFF0000L) ? "#" : "." );
// Diag_Tell( (changed_bits & 0x0000FFFFL) ? "#" : "." );
// //---------------------------------------------------------
// // Changed pixels! Make sure display page is correct
// //---------------------------------------------------------
// if (currentPageNumber != nextPageNumber)
// {
// SVGASetPage(nextPageNumber);
// currentPageNumber = nextPageNumber;
// }
// //---------------------------------------------------------
// // Then transfer changed pixels
// //---------------------------------------------------------
// if (specialInterface)
// {
//# if defined(BLIT_STATISTICS)
// transferPixelCount +=
//# endif
// SVGATransfer32x(destOffset, sourcePointer, changed_bits);
// }
// else
// {
//# if defined(BLIT_STATISTICS)
// transferPixelCount +=
//# endif
// SVGATransfer32(destOffset, sourcePointer, changed_bits);
// }
// }
//# if defined(DEBUG)
// else
// {
// //---------------------------------------------------------
// // No pixels in this LWord, move to next one
// //---------------------------------------------------------
// Tell("--");
// }
//# endif
// //---------------------------------------------------------
// // Update remaining pixel count
// //---------------------------------------------------------
// sourcePointer += 32;
// destOffset += dest_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
// }
// Diag_Tell("\n");
// }
// else
// {
// //---------------------------------------------------------
// // Line has not changed, skip over it
// //---------------------------------------------------------
//#if defined(CHECK_FOR_DIRT)
// Logical
// dirty_flag = False;
//
// for(int x=0; x<changedBitWidth; ++x)
// {
// //---------------------------------------------------------
// // Check for changed pixels in LWord
// //---------------------------------------------------------
// Verify(
// changedBitPointer < &changedBit[height*changedBitWidth]
// );
//
// LWord
// changed_bits = *changedBitPointer;
// *changedBitPointer++ = 0L;
//
// if (changed_bits)
// {
// dirty_flag = True;
// }
// //---------------------------------------------------------
// // Update remaining pixel count
// //---------------------------------------------------------
// sourcePointer += 32;
// destOffset += dest_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
// }
// if (dirty_flag)
// {
// Tell(
// "SVGA16::Update: Unexpected dirty bits in line " <<
// lineNumber <<
// "\n!"
// );
// }
//#else
// changedBitPointer += changedBitWidth;
// sourcePointer += width;
// destOffset += dest_line_size;
//
// if (destOffset >= pageSize)
// {
// destOffset -= pageSize;
// nextPageNumber += pageDelta;
// }
//#endif
// }
//
//# if defined(BLIT_STATISTICS)
// //---------------------------------
// // Keep values within a sane range
// //---------------------------------
// if (
// (transferPixelCount > 0x10000000)
// ||
// (dirtyPixelCount > 0x10000000)
// )
// {
// transferPixelCount >>= 1;
// dirtyPixelCount >>= 1;
// ++overflowPixelCount;
// }
//# endif
// //---------------------------------------------------------
// // Check for wrap
// //---------------------------------------------------------
// if (++lineNumber >= height)
// {
// ResetUpdatePosition();
// }
// //---------------------------------------------------------
// // If back to beginning, exit loop
// //---------------------------------------------------------
// if (lineNumber == previous_line_number)
// {
// Check_Fpu();
// CLEAR_SCREEN_COPY();
// return False; // All done
// }
// }
// }
// Check_Fpu();
// CLEAR_SCREEN_COPY();
void
SVGA16::ResetUpdatePosition()
{
lineNumber = 0;
sourcePointer = pixelBuffer.Data.MapPointer;
changedLinePointer = changedLine;
changedBitPointer = changedBit;
nextPageNumber = 0;
destOffset = 0L;
}
void
SVGA16::FadeToPalettes(Scalar fade_time)
{
Check(this);
previousFadeTime = Now();
paletteFadeState = fadeToColor;
if(Small_Enough(fade_time))
{
fadeUnitsPerSecond = 0.0;
fadeAlpha = 1.0;
}
else
{
fadeUnitsPerSecond = (1.0/fade_time);
}
Check_Fpu();
}
void
SVGA16::FadeToWhite(Scalar fade_time)
{
Check(this);
previousFadeTime = Now();
paletteFadeState = fadeToWhite;
if(Small_Enough(fade_time))
{
fadeUnitsPerSecond = 0.0;
fadeAlpha = 0.0;
}
else
{
fadeUnitsPerSecond = (1.0/fade_time);
}
Check_Fpu();
}
void
generateFade(
SVGA16Palette *source,
Scalar alpha
)
{
//STUBBED: VIDEO RB 1/15/07
Check_Pointer(source);
if (alpha < 0.0)
{
alpha = 0.0;
}
else if (alpha > 1.0)
{
alpha = 1.0;
}
Palette8
temp;
// Scalar
// inverse_alpha = (1.0 - alpha) * 255.0;
int
i;
for(i=0; i<256; ++i)
{
temp.Color[i].Red = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Red * alpha));
((source->paletteData.Color[i].Red * alpha));
temp.Color[i].Green = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Green * alpha));
((source->paletteData.Color[i].Green * alpha));
temp.Color[i].Blue = (Byte)
// (inverse_alpha + (source->paletteData.Color[i].Blue * alpha));
((source->paletteData.Color[i].Blue * alpha));
}
// SVGAWriteFullPalette( // in L4SVGA16.ASM
// &temp.Color[0].Red,
// source->hardwarePort
// );
Check_Fpu();
}
void
SVGA16::FlashPalette(
int palette_number,
Scalar rate,
unsigned char *stateList
)
{
Check(this);
Verify(palette_number >= 0);
Verify(palette_number < PaletteCount);
SVGA16Palette
*palette_pointer = &palette[palette_number];
//-------------------------------------------------
// Adjust rate so value becomes "cycles per second"
//-------------------------------------------------
palette_pointer->flashRate = rate * (Scalar) SVGA16Palette::maskStates;
//-------------------------------------------------
// Copy the mask values
//-------------------------------------------------
for (int i=0; i<SVGA16Palette::maskStates; ++i)
{
palette_pointer->mask[i] = *stateList++;
}
Check_Fpu();
}
void
SVGA16::UnflashPalette(
int palette_number
)
{
//STUBBED: VIDEO RB 1/15/07
//Check(this);
//Verify(palette_number >= 0);
//Verify(palette_number < PaletteCount);
//SVGA16Palette
// *palette_pointer = &palette[palette_number];
//palette_pointer->flashRate = 0.0;
//palette_pointer->flashAccumulator = 0.0;
//palette_pointer->previousMaskState = -1;
//SVGAWritePaletteMask(palette_pointer->hardwarePort, 0xFF);
//Check_Fpu();
}
void
SVGA16::UpdatePalette()
{
//STUBBED: VIDEO RB 1/15/07
Check(this);
int
i,
mask_state;
SVGA16Palette
*palette_pointer;
//--------------------------------------------------------
// Update time values
//--------------------------------------------------------
Time
right_now = Now();
Scalar
delta_t = (Scalar) (right_now - previousFadeTime);
previousFadeTime = right_now;
if (delta_t <= 0.0)
{
return;
}
//--------------------------------------------------------
// Set palette masks
//--------------------------------------------------------
palette_pointer = &palette[0];
for(i=0; i<PaletteCount; ++i,++palette_pointer)
{
if (palette_pointer->flashRate != 0.0)
{
palette_pointer->flashAccumulator +=
palette_pointer->flashRate * delta_t;
while (palette_pointer->flashAccumulator >=
(Scalar) SVGA16Palette::maskStates)
{
palette_pointer->flashAccumulator -=
(Scalar) SVGA16Palette::maskStates;
}
mask_state = (int) palette_pointer->flashAccumulator;
if (mask_state != palette_pointer->previousMaskState)
{
palette_pointer->previousMaskState = mask_state;
// SVGAWritePaletteMask(
// palette_pointer->hardwarePort,
// palette_pointer->mask[mask_state]
// );
}
}
}
//--------------------------------------------------------
// Fade palettes
//--------------------------------------------------------
palette_pointer = &palette[0];
for(i=0; i<PaletteCount; ++i,++palette_pointer)
{
//--------------------------------------------------------
// Only the secondary palette (i==1) is allowed to fade!
// All other palettes are merely copied.
//--------------------------------------------------------
if ((i != 1) || (paletteFadeState == staticPalette))
{
if (palette_pointer->modified)
{
palette_pointer->modified = False;
// SVGAWriteFullPalette(
// &palette_pointer->paletteData.Color[0].Red,
// palette_pointer->hardwarePort
// );
}
}
else
{
//--------------------------------------------------------
// Discard 'modified' flag (we use the local values for
// fade in/out, and in the 'white' state we don't care,
// because we'll have to fade back in anyway)
//--------------------------------------------------------
palette_pointer->modified = False;
//--------------------------------------------------------
// Perform fade (or stay white)
//--------------------------------------------------------
switch(paletteFadeState)
{
case fadeToWhite:
fadeAlpha -= (delta_t * fadeUnitsPerSecond);
generateFade(palette_pointer, fadeAlpha);
if (fadeAlpha <= 0.0)
{
fadeAlpha = 0.0;
paletteFadeState = whitePalette;
}
break;
case whitePalette:
break;
case fadeToColor:
fadeAlpha += (delta_t * fadeUnitsPerSecond);
generateFade(palette_pointer, fadeAlpha);
if (fadeAlpha >= 1.0)
{
fadeAlpha = 1.0;
paletteFadeState = staticPalette;
}
break;
}
}
}
Check_Fpu();
}
void
SVGA16::FunkyVideo(Logical on_off)
{
//STUBBED: VIDEO RB 1/15/07
//Check(this);
//SVGAFunkyVideo(on_off);
//Check_Fpu();
}
//########################################################################
//########################### L4GraphicsPort #############################
//########################################################################
L4GraphicsPort::L4GraphicsPort(
Video16BitBuffered *graphics_display,
const char *name,
int rotation,
int bit_mask,
SVGA16::PaletteID palette_ID,
L4GraphicsPort::ChannelEnableID channel_enable
):GraphicsPort(graphics_display, name)
{
int
bit_test;
//
// Save the base rotation value
//
baseRotation = rotation;
//
// Save the paletteID and channel enable
//
paletteID = palette_ID;
channelEnable = channel_enable;
//
// Save the bitMask
//
bitMask = bit_mask;
Verify (bitMask != 0);
//
// Count the number of active bits in the bitMask
//
for(bit_test=0x8000,numberOfBits=0; bit_test!=0; bit_test>>=1)
{
if (bit_test & bitMask)
{
++numberOfBits;
}
}
//
// Initialize conversion constants
//
maximumX = bounds.topRight.x - bounds.bottomLeft.x;
maximumY = bounds.topRight.y - bounds.bottomLeft.y;
//
// Overwrite the GraphicsPort::bounds data with rotated values
// for GraphView's benefit
//
switch(baseRotation)
{
default:
// do nothing
break;
case 90:
case 270:
if (graphics_display != NULL)
{
Check(graphics_display);
bounds.bottomLeft.x = graphics_display->bounds.bottomLeft.y;
bounds.bottomLeft.y = graphics_display->bounds.bottomLeft.x;
bounds.topRight.x = graphics_display->bounds.topRight.y;
bounds.topRight.y = graphics_display->bounds.topRight.x;
}
break;
}
for(int j=0; j<256; ++j)
{
myColor[j] = NULL;
}
Check_Fpu();
}
L4GraphicsPort::~L4GraphicsPort()
{
Check(this);
Check_Fpu();
}
Logical
L4GraphicsPort::TestInstance() const
{
return True;
}
void
L4GraphicsPort::ShowInstance(char *indent)
{
Check(this);
std::cout << indent << "L4GraphicsPort:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
std::cout << temp << "bitMask =" << bitMask << "\n";
std::cout << temp << "baseRotation =" << baseRotation << "\n";
std::cout << temp << "maximumX =" << maximumX << "\n";
std::cout << temp << "maximumY =" << maximumY << "\n";
std::cout << temp << "bounds =" << bounds << "\n";
std::cout << std::flush;
GraphicsPort::ShowInstance(temp);
Check_Fpu();
}
void
L4GraphicsPort::SetColor(
PaletteTriplet *source_triplet,
int color_index
)
{
Check(this);
Check_Pointer(source_triplet);
Verify(color_index >= 0);
Verify(color_index < 256);
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
case L4GraphicsPort::BlankColor:
break;
default:
BuildSecondaryColor(source_triplet, color_index);
break;
}
Check_Fpu();
}
void
L4GraphicsPort::SetSecondaryPalette(
Palette8 *source_palette
)
{
Check(this);
Check(source_palette);
if (graphicsDisplay == NULL)
{
return;
}
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
BuildDirectTranslation(source_palette);
break;
case L4GraphicsPort::BlankColor:
BlankPalette();
BuildSecondaryTranslation();
break;
default:
BuildSecondaryPalette(source_palette);
BuildSecondaryTranslation();
break;
}
Check_Fpu();
}
void
L4GraphicsPort::SetAuxiliaryPalette()
{
Check(this);
if (graphicsDisplay == NULL)
{
return;
}
switch(channelEnable)
{
case L4GraphicsPort::DirectColor:
//---------------------------------------------------------------
// Set translation table for direct color mode
//---------------------------------------------------------------
{
Palette8
monochrome_palette;
PaletteTriplet
black,
white;
black.Red = 0;
black.Green = 0;
black.Blue = 0;
white.Red = 255;
white.Green = 255;
white.Blue = 255;
monochrome_palette.BuildColorRange(0,255,black, white);
BuildDirectTranslation(&monochrome_palette);
}
break;
case L4GraphicsPort::BlankColor:
BlankPalette();
BuildAuxiliaryTranslation();
break;
default:
BuildAuxiliaryPalette();
BuildAuxiliaryTranslation();
break;
}
Check_Fpu();
}
void
L4GraphicsPort::DrawPoint(
int color,
Enumeration operation,
int x, int y
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
graphicsDisplay->
DrawPoint(
translationTable[color],
bitMask,
operation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y
);
Check_Fpu();
}
void
L4GraphicsPort::DrawLine(
int color,
Enumeration operation,
int x1, int y1,
int x2, int y2,
Logical include_last_pixel
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
x1p, y1p,
x2p, y2p;
convertPortPair(&x1p, &y1p, x1, y1);
convertPortPair(&x2p, &y2p, x2, y2);
graphicsDisplay->
DrawLine(
translationTable[color],
bitMask,
operation,
x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y,
include_last_pixel
);
Check_Fpu();
}
void
L4GraphicsPort::DrawFilledRectangle(
int color,
Enumeration operation,
int x1, int y1,
int x2, int y2
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
int
x1p, y1p,
x2p, y2p;
convertPortPair(&x1p, &y1p, x1, y1);
convertPortPair(&x2p, &y2p, x2, y2);
graphicsDisplay->
DrawFilledRectangle(
translationTable[color],
bitMask,
operation,
x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y
);
Check_Fpu();
}
void
L4GraphicsPort::DrawText(
int /*color*/,
Enumeration /*operation*/,
Logical /*opaque*/,
int /*rotation*/,
Enumeration /*fontNumber*/,
Logical /*vertical*/,
GraphicsDisplay::Justification /*justification*/,
Rectangle2D */*clippingRectanglepointer*/,
char */*stringPointer*/
)
{
}
void
L4GraphicsPort::DrawBitMap(
int color,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (bitmap == NULL)
{
Check_Fpu();
return;
}
if (bitmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(bitmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawBitMap(
translationTable[color],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
bitmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::DrawBitMapOpaque(
int color,
int background,
Enumeration operation,
int rotation,
int x, int y,
BitMap *bitmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (bitmap == NULL)
{
Check_Fpu();
return;
}
if (bitmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(bitmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawBitMapOpaque(
translationTable[color],
translationTable[background],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
bitmap,
sLeft, sBottom, sRight, sTop
);
}
void
L4GraphicsPort::DrawPixelMap8(
Enumeration operation,
Logical opaque,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (pixelmap == NULL)
{
Check_Fpu();
return;
}
if (pixelmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(pixelmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawPixelMap8(
translationTable,
bitMask,
operation,
opaque,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
pixelmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::DrawPixelMap8SingleColor(
int color,
Enumeration operation,
int rotation,
int x, int y,
PixelMap8 *pixelmap,
int sLeft, int sBottom, int sRight, int sTop
)
{
Check(this);
if (graphicsDisplay == NULL)
{
Check_Fpu();
return;
}
Check(graphicsDisplay);
if (pixelmap == NULL)
{
Check_Fpu();
return;
}
if (pixelmap->Data.MapPointer == NULL)
{
Check_Fpu();
return;
}
Check(pixelmap);
int
xp, yp;
convertPortPair(&xp, &yp, x, y);
rotation += baseRotation;
while (rotation < 0) { rotation += 360; }
while (rotation >= 360) { rotation -= 360; }
graphicsDisplay->
DrawPixelMap8SingleColor(
translationTable[color],
bitMask,
operation,
rotation,
xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
pixelmap,
sLeft, sBottom, sRight, sTop
);
Check_Fpu();
}
void
L4GraphicsPort::convertPortPair(
int *xp,
int *yp,
int x,
int y
)
{
switch(baseRotation)
{
default:
*xp = x;
*yp = y;
break;
case 90:
*xp = y;
*yp = maximumY - x;
break;
case 180:
*xp = maximumX - x;
*yp = maximumY - y;
break;
case 270:
*xp = maximumX - y;
*yp = x;
break;
}
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table specifically for writing
// to a "direct" color mode display, in which colors are represented
// as 5 red bits, 6 green bits, and 5 blue bits in a display word.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildDirectTranslation(
Palette8 *source_palette
)
{
PaletteTriplet
*source_data(source_palette->Color);
int
*dest(translationTable);
int
red_bits,
green_bits,
blue_bits,
i;
//
// Force to all bits (just to be sure)
//
bitMask = 0xFFFF;
for(i=256; i>0; --i,++source_data)
{
red_bits = source_data->Red >> 3;
green_bits = source_data->Green >> 2;
blue_bits = source_data->Blue >> 3;
*dest++ = (red_bits << 11)|(green_bits << 5) | blue_bits;
}
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped onto the same RGB display, then
// the most recently built palette has precedence over the previous one(s).
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryPalette(
Palette8 *source_palette
)
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
Check(source_palette);
int
byte_mask(bitMask & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
PaletteTriplet
*source_triplet,
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
source_triplet = &source_palette->Color[0];
//-------------------------------------------
// Clear the 'owned color' flags
//-------------------------------------------
for(int j=0; j<256; ++j)
{
myColor[wrangler.Value] = 0;
}
//
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
//
if (channelEnable & 0x80)
{
++source_triplet;
wrangler.IncrementActive();
}
//
// Fill in the color table for this palette set
//
do
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
do
{
//-------------------------------------------
// Set the 'owned color' flag
//-------------------------------------------
myColor[wrangler.Value] = 1;
//-------------------------------------------
// Get destination pointer
//-------------------------------------------
destination_triplet =
&svga_palette->paletteData.Color[wrangler.Value];
//-------------------------------------------
// Copy color data
//-------------------------------------------
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = source_triplet->Red;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = source_triplet->Green;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = source_triplet->Blue;
break;
case AllChannels:
case AllChannelsTransparentZero:
*destination_triplet = *source_triplet;
break;
}
}
while (wrangler.IncrementInactive());
//-------------------------------------------
// Bump the source pointer
//-------------------------------------------
++source_triplet;
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped onto the same RGB display, then
// the most recently built palette has precedence over the previous one(s).
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryColor(
PaletteTriplet *source_triplet,
int dest_color_number
)
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
Check_Pointer(source_triplet);
int
byte_mask(bitMask & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
destination_color = 0;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
//-------------------------------------------
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
//-------------------------------------------
if (channelEnable & 0x80)
{
++destination_color;
wrangler.IncrementActive();
}
//-------------------------------------------
// Set the color value
//-------------------------------------------
do
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
if (destination_color == dest_color_number)
{
//-------------------------------------------
// Write all destination colors
//-------------------------------------------
do
{
//-------------------------------------------
// Do we own this color? Skip if unowned
//-------------------------------------------
if (myColor[wrangler.Value])
{
//-------------------------------------------
// Copy color data
//-------------------------------------------
destination_triplet =
&svga_palette->paletteData.Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = source_triplet->Red;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = source_triplet->Green;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = source_triplet->Blue;
break;
case AllChannels:
case AllChannelsTransparentZero:
*destination_triplet = *source_triplet;
break;
}
}
}
while (wrangler.IncrementInactive());
//-------------------------------------------
// Only doing one color, so exit the loop
//-------------------------------------------
break;
}
//-------------------------------------------
// Bump the color counter
//-------------------------------------------
++destination_color;
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method combines palettes from multiple L4GraphicsPorts.
// If several ports have palettes mapped on top of another, then
// the most recently built palette has precedence over the previous one(s).
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildAuxiliaryPalette()
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
rate,
accumulator;
Byte
color_value;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
Verify(((1<<wrangler.NumberOfActiveBits())-1) > 0);
rate = (255<<5)/((1<<wrangler.NumberOfActiveBits())-1);
accumulator = 0;
//
//-----------------------------------------------------------------------
// Generate palette
//-----------------------------------------------------------------------
//
// If any of the ...TransparentZero modes are used,
// leave color zero undefined for this bit group by
// skipping over it
if (channelEnable & 0x80)
{
accumulator += rate;
wrangler.IncrementActive();
}
do
{
color_value = (Byte) (accumulator >> 5);
accumulator += rate;
do
{
destination_triplet = &svga_palette->paletteData.
Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = color_value;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = color_value;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = color_value;
break;
case AllChannels:
case AllChannelsTransparentZero:
destination_triplet->Red = color_value;
destination_triplet->Green = color_value;
destination_triplet->Blue = color_value;
break;
}
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
# if defined(TESTPALETTE)
std::cout << "L4GraphicsPort::BuildAuxiliaryPalette for port " <<
std::hex << svga_palette->hardwarePort << "\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x03) == 0)
{
std::cout << std::dec << "\n" << i << ":" << std::hex;
}
std::cout << svga_palette->paletteData.Color[i] << " ";
}
std::cout << "\n";
{
Palette8
temp;
SVGAReadFullPalette(
&temp.Color[0].Red,
svga_palette->hardwarePort
);
std::cout << "L4GraphicsPort::BuildAuxiliaryPalette, read back\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x03) == 0)
{
std::cout << std::dec << "\n" << i << ":" << std::hex;
}
std::cout << temp.Color[i] << " ";
}
std::cout << "\n";
}
# endif
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This sets 'owned' color values in a palette to zero.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BlankPalette()
{
Verify (bitMask != 0);
if (graphicsDisplay == NULL)
{
return;
}
Check(graphicsDisplay);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify (byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
Byte
color_value;
PaletteTriplet
*destination_triplet;
SVGA16Palette
*svga_palette(&((SVGA16 *) graphicsDisplay)->palette[paletteID]);
Verify(((1<<wrangler.NumberOfActiveBits())-1) > 0);
color_value = 0;
do
{
do
{
destination_triplet = &svga_palette->paletteData.
Color[wrangler.Value];
switch(channelEnable)
{
case RedChannel:
case RedChannelTransparentZero:
destination_triplet->Red = color_value;
break;
case GreenChannel:
case GreenChannelTransparentZero:
destination_triplet->Green = color_value;
break;
case BlueChannel:
case BlueChannelTransparentZero:
destination_triplet->Blue = color_value;
break;
case AllChannels:
case AllChannelsTransparentZero:
destination_triplet->Red = color_value;
destination_triplet->Green = color_value;
destination_triplet->Blue = color_value;
break;
}
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
svga_palette->paletteData.Valid = True;
svga_palette->modified = True;
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table for the secondary display,
// using a previously set palette and channel.
//
// Palettes are assumed to always have 256 colors.
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildSecondaryTranslation()
{
Verify((bitMask & 0xFF) != 0);
BitWrangler
wrangler(bitMask & 0xFF, 8);
int
*destination(translationTable);
do
{
*destination++ = wrangler.Value;
}
while (wrangler.IncrementActive());
Check_Fpu();
}
//
//---------------------------------------------------------------------------
// This method generates a translation table for the auxiliary displays.
//
// Palettes are assumed to always have 256 colors (0=black, 255=white).
//---------------------------------------------------------------------------
//
void
L4GraphicsPort::BuildAuxiliaryTranslation()
{
Verify(numberOfBits != 0);
Verify(numberOfBits <= 8);
int
byte_mask((bitMask >> 8) & 0xFF);
Verify(byte_mask != 0);
BitWrangler
wrangler(byte_mask, 8);
int
*destination(translationTable);
int
currentValue;
//
// Generate lookup table
//
do
{
currentValue = wrangler.Value << 8;
do
{
*destination++ = currentValue;
}
while (wrangler.IncrementInactive());
}
while (wrangler.IncrementActive());
# if defined(TESTPALETTE)
std::cout << "L4GraphicsPort::BuildAuxiliaryTranslation\n";
for(int i=0; i<256; ++i)
{
if ((i & 0x07) == 0)
{
std::cout << "\n" << std::dec << i << ":" << std::hex;
}
std::cout << translationTable[i] << " ";
}
std::cout << "\n";
# endif
Check_Fpu();
}