| 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 facet that can hold its own surface and also target coordinates */ |
| 18 | |
| 19 | #include <C4Include.h> |
| 20 | #include <C4FacetEx.h> |
| 21 | |
| 22 | #include <C4Random.h> |
| 23 | #include <C4Shape.h> |
| 24 | #include <C4Group.h> |
| 25 | |
| 26 | void C4FacetEx::Set(C4Surface *nsfc, int nx, int ny, int nwdt, int nhgt, int ntx, int nty) |
| 27 | { |
| 28 | C4Facet::Set(nsfc, nx, ny, nwdt, nhgt); |
| 29 | TargetX = ntx; TargetY = nty; |
| 30 | } |
| 31 | |
| 32 | C4FacetEx C4FacetEx::GetSection(int iSection) |
| 33 | { |
| 34 | C4FacetEx fctResult; |
| 35 | fctResult.Set(nsfc: Surface, nx: X + Hgt * iSection, ny: Y, nwdt: Hgt, nhgt: Hgt, ntx: 0, nty: 0); |
| 36 | return fctResult; |
| 37 | } |
| 38 | |
| 39 | C4FacetEx C4FacetEx::GetPhase(int iPhaseX, int iPhaseY) |
| 40 | { |
| 41 | C4FacetEx fctResult; |
| 42 | fctResult.Set(nsfc: Surface, nx: X + Wdt * iPhaseX, ny: Y + Hgt * iPhaseY, nwdt: Wdt, nhgt: Hgt, ntx: 0, nty: 0); |
| 43 | return fctResult; |
| 44 | } |
| 45 | |
| 46 | void C4FacetEx::DrawLine(int iX1, int iY1, int iX2, int iY2, uint8_t bCol1, uint8_t bCol2) |
| 47 | { |
| 48 | if (!lpDDraw || !Surface || !Wdt || !Hgt) return; |
| 49 | // Scroll position |
| 50 | iX1 -= TargetX; iY1 -= TargetY; iX2 -= TargetX; iY2 -= TargetY; |
| 51 | // No clipping is done here, because clipping will be done by gfx wrapper anyway |
| 52 | // Draw line |
| 53 | lpDDraw->DrawLine(sfcTarget: Surface, x1: X + iX1, y1: Y + iY1, x2: X + iX2, y2: Y + iY2, byCol: bCol1); |
| 54 | lpDDraw->DrawPix(sfcDest: Surface, tx: static_cast<float>(X + iX1), ty: static_cast<float>(Y + iY1), dwCol: lpDDraw->Pal.GetClr(byCol: bCol2)); |
| 55 | } |
| 56 | |
| 57 | // bolt random size |
| 58 | #define DrawBoltR1 7 |
| 59 | #define DrawBoltR2 3 |
| 60 | |
| 61 | void C4FacetEx::DrawBolt(int iX1, int iY1, int iX2, int iY2, uint8_t bCol, uint8_t bCol2) |
| 62 | { |
| 63 | if (!lpDDraw || !Surface || !Wdt || !Hgt) return; |
| 64 | // Scroll position |
| 65 | iX1 -= TargetX; iY1 -= TargetY; iX2 -= TargetX; iY2 -= TargetY; |
| 66 | // Facet bounds |
| 67 | if (!Inside(ival: iX1, lbound: 0, rbound: Wdt - 1) && !Inside(ival: iX2, lbound: 0, rbound: Wdt - 1)) return; |
| 68 | if (!Inside(ival: iY1, lbound: 0, rbound: Hgt - 1) && !Inside(ival: iY2, lbound: 0, rbound: Hgt - 1)) return; |
| 69 | iX1 += X; iX2 += X; iY1 += Y; iY2 += Y; |
| 70 | // Draw bolt |
| 71 | int pvtx[2 * 4]; |
| 72 | pvtx[0] = iX1; pvtx[1] = iY1; pvtx[2] = iX2; pvtx[3] = iY2; |
| 73 | pvtx[4] = iX2 + SafeRandom(DrawBoltR1) - DrawBoltR2; pvtx[5] = iY2 + SafeRandom(DrawBoltR1) - DrawBoltR2; |
| 74 | pvtx[6] = iX1 + SafeRandom(DrawBoltR1) - DrawBoltR2; pvtx[7] = iY1 + SafeRandom(DrawBoltR1) - DrawBoltR2; |
| 75 | // Draw in surface |
| 76 | uint32_t dwClr1 = lpDDraw->Pal.GetClr(byCol: bCol), dwClr2; |
| 77 | uint32_t dwClr3 = lpDDraw->Pal.GetClr(byCol: bCol2), dwClr4; |
| 78 | dwClr2 = dwClr1; |
| 79 | dwClr4 = dwClr3; |
| 80 | lpDDraw->DrawQuadDw(sfcTarget: Surface, ipVtx: pvtx, dwClr1, dwClr2: dwClr3, dwClr3: dwClr4, dwClr4: dwClr2); |
| 81 | } |
| 82 | |
| 83 | // C4FacetExSurface |
| 84 | |
| 85 | bool C4FacetExSurface::Create(int iWdt, int iHgt, int iWdt2, int iHgt2) |
| 86 | { |
| 87 | Clear(); |
| 88 | // Create surface |
| 89 | Face.Default(); |
| 90 | if (!Face.Create(iWdt, iHgt)) return false; |
| 91 | // Set facet |
| 92 | if (iWdt2 == C4FCT_Full) iWdt2 = Face.Wdt; if (iWdt2 == C4FCT_Height) iWdt2 = Face.Hgt; if (iWdt2 == C4FCT_Width) iWdt2 = Face.Wdt; |
| 93 | if (iHgt2 == C4FCT_Full) iHgt2 = Face.Hgt; if (iHgt2 == C4FCT_Height) iHgt2 = Face.Hgt; if (iHgt2 == C4FCT_Width) iHgt2 = Face.Wdt; |
| 94 | Set(nsfc: &Face, nx: 0, ny: 0, nwdt: iWdt2, nhgt: iHgt2, ntx: 0, nty: 0); |
| 95 | return true; |
| 96 | } |
| 97 | |
| 98 | bool C4FacetExSurface::CreateClrByOwner(C4Surface *pBySurface) |
| 99 | { |
| 100 | Clear(); |
| 101 | // create surface |
| 102 | if (!Face.CreateColorByOwner(pBySurface)) return false; |
| 103 | // set facet |
| 104 | Set(nsfc: &Face, nx: 0, ny: 0, nwdt: Face.Wdt, nhgt: Face.Hgt, ntx: 0, nty: 0); |
| 105 | // success |
| 106 | return true; |
| 107 | } |
| 108 | |
| 109 | bool C4FacetExSurface::EnsureSize(int iMinWdt, int iMinHgt) |
| 110 | { |
| 111 | // safety |
| 112 | if (!Surface) return false; |
| 113 | // check size |
| 114 | int iWdt = Face.Wdt, iHgt = Face.Hgt; |
| 115 | if (iWdt >= iMinWdt && iHgt >= iMinHgt) return true; |
| 116 | // create temp surface |
| 117 | C4Surface *sfcDup = new C4Surface(iWdt, iHgt); |
| 118 | if (!sfcDup) return false; |
| 119 | if (!lpDDraw->BlitSurface(sfcSurface: &Face, sfcTarget: sfcDup, tx: 0, ty: 0, fBlitBase: false)) |
| 120 | { |
| 121 | delete sfcDup; return false; |
| 122 | } |
| 123 | // calc needed size |
| 124 | int iDstWdt = Surface->Wdt, iDstHgt = iHgt; |
| 125 | while (iDstWdt < iMinWdt) iDstWdt += iWdt; |
| 126 | while (iDstHgt < iMinHgt) iDstHgt += iHgt; |
| 127 | // recreate this one |
| 128 | if (!Face.Create(iWdt: iDstWdt, iHgt: iDstHgt)) { delete sfcDup; Clear(); return false; } |
| 129 | // blit tiled into it |
| 130 | bool fSuccess = lpDDraw->BlitSurfaceTile(sfcSurface: sfcDup, sfcTarget: &Face, iToX: 0, iToY: 0, iToWdt: iDstWdt, iToHgt: iDstHgt, iOffsetX: 0, iOffsetY: 0, fSrcColKey: false); |
| 131 | // del temp surface |
| 132 | delete sfcDup; |
| 133 | // done |
| 134 | return fSuccess; |
| 135 | } |
| 136 | |
| 137 | bool C4FacetExSurface::Load(C4Group &hGroup, const char *szName, int iWdt, int iHgt, bool fOwnPal, bool fNoErrIfNotFound) |
| 138 | { |
| 139 | Clear(); |
| 140 | // Entry name |
| 141 | char szFilename[_MAX_FNAME + 1]; |
| 142 | SCopy(szSource: szName, sTarget: szFilename, _MAX_FNAME); |
| 143 | char *szExt = GetExtension(fname: szFilename); |
| 144 | if (!*szExt) |
| 145 | { |
| 146 | // no extension: Default to extension that is found as file in group |
| 147 | const char *const extensions[] = { "png" , "bmp" , "jpeg" , "jpg" , nullptr }; |
| 148 | int i = 0; const char *szExt; |
| 149 | while (szExt = extensions[i++]) |
| 150 | { |
| 151 | EnforceExtension(szFileName: szFilename, szExtension: szExt); |
| 152 | if (hGroup.FindEntry(szWildCard: szFilename)) break; |
| 153 | } |
| 154 | } |
| 155 | // Load surface |
| 156 | if (!Face.Load(hGroup, szFilename, fOwnPal, fNoErrIfNotFound)) return false; |
| 157 | // Set facet |
| 158 | if (iWdt == C4FCT_Full) iWdt = Face.Wdt; if (iWdt == C4FCT_Height) iWdt = Face.Hgt; if (iWdt == C4FCT_Width) iWdt = Face.Wdt; |
| 159 | if (iHgt == C4FCT_Full) iHgt = Face.Hgt; if (iHgt == C4FCT_Height) iHgt = Face.Hgt; if (iHgt == C4FCT_Width) iHgt = Face.Wdt; |
| 160 | Set(nsfc: &Face, nx: 0, ny: 0, nwdt: iWdt, nhgt: iHgt, ntx: 0, nty: 0); |
| 161 | return true; |
| 162 | } |
| 163 | |
| 164 | bool C4FacetExSurface::CopyFromSfcMaxSize(C4Surface &srcSfc, int32_t iMaxSize, uint32_t dwColor) |
| 165 | { |
| 166 | // safety |
| 167 | if (!srcSfc.Wdt || !srcSfc.Hgt) return false; |
| 168 | Clear(); |
| 169 | // no scale? |
| 170 | bool fNeedsScale = !(srcSfc.Wdt <= iMaxSize && srcSfc.Hgt <= iMaxSize); |
| 171 | if (!fNeedsScale && !dwColor) |
| 172 | { |
| 173 | // no change necessary; just copy then |
| 174 | Face.Copy(fromSfc&: srcSfc); |
| 175 | } |
| 176 | else |
| 177 | { |
| 178 | // must scale down or colorize. Just blit. |
| 179 | C4Facet fctSource; |
| 180 | fctSource.Set(nsfc: &srcSfc, nx: 0, ny: 0, nwdt: srcSfc.Wdt, nhgt: srcSfc.Hgt); |
| 181 | int32_t iTargetWdt, iTargetHgt; |
| 182 | if (fNeedsScale) |
| 183 | { |
| 184 | if (fctSource.Wdt > fctSource.Hgt) |
| 185 | { |
| 186 | iTargetWdt = iMaxSize; |
| 187 | iTargetHgt = fctSource.Hgt * iTargetWdt / fctSource.Wdt; |
| 188 | } |
| 189 | else |
| 190 | { |
| 191 | iTargetHgt = iMaxSize; |
| 192 | iTargetWdt = fctSource.Wdt * iTargetHgt / fctSource.Hgt; |
| 193 | } |
| 194 | } |
| 195 | else |
| 196 | { |
| 197 | iTargetWdt = fctSource.Wdt; |
| 198 | iTargetHgt = fctSource.Hgt; |
| 199 | } |
| 200 | if (dwColor) srcSfc.SetClr(dwColor); |
| 201 | Create(iWdt: iTargetWdt, iHgt: iTargetHgt); |
| 202 | lpDDraw->Blit(sfcSource: &srcSfc, fx: 0.0f, fy: 0.0f, fwdt: float(fctSource.Wdt), fhgt: float(fctSource.Hgt), |
| 203 | sfcTarget: &Face, tx: 0, ty: 0, twdt: iTargetWdt, thgt: iTargetHgt); |
| 204 | } |
| 205 | Set(nsfc: &Face, nx: 0, ny: 0, nwdt: Face.Wdt, nhgt: Face.Hgt); |
| 206 | return true; |
| 207 | } |
| 208 | |
| 209 | void C4FacetExSurface::Grayscale(int32_t iOffset) |
| 210 | { |
| 211 | if (!lpDDraw || !Surface || !Wdt || !Hgt) return; |
| 212 | lpDDraw->Grayscale(sfcSfc: Surface, iOffset); |
| 213 | } |
| 214 | |