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