Ejemplo n.º 1
0
// Recursive implementation of the EPA loop.
// Each recursion adds a point to the convex hull until it's known that we have the closest point on the surface.
static struct ClosestPoints
EPARecurse(const struct SupportContext *ctx, const int count, const struct MinkowskiPoint *hull, const int iteration)
{
    int mini = 0;
    cpFloat minDist = INFINITY;

    // TODO: precalculate this when building the hull and save a step.
    // Find the closest segment hull[i] and hull[i + 1] to (0, 0)
    for(int j=0, i=count-1; j<count; i=j, j++) {
        cpFloat d = ClosestDist(hull[i].ab, hull[j].ab);
        if(d < minDist) {
            minDist = d;
            mini = i;
        }
    }

    struct MinkowskiPoint v0 = hull[mini];
    struct MinkowskiPoint v1 = hull[(mini + 1)%count];
    cpAssertSoft(!cpveql(v0.ab, v1.ab), "Internal Error: EPA vertexes are the same (%d and %d)", mini, (mini + 1)%count);

    // Check if there is a point on the minkowski difference beyond this edge.
    struct MinkowskiPoint p = Support(ctx, cpvperp(cpvsub(v1.ab, v0.ab)));

#if DRAW_EPA
    cpVect verts[count];
    for(int i=0; i<count; i++) verts[i] = hull[i].ab;

    ChipmunkDebugDrawPolygon(count, verts, 0.0, RGBAColor(1, 1, 0, 1), RGBAColor(1, 1, 0, 0.25));
    ChipmunkDebugDrawSegment(v0.ab, v1.ab, RGBAColor(1, 0, 0, 1));

    ChipmunkDebugDrawDot(5, p.ab, LAColor(1, 1));
#endif

    if(CheckArea(cpvsub(v1.ab, v0.ab), cpvadd(cpvsub(p.ab, v0.ab), cpvsub(p.ab, v1.ab))) && iteration < MAX_EPA_ITERATIONS) {
        // Rebuild the convex hull by inserting p.
        struct MinkowskiPoint *hull2 = (struct MinkowskiPoint *)alloca((count + 1)*sizeof(struct MinkowskiPoint));
        int count2 = 1;
        hull2[0] = p;

        for(int i=0; i<count; i++) {
            int index = (mini + 1 + i)%count;

            cpVect h0 = hull2[count2 - 1].ab;
            cpVect h1 = hull[index].ab;
            cpVect h2 = (i + 1 < count ? hull[(index + 1)%count] : p).ab;

            if(CheckArea(cpvsub(h2, h0), cpvadd(cpvsub(h1, h0), cpvsub(h1, h2)))) {
                hull2[count2] = hull[index];
                count2++;
            }
        }

        return EPARecurse(ctx, count2, hull2, iteration + 1);
    } else {
        // Could not find a new point to insert, so we have found the closest edge of the minkowski difference.
        cpAssertWarn(iteration < WARN_EPA_ITERATIONS, "High EPA iterations: %d", iteration);
        return ClosestPointsNew(v0, v1);
    }
}
Ejemplo n.º 2
0
// Recursive implementatino of the GJK loop.
static inline struct ClosestPoints
GJKRecurse(const struct SupportContext *ctx, const struct MinkowskiPoint v0, const struct MinkowskiPoint v1, const int iteration)
{
    if(iteration > MAX_GJK_ITERATIONS) {
        cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK iterations: %d", iteration);
        return ClosestPointsNew(v0, v1);
    }

    cpVect delta = cpvsub(v1.ab, v0.ab);
    if(CheckArea(delta, cpvadd(v0.ab, v1.ab))) {
        // Origin is behind axis. Flip and try again.
        return GJKRecurse(ctx, v1, v0, iteration);
    } else {
        cpFloat t = ClosestT(v0.ab, v1.ab);
        cpVect n = (-1.0f < t && t < 1.0f ? cpvperp(delta) : cpvneg(LerpT(v0.ab, v1.ab, t)));
        struct MinkowskiPoint p = Support(ctx, n);

#if DRAW_GJK
        ChipmunkDebugDrawSegment(v0.ab, v1.ab, RGBAColor(1, 1, 1, 1));
        cpVect c = cpvlerp(v0.ab, v1.ab, 0.5);
        ChipmunkDebugDrawSegment(c, cpvadd(c, cpvmult(cpvnormalize(n), 5.0)), RGBAColor(1, 0, 0, 1));

        ChipmunkDebugDrawDot(5.0, p.ab, LAColor(1, 1));
#endif

        if(
            CheckArea(cpvsub(v1.ab, p.ab), cpvadd(v1.ab, p.ab)) &&
            CheckArea(cpvadd(v0.ab, p.ab), cpvsub(v0.ab, p.ab))
        ) {
            // The triangle v0, p, v1 contains the origin. Use EPA to find the MSA.
            cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK->EPA iterations: %d", iteration);
            return EPA(ctx, v0, p, v1);
        } else {
            if(cpvdot(p.ab, n) <= cpfmax(cpvdot(v0.ab, n), cpvdot(v1.ab, n))) {
                // The edge v0, v1 that we already have is the closest to (0, 0) since p was not closer.
                cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK iterations: %d", iteration);
                return ClosestPointsNew(v0, v1);
            } else {
                // p was closer to the origin than our existing edge.
                // Need to figure out which existing point to drop.
                if(ClosestDist(v0.ab, p.ab) < ClosestDist(p.ab, v1.ab)) {
                    return GJKRecurse(ctx, v0, p, iteration + 1);
                } else {
                    return GJKRecurse(ctx, p, v1, iteration + 1);
                }
            }
        }
    }
}
Ejemplo n.º 3
0
bool Label::onMouseButton(int button, int action) {
	if (CheckArea(mousePosX, mousePosY) && action == 1) {
		textColor = vmath::vec4(0.6f, 0.1f, 0.5f, 1.0f);
		return TRUE;
	} else {
		return FALSE;
	}
}
bool CAreaManager::QueryAreas(EntityId const nEntityID, Vec3 const& rPos, SAreaManagerResult *pResults, int nMaxResults, int& rNumResults)
{
    rNumResults = 0;

    if (pResults)
    {
        // Make sure the area grid is recompiled, if needed, before accessing it
        UpdateDirtyAreas();

        uint32 numAreas = 0;
        TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos));
        TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin());
        TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end());

        for (; IterAreas != IterAreasEnd; ++IterAreas)
        {
            CArea* const pArea = *IterAreas;

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER

            // check if Area is hidden
            IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID());

            if (pAreaEntity && !pAreaEntity->IsHidden())
            {
                Vec3 Closest3d(ZERO);
                float const fGreatestFadeDistance = pArea->GetGreatestFadeDistance();

                // This is optimized internally and might not recalculate but rather retrieve the cached data.
                float const fDistanceSq = pArea->CalcPointNearDistSq(nEntityID, rPos, Closest3d, false);
                bool const bIsPointWithin = (pArea->CalcPosType(nEntityID, rPos, false) == AREA_POS_TYPE_2DINSIDE_ZINSIDE);
                bool const isNear = ((fDistanceSq > 0.0f) && (fDistanceSq < fGreatestFadeDistance*fGreatestFadeDistance));

                if (isNear || bIsPointWithin)
                {
                    // still have room to put it in?
                    if (rNumResults == nMaxResults)
                        return false;

                    // found area that should go into the results
                    pResults[rNumResults].pArea = pArea;
                    pResults[rNumResults].fDistanceSq = fDistanceSq;
                    pResults[rNumResults].vPosOnHull = Closest3d;
                    pResults[rNumResults].bInside = bIsPointWithin;
                    pResults[rNumResults].bNear = isNear;

                    ++rNumResults;
                }
            }
        }

        return true;
    }

    return false;
}
Ejemplo n.º 5
0
/* ---------------------------------------------------------------------------
 */
