// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdpacs.h"
#include "nel/pacs/retriever_instance.h"
#include "nel/pacs/global_retriever.h"
using namespace std;
using namespace NLMISC;
NLPACS::CRetrieverInstance::CRetrieverInstance()
{
reset();
}
void NLPACS::CRetrieverInstance::resetLinks()
{
uint i;
// WARNING !!
// this is a HARD reset !
// only the instance i reset, no care about neighbors !!
for (i=0; i<_Neighbors.size(); ++i)
_Neighbors[i] = -1;
_BorderChainLinks.clear();
_ExteriorEdgeQuad.removeLinks();
}
void NLPACS::CRetrieverInstance::resetLinks(uint32 id)
{
vector::iterator rit;
for (rit=_Neighbors.begin(); rit!=_Neighbors.end(); )
if (*rit == (sint32)id)
rit = _Neighbors.erase(rit);
else
++rit;
uint i;
for (i=0; i<_BorderChainLinks.size(); ++i)
if (_BorderChainLinks[i].Instance == (uint16)id)
_BorderChainLinks[i].reset();
_ExteriorEdgeQuad.removeLinks(id);
}
void NLPACS::CRetrieverInstance::reset()
{
// WARNING !!
// this is a HARD reset !
// only the instance i reset, no care about neighbors !!
_NodesInformation.clear();
_InstanceId = -1;
_RetrieverId = -1;
_Orientation = 0;
_Origin = CVector::Null;
_Type = CLocalRetriever::Landscape;
_BorderChainLinks.clear();
_ExteriorEdgeQuad.clear();
resetLinks();
}
void NLPACS::CRetrieverInstance::init(const CLocalRetriever &retriever)
{
if (!retriever.isLoaded())
return;
/*
_NodesInformation.resize(retriever.getSurfaces().size());
uint i;
// Resets _NodesInformation for later pathfinding graph annotation.
for (i=0; i<_NodesInformation.size(); ++i)
{
CVector pos = getGlobalPosition(retriever.getSurfaces()[i].getCenter());
_NodesInformation[i].Position = CVector2f(pos.x, pos.y);
}
*/
_Type = retriever.getType();
_BorderChainLinks.resize(retriever.getBorderChains().size());
}
void NLPACS::CRetrieverInstance::make(sint32 instanceId, sint32 retrieverId, const CLocalRetriever &retriever,
uint8 orientation, const CVector &origin)
{
if (_InstanceId != -1 || _RetrieverId != -1)
{
nlwarning("in call to NLPACS::CRetrieverInstance::make");
nlwarning("_InstanceId=%d _RetrieverId=%d _Orientation=%d", _InstanceId, _RetrieverId, _Orientation);
nlwarning("instanceId=%d retrieverId=%d orientation=%d", instanceId, retrieverId, orientation);
nlerror("Retriever instance %d has already been set", _InstanceId);
}
_InstanceId = instanceId;
_RetrieverId = retrieverId;
_Orientation = (orientation%4);
_Origin = origin;
_BBox = retriever.getBBox();
_BBox.setCenter(_BBox.getCenter()+_Origin);
if (_Orientation == 1 || _Orientation == 3)
{
CVector hs = _BBox.getHalfSize();
std::swap(hs.x, hs.y);
_BBox.setHalfSize(hs);
}
init(retriever);
}
//
void NLPACS::CRetrieverInstance::initEdgeQuad(NLPACS::CGlobalRetriever &gr)
{
const CLocalRetriever &lr = gr.getRetriever(_RetrieverId);
if (lr.getType() != CLocalRetriever::Interior)
{
nlerror("Attempt to init the edgequad of instance %d whereas local retriever %d is not interior", _InstanceId, _RetrieverId);
}
// build the edge quad
_ExteriorEdgeQuad.build(lr.getExteriorMesh(), gr, gr.getInternalCST(),_InstanceId);
}
void NLPACS::CRetrieverInstance::linkEdgeQuad(NLPACS::CGlobalRetriever &gr)
{
const CLocalRetriever &lr = gr.getRetriever(_RetrieverId);
const CExteriorMesh &em = lr.getExteriorMesh();
const vector &ee = _ExteriorEdgeQuad.getEdgeEntries();
// here we fill (partially) the _BorderChainLinks table
uint i;
for (i=0; i &retrievers)
{
uint i, j;
for (i=0; i<_Neighbors.size(); ++i)
if (_Neighbors[i] == neighbor._InstanceId)
return;
const CLocalRetriever &retriever = retrievers[_RetrieverId];
const CLocalRetriever &nRetriever = retrievers[neighbor._RetrieverId];
const vector &chains = retriever.getChains(),
&nChains = nRetriever.getChains();
const vector &borderChains = retriever.getBorderChains(),
&nBorderChains = nRetriever.getBorderChains();
vector< pair > chainTips,
nChainTips;
_BorderChainLinks.resize(borderChains.size());
neighbor._BorderChainLinks.resize(nBorderChains.size());
/*
for (i=0; i 1.0e-1f || best == -1)
continue;
_BorderChainLinks[i].Instance = (uint16)neighbor._InstanceId;
_BorderChainLinks[i].BorderChainId = (uint16)best;
_BorderChainLinks[i].ChainId = nBorderChains[_BorderChainLinks[i].BorderChainId];
_BorderChainLinks[i].SurfaceId = (uint16)nChains[_BorderChainLinks[i].ChainId].getLeft();
neighbor._BorderChainLinks[best].Instance = (uint16)_InstanceId;
neighbor._BorderChainLinks[best].BorderChainId = (uint16)i;
neighbor._BorderChainLinks[best].ChainId = borderChains[neighbor._BorderChainLinks[best].BorderChainId];
neighbor._BorderChainLinks[best].SurfaceId = (uint16)chains[neighbor._BorderChainLinks[best].ChainId].getLeft();
}
_Neighbors.push_back(neighbor._InstanceId);
neighbor._Neighbors.push_back(_InstanceId);
}
void NLPACS::CRetrieverInstance::unlink(vector &instances)
{
uint i;
for (i=0; i<_Neighbors.size(); ++i)
instances[_Neighbors[i]].resetLinks(_InstanceId);
resetLinks();
}
void NLPACS::CRetrieverInstance::retrievePosition(const NLMISC::CVector &estimated, const CLocalRetriever &retriever, CCollisionSurfaceTemp &cst, bool sortByDistance) const
//NLPACS::CLocalRetriever::CLocalPosition NLPACS::CRetrieverInstance::retrievePosition(const NLMISC::CVector &estimated, const CLocalRetriever &retriever, CCollisionSurfaceTemp &cst) const
{
/*
CVector localEstimated;
CLocalRetriever::CLocalPosition retrieved;
// get local coordinates
localEstimated = getLocalPosition(estimated);
// Yoyo: must snap vector.
CRetrieverInstance::snapVector(localEstimated);
// fills _RetrieveTable by retrievingPosition.
retriever.retrievePosition(localEstimated, cst);
uint i, surf;
sint bestSurf = -1;
sint lastSurf = -1;
float bestDistance = 1.0e10f;
float bestHeight;
bool lfound;
// for each surface in the retriever
for (i=0; igetMaxHeight();
lfound = true;
break;
case CLocalRetriever::Interior:
// for interior
// get the exact position
lp.Surface = surf;
lp.Estimation = localEstimated;
meanHeight = localEstimated.z;
retriever.snapToInteriorGround(lp, lfound);
if (lfound)
meanHeight = lp.Estimation.z;
break;
default:
// hu?
continue;
}
// if it is closer to the estimation than the previous remembered...
float distance = (float)fabs(localEstimated.z-meanHeight);
if (distance < bestDistance && lfound)
{
bestDistance = distance;
bestHeight = meanHeight;
bestSurf = surf;
}
}
}
if (bestSurf != -1)
{
// if there is a best surface, returns it
retrieved.Surface = bestSurf;
retrieved.Estimation = CVector(localEstimated.x, localEstimated.y, bestHeight);
}
else
{
// else return the last remembered...
retrieved.Surface = lastSurf;
retrieved.Estimation = localEstimated;
}
return retrieved;
*/
retrievePosition(CVectorD(estimated), retriever, cst, sortByDistance);
}
void NLPACS::CRetrieverInstance::retrievePosition(const NLMISC::CVectorD &estimated, const CLocalRetriever &retriever, CCollisionSurfaceTemp &cst, bool sortByDistance) const
{
CVector localEstimated;
// nldebug("PACS: retrievePosition in instance %d (retriever %d)", _InstanceId, _RetrieverId);
// get local coordinates
localEstimated = getLocalPosition(estimated);
// Yoyo: must snap vector.
CRetrieverInstance::snapVector(localEstimated);
// fills _RetrieveTable by retrievingPosition.
retriever.retrievePosition(localEstimated, cst);
uint i, surf;
/* sint bestSurf = -1;
sint lastSurf = -1;
float bestDistance = 1.0e10f;
float bestHeight;*/
bool found = false;
switch (_Type)
{
case CLocalRetriever::Landscape:
// for landscape
for (i=0; igetMaxHeight();
//meanHeight = retriever.getSurfaces()[surf].getQuadTree().getInterpZ(localEstimated);
// if it is closer to the estimation than the previous remembered...
found = true;
float distance = (float)fabs(localEstimated.z-meanHeight);
cst.SortedSurfaces.push_back(CCollisionSurfaceTemp::CDistanceSurface(distance, (uint16)surf, (uint16)_InstanceId, cst.SurfaceLUT[surf].FoundCloseEdge));
}
*/
meanHeight = retriever.getSurface(surf).getQuantHeight()*2.0f + 1.0f;
// if it is closer to the estimation than the previous remembered...
found = true;
float distance = sortByDistance ? (float)fabs(localEstimated.z-meanHeight) : meanHeight;
cst.SortedSurfaces.push_back(CCollisionSurfaceTemp::CDistanceSurface(distance, (uint16)surf, (uint16)_InstanceId, cst.SurfaceLUT[surf].FoundCloseEdge));
}
else if (cst.SurfaceLUT[surf].Counter != 0)
{
nlwarning("PACS: unexpected surface (%d) count (%d) at instance %d (pos=(%f,%f,%f))", surf, cst.SurfaceLUT[surf].Counter, _InstanceId, estimated.x, estimated.y, estimated.z);
}
cst.SurfaceLUT[surf].reset();
}
break;
case CLocalRetriever::Interior:
// for interior
for (i=0; igetMaxHeight();
}
else
{
nlwarning("PACS: couldn't snap position (%f,%f,%f) on surface %d instance %d", position.Estimation.x, position.Estimation.y, position.Estimation.z, position.Surface, _InstanceId);
}
*/
}
else if (_Type == CLocalRetriever::Interior)
{
bool lfound;
retriever.snapToInteriorGround(position, lfound);
}
else
{
nlwarning("PACS: unknown instance (%d) type %d", _InstanceId, _Type);
}
}
CVector NLPACS::CRetrieverInstance::getLocalPosition(const CVector &globalPosition) const
{
switch (_Orientation)
{
default:
nlwarning("in NLPACS::CRetrieverInstance::getLocalPosition()");
nlerror("unexpected orientation value (%d)", _Orientation);
case 0:
return CVector(+globalPosition.x-_Origin.x, +globalPosition.y-_Origin.y, globalPosition.z-_Origin.z);
break;
case 1:
return CVector(+globalPosition.y-_Origin.y, -globalPosition.x+_Origin.x, globalPosition.z-_Origin.z);
break;
case 2:
return CVector(-globalPosition.x+_Origin.x, -globalPosition.y+_Origin.y, globalPosition.z-_Origin.z);
break;
case 3:
return CVector(-globalPosition.y+_Origin.y, +globalPosition.x-_Origin.x, globalPosition.z-_Origin.z);
break;
}
}
CVector NLPACS::CRetrieverInstance::getLocalPosition(const CVectorD &globalPosition) const
{
switch (_Orientation)
{
default:
nlwarning("in NLPACS::CRetrieverInstance::getLocalPosition()");
nlerror("unexpected orientation value (%d)", _Orientation);
case 0:
return CVector((float)(+globalPosition.x-_Origin.x), (float)(+globalPosition.y-_Origin.y), (float)(globalPosition.z-_Origin.z));
break;
case 1:
return CVector((float)(+globalPosition.y-_Origin.y), (float)(-globalPosition.x+_Origin.x), (float)(globalPosition.z-_Origin.z));
break;
case 2:
return CVector((float)(-globalPosition.x+_Origin.x), (float)(-globalPosition.y+_Origin.y), (float)(globalPosition.z-_Origin.z));
break;
case 3:
return CVector((float)(-globalPosition.y+_Origin.y), (float)(+globalPosition.x-_Origin.x), (float)(globalPosition.z-_Origin.z));
break;
}
}
CVector NLPACS::CRetrieverInstance::getGlobalPosition(const CVector &localPosition) const
{
switch (_Orientation)
{
default:
nlwarning("in NLPACS::CRetrieverInstance::getLocalPosition()");
nlerror("unexpected orientation value (%d)", _Orientation);
case 0:
return CVector(+localPosition.x+_Origin.x, +localPosition.y+_Origin.y, localPosition.z+_Origin.z );
break;
case 1:
return CVector(-localPosition.y+_Origin.x, +localPosition.x+_Origin.y, localPosition.z+_Origin.z );
break;
case 2:
return CVector(-localPosition.x+_Origin.x, -localPosition.y+_Origin.y, localPosition.z+_Origin.z );
break;
case 3:
return CVector(+localPosition.y+_Origin.x, -localPosition.x+_Origin.y, localPosition.z+_Origin.z );
break;
}
}
CVectorD NLPACS::CRetrieverInstance::getDoubleGlobalPosition(const CVector &localPosition) const
{
switch (_Orientation)
{
default:
nlwarning("in NLPACS::CRetrieverInstance::getLocalPosition()");
nlerror("unexpected orientation value (%d)", _Orientation);
case 0:
return CVectorD(+(double)localPosition.x+(double)_Origin.x, +(double)localPosition.y+(double)_Origin.y, (double)localPosition.z+(double)_Origin.z );
break;
case 1:
return CVectorD(-(double)localPosition.y+(double)_Origin.x, +(double)localPosition.x+(double)_Origin.y, (double)localPosition.z+(double)_Origin.z );
break;
case 2:
return CVectorD(-(double)localPosition.x+(double)_Origin.x, -(double)localPosition.y+(double)_Origin.y, (double)localPosition.z+(double)_Origin.z );
break;
case 3:
return CVectorD(+(double)localPosition.y+(double)_Origin.x, -(double)localPosition.x+(double)_Origin.y, (double)localPosition.z+(double)_Origin.z );
break;
}
}
// ***************************************************************************
void NLPACS::CRetrieverInstance::testExteriorCollision(NLPACS::CCollisionSurfaceTemp &cst, const CAABBox &bboxMove, const CVector2f &transBase, const NLPACS::CLocalRetriever &retriever) const
{
sint i;
// 0. select ordered chains in the chainquad.
//=====================================
sint nEei= _ExteriorEdgeQuad.selectEdges(bboxMove, cst);
// NB: cst.OChainLUT is assured to be full of 0xFFFF after this call (if was right before).
// 1. regroup them in chains. build cst.CollisionChains
//=====================================
// NB: use cst.OChainLUT to look if a Chain has been inserted before.
uint16 *edgeLUT= cst.OChainLUT;
// bkup where we begin to add chains.
uint firstChainAdded= (uint)cst.CollisionChains.size();
// For all exterioredge entry.
for(i=0;i= 1)
{
f.serialEnum(_Type);
f.serial(_ExteriorEdgeQuad);
// a fix for old versions (with wrong _Type value)
if (_Type != CLocalRetriever::Interior) _Type = CLocalRetriever::Landscape;
}
}
void NLPACS::CRetrieverInstance::resetBorderChainLinks(const vector &links)
{
uint i;
for (i=0; i= _BorderChainLinks.size())
_BorderChainLinks.resize(links[i]+1);
_BorderChainLinks[links[i]].reset();
}
}