mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-16 12:08:36 +00:00
547 lines
14 KiB
C++
547 lines
14 KiB
C++
#include "ht.h"
|
|
|
|
namespace wi {
|
|
|
|
// Dib bitmaps
|
|
|
|
DibBitmap *CreateDibBitmap(byte *pb, int cx, int cy)
|
|
{
|
|
DibBitmap *pbm = new DibBitmap;
|
|
Assert(pbm != NULL, "out of memory!");
|
|
if (pbm == NULL)
|
|
return NULL;
|
|
if (!pbm->Init(pb, cx, cy)) {
|
|
delete pbm;
|
|
return NULL;
|
|
}
|
|
return pbm;
|
|
}
|
|
|
|
DibBitmap::DibBitmap()
|
|
{
|
|
m_cbRow = 0;
|
|
m_cb = 0;
|
|
m_pb = NULL;
|
|
m_siz.cx = 0;
|
|
m_siz.cy = 0;
|
|
m_wf = 0;
|
|
}
|
|
|
|
DibBitmap::~DibBitmap()
|
|
{
|
|
if (m_wf & kfDibFreeMem)
|
|
delete[] m_pb;
|
|
m_pb = NULL;
|
|
}
|
|
|
|
bool DibBitmap::Init(byte *pb, int cx, int cy)
|
|
{
|
|
m_cbRow = (cx + 1) & ~1;
|
|
m_cb = (int)cy * m_cbRow;
|
|
if (pb == NULL) {
|
|
m_pb = new byte[m_cb];
|
|
Assert(m_pb != NULL, "out of memory!");
|
|
m_wf |= kfDibFreeMem;
|
|
} else {
|
|
m_pb = pb;
|
|
}
|
|
m_siz.cx = cx;
|
|
m_siz.cy = cy;
|
|
return m_pb != NULL;
|
|
}
|
|
|
|
byte *DibBitmap::GetBits()
|
|
{
|
|
return m_pb;
|
|
}
|
|
|
|
int DibBitmap::GetRowBytes()
|
|
{
|
|
return m_cbRow;
|
|
}
|
|
|
|
#define TopToBottomBltThunk LeftToRightBltThunk
|
|
#define FastestBltThunk LeftToRightBltThunk
|
|
#define BottomToTopBltThunk RightToLeftBltThunk
|
|
|
|
void DibBitmap::Blt(DibBitmap *pbmSrc, Rect *prcSrc, int xDst, int yDst)
|
|
{
|
|
// Get src dib dimensions
|
|
|
|
Size sizSrc;
|
|
pbmSrc->GetSize(&sizSrc);
|
|
|
|
// Clip to source rect
|
|
|
|
if (prcSrc->left < 0)
|
|
prcSrc->left = 0;
|
|
if (prcSrc->top < 0)
|
|
prcSrc->top = 0;
|
|
if (prcSrc->right > sizSrc.cx)
|
|
prcSrc->right = sizSrc.cx;
|
|
if (prcSrc->bottom > sizSrc.cy)
|
|
prcSrc->bottom = sizSrc.cy;
|
|
|
|
// Clip to dest
|
|
|
|
if (xDst < 0) {
|
|
prcSrc->left -= xDst;
|
|
xDst = 0;
|
|
}
|
|
if (yDst < 0) {
|
|
prcSrc->top -= yDst;
|
|
yDst = 0;
|
|
}
|
|
|
|
int xRightDst = xDst + prcSrc->Width();
|
|
if (xRightDst > m_siz.cx)
|
|
prcSrc->right -= xRightDst - m_siz.cx;
|
|
int yBottomDst = yDst + prcSrc->Height();
|
|
if (yBottomDst > m_siz.cy)
|
|
prcSrc->bottom -= yBottomDst - m_siz.cy;
|
|
|
|
// Anything to blt?
|
|
|
|
if (prcSrc->IsEmpty())
|
|
return;
|
|
|
|
// Figure out direction to blt if we're doing a blt in the same dib
|
|
|
|
if (this == pbmSrc) {
|
|
// Calc addresses
|
|
|
|
byte *pbSrc = m_pb + (long)prcSrc->top * m_cbRow + prcSrc->left;
|
|
byte *pbDst = m_pb + (long)yDst * m_cbRow + xDst;
|
|
|
|
// If same y, ...
|
|
|
|
if (yDst == prcSrc->top) {
|
|
// Overlap?
|
|
|
|
int cxInterval = prcSrc->right - xDst;
|
|
if (cxInterval > 0 && cxInterval < prcSrc->Width() * 2) {
|
|
// Overlap. If bltting to the left, copy from left to right
|
|
|
|
if (xDst < prcSrc->left) {
|
|
LeftToRightBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
} else {
|
|
RightToLeftBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
}
|
|
} else {
|
|
// No overlap. Do the fastest blt
|
|
|
|
FastestBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
}
|
|
} else {
|
|
int cyInterval = prcSrc->bottom - yDst;
|
|
if (cyInterval > 0 && cyInterval < prcSrc->Height() * 2) {
|
|
// Overlap. If bltting upwards, copy from top to bottom
|
|
|
|
if (yDst < prcSrc->top) {
|
|
TopToBottomBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
} else {
|
|
BottomToTopBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
}
|
|
} else {
|
|
// No overlap. Do the fastest blt
|
|
|
|
FastestBltThunk(pbSrc, m_cbRow, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
}
|
|
}
|
|
} else {
|
|
// No overlap. Do the fastest blt
|
|
|
|
int cbRowBytesSrc = pbmSrc->GetRowBytes();
|
|
byte *pbSrc = pbmSrc->GetBits() + (long)prcSrc->top * cbRowBytesSrc + prcSrc->left;
|
|
byte *pbDst = m_pb + (long)yDst * m_cbRow + xDst;
|
|
|
|
FastestBltThunk(pbSrc, cbRowBytesSrc, pbDst, m_cbRow, prcSrc->Width(), prcSrc->Height());
|
|
}
|
|
}
|
|
|
|
void DibBitmap::Clear(Color clr)
|
|
{
|
|
#ifdef __CPU_68K
|
|
if (gfArmPresent) {
|
|
memsetArm(m_pb, (byte)clr, m_cb);
|
|
return;
|
|
}
|
|
#endif
|
|
memset(m_pb, (byte)clr, m_cb);
|
|
}
|
|
|
|
void DibBitmap::Fill(int x, int y, int cx, int cy, Color clr)
|
|
{
|
|
// Destination clipping
|
|
|
|
if (x < 0) {
|
|
cx += x;
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
cy += y;
|
|
y = 0;
|
|
}
|
|
if (x + cx > m_siz.cx)
|
|
cx = m_siz.cx - x;
|
|
if (y + cy > m_siz.cy)
|
|
cy = m_siz.cy - y;
|
|
|
|
if (cx <= 0 || cy <= 0)
|
|
return;
|
|
|
|
// Drawing
|
|
|
|
byte *pbDst = m_pb + (long)y * m_cbRow + x;
|
|
FillThunk(pbDst, cx, cy, m_cbRow, (byte)clr);
|
|
}
|
|
|
|
void DibBitmap::Shadow(int x, int y, int cx, int cy)
|
|
{
|
|
// Destination clipping
|
|
|
|
if (x < 0) {
|
|
cx += x;
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
cy += y;
|
|
y = 0;
|
|
}
|
|
if (x + cx > m_siz.cx)
|
|
cx = m_siz.cx - x;
|
|
if (y + cy > m_siz.cy)
|
|
cy = m_siz.cy - y;
|
|
|
|
if (cx <= 0 || cy <= 0)
|
|
return;
|
|
|
|
byte *pbRow = m_pb + (long)y * m_cbRow + x;
|
|
FillShadowThunk(pbRow, m_cbRow, cx, cy, gmpiclriclrShadow);
|
|
}
|
|
|
|
void DibBitmap::GetSize(Size *psiz)
|
|
{
|
|
*psiz = m_siz;
|
|
}
|
|
|
|
#ifdef DRAW_LINES
|
|
|
|
#define LEFT 1
|
|
#define RIGHT 2
|
|
#define BOTTOM 4
|
|
#define TOP 8
|
|
|
|
#define SWAP(x, y) { int _t = x; x = y; y = _t; }
|
|
|
|
#define OUTCODE(x, y, outcode, type) \
|
|
{ \
|
|
if (x < xl) outcode = LEFT, type = 1; \
|
|
else if (x > xr) outcode = RIGHT, type = 1; \
|
|
else outcode = type = 0; \
|
|
if (y < yb) outcode |= BOTTOM, type++; \
|
|
else if (y > yt) outcode |= TOP, type++; \
|
|
}
|
|
|
|
#define CLIP(a1, a2, b1, da, da2, db2, as, bs, sa, sb, \
|
|
amin, AMIN, amax, AMAX, bmin, BMIN, bmax, BMAX) \
|
|
{ \
|
|
if (out1) { \
|
|
if (out1 & AMIN) { ca = db2 * (amin - a1); as = amin; } \
|
|
else if (out1 & AMAX) { ca = db2 * (a1 - amax); as = amax; } \
|
|
if (out1 & BMIN) { cb = da2 * (bmin - b1); bs = bmin; } \
|
|
else if (out1 & BMAX) { cb = da2 * (b1 - bmax); bs = bmax; } \
|
|
if (type1 == 2) \
|
|
out1 &= (ca + da < cb) ? ~(AMIN | AMAX) : ~(BMAX | BMIN); \
|
|
if (out1 & (AMIN | AMAX)) { \
|
|
cb = (ca + da) / da2; \
|
|
if (sb >= 0) { if ((bs = b1 + cb) > bmax) return; } \
|
|
else { if ((bs = b1 - cb) < bmin) return; } \
|
|
r += ca - da2 * cb; \
|
|
} \
|
|
else { \
|
|
ca = (cb - da + db2 - 1) / db2; \
|
|
if (sa >= 0) { if ((as = a1 + ca) > amax) return; } \
|
|
else { if ((as = a1 - ca) < amin) return; } \
|
|
r += db2 * ca - cb; \
|
|
} \
|
|
} \
|
|
else { as = a1; bs = b1; } \
|
|
alt = 0; \
|
|
if (out2) { \
|
|
if (type2 == 2) { \
|
|
ca = db2 * ((out2 & AMIN) ? a1 - amin : amax - a1); \
|
|
cb = da2 * ((out2 & BMIN) ? b1 - bmin : bmax - b1); \
|
|
out2 &= (cb + da < ca + 1) ? ~(AMIN | AMAX) : ~(BMIN | BMAX); \
|
|
} \
|
|
if (out2 & (AMIN | AMAX)) n = (out2 & AMIN) ? as - amin : amax - as; \
|
|
else { n = (out2 & BMIN) ? bs - bmin : bmax - bs; alt = 1; } \
|
|
} \
|
|
else n = (a2 >= as) ? a2 - as : as - a2; \
|
|
}
|
|
|
|
#define plot(x, y) (*(m_pb + (y * m_cbRow) + x) = (byte)clr)
|
|
|
|
void DibBitmap::DrawLine(short x1, short y1, short x2, short y2, Color clr)
|
|
{
|
|
int xl = 0, yb = 0;
|
|
int xr = m_siz.cx - 1;
|
|
int yt = m_siz.cy - 1;
|
|
|
|
int adx, ady, adx2, ady2, sx, sy;
|
|
int out1, out2, type1, type2;
|
|
int ca, cb, r, diff, xs, ys, n, alt;
|
|
|
|
OUTCODE(x1, y1, out1, type1);
|
|
OUTCODE(x2, y2, out2, type2);
|
|
if (out1 & out2) return;
|
|
if ((type1 != 0 && type2 == 0) || (type1 == 2 && type2 == 1)){
|
|
SWAP(out1, out2);
|
|
SWAP(type1, type2);
|
|
SWAP(x1, x2);
|
|
SWAP(y1, y2);
|
|
}
|
|
xs = x1;
|
|
ys = y1;
|
|
sx = 1;
|
|
adx = x2 - x1;
|
|
if (adx < 0) { adx = -adx; sx = -1; }
|
|
sy = 1;
|
|
ady = y2 - y1;
|
|
if (ady < 0) { ady = -ady; sy = -1; }
|
|
adx2 = adx + adx;
|
|
ady2 = ady + ady;
|
|
if (adx >= ady) {
|
|
/*
|
|
* line is semi-horizontal
|
|
*/
|
|
r = ady2 - adx;
|
|
CLIP(x1, x2, y1, adx, adx2, ady2, xs, ys, sx, sy,
|
|
xl, LEFT, xr, RIGHT, yb, BOTTOM, yt, TOP);
|
|
diff = ady2 - adx2;
|
|
if (alt) {
|
|
for (;; xs += sx) { /* alternate Bresenham */
|
|
plot(xs, ys);
|
|
if (r >= 0 ) {
|
|
if (--n < 0) break;
|
|
r += diff;
|
|
ys += sy;
|
|
}
|
|
else r += ady2;
|
|
}
|
|
}
|
|
else{
|
|
for (;; xs += sx) { /* standard Bresenham */
|
|
plot(xs, ys);
|
|
if (--n < 0) break;
|
|
if (r >= 0 ) { r += diff; ys += sy; }
|
|
else r += ady2;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
* line is semi-vertical
|
|
*/
|
|
r = adx2 - ady;
|
|
CLIP(y1, y2, x1, ady, ady2, adx2, ys, xs, sy, sx,
|
|
yb, BOTTOM, yt, TOP, xl, LEFT, xr, RIGHT);
|
|
diff = adx2 - ady2;
|
|
if (alt) {
|
|
for (;; ys += sy) { /* alternate Bresenham */
|
|
plot(xs, ys);
|
|
if (r >= 0 ) {
|
|
if (--n < 0) break;
|
|
r += diff;
|
|
xs += sx;
|
|
}
|
|
else r += adx2;
|
|
}
|
|
}
|
|
else {
|
|
for (;; ys += sy) { /* standard Bresenham */
|
|
plot(xs, ys);
|
|
if (--n < 0) break;
|
|
if (r >= 0 ) { r += diff; xs += sx; }
|
|
else r += adx2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // DRAW_LINES
|
|
|
|
DibBitmap *DibBitmap::Suballoc(int yTop, int cy)
|
|
{
|
|
Assert(yTop < m_siz.cy && yTop + cy <= m_siz.cy);
|
|
byte *pb = m_pb + (long)m_siz.cx * yTop;
|
|
return CreateDibBitmap(pb, m_siz.cx, cy);
|
|
}
|
|
|
|
void DibBitmap::Scroll(Rect *prcSrc, int xDst, int yDst)
|
|
{
|
|
// Some implementations do blts differently (such as rotated dibs).
|
|
// That is why this method - essentially a blt from and to the
|
|
// destination - exists.
|
|
Blt(this, prcSrc, xDst, yDst);
|
|
}
|
|
|
|
#ifdef __CPU_68K
|
|
void DibBitmap::BltTiles(DibBitmap *pbmSrc, UpdateMap *pupd, int yTopDst)
|
|
{
|
|
// OS5 path usually not executed
|
|
|
|
if (IsOS50Compat()) {
|
|
bool fFirst = true;
|
|
Rect rc;
|
|
while (pupd->EnumUpdateRects(fFirst, NULL, &rc)) {
|
|
fFirst = false;
|
|
Blt(pbmSrc, &rc, rc.left, rc.top + yTopDst);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Init
|
|
|
|
bool *pfMap = pupd->GetInvalidMap();
|
|
MapInfo *pmnfo = pupd->GetMapInfo();
|
|
Size sizMap;
|
|
pupd->GetMapSize(&sizMap);
|
|
|
|
dword cbOffset = yTopDst * (dword)m_siz.cx;
|
|
byte *pbSrc = pbmSrc->GetBits();
|
|
byte *pbDst = m_pb + cbOffset;
|
|
|
|
switch (gcxTile) {
|
|
case 16:
|
|
UpdateScreen816(pfMap, sizMap.cx, sizMap.cy, pbSrc, pbDst, m_siz.cx,
|
|
pmnfo->cxLeftTile, pmnfo->cyTopTile, pmnfo->cxRightTile, pmnfo->cyBottomTile, pmnfo->ctxInside, pmnfo->ctyInside);
|
|
break;
|
|
|
|
case 24:
|
|
UpdateScreen824(pfMap, sizMap.cx, sizMap.cy, pbSrc, pbDst, m_siz.cx,
|
|
pmnfo->cxLeftTile, pmnfo->cyTopTile, pmnfo->cxRightTile, pmnfo->cyBottomTile, pmnfo->ctxInside, pmnfo->ctyInside);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#else
|
|
void DibBitmap::BltTiles(DibBitmap *pbmSrc, UpdateMap *pupd, int yTopDst)
|
|
{
|
|
bool fFirst = true;
|
|
Rect rc;
|
|
while (pupd->EnumUpdateRects(fFirst, NULL, &rc)) {
|
|
fFirst = false;
|
|
Blt(pbmSrc, &rc, rc.left, rc.top + yTopDst);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void DibBitmap::BltTiles(DibBitmap *pbmSrc, UpdateMap *pupd, int yTopDst)
|
|
{
|
|
MapInfo *pmnfo = pupd->GetMapInfo();
|
|
bool *pfInvalid = pupd->GetInvalidMap();
|
|
Size sizMap;
|
|
pupd->GetMapSize(&sizMap);
|
|
int cbReturn = sizMap.cx - ((pmnfo->cxLeftTile != 0 ? 1 : 0) + pmnfo->ctxInside + (pmnfo->cxRightTile != 0 ? 1 : 0));
|
|
|
|
Rect rcSrc;
|
|
int xT = 0;
|
|
int yDst = yTopDst;
|
|
int ySrc = 0;
|
|
if (pmnfo->cyTopTile != 0) {
|
|
// Upper left corner
|
|
|
|
if (pmnfo->cxLeftTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxLeftTile, ySrc + pmnfo->cyTopTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += pmnfo->cxLeftTile;
|
|
|
|
// Upper edge
|
|
|
|
for (int tx = 0; tx < pmnfo->ctxInside; tx++) {
|
|
if (*pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + gcxTile, ySrc + pmnfo->cyTopTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += gcxTile;
|
|
}
|
|
|
|
// Upper right corner
|
|
|
|
if (pmnfo->cxRightTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxRightTile, ySrc + pmnfo->cyTopTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT = 0;
|
|
yDst += pmnfo->cyTopTile;
|
|
ySrc += pmnfo->cyTopTile;
|
|
pfInvalid += cbReturn;
|
|
}
|
|
|
|
// Inside
|
|
|
|
for (int ty = 0; ty < pmnfo->ctyInside; ty++) {
|
|
|
|
// Inside left
|
|
|
|
if (pmnfo->cxLeftTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxLeftTile, ySrc + gcyTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += pmnfo->cxLeftTile;
|
|
|
|
// Inside
|
|
|
|
for (int tx = 0; tx < pmnfo->ctxInside; tx++) {
|
|
if (*pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + gcxTile, ySrc + gcyTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += gcxTile;
|
|
}
|
|
|
|
// Inside right
|
|
|
|
if (pmnfo->cxRightTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxRightTile, ySrc + gcyTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT = 0;
|
|
yDst += gcyTile;
|
|
ySrc += gcyTile;
|
|
pfInvalid += cbReturn;
|
|
}
|
|
|
|
if (pmnfo->cyBottomTile != 0) {
|
|
// Bottom left tile
|
|
|
|
if (pmnfo->cxLeftTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxLeftTile, ySrc + pmnfo->cyBottomTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += pmnfo->cxLeftTile;
|
|
|
|
// Bottom edge
|
|
|
|
for (int tx = 0; tx < pmnfo->ctxInside; tx++) {
|
|
if (*pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + gcxTile, ySrc + pmnfo->cyBottomTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
xT += gcxTile;
|
|
}
|
|
|
|
// Bottom right corner
|
|
|
|
if (pmnfo->cxRightTile != 0 && *pfInvalid++) {
|
|
rcSrc.Set(xT, ySrc, xT + pmnfo->cxRightTile, ySrc + pmnfo->cyBottomTile);
|
|
Blt(pbmSrc, &rcSrc, xT, yDst);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
} // namespace wi
|