void GlassLayer::draw(Graphics* const TheGraphics, const Pnt2f& TopLeft, const Pnt2f& BottomRight, const Real32 Opacity) const
{
    Pnt2f IntermediatePosition;
    Vec3f Bounds(BottomRight- TopLeft);
    
    //Setup the Blending equations properly
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glBegin(GL_TRIANGLE_FAN);
        glColor4f(getEdgeColor().red(),getEdgeColor().green(),getEdgeColor().blue(),getEdgeColor().alpha() * Opacity);
        glVertex2f(getStartPosition().x(), getEndPosition().y());
        glColor4f(getCenterColor().red(),getCenterColor().green(),getCenterColor().blue(),getCenterColor().alpha() * Opacity);
        glVertex2fv(getStartPosition().getValues());
        for(UInt32 i(0) ; i<_Segments.size(); ++i)
        {
            IntermediatePosition.setValues(_Segments[i].x() * Bounds.x(),_Segments[i].y() * Bounds.y());
            glVertex2fv(IntermediatePosition.getValues());
        }
        glVertex2fv(getEndPosition().getValues());
    glEnd();

    glDisable(GL_BLEND);

}
Example #2
0
void Needle::setTransformFromEndEffectorBoxConstrained(const Vector3d& new_ee_pos, const Matrix3d& new_ee_rot, Box* box)
{
	Vector3d old_ee_pos;
	Matrix3d old_ee_rot;
	getEndEffectorTransform(old_ee_pos, old_ee_rot);

	Vector3d old_proj = (old_ee_pos - position);
	old_proj.normalize();
	Vector3d proj = (new_ee_pos-position).dot(rotation.col(0))*rotation.col(0) + (new_ee_pos-position).dot(rotation.col(2))*rotation.col(2);
	proj.normalize();

	glColor3f(0.8,0.8,0);
	drawArrow(position, 20*proj);
	glColor3f(0.8,0,0);
	drawArrow(position, 20*old_proj);

	Vector3d normal = proj.cross(old_proj);
	normal.normalize();

	double angle = angle_between(proj, old_proj)*180.0/M_PI;
	if (angle > 90.0) {
		angle = 0.0;
		//TODO return;
	} else {
		double sign = ((normal - rotation.col(1)).squaredNorm() < 1e-5) ? -1 : 1;
		angle = sign*min(angle_between(proj, old_proj)*180.0/M_PI, 5.0);
	}

	if (!isnan(angle) && abs(angle)>1e-5 && angle>0.0) { //TODO for now, only allows forward movement of needle through box
		rotateAboutAxis(angle);
		if(isThreadAttached()) {
			thread->updateConstrainedTransform(constraint_ind, getEndPosition(), getEndRotation());
		}
	}
	
	if (isThreadAttached()) {
		Vector3d direction;
		if (!box->isThreadAttached() && (sphereBoxDistance(getEndPosition(), getThicknessRadius(), box->getPosition(), box->getHalfLength(), direction) < 0)) {
		  cout << "thread gets into the box" << endl;
		  //box->attach(getThread());
			box->attachThreadIn(getThread(), getEndPosition(), getEndRotation());
		}
		if (box->isThreadAttached() && !boxCollision(box->getPosition(), box->getHalfLength())) {
		  cout << "thread gets out of the box" << endl;
		  box->attachThreadOut(getThread(), getEndPosition(), getEndRotation());
		}
	}
}
Example #3
0
void Needle::setTransformFromEndEffector(const Vector3d& ee_pos, const Matrix3d& ee_rot)
{
	vector<Box*> boxes;
	world->getObjects<Box>(boxes);
	Box* box = NULL;
	for (int i = 0; i < boxes.size(); i++) {
		if (boxes[i]->isNeedleAttached() && (boxes[i]->getNeedle() == this)) {
			box = boxes[i];
			break;
		}
	}
	if (box == NULL) {
		setTransform(ee_pos + ee_rot*rotation_offset*position_offset, ee_rot * rotation_offset);

		if(isThreadAttached()) {
			vector<int> constraint_inds;
			thread->getConstrainedVerticesNums(constraint_inds);
			if (constraint_inds.size() != 3) {
				cout << "adding constraint" << endl;
				thread->addConstraint(10);
				//thread->updateRotationOffset(1, (Matrix3d) Angle;
			}
			Vector3d position_diff = thread->rotationAtConstraint(1).transpose() * (thread->positionAtConstraint(1) - thread->positionAtConstraint(0));
			position_diff = (thread->positionAtConstraint(1) - thread->positionAtConstraint(0));
			//Matrix3d rotation_diff = thread->rotationAtConstraint(0).transpose() * thread->rotationAtConstraint(1);
			Matrix3d rotation_diff =  thread->rotationAtConstraint(0).transpose() * thread->rotationAtConstraint(1);
			assert(constraint_ind == 0);
			//thread->updateConstrainedTransform(constraint_ind, getEndPosition(), getEndRotation());
			thread->updateConstrainedTransform(0, getEndPosition(), getEndRotation());
			Matrix3d ee_rot = thread->rotationAtConstraint(0) * rotation_diff;
			//ee_rot = (Matrix3d) AngleAxisd(ee_rot);
//			ee_rot.col(1) = ee_rot.col(2).cross(ee_rot.col(0));
//			ee_rot.col(2) = ee_rot.col(0).cross(ee_rot.col(1));
//			ee_rot.col(0).normalize();
//			ee_rot.col(1).normalize();
//			ee_rot.col(2).normalize();
			//position_diff = Vector3d(-10,0,0);
			//thread->updateConstrainedTransform(1, ee_rot*position_diff + getEndPosition(), ee_rot);
			thread->updateConstrainedTransform(1, position_diff + getEndPosition(), ee_rot); //thread->rotationAtConstraint(1);
			//thread->updateConstrainedRawTransform(1, position_diff + getEndPosition(), ee_rot, ee_rot);
			//thread->updateConstrainedRawTransform(1, ee_rot*position_diff + getEndPosition(), ee_rot, ee_rot);
			//thread->minimize_energy();
		}
	} else {
		setTransformFromEndEffectorBoxConstrained(ee_pos, ee_rot, box);
	}
	checkBoxAttach();
}
Example #4
0
bool PathFinder::calculate(float destX, float destY, float destZ, bool forceDest)
{
    Vector3 oldDest = getEndPosition();
    Vector3 dest(destX, destY, destZ);
    setEndPosition(dest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    Vector3 start(x, y, z);
    setStartPosition(start);

    m_forceDestination = forceDest;

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate() for %u \n", m_sourceUnit->GetGUIDLow());

    // make sure navMesh works - we can run on map w/o mmap
    // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
    if (!m_navMesh || !m_navMeshQuery || m_sourceUnit->hasUnitState(UNIT_STAT_IGNORE_PATHFINDING) ||
        !HaveTile(start) || !HaveTile(dest) || m_sourceUnit->m_movementInfo.HasMovementFlag(MOVEFLAG_TAXI)) //for transport
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    BuildPolyPath(start, dest);
    return true;
}
Example #5
0
void Needle::rotateAboutAxis(double degrees)
{
	setTransform(position, AngleAxisd(degrees * M_PI/180.0, rotation.col(1)) * rotation);
	if(isThreadAttached()) {
		thread->updateConstrainedTransform(constraint_ind, getEndPosition(), getEndRotation());
	}
}
Example #6
0
void PathInfo::Build()
{
    float x, y, z;
    // set start and a default next position
    m_sourceObject->GetPosition(x, y, z);
    setStartPosition(x, y, z);
    setNextPosition(x, y, z);

    // get nav mesh
    m_navMesh = m_sourceObject->GetMap()->GetNavMesh();

    if(!m_navMesh)
    {
        // if there is no navmesh, just move to destination
        shortcut();
        return;
    }

    float extents[3] = {2.0f, 4.0f, 2.0f};      // defines bounds of box for search area
    dtQueryFilter filter = dtQueryFilter();     // use general filter so we know if we are near navmesh

    // get start and end positions
    getStartPosition(x, y, z);
    float startPos[3] = {y, z, x};
    getEndPosition(x, y, z);
    float endPos[3] = {y, z, x};

    // find start and end poly
    dtPolyRef startPoly = m_navMesh->findNearestPoly(startPos, extents, &filter, 0);
    dtPolyRef endPoly = m_navMesh->findNearestPoly(endPos, extents, &filter, 0);

    Build(startPoly, endPoly);
}
Example #7
0
bool PathFinder::calculate(float destX, float destY, float destZ, bool forceDest)
{
    Vector3 oldDest = getEndPosition();
    Vector3 dest(destX, destY, destZ);
    setEndPosition(dest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    Vector3 start(x, y, z);
    setStartPosition(start);

    m_forceDestination = forceDest;

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate() for %u \n", m_sourceUnit->GetGUIDLow());

    // make sure navMesh works - we can run on map w/o mmap
    // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
    if (!m_navMesh || !m_navMeshQuery || m_sourceUnit->hasUnitState(UNIT_STAT_IGNORE_PATHFINDING) ||
        !HaveTile(start) || !HaveTile(dest) || (m_sourceUnit->GetTypeId() == TYPEID_UNIT && ((Creature*)m_sourceUnit)->IsLevitating()))
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    {
        ReadGuard Guard(MMAP::MMapFactory::createOrGetMMapManager()->GetLock(m_sourceUnit->GetMapId()));
        BuildPolyPath(start, dest);
    }
    return true;
}
Example #8
0
void PathInfo::shortcut()
{
    clear();

    float x, y, z;
    getEndPosition(x, y, z);
    setNextPosition(x, y, z);
    m_type = PATHFIND_SHORTCUT;
}
Example #9
0
bool PathInfo::Update(const float destX, const float destY, const float destZ, bool useStraightPath)
{
    PathNode newDest(destX, destY, m_sourceUnit->GetMap()->GetHeight(destX,destY,destZ,100.0f));
    PathNode oldDest = getEndPosition();
    setEndPosition(newDest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    PathNode newStart(x, y, m_sourceUnit->GetMap()->GetHeight(x,y,z,100.0f));
    PathNode oldStart = getStartPosition();
    setStartPosition(newStart);

    m_useStraightPath = useStraightPath;

    PATH_DEBUG("++ PathInfo::Update() for %u \n", m_sourceUnit->GetGUID());

    // make sure navMesh works - we can run on map w/o mmap
    if (!m_navMesh || !m_navMeshQuery)
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    float dist = m_sourceUnit->GetObjectBoundingRadius();
    bool oldDestInRange = inRange(oldDest, newDest, dist, dist);

    // this can happen only if caller did a bad job calculating the need for path update
    if (oldDestInRange && inRange(newStart, oldStart, dist, dist))
    {
        setEndPosition(oldDest);
        setStartPosition(oldStart);
        return false;
    }

    // check if destination moved - if not we can optimize something here
    // we are following old, precalculated path?
    if (oldDestInRange && m_pathPoints.size() > 2)
    {
        // our target is not moving - we just coming closer
        // we are moving on precalculated path - enjoy the ride
        PATH_DEBUG("++ PathInfo::Update:: precalculated path\n");

        m_pathPoints.crop(1, 0);
        setNextPosition(m_pathPoints[1]);

        return false;
    }
    else
    {
        // target moved, so we need to update the poly path
        BuildPolyPath(newStart, newDest);
        return true;
    }
}
void MissionObjectiveImplementation::awardReward() {
	Vector<ManagedReference<CreatureObject*> > players;
	PlayMusicMessage* pmm = new PlayMusicMessage("sound/music_mission_complete.snd");

	Vector3 missionEndPoint = getEndPosition();

	ManagedReference<CreatureObject*> owner = getPlayerOwner();

	ManagedReference<GroupObject*> group = owner->getGroup();

	if (group != NULL) {
		Locker lockerGroup(group, _this.get());

		for(int i = 0; i < group->getGroupSize(); i++) {
			Reference<CreatureObject*> groupMember = group->getGroupMember(i)->isPlayerCreature() ? (group->getGroupMember(i)).castTo<CreatureObject*>() : NULL;

			if (groupMember != NULL) {
				//Play mission complete sound.
				groupMember->sendMessage(pmm->clone());

				if (groupMember->getWorldPosition().distanceTo(missionEndPoint) < 128) {
					players.add(groupMember);
				}
			}
		}

		delete pmm;
	} else {
		//Play mission complete sound.
		owner->sendMessage(pmm);
		players.add(owner);
	}

	if (players.size() == 0) {
		players.add(owner);
	}

	ManagedReference<MissionObject* > mission = this->mission.get();

	int dividedReward = mission->getRewardCredits() / players.size();

	for (int i = 0; i < players.size(); i++) {
		ManagedReference<CreatureObject*> player = players.get(i);
		StringIdChatParameter stringId("mission/mission_generic", "success_w_amount");
		stringId.setDI(dividedReward);
		player->sendSystemMessage(stringId);

		Locker lockerPl(player, _this.get());
		player->addBankCredits(dividedReward, true);
	}

	StatisticsManager::instance()->completeMission(mission->getTypeCRC() ,mission->getRewardCredits());
}
bool PathFinderMovementGenerator::calculate(float destX, float destY, float destZ, bool forceDest)
{
    if (!SkyFire::IsValidMapCoord(destX, destY, destZ) ||
        !SkyFire::IsValidMapCoord(m_sourceUnit->GetPositionX(), m_sourceUnit->GetPositionY(), m_sourceUnit->GetPositionZ()))
        return false;

    Vector3 oldDest = getEndPosition();
    Vector3 dest(destX, destY, destZ);
    setEndPosition(dest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    Vector3 start(x, y, z);
    setStartPosition(start);

    m_forceDestination = forceDest;

    sLog->outDebug(LOG_FILTER_MAPS, "++ PathFinderMovementGenerator::calculate() for %u \n", m_sourceUnit->GetGUIDLow());

    // make sure navMesh works - we can run on map w/o mmap
    // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
    if (!m_navMesh || !m_navMeshQuery || m_sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) ||
        !HaveTile(start) || !HaveTile(dest))
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    // check if destination moved - if not we can optimize something here
    // we are following old, precalculated path?
    float dist = m_sourceUnit->GetObjectSize();
    if (inRange(oldDest, dest, dist, dist) && m_pathPoints.size() > 2)
    {
        // our target is not moving - we just coming closer
        // we are moving on precalculated path - enjoy the ride
        sLog->outStaticDebug("++ PathFinderMovementGenerator::calculate:: precalculated path\n");

        m_pathPoints.erase(m_pathPoints.begin());
        return false;
    }
    else
    {
        // target moved, so we need to update the poly path
        m_navMeshLock->acquire_read();
        BuildPolyPath(start, dest);
        m_navMeshLock->release();
        return true;
    }
}
Example #12
0
bool PathInfo::Update(const float destX, const float destY, const float destZ,
                      bool useStraightPath, bool forceDest)
{
    PathNode newDest(destX, destY, destZ);
    PathNode oldDest = getEndPosition();
    setEndPosition(newDest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    PathNode newStart(x, y, z);
    PathNode oldStart = getStartPosition();
    setStartPosition(newStart);

    m_useStraightPath = useStraightPath;
    m_forceDestination = forceDest;

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathInfo::Update() for %u \n", m_sourceUnit->GetGUID());

    // make sure navMesh works - we can run on map w/o mmap
    if (!m_navMesh || !m_navMeshQuery || !HaveTiles(newDest) ||
            m_sourceUnit->hasUnitState(UNIT_STAT_IGNORE_PATHFINDING))
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    // check if destination moved - if not we can optimize something here
    // we are following old, precalculated path?
    float dist = m_sourceUnit->GetObjectBoundingRadius();
    if (inRange(oldDest, newDest, dist, dist) && m_pathPoints.size() > 2)
    {
        // our target is not moving - we just coming closer
        // we are moving on precalculated path - enjoy the ride
        DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathInfo::Update:: precalculated path\n");

        m_pathPoints.crop(1, 0);
        setNextPosition(m_pathPoints[1]);

        return false;
    }
    else
    {
        // target moved, so we need to update the poly path
        BuildPolyPath(newStart, newDest);
        return true;
    }
}
Example #13
0
bool PathFinder::calculate(float destX, float destY, float destZ, bool forceDest)
{
    Vector3 oldDest = getEndPosition();
    Vector3 dest(destX, destY, destZ);
    setEndPosition(dest);

    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);
    Vector3 start(x, y, z);
    setStartPosition(start);

    m_forceDestination = forceDest;

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate() for %u \n", m_sourceUnit->GetGUIDLow());

    // make sure navMesh works - we can run on map w/o mmap
    // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
    if (!m_navMesh || !m_navMeshQuery || m_sourceUnit->hasUnitState(UNIT_STAT_IGNORE_PATHFINDING) ||
        !HaveTile(start) || !HaveTile(dest))
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    // check if destination moved - if not we can optimize something here
    // we are following old, precalculated path?
    float dist = m_sourceUnit->GetObjectBoundingRadius();
    if (inRange(oldDest, dest, dist, dist) && m_pathPoints.size() > 2)
    {
        // our target is not moving - we just coming closer
        // we are moving on precalculated path - enjoy the ride
        DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate:: precalculated path\n");

        m_pathPoints.erase(m_pathPoints.begin());
        return false;
    }
    else
    {
        // target moved, so we need to update the poly path
        ReadGuard Guard(MMAP::MMapFactory::createOrGetMMapManager()->GetLock(m_sourceUnit->GetMapId()));
        BuildPolyPath(start, dest);
        return true;
    }
}
Example #14
0
bool PathInfo::Update(float destX, float destY, float destZ, bool forceDest)
{
    float x, y, z;
    m_sourceUnit->GetPosition(x, y, z);

    if (!Oregon::IsValidMapCoord(destX, destY, destZ) || !Oregon::IsValidMapCoord(x, y, z))
    {
        sLog.outMMap("PathInfo::Update() called with invalid map coords, destX: %f destY: %f destZ: %f x: %f y: %f z: %f for creature %u", destX, destY, destZ, x, y, z, m_sourceUnit->GetGUIDLow());
        m_type = PATHFIND_NOPATH;
        return false;
    }

    Vector3 oldDest = getEndPosition();
    Vector3 newDest(destX, destY, destZ);
    setEndPosition(newDest);

    Vector3 newStart(x, y, z);
    setStartPosition(newStart);

    m_forceDestination = forceDest;

    sLog.outMMap("PathInfo::Update() for %u \n", m_sourceUnit->GetGUIDLow());

    // make sure navMesh works - we can run on map w/o mmap
    // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
    if (!m_navMesh || !m_navMeshQuery || m_sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) ||
        !HaveTile(newStart) || !HaveTile(newDest))
    {
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return true;
    }

    updateFilter();

    BuildPolyPath(newStart, newDest);
    return true;
}
void GlassLayer::updateSegments(void)
{
    //Calculate a Cubic Hermite spline
    _Segments.clear();

    Vec2f Pos;
    Real32 t,
           t_sqr,
           t_cub;
    for(UInt32 i(1) ; i<getSegments() ; ++i)
    {
        t = static_cast<Real32>(i)/static_cast<Real32>(getSegments());
        t_sqr = t*t;
        t_cub = t_sqr*t;

        Pos = ( 2.0f * t_cub - 3.0f*t_sqr + 1.0f) * getStartPosition().subZero() +
              (        t_cub - 2.0f*t_sqr +    t) * getStartDirection() +
              (-2.0f * t_cub + 3.0f*t_sqr       ) * getEndPosition().subZero() +
              (        t_cub -      t_sqr       ) * getEndDirection();

        _Segments.push_back(Pos);
    }
}
Example #16
0
void PathInfo::Update(const float destX, const float destY, const float destZ)
{
    float x, y, z;

    // update start and end
    m_sourceObject->GetPosition(x, y, z);
    setStartPosition(x, y, z);
    setEndPosition(destX, destY, destZ);

    // make sure navMesh works
    if(!m_navMesh)
    {
        m_sourceObject->GetPosition(x, y, z);
        m_navMesh = m_sourceObject->GetMap()->GetNavMesh();

        if(!m_navMesh)
        {
            // can't pathfind if navmesh doesn't exist
            shortcut();
            return;
        }
    }

    if(!m_pathPolyRefs)
    {
        // path was not built before, most likely because navmesh wasn't working
        // start from scratch, then return
        Build();
        return;
    }

    // should be safe to update path now

    bool startOffPath = false;
    bool endOffPath = false;

    // find start and end poly
    // navMesh.findNearestPoly is expensive, so first we check just the current path
    getStartPosition(x, y, z);
    dtPolyRef startPoly = getPathPolyByPosition(x, y, z);
    getEndPosition(x, y, z);
    dtPolyRef endPoly = getPathPolyByPosition(x, y, z);

    if(startPoly != 0 && endPoly != 0)
        trim(startPoly, endPoly);
    else
    {
        // start or end is off the path, need to find the polygon

        float extents[3] = {2.f, 4.f, 2.f};      // bounds of poly search area
        dtQueryFilter filter = dtQueryFilter();     // filter for poly search

        if(!startPoly)
        {
            getStartPosition(x, y, z);
            float startPos[3] = {y, z, x};
            startOffPath = true;
            startPoly = m_navMesh->findNearestPoly(startPos, extents, &filter, 0);
        }
        if(!endPoly)
        {
            getEndPosition(x, y, z);
            float endPos[3] = {y, z, x};
            endOffPath = true;
            endPoly = m_navMesh->findNearestPoly(endPos, extents, &filter, 0);
        }

        if(startPoly == 0 || endPoly == 0)
        {
            // source or dest not near navmesh polygons:
            // flying, falling, swimming, or navmesh has a hole

            // ignore obstacles/terrain is better than giving up
            // PATHFIND TODO: prevent walking/swimming mobs from flying into the air
            shortcut();
            return;
        }
    }

    if(startPoly == endPoly)
    {
        // start and end are on same polygon
        // just need to move in straight line

        // PATHFIND TODO: prevent walking/swimming mobs from flying into the air

        clear();
        m_pathPolyRefs = new dtPolyRef[1];
        m_pathPolyRefs[0] = startPoly;
        m_length = 1;
        getEndPosition(x, y, z);
        setNextPosition(x, y, z);
        m_type = PathType(m_type | PATHFIND_NORMAL);
        return;
    }

    if(startOffPath)
    {
        bool adjacent = false;
        int i;
        for(i = 0; i < DT_VERTS_PER_POLYGON; ++i)
            if(startPoly == m_navMesh->getPolyByRef(m_pathPolyRefs[0])->neis[i])
            {
                adjacent = true;
                break;
            }

        if(adjacent)
        {
            // startPoly is adjacent to the path, we can add it to the start of the path
            // 50th poly will fall off of path, shouldn't be an issue because most paths aren't that long
            m_length = m_length < MAX_PATH_LENGTH ? m_length + 1 : m_length;
            dtPolyRef* temp = new dtPolyRef[m_length];
            temp[0] = startPoly;

            for(i = 1; i < m_length; ++i)
                temp[i] = m_pathPolyRefs[i - 1];

            delete [] m_pathPolyRefs;
            m_pathPolyRefs = temp;
        }
        else
        {
            // waste of time to optimize, just find brand new path
            Build(startPoly, endPoly);
            return;
        }
    }

    if(endOffPath)
    {
        bool adjacent = false;
        int i;
        for(i = 0; i < DT_VERTS_PER_POLYGON; ++i)
            if(startPoly == m_navMesh->getPolyByRef(m_pathPolyRefs[0])->neis[i])
            {
                adjacent = true;
                break;
            }

        if(adjacent)
        {
            if(m_length < MAX_PATH_LENGTH)
            {
                // endPoly is adjacent to the path, and we have enough room to add it to the end
                dtPolyRef* temp = new dtPolyRef[m_length + 1];
                for(i = 0; i < m_length; ++i)
                    temp[i] = m_pathPolyRefs[i];

                temp[i] = endPoly;

                delete [] m_pathPolyRefs;
                m_pathPolyRefs = temp;
            }
            //else
            //    ;   // endPoly is adjacent to the path, we just don't have room to store it
        }
        else
        {
            // waste of time to optimize, just find brand new path
            Build(startPoly, endPoly);
            return;
        }
    }

    updateNextPosition();
}
Example #17
0
void PathFinder::BuildPointPath(const float *startPoint, const float *endPoint)
{
    float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
    uint32 pointCount = 0;
    dtStatus dtResult = DT_FAILURE;
    if(m_useStraightPath)
    {
        dtResult = m_navMeshQuery->findStraightPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // lenth of current path
                pathPoints,         // [out] path corner points
                NULL,               // [out] flags
                NULL,               // [out] shortened path
                (int*)&pointCount,
                m_pointPathLimit);   // maximum number of points/polygons to use
    }
    else
    {
        dtResult = findSmoothPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // length of current path
                pathPoints,         // [out] path corner points
                (int*)&pointCount,
                m_pointPathLimit);    // maximum number of points
    }

    if(pointCount < 2 || dtResult != DT_SUCCESS)
    {
        // only happens if pass bad data to findStraightPath or navmesh is broken
        // single point paths can be generated here
        // TODO : check the exact cases
        sLog->outDebug(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath FAILED! path sized %d returned\n", pointCount);
        BuildShortcut();
        m_type = PATHFIND_NOPATH;
        return;
    }

    m_pathPoints.resize(pointCount);
    for(uint32 i = 0; i < pointCount; ++i)
        m_pathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);

    // first point is always our current location - we need the next one
    setActualEndPosition(m_pathPoints[pointCount-1]);

    // force the given destination, if needed
    if(m_forceDestination &&
        (!(m_type & PATHFIND_NORMAL) || !inRange(getEndPosition(), getActualEndPosition(), 1.0f, 1.0f)))
    {
        // we may want to keep partial subpath
        if(dist3DSqr(getActualEndPosition(), getEndPosition()) <
            0.3f * dist3DSqr(getStartPosition(), getEndPosition()))
        {
            setActualEndPosition(getEndPosition());
            m_pathPoints[m_pathPoints.size()-1] = getEndPosition();
        }
        else
        {
            setActualEndPosition(getEndPosition());
            BuildShortcut();
        }

        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
    }

    sLog->outDebug(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath path type %d size %d poly-size %d\n", m_type, pointCount, m_polyLength);
}
Example #18
0
void PathInfo::BuildPointPath(float *startPoint, float *endPoint)
{
    float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
    uint32 pointCount = 0;
    dtStatus dtResult = DT_FAILURE;
    bool usedOffmesh = false;
    if (m_useStraightPath)
    {
        dtResult = m_navMeshQuery->findStraightPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // lenth of current path
                pathPoints,         // [out] path corner points
                NULL,               // [out] flags
                NULL,               // [out] shortened path
                (int*)&pointCount,
                MAX_POINT_PATH_LENGTH);   // maximum number of points/polygons to use
    }
    else
    {
        dtResult = findSmoothPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // length of current path
                pathPoints,         // [out] path corner points
                (int*)&pointCount,
                usedOffmesh,
                MAX_POINT_PATH_LENGTH);    // maximum number of points
    }

    if (pointCount < 2 || dtResult != DT_SUCCESS)
    {
        // only happens if pass bad data to findStraightPath or navmesh is broken
        // single point paths can be generated here
        // TODO : check the exact cases
        DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathInfo::BuildPointPath FAILED! path sized %d returned\n", pointCount);
        BuildShortcut();
        m_type = PATHFIND_NOPATH;
        return;
    }

    // we need to flash our poly path to prevent it being used as subpath next cycle
    // in case of off mesh connection was used
    if(usedOffmesh)
        m_polyLength = 0;

    m_pathPoints.resize(pointCount);
    for (uint32 i = 0; i < pointCount; ++i)
        m_pathPoints.set(i, PathNode(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]));

    // first point is always our current location - we need the next one
    setNextPosition(m_pathPoints[1]);
    setActualEndPosition(m_pathPoints[pointCount-1]);

    // force the given destination, if needed
    if(m_forceDestination &&
        (!(m_type & PATHFIND_NORMAL) || !inRange(getEndPosition(), getActualEndPosition(), 1.0f, 1.0f)))
    {
        setActualEndPosition(getEndPosition());
        BuildShortcut();
        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
        return;
    }

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathInfo::BuildPointPath path type %d size %d poly-size %d\n", m_type, pointCount, m_polyLength);
}
Example #19
0
void PathInfo::updateNextPosition()
{
    float x, y, z;

    getStartPosition(x, y, z);
    float startPos[3] = {y, z, x};
    getEndPosition(x, y, z);
    float endPos[3] = {y, z, x};

    float* pathPoints = new float[MAX_PATH_LENGTH*3];
    int pointCount = m_navMesh->findStraightPath(
        startPos,           // start position
        endPos,             // end position
        m_pathPolyRefs,     // current path
        m_length,           // lenth of current path
        pathPoints,         // [out] path corner points
        0,                  // [out] flags
        0,                  // [out] shortened path  PATHFIND TODO: see if this is usable (IE, doesn't leave gaps in path)
        MAX_PATH_LENGTH);   // maximum number of points/polygons to use

    // TODO: imitate PATHFIND_ITER code from RecastDemo so that terrain following is smoother

    if(pointCount == 0)
    {
        delete [] pathPoints;

        // only happens if pass bad data to findStraightPath or navmesh is broken
        sLog.outDebug("%u's UpdateNextPosition failed: 0 length path", m_sourceObject->GetGUID());
        shortcut();
        return;
    }

    int ix, iy, iz;
    if(pointCount == 1)
    {
        ix = 2; iy = 0; iz = 1;
    }
    else
    {
        ix = 5; iy = 3; iz = 4;
    }

    setNextPosition(pathPoints[ix], pathPoints[iy], pathPoints[iz]);

    // if startPosition == nextPosition, NPC will never advance to destination
    if(isSamePoint(m_startPosition, m_nextPosition) && !isSamePoint(m_nextPosition, m_endPosition))
        setNextPosition(pathPoints[ix + 3], pathPoints[iy + 3], pathPoints[iz + 3]);

    delete [] m_pathPoints;
    m_pathPoints = pathPoints;

    m_type = PathType(m_type | PATHFIND_NORMAL);

    // if end position from findStraightPath isn't the
    // place we want to go, there is likely no path
    endPos[0] = pathPoints[(pointCount-1)*3+2];
    endPos[1] = pathPoints[(pointCount-1)*3];
    endPos[2] = pathPoints[(pointCount-1)*3+1];
    if(!dtVequal(endPos, m_endPosition))
        m_type = PathType(m_type | PATHFIND_NOPATH);
}
void PathFinderMovementGenerator::BuildPointPath(const float *startPoint, const float *endPoint)
{
    float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
    uint32 pointCount = 0;
    dtStatus dtResult = DT_FAILURE;
    if (m_useStraightPath)
    {
        dtResult = m_navMeshQuery->findStraightPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // lenth of current path
                pathPoints,         // [out] path corner points
                NULL,               // [out] flags
                NULL,               // [out] shortened path
                (int*)&pointCount,
                m_pointPathLimit);   // maximum number of points/polygons to use
    }
    else
    {
        dtResult = findSmoothPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // length of current path
                pathPoints,         // [out] path corner points
                (int*)&pointCount,
                m_pointPathLimit);    // maximum number of points
    }

    if (pointCount < 2 || dtResult != DT_SUCCESS)
    {
        // only happens if pass bad data to findStraightPath or navmesh is broken
        // single point paths can be generated here
        // TODO : check the exact cases
        sLog->outDebug(LOG_FILTER_MAPS, "++ PathFinderMovementGenerator::BuildPointPath FAILED! path sized %d returned\n", pointCount);
        BuildShortcut();
        m_type = PATHFIND_NOPATH;
        return;
    }
    else if (pointCount == m_pointPathLimit)
    {
        sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned, lower than limit set to %d\n", pointCount, m_pointPathLimit);
        BuildShortcut();
        m_type = PATHFIND_SHORT;
        return;
    }

    m_pathPoints.resize(pointCount);
    for (uint32 i = 0; i < pointCount; ++i)
        m_pathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);

    // first point is always our current location - we need the next one
    setActualEndPosition(m_pathPoints[pointCount-1]);

    // force the given destination, if needed
    if(m_forceDestination &&
        (!(m_type & PATHFIND_NORMAL) || !inRange(getEndPosition(), getActualEndPosition(), 1.0f, 1.0f)))
    {
        // we may want to keep partial subpath
        if(dist3DSqr(getActualEndPosition(), getEndPosition()) <
            0.3f * dist3DSqr(getStartPosition(), getEndPosition()))
        {
            setActualEndPosition(getEndPosition());
            m_pathPoints[m_pathPoints.size()-1] = getEndPosition();
        }
        else
        {
            setActualEndPosition(getEndPosition());
            BuildShortcut();
        }

        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
    }

	// Custom point for bugged zone - start
    float startEndDist = dist3DSqr(getStartPosition(), getEndPosition());   

    // Blade's Edge Arena (mapid)
	if (m_sourceUnit->GetMapId() == 562)
    {
    	// Start & End Position
		// NAPOLOVINA RABOTESHT PILLAR
		if (startEndDist < 3000.0f && startPoint[1] >= 9.000000f && startPoint[2] <= 6234.335938f && startPoint[2] >= 6224.140430f && startPoint[0] >= 244.160000f && startPoint[0] <= 255.118940f) // southeast pillar
	    {
			clear();
            m_pathPoints.resize(4);
			m_pathPoints[0] = getStartPosition();
			m_pathPoints[1] = Vector3(6231.038574f, 252.630981f, 11.300000f);
			m_pathPoints[2] = Vector3(6234.254395f, 256.513702f, 11.280000f);
			m_pathPoints[3] = getEndPosition();
		}
		// Problemna chast:
		else if (startEndDist < 3000.0f && endPoint[1] >= 9.000000f && endPoint[2] <= 6234.335938f && endPoint[2] >= 6224.140430f && endPoint[0] >= 244.160000f && endPoint[0] <= 255.118940f) // southeast pillar
		{
			clear();
            m_pathPoints.resize(4);
		    m_pathPoints[0] = getStartPosition();
			m_pathPoints[1] = Vector3(6234.254395f, 256.513702f, 11.280000f);
			m_pathPoints[2] = Vector3(6231.038574f, 252.630981f, 11.300000f);
			m_pathPoints[3] = getEndPosition();
		}

		// RABOTESHT PILLAR 
		// TODO: (na zemqta ima mqsto na koeto Z e > 9 koeto znachi che moje da se charge i ot dolu -> fail
		if (startEndDist < 3000.0f && startPoint[1] >= 9.000000f && startPoint[2] >= 6243.385660f && startPoint[2] <= 6254.611660f && startPoint[0] >= 268.757917f && startPoint[0] <= 279.558794f) // northwest pillar
        {
    		clear();
            m_pathPoints.resize(4);
            m_pathPoints[0] = getStartPosition();
            m_pathPoints[1] = Vector3(6246.324219f, 271.570000f, 11.300000f);
            m_pathPoints[2] = Vector3(6242.942484f, 267.210030f, 11.280000f);
            m_pathPoints[3] = getEndPosition();
        } 
		else if (startEndDist < 3000.0f && endPoint[1] >= 9.000000f && endPoint[2] >= 6243.385660f && endPoint[2] <= 6254.611660f && endPoint[0] >= 268.757917f && endPoint[0] <= 279.558794f) // northwest pillar
        {
		    clear();
            m_pathPoints.resize(4);
            m_pathPoints[0] = getStartPosition();
            m_pathPoints[1] = Vector3(6242.942484f, 267.210030f, 11.280000f);
            m_pathPoints[2] = Vector3(6246.324219f, 271.570000f, 11.300000f);
            m_pathPoints[3] = getEndPosition();
        }
    }
    // Dalaran Sewers
    if (m_sourceUnit->GetMapId() == 617)
    {
        if (startPoint[2] >= 1330.033223f && startPoint[1] >= 9.000000f)      // Canal 1#
        {
            //  Path x,y,z
            m_pathPoints.resize(5);
            m_pathPoints[0] = getStartPosition();
            m_pathPoints[1] = Vector3(1332.749268f, 816.274780f, 8.355900f);
            m_pathPoints[2] = Vector3(1325.749268f, 816.602539f, 5.4000000f);
            m_pathPoints[3] = Vector3(1328.749268f, 816.602539f, 3.4000000f);
            m_pathPoints[4] = getEndPosition();
        }
        else if (startPoint[2] <= 1253.904785f && startPoint[1] >= 9.000000f)      // Canal 2#
        {
            //  Path x,y,z
            m_pathPoints.resize(5);
            m_pathPoints[0] = getStartPosition();
            m_pathPoints[1] = Vector3(1252.425395f, 764.971680f, 8.000000f); 
            m_pathPoints[3] = Vector3(1255.425395f, 764.971680f, 5.3559000f);
            m_pathPoints[3] = Vector3(1257.425395f, 764.971680f, 3.3559000f);
            m_pathPoints[4] = getEndPosition();
        }
    }
    // Custom point for bugged zone - end

    sLog->outDebug(LOG_FILTER_MAPS, "++ PathFinderMovementGenerator::BuildPointPath path type %d size %d poly-size %d\n", m_type, pointCount, m_polyLength);
}
void GradientLayer::draw(Graphics* const TheGraphics, const Pnt2f& TopLeft, const Pnt2f& BottomRight, const Real32 Opacity) const
{
	if(getMFColors()->size() == getMFStops()->size())
	{
		if(getMFColors()->size() == 1)
		{
			TheGraphics->drawQuad(TopLeft, Pnt2f(BottomRight.x(), TopLeft.y()), BottomRight, Pnt2f(TopLeft.x(), BottomRight.y()), getColors(0), getColors(0), getColors(0), getColors(0), Opacity);
		}
		else
		{
			Pnt2f StartPosition= TopLeft;
			StartPosition[0] += getStartPosition()[0]*(BottomRight[0] - TopLeft[0]);
			StartPosition[1] += getStartPosition()[1]*(BottomRight[1] - TopLeft[1]);
			Pnt2f EndPosition= TopLeft;
			EndPosition[0] += getEndPosition()[0]*(BottomRight[0] - TopLeft[0]);
			EndPosition[1] += getEndPosition()[1]*(BottomRight[1] - TopLeft[1]);
			
			//Calculate the coordinate system
			Vec2f u(EndPosition-StartPosition);
			u.normalize();
			Vec3f v3D(Vec3f(u.x(), u.y(), 0.0f).cross(Vec3f(0.0,0.0,-1.0)));
			Vec2f v(v3D.x(), v3D.y());
			Matrix22<Real32> CoordinateSystem(u.x(), u.y(), v.x(), v.y());

			Pnt2f Min;
			Pnt2f Max;
			{
				//Calculate the bounding box in the new coordinate system
				Pnt2f UVTopLeft(CoordinateSystem*TopLeft), 
					UVBottomRight(CoordinateSystem*BottomRight), 
					UVTopRight(CoordinateSystem*Vec2f(BottomRight.x(), TopLeft.y())),
					UVBottomLeft(CoordinateSystem*Vec2f(TopLeft.x(), BottomRight.y()));


				Min.setValues( osgMin(UVTopLeft.x(), osgMin(UVBottomRight.x(), osgMin(UVTopRight.x(), UVBottomLeft.x()))),
							   osgMin(UVTopLeft.y(), osgMin(UVBottomRight.y(), osgMin(UVTopRight.y(), UVBottomLeft.y()))));
				Max.setValues( osgMax(UVTopLeft.x(), osgMax(UVBottomRight.x(), osgMax(UVTopRight.x(), UVBottomLeft.x()))),
							   osgMax(UVTopLeft.y(), osgMax(UVBottomRight.y(), osgMax(UVTopRight.y(), UVBottomLeft.y()))));
			}

			Pnt2f Origin(CoordinateSystem.inverse() * Min);
			Real32 PreStartLength(((CoordinateSystem*StartPosition).x()-Min.x())/(Max.x() - Min.x())),
				   PostEndLength((Max.x()- (CoordinateSystem*EndPosition).x())/(Max.x() - Min.x())),
				   GradientLength(1.0f-PostEndLength-PreStartLength);
			
			if(getSpreadMethod() == SPREAD_REFLECT||
			   getSpreadMethod() == SPREAD_REPEAT)
			{
				//Code for drawing the Gradient with Repeating/Reflection
					//Determine the Number of Repeats
					UInt32 RepeatCount = static_cast<UInt32>(osgCeil(1.0f/GradientLength));

					//Determine the relative location in the gradient that the Start left is at
					Real32 StartGradientLocation = PreStartLength - GradientLength * osgCeil(PreStartLength/GradientLength);

					//Determine whether the start is a reflection or normal
					bool isReflection = getSpreadMethod() == SPREAD_REFLECT && static_cast<UInt32>(osgCeil(PreStartLength/GradientLength))%2==1;

					for(UInt32 i(0) ; i<RepeatCount ; ++i)
					{
						if(isReflection)
						{
							drawGradient(TheGraphics, Origin, Max-Min,u,StartGradientLocation+GradientLength*(i+1),StartGradientLocation+GradientLength*i,Opacity);					
						}
						else
						{
							drawGradient(TheGraphics, Origin, Max-Min,u,StartGradientLocation+GradientLength*i,StartGradientLocation+GradientLength*(i+1),Opacity);					
						}

						if(getSpreadMethod() == SPREAD_REFLECT)
						{
							isReflection = !isReflection;
						}
					}
				
			}
			else
			{
				//Code for drawing the Gradient with Padding
				
				//Front Pad
				if(PreStartLength != 0.0f)
				{
					drawPad(TheGraphics, Origin,
                            Max-Min,u,0.0,PreStartLength,getMFColors()->front(),Opacity);
				}
				
				drawGradient(TheGraphics, Origin, Max-Min,u,PreStartLength,PreStartLength+GradientLength,Opacity);
				
				//End Pad
				if(PostEndLength != 0.0f)
				{
					drawPad(TheGraphics, Origin, Max-Min,u,PreStartLength+GradientLength,1.0,getMFColors()->back(),Opacity);
				}
			}
		}
	}
}
Example #22
0
void PathInfo::Build(dtPolyRef startPoly, dtPolyRef endPoly)
{
    clear();

    float x, y, z;

    if(startPoly == 0 || endPoly == 0)
    {
        // polygon didn't touch the search box
        // could mean start or end has...
        //     (x,y) outside navmesh
        //     (z) above/below the navmesh
        sLog.outDebug("%u's Path Build failed: invalid start or end polygon", m_sourceObject->GetGUID());
        //if(canFly())    // TODO
            shortcut();
        return;
    }

    getStartPosition(x, y, z);
    float startPos[3] = {y, z, x};
    getEndPosition(x, y, z);
    float endPos[3] = {y, z, x};

    bool startOffPoly, endOffPoly;
    float distanceStart, distanceEnd;
    startOffPoly = !isPointInPolyBounds(startPos[2], startPos[0], startPos[1], distanceStart, startPoly);
    endOffPoly = !isPointInPolyBounds(endPos[2], endPos[0], endPos[1], distanceEnd, endPoly);

    dtQueryFilter filter = createFilter();      // use special filter so we use proper terrain types

    dtPolyRef pathPolys[MAX_PATH_LENGTH];
    m_length = m_navMesh->findPath(
        startPoly,          // start polygon
        endPoly,            // end polygon
        startPos,           // start position
        endPos,             // end position
        &filter,            // polygon search filter
        pathPolys,          // [out] path
        MAX_PATH_LENGTH);   // max number of polygons in output path

    if(m_length == 0)
    {
        // only happens if we passed bad data to findPath(), or navmesh is messed up
        sLog.outDebug("%u's Path Build failed: 0-length path", m_sourceObject->GetGUID());
        shortcut();
        return;
    }

    // pathPolyRefs was deleted when we entered Build(dtPolyRef, dtPolyRef)
    m_pathPolyRefs = new dtPolyRef[m_length];

    int i;
    for(i = 0; i < m_length; ++i)
        m_pathPolyRefs[i] = pathPolys[i];

    updateNextPosition();

    if(m_length >= MAX_PATH_LENGTH)
        m_type = PathType(m_type | PATHFIND_INCOMPLETE);

    m_currentNode = 0;
}
Example #23
0
void PathFinder::BuildPointPath(const float* startPoint, const float* endPoint)
{
    float pathPoints[MAX_POINT_PATH_LENGTH * VERTEX_SIZE];
    uint32 pointCount = 0;
    dtStatus dtResult = DT_FAILURE;
    if (m_useStraightPath)
    {
        dtResult = m_navMeshQuery->findStraightPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // lenth of current path
                pathPoints,         // [out] path corner points
                NULL,               // [out] flags
                NULL,               // [out] shortened path
                (int*)&pointCount,
                m_pointPathLimit);   // maximum number of points/polygons to use
    }
    else
    {
        dtResult = findSmoothPath(
                startPoint,         // start position
                endPoint,           // end position
                m_pathPolyRefs,     // current path
                m_polyLength,       // length of current path
                pathPoints,         // [out] path corner points
                (int*)&pointCount,
                m_pointPathLimit);    // maximum number of points
    }

    if (pointCount < 2 || dtStatusFailed(dtResult))
    {
        // only happens if pass bad data to findStraightPath or navmesh is broken
        // single point paths can be generated here
        // TODO : check the exact cases
        DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath FAILED! path sized %d returned\n", pointCount);
        BuildShortcut();
        m_type = PATHFIND_NOPATH;
        return;
    }

    uint32 tempPointCounter = 2;
    uint8  cutLimit         = 0;

    PointsArray    tempPathPoints;
    tempPathPoints.resize(pointCount);

    for (uint32 i = 0; i < pointCount; ++i)
        tempPathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);

    // Optimize points
    for (uint32 i = 1; i < pointCount - 1; ++i)
    {
        G3D::Vector3 p  = tempPathPoints[i];     // Point        
        G3D::Vector3 p1 = tempPathPoints[i - 1]; // PrevPoint
        G3D::Vector3 p2 = tempPathPoints[i + 1]; // NextPoint

        float line = (p1.y - p2.y) * p.x + (p2.x - p1.x) * p.y + (p1.x * p2.y - p2.x * p1.y);

        if (fabs(line) < LINE_FAULT && cutLimit < SKIP_POINT_LIMIT)
        {
            tempPathPoints[i] = Vector3(0, 0, 0);
            ++cutLimit;
        }
        else
        {
            ++tempPointCounter;
            cutLimit = 0;
        }
    }

    m_pathPoints.resize(tempPointCounter);

    uint32 b = 0;
    for (uint32 i = 0; i < pointCount; ++i)
    {
        if (tempPathPoints[i] != Vector3(0, 0, 0))
        {
            m_pathPoints[b] = tempPathPoints[i];
            ++b;
        }
    }

    pointCount = tempPointCounter;

    // first point is always our current location - we need the next one
    setActualEndPosition(m_pathPoints[pointCount - 1]);

    // force the given destination, if needed
    if (m_forceDestination &&
        (!(m_type & PATHFIND_NORMAL) || !inRange(getEndPosition(), getActualEndPosition(), 1.0f, 1.0f)))
    {
        // we may want to keep partial subpath
        if (dist3DSqr(getActualEndPosition(), getEndPosition()) <
            0.3f * dist3DSqr(getStartPosition(), getEndPosition()))
        {
            setActualEndPosition(getEndPosition());
            m_pathPoints[m_pathPoints.size()-1] = getEndPosition();
        }
        else
        {
            setActualEndPosition(getEndPosition());
            BuildShortcut();
        }

        m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
    }

    DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath path type %d size %d poly-size %d\n", m_type, pointCount, m_polyLength);
}