mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 07:03:44 +02:00
split EntityPriorityQueue stuff into separate file
This commit is contained in:
parent
64cd209835
commit
abf968aab6
4 changed files with 262 additions and 230 deletions
170
assignment-client/src/entities/EntityPriorityQueue.cpp
Normal file
170
assignment-client/src/entities/EntityPriorityQueue.cpp
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
//
|
||||||
|
// EntityPriorityQueue.cpp
|
||||||
|
// assignment-client/src/entities
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2017.08.08
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EntityPriorityQueue.h"
|
||||||
|
|
||||||
|
const float DO_NOT_SEND = -1.0e-6f;
|
||||||
|
|
||||||
|
void ConicalView::set(const ViewFrustum& viewFrustum) {
|
||||||
|
// The ConicalView has two parts: a central sphere (same as ViewFrustm) and a circular cone that bounds the frustum part.
|
||||||
|
// Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum.
|
||||||
|
_position = viewFrustum.getPosition();
|
||||||
|
_direction = viewFrustum.getDirection();
|
||||||
|
|
||||||
|
// We cache the sin and cos of the half angle of the cone that bounds the frustum.
|
||||||
|
// (the math here is left as an exercise for the reader)
|
||||||
|
float A = viewFrustum.getAspectRatio();
|
||||||
|
float t = tanf(0.5f * viewFrustum.getFieldOfView());
|
||||||
|
_cosAngle = 1.0f / sqrtf(1.0f + (A * A + 1.0f) * (t * t));
|
||||||
|
_sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle);
|
||||||
|
|
||||||
|
_radius = viewFrustum.getCenterRadius();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ConicalView::computePriority(const AACube& cube) const {
|
||||||
|
glm::vec3 p = cube.calcCenter() - _position; // position of bounding sphere in view-frame
|
||||||
|
float d = glm::length(p); // distance to center of bounding sphere
|
||||||
|
float r = 0.5f * cube.getScale(); // radius of bounding sphere
|
||||||
|
if (d < _radius + r) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (glm::dot(p, _direction) > sqrtf(d * d - r * r) * _cosAngle - r * _sinAngle) {
|
||||||
|
const float AVOID_DIVIDE_BY_ZERO = 0.001f;
|
||||||
|
return r / (d + AVOID_DIVIDE_BY_ZERO);
|
||||||
|
}
|
||||||
|
return DO_NOT_SEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
float ConicalView::computePriority(const EntityItemPointer& entity) const {
|
||||||
|
assert(entity);
|
||||||
|
bool success;
|
||||||
|
AACube cube = entity->getQueryAACube(success);
|
||||||
|
if (success) {
|
||||||
|
return computePriority(cube);
|
||||||
|
} else {
|
||||||
|
// when in doubt give it something positive
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float PrioritizedEntity::updatePriority(const ConicalView& conicalView) {
|
||||||
|
EntityItemPointer entity = _weakEntity.lock();
|
||||||
|
if (entity) {
|
||||||
|
_priority = conicalView.computePriority(entity);
|
||||||
|
} else {
|
||||||
|
_priority = DO_NOT_SEND;
|
||||||
|
}
|
||||||
|
return _priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraversalWaypoint::TraversalWaypoint(EntityTreeElementPointer& element) : _nextIndex(0) {
|
||||||
|
assert(element);
|
||||||
|
_weakElement = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraversalWaypoint::getNextVisibleElementFirstTime(VisibleElement& next, const ViewFrustum& view) {
|
||||||
|
// NOTE: no need to set next.intersection in the "FirstTime" context
|
||||||
|
if (_nextIndex == -1) {
|
||||||
|
// only get here for the root TraversalWaypoint at the very beginning of traversal
|
||||||
|
// safe to assume this element intersects view
|
||||||
|
++_nextIndex;
|
||||||
|
next.element = _weakElement.lock();
|
||||||
|
return;
|
||||||
|
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer element = _weakElement.lock();
|
||||||
|
if (element) {
|
||||||
|
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||||
|
++_nextIndex;
|
||||||
|
if (nextElement && view.cubeIntersectsKeyhole(nextElement->getAACube())) {
|
||||||
|
next.element = nextElement;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.element.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraversalWaypoint::getNextVisibleElementAgain(VisibleElement& next, const ViewFrustum& view, uint64_t lastTime) {
|
||||||
|
if (_nextIndex == -1) {
|
||||||
|
// only get here for the root TraversalWaypoint at the very beginning of traversal
|
||||||
|
// safe to assume this element intersects view
|
||||||
|
++_nextIndex;
|
||||||
|
EntityTreeElementPointer element = _weakElement.lock();
|
||||||
|
// root case is special: its intersection is always INTERSECT
|
||||||
|
// and we can skip it if the content hasn't changed
|
||||||
|
if (element->getLastChangedContent() > lastTime) {
|
||||||
|
next.element = element;
|
||||||
|
next.intersection = ViewFrustum::INTERSECT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer element = _weakElement.lock();
|
||||||
|
if (element) {
|
||||||
|
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||||
|
++_nextIndex;
|
||||||
|
if (nextElement && nextElement->getLastChanged() > lastTime) {
|
||||||
|
ViewFrustum::intersection intersection = view.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
||||||
|
if (intersection != ViewFrustum::OUTSIDE) {
|
||||||
|
next.element = nextElement;
|
||||||
|
next.intersection = intersection;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.element.reset();
|
||||||
|
next.intersection = ViewFrustum::OUTSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraversalWaypoint::getNextVisibleElementDifferential(VisibleElement& next,
|
||||||
|
const ViewFrustum& view, const ViewFrustum& lastView, uint64_t lastTime) {
|
||||||
|
if (_nextIndex == -1) {
|
||||||
|
// only get here for the root TraversalWaypoint at the very beginning of traversal
|
||||||
|
// safe to assume this element intersects view
|
||||||
|
++_nextIndex;
|
||||||
|
EntityTreeElementPointer element = _weakElement.lock();
|
||||||
|
// root case is special: its intersection is always INTERSECT
|
||||||
|
// and we can skip it if the content hasn't changed
|
||||||
|
if (element->getLastChangedContent() > lastTime) {
|
||||||
|
next.element = element;
|
||||||
|
next.intersection = ViewFrustum::INTERSECT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer element = _weakElement.lock();
|
||||||
|
if (element) {
|
||||||
|
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
||||||
|
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
||||||
|
++_nextIndex;
|
||||||
|
if (nextElement) {
|
||||||
|
AACube cube = nextElement->getAACube();
|
||||||
|
// NOTE: for differential case next.intersection is against the _completedView
|
||||||
|
ViewFrustum::intersection intersection = lastView.calculateCubeKeyholeIntersection(cube);
|
||||||
|
if ( lastView.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE &&
|
||||||
|
!(intersection == ViewFrustum::INSIDE && nextElement->getLastChanged() < lastTime)) {
|
||||||
|
next.element = nextElement;
|
||||||
|
next.intersection = intersection;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.element.reset();
|
||||||
|
next.intersection = ViewFrustum::OUTSIDE;
|
||||||
|
}
|
86
assignment-client/src/entities/EntityPriorityQueue.h
Normal file
86
assignment-client/src/entities/EntityPriorityQueue.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// EntityPriorityQueue.h
|
||||||
|
// assignment-client/src/entities
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows 2017.08.08
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_EntityPriorityQueue_h
|
||||||
|
#define hifi_EntityPriorityQueue_h
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#include <AACube.h>
|
||||||
|
|
||||||
|
#include "EntityTreeElement.h"
|
||||||
|
|
||||||
|
const float SQRT_TWO_OVER_TWO = 0.7071067811865;
|
||||||
|
const float DEFAULT_VIEW_RADIUS = 10.0f;
|
||||||
|
|
||||||
|
// ConicalView is an approximation of a ViewFrustum for fast calculation of sort priority.
|
||||||
|
class ConicalView {
|
||||||
|
public:
|
||||||
|
ConicalView() {}
|
||||||
|
ConicalView(const ViewFrustum& viewFrustum) { set(viewFrustum); }
|
||||||
|
void set(const ViewFrustum& viewFrustum);
|
||||||
|
float computePriority(const AACube& cube) const;
|
||||||
|
float computePriority(const EntityItemPointer& entity) const;
|
||||||
|
private:
|
||||||
|
glm::vec3 _position { 0.0f, 0.0f, 0.0f };
|
||||||
|
glm::vec3 _direction { 0.0f, 0.0f, 1.0f };
|
||||||
|
float _sinAngle { SQRT_TWO_OVER_TWO };
|
||||||
|
float _cosAngle { SQRT_TWO_OVER_TWO };
|
||||||
|
float _radius { DEFAULT_VIEW_RADIUS };
|
||||||
|
};
|
||||||
|
|
||||||
|
// PrioritizedEntity is a placeholder in a sorted queue.
|
||||||
|
class PrioritizedEntity {
|
||||||
|
public:
|
||||||
|
PrioritizedEntity(EntityItemPointer entity, float priority) : _weakEntity(entity), _priority(priority) { }
|
||||||
|
float updatePriority(const ConicalView& view);
|
||||||
|
EntityItemPointer getEntity() const { return _weakEntity.lock(); }
|
||||||
|
float getPriority() const { return _priority; }
|
||||||
|
|
||||||
|
class Compare {
|
||||||
|
public:
|
||||||
|
bool operator() (const PrioritizedEntity& A, const PrioritizedEntity& B) { return A._priority < B._priority; }
|
||||||
|
};
|
||||||
|
friend class Compare;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EntityItemWeakPointer _weakEntity;
|
||||||
|
float _priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
// VisibleElement is a struct identifying an element and how it intersected the view.
|
||||||
|
// The intersection is used to optimize culling entities from the sendQueue.
|
||||||
|
class VisibleElement {
|
||||||
|
public:
|
||||||
|
EntityTreeElementPointer element;
|
||||||
|
ViewFrustum::intersection intersection { ViewFrustum::OUTSIDE };
|
||||||
|
};
|
||||||
|
|
||||||
|
// TraversalWaypoint is an bookmark in a "path" of waypoints during a traversal.
|
||||||
|
class TraversalWaypoint {
|
||||||
|
public:
|
||||||
|
TraversalWaypoint(EntityTreeElementPointer& element);
|
||||||
|
|
||||||
|
void getNextVisibleElementFirstTime(VisibleElement& next, const ViewFrustum& view);
|
||||||
|
void getNextVisibleElementAgain(VisibleElement& next, const ViewFrustum& view, uint64_t lastTime);
|
||||||
|
void getNextVisibleElementDifferential(VisibleElement& next, const ViewFrustum& view, const ViewFrustum& lastView, uint64_t lastTime);
|
||||||
|
|
||||||
|
int8_t getNextIndex() const { return _nextIndex; }
|
||||||
|
void initRootNextIndex() { _nextIndex = -1; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EntityTreeElementWeakPointer _weakElement;
|
||||||
|
int8_t _nextIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
using EntityPriorityQueue = std::priority_queue< PrioritizedEntity, std::vector<PrioritizedEntity>, PrioritizedEntity::Compare >;
|
||||||
|
|
||||||
|
#endif // hifi_EntityPriorityQueue_h
|
|
@ -17,165 +17,6 @@
|
||||||
|
|
||||||
#include "EntityServer.h"
|
#include "EntityServer.h"
|
||||||
|
|
||||||
const float DO_NOT_SEND = -1.0e-6f;
|
|
||||||
|
|
||||||
void ConicalView::set(const ViewFrustum& viewFrustum) {
|
|
||||||
// The ConicalView has two parts: a central sphere (same as ViewFrustm) and a circular cone that bounds the frustum part.
|
|
||||||
// Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum.
|
|
||||||
_position = viewFrustum.getPosition();
|
|
||||||
_direction = viewFrustum.getDirection();
|
|
||||||
|
|
||||||
// We cache the sin and cos of the half angle of the cone that bounds the frustum.
|
|
||||||
// (the math here is left as an exercise for the reader)
|
|
||||||
float A = viewFrustum.getAspectRatio();
|
|
||||||
float t = tanf(0.5f * viewFrustum.getFieldOfView());
|
|
||||||
_cosAngle = 1.0f / sqrtf(1.0f + (A * A + 1.0f) * (t * t));
|
|
||||||
_sinAngle = sqrtf(1.0f - _cosAngle * _cosAngle);
|
|
||||||
|
|
||||||
_radius = viewFrustum.getCenterRadius();
|
|
||||||
}
|
|
||||||
|
|
||||||
float ConicalView::computePriority(const AACube& cube) const {
|
|
||||||
glm::vec3 p = cube.calcCenter() - _position; // position of bounding sphere in view-frame
|
|
||||||
float d = glm::length(p); // distance to center of bounding sphere
|
|
||||||
float r = 0.5f * cube.getScale(); // radius of bounding sphere
|
|
||||||
if (d < _radius + r) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (glm::dot(p, _direction) > sqrtf(d * d - r * r) * _cosAngle - r * _sinAngle) {
|
|
||||||
const float AVOID_DIVIDE_BY_ZERO = 0.001f;
|
|
||||||
return r / (d + AVOID_DIVIDE_BY_ZERO);
|
|
||||||
}
|
|
||||||
return DO_NOT_SEND;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// static
|
|
||||||
float ConicalView::computePriority(const EntityItemPointer& entity) const {
|
|
||||||
assert(entity);
|
|
||||||
bool success;
|
|
||||||
AACube cube = entity->getQueryAACube(success);
|
|
||||||
if (success) {
|
|
||||||
return computePriority(cube);
|
|
||||||
} else {
|
|
||||||
// when in doubt give it something positive
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float PrioritizedEntity::updatePriority(const ConicalView& conicalView) {
|
|
||||||
EntityItemPointer entity = _weakEntity.lock();
|
|
||||||
if (entity) {
|
|
||||||
_priority = conicalView.computePriority(entity);
|
|
||||||
} else {
|
|
||||||
_priority = DO_NOT_SEND;
|
|
||||||
}
|
|
||||||
return _priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
Fork::Fork(EntityTreeElementPointer& element) : _nextIndex(0) {
|
|
||||||
assert(element);
|
|
||||||
_weakElement = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fork::getNextVisibleElementFirstTime(VisibleElement& next, const ViewFrustum& view) {
|
|
||||||
// NOTE: no need to set next.intersection in the "FirstTime" context
|
|
||||||
if (_nextIndex == -1) {
|
|
||||||
// only get here for the root Fork at the very beginning of traversal
|
|
||||||
// safe to assume this element intersects view
|
|
||||||
++_nextIndex;
|
|
||||||
next.element = _weakElement.lock();
|
|
||||||
return;
|
|
||||||
} else if (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer element = _weakElement.lock();
|
|
||||||
if (element) {
|
|
||||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
|
||||||
++_nextIndex;
|
|
||||||
if (nextElement && view.cubeIntersectsKeyhole(nextElement->getAACube())) {
|
|
||||||
next.element = nextElement;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next.element.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fork::getNextVisibleElementAgain(VisibleElement& next, const ViewFrustum& view, uint64_t lastTime) {
|
|
||||||
if (_nextIndex == -1) {
|
|
||||||
// only get here for the root Fork at the very beginning of traversal
|
|
||||||
// safe to assume this element intersects view
|
|
||||||
++_nextIndex;
|
|
||||||
EntityTreeElementPointer element = _weakElement.lock();
|
|
||||||
// root case is special: its intersection is always INTERSECT
|
|
||||||
// and we can skip it if the content hasn't changed
|
|
||||||
if (element->getLastChangedContent() > lastTime) {
|
|
||||||
next.element = element;
|
|
||||||
next.intersection = ViewFrustum::INTERSECT;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer element = _weakElement.lock();
|
|
||||||
if (element) {
|
|
||||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
|
||||||
++_nextIndex;
|
|
||||||
if (nextElement && nextElement->getLastChanged() > lastTime) {
|
|
||||||
ViewFrustum::intersection intersection = view.calculateCubeKeyholeIntersection(nextElement->getAACube());
|
|
||||||
if (intersection != ViewFrustum::OUTSIDE) {
|
|
||||||
next.element = nextElement;
|
|
||||||
next.intersection = intersection;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next.element.reset();
|
|
||||||
next.intersection = ViewFrustum::OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fork::getNextVisibleElementDifferential(VisibleElement& next,
|
|
||||||
const ViewFrustum& view, const ViewFrustum& lastView, uint64_t lastTime) {
|
|
||||||
if (_nextIndex == -1) {
|
|
||||||
// only get here for the root Fork at the very beginning of traversal
|
|
||||||
// safe to assume this element intersects view
|
|
||||||
++_nextIndex;
|
|
||||||
EntityTreeElementPointer element = _weakElement.lock();
|
|
||||||
// root case is special: its intersection is always INTERSECT
|
|
||||||
// and we can skip it if the content hasn't changed
|
|
||||||
if (element->getLastChangedContent() > lastTime) {
|
|
||||||
next.element = element;
|
|
||||||
next.intersection = ViewFrustum::INTERSECT;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer element = _weakElement.lock();
|
|
||||||
if (element) {
|
|
||||||
while (_nextIndex < NUMBER_OF_CHILDREN) {
|
|
||||||
EntityTreeElementPointer nextElement = element->getChildAtIndex(_nextIndex);
|
|
||||||
++_nextIndex;
|
|
||||||
if (nextElement) {
|
|
||||||
AACube cube = nextElement->getAACube();
|
|
||||||
// NOTE: for differential case next.intersection is against the _completedView
|
|
||||||
ViewFrustum::intersection intersection = lastView.calculateCubeKeyholeIntersection(cube);
|
|
||||||
if ( lastView.calculateCubeKeyholeIntersection(cube) != ViewFrustum::OUTSIDE &&
|
|
||||||
!(intersection == ViewFrustum::INSIDE && nextElement->getLastChanged() < lastTime)) {
|
|
||||||
next.element = nextElement;
|
|
||||||
next.intersection = intersection;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next.element.reset();
|
|
||||||
next.intersection = ViewFrustum::OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node)
|
EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node)
|
||||||
: OctreeSendThread(myServer, node) {
|
: OctreeSendThread(myServer, node) {
|
||||||
const int32_t MIN_PATH_DEPTH = 16;
|
const int32_t MIN_PATH_DEPTH = 16;
|
||||||
|
@ -454,7 +295,7 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& viewFrustum, Ent
|
||||||
|
|
||||||
_traversalPath.clear();
|
_traversalPath.clear();
|
||||||
assert(root);
|
assert(root);
|
||||||
_traversalPath.push_back(Fork(root));
|
_traversalPath.push_back(TraversalWaypoint(root));
|
||||||
// set root fork's index such that root element returned at getNextElement()
|
// set root fork's index such that root element returned at getNextElement()
|
||||||
_traversalPath.back().initRootNextIndex();
|
_traversalPath.back().initRootNextIndex();
|
||||||
|
|
||||||
|
@ -472,7 +313,7 @@ void EntityTreeSendThread::getNextVisibleElement(VisibleElement& next) {
|
||||||
int8_t nextIndex = _traversalPath.back().getNextIndex();
|
int8_t nextIndex = _traversalPath.back().getNextIndex();
|
||||||
if (nextIndex > 0) {
|
if (nextIndex > 0) {
|
||||||
// next.element needs to be added to the path
|
// next.element needs to be added to the path
|
||||||
_traversalPath.push_back(Fork(next.element));
|
_traversalPath.push_back(TraversalWaypoint(next.element));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we're done at this level
|
// we're done at this level
|
||||||
|
@ -489,7 +330,7 @@ void EntityTreeSendThread::getNextVisibleElement(VisibleElement& next) {
|
||||||
_getNextVisibleElementCallback(next);
|
_getNextVisibleElementCallback(next);
|
||||||
if (next.element) {
|
if (next.element) {
|
||||||
// we've descended one level so add it to the path
|
// we've descended one level so add it to the path
|
||||||
_traversalPath.push_back(Fork(next.element));
|
_traversalPath.push_back(TraversalWaypoint(next.element));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,80 +12,15 @@
|
||||||
#ifndef hifi_EntityTreeSendThread_h
|
#ifndef hifi_EntityTreeSendThread_h
|
||||||
#define hifi_EntityTreeSendThread_h
|
#define hifi_EntityTreeSendThread_h
|
||||||
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "../octree/OctreeSendThread.h"
|
#include "../octree/OctreeSendThread.h"
|
||||||
|
|
||||||
#include <AACube.h>
|
#include "EntityPriorityQueue.h"
|
||||||
|
|
||||||
#include "EntityTreeElement.h"
|
|
||||||
|
|
||||||
const float SQRT_TWO_OVER_TWO = 0.7071067811865;
|
|
||||||
const float DEFAULT_VIEW_RADIUS = 10.0f;
|
|
||||||
|
|
||||||
class EntityNodeData;
|
class EntityNodeData;
|
||||||
class EntityItem;
|
class EntityItem;
|
||||||
|
|
||||||
|
|
||||||
class ConicalView {
|
|
||||||
public:
|
|
||||||
ConicalView() {}
|
|
||||||
ConicalView(const ViewFrustum& viewFrustum) { set(viewFrustum); }
|
|
||||||
void set(const ViewFrustum& viewFrustum);
|
|
||||||
float computePriority(const AACube& cube) const;
|
|
||||||
float computePriority(const EntityItemPointer& entity) const;
|
|
||||||
private:
|
|
||||||
glm::vec3 _position { 0.0f, 0.0f, 0.0f };
|
|
||||||
glm::vec3 _direction { 0.0f, 0.0f, 1.0f };
|
|
||||||
float _sinAngle { SQRT_TWO_OVER_TWO };
|
|
||||||
float _cosAngle { SQRT_TWO_OVER_TWO };
|
|
||||||
float _radius { DEFAULT_VIEW_RADIUS };
|
|
||||||
};
|
|
||||||
|
|
||||||
class PrioritizedEntity {
|
|
||||||
public:
|
|
||||||
PrioritizedEntity(EntityItemPointer entity, float priority) : _weakEntity(entity), _priority(priority) { }
|
|
||||||
float updatePriority(const ConicalView& view);
|
|
||||||
EntityItemPointer getEntity() const { return _weakEntity.lock(); }
|
|
||||||
float getPriority() const { return _priority; }
|
|
||||||
|
|
||||||
class Compare {
|
|
||||||
public:
|
|
||||||
bool operator() (const PrioritizedEntity& A, const PrioritizedEntity& B) { return A._priority < B._priority; }
|
|
||||||
};
|
|
||||||
friend class Compare;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntityItemWeakPointer _weakEntity;
|
|
||||||
float _priority;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VisibleElement {
|
|
||||||
public:
|
|
||||||
EntityTreeElementPointer element;
|
|
||||||
ViewFrustum::intersection intersection { ViewFrustum::OUTSIDE };
|
|
||||||
};
|
|
||||||
|
|
||||||
class Fork {
|
|
||||||
public:
|
|
||||||
Fork(EntityTreeElementPointer& element);
|
|
||||||
|
|
||||||
void getNextVisibleElementFirstTime(VisibleElement& next, const ViewFrustum& view);
|
|
||||||
void getNextVisibleElementAgain(VisibleElement& next, const ViewFrustum& view, uint64_t lastTime);
|
|
||||||
void getNextVisibleElementDifferential(VisibleElement& next, const ViewFrustum& view, const ViewFrustum& lastView, uint64_t lastTime);
|
|
||||||
|
|
||||||
int8_t getNextIndex() const { return _nextIndex; }
|
|
||||||
void initRootNextIndex() { _nextIndex = -1; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
EntityTreeElementWeakPointer _weakElement;
|
|
||||||
int8_t _nextIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
using EntityPriorityQueue = std::priority_queue< PrioritizedEntity, std::vector<PrioritizedEntity>, PrioritizedEntity::Compare >;
|
|
||||||
|
|
||||||
|
|
||||||
class EntityTreeSendThread : public OctreeSendThread {
|
class EntityTreeSendThread : public OctreeSendThread {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node);
|
EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node);
|
||||||
|
|
||||||
|
@ -107,7 +42,7 @@ private:
|
||||||
ViewFrustum _currentView;
|
ViewFrustum _currentView;
|
||||||
ViewFrustum _completedView;
|
ViewFrustum _completedView;
|
||||||
ConicalView _conicalView; // optimized view for fast priority calculations
|
ConicalView _conicalView; // optimized view for fast priority calculations
|
||||||
std::vector<Fork> _traversalPath;
|
std::vector<TraversalWaypoint> _traversalPath;
|
||||||
std::function<void (VisibleElement&)> _getNextVisibleElementCallback { nullptr };
|
std::function<void (VisibleElement&)> _getNextVisibleElementCallback { nullptr };
|
||||||
std::function<void (VisibleElement&)> _scanNextElementCallback { nullptr };
|
std::function<void (VisibleElement&)> _scanNextElementCallback { nullptr };
|
||||||
uint64_t _startOfCompletedTraversal { 0 };
|
uint64_t _startOfCompletedTraversal { 0 };
|
||||||
|
|
Loading…
Reference in a new issue