| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design) |
| 5 | * Copyright (c) 2017-2021, The LegacyClonk Team and contributors |
| 6 | * |
| 7 | * Distributed under the terms of the ISC license; see accompanying file |
| 8 | * "COPYING" for details. |
| 9 | * |
| 10 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 11 | * See accompanying file "TRADEMARK" for details. |
| 12 | * |
| 13 | * To redistribute this file separately, substitute the full license texts |
| 14 | * for the above references. |
| 15 | */ |
| 16 | |
| 17 | /* a wrapper class to DirectDraw surfaces */ |
| 18 | |
| 19 | #pragma once |
| 20 | |
| 21 | #include "C4Rect.h" |
| 22 | #include "Standard.h" |
| 23 | #include "StdColors.h" |
| 24 | |
| 25 | #ifndef USE_CONSOLE |
| 26 | #include <GL/glew.h> |
| 27 | #endif |
| 28 | |
| 29 | #include <list> |
| 30 | |
| 31 | // config settings |
| 32 | #define C4GFXCFG_NO_ALPHA_ADD 1 |
| 33 | #define C4GFXCFG_POINT_FILTERING 2 |
| 34 | #define C4GFXCFG_NOADDITIVEBLTS 8 |
| 35 | #define C4GFXCFG_NOBOXFADES 16 |
| 36 | #define C4GFXCFG_NOACCELERATION 512 |
| 37 | |
| 38 | // blitting modes |
| 39 | #define C4GFXBLIT_NORMAL 0 // regular blit |
| 40 | #define C4GFXBLIT_ADDITIVE 1 // all blits additive |
| 41 | #define C4GFXBLIT_MOD2 2 // additive color modulation |
| 42 | #define C4GFXBLIT_CLRSFC_OWNCLR 4 // do not apply global modulation to ColorByOwner-surface |
| 43 | #define C4GFXBLIT_CLRSFC_MOD2 8 // additive color modulation for ClrByOwner-surface |
| 44 | |
| 45 | #define C4GFXBLIT_ALL 15 // bist mask covering all blit modes |
| 46 | #define C4GFXBLIT_NOADD 14 // bit mask covering all blit modes except additive |
| 47 | |
| 48 | #define C4GFXBLIT_CUSTOM 128 // custom blitting mode - ignored by gfx system |
| 49 | #define C4GFXBLIT_PARENT 256 // blitting mode inherited by parent - ignored by gfx system |
| 50 | |
| 51 | const int ALeft = 0, ACenter = 1, ARight = 2; |
| 52 | |
| 53 | #ifndef USE_CONSOLE |
| 54 | class CStdGL; |
| 55 | extern CStdGL *pGL; |
| 56 | #endif |
| 57 | |
| 58 | // class predefs |
| 59 | class C4TexRef; |
| 60 | class C4TexMgr; |
| 61 | class CPattern; |
| 62 | class CStdDDraw; |
| 63 | |
| 64 | extern CStdDDraw *lpDDraw; |
| 65 | |
| 66 | class C4Group; |
| 67 | class C4GroupSet; |
| 68 | |
| 69 | class C4Surface |
| 70 | { |
| 71 | public: |
| 72 | C4Surface(); |
| 73 | ~C4Surface(); |
| 74 | C4Surface(std::int32_t width, std::int32_t height); |
| 75 | |
| 76 | C4Surface(const C4Surface &other) = delete; |
| 77 | C4Surface &operator=(const C4Surface &other) = delete; |
| 78 | |
| 79 | C4Surface(C4Surface &&other); |
| 80 | C4Surface &operator=(C4Surface &&other); |
| 81 | |
| 82 | public: |
| 83 | bool IsRenderTarget(); // surface can be used as a render target? |
| 84 | |
| 85 | void SetBackground() { fIsBackground = true; } |
| 86 | // Note: This uses partial locks, anything but SetPixDw and Unlock is undefined afterwards until unlock. |
| 87 | void ClearBoxDw(int iX, int iY, int iWdt, int iHgt); |
| 88 | bool Unlock(bool noUpload = false); |
| 89 | bool Lock(); |
| 90 | bool LockForUpdate(C4Rect rect); |
| 91 | bool GetTexAt(C4TexRef **ppTexRef, int &rX, int &rY); // get texture and adjust x/y |
| 92 | bool GetLockTexAt(C4TexRef **ppTexRef, int &rX, int &rY); // get texture; ensure it's locked and adjust x/y |
| 93 | bool SetPix(int iX, int iY, uint8_t byCol); // set 8bit-px |
| 94 | uint32_t GetPixDw(int iX, int iY, bool fApplyModulation, float scale = 1.0); // get 32bit-px |
| 95 | bool IsPixTransparent(int iX, int iY); // is pixel's alpha value 0xff? |
| 96 | bool SetPixDw(int iX, int iY, uint32_t dwCol); // set pix in surface only |
| 97 | bool BltPix(int iX, int iY, C4Surface *sfcSource, int iSrcX, int iSrcY, bool fTransparency); // blit pixel from source to this surface (assumes clipped coordinates!) |
| 98 | bool Create(int iWdt, int iHgt, bool fOwnPal = false, bool fIsRenderTarget = false); |
| 99 | bool CreateColorByOwner(C4Surface *pBySurface); // create ColorByOwner-surface |
| 100 | bool SetAsClrByOwnerOf(C4Surface *pOfSurface); // assume that ColorByOwner-surface has been created, and just assign it; fails if the size doesn't match |
| 101 | bool AttachSfc(void *sfcSurface); |
| 102 | void Clear(); |
| 103 | void Default(); |
| 104 | void Clip(int iX, int iY, int iX2, int iY2); |
| 105 | void NoClip(); |
| 106 | bool Read(C4Group &hGroup, bool fOwnPal = false); |
| 107 | bool SavePNG(const char *szFilename, bool fSaveAlpha, bool fApplyGamma, bool fSaveOverlayOnly, float scale = 1.0f); |
| 108 | bool Wipe(); // empty to transparent |
| 109 | bool GetSurfaceSize(int &irX, int &irY); // get surface size |
| 110 | void SetClr(uint32_t toClr) { ClrByOwnerClr = toClr ? toClr : 0xff; } |
| 111 | uint32_t GetClr() { return ClrByOwnerClr; } |
| 112 | bool CopyBytes(uint8_t *pImageData); // assumes an array of wdt*hgt*4 and copies data directly from it |
| 113 | |
| 114 | bool LoadAny(C4Group &hGroup, const char *szFilename, bool fOwnPal = false, bool fNoErrIfNotFound = false); |
| 115 | bool LoadAny(C4GroupSet &hGroupset, const char *szFilename, bool fOwnPal = false, bool fNoErrIfNotFound = false); |
| 116 | bool Load(C4Group &hGroup, const char *szFilename, bool fOwnPal = false, bool fNoErrIfNotFound = false); |
| 117 | bool SavePNG(C4Group &hGroup, const char *szFilename, bool fSaveAlpha = true, bool fApplyGamma = false, bool fSaveOverlayOnly = false); |
| 118 | bool Copy(C4Surface &fromSfc); |
| 119 | bool ReadPNG(C4Group &hGroup); |
| 120 | bool ReadJPEG(C4Group &hGroup); |
| 121 | |
| 122 | private: |
| 123 | bool CreateTextures(); // create ppTex-array |
| 124 | void FreeTextures(); // free ppTex-array if existent |
| 125 | |
| 126 | friend class CStdDDraw; |
| 127 | friend class CPattern; |
| 128 | friend class CStdGL; |
| 129 | |
| 130 | public: |
| 131 | int Wdt, Hgt; // size of surface |
| 132 | int PrimarySurfaceLockPitch; uint8_t *PrimarySurfaceLockBits; // lock data if primary surface is locked |
| 133 | int iTexSize; // size of textures |
| 134 | int iTexX, iTexY; // number of textures in x/y-direction |
| 135 | int ClipX, ClipY, ClipX2, ClipY2; |
| 136 | bool fIsRenderTarget; // set for surfaces to be used as offscreen render targets |
| 137 | bool fIsBackground; // background surfaces fill unused pixels with black, rather than transparency - must be set prior to loading |
| 138 | #ifndef NDEBUG |
| 139 | int *dbg_idx; |
| 140 | #endif |
| 141 | #ifndef USE_CONSOLE |
| 142 | GLenum Format; // used color format in textures |
| 143 | #endif |
| 144 | C4TexRef **ppTex; // textures |
| 145 | C4Surface *pMainSfc; // main surface for simple ColorByOwner-surfaces |
| 146 | uint32_t ClrByOwnerClr; // current color to be used for ColorByOwner-blits |
| 147 | |
| 148 | private: |
| 149 | int Locked; |
| 150 | bool fPrimary; |
| 151 | |
| 152 | bool IsSingleSurface() const { return iTexX * iTexY == 1; } // return whether surface is not split |
| 153 | }; |
| 154 | |
| 155 | struct D3DLOCKED_RECT |
| 156 | { |
| 157 | int Pitch; |
| 158 | unsigned char *pBits; |
| 159 | }; |
| 160 | |
| 161 | // one texture encapsulation |
| 162 | class C4TexRef |
| 163 | { |
| 164 | public: |
| 165 | D3DLOCKED_RECT texLock; // current lock-data |
| 166 | #ifndef USE_CONSOLE |
| 167 | GLuint texName; |
| 168 | #endif |
| 169 | int iSize; |
| 170 | bool fIntLock; // if set, texref is locked internally only |
| 171 | C4Rect LockSize; |
| 172 | |
| 173 | C4TexRef(int iSize, bool fAsRenderTarget); // create texture with given size |
| 174 | ~C4TexRef(); // release texture |
| 175 | bool Lock(); // lock texture |
| 176 | // Lock a part of the rect, discarding the content |
| 177 | // Note: Calling Lock afterwards without an Unlock first is undefined |
| 178 | bool LockForUpdate(C4Rect rect); |
| 179 | void Unlock(bool noUpload = false); // unlock texture |
| 180 | bool ClearRect(C4Rect rect); // clear rect in texture to transparent |
| 181 | bool FillBlack(); // fill complete texture in black |
| 182 | |
| 183 | void SetPix(int iX, int iY, uint32_t v) |
| 184 | { |
| 185 | *reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(texLock.pBits) + (iY - LockSize.y) * texLock.Pitch + (iX - LockSize.x) * 4) = v; |
| 186 | } |
| 187 | |
| 188 | private: |
| 189 | int32_t LockCount; |
| 190 | }; |
| 191 | |
| 192 | // texture management |
| 193 | class C4TexMgr |
| 194 | { |
| 195 | public: |
| 196 | std::list<C4TexRef *> Textures; |
| 197 | |
| 198 | public: |
| 199 | C4TexMgr(); |
| 200 | ~C4TexMgr(); |
| 201 | |
| 202 | void RegTex(C4TexRef *pTex); |
| 203 | void UnregTex(C4TexRef *pTex); |
| 204 | |
| 205 | void IntLock(); // do an internal lock |
| 206 | void IntUnlock(); // undo internal lock |
| 207 | }; |
| 208 | |
| 209 | extern C4TexMgr *pTexMgr; |
| 210 | |