1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2009-2016, The OpenClonk 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 /* Solid areas of objects, put into the landscape */
18
19 #include "C4Include.h"
20 #include "landscape/C4SolidMask.h"
21
22 #include "graphics/C4DrawGL.h"
23 #include "graphics/CSurface8.h"
24 #include "graphics/StdPNG.h"
25 #include "landscape/C4Landscape.h"
26 #include "landscape/C4Material.h"
27 #include "object/C4Def.h"
28 #include "object/C4GameObjects.h"
29 #include "object/C4Object.h"
30
31
Put(bool fCauseInstability,C4TargetRect * pClipRect,bool fRestoreAttachment)32 void C4SolidMask::Put(bool fCauseInstability, C4TargetRect *pClipRect, bool fRestoreAttachment)
33 {
34 // If not put, put mask to background,
35 // storing background pixels in cSolidMask.
36
37 // No mask
38 if (!pForObject || !pForObject->Def || !pForObject->Def->pSolidMask || !pSolidMaskMatBuff) { iAttachingObjectsCount = 0; return; }
39 // Contained
40 if (pForObject->Contained) { iAttachingObjectsCount = 0; return; }
41 // Mask is put
42 if (fCauseInstability) CheckConsistency();
43
44 bool RegularPut;
45 if (!pClipRect)
46 {
47 // Regular Put: Update MaskPutRect and MaskPutRotation
48 MaskPutRotation = pForObject->GetR();
49 pClipRect = &MaskPutRect;
50 RegularPut = true;
51 }
52 else
53 {
54 // Reput by C4SolidMask::Remove
55 // Don't change MaskPutRotation or MaskPutRect
56 // Intersect ClipRect with the MaskPutRect
57 if (!pClipRect->ClipBy(MaskPutRect)) return;
58 RegularPut = false;
59 }
60 // Get mask surface
61 CSurface8 *pSolidMask = pForObject->Def->pSolidMask;
62 // Put mask pixels
63 int xcnt,ycnt,iTx,iTy;
64 BYTE byPixel;
65 // not rotated?
66 if (!MaskPutRotation)
67 {
68 // calc put rect
69 if (RegularPut)
70 {
71 int ox, oy;
72 ox = pForObject->GetX() + pForObject->Def->Shape.x + pForObject->SolidMask.tx;
73 oy = pForObject->GetY() + pForObject->Def->Shape.y + pForObject->SolidMask.ty;
74 MaskPutRect.x = ox;
75 if (MaskPutRect.x < 0) { MaskPutRect.tx = -MaskPutRect.x; MaskPutRect.x = 0; }
76 else MaskPutRect.tx = 0;
77 MaskPutRect.y = oy;
78 if (MaskPutRect.y < 0) { MaskPutRect.ty = -MaskPutRect.y; MaskPutRect.y = 0; }
79 else MaskPutRect.ty = 0;
80 MaskPutRect.Wdt = std::min<int32_t>(ox + pForObject->SolidMask.Wdt, ::Landscape.GetWidth()) - MaskPutRect.x;
81 MaskPutRect.Hgt = std::min<int32_t>(oy + pForObject->SolidMask.Hgt, ::Landscape.GetHeight()) - MaskPutRect.y;
82 }
83 // fill rect with mask
84 for (ycnt=0; ycnt<pClipRect->Hgt; ++ycnt)
85 {
86 BYTE *pPix=pSolidMask->Bits + (ycnt+pClipRect->ty+pForObject->SolidMask.y)*pSolidMask->Pitch + pClipRect->tx + pForObject->SolidMask.x;
87 for (xcnt=0; xcnt<pClipRect->Wdt; ++xcnt,++pPix)
88 {
89 if (*pPix)
90 {
91 // solid mask present here
92 // calc position in landscape
93 iTx=pClipRect->x+xcnt; iTy=pClipRect->y+ycnt;
94 // is background mat to be stored? always do this in the given rect
95 if (!MaskPut)
96 {
97 // get background pixel
98 byPixel=::Landscape.GetPix(iTx,iTy);
99 // store it. If MCVehic, also store in initial put, but won't be used in restore
100 // do not overwrite current value in re-put issued by SolidMask-remover
101 if (!IsSomeVehicle(byPixel) || RegularPut)
102 pSolidMaskMatBuff[(ycnt+pClipRect->ty)*MatBuffPitch+xcnt+pClipRect->tx]=byPixel;
103 }
104 // and set mask
105 ::Landscape.SetPix2(iTx,iTy,MaskMaterial,::Landscape.Transparent);
106 }
107 else
108 // no SolidMask: mark buffer as unused here
109 if (!MaskPut)
110 pSolidMaskMatBuff[(ycnt+pClipRect->ty)*MatBuffPitch+xcnt+pClipRect->tx]=MCVehic;
111 }
112 }
113 }
114 else
115 {
116 // calc matrix for given rotation
117 C4Real Ma1 = Cos(itofix(-MaskPutRotation)), Ma2 = -Sin(itofix(-MaskPutRotation)),
118 Mb1 = Sin(itofix(-MaskPutRotation)), Mb2 = Cos(itofix(-MaskPutRotation));
119 // get upper-left corner of landscape copy rect
120 int centerx = pForObject->Def->Shape.x + pForObject->SolidMask.tx + pForObject->SolidMask.Wdt / 2;
121 int centery = pForObject->Def->Shape.y + pForObject->SolidMask.ty + pForObject->SolidMask.Hgt / 2;
122 int xstart = pForObject->GetX() + fixtoi(Ma1 * itofix(centerx) - Ma2 * itofix(centery)) - MatBuffPitch / 2;
123 int ystart = pForObject->GetY() + fixtoi(-Mb1 * itofix(centerx) + Mb2 * itofix(centery)) - MatBuffPitch / 2;
124 // store put rect
125 if (RegularPut)
126 {
127 MaskPutRect.x = xstart;
128 if (MaskPutRect.x < 0) { MaskPutRect.tx = -MaskPutRect.x; MaskPutRect.Wdt = MaskPutRect.x; MaskPutRect.x = 0; }
129 else { MaskPutRect.tx = 0; MaskPutRect.Wdt = 0; }
130 MaskPutRect.y = ystart;
131 if (MaskPutRect.y < 0) { MaskPutRect.ty = -MaskPutRect.y; MaskPutRect.Hgt = MaskPutRect.y; MaskPutRect.y = 0; }
132 else { MaskPutRect.ty = 0; MaskPutRect.Hgt = 0; }
133 MaskPutRect.Wdt = std::min<int32_t>(xstart + MatBuffPitch, ::Landscape.GetWidth()) - MaskPutRect.x;
134 MaskPutRect.Hgt = std::min<int32_t>(ystart + MatBuffPitch, ::Landscape.GetHeight()) - MaskPutRect.y;
135 }
136 // go through clipping rect
137 const C4Real y0 = itofix(pClipRect->ty - MatBuffPitch/2);
138 const C4Real x0 = itofix(pClipRect->tx - MatBuffPitch/2);
139 iTy=pClipRect->y;
140 int32_t w = pForObject->SolidMask.Wdt;
141 int32_t h = pForObject->SolidMask.Hgt;
142 int32_t mx0 = pForObject->SolidMask.x;
143 int32_t my0 = pForObject->SolidMask.y;
144 C4Real ya = y0 * Ma2;
145 C4Real yb = y0 * Mb2;
146 for (ycnt = 0; ycnt < pClipRect->Hgt; ycnt++)
147 {
148 iTx=pClipRect->x;
149 int i = (ycnt + pClipRect->ty) * MatBuffPitch + pClipRect->tx;
150 C4Real xa = x0 * Ma1;
151 C4Real xb = x0 * Mb1;
152 for (xcnt = 0; xcnt < pClipRect->Wdt; xcnt++)
153 {
154 // calc position in solidmask buffer
155 int32_t iMx = fixtoi(xa + ya) + w / 2;
156 int32_t iMy = fixtoi(xb + yb) + h / 2;
157 // in bounds? and solidmask?
158 if (iMx >= 0 && iMy >= 0 && iMx < w && iMy < h && pSolidMask->_GetPix(iMx+mx0, iMy+my0))
159 {
160 // is background mat to be stored?
161 if (!MaskPut)
162 {
163 // get background pixel
164 byPixel=::Landscape._GetPix(iTx,iTy);
165 // store it. If MCVehic, also store in initial put, but won't be used in restore
166 // do not overwrite current value in re-put issued by SolidMask-remover
167 if (!IsSomeVehicle(byPixel) || RegularPut)
168 pSolidMaskMatBuff[i + xcnt] = byPixel;
169 }
170 // set mask pix
171 ::Landscape.SetPix2(iTx, iTy, MaskMaterial, ::Landscape.Transparent);
172 }
173 else if (!MaskPut)
174 // mark pix as unused in buf
175 pSolidMaskMatBuff[i+xcnt] = MCVehic;
176 xa += Ma1; xb += Mb1;
177 ++iTx;
178 }
179 ya += Ma2; yb += Mb2;
180 ++iTy;
181 }
182 }
183 // Store mask put status
184 MaskPut=true;
185 // restore attached object positions if moved
186 if (fRestoreAttachment && iAttachingObjectsCount)
187 {
188 C4Real dx = pForObject->GetFixedX() - MaskRemovalX;
189 int32_t dy = pForObject->GetY() - MaskRemovalY;
190 if (dx != Fix0 || dy != 0)
191 for (int i = 0; i < iAttachingObjectsCount; ++i)
192 {
193 C4Object *pObj = ppAttachingObjects[i];
194 if (pObj->IsMoveableBySolidMask(pForObject->GetSolidMaskPlane()))
195 if (!pObj->Shape.ContactCheck(fixtoi(pObj->GetFixedX()+dx), fixtoi(pObj->GetFixedY()+dy)))
196 if (pObj->iLastAttachMovementFrame != Game.FrameCounter)
197 {
198 pObj->iLastAttachMovementFrame = Game.FrameCounter;
199 pObj->MovePosition(dx, itofix(dy));
200 }
201 }
202 iAttachingObjectsCount = 0;
203 }
204
205 if (fCauseInstability) CheckConsistency();
206 }
207
GetDensity(int32_t x,int32_t y) const208 int32_t C4SolidMask::DensityProvider::GetDensity(int32_t x, int32_t y) const
209 {
210 // outside SolidMask: free
211 x -= rSolidMaskData.MaskPutRect.x;
212 y -= rSolidMaskData.MaskPutRect.y;
213 if (!Inside<int32_t>(x, 0, rSolidMaskData.MaskPutRect.Wdt-1)
214 || !Inside<int32_t>(y, 0, rSolidMaskData.MaskPutRect.Hgt-1))
215 return 0;
216 // check put mask. Easy for unrotated
217 BYTE pix;
218 if (!rSolidMaskData.MaskPutRotation)
219 {
220 CSurface8 *pSolidMask = rSolidMaskData.pForObject->Def->pSolidMask;
221 if (!pSolidMask) return 0; // can't really happen
222 pix=pSolidMask->_GetPix(x+rSolidMaskData.pForObject->SolidMask.x+rSolidMaskData.MaskPutRect.tx,
223 y+rSolidMaskData.pForObject->SolidMask.y+rSolidMaskData.MaskPutRect.ty);
224 if (pix == 0xff)
225 return C4M_Vehicle;
226 else
227 return 0;
228 }
229 else
230 {
231 // Using put-buffer for rotated masks
232 // for SolidMask-pixels not put because there was another SolidMask already, this will not return solid
233 pix=*(rSolidMaskData.pSolidMaskMatBuff+(y+rSolidMaskData.MaskPutRect.ty)*rSolidMaskData.MatBuffPitch+rSolidMaskData.MaskPutRect.tx+x);
234 if (IsSomeVehicle(pix))
235 return 0;
236 else
237 return C4M_Vehicle;
238 }
239 }
240
Remove(bool fBackupAttachment)241 void C4SolidMask::Remove(bool fBackupAttachment)
242 {
243 // If put, restore background pixels from buffer
244
245 // Not put
246 if (!MaskPut || !pSolidMaskMatBuff) return;
247
248 CheckConsistency();
249
250 // reput background pixels
251 for (int ycnt=0; ycnt<MaskPutRect.Hgt; ++ycnt)
252 {
253 BYTE *pPix=pSolidMaskMatBuff+(ycnt+MaskPutRect.ty)*MatBuffPitch+MaskPutRect.tx;
254 for (int xcnt=0; xcnt<MaskPutRect.Wdt; ++xcnt,++pPix)
255 // only if mask was used here
256 if (*pPix != MCVehic)
257 {
258 // calc position in landscape
259 int iTx=MaskPutRect.x+xcnt; int iTy=MaskPutRect.y+ycnt;
260 // restore pixel here
261 // The pPix-check ensures that only pixels that hads been overwritten by this SolidMask are restored
262 // Non-SolidMask-pixels should not happen here, because all relevant landscape change routines should
263 // temp remove SolidMasks before
264 assert(IsSomeVehicle(::Landscape._GetPix(iTx,iTy)));
265 if (IsSomeVehicle(::Landscape._GetPix(iTx, iTy)))
266 ::Landscape._SetPix2(iTx, iTy, *pPix, ::Landscape.Transparent);
267 // Instability
268 ::Landscape.CheckInstabilityRange(iTx,iTy);
269 }
270 }
271 // Mask not put flag
272 MaskPut=false;
273 // update surrounding masks in that range
274 C4TargetRect ClipRect;
275 for (C4SolidMask *pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
276 if (pSolid->MaskPut) if (pSolid->MaskPutRect.Overlap(MaskPutRect))
277 {
278 // set clipping rect for all calls, since they may modify it
279 ClipRect.Set(MaskPutRect.x, MaskPutRect.y, MaskPutRect.Wdt, MaskPutRect.Hgt, 0, 0);
280 // doubled solidmask-pixels have just been removed in the clipped area!
281 pSolid->MaskPut = false;
282 // re-put the solidmask
283 pSolid->Put(false, &ClipRect, false);
284 }
285
286 // backup attachment if desired: Backup old pos and all objects that attach to or lie on the SolidMask
287 if (fBackupAttachment)
288 {
289 MaskRemovalX = pForObject->GetFixedX();
290 MaskRemovalY = pForObject->GetY();
291 iAttachingObjectsCount = 0;
292 // Search in area slightly larger than SolidMask because objects might have vertices slightly outside their shape
293 C4LArea SolidArea(&::Objects.Sectors, MaskPutRect.x-1, MaskPutRect.y-4, MaskPutRect.Wdt+2, MaskPutRect.Hgt+2);
294 C4LSector *pSct;
295 for (C4ObjectList *pLst=SolidArea.FirstObjectShapes(&pSct); pLst; pLst=SolidArea.NextObjectShapes(pLst, &pSct))
296 for (C4Object *pObj : *pLst)
297 if (pObj && pObj != pForObject && pObj->IsMoveableBySolidMask(pForObject->GetSolidMaskPlane()) && !pObj->Shape.CheckContact(pObj->GetX(),pObj->GetY()))
298 {
299 // avoid duplicate that may be found due to sector overlaps
300 bool has_dup = false;
301 for (int32_t i_dup = 0; i_dup < iAttachingObjectsCount; ++i_dup)
302 if (ppAttachingObjects[i_dup] == pObj)
303 {
304 has_dup = true;
305 break;
306 }
307 if (has_dup) continue;
308 // check for any contact to own SolidMask - attach-directions, bottom - "stuck" (CNAT_Center) is ignored, because that causes problems with things being stuck in basements :(
309 int iVtx = 0;
310 for (; iVtx < pObj->Shape.VtxNum; ++iVtx)
311 if (pObj->Shape.GetVertexContact(iVtx, pObj->Action.t_attach | CNAT_Bottom, pObj->GetX(), pObj->GetY(), DensityProvider(pForObject, *this)))
312 break;
313 if (iVtx == pObj->Shape.VtxNum) continue; // no contact
314 // contact: Add object to list
315 if (iAttachingObjectsCapacity == iAttachingObjectsCount)
316 {
317 iAttachingObjectsCapacity += 4;
318 C4Object **ppNewAttachingObjects = new C4Object *[iAttachingObjectsCapacity];
319 if (iAttachingObjectsCount) memcpy(ppNewAttachingObjects, ppAttachingObjects, sizeof(C4Object *) * iAttachingObjectsCount);
320 delete [] ppAttachingObjects;
321 ppAttachingObjects = ppNewAttachingObjects;
322 }
323 ppAttachingObjects[iAttachingObjectsCount++] = pObj;
324 }
325 }
326
327 CheckConsistency();
328 }
329
Draw(C4TargetFacet & cgo)330 void C4SolidMask::Draw(C4TargetFacet &cgo)
331 {
332 // only if put
333 if (!MaskPut) return;
334 // set topface facet
335 C4Facet fct; fct.Set(pForObject->GetGraphics()->GetBitmap(), pForObject->SolidMask.x, pForObject->SolidMask.y, pForObject->SolidMask.Wdt, pForObject->SolidMask.Hgt);
336 // draw it
337 if (MaskPutRotation)
338 fct.DrawXR(cgo.Surface, pForObject->GetX()+pForObject->Shape.x+cgo.X-cgo.TargetX+pForObject->SolidMask.tx, pForObject->GetY()+pForObject->Shape.y+cgo.Y-cgo.TargetY+pForObject->SolidMask.ty, fct.Wdt, fct.Hgt, 0, 0, MaskPutRotation);
339 else
340 fct.DrawX(cgo.Surface, pForObject->GetX()+pForObject->Shape.x+cgo.X-cgo.TargetX+pForObject->SolidMask.tx, pForObject->GetY()+pForObject->Shape.y+cgo.Y-cgo.TargetY+pForObject->SolidMask.ty, fct.Wdt, fct.Hgt, 0, 0);
341 }
342
343
RemoveTemporary(C4Rect where)344 void C4SolidMask::RemoveTemporary(C4Rect where)
345 {
346 if (!MaskPut || !pSolidMaskMatBuff) return;
347 where.Intersect(MaskPutRect);
348 // reput background pixels
349 for (int y = where.y; y < where.y + where.Hgt; ++y)
350 {
351 for (int x = where.x; x < where.x + where.Wdt; ++x)
352 {
353 BYTE *pPix = pSolidMaskMatBuff + (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x - MaskPutRect.x + MaskPutRect.tx;
354 // only if mask was used here
355 if (!IsSomeVehicle(*pPix)) //
356 {
357 // restore
358 assert(IsSomeVehicle(::Landscape.GetPix(x,y)));
359 ::Landscape._SetPix2Tmp(x, y, *pPix, ::Landscape.Transparent);
360 }
361 }
362 }
363 }
364
PutTemporary(C4Rect where)365 void C4SolidMask::PutTemporary(C4Rect where)
366 {
367 if (!MaskPut || !pSolidMaskMatBuff) return;
368 where.Intersect(MaskPutRect);
369 // reput vehicle pixels
370 for (int y = where.y; y < where.y + where.Hgt; ++y)
371 {
372 for (int x = where.x; x < where.x + where.Wdt; ++x)
373 {
374 BYTE *pPix = pSolidMaskMatBuff + (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x - MaskPutRect.x + MaskPutRect.tx;
375 // only if mask was used here
376 if (!IsSomeVehicle(*pPix))
377 {
378 // put
379 assert(::Landscape.GetPix(x,y)==*pPix);
380 ::Landscape._SetPix2Tmp(x, y, MaskMaterial, ::Landscape.Transparent);
381 }
382 }
383 }
384 }
385
Repair(C4Rect where)386 void C4SolidMask::Repair(C4Rect where)
387 {
388 if (!MaskPut || !pSolidMaskMatBuff) return;
389 where.Intersect(MaskPutRect);
390 // reput vehicle pixels
391 for (int y = where.y; y < where.y + where.Hgt; ++y)
392 {
393 for (int x = where.x; x < where.x + where.Wdt; ++x)
394 {
395 BYTE *pPix = pSolidMaskMatBuff + (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x - MaskPutRect.x + MaskPutRect.tx;
396 // only if mask was used here
397 if (!IsSomeVehicle(*pPix))
398 {
399 // record changed landscape in MatBuff
400 *pPix = ::Landscape.GetPix(x,y);
401 // put
402 ::Landscape.SetPix2(x, y, MaskMaterial, ::Landscape.Transparent);
403 }
404 }
405 }
406 }
407
C4SolidMask(C4Object * pForObject)408 C4SolidMask::C4SolidMask(C4Object *pForObject) : pForObject(pForObject)
409 {
410 // zero fields
411 MaskPut=false;
412 MaskPutRotation=0;
413 MaskRemovalX = Fix0;
414 MaskRemovalY = 0;
415 ppAttachingObjects=nullptr;
416 iAttachingObjectsCount=iAttachingObjectsCapacity=0;
417 MaskMaterial=MCVehic;
418 // Update linked list
419 Next = nullptr;
420 Prev = Last;
421 Last = this;
422 if (Prev) Prev->Next = this;
423 else First = this;
424 // create mat buff to store the material replaced by the solid mask
425 // the upper left corner is here the [objpos]+rot([shapexy]+[targetxy]+[realWH]/2)-maxWH/2
426 MatBuffPitch = (int) sqrt(double(pForObject->SolidMask.Wdt * pForObject->SolidMask.Wdt + pForObject->SolidMask.Hgt * pForObject->SolidMask.Hgt))+1;
427 if (!(pSolidMaskMatBuff= new BYTE [MatBuffPitch * MatBuffPitch] )) return;
428 memset(pSolidMaskMatBuff, 0, MatBuffPitch * MatBuffPitch);
429 }
430
~C4SolidMask()431 C4SolidMask::~C4SolidMask()
432 {
433 Remove(false);
434 // Update linked list
435 if (Next) Next->Prev = Prev;
436 if (Prev) Prev->Next = Next;
437 if (First == this) First = Next;
438 if (Last == this) Last = Prev;
439 delete [] pSolidMaskMatBuff;
440 delete [] ppAttachingObjects;
441 }
442
RemoveSolidMasks()443 void C4SolidMask::RemoveSolidMasks()
444 {
445 C4Rect SolidMaskRect(0,0,::Landscape.GetWidth(),::Landscape.GetHeight());
446 C4SolidMask *pSolid;
447 for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
448 {
449 pSolid->RemoveTemporary(SolidMaskRect);
450 }
451 }
452
PutSolidMasks()453 void C4SolidMask::PutSolidMasks()
454 {
455 C4Rect SolidMaskRect(0,0,::Landscape.GetWidth(),::Landscape.GetHeight());
456 C4SolidMask *pSolid;
457 // Restore Solidmasks
458 for (pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
459 {
460 pSolid->PutTemporary(SolidMaskRect);
461 }
462 }
463
464 C4SolidMask * C4SolidMask::First = nullptr;
465 C4SolidMask * C4SolidMask::Last = nullptr;
466
467
CheckConsistency()468 bool C4SolidMask::CheckConsistency()
469 {
470 if (!SOLIDMASK_DEBUG)
471 return true;
472
473 C4Rect SolidMaskRect(0,0,::Landscape.GetWidth(),::Landscape.GetHeight());
474 C4SolidMask *pSolid;
475 for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
476 {
477 pSolid->RemoveTemporary(SolidMaskRect);
478 }
479 assert(!::Landscape.GetMatCount(MVehic));
480 // Restore Solidmasks
481 for (pSolid = C4SolidMask::First; pSolid; pSolid = pSolid->Next)
482 {
483 pSolid->PutTemporary(SolidMaskRect);
484 }
485 return true;
486 }
487
LoadMaskFromFile(class C4Group & hGroup,const char * szFilename)488 CSurface8 *C4SolidMask::LoadMaskFromFile(class C4Group &hGroup, const char *szFilename)
489 {
490 // Construct SolidMask surface from PNG bitmap:
491 // All pixels that are more than 50% transparent are not solid
492 CPNGFile png;
493 StdBuf png_buf;
494 if (!hGroup.LoadEntry(szFilename, &png_buf)) return nullptr; // error messages done by caller
495 if (!png.Load((BYTE*)png_buf.getMData(), png_buf.getSize())) return nullptr;
496 CSurface8 *result = new CSurface8(png.iWdt, png.iHgt);
497 for (size_t y=0u; y<png.iHgt; ++y)
498 for (size_t x=0u; x<png.iWdt; ++x)
499 result->SetPix(x,y,((png.GetPix(x,y)>>24)<128) ? 0x00 : 0xff);
500 return result;
501 }
502
SetHalfVehicle(bool set)503 void C4SolidMask::SetHalfVehicle(bool set)
504 {
505 MaskMaterial = set ? MCHalfVehic : MCVehic;
506 // TODO: Redraw
507 }
508