/* * OpenClonk, http://www.openclonk.org * * Copyright (c) 2001, 2006-2009 Sven Eberhardt * Copyright (c) 2005, 2008, 2011 Günther Brammer * Copyright (c) 2006 Peter Wortmann * Copyright (c) 2009 Nicolas Hake * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de * * Portions might be copyrighted by other authors who have contributed * to OpenClonk. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * See isc_license.txt for full license and disclaimer. * * "Clonk" is a registered trademark of Matthes Bender. * See clonk_trademark_license.txt for full license. */ // landscape sector base class #include #include #include #include #include #include #include /* sector */ void C4LSector::Init(int ix, int iy) { // clear any previous initialization Clear(); // store class members x=ix; y=iy; } void C4LSector::Clear() { // clear objects ClearObjects(); } void C4LSector::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers) { pComp->Value(mkNamingAdapt(mkIntAdapt(x), "x")); pComp->Value(mkNamingAdapt(mkIntAdapt(y), "y")); pComp->Value(mkNamingAdapt(mkParAdapt(Objects, numbers), "Objects")); pComp->Value(mkNamingAdapt(mkParAdapt(ObjectShapes, numbers), "ObjectShapes")); } void C4LSector::ClearObjects() { // clear objects Objects.Clear(); ObjectShapes.Clear(); } /* sector map */ void C4LSectors::Init(int iWdt, int iHgt) { // clear any previous initialization Clear(); // store class members, calc size Wdt = ((PxWdt=iWdt)-1)/C4LSectorWdt+1; Hgt = ((PxHgt=iHgt)-1)/C4LSectorHgt+1; // create sectors Sectors = new C4LSector[Size=Wdt*Hgt]; // init sectors C4LSector *sct=Sectors; for (int cnt=0; cntInit(cnt%Wdt, cnt/Wdt); SectorOut.Init(-1,-1); // outpos at -1,-1 - MUST NOT intersect with an inside sector! } void C4LSectors::Clear() { // clear out-sector SectorOut.Clear(); // free sectors delete [] Sectors; Sectors=NULL; } C4LSector *C4LSectors::SectorAt(int ix, int iy) { // check bounds if (ix<0 || iy<0 || ix>=PxWdt || iy>=PxHgt) return &SectorOut; // get sector return Sectors+(iy/C4LSectorHgt)*Wdt+(ix/C4LSectorWdt); } void C4LSectors::Add(C4Object *pObj, C4ObjectList *pMainList) { assert(Sectors); // Add to owning sector C4LSector *pSct = SectorAt(pObj->GetX(), pObj->GetY()); pSct->Objects.Add(pObj, C4ObjectList::stMain, pMainList); // Save position pObj->old_x = pObj->GetX(); pObj->old_y = pObj->GetY(); // Add to all sectors in shape area pObj->Area.Set(this, pObj); for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct)) { pSct->ObjectShapes.Add(pObj, C4ObjectList::stMain, pMainList); } if (Config.General.DebugRec) pObj->Area.DebugRec(pObj, 'A'); } void C4LSectors::Update(C4Object *pObj, C4ObjectList *pMainList) { assert(Sectors); // Not added yet? if (pObj->Area.IsNull()) { Add(pObj, pMainList); return; } C4LSector *pOld, *pNew; if (pObj->old_x != pObj->GetX() || pObj->old_y != pObj->GetY()) { // Get involved sectors pOld = SectorAt(pObj->old_x, pObj->old_y); pNew = SectorAt(pObj->GetX(), pObj->GetY()); if (pOld != pNew) { pOld->Objects.Remove(pObj); pNew->Objects.Add(pObj, C4ObjectList::stMain, pMainList); } // Save position pObj->old_x = pObj->GetX(); pObj->old_y = pObj->GetY(); } // New area C4LArea NewArea(this, pObj); if (pObj->Area == NewArea) return; // Remove from all old sectors in shape area for (pOld = pObj->Area.First(); pOld; pOld = pObj->Area.Next(pOld)) if (!NewArea.Contains(pOld)) pOld->ObjectShapes.Remove(pObj); // Add to all new sectors in shape area for (pNew = NewArea.First(); pNew; pNew = NewArea.Next(pNew)) if (!pObj->Area.Contains(pNew)) { pNew->ObjectShapes.Add(pObj, C4ObjectList::stMain, pMainList); } // Update area pObj->Area = NewArea; if (Config.General.DebugRec) pObj->Area.DebugRec(pObj, 'U'); } void C4LSectors::Remove(C4Object *pObj) { assert(Sectors); assert(pObj); // Remove from owning sector C4LSector *pSct = SectorAt(pObj->old_x, pObj->old_y); if (!pSct->Objects.Remove(pObj)) { #ifdef _DEBUG LogF("WARNING: Object %d of type %s deleted but not found in pos sector list!", pObj->Number, pObj->id.ToString()); #endif // if it was not found in owning sector, it must be somewhere else. yeah... bool fFound = false; for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct)) if (pSct->Objects.Remove(pObj)) { fFound=true; break; } // yukh, somewhere else entirely... if (!fFound) { fFound = !!SectorOut.Objects.Remove(pObj); if (!fFound) { pSct = Sectors; for (int cnt=0; cntObjects.Remove(pObj)) { fFound=true; break; } } assert(fFound); } } // Remove from all sectors in shape area for (pSct = pObj->Area.First(); pSct; pSct = pObj->Area.Next(pSct)) pSct->ObjectShapes.Remove(pObj); if (Config.General.DebugRec) pObj->Area.DebugRec(pObj, 'R'); } void C4LSectors::AssertObjectNotInList(C4Object *pObj) { #ifndef NDEBUG C4LSector *sct=Sectors; for (int cnt=0; cntObjects.IsContained(pObj)); assert(!sct->ObjectShapes.IsContained(pObj)); } assert(!SectorOut.Objects.IsContained(pObj)); assert(!SectorOut.ObjectShapes.IsContained(pObj)); #endif } int C4LSectors::getShapeSum() const { int iSum = 0; for (int cnt=0; cnt( mkNamingAdapt( mkArrayAdaptMap(Sectors, Size, mkParAdaptMaker(&numbers)), "Sector")).getData()); } bool C4LSectors::CheckSort() { for (int cnt=0; cntPxWdt, pSectors->PxHgt); ClippedRect.Normalize(); if (!Bounds.Contains(ClippedRect)) { ClippedRect.Intersect(Bounds); pOut = &pSectors->SectorOut; } // calc first sector pFirst = pSectors->SectorAt(ClippedRect.x, ClippedRect.y); // assert the rect isn't degenerated for the following calculations // (note this will associate areas that are above landscape bounds with sectors inside) if (!ClippedRect.Wdt) ClippedRect.Wdt = 1; if (!ClippedRect.Hgt) ClippedRect.Hgt = 1; // calc bounds xL = (ClippedRect.x + ClippedRect.Wdt - 1) / C4LSectorWdt; yL = (ClippedRect.y + ClippedRect.Hgt - 1) / C4LSectorHgt; // calc pitch dpitch = pSectors->Wdt - (ClippedRect.x + ClippedRect.Wdt - 1) / C4LSectorWdt + ClippedRect.x / C4LSectorWdt; } void C4LArea::Set(C4LSectors *pSectors, C4Object *pObj) { // set to object facet rect Set(pSectors, C4Rect(pObj->Left(), pObj->Top(), pObj->Width(), pObj->Height())); } C4LSector *C4LArea::Next(C4LSector *pPrev) const { // the outside-sector is the last sector that is returned if (pPrev == pOut) return NULL; // within one line? if (pPrev->xyx>=pFirst->x && pSct->y>=pFirst->y && pSct->x<=xL && pSct->y<=yL); } C4ObjectList *C4LArea::NextObjects(C4ObjectList *pPrev, C4LSector **ppSct) { // get next sector if (!*ppSct) *ppSct = First(); else *ppSct = Next(*ppSct); // nothing left? if (!*ppSct) return NULL; // return object list return &(*ppSct)->Objects; } C4ObjectList *C4LArea::NextObjectShapes(C4ObjectList *pPrev, C4LSector **ppSct) { // get next sector if (!*ppSct) *ppSct = First(); else *ppSct = Next(*ppSct); // nothing left? if (!*ppSct) return NULL; // return object list return &(*ppSct)->ObjectShapes; } void C4LArea::DebugRec(class C4Object *pObj, char cMarker) { C4RCArea rc; rc.op = cMarker; rc.obj = pObj ? pObj->Number : -1; rc.x1 = pFirst ? pFirst->x : -1; rc.y1 = pFirst ? pFirst->x /* 2do: y */ : -1; rc.xL = xL; rc.yL = yL; rc.dpitch = dpitch; rc.out = !!pOut; AddDbgRec(RCT_Area, &rc, sizeof(C4RCArea)); }