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