diff --git a/game/bitmap.cpp b/game/bitmap.cpp index e69de29..6a515d5 100644 --- a/game/bitmap.cpp +++ b/game/bitmap.cpp @@ -0,0 +1,283 @@ +#include "ht.h" + +#if defined(SDL) +#include +#include + +#define SURFACE_FLAGS 0 +#define SURFACE_DEPTH 32 +#define SURFACE_PITCH(x) x*4 // row length in bytes: x*sizeof(byte)*sizeof(dword) +#define SHADOW_ALPHA_MOD 100 +#endif // defined(SDL) + +namespace wi { + +#if defined(SDL) + +DibBitmap::DibBitmap() +{ + m_surface = NULL; + m_wf = 0; + m_pszFn = NULL; + m_renderer = NULL; +} + +DibBitmap::~DibBitmap() +{ + SDL_DestroyRenderer(m_renderer); + SDL_FreeSurface(m_surface); + if (m_wf & kfDibFreeMem) + free(m_surface->pixels); + m_surface = NULL; + if (m_pszFn != NULL) + delete[] m_pszFn; +} + +DibBitmap *LoadDibBitmap(char *pszFn) +{ + DibBitmap *pbm = new DibBitmap(); + Assert(pbm != NULL, "out of memory!"); + if (pbm == NULL) + return NULL; + if (!pbm->Init(pszFn)) { + delete pbm; + return NULL; + } + return pbm; +} + +DibBitmap *CreateDibBitmap(dword *pb, int cx, int cy, bool alpha) +{ + DibBitmap *pbm = new DibBitmap(); + Assert(pbm != NULL, "out of memory!"); + if (pbm == NULL) + return NULL; + if (!pbm->Init(pb, cx, cy, alpha, false)) { + delete pbm; + return NULL; + } + return pbm; +} + +DibBitmap *CreateBigDibBitmap(dword *pb, int cx, int cy, bool alpha) +{ + DibBitmap *pbm = new DibBitmap(); + Assert(pbm != NULL, "out of memory!"); + if (pbm == NULL) + return NULL; + if (!pbm->Init(pb, cx, cy, alpha, true)) { + delete pbm; + return NULL; + } + return pbm; +} + +bool DibBitmap::Init(char *pszFn) +{ + // Read the file + + File *pfil = gpakr.fopen(pszFn, "rb"); + if (pfil == NULL) + return false; + byte *pb = new byte[pfil->cbTotal]; + + if (gpakr.fread(pb, pfil->cbTotal, 1, pfil) != 1) + return false; + + // Feed the bytes into an SDL surface + + SDL_RWops *prwio = SDL_RWFromMem(pb, pfil->cbTotal); + m_surface = IMG_Load_RW(prwio, 0); + + // Cleanup + + SDL_FreeRW(prwio); + delete[] pb; + gpakr.fclose(pfil); + + // Keep the name around + + m_pszFn = AllocString(pszFn); + + return m_surface != NULL; +} + +bool DibBitmap::Init(dword *pb, int cx, int cy, bool alpha, bool bigendian) +{ + Uint32 rmask, gmask, bmask, amask; + if (bigendian) { + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; + } else { + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; + } + if (!alpha) + amask = 0; + + if (pb == NULL) { + m_surface = SDL_CreateRGBSurface(SURFACE_FLAGS, cx, cy, SURFACE_DEPTH, + rmask, gmask, bmask, amask); + } else { + m_surface = SDL_CreateRGBSurfaceFrom(pb, cx, cy, SURFACE_DEPTH, SURFACE_PITCH(cx), + rmask, gmask, bmask, amask); + + // When using SDL_CreateRGBSurfaceFrom(), SDL does not manage the pixel data + // so it will need to be freed manually + + m_wf |= kfDibFreeMem; + } + +#if 0 + // This can be used to set the alpha color (only works if amask is 0) + // SDL_SetColorKey(m_surface, 1, SDL_MapRGB(m_surface->format, 255, 0, 255)); +#endif + + return m_surface != NULL; +} + +void DibBitmap::Blt(DibBitmap *pbmSrc, Rect *prcSrc, int xDst, int yDst) +{ + if (prcSrc == NULL) { + SDL_Rect rcDst = { xDst, yDst, pbmSrc->GetSurface()->w, pbmSrc->GetSurface()->h }; + SDL_BlitSurface(pbmSrc->GetSurface(), NULL, m_surface, &rcDst); + } else { + SDL_Rect rcSrc = { prcSrc->left, prcSrc->top, prcSrc->Width(), prcSrc->Height() }; + SDL_Rect rcDst = { xDst, yDst, prcSrc->Width(), prcSrc->Height() }; + SDL_BlitSurface(pbmSrc->GetSurface(), &rcSrc, m_surface, &rcDst); + } +} + +void DibBitmap::BltTo(class DibBitmap *pbmDst, int xDst, int yDst, Rect *prcSrc) +{ + if (prcSrc == NULL) { + SDL_Rect rcDst = { xDst, yDst, m_surface->w, m_surface->h }; + SDL_BlitSurface(m_surface, NULL, pbmDst->GetSurface(), &rcDst); + } else { + SDL_Rect rcSrc = { prcSrc->left, prcSrc->top, prcSrc->Width(), prcSrc->Height() }; + SDL_Rect rcDst = { xDst, yDst, prcSrc->Width(), prcSrc->Height() }; + SDL_BlitSurface(m_surface, &rcSrc, pbmDst->GetSurface(), &rcDst); + } +} + +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); + } +} + +void DibBitmap::GetSize(Size *psiz) +{ + psiz->cx = m_surface->w; + psiz->cy = m_surface->h; +} + +dword *DibBitmap::GetBits() +{ + return (dword *)m_surface->pixels; +} + +int DibBitmap::GetPitch() +{ + return m_surface->pitch; +} + +void DibBitmap::Fill(int x, int y, int cx, int cy, Color clr) +{ + SDL_Rect rc = { x, y, cx, cy }; + SDL_FillRect(m_surface, &rc, clr); +} + +void DibBitmap::FillTo(class DibBitmap *pbmDst, int xDst, int yDst, + int cxDst, int cyDst, int xOrigin, int yOrigin) +{ + Rect rcclp; + + // For every y point that is disivible by m_surface->h + + for (int y = 0; y < cyDst; y++) { + if (!(y % m_surface->h)) { + + // For every x point that is disivible by m_surface->w + + for (int x = 0; x < cxDst; x++) { + if (!(x % m_surface->w)) { + + // Blt and clip appropriately + + rcclp.Set(xDst + x, yDst + y, cxDst, cyDst); + pbmDst->Blt(this, NULL, xDst + x, yDst + y); + } + } + } + } +} + +void DibBitmap::Clear(Color clr) +{ + Fill(0, 0, m_surface->w, m_surface->h, clr); +} + +void DibBitmap::Shadow(int x, int y, int cx, int cy) +{ + DibBitmap *pbm = CreateDibBitmap(NULL, cx, cy); + pbm->Clear(GetColor(kiclrBlack)); + + SDL_SetSurfaceBlendMode(pbm->GetSurface(), SDL_BLENDMODE_BLEND); + SDL_SetSurfaceAlphaMod(pbm->GetSurface(), SHADOW_ALPHA_MOD); + + pbm->BltTo(this, x, y); +} + +void DibBitmap::DrawLine(short x1, short y1, short x2, short y2, Color clr) +{ + if (m_renderer == NULL) + if ((m_renderer = SDL_CreateSoftwareRenderer(m_surface)) == NULL) + return; + + byte r, g, b; + SDL_GetRGB(clr, m_surface->format, &r, &g, &b); + + SDL_SetRenderDrawColor(m_renderer, r, g, b, 255); + SDL_RenderDrawLine(m_renderer, x1, y1, x2, y2); +} + +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); +} + + +DibBitmap *DibBitmap::Suballoc(int yTop, int cy) +{ + Assert(yTop < m_surface->h && yTop + cy <= m_surface->h); + dword *pb = (dword *)m_surface->pixels + (long)m_surface->w * yTop; + DibBitmap *pbm = CreateDibBitmap(pb, m_surface->w, cy); + + // We don't want it to free memory since that will be taken care + // of by 'this' + if (pbm != NULL) + pbm->SetFlags(pbm->GetFlags() & ~kfDibFreeMem); + + return pbm; +} + +dword DibBitmap::MapRGB(byte r, byte g, byte b) +{ + return SDL_MapRGB(m_surface->format, r, g, b); +} + +#endif // defined(SDL) + +} // namespace wi diff --git a/game/ht.h b/game/ht.h index 919e5a8..abc663e 100644 --- a/game/ht.h +++ b/game/ht.h @@ -1055,6 +1055,71 @@ struct TBitmapHeader // tbh TBitmapEntry atbe[1]; }; +// DibBitmap + +#define kfDibFreeMem 0x0001 +#define kfDibBackWindow 0x0002 +#define kfDibWantScrolls 0x0004 + +class DibBitmap +{ +public: + DibBitmap() secDibBitmap; + ~DibBitmap() secDibBitmap; + + bool Init(char *pszFn) secDibBitmap; + bool Init(dword *pb, int cx, int cy, bool alpha, bool bigendian) secDibBitmap; + + void Blt(DibBitmap *pbmSrc, Rect *prcSrc, int xDst, int yDst) secDibBitmap; + void BltTo(class DibBitmap *pbmDst, int xDst, int yDst, Rect *prcSrc = NULL) secDibBitmap; + void BltTiles(DibBitmap *pbmSrc, UpdateMap *pupd, int yTopDst) secDibBitmap; + + void GetSize(Size *psiz) secDibBitmap; + dword *GetBits() secDibBitmap; + int GetPitch() secDibBitmap; + + void Fill(int x, int y, int cx, int cy, Color clr) secDibBitmap; + void FillTo(class DibBitmap *pbmDst, int xDst, int yDst, + int cxDst, int cyDst, int xOrigin = 0, int yOrigin = 0) secDibBitmap; + void Clear(Color clr) secDibBitmap; + void Shadow(int x, int y, int cx, int cy) secDibBitmap; + void DrawLine(short x1, short y1, short x2, short y2, Color clr) secDibBitmap; + void Scroll(Rect *prcSrc, int xDst, int yDst) secDibBitmap; + + DibBitmap *Suballoc(int yTop, int cy) secDibBitmap; + + word GetFlags() { + return m_wf; + } + void SetFlags(word wf) { + m_wf = wf; + } + int GetBaseline() { + return 0; + } + char *GetFileName() { + return m_pszFn; + } + +#if defined(SDL) + int GetWidth() { return m_surface->w; } + int GetHeight() { return m_surface->h; } + dword MapRGB(byte r, byte g, byte b); + SDL_Surface *GetSurface() { return m_surface; } +#endif + char *m_pszFn; + +private: +#if defined(SDL) + SDL_Surface *m_surface; + SDL_Renderer *m_renderer; +#endif + word m_wf; +}; +DibBitmap *LoadDibBitmap(char *pszFn) secDibBitmap; +DibBitmap *CreateDibBitmap(dword *pb, int cx, int cy, bool alpha = false) secDibBitmap; +DibBitmap *CreateBigDibBitmap(dword *pb, int cx, int cy, bool alpha = false) secDibBitmap; + struct FontHeader // fnth { word cy;