void cVideoOut::DrawStill_420pl(sPicBuffer *buf)
{
  oldPictureMutex.Lock();

  OsdRefreshCounter=0;
  Osd_changed=0;
  CheckArea(buf->width, buf->height);
  CheckAspect(buf->dtg_active_format,buf->aspect_ratio);
  // display picture
  YUV (buf);
  oldPictureMutex.Unlock();

  ProcessEvents();
}
Ejemplo n.º 6
0
/*
 * ValidArea()
 *
 * This will validate an area choice the system operator has made.
 */
char ValidArea(char *area)
{
    char drive, *work, c;

    MSDOSparse(area, &drive);
    c = fileType(area, drive);

    if (!CheckArea(NO_MENU, c, &drive, area))
	return FALSE;

    work = GetDynamic(strlen(area) + 5);
    sprintf(work, "%c:%s", drive, area);
    strcpy(area, work);
    free(work);
    return TRUE;
}
Ejemplo n.º 7
0
/*
 * goodArea()
 *
 * This will get a valid path from the sysop. Drive should be set already.
 */
static goodArea(MenuId id, char *prompt, char *dir, char *drive)
{
    int  c;
    char dir_x[150], *dft;

    while (TRUE) {
	if (roomBuf.rbflags.ISDIR)
	    dft = FindDirName(thisRoom);
	else
	    dft = ourHomeSpace;

	if (!getXInternal(id, prompt, dir_x, 149, dft, dft))
	    return FALSE;

	MSDOSparse(dir_x, drive);
	c = fileType(dir_x, *drive);

	if (CheckArea(id, c, drive, dir_x)) {
	    strCpy(dir, dir_x);
	    return TRUE;
	}
    }
}
Ejemplo n.º 8
0
int main(int argc, char *argv[])

