OpenClonk
C4PXS.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 
18 /* Pixel Sprite system for tiny bits of moving material */
19 
20 #include "C4Include.h"
21 #include "landscape/C4PXS.h"
22 
23 #include "c4group/C4Components.h"
24 #include "control/C4Record.h"
25 #include "game/C4Physics.h"
26 #include "graphics/C4Draw.h"
27 #include "landscape/C4Weather.h"
28 #include "lib/C4Random.h"
29 #include "lib/StdColors.h"
30 
31 static const C4Real WindDrift_Factor = itofix(1, 800);
32 
34 {
36  {
37  C4RCExecPXS rc;
38  rc.x=x; rc.y=y; rc.iMat=Mat;
39  rc.pos = 0;
40  AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
41  }
42  int32_t inmat;
43 
44  // Safety
45  if (!MatValid(Mat))
46  { Deactivate(); return false; }
47 
48  // Out of bounds
49  if ((x<0) || (x>=::Landscape.GetWidth()) || (y<-10) || (y>=::Landscape.GetHeight()))
50  { Deactivate(); return false; }
51 
52  // Material conversion
53  int32_t iX = fixtoi(x), iY = fixtoi(y);
54  inmat=GBackMat(iX,iY);
56  if (pReact && (*pReact->pFunc)(pReact, iX,iY, iX,iY, xdir,ydir, Mat,inmat, meePXSPos, nullptr))
57  { Deactivate(); return false; }
58 
59  // Gravity
60  ydir+=GravAccel;
61 
62  if (GBackDensity(iX, iY + 1) < ::MaterialMap.Map[Mat].Density)
63  {
64  // Air speed: Wind plus some random
65  int32_t iWind = Weather.GetWind(iX, iY);
66  C4Real txdir = itofix(iWind, 15) + C4REAL256(Random(1200) - 600);
67  C4Real tydir = C4REAL256(Random(1200) - 600);
68 
69  // Air friction, based on WindDrift. MaxSpeed is ignored.
70  int32_t iWindDrift = std::max(::MaterialMap.Map[Mat].WindDrift - 20, 0);
71  xdir += ((txdir - xdir) * iWindDrift) * WindDrift_Factor;
72  ydir += ((tydir - ydir) * iWindDrift) * WindDrift_Factor;
73  }
74 
75  C4Real ctcox = x + xdir;
76  C4Real ctcoy = y + ydir;
77 
78  int32_t iToX = fixtoi(ctcox), iToY = fixtoi(ctcoy);
79 
80  // In bounds?
81  if (Inside<int32_t>(iToX, 0, ::Landscape.GetWidth()-1) && Inside<int32_t>(iToY, 0, ::Landscape.GetHeight()-1))
82  // Check path
83  if (::Landscape._PathFree(iX, iY, iToX, iToY))
84  {
85  x=ctcox; y=ctcoy;
86  return true;
87  }
88 
89  // Test path to target position
90  int32_t iX0 = iX, iY0 = iY;
91  bool fStopMovement = false;
92  do
93  {
94  // Step
95  int32_t inX = iX + Sign(iToX - iX), inY = iY + Sign(iToY - iY);
96  // Contact?
97  inmat = GBackMat(inX, inY);
99  if (pReact)
100  {
101  if ((*pReact->pFunc)(pReact, iX,iY, inX,inY, xdir,ydir, Mat,inmat, meePXSMove, &fStopMovement))
102  {
103  // destructive contact
104  Deactivate();
105  return false;
106  }
107  else
108  {
109  // no destructive contact, but speed or position changed: Stop moving for now
110  if (fStopMovement)
111  {
112  // But keep fractional positions to allow proper movement on moving ground
113  if (iX != iX0) x = itofix(iX);
114  if (iY != iY0) y = itofix(iY);
115  return true;
116  }
117  // there was a reaction func, but it didn't do anything - continue movement
118  }
119  }
120  iX = inX; iY = inY;
121  }
122  while (iX != iToX || iY != iToY);
123 
124  // No contact? Free movement
125  x=ctcox; y=ctcoy;
127  {
128  C4RCExecPXS rc;
129  rc.x=x; rc.y=y; rc.iMat=Mat;
130  rc.pos = 1;
131  AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
132  }
133  return true;
134 }
135 
137 {
139  {
140  C4RCExecPXS rc;
141  rc.x=x; rc.y=y; rc.iMat=Mat;
142  rc.pos = 2;
143  AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc));
144  }
145  Mat=MNone;
146 }
147 
149 {
150  Default();
151 }
152 
154 {
155  Clear();
156 }
157 
159 {
160  Count=0;
161 }
162 
164 {
165  Count=0;
166 }
167 
169 {
170  if (Count < PXSMax)
171  return &PXS[Count++];
172  return nullptr;
173 }
174 
175 bool C4PXSSystem::Create(int32_t mat, C4Real ix, C4Real iy, C4Real ixdir, C4Real iydir)
176 {
177  C4PXS *pxp;
178  if (!MatValid(mat)) return false;
179  if (!(pxp=New())) return false;
180  pxp->Mat=mat;
181  pxp->x=ix; pxp->y=iy;
182  pxp->xdir=ixdir; pxp->ydir=iydir;
183  return true;
184 }
185 
187 {
188  for (size_t i = 0; i < Count; i++)
189  {
190  if (!PXS[i].Execute())
191  {
192  assert(PXS[i].Mat == MNone);
193  PXS[i--] = PXS[--Count];
194  }
195  }
196 }
197 
199 {
200  // Draw PXS in this region
201  C4Rect VisibleRect(cgo.TargetX, cgo.TargetY, cgo.Wdt, cgo.Hgt);
202  VisibleRect.Enlarge(20);
203 
204  // Go through all PXS and build vertex arrays. The vertex arrays are
205  // then submitted to the GL in one go.
206  std::vector<C4BltVertex> pixVtx;
207  std::vector<C4BltVertex> lineVtx;
208  std::map<int, std::vector<C4BltVertex> > bltVtx;
209  // TODO: reserve some space to avoid too many allocations
210  // TODO: keep vertex mem allocated between draw invocations
211 
212  float cgox = cgo.X - cgo.TargetX, cgoy = cgo.Y - cgo.TargetY;
213  // First pass: draw simple PXS (lines/pixels)
214  for (size_t i = 0; i < Count; i++)
215  {
216  C4PXS *pxp = &PXS[i];
217  if (pxp->Mat != MNone && VisibleRect.Contains(fixtoi(pxp->x), fixtoi(pxp->y)))
218  {
219  C4Material *pMat = &::MaterialMap.Map[pxp->Mat];
220  const DWORD dwMatClr = ::Landscape.GetPal()->GetClr((BYTE) (Mat2PixColDefault(pxp->Mat)));
221  if(pMat->PXSFace.Surface)
222  {
223  int32_t pnx, pny;
224  pMat->PXSFace.GetPhaseNum(pnx, pny);
225  int32_t fcWdt = pMat->PXSFace.Wdt;
226  int32_t fcHgt = pMat->PXSFace.Hgt;
227  // calculate draw width and tile to use (random-ish)
228  uint32_t size = (1103515245 * i + 12345) >> 3;
229  float z = pMat->PXSGfxSize * (0.625f + 0.05f * int(size % 16));
230  pny = (i / pnx) % pny; pnx = i % pnx;
231 
232  const float w = z;
233  const float h = z * fcHgt / fcWdt;
234  const float x1 = fixtof(pxp->x) + cgox + z * pMat->PXSGfxRt.tx / fcWdt;
235  const float y1 = fixtof(pxp->y) + cgoy + z * pMat->PXSGfxRt.ty / fcHgt;
236  const float x2 = x1 + w;
237  const float y2 = y1 + h;
238 
239  const float sfcWdt = pMat->PXSFace.Surface->Wdt;
240  const float sfcHgt = pMat->PXSFace.Surface->Hgt;
241 
242  C4BltVertex vtx[6];
243  vtx[0].tx = (pnx + 0.f) * fcWdt / sfcWdt; vtx[0].ty = (pny + 0.f) * fcHgt / sfcHgt;
244  vtx[0].ftx = x1; vtx[0].fty = y1;
245  vtx[1].tx = (pnx + 1.f) * fcWdt / sfcWdt; vtx[1].ty = (pny + 0.f) * fcHgt / sfcHgt;
246  vtx[1].ftx = x2; vtx[1].fty = y1;
247  vtx[2].tx = (pnx + 1.f) * fcWdt / sfcWdt; vtx[2].ty = (pny + 1.f) * fcHgt / sfcHgt;
248  vtx[2].ftx = x2; vtx[2].fty = y2;
249  vtx[3].tx = (pnx + 0.f) * fcWdt / sfcWdt; vtx[3].ty = (pny + 1.f) * fcHgt / sfcHgt;
250  vtx[3].ftx = x1; vtx[3].fty = y2;
251  DwTo4UB(0xFFFFFFFF, vtx[0].color);
252  DwTo4UB(0xFFFFFFFF, vtx[1].color);
253  DwTo4UB(0xFFFFFFFF, vtx[2].color);
254  DwTo4UB(0xFFFFFFFF, vtx[3].color);
255  vtx[4] = vtx[2];
256  vtx[5] = vtx[0];
257 
258  std::vector<C4BltVertex>& vec = bltVtx[pxp->Mat];
259  vec.push_back(vtx[0]);
260  vec.push_back(vtx[1]);
261  vec.push_back(vtx[2]);
262  vec.push_back(vtx[3]);
263  vec.push_back(vtx[4]);
264  vec.push_back(vtx[5]);
265  }
266  else
267  {
268  // old-style: unicolored pixels or lines
269  if (fixtoi(pxp->xdir) || fixtoi(pxp->ydir))
270  {
271  // lines for stuff that goes whooosh!
272  int len = fixtoi(Abs(pxp->xdir) + Abs(pxp->ydir));
273  const DWORD dwMatClrLen = uint32_t(std::max<int>(dwMatClr >> 24, 195 - (195 - (dwMatClr >> 24)) / len)) << 24 | (dwMatClr & 0xffffff);
274  C4BltVertex begin, end;
275  begin.ftx = fixtof(pxp->x - pxp->xdir) + cgox; begin.fty = fixtof(pxp->y - pxp->ydir) + cgoy;
276  end.ftx = fixtof(pxp->x) + cgox; end.fty = fixtof(pxp->y) + cgoy;
277  DwTo4UB(dwMatClrLen, begin.color);
278  DwTo4UB(dwMatClrLen, end.color);
279  lineVtx.push_back(begin);
280  lineVtx.push_back(end);
281  }
282  else
283  {
284  // single pixels for slow stuff
285  C4BltVertex vtx;
286  vtx.ftx = fixtof(pxp->x) + cgox;
287  vtx.fty = fixtof(pxp->y) + cgoy;
288  DwTo4UB(dwMatClr, vtx.color);
289  pixVtx.push_back(vtx);
290  }
291  }
292  }
293  }
294 
295  if(!pixVtx.empty()) pDraw->PerformMultiPix(cgo.Surface, &pixVtx[0], pixVtx.size(), nullptr);
296  if(!lineVtx.empty()) pDraw->PerformMultiLines(cgo.Surface, &lineVtx[0], lineVtx.size(), 1.0f, nullptr);
297 
298  // PXS graphics disabled?
299  if (!Config.Graphics.PXSGfx)
300  return;
301 
302  for(std::map<int, std::vector<C4BltVertex> >::const_iterator iter = bltVtx.begin(); iter != bltVtx.end(); ++iter)
303  {
304  C4Material *pMat = &::MaterialMap.Map[iter->first];
305  pDraw->PerformMultiTris(cgo.Surface, &iter->second[0], iter->second.size(), nullptr, pMat->PXSFace.Surface->texture.get(), nullptr, nullptr, 0, nullptr);
306  }
307 }
308 
309 void C4PXSSystem::Cast(int32_t mat, int32_t num, int32_t tx, int32_t ty, int32_t level)
310 {
311  int32_t cnt;
312  for (cnt=0; cnt<num; cnt++)
313  {
314  // Must do these calculation steps separately, because the order of
315  // invokations of Random() is not defined if they're used as parameters
316  C4Real xdir = itofix(Random(level+1)-level/2); xdir/=10;
317  C4Real ydir = itofix(Random(level+1)-level); ydir/=10;
318  Create(mat,
319  itofix(tx),itofix(ty),
320  xdir,
321  ydir);
322  }
323 }
324 
326 {
327  if (Count == 0)
328  {
329  hGroup.Delete(C4CFN_PXS);
330  return true;
331  }
332 
333  // Save chunks to temp file
334  CStdFile hTempFile;
335  if (!hTempFile.Create(Config.AtTempPath(C4CFN_TempPXS)))
336  return false;
337 #ifdef C4REAL_USE_FIXNUM
338  int32_t iNumFormat = 1;
339 #else
340  int32_t iNumFormat = 2;
341 #endif
342  if (!hTempFile.Write(&iNumFormat, sizeof (iNumFormat)))
343  return false;
344  if (!hTempFile.Write(PXS, Count * sizeof(C4PXS)))
345  return false;
346 
347  if (!hTempFile.Close())
348  return false;
349 
350  // Move temp file to group
351  if (!hGroup.Move( Config.AtTempPath(C4CFN_TempPXS),
352  C4CFN_PXS ))
353  return false;
354 
355  return true;
356 }
357 
359 {
360  // load new
361  size_t iBinSize, PXSNum;
362  if (!hGroup.AccessEntry(C4CFN_PXS,&iBinSize)) return false;
363  // clear previous
364  Clear();
365  // using C4Real or float?
366  int32_t iNumForm = 1;
367  if (iBinSize % sizeof(C4PXS) == 4)
368  {
369  if (!hGroup.Read(&iNumForm, sizeof (iNumForm))) return false;
370  if (!Inside<int32_t>(iNumForm, 1, 2)) return false;
371  iBinSize -= 4;
372  }
373  // old pxs-files have no tag for the number format
374  else if (iBinSize % sizeof(C4PXS) != 0) return false;
375  // calc chunk count
376  PXSNum = iBinSize / sizeof(C4PXS);
377  if (PXSNum > PXSMax) return false;
378  if (!hGroup.Read(PXS, iBinSize)) return false;
379  // count the PXS, Peter!
380  Count = PXSNum;
381  // convert num format, if neccessary
382  for (size_t i = 0; i < Count; i++)
383  {
384  C4PXS *pxp = &PXS[i];
385  if (pxp->Mat != MNone)
386  {
387  // convert number format
388 #ifdef C4REAL_USE_FIXNUM
389  if (iNumForm == 2) { FLOAT_TO_FIXED(&pxp->x); FLOAT_TO_FIXED(&pxp->y); FLOAT_TO_FIXED(&pxp->xdir); FLOAT_TO_FIXED(&pxp->ydir); }
390 #else
391  if (iNumForm == 1) { FIXED_TO_FLOAT(&pxp->x); FIXED_TO_FLOAT(&pxp->y); FIXED_TO_FLOAT(&pxp->xdir); FIXED_TO_FLOAT(&pxp->ydir); }
392 #endif
393  }
394  }
395  return true;
396 }
397 
398 int32_t C4PXSSystem::GetCount(int32_t mat) const
399 {
400  // count PXS of given material
401  int32_t result = 0;
402  for (size_t i = 0; i < Count; i++)
403  {
404  if (PXS[i].Mat == mat) ++result;
405  }
406  return result;
407 }
408 
409 int32_t C4PXSSystem::GetCount(int32_t mat, int32_t x, int32_t y, int32_t wdt, int32_t hgt) const
410 {
411  // count PXS of given material in given area
412  int32_t result = 0;
413  for (size_t i = 0; i < Count; i++)
414  {
415  const C4PXS *pxp = &PXS[i];
416  if (pxp->Mat == mat || mat == MNone)
417  if (Inside(pxp->x, x, x + wdt - 1) && Inside(pxp->y, y, y + hgt - 1))
418  ++result;
419  }
420  return result;
421 }
422 
#define C4CFN_PXS
Definition: C4Components.h:75
#define C4CFN_TempPXS
Definition: C4Components.h:158
C4Config Config
Definition: C4Config.cpp:930
const int32_t MNone
Definition: C4Constants.h:177
C4Draw * pDraw
Definition: C4Draw.cpp:42
unsigned char color[4]
Definition: C4Draw.h:63
float tx
Definition: C4Draw.h:62
float ftx
Definition: C4Draw.h:64
void DwTo4UB(DWORD dwClr, unsigned char(&r)[4])
Definition: C4Draw.h:29
float ty
Definition: C4Draw.h:62
float fty
Definition: C4Draw.h:64
constexpr bool DEBUGREC_PXS
Definition: C4Include.h:32
C4Landscape Landscape
int32_t GBackMat(int32_t x, int32_t y)
Definition: C4Landscape.h:219
int32_t GBackDensity(int32_t x, int32_t y)
Definition: C4Landscape.h:224
#define z
C4MaterialMap MaterialMap
Definition: C4Material.cpp:974
bool MatValid(int32_t mat)
Definition: C4Material.h:210
BYTE Mat2PixColDefault(int32_t mat)
Definition: C4Material.h:235
@ meePXSPos
Definition: C4Material.h:36
@ meePXSMove
Definition: C4Material.h:37
C4PXSSystem PXS
Definition: C4PXS.cpp:423
const size_t PXSMax
Definition: C4PXS.h:36
#define GravAccel
Definition: C4Physics.h:27
uint32_t Random()
Definition: C4Random.cpp:43
float fixtof(const C4Fixed &x)
Definition: C4Real.h:257
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
void FLOAT_TO_FIXED(C4Real *pVal)
Definition: C4Real.h:318
C4Real C4REAL256(int x)
Definition: C4Real.h:268
void AddDbgRec(C4RecordChunkType eType, const void *pData, int iSize)
Definition: C4Record.cpp:32
int32_t pos
Definition: C4Record.h:175
@ RCT_ExecPXS
Definition: C4Record.h:67
int32_t iMat
Definition: C4Record.h:173
C4Real y
Definition: C4Record.h:171
C4Real x
Definition: C4Record.h:171
C4Weather Weather
Definition: C4Weather.cpp:206
uint8_t BYTE
uint32_t DWORD
int Sign(T val)
Definition: Standard.h:45
T Abs(T val)
Definition: Standard.h:42
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
int32_t DebugRec
Definition: C4Config.h:63
int32_t PXSGfx
Definition: C4Config.h:110
C4ConfigGeneral General
Definition: C4Config.h:255
const char * AtTempPath(const char *filename)
Definition: C4Config.cpp:600
C4ConfigGraphics Graphics
Definition: C4Config.h:257
virtual void PerformMultiLines(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, float width, C4ShaderCall *shader_call)=0
virtual void PerformMultiTris(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, const C4BltTransform *pTransform, C4TexRef *pTex, C4TexRef *pOverlay, C4TexRef *pNormal, DWORD dwOverlayClrMod, C4ShaderCall *shader_call)=0
virtual void PerformMultiPix(C4Surface *sfcTarget, const C4BltVertex *vertices, unsigned int n_vertices, C4ShaderCall *shader_call)=0
C4Surface * Surface
Definition: C4Facet.h:117
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
bool GetPhaseNum(int32_t &rX, int32_t &rY)
Definition: C4Facet.cpp:472
float Y
Definition: C4Facet.h:118
float X
Definition: C4Facet.h:118
Definition: C4Real.h:59
bool Read(void *buffer, size_t size) override
Definition: C4Group.cpp:1430
bool AccessEntry(const char *wildcard, size_t *size=nullptr, char *filename=nullptr, bool needs_to_be_a_group=false)
Definition: C4Group.cpp:2104
bool Move(const char *filename, const char *entry_name)
Definition: C4Group.cpp:1633
bool Delete(const char *files, bool recursive=false)
Definition: C4Group.cpp:1645
int32_t GetWidth() const
CStdPalette * GetPal() const
int32_t GetHeight() const
bool _PathFree(int32_t x, int32_t y, int32_t x2, int32_t y2) const
C4TargetRect PXSGfxRt
Definition: C4Material.h:117
int32_t WindDrift
Definition: C4Material.h:105
int32_t Density
Definition: C4Material.h:92
int32_t PXSGfxSize
Definition: C4Material.h:118
C4Facet PXSFace
Definition: C4Material.h:157
C4MaterialReaction * GetReactionUnsafe(int32_t iPXSMat, int32_t iLandscapeMat)
Definition: C4Material.h:191
C4Material * Map
Definition: C4Material.h:169
Definition: C4PXS.h:26
C4Real ydir
Definition: C4PXS.h:30
bool Execute()
Definition: C4PXS.cpp:33
C4Real xdir
Definition: C4PXS.h:30
void Deactivate()
Definition: C4PXS.cpp:136
int32_t Mat
Definition: C4PXS.h:29
C4Real y
Definition: C4PXS.h:30
C4Real x
Definition: C4PXS.h:30
~C4PXSSystem()
Definition: C4PXS.cpp:153
int32_t GetCount() const
Definition: C4PXS.h:56
void Cast(int32_t mat, int32_t num, int32_t tx, int32_t ty, int32_t level)
Definition: C4PXS.cpp:309
C4PXS PXS[PXSMax]
Definition: C4PXS.h:46
C4PXS * New()
Definition: C4PXS.cpp:168
bool Save(C4Group &hGroup)
Definition: C4PXS.cpp:325
bool Load(C4Group &hGroup)
Definition: C4PXS.cpp:358
void Execute()
Definition: C4PXS.cpp:186
void Default()
Definition: C4PXS.cpp:158
void Clear()
Definition: C4PXS.cpp:163
bool Create(int32_t mat, C4Real ix, C4Real iy, C4Real ixdir=Fix0, C4Real iydir=Fix0)
Definition: C4PXS.cpp:175
void Draw(C4TargetFacet &cgo)
Definition: C4PXS.cpp:198
size_t Count
Definition: C4PXS.h:44
C4PXSSystem()
Definition: C4PXS.cpp:148
Definition: C4Rect.h:28
void Enlarge(int32_t iByX, int32_t iByY)
Definition: C4Rect.h:51
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:40
int Wdt
Definition: C4Surface.h:65
std::unique_ptr< C4TexRef > texture
Definition: C4Surface.h:78
int Hgt
Definition: C4Surface.h:65
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
int32_t tx
Definition: C4Rect.h:79
int32_t ty
Definition: C4Rect.h:79
int32_t GetWind(int32_t x, int32_t y)
Definition: C4Weather.cpp:94
bool Close(StdBuf **ppMemory=nullptr)
Definition: CStdFile.cpp:151
bool Create(const char *szFileName, bool fCompressed=false, bool fExecutable=false, bool fMemory=false)
Definition: CStdFile.cpp:49
bool Write(const void *pBuffer, int iSize)
Definition: CStdFile.cpp:240
C4MaterialReactionFunc pFunc
Definition: C4Material.h:47
DWORD GetClr(BYTE byCol)
Definition: StdColors.h:188