OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Sector.cpp
Go to the documentation of this file.
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 // landscape sector base class
17 
18 #include "C4Include.h"
19 #include "object/C4Sector.h"
20 
21 #include "game/C4Game.h"
22 #include "object/C4Object.h"
23 #include "lib/C4Log.h"
24 #include "control/C4Record.h"
25 #include "object/C4GameObjects.h"
26 
27 /* sector */
28 
29 void C4LSector::Init(int ix, int iy)
30 {
31  // clear any previous initialization
32  Clear();
33  // store class members
34  x=ix; y=iy;
35 }
36 
38 {
39  // clear objects
40  ClearObjects();
41 }
42 
44 {
45  pComp->Value(mkNamingAdapt(mkIntAdapt(x), "x"));
46  pComp->Value(mkNamingAdapt(mkIntAdapt(y), "y"));
47  pComp->Value(mkNamingAdapt(mkParAdapt(Objects, numbers), "Objects"));
48  pComp->Value(mkNamingAdapt(mkParAdapt(ObjectShapes, numbers), "ObjectShapes"));
49 }
50 
52 {
53  // clear objects
54  Objects.Clear();
56 }
57 
58 /* sector map */
59 
60 void C4LSectors::Init(int iWdt, int iHgt)
61 {
62  // clear any previous initialization
63  Clear();
64  // store class members, calc size
65  Wdt = ((PxWdt=iWdt)-1)/C4LSectorWdt+1;
66  Hgt = ((PxHgt=iHgt)-1)/C4LSectorHgt+1;
67  // create sectors
68  Sectors = new C4LSector[Size=Wdt*Hgt];
69  // init sectors
70  C4LSector *sct=Sectors;
71  for (int cnt=0; cnt<Size; cnt++, sct++)
72  sct->Init(cnt%Wdt, cnt/Wdt);
73  SectorOut.Init(-1,-1); // outpos at -1,-1 - MUST NOT intersect with an inside sector!
74 }
75 
77 {
78  // clear out-sector
79  SectorOut.Clear();
80  // free sectors
81  delete [] Sectors; Sectors=nullptr;
82 }
83 
85 {
86  // check bounds
87  if (ix<0 || iy<0 || ix>=PxWdt || iy>=PxHgt)
88  return &SectorOut;
89  // get sector
90  return Sectors+(iy/C4LSectorHgt)*Wdt+(ix/C4LSectorWdt);
91 }
92 
93 void C4LSectors::Add(C4Object *pObj, C4ObjectList *pMainList)
94 {
95  assert(Sectors);
96  // Add to owning sector
97  C4LSector *pSct = SectorAt(pObj->GetX(), pObj->GetY());
98  pSct->Objects.Add(pObj, C4ObjectList::stMain, pMainList);
99  // Save position
100  pObj->old_x = pObj->GetX(); pObj->old_y = pObj->GetY();
101  // Add to all sectors in shape area
102  pObj->Area.Set(this, pObj);
103  for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct))
104  {
105  pSct->ObjectShapes.Add(pObj, C4ObjectList::stMain, pMainList);
106  }
107  if (Config.General.DebugRec)
108  pObj->Area.DebugRec(pObj, 'A');
109 }
110 
111 void C4LSectors::Update(C4Object *pObj, C4ObjectList *pMainList)
112 {
113  assert(Sectors);
114  // Not added yet?
115  if (pObj->Area.IsNull())
116  {
117  Add(pObj, pMainList);
118  return;
119  }
120  C4LSector *pOld, *pNew;
121  if (pObj->old_x != pObj->GetX() || pObj->old_y != pObj->GetY())
122  {
123  // Get involved sectors
124  pOld = SectorAt(pObj->old_x, pObj->old_y);
125  pNew = SectorAt(pObj->GetX(), pObj->GetY());
126  if (pOld != pNew)
127  {
128  pOld->Objects.Remove(pObj);
129  pNew->Objects.Add(pObj, C4ObjectList::stMain, pMainList);
130  }
131  // Save position
132  pObj->old_x = pObj->GetX(); pObj->old_y = pObj->GetY();
133  }
134  // New area
135  C4LArea NewArea(this, pObj);
136  if (pObj->Area == NewArea) return;
137  // Remove from all old sectors in shape area
138  for (pOld = pObj->Area.First(); pOld; pOld = pObj->Area.Next(pOld))
139  if (!NewArea.Contains(pOld))
140  pOld->ObjectShapes.Remove(pObj);
141  // Add to all new sectors in shape area
142  for (pNew = NewArea.First(); pNew; pNew = NewArea.Next(pNew))
143  if (!pObj->Area.Contains(pNew))
144  {
145  pNew->ObjectShapes.Add(pObj, C4ObjectList::stMain, pMainList);
146  }
147  // Update area
148  pObj->Area = NewArea;
149  if (Config.General.DebugRec)
150  pObj->Area.DebugRec(pObj, 'U');
151 }
152 
154 {
155  assert(Sectors); assert(pObj);
156  // Remove from owning sector
157  C4LSector *pSct = SectorAt(pObj->old_x, pObj->old_y);
158  if (!pSct->Objects.Remove(pObj))
159  {
160 #ifdef _DEBUG
161  LogF("WARNING: Object %d of type %s deleted but not found in pos sector list!", pObj->Number, pObj->id.ToString());
162 #endif
163  // if it was not found in owning sector, it must be somewhere else. yeah...
164  bool fFound = false;
165  for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct))
166  if (pSct->Objects.Remove(pObj)) { fFound=true; break; }
167  // yukh, somewhere else entirely...
168  if (!fFound)
169  {
170  fFound = !!SectorOut.Objects.Remove(pObj);
171  if (!fFound)
172  {
173  pSct = Sectors;
174  for (int cnt=0; cnt<Size; cnt++, pSct++)
175  if (pSct->Objects.Remove(pObj)) { fFound=true; break; }
176  }
177  assert(fFound);
178  }
179  }
180  // Remove from all sectors in shape area
181  for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct))
182  pSct->ObjectShapes.Remove(pObj);
183  if (Config.General.DebugRec)
184  pObj->Area.DebugRec(pObj, 'R');
185 }
186 
188 {
189 #ifndef NDEBUG
190  C4LSector *sct=Sectors;
191  for (int cnt=0; cnt<Size; cnt++, sct++)
192  {
193  assert(!sct->Objects.IsContained(pObj));
194  assert(!sct->ObjectShapes.IsContained(pObj));
195  }
196  assert(!SectorOut.Objects.IsContained(pObj));
197  assert(!SectorOut.ObjectShapes.IsContained(pObj));
198 #endif
199 }
200 
202 {
203  int iSum = 0;
204  for (int cnt=0; cnt<Size; cnt++)
205  iSum += Sectors[cnt].ObjectShapes.ObjectCount();
206  return iSum;
207 }
208 
210 {
211  C4ValueNumbers numbers;
212  LogSilent(DecompileToBuf<StdCompilerINIWrite>(
215  "Sector")).getData());
216 }
217 
219 {
220  for (int cnt=0; cnt<Size; cnt++)
221  if (!Sectors[cnt].Objects.CheckSort(&::Objects))
222  return false;
223  if (!SectorOut.Objects.CheckSort(&::Objects)) return false;
224  return true;
225 }
226 
228 {
229  if (Sectors)
230  {
231  for (int cnt=0; cnt<Size; cnt++) Sectors[cnt].ClearObjects();
232  }
234 }
235 
236 /* landscape area */
237 
238 bool C4LArea::operator == (const C4LArea &Area) const
239 {
240  return pFirst == Area.pFirst &&
241  xL == Area.xL &&
242  yL == Area.yL &&
243  pOut == Area.pOut;
244 }
245 
246 void C4LArea::Set(C4LSectors *pSectors, const C4Rect &Rect)
247 {
248  // default: no area
249  pFirst=nullptr; pOut=nullptr;
250  // check bounds
251  C4Rect ClippedRect(Rect),
252  Bounds(0, 0, pSectors->PxWdt, pSectors->PxHgt);
253  ClippedRect.Normalize();
254  if (!Bounds.Contains(ClippedRect))
255  {
256  ClippedRect.Intersect(Bounds);
257  pOut = &pSectors->SectorOut;
258  }
259  // calc first sector
260  pFirst = pSectors->SectorAt(ClippedRect.x, ClippedRect.y);
261  // assert the rect isn't degenerated for the following calculations
262  // (note this will associate areas that are above landscape bounds with sectors inside)
263  if (!ClippedRect.Wdt) ClippedRect.Wdt = 1;
264  if (!ClippedRect.Hgt) ClippedRect.Hgt = 1;
265  // calc bounds
266  xL = (ClippedRect.x + ClippedRect.Wdt - 1) / C4LSectorWdt;
267  yL = (ClippedRect.y + ClippedRect.Hgt - 1) / C4LSectorHgt;
268  // calc pitch
269  dpitch = pSectors->Wdt - (ClippedRect.x + ClippedRect.Wdt - 1) / C4LSectorWdt + ClippedRect.x / C4LSectorWdt;
270 }
271 
272 void C4LArea::Set(C4LSectors *pSectors, C4Object *pObj)
273 {
274  // set to object facet rect
275  Set(pSectors, C4Rect(pObj->Left(), pObj->Top(), pObj->Width(), pObj->Height()));
276 }
277 
279 {
280  // the outside-sector is the last sector that is returned
281  if (pPrev == pOut)
282  return nullptr;
283  // within one line?
284  if (pPrev->x<xL)
285  return pPrev+1;
286  // within the area?
287  if (pPrev->y<yL)
288  return pPrev+dpitch;
289  // end reached - return outside-sector if applicable
290  return pOut;
291 }
292 
293 bool C4LArea::Contains(C4LSector *pSct) const
294 {
295  assert(pSct);
296  // no area
297  if (!pFirst) return false;
298  // outside?
299  if (pSct == pOut) return true;
300  if (pFirst == pOut) return false;
301  // check bounds
302  return (pSct->x>=pFirst->x && pSct->y>=pFirst->y && pSct->x<=xL && pSct->y<=yL);
303 }
304 
306 {
307  // get next sector
308  if (!*ppSct)
309  *ppSct = First();
310  else
311  *ppSct = Next(*ppSct);
312  // nothing left?
313  if (!*ppSct)
314  return nullptr;
315  // return object list
316  return &(*ppSct)->Objects;
317 }
318 
320 {
321  // get next sector
322  if (!*ppSct)
323  *ppSct = First();
324  else
325  *ppSct = Next(*ppSct);
326  // nothing left?
327  if (!*ppSct)
328  return nullptr;
329  // return object list
330  return &(*ppSct)->ObjectShapes;
331 }
332 
333 void C4LArea::DebugRec(class C4Object *pObj, char cMarker)
334 {
335  C4RCArea rc;
336  rc.op = cMarker;
337  rc.obj = pObj ? pObj->Number : -1;
338  rc.x1 = pFirst ? pFirst->x : -1;
339  rc.y1 = pFirst ? pFirst->x /* 2do: y */ : -1;
340  rc.xL = xL;
341  rc.yL = yL;
342  rc.dpitch = dpitch;
343  rc.out = !!pOut;
344  AddDbgRec(RCT_Area, &rc, sizeof(C4RCArea));
345 }
int32_t Height() const
Definition: C4Object.h:285
int32_t GetY() const
Definition: C4Object.h:287
bool Contains(C4LSector *pSct) const
Definition: C4Sector.cpp:293
C4LSector SectorOut
Definition: C4Sector.h:65
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:42
int32_t Left() const
Definition: C4Object.h:282
C4Config Config
Definition: C4Config.cpp:837
C4LArea Area
Definition: C4Object.h:114
C4ID id
Definition: C4Object.h:108
bool LogSilent(const char *szMessage, bool fConsole)
Definition: C4Log.cpp:117
virtual bool Add(C4Object *nObj, SortType eSort, C4ObjectList *pLstSorted=nullptr)
C4ObjectList Objects
Definition: C4Sector.h:48
C4LSector * First() const
Definition: C4Sector.h:111
int32_t xL
Definition: C4Record.h:204
int Wdt
Definition: C4Sector.h:63
bool IsNull() const
Definition: C4Sector.h:106
int Hgt
Definition: C4Sector.h:63
int32_t y1
Definition: C4Record.h:204
C4ConfigGeneral General
Definition: C4Config.h:252
bool CheckSort()
Definition: C4Sector.cpp:218
void Add(C4Object *pObj, C4ObjectList *pMainList)
Definition: C4Sector.cpp:93
C4LSector * SectorAt(int ix, int iy)
Definition: C4Sector.cpp:84
int32_t old_y
Definition: C4Object.h:114
Definition: C4Rect.h:29
void DebugRec(class C4Object *pObj, char cMarker)
Definition: C4Sector.cpp:333
StdParameterAdaptMaker< P > mkParAdaptMaker(P &&rPar)
Definition: StdAdaptors.h:472
void Dump()
Definition: C4Sector.cpp:209
int PxHgt
Definition: C4Sector.h:62
int y
Definition: C4Sector.h:46
C4ObjectList * NextObjectShapes(C4ObjectList *pPrev, C4LSector **ppSct)
Definition: C4Sector.cpp:319
bool out
Definition: C4Record.h:205
int xL
Definition: C4Sector.h:90
void Clear()
Definition: C4Sector.cpp:76
int32_t old_x
Definition: C4Object.h:114
C4LSector * Next(C4LSector *pPrev) const
Definition: C4Sector.cpp:278
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:93
const int32_t C4LSectorWdt
Definition: C4Sector.h:31
void AssertObjectNotInList(C4Object *pObj)
Definition: C4Sector.cpp:187
void Init(int Wdt, int Hgt)
Definition: C4Sector.cpp:60
void ClearObjects()
Definition: C4Sector.cpp:51
int32_t Top() const
Definition: C4Object.h:283
int dpitch
Definition: C4Sector.h:90
C4LSector * pOut
Definition: C4Sector.h:91
bool operator==(const C4LArea &Area) const
Definition: C4Sector.cpp:238
char op
Definition: C4Record.h:202
void Update(C4Object *pObj, C4ObjectList *pMainList)
Definition: C4Sector.cpp:111
int32_t GetX() const
Definition: C4Object.h:286
void AddDbgRec(C4RecordChunkType eType, const void *pData, int iSize)
Definition: C4Record.cpp:36
const int32_t C4LSectorHgt
Definition: C4Sector.h:32
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *numbers)
Definition: C4Sector.cpp:43
void Value(const T &rStruct)
Definition: StdCompiler.h:171
C4ObjectList ObjectShapes
Definition: C4Sector.h:49
int32_t yL
Definition: C4Record.h:204
C4LSector * Sectors
Definition: C4Sector.h:61
int32_t Width() const
Definition: C4Object.h:284
void Init(int ix, int iy)
Definition: C4Sector.cpp:29
void ClearObjects()
Definition: C4Sector.cpp:227
const char * ToString() const
Definition: C4Id.h:62
int32_t dpitch
Definition: C4Record.h:204
C4LSector * pFirst
Definition: C4Sector.h:89
void Set(C4LSectors *pSectors, const C4Rect &rect)
Definition: C4Sector.cpp:246
bool IsContained(const C4Object *pObj) const
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:459
int32_t DebugRec
Definition: C4Config.h:61
int yL
Definition: C4Sector.h:90
int Size
Definition: C4Sector.h:63
virtual void Clear()
void Remove(C4Object *pObj)
Definition: C4Sector.cpp:153
StdArrayAdapt< T, M > mkArrayAdaptMap(T *pArray, int iSize, M &&map)
Definition: StdAdaptors.h:314
int getShapeSum() const
Definition: C4Sector.cpp:201
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
bool CheckSort(C4ObjectList *pList)
void Clear()
Definition: C4Sector.cpp:37
int x
Definition: C4Sector.h:46
C4ObjectList * NextObjects(C4ObjectList *pPrev, C4LSector **ppSct)
Definition: C4Sector.cpp:305
int32_t obj
Definition: C4Record.h:203
int PxWdt
Definition: C4Sector.h:62
virtual bool Remove(C4Object *pObj)
C4GameObjects Objects
Definition: C4Globals.cpp:48
StdIntAdapt< T > mkIntAdapt(T &rValue)
Definition: StdAdaptors.h:230
int32_t x1
Definition: C4Record.h:204