{
	int ntotal,external;
	NodeList hull, intern, boundary, given;

	HNN=MakeHashTable();
	HEL=MakeHashTable();
	HLI=MakeHashTable();
	NEL=MakeListTable();
	CM=MakeQueueTable();

 	SetOptions(argc,argv);

	ReadFiles(argc,argv);
	/* CheckBoundary(); */

	ntotal = CheckInput();
	hull = MakeNodeList(ntotal);
	intern = MakeNodeList(ntotal);

	printf("Making convex hull... %d\n",hull->count);
	ConvexHull(hull,intern);
/*
	CheckConvex(hull,intern);
	PrintNodeList("hull",hull);
	PrintNodeList("intern",intern);
*/

	printf("Making maxi elements...\n");
	MakeMaxiTriang(hull);
	CheckNeibor(-1);

	printf("Inserting convex hull... %d\n",hull->count);
	InsertBoundaryNodes(hull);
	CheckCircumCircle();
	CheckNeibor(-2);

	WriteAll("M_hull.grd",hull);
	CheckNeibor(-3);

	printf("Inserting internal boundary points... %d\n",intern->count);
	InsertBoundaryNodes(intern);
	CheckCircumCircle();
	CheckNeibor(-4);
	WriteAll("M_orgbound.grd",NULL);

	SetResolution(hull);
	CopyBoundaryLine();

	printf("Recovering boundary lines 1...\n");
	RecoverBoundary();
	CheckCircumCircle();
	CheckNeibor(-43);
	WriteAll("M_bndrecover.grd",NULL);

	printf("Refining boundary points 1...\n");
	boundary = RefineBoundary();

	if( boundary ) {
	    printf("Inserting new boundary points... %d\n",boundary->count);
	    InsertBoundaryNodes(boundary);
	    CheckCircumCircle();
	    CheckCircumCircleProperty();
	    CheckNeibor(-5);
	}

	TestVersion();

	printf("Marking external elements...");
	external=MarkExternalElements( hull );
	printf(" %d / %d\n",external,NTotElems);
	WriteGrd("M_finebound.grd");

/*
	printf("Marking outer elements...");
	external=MarkOuterElements();
	printf(" %d / %d\n",external,NTotElems);
	WriteGrd("M_test.grd");
*/

	FreeNodeList(hull);
	FreeNodeList(intern);
	FreeNodeList(boundary);

	given = GivenNodes();
	printf("Inserting internal given points... %d\n",given->count);
	InsertNodes(given);
	FreeNodeList(given);
	CheckCircumCircle();
	CheckNeibor(-44);
	WriteAll("M_given.grd",NULL);

	printf("Recovering boundary lines 2...\n");
	RecoverBoundary();
	CheckCircumCircle();
	CheckNeibor(-45);
	WriteAll("M_intrecover.grd",NULL);

	CheckArea();
	printf("Inserting internal points...\n");
	InsertInternalNodes();
	CheckCircumCircle();
	CheckCircumCircleProperty();
	WriteGrd("M_insert.grd");

	TestVersion();

	CheckArea();
	printf("Refining internal points... %f\n",OpAspect);
	RefineInternalNodes();
	CheckArea();
	CheckCircumCircle();
	CheckCircumCircleProperty();
	WriteGrd("M_refine.grd");

	CheckArea();
	printf("Recovering boundary lines 3...\n");
	RecoverBoundary();
	printf("Recovering fault lines...\n");
	RecoverInternalFault();
	CheckCircumCircle();
	CheckNeibor(-48);
	WriteAll("M_intrecover2.grd",NULL);

	printf("Marking outer elements...");
	external=MarkOuterElements();
	printf(" %d / %d\n",external,NTotElems);
	printf("Marking outer nodes...");
	external=MarkOuterNodes();
	printf(" %d / %d\n",external,NTotNodes);
	WriteGrd("M_test.grd");

	TestVersion();

	CheckArea();
	printf("Smoothing internal points... %f\n",OpSmoothOmega);
	SmoothInternalNodes();
	CheckArea();
	WriteGrd("final.grd");

	return 0;
}
Ejemplo n.º 9
0
void
BorderResizer::Wrap()
{
	auto& controller(widget.get().GetController());

	yunseq(
	FetchEvent<TouchDown>(controller).Add([this](CursorEventArgs&& e){
		yunseq(orig_loc = FetchGUIState().CursorLocation,
			locked_bounds = GetBoundsOf(widget), focused = CheckArea(e));
	}, 0xE0),
	FetchEvent<TouchHeld>(controller).Add([this](CursorEventArgs&& e){
		if(e.Strategy == RoutedEventArgs::Direct
			&& focused != Area(BorderArea::Center, BorderArea::Center))
		{
			auto& st(FetchGUIState());

			if(st.CheckDraggingOffset())
			{
				const auto offset(st.CursorLocation - orig_loc);
				auto bounds(locked_bounds);

				switch(focused.first)
				{
				case BorderArea::Left:
					bounds.Width = max<SPos>(MinSize.Width,
						locked_bounds.Width - offset.X);
					bounds.X += locked_bounds.Width - bounds.Width;
					break;
				case BorderArea::Right:
					bounds.Width = max<SPos>(MinSize.Width,
						locked_bounds.Width + offset.X);
					break;
				default:
					;
				}
				switch(focused.second)
				{
				case BorderArea::Up:
					bounds.Height = max<SPos>(MinSize.Height,
						locked_bounds.Height - offset.Y);
					bounds.Y += locked_bounds.Height - bounds.Height;
					break;
				case BorderArea::Down:
					bounds.Height = max<SPos>(MinSize.Height,
						locked_bounds.Height + offset.Y);
					break;
				default:
					;
				}

				YTraceDe(Notice, "BorderResizer: new bounds = %s.\n",
					to_string(bounds).c_str());

				InvalidateParent(widget);

				if(HostMode)
				{
					const auto& off(
						bounds.GetPoint() - locked_bounds.GetPoint());

					SetBoundsOf(widget, bounds);

					const auto& nloc(FetchGUIState().CursorLocation - off);

					if(bounds.Width != MinSize.Width)
						orig_loc.X = nloc.X;
					if(bounds.Height != MinSize.Height)
						orig_loc.Y = nloc.Y;
					locked_bounds = GetBoundsOf(widget);
					locked_bounds.GetPointRef() -= off;
				}
				else
					SetBoundsOf(widget, bounds);
			}
			e.Handled = true;
			// XXX: Paint context target invalidated.
		}
	}, 0xE0),
	FetchEvent<Click>(controller).Add([this](CursorEventArgs&& e){
		CallEvent<ClickAcross>(widget, e);
	}, 0xE0),
	FetchEvent<ClickAcross>(controller).Add([this](CursorEventArgs&&){
		yunseq(orig_loc = Point::Invalid, locked_bounds = Rect(),
			focused = {BorderArea::Center, BorderArea::Center});
	}, 0xE0)
	);
}
Ejemplo n.º 10
0
void TeamFortress_Build( int objtobuild )
{
    float btime;

//      gedict_t *te;
    vec3_t tmp1;
    vec3_t tmp2;

    newmis = spawn(  );
    g_globalvars.newmis = EDICT_TO_PROG( newmis );

    // get an origin
    makevectors( self->s.v.v_angle );
    g_globalvars.v_forward[2] = 0;
    VectorNormalize( g_globalvars.v_forward );
    VectorScale( g_globalvars.v_forward, 64, g_globalvars.v_forward );
    VectorAdd( self->s.v.origin, g_globalvars.v_forward, newmis->s.v.origin );

    if ( objtobuild == BUILD_DISPENSER )
    {
        if( self->has_dispenser && !tg_data.tg_enabled)
	{
	    G_sprint( self, 2, "You can only have one dispenser.\nTry dismantling your old one.\n" );
	    return;
	}
	SetVector( tmp1, -8, -8, 0 );
	SetVector( tmp2, 8, 8, 24 );
//	newmis->mdl = "progs/disp.mdl";
	newmis->mdl = "progs/dispencr.mdl";		// megatf disp!
	newmis->s.v.netname = "dispenser";
	btime = g_globalvars.time + BUILD_TIME_DISPENSER;
	if( tg_data.tg_enabled )
		btime = g_globalvars.time;
    } else
    {
	if ( objtobuild == BUILD_SENTRYGUN )
	{
           if( self->has_sentry && !tg_data.tg_enabled)
	    {
		G_sprint( self, 2, "You can only have one sentry gun.\nTry dismantling your old one.\n" );
		return;
	    }
	    SetVector( tmp1, -16, -16, 0 );
	    SetVector( tmp2, 16, 16, 48 );
	    newmis->mdl = "progs/turrbase.mdl";
	    newmis->s.v.netname = "sentrygun";
	    btime = g_globalvars.time + BUILD_TIME_SENTRYGUN;
	    if( tg_data.tg_enabled )
	    	btime = g_globalvars.time;
	}else
	{
		G_Error("Unknown objtobuild in TeamFortress_Build\n");
		return;
	}

    }
    VectorCopy(tmp1,newmis->s.v.mins);
    VectorCopy(tmp2,newmis->s.v.maxs);
    // before we start building it, check it out
    // check for validity of point
    if ( !CheckArea( newmis, self ) )
    {
	G_sprint( self, 2, "Not enough room to build here\n" );
	dremove( newmis );
	return;
    }

    if ( !( ( int ) self->s.v.flags & FL_ONGROUND ) )
    {
	CenterPrint( self, "You can't build in the air!\n\n" );
	return;
    }
    self->is_building = 1;
    self->tfstate = self->tfstate | TFSTATE_CANT_MOVE;
    // Save the current weapon and remove it
    self->s.v.weapon = self->current_weapon;
    self->current_weapon = 0;
    self->s.v.weaponmodel = "";
    self->s.v.weaponframe = 0;

    TeamFortress_SetSpeed( self );
    newmis->s.v.owner = EDICT_TO_PROG( self );
    newmis->s.v.classname = "timer";
    newmis->s.v.netname = "build_timer";
    newmis->s.v.nextthink = btime;
    newmis->s.v.think = ( func_t ) TeamFortress_FinishedBuilding;
    newmis->s.v.colormap = self->s.v.colormap;
    newmis->s.v.weapon = objtobuild;
    newmis->s.v.angles[1] = anglemod( self->s.v.angles[1] + 180 );
    SetVector( newmis->s.v.velocity, 0, 0, 8 );
    newmis->s.v.movetype = MOVETYPE_TOSS;
    newmis->s.v.solid = SOLID_BBOX;
    setmodel( newmis, newmis->mdl );
    setsize( newmis, PASSVEC3( tmp1 ), PASSVEC3( tmp2 ) );
    setorigin( newmis, PASSVEC3( newmis->s.v.origin ) );
    newmis->s.v.flags = ( int ) newmis->s.v.flags - ( ( int ) newmis->s.v.flags & FL_ONGROUND );
}
bool CAreaManager::QueryAudioAreas(Vec3 const& rPos, SAudioAreaInfo *pResults, size_t const nMaxResults, size_t& rNumResults)
{
    rNumResults = 0;

    if (pResults != nullptr)
    {
        // Make sure the area grid is recompiled, if needed, before accessing it
        UpdateDirtyAreas();

        uint32 numAreas = 0;
        TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos));
        TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin());
        TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end());

        for (; IterAreas != IterAreasEnd; ++IterAreas)
        {
            CArea* const pArea = *IterAreas;

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER

            // check if Area is hidden
            IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID());

            if (pAreaEntity && !pAreaEntity->IsHidden())
            {
                size_t const nAttachedEntities = pArea->GetEntityAmount();

                if (nAttachedEntities > 0)
                {
                    for (size_t iEntity = 0; iEntity < nAttachedEntities; ++iEntity)
                    {
                        IEntity const* const pEntity = gEnv->pEntitySystem->GetEntity(pArea->GetEntityByIdx(iEntity));

                        if (pEntity != nullptr)
                        {
                            IEntityAudioProxy const* const pAudioProxy = (IEntityAudioProxy*)pEntity->GetProxy(ENTITY_PROXY_AUDIO);

                            if (pAudioProxy != nullptr)
                            {
                                TAudioEnvironmentID const nEnvironmentID = pAudioProxy->GetEnvironmentID();
                                float const fEnvironmentFadeDistance = pAudioProxy->GetEnvironmentFadeDistance();

                                if (nEnvironmentID != INVALID_AUDIO_ENVIRONMENT_ID)
                                {
                                    // This is optimized internally and might not recalculate but rather retrieve the cached data.
                                    bool const bIsPointWithin = (pArea->CalcPosType(INVALID_ENTITYID, rPos, false) == AREA_POS_TYPE_2DINSIDE_ZINSIDE);
                                    float fEnvironmentAmount = 0.0f;
                                    if (!bIsPointWithin && (fEnvironmentFadeDistance > 0.0f))
                                    {
                                        Vec3 Closest3d(ZERO);
                                        float const fDistance = sqrt_tpl(pArea->CalcPointNearDistSq(INVALID_ENTITYID, rPos, Closest3d, false));
                                        if (fDistance <= fEnvironmentFadeDistance)
                                        {
                                            fEnvironmentAmount = 1.0f - (fDistance/fEnvironmentFadeDistance);
                                        }
                                    }
                                    else
                                    {
                                        fEnvironmentAmount = 1.0f;
                                    }

                                    if (fEnvironmentAmount > 0.0f)
                                    {
                                        // still have room to put it in?
                                        if (rNumResults == nMaxResults)
                                            return false;

                                        // found area that should go into the results
                                        pResults[rNumResults].pArea									= pArea;
                                        pResults[rNumResults].fEnvironmentAmount		= fEnvironmentAmount;
                                        pResults[rNumResults].nEnvironmentID				= nEnvironmentID;
                                        pResults[rNumResults].nEnvProvidingEntityID	= pEntity->GetId();

                                        ++rNumResults;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return true;
    }

    return false;
}
void CAreaManager::UpdateEntity(Vec3 const& rPos, IEntity const* const pEntity)
{
    EntityId const nEntityID = pEntity->GetId();
    SAreasCache* pAreaCache = GetAreaCache(nEntityID);

    // Create a new area cache if necessary.
    if (pAreaCache == nullptr)
    {
        pAreaCache = MakeAreaCache(nEntityID);
    }

    assert(pAreaCache != nullptr);

    // Audio listeners and moving entities affected by environment changes need to update more often
    // to ensure smooth fading.
    uint32 const nExtendedFlags = pEntity->GetFlagsExtended();
    float const fPosDelta =
        ((nExtendedFlags & ENTITY_FLAG_EXTENDED_AUDIO_LISTENER) != 0) || ((nExtendedFlags & ENTITY_FLAG_EXTENDED_NEEDS_MOVEINSIDE) != 0)
        ? 0.01f
        : CVar::es_EntityUpdatePosDelta;

    if (pAreaCache != nullptr && !rPos.IsEquivalent(pAreaCache->vLastUpdatePos, fPosDelta))
    {
        pAreaCache->vLastUpdatePos = rPos;

        // First mark all cache entries that as if they are not in the grid.
        TAreaCacheVector::iterator Iter(pAreaCache->aoAreas.begin());
        TAreaCacheVector::const_iterator IterEnd(pAreaCache->aoAreas.end());

        for (; Iter != IterEnd; ++Iter)
        {
            SAreaCacheEntry& rAreaCacheEntry = (*Iter);
            CArea* const pArea = rAreaCacheEntry.pArea;

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER

            rAreaCacheEntry.bInGrid = false;

            // Now pre-calculate position data.
            pArea->InvalidateCachedAreaData(nEntityID);
            pArea->CalcPosType(nEntityID, rPos);
        }

        TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos));
        TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin());
        TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end());

        for (; IterAreas != IterAreasEnd; ++IterAreas)
        {
            // Mark cache entries as if they are in the grid.
            CArea* const pArea = *IterAreas;
            SAreaCacheEntry* pAreaCacheEntry = nullptr;

            if (pAreaCache->GetCacheEntry(pArea, &pAreaCacheEntry))
            {
                // cppcheck-suppress nullPointer
                pAreaCacheEntry->bInGrid = true;
            }
            else
            {
                // if they are not yet in the cache, add them
                pAreaCache->aoAreas.push_back(SAreaCacheEntry(pArea, false, false));
                pArea->OnAddedToAreaCache(pEntity);
            }

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER
        }

        // Go through all cache entries and process the areas.
        Iter = pAreaCache->aoAreas.begin();
        IterEnd = pAreaCache->aoAreas.end();

        for (; Iter != IterEnd; ++Iter)
        {
            SAreaCacheEntry& rAreaCacheEntry = (*Iter);
            CArea* const pArea = rAreaCacheEntry.pArea;

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER

            // check if Area is hidden
            IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID());
            bool bIsHidden = (pAreaEntity && pAreaEntity->IsHidden());

            // area was just hidden
            if (bIsHidden && pArea->IsActive())
            {
                pArea->LeaveArea(pEntity);
                pArea->LeaveNearArea(pEntity);
                rAreaCacheEntry.bNear		= false;
                rAreaCacheEntry.bInside	= false;
                pArea->SetActive(false);
                continue;
            }

            // area was just unhidden
            if (!bIsHidden && !pArea->IsActive())
            {
                // ProcessArea will take care of properly setting cache entry data.
                rAreaCacheEntry.bNear		= false;
                rAreaCacheEntry.bInside	= false;
                pArea->SetActive(true);
            }

            // We process only for active areas in which grid we are.
            // Areas in our cache in which grid we are not get removed down below anyhow.
            if (pArea->IsActive())
            {
                ProcessArea(pArea, rAreaCacheEntry, pAreaCache, rPos, pEntity);
            }
        }

        // Go through all areas again and send accumulated events. (needs to be done in a separate step)
        Iter = pAreaCache->aoAreas.begin();

        for (; Iter != IterEnd; ++Iter)
        {
            SAreaCacheEntry& rAreaCacheEntry = (*Iter);
            CArea* const pArea = rAreaCacheEntry.pArea;

#if defined(DEBUG_AREAMANAGER)
            CheckArea(pArea);
#endif // DEBUG_AREAMANAGER

            pArea->SendCachedEventsFor(nEntityID);
        }

        // Remove all entries in the cache which are no longer in the grid.
        if (!pAreaCache->aoAreas.empty())
        {
            pAreaCache->aoAreas.erase(std::remove_if(pAreaCache->aoAreas.begin(), pAreaCache->aoAreas.end(), SIsNotInGrid(pEntity, m_apAreas, m_apAreas.size())), pAreaCache->aoAreas.end());
        }

        if (pAreaCache->aoAreas.empty())
        {
            DeleteAreaCache(nEntityID);
        }
    }
}