OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Surface.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk 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 // a wrapper class to DirectDraw surfaces
18 
19 #include "C4Include.h"
21 #include "graphics/C4Surface.h"
22 
23 #include "c4group/CStdFile.h"
24 #include "graphics/Bitmap256.h"
25 #include "graphics/C4Draw.h"
26 #include "graphics/C4DrawGL.h"
27 #include "graphics/StdPNG.h"
28 #include "lib/StdColors.h"
29 #include "platform/C4App.h"
30 #include "platform/C4Window.h"
31 #include "platform/StdRegistry.h"
32 
33 #ifdef HAVE_IO_H
34 #include <io.h>
35 #endif
36 
38 {
39  Default();
40 }
41 
42 C4Surface::C4Surface(int iWdt, int iHgt, int iFlags)
43 {
44  Default();
45  // create
46  Create(iWdt, iHgt, iFlags);
47 }
48 
50  Wdt(0), Hgt(0)
51 {
52  Default();
53  fPrimary=true;
54  this->pWindow=pWindow;
55  // create rendering context
56 #ifndef USE_CONSOLE
57  pCtx = pGL->CreateContext(pWindow, pApp);
58 #endif
59  // reset clipping
60  NoClip();
61 }
62 
64 {
65  /* for (C4ObjectLink *lnk = ::Objects.First; lnk; lnk=lnk->Next)
66  if (lnk->Obj->Menu)
67  lnk->Obj->Menu->AssertSurfaceNotUsed(this);*/
68  Clear();
69 }
70 
72 {
73  Wdt=Hgt=0;
74  Scale=1;
77  Locked=0;
78  Attached=false;
79  fPrimary=false;
80  pMainSfc=nullptr;
81  pNormalSfc=nullptr;
82 #ifndef USE_CONSOLE
83  pCtx=nullptr;
84 #endif
85  pWindow=nullptr;
86  ClrByOwnerClr=0;
87  iTexSize=0;
88  fIsBackground=false;
89 #ifdef _DEBUG
90  dbg_idx = 0;
91 #endif
92 }
93 
95 {
96  // clear own
97  Clear();
98  // safety
99  if (!psfcFrom) return;
100  // grab data from other sfc
101 #ifdef _DEBUG
102  dbg_idx = psfcFrom->dbg_idx;
103 #endif
104  Wdt=psfcFrom->Wdt; Hgt=psfcFrom->Hgt;
107  psfcFrom->PrimarySurfaceLockBits=nullptr;
108  ClipX=psfcFrom->ClipX; ClipY=psfcFrom->ClipY;
109  ClipX2=psfcFrom->ClipX2; ClipY2=psfcFrom->ClipY2;
110  Locked=psfcFrom->Locked;
111  Attached=psfcFrom->Attached;
112  fPrimary=psfcFrom->fPrimary; // shouldn't be true!
113  texture = std::move(psfcFrom->texture);
114  pMainSfc=psfcFrom->pMainSfc;
115  pNormalSfc=psfcFrom->pNormalSfc;
116  ClrByOwnerClr=psfcFrom->ClrByOwnerClr;
117  iTexSize=psfcFrom->iTexSize;
118 #ifndef USE_CONSOLE
119  Format=psfcFrom->Format;
120 #endif
121  fIsBackground = psfcFrom->fIsBackground;
122  // default other sfc
123  psfcFrom->Default();
124 }
125 
127 {
128  // Undo all locks
129  while (Locked) Unlock();
130  // release surface
131 #ifndef USE_CONSOLE
132  if (pCtx)
133  {
134  delete pCtx;
135  pCtx = nullptr;
136  }
137 #endif
138  texture.reset();
139 #ifdef _DEBUG
140  dbg_idx = 0;
141 #endif
142 }
143 
145 {
146  // primary is always OK...
147  return fPrimary;
148 }
149 
151 {
152  ClipX=0; ClipY=0; ClipX2=Wdt-1; ClipY2=Hgt-1;
153 }
154 
155 void C4Surface::Clip(int iX, int iY, int iX2, int iY2)
156 {
157  ClipX=Clamp(iX,0,Wdt-1); ClipY=Clamp(iY,0,Hgt-1);
158  ClipX2=Clamp(iX2,0,Wdt-1); ClipY2=Clamp(iY2,0,Hgt-1);
159 }
160 
161 bool C4Surface::Create(int iWdt, int iHgt, int iFlags)
162 {
163  Clear(); Default();
164  // check size
165  if (!iWdt || !iHgt) return false;
166  Wdt=iWdt; Hgt=iHgt;
167  // create texture: check gfx system
168  if (!pDraw) return false;
169  if (!pDraw->DeviceReady()) return false;
170 
171  // store color format that will be used
172 #ifndef USE_CONSOLE
173  Format=pGL->sfcFmt;
174 #endif
175  // create texture
176  iTexSize = std::max(iWdt, iHgt);
177  texture = std::make_unique<C4TexRef>(iWdt, iHgt, iFlags);
178  // update clipping
179  NoClip();
180  // success
181  return true;
182 }
183 
185 {
186  // Clear anything old
187  Clear();
188  // Default to other surface's color depth
189  Default();
190  // Create surface (TODO: copy flags)
191  if (!Create(fromSfc.Wdt, fromSfc.Hgt)) return false;
192  // Blit copy
193  if (!pDraw->BlitSurface(&fromSfc, this, 0, 0, false))
194  { Clear(); return false; }
195  // Success
196  return true;
197 }
198 
199 #define RANGE 255
200 #define HLSMAX RANGE
201 #define RGBMAX 255
202 
203 bool ClrByOwner(DWORD &dwClr) // new style, based on Microsoft Knowledge Base Article - 29240
204 {
205  int H,L,S;
206  WORD R,G,B;
207  BYTE cMax,cMin;
208  WORD Rdelta,Gdelta,Bdelta;
209  // get RGB
210  R = GetRedValue(dwClr);
211  G = GetGreenValue(dwClr);
212  B = GetBlueValue(dwClr);
213  // calculate lightness
214  cMax = std::max<int>(std::max<int>(R,G),B);
215  cMin = std::min<int>(std::min<int>(R,G),B);
216  L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX);
217  // achromatic case
218  if (cMax == cMin)
219  {
220  S = 0;
221  H = (HLSMAX*2/3);
222  }
223  // chromatic case
224  else
225  {
226  // saturation
227  if (L <= (HLSMAX/2))
228  S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
229  else
230  S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) )
231  / (2*RGBMAX-cMax-cMin);
232  // hue
233  Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
234  Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
235  Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
236  if (R == cMax)
237  H = Bdelta - Gdelta;
238  else if (G == cMax)
239  H = (HLSMAX/3) + Rdelta - Bdelta;
240  else
241  H = ((2*HLSMAX)/3) + Gdelta - Rdelta;
242  if (H < 0)
243  H += HLSMAX;
244  if (H > HLSMAX)
245  H -= HLSMAX;
246  }
247  // Not blue
248  if (!(Inside(H, 145, 175) && (S > 100))) return false;
249  // It's blue: make it gray
250  BYTE b = GetBlueValue(dwClr);
251  dwClr = RGBA(b, b, b, 0) | (dwClr & 0xff000000);
252  return true;
253 }
254 
256 {
257  // safety
258  if (!pBySurface) return false;
259  if (!pBySurface->texture) return false;
260  // create in same size
261  if (!Create(pBySurface->Wdt, pBySurface->Hgt)) return false;
262  // copy scale
263  Scale = pBySurface->Scale;
264  // set main surface
265  pMainSfc=pBySurface;
266  // lock it
267  if (!pMainSfc->Lock()) return false;
268  if (!Lock()) { pMainSfc->Unlock(); return false; }
269  // set ColorByOwner-pixels
270  for (int iY=0; iY<Hgt; ++iY)
271  for (int iX=0; iX<Wdt; ++iX)
272  {
273  // get pixel
274  DWORD dwPix=pMainSfc->GetPixDw(iX, iY, false);
275  // is it a ClrByOwner-px?
276  if (!ClrByOwner(dwPix)) continue;
277  // set in this surface
278  SetPixDw(iX, iY, dwPix);
279  // clear in the other
280  pMainSfc->SetPixDw(iX, iY, 0x00ffffff);
281  }
282  // unlock
283  Unlock();
284  pMainSfc->Unlock();
285  // success
286  return true;
287 }
288 
290 {
291  // safety
292  if (!pOfSurface) return false;
293  if (Wdt != pOfSurface->Wdt || Hgt != pOfSurface->Hgt)
294  return false;
295  // set main surface
296  pMainSfc=pOfSurface;
297  // success
298  return true;
299 }
300 
301 bool C4Surface::UpdateSize(int wdt, int hgt)
302 {
303  assert(fPrimary);
304  if (!fPrimary)
305  return false;
306  this->Wdt = wdt; this->Hgt = hgt;
307  return true;
308 }
309 
310 bool C4Surface::PageFlip(C4Rect *pSrcRt, C4Rect *pDstRt)
311 {
312  assert(fPrimary);
313  if (!fPrimary)
314  return false;
315  // call from gfx thread only!
316  if (!pDraw->pApp || !pDraw->pApp->AssertMainThread()) return false;
317 #ifndef USE_CONSOLE
318  return pCtx->PageFlip();
319 #endif
320  return true;
321 }
322 
323 bool C4Surface::ReadBMP(CStdStream &hGroup, int iFlags)
324 {
325  int lcnt;
326  C4BMP256Info BitmapInfo;
327  // read bmpinfo-header
328  if (!hGroup.Read(&BitmapInfo,sizeof(C4BMPInfo))) return false;
329  // is it 8bpp?
330  if (BitmapInfo.Info.biBitCount == 8)
331  {
332  if (!hGroup.Read(((BYTE *) &BitmapInfo)+sizeof(C4BMPInfo),
333  std::min(sizeof(BitmapInfo)-sizeof(C4BMPInfo),sizeof(BitmapInfo)-sizeof(C4BMPInfo)+BitmapInfo.FileBitsOffset())))
334  return false;
335  if (!hGroup.Advance(BitmapInfo.FileBitsOffset())) return false;
336  }
337  else
338  {
339  // read 24bpp
340  if (BitmapInfo.Info.biBitCount != 24) return false;
341  if (!hGroup.Advance(((C4BMPInfo) BitmapInfo).FileBitsOffset())) return false;
342  }
343 
344  // Create and lock surface
345  if (!Create(BitmapInfo.Info.biWidth,BitmapInfo.Info.biHeight, iFlags)) return false;
346  if (!Lock()) { Clear(); return false; }
347 
348  // create line buffer
349  int iBufSize=DWordAligned(BitmapInfo.Info.biWidth*BitmapInfo.Info.biBitCount/8);
350  BYTE *pBuf = new BYTE[iBufSize];
351  // Read lines
352  for (lcnt=Hgt-1; lcnt>=0; lcnt--)
353  {
354  if (!hGroup.Read(pBuf, iBufSize))
355  { Clear(); delete [] pBuf; return false; }
356  BYTE *pPix=pBuf;
357  for (int x=0; x<BitmapInfo.Info.biWidth; ++x)
358  switch (BitmapInfo.Info.biBitCount)
359  {
360  case 8:
361  SetPixDw(x, lcnt, C4RGB(
362  BitmapInfo.Colors[*pPix].rgbRed,
363  BitmapInfo.Colors[*pPix].rgbGreen,
364  BitmapInfo.Colors[*pPix].rgbBlue));
365  ++pPix;
366  break;
367  case 24:
368  SetPixDw(x, lcnt, C4RGB(pPix[0], pPix[1], pPix[2]));
369  pPix+=3;
370  break;
371  }
372  }
373  // free buffer again
374  delete [] pBuf;
375 
376  Unlock();
377 
378  return true;
379 }
380 
381 bool C4Surface::SavePNG(const char *szFilename, bool fSaveAlpha, bool fSaveOverlayOnly, bool use_background_thread)
382 {
383  // Lock - WARNING - maybe locking primary surface here...
384  if (!Lock()) return false;
385 
386  // create png file
387  std::unique_ptr<CPNGFile> png(new CPNGFile());
388  if (!png->Create(Wdt, Hgt, fSaveAlpha)) { Unlock(); return false; }
389 
390  // reset overlay if desired
391  C4Surface *pMainSfcBackup = nullptr;
392  if (fSaveOverlayOnly) { pMainSfcBackup=pMainSfc; pMainSfc=nullptr; }
393 
394 #ifndef USE_CONSOLE
395  if (fPrimary)
396  {
397  // Take shortcut. FIXME: Check Endian
398  for (int y = 0; y < Hgt; ++y)
399  glReadPixels(0, Hgt - y - 1, Wdt, 1, fSaveAlpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, png->GetRow(y));
400  }
401  else
402 #endif
403  {
404  // write pixel values
405  for (int y=0; y<Hgt; ++y)
406  for (int x=0; x<Wdt; ++x)
407  {
408  DWORD dwClr = GetPixDw(x, y, false);
409  png->SetPix(x, y, dwClr);
410  }
411  }
412 
413  // reset overlay
414  if (fSaveOverlayOnly) pMainSfc=pMainSfcBackup;
415 
416  // Unlock
417  Unlock();
418 
419  // save png - either directly or delayed in a background thread if desired
420  if (use_background_thread)
421  {
422  CPNGFile::ScheduleSaving(png.release(), szFilename);
423  }
424  else
425  {
426  if (!png->Save(szFilename)) return false;
427  }
428 
429  // Success
430  return true;
431 }
432 
433 
435 {
436  return true;
437 }
438 
439 double ColorDistance(BYTE *bpRGB1, BYTE *bpRGB2)
440 {
441  return (double) (Abs(bpRGB1[0]-bpRGB2[0]) + Abs(bpRGB1[1]-bpRGB2[1]) + Abs(bpRGB1[2]-bpRGB2[2])) / 6.0;
442 }
443 
444 bool C4Surface::GetSurfaceSize(int &irX, int &irY)
445 {
446  // simply assign stored values
447  irX=Wdt;
448  irY=Hgt;
449  // success
450  return true;
451 }
452 
454 {
455  // lock main sfc
456  if (pMainSfc) if (!pMainSfc->Lock()) return false;
457  // lock texture
458  if (!Locked && !fPrimary && !texture)
459  return false;
460  // count lock
461  Locked++; return true;
462 }
463 
465 {
466  // unlock main sfc
467  if (pMainSfc) pMainSfc->Unlock();
468  // locked?
469  if (!Locked) return false;
470  // decrease lock counter; check if zeroed and unlock then
471  Locked--;
472  if (!Locked)
473  {
474  if (fPrimary)
475  {
476  // emulated primary locks in OpenGL
477  delete[] PrimarySurfaceLockBits;
478  PrimarySurfaceLockBits = nullptr;
479  return true;
480  }
481  else
482  {
483  // non-primary unlock: unlock all texture surfaces (if locked)
484  if (texture)
485  texture->Unlock();
486  }
487  }
488  return true;
489 }
490 
491 DWORD C4Surface::GetPixDw(int iX, int iY, bool fApplyModulation)
492 {
493  BYTE *pBuf = nullptr; int iPitch = 0; // TODO: are those initialised to something sensible?
494  // backup pos
495  int iX2=iX; int iY2=iY;
496  // primary?
497  if (fPrimary)
498  {
499 #ifndef USE_CONSOLE
501  {
502  PrimarySurfaceLockBits = new unsigned char[Wdt*Hgt*3];
503  glPixelStorei(GL_PACK_ALIGNMENT, 1);
504  glReadPixels( 0, 0, Wdt, Hgt, GL_BGR, GL_UNSIGNED_BYTE, PrimarySurfaceLockBits);
506  }
507  return * (DWORD *) (PrimarySurfaceLockBits+(Hgt-iY-1)*PrimarySurfaceLockPitch+iX*3);
508 #endif
509  }
510  else
511  {
512  // get+lock affected texture
513  if (!texture) return 0;
514  texture->Lock();
515  pBuf=(BYTE *) texture->texLock.pBits;
516  iPitch=texture->texLock.Pitch;
517  }
518  // get pix of surface
519  DWORD dwPix;
520  DWORD *pPix=(DWORD *) (pBuf+iY*iPitch+iX*4);
521  dwPix = *pPix;
522  // this is a ColorByOwner-surface?
523  if (pMainSfc)
524  {
525  BYTE byAlpha=BYTE(dwPix>>24);
526  // pix is fully transparent?
527  if (byAlpha==0x00)
528  // then get the main surfaces's pixel
529  dwPix = pMainSfc->GetPixDw(iX2, iY2, fApplyModulation);
530  else
531  {
532  // otherwise, it's a ColorByOwner-pixel: adjust the color
533  if (fApplyModulation)
534  {
537  else
538  ModulateClr(dwPix, ClrByOwnerClr);
541  }
542  else
543  ModulateClr(dwPix, ClrByOwnerClr);
544  // does it contain transparency? then blit on main sfc
545  if (byAlpha)
546  {
547  DWORD dwMainPix = pMainSfc->GetPixDw(iX2, iY2, fApplyModulation);
548  BltAlpha(dwMainPix, dwPix); dwPix=dwMainPix;
549  }
550  }
551  }
552  else
553  {
554  // single main surface
555  // apply color modulation if desired
556  if (fApplyModulation && pDraw->BlitModulated)
557  {
560  else
562  }
563  }
564  // return pixel value
565  return dwPix;
566 }
567 
568 bool C4Surface::IsPixTransparent(int iX, int iY)
569 {
570  // get pixel value
571  DWORD dwPix=GetPixDw(iX, iY, false);
572  // get alpha value
573  return (dwPix>>24) < 128;
574 }
575 
576 bool C4Surface::SetPixDw(int iX, int iY, DWORD dwClr)
577 {
578  // clip
579  if ((iX<ClipX) || (iX>ClipX2) || (iY<ClipY) || (iY>ClipY2)) return true;
580  // get+lock affected texture
581  if (!texture) return false;
582  texture->Lock();
583  // if color is fully transparent, ensure it's black
584  if (dwClr>>24 == 0x00) dwClr=0x00000000;
585  // ...and set in actual surface
586  texture->SetPix(iX, iY, dwClr);
587  // success
588  return true;
589 }
590 
591 bool C4Surface::BltPix(int iX, int iY, C4Surface *sfcSource, int iSrcX, int iSrcY, bool fTransparency)
592 {
593  // 32bit-blit. lock target
594  if (!texture) return false;
595  texture->Lock();
596  DWORD *pPix32 = (DWORD *)(((BYTE *)texture->texLock.pBits) + iY*texture->texLock.Pitch + iX * 4);
597  // get source pix as dword
598  DWORD srcPix=sfcSource->GetPixDw(iSrcX, iSrcY, true);
599  // merge
600  if (!fTransparency)
601  {
602  // set it
603  *pPix32=srcPix;
604  }
605  else
606  {
608  BltAlphaAdd(*pPix32, srcPix);
609  else
610  BltAlpha(*pPix32, srcPix);
611  }
612  // done
613  return true;
614 }
615 
616 void C4Surface::ClearBoxDw(int iX, int iY, int iWdt, int iHgt)
617 {
618  // lock
619  if (!Locked) return;
620  // clip to target size
621  if (iX<0) { iWdt+=iX; iX=0; }
622  if (iY<0) { iHgt+=iY; iY=0; }
623  int iOver;
624  iOver=Wdt-(iX+iWdt); if (iOver<0) iWdt+=iOver;
625  iOver=Hgt-(iY+iHgt); if (iOver<0) iHgt+=iOver;
626  C4Rect rtClear{ iX, iY, iWdt, iHgt };
627  if (pMainSfc && pMainSfc->texture)
628  {
629  // assuming this is only valid as long as there's no texture management,
630  // organizing partially used textures together!
631  pMainSfc->texture->ClearRect(rtClear);
632  }
633  // clear this texture
634  texture->ClearRect(rtClear);
635 }
636 
637 C4TexRef::C4TexRef(int iSizeX, int iSizeY, int iFlags)
638 {
639  // zero fields
640 #ifndef USE_CONSOLE
641  texName = 0;
642 #endif
643  texLock.pBits=nullptr; fIntLock=false;
644  // store size
645  this->iSizeX=iSizeX;
646  this->iSizeY=iSizeY;
647  this->iFlags=iFlags;
648  // add to texture manager
649  if (!pTexMgr) pTexMgr = new C4TexMgr();
650  pTexMgr->RegTex(this);
651  // create texture: check ddraw
652  if (!pDraw) return;
653  if (!pDraw->DeviceReady()) return;
654  // create it!
655  // Reserve video memory
656  CreateTexture();
657 
658  if ((iFlags & C4SF_Unlocked) == 0 && pDraw)
659  {
660  texLock.pBits = new unsigned char[iSizeX * iSizeY * C4Draw::COLOR_DEPTH_BYTES];
662  memset(texLock.pBits, 0x00, texLock.Pitch*iSizeY);
663  // Always locked
664  LockSize.x = LockSize.y = 0;
666  }
667 }
668 
670 {
671  fIntLock=false;
672  // free texture
673 #ifndef USE_CONSOLE
674  if (pGL && pGL->pCurrCtx) glDeleteTextures(1, &texName);
675 #endif
676  if (pDraw) delete [] static_cast<unsigned char*>(texLock.pBits); texLock.pBits = nullptr;
677  // remove from texture manager
678  pTexMgr->UnregTex(this);
679 }
680 
681 void C4TexRef::CreateTexture()
682 {
683 #ifndef USE_CONSOLE
684  assert(texName == 0);
685 
686  const bool fTileable = (iFlags & C4SF_Tileable) != 0;
687  const bool fMipMap = (iFlags & C4SF_MipMap) != 0;
688 
689  glGenTextures(1, &texName);
690  glBindTexture(GL_TEXTURE_2D, texName);
691  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, fTileable ? GL_REPEAT : GL_CLAMP_TO_EDGE);
692  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, fTileable ? GL_REPEAT : GL_CLAMP_TO_EDGE);
693  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
694  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, fMipMap ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
695  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iSizeX, iSizeY, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
696  if (fMipMap) glGenerateMipmap(GL_TEXTURE_2D);
697 #endif
698 }
699 
701 {
702  // already locked?
703  if (texLock.pBits)
704  {
705  // fully locked
706  if (LockSize.x == 0 && LockSize.Wdt == iSizeX && LockSize.y == 0 && LockSize.Hgt == iSizeY)
707  {
708  return true;
709  }
710  else
711  {
712  // Commit previous changes to the texture
713  Unlock();
714  }
715  }
716  // lock
717 #ifndef USE_CONSOLE
718  // prepare texture data
719  texLock.pBits = new unsigned char[rtUpdate.Wdt * rtUpdate.Hgt * C4Draw::COLOR_DEPTH_BYTES];
721  LockSize = rtUpdate;
722  return true;
723 #endif
724  // failure
725  return false;
726 }
727 
729 {
730  // already locked?
731  if (texLock.pBits) return true;
733  LockSize.x = LockSize.y = 0;
734  // lock
735 #ifndef USE_CONSOLE
736  if (texName)
737  {
738  if (!pGL->pCurrCtx) return false;
739  // get texture
740  texLock.pBits = new unsigned char[iSizeX * iSizeY * C4Draw::COLOR_DEPTH_BYTES];
742  glBindTexture(GL_TEXTURE_2D, texName);
743  glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texLock.pBits);
744  return true;
745  }
746 #endif
747  {
748  // nothing to do
749  }
750  // failure
751  return false;
752 }
753 
755 {
756  // locked?
757  if (!texLock.pBits || fIntLock) return;
758 #ifndef USE_CONSOLE
759  if (!pGL->pCurrCtx)
760  {
761 // BREAKPOINT_HERE;
762  assert(pGL->pMainCtx);
763  pGL->pMainCtx->Select();
764  }
765 
766  const bool fTileable = (iFlags & C4SF_Tileable) != 0;
767  const bool fMipMap = (iFlags & C4SF_MipMap) != 0;
768 
769  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
770 
771  // reuse the existing texture
772  glBindTexture(GL_TEXTURE_2D, texName);
773  glTexSubImage2D(GL_TEXTURE_2D, 0,
775  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texLock.pBits);
776 
777  delete[] static_cast<unsigned char*>(texLock.pBits); texLock.pBits=nullptr;
778  if (fMipMap) glGenerateMipmap(GL_TEXTURE_2D);
779 #endif
780 }
781 
783 {
784  // ensure locked
785  if (!LockForUpdate(rtClear)) return false;
786  // clear pixels
787  int y;
788  for (y = rtClear.y; y < rtClear.y + rtClear.Hgt; ++y)
789  {
790  for (int x = rtClear.x; x < rtClear.x + rtClear.Wdt; ++x)
791  SetPix(x, y, 0x00000000);
792  }
793  // success
794  return true;
795 }
796 
798 {
799  // ensure locked
800  if (!Lock()) return false;
801  // clear pixels
802  int y;
803  for (y=0; y<iSizeY; ++y)
804  {
805  for (int x = 0; x < iSizeX; ++x)
806  SetPix(x, y, 0xff000000);
807  }
808  // success
809  return true;
810 }
811 
812 // texture manager
813 
815 {
816  // clear textures
817  Textures.clear();
818 }
819 
821 {
822  // unlock all textures
823  IntUnlock();
824 }
825 
827 {
828  // add texture to list
829  Textures.push_front(pTex);
830 }
831 
833 {
834  // remove texture from list
835  Textures.remove(pTex);
836  // if list is empty, remove self
837  if (Textures.empty()) { delete this; pTexMgr=nullptr; }
838 }
839 
841 {
842  // lock all textures
843  int j=Textures.size();
844  for (std::list<C4TexRef *>::iterator i=Textures.begin(); j--; ++i)
845  {
846  C4TexRef *pRef = *i;
847  if (pRef->Lock() && pRef->texLock.pBits)
848  {
849  pRef->fIntLock = true;
850 #ifndef USE_CONSOLE
851  // Release the underlying texture with GL and recreate
852  // it on unlock, so that the texture survives
853  // context recreation.
854  if(pGL)
855  {
856  glDeleteTextures(1, &pRef->texName);
857  pRef->texName = 0;
858  }
859 #endif
860  }
861  }
862 }
863 
865 {
866  // unlock all internally locked textures
867  int j=Textures.size();
868  for (std::list<C4TexRef *>::iterator i=Textures.begin(); j--; ++i)
869  {
870  C4TexRef *pRef = *i;
871  if (pRef->fIntLock)
872  {
873  pRef->fIntLock = false;
874  pRef->CreateTexture();
875  pRef->Unlock();
876  }
877  }
878 }
879 
bool AssertMainThread()
Definition: C4App.h:123
static constexpr int COLOR_DEPTH_BYTES
Definition: C4Draw.h:90
BYTE rgbRed
Definition: Bitmap256.h:54
int DWordAligned(int val)
Definition: Standard.h:47
bool ReadBMP(CStdStream &hGroup, int iFlags)
Definition: C4Surface.cpp:323
virtual bool Select(bool verbose=false)
#define C4GFXBLIT_MOD2
Definition: C4Surface.h:27
bool SetAsClrByOwnerOf(C4Surface *pOfSurface)
Definition: C4Surface.cpp:289
CStdGLCtx * pCurrCtx
Definition: C4DrawGL.h:179
int Wdt
Definition: C4Surface.h:65
bool LockForUpdate(C4Rect &rtUpdate)
Definition: C4Surface.cpp:700
C4Window * pWindow
Definition: C4Surface.h:86
#define GetGreenValue(rgb)
Definition: StdColors.h:28
bool Lock()
Definition: C4Surface.cpp:728
#define b
void IntLock()
Definition: C4Surface.cpp:840
virtual bool DeviceReady()=0
CStdGLCtx * pCtx
Definition: C4Surface.h:76
bool Lock()
Definition: C4Surface.cpp:453
bool SavePNG(C4Group &hGroup, const char *szFilename, bool fSaveAlpha=true, bool fSaveOverlayOnly=false)
void MoveFrom(C4Surface *psfcFrom)
Definition: C4Surface.cpp:94
bool ClrByOwner(DWORD &dwClr)
Definition: C4Surface.cpp:203
void Default()
Definition: C4Surface.cpp:71
void SetPix(int iX, int iY, DWORD v)
Definition: C4Surface.h:172
CStdGLCtx * pMainCtx
Definition: C4DrawGL.h:178
bool CreateColorByOwner(C4Surface *pBySurface)
Definition: C4Surface.cpp:255
void RegTex(C4TexRef *pTex)
Definition: C4Surface.cpp:826
#define C4GFXBLIT_ADDITIVE
Definition: C4Surface.h:26
BITMAPINFOHEADER Info
Definition: Bitmap256.h:67
bool Unlock()
Definition: C4Surface.cpp:464
int iSizeY
Definition: C4Surface.h:158
DWORD ClrByOwnerClr
Definition: C4Surface.h:81
Definition: C4Rect.h:27
uint8_t BYTE
void ModulateClr(DWORD &dwDst, DWORD dwMod)
Definition: StdColors.h:53
double ColorDistance(BYTE *bpRGB1, BYTE *bpRGB2)
Definition: C4Surface.cpp:439
unsigned char * pBits
Definition: C4Surface.h:146
int ClipX
Definition: C4Surface.h:69
#define GetRedValue(rgb)
Definition: StdColors.h:29
CStdGLCtx * CreateContext(C4Window *pWindow, C4AbstractApp *pApp) override
Definition: C4DrawGL.cpp:282
static void ScheduleSaving(CPNGFile *png, const char *filename)
Definition: StdPNG.cpp:352
int Hgt
Definition: C4Surface.h:65
int iSizeX
Definition: C4Surface.h:157
void ClearBoxDw(int iX, int iY, int iWdt, int iHgt)
Definition: C4Surface.cpp:616
void ModulateClrMOD2(DWORD &dwDst, DWORD dwMod)
Definition: StdColors.h:73
int Scale
Definition: C4Surface.h:66
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
const int C4SF_Unlocked
Definition: C4Surface.h:51
GLenum sfcFmt
Definition: C4DrawGL.h:177
int32_t Wdt
Definition: C4Rect.h:30
unsigned int Format
Definition: C4Surface.h:75
bool BlitSurface(C4Surface *sfcSurface, C4Surface *sfcTarget, int tx, int ty, bool fBlitBase)
Definition: C4Draw.cpp:517
C4Surface * pNormalSfc
Definition: C4Surface.h:80
C4TexMgr * pTexMgr
Definition: C4Surface.cpp:880
BYTE rgbGreen
Definition: Bitmap256.h:53
int iFlags
Definition: C4Surface.h:160
bool UpdateSize(int wdt, int hgt)
Definition: C4Surface.cpp:301
int32_t y
Definition: C4Rect.h:30
bool AttachPalette()
Definition: C4Surface.cpp:434
C4TexRef(int iSizeX, int iSizeY, int iFlags)
Definition: C4Surface.cpp:637
#define GetBlueValue(rgb)
Definition: StdColors.h:27
bool SetPixDw(int iX, int iY, DWORD dwCol)
Definition: C4Surface.cpp:576
void Clear()
Definition: C4Surface.cpp:126
bool PageFlip(C4Rect *pSrcRt=nullptr, C4Rect *pDstRt=nullptr)
Definition: C4Surface.cpp:310
bool GetSurfaceSize(int &irX, int &irY)
Definition: C4Surface.cpp:444
bool fIntLock
Definition: C4Surface.h:159
#define C4GFXBLIT_CLRSFC_OWNCLR
Definition: C4Surface.h:28
const int C4SF_Tileable
Definition: C4Surface.h:49
const int C4SF_MipMap
Definition: C4Surface.h:50
int iTexSize
Definition: C4Surface.h:68
C4Draw * pDraw
Definition: C4Draw.cpp:42
#define C4RGB(r, g, b)
Definition: StdColors.h:26
bool fIsBackground
Definition: C4Surface.h:70
void UnregTex(C4TexRef *pTex)
Definition: C4Surface.cpp:832
bool Copy(C4Surface &fromSfc)
Definition: C4Surface.cpp:184
DWORD GetPixDw(int iX, int iY, bool fApplyModulation)
Definition: C4Surface.cpp:491
LOCKED_RECT texLock
Definition: C4Surface.h:153
void Clip(int iX, int iY, int iX2, int iY2)
Definition: C4Surface.cpp:155
void BltAlpha(DWORD &dwDst, DWORD dwSrc)
Definition: StdColors.h:31
#define HLSMAX
Definition: C4Surface.cpp:200
#define RGBMAX
Definition: C4Surface.cpp:201
virtual bool PageFlip()
bool BltPix(int iX, int iY, C4Surface *sfcSource, int iSrcX, int iSrcY, bool fTransparency)
Definition: C4Surface.cpp:591
DWORD BlitModulateClr
Definition: C4Draw.h:109
unsigned int texName
Definition: C4Surface.h:155
int32_t x
Definition: C4Rect.h:30
std::unique_ptr< C4TexRef > texture
Definition: C4Surface.h:78
#define C4GFXBLIT_CLRSFC_MOD2
Definition: C4Surface.h:29
C4Rect LockSize
Definition: C4Surface.h:161
int ClipX2
Definition: C4Surface.h:69
BYTE rgbBlue
Definition: Bitmap256.h:52
bool IsPixTransparent(int iX, int iY)
Definition: C4Surface.cpp:568
bool ClearRect(C4Rect &rtClear)
Definition: C4Surface.cpp:782
void BltAlphaAdd(DWORD &dwDst, DWORD dwSrc)
Definition: StdColors.h:42
bool Attached
Definition: C4Surface.h:88
BYTE * PrimarySurfaceLockBits
Definition: C4Surface.h:67
int PrimarySurfaceLockPitch
Definition: C4Surface.h:67
DWORD dwBlitMode
Definition: C4Draw.h:110
virtual bool Advance(int iOffset)=0
bool IsRenderTarget()
Definition: C4Surface.cpp:144
int ClipY
Definition: C4Surface.h:69
CStdGL * pGL
Definition: C4DrawGL.cpp:905
int32_t Hgt
Definition: C4Rect.h:30
T Abs(T val)
Definition: Standard.h:42
std::list< C4TexRef * > Textures
Definition: C4Surface.h:185
int Locked
Definition: C4Surface.h:87
uint32_t RGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
Definition: StdColors.h:22
bool fPrimary
Definition: C4Surface.h:89
bool Create(int iWdt, int iHgt, int iFlags=0)
Definition: C4Surface.cpp:161
uint32_t DWORD
virtual bool Read(void *pBuffer, size_t iSize)=0
bool BlitModulated
Definition: C4Draw.h:108
void Unlock()
Definition: C4Surface.cpp:754
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
void NoClip()
Definition: C4Surface.cpp:150
int FileBitsOffset()
Definition: Bitmap256.cpp:60
int ClipY2
Definition: C4Surface.h:69
uint16_t WORD
void IntUnlock()
Definition: C4Surface.cpp:864
bool FillBlack()
Definition: C4Surface.cpp:797
C4AbstractApp * pApp
Definition: C4Draw.h:95
friend class C4TexMgr
Definition: C4Surface.h:178
C4Surface * pMainSfc
Definition: C4Surface.h:79
RGBQUAD Colors[256]
Definition: Bitmap256.h:76