| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2004, Sven2 |
| 6 | * Copyright (c) 2017-2022, The LegacyClonk Team and contributors |
| 7 | * |
| 8 | * Distributed under the terms of the ISC license; see accompanying file |
| 9 | * "COPYING" for details. |
| 10 | * |
| 11 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 12 | * See accompanying file "TRADEMARK" for details. |
| 13 | * |
| 14 | * To redistribute this file separately, substitute the full license texts |
| 15 | * for the above references. |
| 16 | */ |
| 17 | |
| 18 | // graphics used by object definitions (object and portraits) |
| 19 | |
| 20 | #pragma once |
| 21 | |
| 22 | #include <C4EnumeratedObjectPtr.h> |
| 23 | #include <C4FacetEx.h> |
| 24 | #include "C4ForwardDeclarations.h" |
| 25 | #include <C4Material.h> |
| 26 | #include <C4Surface.h> |
| 27 | |
| 28 | #define C4Portrait_None "none" |
| 29 | #define C4Portrait_Random "random" |
| 30 | #define C4Portrait_Custom "custom" |
| 31 | |
| 32 | // defintion graphics |
| 33 | class C4AdditionalDefGraphics; |
| 34 | class C4DefGraphicsPtrBackup; |
| 35 | class C4PortraitGraphics; |
| 36 | |
| 37 | class C4DefGraphics |
| 38 | { |
| 39 | public: |
| 40 | C4Def *pDef; // underlying definition |
| 41 | |
| 42 | protected: |
| 43 | C4AdditionalDefGraphics *pNext; // next graphics |
| 44 | |
| 45 | public: |
| 46 | C4Surface *Bitmap, *BitmapClr; |
| 47 | bool fColorBitmapAutoCreated; // if set, the color-by-owner-bitmap has been created automatically by all blue shades of the bitmap |
| 48 | |
| 49 | inline C4Surface *GetBitmap(uint32_t dwClr = 0) { if (BitmapClr) { BitmapClr->SetClr(dwClr); return BitmapClr; } else return Bitmap; } |
| 50 | |
| 51 | C4DefGraphics(C4Def *pOwnDef = nullptr); |
| 52 | virtual ~C4DefGraphics() { Clear(); } |
| 53 | |
| 54 | bool LoadGraphics(C4Group &hGroup, const char *szFilename, const char *szFilenamePNG, const char *szOverlayPNG, bool fColorByOwner); // load specified graphics from group |
| 55 | bool LoadAllGraphics(C4Group &hGroup, bool fColorByOwner); // load graphics from group |
| 56 | bool ColorizeByMaterial(int32_t iMat, C4MaterialMap &rMats, uint8_t bGBM); // colorize all graphics by material |
| 57 | C4DefGraphics *Get(const char *szGrpName); // get graphics by name |
| 58 | void Clear(); // clear fields; delete additional graphics |
| 59 | |
| 60 | bool IsColorByOwner() // returns whether ColorByOwner-surfaces have been created |
| 61 | { |
| 62 | return !!BitmapClr; |
| 63 | } |
| 64 | |
| 65 | bool CopyGraphicsFrom(C4DefGraphics &rSource); // copy bitmaps from source graphics |
| 66 | |
| 67 | virtual const char *GetName() { return nullptr; } // return name to be stored in safe game files |
| 68 | |
| 69 | C4AdditionalDefGraphics *GetNext() { return pNext; } |
| 70 | virtual C4PortraitGraphics *IsPortrait() { return nullptr; } |
| 71 | |
| 72 | void DrawClr(C4Facet &cgo, bool fAspect = true, uint32_t dwClr = 0); // set surface color and draw |
| 73 | |
| 74 | friend class C4DefGraphicsPtrBackup; |
| 75 | }; |
| 76 | |
| 77 | // additional definition graphics |
| 78 | class C4AdditionalDefGraphics : public C4DefGraphics |
| 79 | { |
| 80 | protected: |
| 81 | char Name[C4MaxName + 1]; // graphics name |
| 82 | |
| 83 | public: |
| 84 | C4AdditionalDefGraphics(C4Def *pOwnDef, const char *szName); |
| 85 | virtual const char *GetName() override { return Name; } |
| 86 | }; |
| 87 | |
| 88 | // portrait graphics within object definition |
| 89 | class C4PortraitGraphics : public C4AdditionalDefGraphics |
| 90 | { |
| 91 | public: |
| 92 | C4PortraitGraphics(C4Def *pOwnDef, const char *szName) |
| 93 | : C4AdditionalDefGraphics(pOwnDef, szName) {} |
| 94 | |
| 95 | virtual C4PortraitGraphics *IsPortrait() override { return this; } |
| 96 | C4PortraitGraphics *GetByIndex(int32_t iIndex); |
| 97 | C4PortraitGraphics *Get(const char *szGrpName); // get portrait graphics by name |
| 98 | }; |
| 99 | |
| 100 | // backup class holding dead graphics pointers and names |
| 101 | class C4DefGraphicsPtrBackup |
| 102 | { |
| 103 | protected: |
| 104 | C4DefGraphics *pGraphicsPtr; // dead graphics ptr |
| 105 | C4Surface *BitmapPtr; // dead bitmap ptr |
| 106 | C4Def *pDef; // definition of dead graphics |
| 107 | char Name[C4MaxName + 1]; // name of graphics |
| 108 | C4DefGraphicsPtrBackup *pNext; // next member of linked list |
| 109 | |
| 110 | public: |
| 111 | C4DefGraphicsPtrBackup(C4DefGraphics *pSourceGraphics); |
| 112 | ~C4DefGraphicsPtrBackup(); |
| 113 | |
| 114 | void AssignUpdate(C4DefGraphics *pNewGraphics); // update all game objects with new graphics pointers |
| 115 | void AssignRemoval(); // remove graphics of this def from all game objects |
| 116 | }; |
| 117 | |
| 118 | // Helper to compile C4DefGraphics-Pointer |
| 119 | class C4DefGraphicsAdapt |
| 120 | { |
| 121 | protected: |
| 122 | C4DefGraphics *&pDefGraphics; |
| 123 | |
| 124 | public: |
| 125 | C4DefGraphicsAdapt(C4DefGraphics *&pDefGraphics) : pDefGraphics(pDefGraphics) {} |
| 126 | void CompileFunc(StdCompiler *pComp); |
| 127 | |
| 128 | // Default checking / setting |
| 129 | bool operator==(C4DefGraphics *pDef2) { return pDefGraphics == pDef2; } |
| 130 | void operator=(C4DefGraphics *pDef2) { pDefGraphics = pDef2; } |
| 131 | }; |
| 132 | |
| 133 | // portrait link class |
| 134 | class C4Portrait |
| 135 | { |
| 136 | protected: |
| 137 | C4DefGraphics *pGfxPortrait; // the portrait graphics |
| 138 | bool fGraphicsOwned; // if true, the portrait graphics are owned (and deleted upon destruction) |
| 139 | |
| 140 | public: |
| 141 | C4Portrait() : pGfxPortrait(nullptr), fGraphicsOwned(false) {} |
| 142 | ~C4Portrait() { if (fGraphicsOwned) delete pGfxPortrait; } |
| 143 | void Default() { pGfxPortrait = nullptr; fGraphicsOwned = false; } |
| 144 | void Clear() { if (fGraphicsOwned) { delete pGfxPortrait; fGraphicsOwned = false; } pGfxPortrait = nullptr; } |
| 145 | |
| 146 | bool CopyFrom(C4DefGraphics &rCopyGfx); // copy portrait from graphics |
| 147 | bool CopyFrom(C4Portrait &rCopy); // copy portrait |
| 148 | |
| 149 | bool Load(C4Group &rGrp, const char *szFilename, const char *szFilenamePNG, const char *szOverlayPNG); // load own portrait from group |
| 150 | bool Link(C4DefGraphics *pGfxPortrait); // link with a present portrait surface |
| 151 | bool SavePNG(C4Group &rGroup, const char *szFilename, const char *szOverlayFN); // store portrait gfx to file (including overlay) |
| 152 | |
| 153 | C4DefGraphics *GetGfx() { return pGfxPortrait; } |
| 154 | bool IsOwnedGfx() { return fGraphicsOwned; } // return if it's a custom portrait |
| 155 | |
| 156 | static const char *EvaluatePortraitString(const char *szPortrait, C4ID &rIDOut, C4ID idDefaultID, uint32_t *pdwClrOut); // get portrait source and def from string |
| 157 | }; |
| 158 | |
| 159 | // graphics overlay used to attach additional graphics to objects |
| 160 | class C4GraphicsOverlay |
| 161 | { |
| 162 | public: |
| 163 | enum Mode |
| 164 | { |
| 165 | MODE_None = 0, |
| 166 | MODE_Base = 1, // display base facet |
| 167 | MODE_Action = 2, // display action facet specified in Action |
| 168 | MODE_Picture = 3, // overlay picture to this picture only |
| 169 | MODE_IngamePicture = 4, // draw picture of source def |
| 170 | MODE_Object = 5, // draw another object gfx |
| 171 | = 6, // draw like this were a ClrByOwner-surface |
| 172 | }; |
| 173 | |
| 174 | protected: |
| 175 | Mode eMode; // overlay mode |
| 176 | |
| 177 | C4DefGraphics *pSourceGfx; // source graphics - used for savegame saving and comparisons in ReloadDef |
| 178 | char Action[C4MaxName + 1]; // action used as overlay in source gfx |
| 179 | C4FacetEx fctBlit; // current blit data |
| 180 | uint32_t dwBlitMode; // extra parameters for additive blits, etc. |
| 181 | uint32_t dwClrModulation; // colormod for this overlay |
| 182 | C4EnumeratedObjectPtr pOverlayObj; // object to be drawn as overlay in MODE_Object |
| 183 | C4DrawTransform Transform; // drawing transformation: Rotation, zoom, etc. |
| 184 | int32_t iPhase; // action face for MODE_Action |
| 185 | bool fZoomToShape; // if true, overlay will be zoomed to match the target object shape |
| 186 | |
| 187 | int32_t iID; // identification number for Z-ordering and script identification |
| 188 | |
| 189 | C4GraphicsOverlay *pNext; // singly linked list |
| 190 | |
| 191 | void UpdateFacet(); // update fctBlit to reflect current data |
| 192 | void Set(Mode aMode, C4DefGraphics *pGfx, const char *szAction, uint32_t dwBMode, C4Object *pOvrlObj); |
| 193 | |
| 194 | public: |
| 195 | C4GraphicsOverlay() : eMode(MODE_None), pSourceGfx(nullptr), fctBlit(), dwBlitMode(0), dwClrModulation(0xffffff), |
| 196 | Transform(+1), iPhase(0), fZoomToShape(false), iID(0), pNext(nullptr) |
| 197 | { |
| 198 | *Action = 0; |
| 199 | } |
| 200 | |
| 201 | ~C4GraphicsOverlay(); |
| 202 | |
| 203 | void CompileFunc(StdCompiler *pComp); |
| 204 | |
| 205 | // object pointer management |
| 206 | void EnumeratePointers(); |
| 207 | void DenumeratePointers(); |
| 208 | |
| 209 | void SetAsBase(C4DefGraphics *pBaseGfx, uint32_t dwBMode) // set in MODE_Base |
| 210 | { |
| 211 | Set(aMode: MODE_Base, pGfx: pBaseGfx, szAction: nullptr, dwBMode, pOvrlObj: nullptr); |
| 212 | } |
| 213 | |
| 214 | void SetAsAction(C4DefGraphics *pBaseGfx, const char *szAction, uint32_t dwBMode) |
| 215 | { |
| 216 | Set(aMode: MODE_Action, pGfx: pBaseGfx, szAction, dwBMode, pOvrlObj: nullptr); |
| 217 | } |
| 218 | |
| 219 | void SetAsPicture(C4DefGraphics *pBaseGfx, uint32_t dwBMode) |
| 220 | { |
| 221 | Set(aMode: MODE_Picture, pGfx: pBaseGfx, szAction: nullptr, dwBMode, pOvrlObj: nullptr); |
| 222 | } |
| 223 | |
| 224 | void SetAsIngamePicture(C4DefGraphics *pBaseGfx, uint32_t dwBMode) |
| 225 | { |
| 226 | Set(aMode: MODE_IngamePicture, pGfx: pBaseGfx, szAction: nullptr, dwBMode, pOvrlObj: nullptr); |
| 227 | } |
| 228 | |
| 229 | void SetAsObject(C4Object *pOverlayObj, uint32_t dwBMode) |
| 230 | { |
| 231 | Set(aMode: MODE_Object, pGfx: nullptr, szAction: nullptr, dwBMode, pOvrlObj: pOverlayObj); |
| 232 | } |
| 233 | |
| 234 | void (C4DefGraphics *pGfx, uint32_t dwBMode) |
| 235 | { |
| 236 | Set(aMode: MODE_ExtraGraphics, pGfx, szAction: nullptr, dwBMode, pOvrlObj: nullptr); |
| 237 | } |
| 238 | |
| 239 | bool IsValid(const C4Object *pForObj) const; |
| 240 | |
| 241 | C4DrawTransform *GetTransform() { return &Transform; } |
| 242 | C4Object *GetOverlayObject() const { return pOverlayObj; } |
| 243 | int32_t GetID() const { return iID; } |
| 244 | void SetID(int32_t aID) { iID = aID; } |
| 245 | C4GraphicsOverlay *GetNext() const { return pNext; } |
| 246 | void SetNext(C4GraphicsOverlay *paNext) { pNext = paNext; } |
| 247 | bool IsPicture() { return eMode == MODE_Picture; } |
| 248 | C4DefGraphics *GetGfx() const { return pSourceGfx; } |
| 249 | |
| 250 | void Draw(C4FacetEx &cgo, C4Object *pForObj, int32_t iByPlayer); |
| 251 | void DrawPicture(C4Facet &cgo, C4Object *pForObj); |
| 252 | |
| 253 | bool operator==(const C4GraphicsOverlay &rCmp) const; // comparison operator |
| 254 | |
| 255 | uint32_t GetClrModulation() const { return dwClrModulation; } |
| 256 | void SetClrModulation(uint32_t dwToMod) { dwClrModulation = dwToMod; } |
| 257 | |
| 258 | uint32_t GetBlitMode() const { return dwBlitMode; } |
| 259 | void SetBlitMode(uint32_t dwToMode) { dwBlitMode = dwToMode; } |
| 260 | |
| 261 | void UpdateSourceGraphics(C4DefGraphics *newSource); // for ReloadDef |
| 262 | }; |
| 263 | |
| 264 | // Helper to compile lists of C4GraphicsOverlay |
| 265 | class C4GraphicsOverlayListAdapt |
| 266 | { |
| 267 | protected: |
| 268 | C4GraphicsOverlay *&pOverlay; |
| 269 | |
| 270 | public: |
| 271 | C4GraphicsOverlayListAdapt(C4GraphicsOverlay *&pOverlay) : pOverlay(pOverlay) {} |
| 272 | void CompileFunc(StdCompiler *pComp); |
| 273 | |
| 274 | // Default checking / setting |
| 275 | bool operator==(C4GraphicsOverlay *pDefault) { return pOverlay == pDefault; } |
| 276 | void operator=(C4GraphicsOverlay *pDefault) { delete pOverlay; pOverlay = pDefault; } |
| 277 | }; |
| 278 | |