mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 13:43:49 +02:00
Merge remote-tracking branch 'upstream/master' into plugins
Conflicts: interface/src/ui/overlays/LocalModelsOverlay.cpp
This commit is contained in:
commit
95000eec3c
54 changed files with 1741 additions and 1765 deletions
|
@ -760,47 +760,6 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
statsString += QString(" Total: %1 nodes\r\n")
|
||||
.arg(locale.toString((uint)checkSum).rightJustified(16, ' '));
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
statsString += "\r\n";
|
||||
statsString += "OctreeElement Children Encoding Statistics...\r\n";
|
||||
|
||||
statsString += QString().sprintf(" Single or No Children: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getSingleChildrenCount(),
|
||||
((float)OctreeElement::getSingleChildrenCount() / (float)nodeCount) * AS_PERCENT));
|
||||
statsString += QString().sprintf(" Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getTwoChildrenOffsetCount(),
|
||||
((float)OctreeElement::getTwoChildrenOffsetCount() / (float)nodeCount) * AS_PERCENT));
|
||||
statsString += QString().sprintf(" Two Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getTwoChildrenExternalCount(),
|
||||
((float)OctreeElement::getTwoChildrenExternalCount() / (float)nodeCount) * AS_PERCENT);
|
||||
statsString += QString().sprintf(" Three Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getThreeChildrenOffsetCount(),
|
||||
((float)OctreeElement::getThreeChildrenOffsetCount() / (float)nodeCount) * AS_PERCENT);
|
||||
statsString += QString().sprintf(" Three Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getThreeChildrenExternalCount(),
|
||||
((float)OctreeElement::getThreeChildrenExternalCount() / (float)nodeCount) * AS_PERCENT);
|
||||
statsString += QString().sprintf(" Children as External Array: %10.llu nodes (%5.2f%%)\r\n",
|
||||
OctreeElement::getExternalChildrenCount(),
|
||||
((float)OctreeElement::getExternalChildrenCount() / (float)nodeCount) * AS_PERCENT);
|
||||
|
||||
checkSum = OctreeElement::getSingleChildrenCount() +
|
||||
OctreeElement::getTwoChildrenOffsetCount() + OctreeElement::getTwoChildrenExternalCount() +
|
||||
OctreeElement::getThreeChildrenOffsetCount() + OctreeElement::getThreeChildrenExternalCount() +
|
||||
OctreeElement::getExternalChildrenCount();
|
||||
|
||||
statsString += " ----------------\r\n";
|
||||
statsString += QString().sprintf(" Total: %10.llu nodes\r\n", checkSum);
|
||||
statsString += QString().sprintf(" Expected: %10.lu nodes\r\n", nodeCount);
|
||||
|
||||
statsString += "\r\n";
|
||||
statsString += "In other news....\r\n";
|
||||
|
||||
statsString += QString().sprintf("could store 4 children internally: %10.llu nodes\r\n",
|
||||
OctreeElement::getCouldStoreFourChildrenInternally());
|
||||
statsString += QString().sprintf("could NOT store 4 children internally: %10.llu nodes\r\n",
|
||||
OctreeElement::getCouldNotStoreFourChildrenInternally());
|
||||
#endif
|
||||
|
||||
statsString += "\r\n\r\n";
|
||||
statsString += "</pre>\r\n";
|
||||
statsString += "</doc></html>";
|
||||
|
|
1316
examples/utilities/tools/cookies.js
Executable file → Normal file
1316
examples/utilities/tools/cookies.js
Executable file → Normal file
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@
|
|||
|
||||
Script.include("cookies.js");
|
||||
|
||||
var panel = new Panel(10, 800);
|
||||
var panel = new Panel(10, 100);
|
||||
|
||||
panel.newSlider("Num Feed Opaques", 0, 1000,
|
||||
function(value) { },
|
||||
|
@ -66,6 +66,12 @@ panel.newSlider("Max Drawn Overlay3Ds", -1, 100,
|
|||
function(value) { return (value); }
|
||||
);
|
||||
|
||||
panel.newCheckbox("Display status",
|
||||
function(value) { Scene.setEngineDisplayItemStatus(value); },
|
||||
function() { return Scene.doEngineDisplayItemStatus(); },
|
||||
function(value) { return (value); }
|
||||
);
|
||||
|
||||
var tickTackPeriod = 500;
|
||||
|
||||
function updateCounters() {
|
||||
|
|
|
@ -3600,6 +3600,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();
|
||||
renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
|
||||
|
||||
renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus();
|
||||
|
||||
renderArgs->_shouldRender = LODManager::shouldRender;
|
||||
|
||||
renderContext.args = renderArgs;
|
||||
|
|
|
@ -533,6 +533,7 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::PipelineWarnings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::LogExtraTimings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::SuppressShortTimings);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::ShowRealtimeEntityStats);
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio");
|
||||
|
|
|
@ -267,6 +267,7 @@ namespace MenuOption {
|
|||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowIKConstraints = "Show IK Constraints";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
const QString SimpleShadows = "Simple";
|
||||
const QString SixenseEnabled = "Enable Hydra Support";
|
||||
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
||||
|
|
|
@ -25,18 +25,13 @@
|
|||
|
||||
|
||||
// Used to animate the magnification windows
|
||||
static const float MAG_SPEED = 0.08f;
|
||||
|
||||
static const quint64 MSECS_TO_USECS = 1000ULL;
|
||||
static const quint64 TOOLTIP_DELAY = 500 * MSECS_TO_USECS;
|
||||
|
||||
static const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
static const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
|
||||
static const float reticleSize = TWO_PI / 100.0f;
|
||||
|
||||
static const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
|
||||
static const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
||||
|
||||
static const float CURSOR_PIXEL_SIZE = 32.0f;
|
||||
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
|
||||
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
|
||||
|
|
|
@ -36,9 +36,6 @@
|
|||
#include "ui/Stats.h"
|
||||
#include "ui/AvatarInputs.h"
|
||||
|
||||
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
|
||||
const int AUDIO_METER_GAP = 5;
|
||||
const int MUTE_ICON_PADDING = 10;
|
||||
const vec4 CONNECTION_STATUS_BORDER_COLOR{ 1.0f, 0.0f, 0.0f, 0.8f };
|
||||
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
|
||||
static const float ORTHO_NEAR_CLIP = -10000;
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
||||
_model(model) {
|
||||
_model(model),
|
||||
_averageUpdatesPerSecond(SAMPLES_PER_SECOND)
|
||||
{
|
||||
|
||||
_statCount = 0;
|
||||
_octreeServerLabelsCount = 0;
|
||||
|
@ -50,6 +52,14 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo
|
|||
_localElements = AddStatItem("Local Elements");
|
||||
_localElementsMemory = AddStatItem("Elements Memory");
|
||||
_sendingMode = AddStatItem("Sending Mode");
|
||||
|
||||
_processedPackets = AddStatItem("Processed Packets");
|
||||
_processedPacketsElements = AddStatItem("Processed Packets Elements");
|
||||
_processedPacketsEntities = AddStatItem("Processed Packets Entities");
|
||||
_processedPacketsTiming = AddStatItem("Processed Packets Timing");
|
||||
|
||||
_entityUpdateTime = AddStatItem("Entity Update Time");
|
||||
_entityUpdates = AddStatItem("Entity Updates");
|
||||
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
}
|
||||
|
@ -119,6 +129,34 @@ OctreeStatsDialog::~OctreeStatsDialog() {
|
|||
|
||||
void OctreeStatsDialog::paintEvent(QPaintEvent* event) {
|
||||
|
||||
// Processed Entities Related stats
|
||||
auto entities = Application::getInstance()->getEntities();
|
||||
auto entitiesTree = entities->getTree();
|
||||
|
||||
// Do this ever paint event... even if we don't update
|
||||
auto totalTrackedEdits = entitiesTree->getTotalTrackedEdits();
|
||||
|
||||
// track our updated per second
|
||||
const quint64 SAMPLING_WINDOW = USECS_PER_SECOND / SAMPLES_PER_SECOND;
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastWindow = now - _lastWindowAt;
|
||||
auto editsInLastWindow = totalTrackedEdits - _lastKnownTrackedEdits;
|
||||
float sinceLastWindowInSeconds = (float)sinceLastWindow / (float)USECS_PER_SECOND;
|
||||
float recentUpdatesPerSecond = (float)editsInLastWindow / sinceLastWindowInSeconds;
|
||||
if (sinceLastWindow > SAMPLING_WINDOW) {
|
||||
_averageUpdatesPerSecond.updateAverage(recentUpdatesPerSecond);
|
||||
_lastWindowAt = now;
|
||||
_lastKnownTrackedEdits = totalTrackedEdits;
|
||||
}
|
||||
|
||||
// Only refresh our stats every once in a while, unless asked for realtime
|
||||
quint64 REFRESH_AFTER = Menu::getInstance()->isOptionChecked(MenuOption::ShowRealtimeEntityStats) ? 0 : USECS_PER_SECOND;
|
||||
quint64 sinceLastRefresh = now - _lastRefresh;
|
||||
if (sinceLastRefresh < REFRESH_AFTER) {
|
||||
return QDialog::paintEvent(event);
|
||||
}
|
||||
_lastRefresh = now;
|
||||
|
||||
// Update labels
|
||||
|
||||
QLabel* label;
|
||||
|
@ -203,9 +241,100 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
"Leaves: " << qPrintable(serversLeavesString) << "";
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
// Processed Packets Elements
|
||||
auto averageElementsPerPacket = entities->getAverageElementsPerPacket();
|
||||
auto averageEntitiesPerPacket = entities->getAverageEntitiesPerPacket();
|
||||
|
||||
auto averagePacketsPerSecond = entities->getAveragePacketsPerSecond();
|
||||
auto averageElementsPerSecond = entities->getAverageElementsPerSecond();
|
||||
auto averageEntitiesPerSecond = entities->getAverageEntitiesPerSecond();
|
||||
|
||||
auto averageWaitLockPerPacket = entities->getAverageWaitLockPerPacket();
|
||||
auto averageUncompressPerPacket = entities->getAverageUncompressPerPacket();
|
||||
auto averageReadBitstreamPerPacket = entities->getAverageReadBitstreamPerPacket();
|
||||
|
||||
QString averageElementsPerPacketString = locale.toString(averageElementsPerPacket);
|
||||
QString averageEntitiesPerPacketString = locale.toString(averageEntitiesPerPacket);
|
||||
|
||||
QString averagePacketsPerSecondString = locale.toString(averagePacketsPerSecond);
|
||||
QString averageElementsPerSecondString = locale.toString(averageElementsPerSecond);
|
||||
QString averageEntitiesPerSecondString = locale.toString(averageEntitiesPerSecond);
|
||||
|
||||
QString averageWaitLockPerPacketString = locale.toString(averageWaitLockPerPacket);
|
||||
QString averageUncompressPerPacketString = locale.toString(averageUncompressPerPacket);
|
||||
QString averageReadBitstreamPerPacketString = locale.toString(averageReadBitstreamPerPacket);
|
||||
|
||||
label = _labels[_processedPackets];
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"" << qPrintable(averagePacketsPerSecondString) << " per second";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
label = _labels[_processedPacketsElements];
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"" << qPrintable(averageElementsPerPacketString) << " per packet / " <<
|
||||
"" << qPrintable(averageElementsPerSecondString) << " per second";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
label = _labels[_processedPacketsEntities];
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"" << qPrintable(averageEntitiesPerPacketString) << " per packet / " <<
|
||||
"" << qPrintable(averageEntitiesPerSecondString) << " per second";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
label = _labels[_processedPacketsTiming];
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"Lock Wait:" << qPrintable(averageWaitLockPerPacketString) << " (usecs) / " <<
|
||||
"Uncompress:" << qPrintable(averageUncompressPerPacketString) << " (usecs) / " <<
|
||||
"Process:" << qPrintable(averageReadBitstreamPerPacketString) << " (usecs)";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
// Entity Edits update time
|
||||
label = _labels[_entityUpdateTime];
|
||||
auto averageEditDelta = entitiesTree->getAverageEditDeltas();
|
||||
auto maxEditDelta = entitiesTree->getMaxEditDelta();
|
||||
|
||||
QString averageEditDeltaString = locale.toString((uint)averageEditDelta);
|
||||
QString maxEditDeltaString = locale.toString((uint)maxEditDelta);
|
||||
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"Average: " << qPrintable(averageEditDeltaString) << " (usecs) / " <<
|
||||
"Max: " << qPrintable(maxEditDeltaString) << " (usecs)";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
// Entity Edits
|
||||
label = _labels[_entityUpdates];
|
||||
auto bytesPerEdit = entitiesTree->getAverageEditBytes();
|
||||
|
||||
auto updatesPerSecond = _averageUpdatesPerSecond.getAverage();
|
||||
if (updatesPerSecond < 1) {
|
||||
updatesPerSecond = 0; // we don't really care about small updates per second so suppress those
|
||||
}
|
||||
|
||||
QString totalTrackedEditsString = locale.toString((uint)totalTrackedEdits);
|
||||
QString updatesPerSecondString = locale.toString(updatesPerSecond);
|
||||
QString bytesPerEditString = locale.toString(bytesPerEdit);
|
||||
|
||||
statsValue.str("");
|
||||
statsValue <<
|
||||
"" << qPrintable(updatesPerSecondString) << " updates per second / " <<
|
||||
"" << qPrintable(totalTrackedEditsString) << " total updates / " <<
|
||||
"Average Size: " << qPrintable(bytesPerEditString) << " bytes ";
|
||||
|
||||
label->setText(statsValue.str().c_str());
|
||||
|
||||
showAllOctreeServers();
|
||||
|
||||
this->QDialog::paintEvent(event);
|
||||
QDialog::paintEvent(event);
|
||||
}
|
||||
void OctreeStatsDialog::showAllOctreeServers() {
|
||||
int serverCount = 0;
|
||||
|
|
|
@ -63,6 +63,21 @@ private:
|
|||
int _serverElements;
|
||||
int _localElements;
|
||||
int _localElementsMemory;
|
||||
|
||||
int _entityUpdateTime;
|
||||
int _entityUpdates;
|
||||
int _processedPackets;
|
||||
int _processedPacketsElements;
|
||||
int _processedPacketsEntities;
|
||||
int _processedPacketsTiming;
|
||||
|
||||
const int SAMPLES_PER_SECOND = 10;
|
||||
SimpleMovingAverage _averageUpdatesPerSecond;
|
||||
quint64 _lastWindowAt = 0;
|
||||
quint64 _lastKnownTrackedEdits = 0;
|
||||
|
||||
quint64 _lastRefresh = 0;
|
||||
|
||||
int _octreeServerLables[MAX_VOXEL_SERVERS];
|
||||
int _octreeServerLabelsCount;
|
||||
details _extraServerDetails[MAX_VOXEL_SERVERS];
|
||||
|
|
|
@ -93,31 +93,6 @@ void BillboardOverlay::render(RenderArgs* args) {
|
|||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
||||
|
||||
batch->setUniformTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
} else {
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _texture->getID());
|
||||
|
||||
glPushMatrix(); {
|
||||
glTranslatef(getPosition().x, getPosition().y, getPosition().z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glScalef(_dimensions.x, _dimensions.y, 1.0f);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
|
||||
|
||||
} glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,75 +89,6 @@ void Grid3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(*batch, MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
} else {
|
||||
if (!_gridProgram.isLinked()) {
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Vertex, PathUtils::resourcesPath() + "shaders/grid.vert")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, PathUtils::resourcesPath() + "shaders/grid.frag")) {
|
||||
qDebug() << "Failed to compile: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
if (!_gridProgram.link()) {
|
||||
qDebug() << "Failed to link: " + _gridProgram.log();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Render code largely taken from MetavoxelEditor::render()
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glLineWidth(1.5f);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
|
||||
_gridProgram.bind();
|
||||
|
||||
// Minor grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glTranslatef(_minorGridWidth * (floorf(rotated.x / spacing) - MINOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MINOR_GRID_DIVISIONS / 2), position.z);
|
||||
|
||||
float scale = MINOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MINOR_GRID_DIVISIONS, MINOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
// Major grid
|
||||
glPushMatrix();
|
||||
{
|
||||
glLineWidth(4.0f);
|
||||
spacing *= _majorGridEvery;
|
||||
glTranslatef(spacing * (floorf(rotated.x / spacing) - MAJOR_GRID_DIVISIONS / 2),
|
||||
spacing * (floorf(rotated.y / spacing) - MAJOR_GRID_DIVISIONS / 2), position.z);
|
||||
|
||||
float scale = MAJOR_GRID_DIVISIONS * spacing;
|
||||
glScalef(scale, scale, scale);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderGrid(MAJOR_GRID_DIVISIONS, MAJOR_GRID_DIVISIONS, gridColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
_gridProgram.release();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,22 +32,22 @@ void LocalModelsOverlay::update(float deltatime) {
|
|||
|
||||
void LocalModelsOverlay::render(RenderArgs* args) {
|
||||
if (_visible) {
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix(); {
|
||||
Application* app = Application::getInstance();
|
||||
#if 0
|
||||
glm::vec3 oldTranslation = app->getViewMatrixTranslation();
|
||||
app->setViewMatrixTranslation(oldTranslation + getPosition());
|
||||
_entityTreeRenderer->render(args);
|
||||
Application::getInstance()->setViewMatrixTranslation(oldTranslation);
|
||||
#endif
|
||||
} glPopMatrix();
|
||||
|
||||
auto batch = args ->_batch;
|
||||
Application* app = Application::getInstance();
|
||||
glm::vec3 oldTranslation = app->getViewMatrixTranslation();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(oldTranslation + getPosition());
|
||||
batch->setViewTransform(transform);
|
||||
_entityTreeRenderer->render(args);
|
||||
transform.setTranslation(oldTranslation);
|
||||
batch->setViewTransform(transform);
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <Application.h>
|
||||
#include <render/Scene.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include "BillboardOverlay.h"
|
||||
#include "Circle3DOverlay.h"
|
||||
|
@ -96,6 +97,10 @@ void Overlays::cleanupOverlaysToDelete() {
|
|||
|
||||
void Overlays::renderHUD(RenderArgs* renderArgs) {
|
||||
QReadLocker lock(&_lock);
|
||||
gpu::Batch batch;
|
||||
renderArgs->_batch = &batch;
|
||||
|
||||
|
||||
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
||||
if (thisOverlay->is3D()) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@ -109,6 +114,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
|||
thisOverlay->render(renderArgs);
|
||||
}
|
||||
}
|
||||
gpu::GLBackend::renderBatch(batch, true);
|
||||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
|
||||
|
|
|
@ -62,19 +62,19 @@ namespace render {
|
|||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
||||
glPushMatrix();
|
||||
auto batch = args->_batch;
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::quat myAvatarRotation = avatar->getOrientation();
|
||||
glm::vec3 myAvatarPosition = avatar->getPosition();
|
||||
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||
glm::vec3 axis = glm::axis(myAvatarRotation);
|
||||
float myAvatarScale = avatar->getScale();
|
||||
|
||||
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(myAvatarPosition);
|
||||
transform.setRotation(glm::angleAxis(angle, axis));
|
||||
transform.setScale(myAvatarScale);
|
||||
batch->setModelTransform(transform);
|
||||
overlay->render(args);
|
||||
glPopMatrix();
|
||||
} else {
|
||||
overlay->render(args);
|
||||
}
|
||||
|
|
|
@ -87,70 +87,6 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
geometryCache->renderVertices(*batch, gpu::LINE_STRIP, _geometryCacheID);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
//glScalef(dimensions.x, dimensions.y, 1.0f);
|
||||
|
||||
glLineWidth(_lineWidth);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// for our overlay, is solid means we draw a solid "filled" rectangle otherwise we just draw a border line...
|
||||
if (getIsSolid()) {
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, rectangleColor);
|
||||
} else {
|
||||
if (getIsDashedLine()) {
|
||||
|
||||
glm::vec3 point1(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
|
||||
geometryCache->renderDashedLine(point1, point2, rectangleColor);
|
||||
geometryCache->renderDashedLine(point2, point3, rectangleColor);
|
||||
geometryCache->renderDashedLine(point3, point4, rectangleColor);
|
||||
geometryCache->renderDashedLine(point4, point1, rectangleColor);
|
||||
|
||||
} else {
|
||||
|
||||
if (halfDimensions != _previousHalfDimensions) {
|
||||
QVector<glm::vec3> border;
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
border << glm::vec3(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
geometryCache->updateVertices(_geometryCacheID, border, rectangleColor);
|
||||
|
||||
_previousHalfDimensions = halfDimensions;
|
||||
|
||||
}
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _geometryCacheID);
|
||||
}
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,35 +41,6 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
transform.postScale(getDimensions());
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(*batch, 1.0f, SLICES, SLICES, sphereColor, _isSolid);
|
||||
} else {
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
float glowLevel = getGlowLevel();
|
||||
Glower* glower = NULL;
|
||||
if (glowLevel > 0.0f) {
|
||||
glower = new Glower(glowLevel);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(1.0f, SLICES, SLICES, sphereColor, _isSolid);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -167,6 +167,25 @@ namespace render {
|
|||
}
|
||||
}
|
||||
|
||||
void makeEntityItemStatusGetters(RenderableModelEntityItem* entity, render::Item::Status::Getters& statusGetters) {
|
||||
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||
quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote();
|
||||
const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND);
|
||||
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
||||
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
||||
// Color is red if last update is after WAIT_THRESHOLD, green otherwise (120 deg is green)
|
||||
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::GREEN : render::Item::Status::Value::RED));
|
||||
});
|
||||
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||
quint64 delta = usecTimestampNow() - entity->getLastBroadcast();
|
||||
const float WAIT_THRESHOLD_INV = 1.0f / (0.4f * USECS_PER_SECOND);
|
||||
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
||||
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
||||
// Color is Magenta if last update is after WAIT_THRESHOLD, cyan otherwise (180 deg is green)
|
||||
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::MAGENTA : render::Item::Status::Value::CYAN));
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
@ -177,7 +196,9 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
|
|||
pendingChanges.resetItem(_myMetaItem, renderPayload);
|
||||
|
||||
if (_model) {
|
||||
return _model->addToScene(scene, pendingChanges);
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(this, statusGetters);
|
||||
return _model->addToScene(scene, pendingChanges, statusGetters);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -214,7 +235,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
render::PendingChanges pendingChanges;
|
||||
if (_model->needsFixupInScene()) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
_model->addToScene(scene, pendingChanges);
|
||||
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(this, statusGetters);
|
||||
_model->addToScene(scene, pendingChanges, statusGetters);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
|
|
|
@ -30,9 +30,6 @@
|
|||
#include "EntityActionFactoryInterface.h"
|
||||
|
||||
|
||||
const quint64 DEFAULT_SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND);
|
||||
const quint64 MAX_SIMULATOR_CHANGE_LOCKOUT_PERIOD = 2 * USECS_PER_SECOND;
|
||||
|
||||
bool EntityItem::_sendPhysicsUpdates = true;
|
||||
int EntityItem::_maxActionsDataSize = 800;
|
||||
|
||||
|
@ -346,6 +343,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
return 0;
|
||||
}
|
||||
|
||||
args.entitiesPerPacket++;
|
||||
|
||||
// Header bytes
|
||||
// object ID [16 bytes]
|
||||
// ByteCountCoded(type code) [~1 byte]
|
||||
|
@ -426,6 +425,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
dataAt += sizeof(lastEditedFromBuffer);
|
||||
bytesRead += sizeof(lastEditedFromBuffer);
|
||||
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
|
||||
|
||||
if (lastEditedFromBufferAdjusted > now) {
|
||||
lastEditedFromBufferAdjusted = now;
|
||||
}
|
||||
|
@ -498,6 +498,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
|
||||
#endif
|
||||
}
|
||||
|
||||
encodedUpdateDelta = updateDeltaCoder; // determine true length
|
||||
dataAt += encodedUpdateDelta.size();
|
||||
bytesRead += encodedUpdateDelta.size();
|
||||
|
@ -676,6 +677,14 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
}
|
||||
}
|
||||
|
||||
// Tracking for editing roundtrips here. We will tell our EntityTree that we just got incoming data about
|
||||
// and entity that was edited at some time in the past. The tree will determine how it wants to track this
|
||||
// information.
|
||||
if (_element && _element->getTree()) {
|
||||
_element->getTree()->trackIncomingEntityLastEdited(lastEditedFromBufferAdjusted, bytesRead);
|
||||
}
|
||||
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,15 +26,13 @@
|
|||
#include "LogHandler.h"
|
||||
|
||||
|
||||
const quint64 SIMULATOR_CHANGE_LOCKOUT_PERIOD = (quint64)(0.2f * USECS_PER_SECOND);
|
||||
|
||||
|
||||
EntityTree::EntityTree(bool shouldReaverage) :
|
||||
Octree(shouldReaverage),
|
||||
_fbxService(NULL),
|
||||
_simulation(NULL)
|
||||
{
|
||||
_rootElement = createNewElement();
|
||||
resetClientEditStats();
|
||||
}
|
||||
|
||||
EntityTree::~EntityTree() {
|
||||
|
@ -61,6 +59,8 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
|
|||
}
|
||||
_entityToElementMap.clear();
|
||||
Octree::eraseAllOctreeElements(createNewRoot);
|
||||
|
||||
resetClientEditStats();
|
||||
}
|
||||
|
||||
bool EntityTree::handlesEditPacketType(PacketType packetType) const {
|
||||
|
@ -1123,3 +1123,29 @@ bool EntityTree::readFromMap(QVariantMap& map) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EntityTree::resetClientEditStats() {
|
||||
_treeResetTime = usecTimestampNow();
|
||||
_maxEditDelta = 0;
|
||||
_totalEditDeltas = 0;
|
||||
_totalTrackedEdits = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EntityTree::trackIncomingEntityLastEdited(quint64 lastEditedTime, int bytesRead) {
|
||||
// we don't want to track all edit deltas, just those edits that have happend
|
||||
// since we connected to this domain. This will filter out all previously created
|
||||
// content and only track new edits
|
||||
if (lastEditedTime > _treeResetTime) {
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceEdit = now - lastEditedTime;
|
||||
|
||||
_totalEditDeltas += sinceEdit;
|
||||
_totalEditBytes += bytesRead;
|
||||
_totalTrackedEdits++;
|
||||
if (sinceEdit > _maxEditDelta) {
|
||||
_maxEditDelta = sinceEdit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,6 +185,14 @@ public:
|
|||
virtual quint64 getAverageCreateTime() const { return _totalCreates == 0 ? 0 : _totalCreateTime / _totalCreates; }
|
||||
virtual quint64 getAverageLoggingTime() const { return _totalEditMessages == 0 ? 0 : _totalLoggingTime / _totalEditMessages; }
|
||||
|
||||
void trackIncomingEntityLastEdited(quint64 lastEditedTime, int bytesRead);
|
||||
quint64 getAverageEditDeltas() const
|
||||
{ return _totalTrackedEdits == 0 ? 0 : _totalEditDeltas / _totalTrackedEdits; }
|
||||
quint64 getAverageEditBytes() const
|
||||
{ return _totalTrackedEdits == 0 ? 0 : _totalEditBytes / _totalTrackedEdits; }
|
||||
quint64 getMaxEditDelta() const { return _maxEditDelta; }
|
||||
quint64 getTotalTrackedEdits() const { return _totalTrackedEdits; }
|
||||
|
||||
signals:
|
||||
void deletingEntity(const EntityItemID& entityID);
|
||||
void addingEntity(const EntityItemID& entityID);
|
||||
|
@ -230,6 +238,14 @@ private:
|
|||
quint64 _totalUpdateTime = 0;
|
||||
quint64 _totalCreateTime = 0;
|
||||
quint64 _totalLoggingTime = 0;
|
||||
|
||||
// these performance statistics are only used in the client
|
||||
void resetClientEditStats();
|
||||
int _totalTrackedEdits = 0;
|
||||
quint64 _totalEditBytes = 0;
|
||||
quint64 _totalEditDeltas = 0;
|
||||
quint64 _maxEditDelta = 0;
|
||||
quint64 _treeResetTime = 0;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTree_h
|
||||
|
|
|
@ -702,6 +702,8 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
|
|||
int bytesRead = 0;
|
||||
uint16_t numberOfEntities = 0;
|
||||
int expectedBytesPerEntity = EntityItem::expectedBytes();
|
||||
|
||||
args.elementsPerPacket++;
|
||||
|
||||
if (bytesLeftToRead >= (int)sizeof(numberOfEntities)) {
|
||||
// read our entities in....
|
||||
|
|
|
@ -159,6 +159,12 @@ void Batch::setProjectionTransform(const Mat4& proj) {
|
|||
_params.push_back(cacheData(sizeof(Mat4), &proj));
|
||||
}
|
||||
|
||||
void Batch::setViewportTransform(const Vec4i& viewport) {
|
||||
ADD_COMMAND(setViewportTransform);
|
||||
|
||||
_params.push_back(cacheData(sizeof(Vec4i), &viewport));
|
||||
}
|
||||
|
||||
void Batch::setPipeline(const PipelinePointer& pipeline) {
|
||||
ADD_COMMAND(setPipeline);
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@ public:
|
|||
void setModelTransform(const Transform& model);
|
||||
void setViewTransform(const Transform& view);
|
||||
void setProjectionTransform(const Mat4& proj);
|
||||
void setViewportTransform(const Vec4i& viewport); // Viewport is xy = low left corner in the framebuffer, zw = width height of the viewport
|
||||
|
||||
// Pipeline Stage
|
||||
void setPipeline(const PipelinePointer& pipeline);
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
void _glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
void _glUniform3fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void _glUniform4fv(GLint location, GLsizei count, const GLfloat* value);
|
||||
void _glUniform4iv(GLint location, GLsizei count, const GLint* value);
|
||||
void _glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
|
||||
|
||||
void _glEnableVertexAttribArray(GLint location);
|
||||
|
@ -177,6 +179,7 @@ public:
|
|||
COMMAND_setModelTransform,
|
||||
COMMAND_setViewTransform,
|
||||
COMMAND_setProjectionTransform,
|
||||
COMMAND_setViewportTransform,
|
||||
|
||||
COMMAND_setPipeline,
|
||||
COMMAND_setStateBlendFactor,
|
||||
|
@ -217,6 +220,7 @@ public:
|
|||
COMMAND_glUniform3f,
|
||||
COMMAND_glUniform3fv,
|
||||
COMMAND_glUniform4fv,
|
||||
COMMAND_glUniform4iv,
|
||||
COMMAND_glUniformMatrix4fv,
|
||||
|
||||
COMMAND_glEnableVertexAttribArray,
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
<@elif GLPROFILE == MAC_GL @>
|
||||
<@def GPU_FEATURE_PROFILE GPU_LEGACY@>
|
||||
<@def GPU_TRANSFORM_PROFILE GPU_LEGACY@>
|
||||
<@def VERSION_HEADER #version 120@>
|
||||
<@def VERSION_HEADER #version 120
|
||||
#extension GL_EXT_gpu_shader4 : enable@>
|
||||
<@else@>
|
||||
<@def GPU_FEATURE_PROFILE GPU_LEGACY@>
|
||||
<@def GPU_TRANSFORM_PROFILE GPU_LEGACY@>
|
||||
<@def VERSION_HEADER #version 120@>
|
||||
<@def VERSION_HEADER #version 120
|
||||
#extension GL_EXT_gpu_shader4 : enable@>
|
||||
<@endif@>
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -38,6 +38,7 @@ typedef uint32 Offset;
|
|||
typedef glm::mat4 Mat4;
|
||||
typedef glm::mat3 Mat3;
|
||||
typedef glm::vec4 Vec4;
|
||||
typedef glm::ivec4 Vec4i;
|
||||
typedef glm::vec3 Vec3;
|
||||
typedef glm::vec2 Vec2;
|
||||
typedef glm::ivec2 Vec2i;
|
||||
|
|
|
@ -29,6 +29,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setModelTransform),
|
||||
(&::gpu::GLBackend::do_setViewTransform),
|
||||
(&::gpu::GLBackend::do_setProjectionTransform),
|
||||
(&::gpu::GLBackend::do_setViewportTransform),
|
||||
|
||||
(&::gpu::GLBackend::do_setPipeline),
|
||||
(&::gpu::GLBackend::do_setStateBlendFactor),
|
||||
|
@ -67,6 +68,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_glUniform3f),
|
||||
(&::gpu::GLBackend::do_glUniform3fv),
|
||||
(&::gpu::GLBackend::do_glUniform4fv),
|
||||
(&::gpu::GLBackend::do_glUniform4iv),
|
||||
(&::gpu::GLBackend::do_glUniformMatrix4fv),
|
||||
|
||||
(&::gpu::GLBackend::do_glEnableVertexAttribArray),
|
||||
|
@ -190,6 +192,18 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) {
|
|||
}
|
||||
|
||||
void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) {
|
||||
updateInput();
|
||||
updateTransform();
|
||||
updatePipeline();
|
||||
|
||||
GLint numInstances = batch._params[paramOffset + 4]._uint;
|
||||
Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint;
|
||||
GLenum mode = _primitiveToGLmode[primitiveType];
|
||||
uint32 numVertices = batch._params[paramOffset + 2]._uint;
|
||||
uint32 startVertex = batch._params[paramOffset + 1]._uint;
|
||||
uint32 startInstance = batch._params[paramOffset + 0]._uint;
|
||||
|
||||
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
@ -592,6 +606,31 @@ void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniform4iv(GLint location, GLsizei count, const GLint* value) {
|
||||
ADD_COMMAND_GL(glUniform4iv);
|
||||
|
||||
const int VEC4_SIZE = 4 * sizeof(int);
|
||||
_params.push_back(cacheData(count * VEC4_SIZE, value));
|
||||
_params.push_back(count);
|
||||
_params.push_back(location);
|
||||
|
||||
DO_IT_NOW(_glUniform4iv, 3);
|
||||
}
|
||||
void GLBackend::do_glUniform4iv(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform4iv(
|
||||
batch._params[paramOffset + 2]._int,
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
(const GLint*)batch.editData(batch._params[paramOffset + 0]._uint));
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniformMatrix4fv);
|
||||
|
||||
|
|
|
@ -96,7 +96,9 @@ public:
|
|||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
#else
|
||||
GLuint _transformObject_model = -1;
|
||||
GLuint _transformCamera_viewInverse = -1;
|
||||
GLuint _transformCamera_viewport = -1;
|
||||
#endif
|
||||
|
||||
GLShader();
|
||||
|
@ -267,7 +269,8 @@ protected:
|
|||
void do_setModelTransform(Batch& batch, uint32 paramOffset);
|
||||
void do_setViewTransform(Batch& batch, uint32 paramOffset);
|
||||
void do_setProjectionTransform(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void do_setViewportTransform(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void initTransform();
|
||||
void killTransform();
|
||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||
|
@ -281,9 +284,11 @@ protected:
|
|||
Transform _model;
|
||||
Transform _view;
|
||||
Mat4 _projection;
|
||||
Vec4i _viewport;
|
||||
bool _invalidModel;
|
||||
bool _invalidView;
|
||||
bool _invalidProj;
|
||||
bool _invalidViewport;
|
||||
|
||||
GLenum _lastMode;
|
||||
|
||||
|
@ -296,6 +301,7 @@ protected:
|
|||
_invalidModel(true),
|
||||
_invalidView(true),
|
||||
_invalidProj(false),
|
||||
_invalidViewport(false),
|
||||
_lastMode(GL_TEXTURE) {}
|
||||
} _transform;
|
||||
|
||||
|
@ -329,7 +335,9 @@ protected:
|
|||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
#else
|
||||
GLint _program_transformObject_model = -1;
|
||||
GLint _program_transformCamera_viewInverse = -1;
|
||||
GLint _program_transformCamera_viewport = -1;
|
||||
#endif
|
||||
|
||||
State::Data _stateCache;
|
||||
|
@ -390,6 +398,7 @@ protected:
|
|||
void do_glUniform3f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform3fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4iv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset);
|
||||
|
||||
void do_glEnableVertexAttribArray(Batch& batch, uint32 paramOffset);
|
||||
|
|
|
@ -73,7 +73,9 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
|
|||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
#else
|
||||
_pipeline._program_transformObject_model = -1;
|
||||
_pipeline._program_transformCamera_viewInverse = -1;
|
||||
_pipeline._program_transformCamera_viewport = -1;
|
||||
#endif
|
||||
|
||||
_pipeline._state = nullptr;
|
||||
|
@ -91,7 +93,9 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
|
|||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
#else
|
||||
_pipeline._program_transformObject_model = pipelineObject->_program->_transformObject_model;
|
||||
_pipeline._program_transformCamera_viewInverse = pipelineObject->_program->_transformCamera_viewInverse;
|
||||
_pipeline._program_transformCamera_viewport = pipelineObject->_program->_transformCamera_viewport;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -143,10 +147,20 @@ void GLBackend::updatePipeline() {
|
|||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
#else
|
||||
// If shader program needs the model we need to provide it
|
||||
if (_pipeline._program_transformObject_model >= 0) {
|
||||
glUniformMatrix4fv(_pipeline._program_transformObject_model, 1, false, (const GLfloat*) &_transform._transformObject._model);
|
||||
}
|
||||
|
||||
// If shader program needs the inverseView we need to provide it
|
||||
if (_pipeline._program_transformCamera_viewInverse >= 0) {
|
||||
glUniformMatrix4fv(_pipeline._program_transformCamera_viewInverse, 1, false, (const GLfloat*) &_transform._transformCamera._viewInverse);
|
||||
}
|
||||
|
||||
// If shader program needs the viewport we need to provide it
|
||||
if (_pipeline._program_transformCamera_viewport >= 0) {
|
||||
glUniform4fv(_pipeline._program_transformCamera_viewport, 1, (const GLfloat*) &_transform._transformCamera._viewport);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -111,10 +111,20 @@ void makeBindings(GLBackend::GLShader* shader) {
|
|||
shader->_transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
|
||||
}
|
||||
#else
|
||||
loc = glGetUniformLocation(glprogram, "transformObject_model");
|
||||
if (loc >= 0) {
|
||||
shader->_transformObject_model = loc;
|
||||
}
|
||||
|
||||
loc = glGetUniformLocation(glprogram, "transformCamera_viewInverse");
|
||||
if (loc >= 0) {
|
||||
shader->_transformCamera_viewInverse = loc;
|
||||
}
|
||||
|
||||
loc = glGetUniformLocation(glprogram, "transformCamera_viewport");
|
||||
if (loc >= 0) {
|
||||
shader->_transformCamera_viewport = loc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) {
|
|||
_transform._invalidProj = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) {
|
||||
memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
|
||||
_transform._invalidViewport = true;
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::initTransform() {
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
glGenBuffers(1, &_transform._transformObjectBuffer);
|
||||
|
@ -57,10 +63,13 @@ void GLBackend::killTransform() {
|
|||
}
|
||||
|
||||
void GLBackend::syncTransformStateCache() {
|
||||
_transform._invalidViewport = true;
|
||||
_transform._invalidProj = true;
|
||||
_transform._invalidView = true;
|
||||
_transform._invalidModel = true;
|
||||
|
||||
glGetIntegerv(GL_VIEWPORT, (GLint*) &_transform._viewport);
|
||||
|
||||
GLint currentMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, ¤tMode);
|
||||
_transform._lastMode = currentMode;
|
||||
|
@ -78,6 +87,13 @@ void GLBackend::updateTransform() {
|
|||
GLint originalMatrixMode;
|
||||
glGetIntegerv(GL_MATRIX_MODE, &originalMatrixMode);
|
||||
// Check all the dirty flags and update the state accordingly
|
||||
if (_transform._invalidViewport) {
|
||||
_transform._transformCamera._viewport = glm::vec4(_transform._viewport);
|
||||
|
||||
// Where we assign the GL viewport
|
||||
glViewport(_transform._viewport.x, _transform._viewport.y, _transform._viewport.z, _transform._viewport.w);
|
||||
}
|
||||
|
||||
if (_transform._invalidProj) {
|
||||
_transform._transformCamera._projection = _transform._projection;
|
||||
_transform._transformCamera._projectionInverse = glm::inverse(_transform._projection);
|
||||
|
@ -100,7 +116,7 @@ void GLBackend::updateTransform() {
|
|||
}
|
||||
|
||||
#if (GPU_TRANSFORM_PROFILE == GPU_CORE)
|
||||
if (_transform._invalidView || _transform._invalidProj) {
|
||||
if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW);
|
||||
|
@ -162,7 +178,8 @@ void GLBackend::updateTransform() {
|
|||
#endif
|
||||
|
||||
// Flags are clean
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = false;
|
||||
_transform._invalidView = _transform._invalidProj = _transform._invalidModel = _transform._invalidViewport = false;
|
||||
|
||||
glMatrixMode(originalMatrixMode);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,18 @@ TransformCamera getTransformCamera() {
|
|||
}
|
||||
|
||||
uniform mat4 transformCamera_viewInverse;
|
||||
uniform vec4 transformCamera_viewport;
|
||||
|
||||
<@endif@>
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformCameraViewport(cameraTransform, viewport)@>
|
||||
<@if GPU_TRANSFORM_PROFILE == GPU_CORE@>
|
||||
<$viewport$> = <$cameraTransform$>._viewport;
|
||||
<@else@>
|
||||
<$viewport$> = transformCamera_viewport;
|
||||
<@endif@>
|
||||
<@endfunc@>
|
||||
|
||||
<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@>
|
||||
<@if GPU_TRANSFORM_PROFILE == GPU_CORE@>
|
||||
|
|
|
@ -667,11 +667,6 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co
|
|||
element = NULL;
|
||||
}
|
||||
delete[] octalCode; // cleanup memory
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
if (element) {
|
||||
element->auditChildren("Octree::getOctreeElementAt()");
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
return element;
|
||||
}
|
||||
|
||||
|
@ -680,11 +675,6 @@ OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, fl
|
|||
OctreeElement* element = nodeForOctalCode(_rootElement, octalCode, NULL);
|
||||
|
||||
delete[] octalCode; // cleanup memory
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
if (element) {
|
||||
element->auditChildren("Octree::getOctreeElementAt()");
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
return element;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,6 +195,8 @@ public:
|
|||
SharedNodePointer sourceNode;
|
||||
bool wantImportProgress;
|
||||
PacketVersion bitstreamVersion;
|
||||
int elementsPerPacket = 0;
|
||||
int entitiesPerPacket = 0;
|
||||
|
||||
ReadBitstreamToTreeParams(
|
||||
bool includeColor = WANT_COLOR,
|
||||
|
|
|
@ -71,19 +71,9 @@ void OctreeElement::init(unsigned char * octalCode) {
|
|||
_childrenExternal = false;
|
||||
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
_children.external = NULL;
|
||||
_singleChildrenCount++;
|
||||
#endif
|
||||
_childrenCount[0]++;
|
||||
|
||||
// default pointers to child nodes to NULL
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
_childrenArray[i] = NULL;
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
#ifdef SIMPLE_CHILD_ARRAY
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
_simpleChildArray[i] = NULL;
|
||||
|
@ -218,9 +208,6 @@ void OctreeElement::deleteChildAtIndex(int childIndex) {
|
|||
_voxelNodeLeafCount++;
|
||||
}
|
||||
}
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
auditChildren("deleteChildAtIndex()");
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
}
|
||||
|
||||
// does not delete the node!
|
||||
|
@ -236,10 +223,6 @@ OctreeElement* OctreeElement::removeChildAtIndex(int childIndex) {
|
|||
_voxelNodeLeafCount++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
auditChildren("removeChildAtIndex()");
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
return returnedChild;
|
||||
}
|
||||
|
||||
|
@ -255,60 +238,11 @@ bool OctreeElement::isParentOf(OctreeElement* possibleChild) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
void OctreeElement::auditChildren(const char* label) const {
|
||||
bool auditFailed = false;
|
||||
for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) {
|
||||
OctreeElement* testChildNew = getChildAtIndex(childIndex);
|
||||
OctreeElement* testChildOld = _childrenArray[childIndex];
|
||||
|
||||
if (testChildNew != testChildOld) {
|
||||
auditFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
const bool alwaysReport = false; // set this to true to get additional debugging
|
||||
if (alwaysReport || auditFailed) {
|
||||
qDebug("%s... auditChildren() %s <<<<", label, (auditFailed ? "FAILED" : "PASSED"));
|
||||
qDebug(" _childrenExternal=%s", debug::valueOf(_childrenExternal));
|
||||
qDebug(" childCount=%d", getChildCount());
|
||||
|
||||
QDebug bitOutput = qDebug().nospace();
|
||||
bitOutput << " _childBitmask=";
|
||||
outputBits(_childBitmask, bitOutput);
|
||||
|
||||
|
||||
for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) {
|
||||
OctreeElement* testChildNew = getChildAtIndex(childIndex);
|
||||
OctreeElement* testChildOld = _childrenArray[childIndex];
|
||||
|
||||
qCebug("child at index %d... testChildOld=%p testChildNew=%p %s",
|
||||
childIndex, testChildOld, testChildNew ,
|
||||
((testChildNew != testChildOld) ? " DOES NOT MATCH <<<< BAD <<<<" : " - OK ")
|
||||
);
|
||||
}
|
||||
qDebug("%s... auditChildren() <<<< DONE <<<<", label);
|
||||
}
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
|
||||
quint64 OctreeElement::_getChildAtIndexTime = 0;
|
||||
quint64 OctreeElement::_getChildAtIndexCalls = 0;
|
||||
quint64 OctreeElement::_setChildAtIndexTime = 0;
|
||||
quint64 OctreeElement::_setChildAtIndexCalls = 0;
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
quint64 OctreeElement::_singleChildrenCount = 0;
|
||||
quint64 OctreeElement::_twoChildrenOffsetCount = 0;
|
||||
quint64 OctreeElement::_twoChildrenExternalCount = 0;
|
||||
quint64 OctreeElement::_threeChildrenOffsetCount = 0;
|
||||
quint64 OctreeElement::_threeChildrenExternalCount = 0;
|
||||
quint64 OctreeElement::_couldStoreFourChildrenInternally = 0;
|
||||
quint64 OctreeElement::_couldNotStoreFourChildrenInternally = 0;
|
||||
#endif
|
||||
|
||||
quint64 OctreeElement::_externalChildrenCount = 0;
|
||||
quint64 OctreeElement::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
|
@ -341,319 +275,8 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const {
|
|||
} break;
|
||||
}
|
||||
#endif // def SIMPLE_EXTERNAL_CHILDREN
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
PerformanceWarning warn(false,"getChildAtIndex",false,&_getChildAtIndexTime,&_getChildAtIndexCalls);
|
||||
OctreeElement* result = NULL;
|
||||
int childCount = getChildCount();
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
const char* caseStr = NULL;
|
||||
#endif
|
||||
|
||||
switch (childCount) {
|
||||
case 0:
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
caseStr = "0 child case";
|
||||
#endif
|
||||
break;
|
||||
case 1: {
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
caseStr = "1 child case";
|
||||
#endif
|
||||
int indexOne = getNthBit(_childBitmask, 1);
|
||||
if (indexOne == childIndex) {
|
||||
result = _children.single;
|
||||
}
|
||||
} break;
|
||||
case 2: {
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
caseStr = "2 child case";
|
||||
#endif
|
||||
int indexOne = getNthBit(_childBitmask, 1);
|
||||
int indexTwo = getNthBit(_childBitmask, 2);
|
||||
|
||||
if (_childrenExternal) {
|
||||
//assert(_children.external);
|
||||
if (indexOne == childIndex) {
|
||||
result = _children.external[0];
|
||||
} else if (indexTwo == childIndex) {
|
||||
result = _children.external[1];
|
||||
}
|
||||
} else {
|
||||
if (indexOne == childIndex) {
|
||||
int32_t offset = _children.offsetsTwoChildren[0];
|
||||
result = (OctreeElement*)((uint8_t*)this + offset);
|
||||
} else if (indexTwo == childIndex) {
|
||||
int32_t offset = _children.offsetsTwoChildren[1];
|
||||
result = (OctreeElement*)((uint8_t*)this + offset);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case 3: {
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
caseStr = "3 child case";
|
||||
#endif
|
||||
int indexOne = getNthBit(_childBitmask, 1);
|
||||
int indexTwo = getNthBit(_childBitmask, 2);
|
||||
int indexThree = getNthBit(_childBitmask, 3);
|
||||
|
||||
if (_childrenExternal) {
|
||||
//assert(_children.external);
|
||||
if (indexOne == childIndex) {
|
||||
result = _children.external[0];
|
||||
} else if (indexTwo == childIndex) {
|
||||
result = _children.external[1];
|
||||
} else if (indexThree == childIndex) {
|
||||
result = _children.external[2];
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
int64_t offsetOne, offsetTwo, offsetThree;
|
||||
decodeThreeOffsets(offsetOne, offsetTwo, offsetThree);
|
||||
|
||||
if (indexOne == childIndex) {
|
||||
result = (OctreeElement*)((uint8_t*)this + offsetOne);
|
||||
} else if (indexTwo == childIndex) {
|
||||
result = (OctreeElement*)((uint8_t*)this + offsetTwo);
|
||||
} else if (indexThree == childIndex) {
|
||||
result = (OctreeElement*)((uint8_t*)this + offsetThree);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
caseStr = "default";
|
||||
#endif
|
||||
// if we have 4 or more, we know we're in external mode, so we just need to figure out which
|
||||
// slot in our external array this child is.
|
||||
if (oneAtBit(_childBitmask, childIndex)) {
|
||||
childCount = getChildCount();
|
||||
for (int ordinal = 1; ordinal <= childCount; ordinal++) {
|
||||
int index = getNthBit(_childBitmask, ordinal);
|
||||
if (index == childIndex) {
|
||||
int externalIndex = ordinal-1;
|
||||
if (externalIndex < childCount && externalIndex >= 0) {
|
||||
result = _children.external[externalIndex];
|
||||
} else {
|
||||
qCDebug(octree, "getChildAtIndex() attempt to access external client out of "
|
||||
"bounds externalIndex=%d <<<<<<<<<< WARNING!!!", externalIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
if (result != _childrenArray[childIndex]) {
|
||||
qCDebug(octree, "getChildAtIndex() case:%s result<%p> != _childrenArray[childIndex]<%p> <<<<<<<<<< WARNING!!!",
|
||||
caseStr, result,_childrenArray[childIndex]);
|
||||
}
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
void OctreeElement::storeTwoChildren(OctreeElement* childOne, OctreeElement* childTwo) {
|
||||
int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this;
|
||||
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
||||
|
||||
const int64_t minOffset = std::numeric_limits<int32_t>::min();
|
||||
const int64_t maxOffset = std::numeric_limits<int32_t>::max();
|
||||
|
||||
bool forceExternal = true;
|
||||
if (!forceExternal && isBetween(offsetOne, maxOffset, minOffset) && isBetween(offsetTwo, maxOffset, minOffset)) {
|
||||
// if previously external, then clean it up...
|
||||
if (_childrenExternal) {
|
||||
//assert(_children.external);
|
||||
const int previousChildCount = 2;
|
||||
_externalChildrenMemoryUsage -= previousChildCount * sizeof(OctreeElement*);
|
||||
delete[] _children.external;
|
||||
_children.external = NULL; // probably not needed!
|
||||
_childrenExternal = false;
|
||||
}
|
||||
|
||||
// encode in union
|
||||
_children.offsetsTwoChildren[0] = offsetOne;
|
||||
_children.offsetsTwoChildren[1] = offsetTwo;
|
||||
|
||||
_twoChildrenOffsetCount++;
|
||||
} else {
|
||||
// encode in array
|
||||
|
||||
// if not previously external, then allocate appropriately
|
||||
if (!_childrenExternal) {
|
||||
_childrenExternal = true;
|
||||
const int newChildCount = 2;
|
||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||
_children.external = new OctreeElement*[newChildCount];
|
||||
memset(_children.external, 0, sizeof(OctreeElement*) * newChildCount);
|
||||
}
|
||||
_children.external[0] = childOne;
|
||||
_children.external[1] = childTwo;
|
||||
_twoChildrenExternalCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeElement::retrieveTwoChildren(OctreeElement*& childOne, OctreeElement*& childTwo) {
|
||||
// If we previously had an external array, then get the
|
||||
if (_childrenExternal) {
|
||||
childOne = _children.external[0];
|
||||
childTwo = _children.external[1];
|
||||
delete[] _children.external;
|
||||
_children.external = NULL; // probably not needed!
|
||||
_childrenExternal = false;
|
||||
_twoChildrenExternalCount--;
|
||||
const int newChildCount = 2;
|
||||
_externalChildrenMemoryUsage -= newChildCount * sizeof(OctreeElement*);
|
||||
} else {
|
||||
int64_t offsetOne = _children.offsetsTwoChildren[0];
|
||||
int64_t offsetTwo = _children.offsetsTwoChildren[1];
|
||||
childOne = (OctreeElement*)((uint8_t*)this + offsetOne);
|
||||
childTwo = (OctreeElement*)((uint8_t*)this + offsetTwo);
|
||||
_twoChildrenOffsetCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeElement::decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const {
|
||||
const quint64 ENCODE_BITS = 21;
|
||||
const quint64 ENCODE_MASK = 0xFFFFF;
|
||||
const quint64 ENCODE_MASK_SIGN = 0x100000;
|
||||
|
||||
quint64 offsetEncodedOne = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 2)) & ENCODE_MASK;
|
||||
quint64 offsetEncodedTwo = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 1)) & ENCODE_MASK;
|
||||
quint64 offsetEncodedThree = (_children.offsetsThreeChildrenEncoded & ENCODE_MASK);
|
||||
|
||||
quint64 signEncodedOne = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 2)) & ENCODE_MASK_SIGN;
|
||||
quint64 signEncodedTwo = (_children.offsetsThreeChildrenEncoded >> (ENCODE_BITS * 1)) & ENCODE_MASK_SIGN;
|
||||
quint64 signEncodedThree = (_children.offsetsThreeChildrenEncoded & ENCODE_MASK_SIGN);
|
||||
|
||||
bool oneNegative = signEncodedOne == ENCODE_MASK_SIGN;
|
||||
bool twoNegative = signEncodedTwo == ENCODE_MASK_SIGN;
|
||||
bool threeNegative = signEncodedThree == ENCODE_MASK_SIGN;
|
||||
|
||||
offsetOne = oneNegative ? -offsetEncodedOne : offsetEncodedOne;
|
||||
offsetTwo = twoNegative ? -offsetEncodedTwo : offsetEncodedTwo;
|
||||
offsetThree = threeNegative ? -offsetEncodedThree : offsetEncodedThree;
|
||||
}
|
||||
|
||||
void OctreeElement::encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree) {
|
||||
const quint64 ENCODE_BITS = 21;
|
||||
const quint64 ENCODE_MASK = 0xFFFFF;
|
||||
const quint64 ENCODE_MASK_SIGN = 0x100000;
|
||||
|
||||
quint64 offsetEncodedOne, offsetEncodedTwo, offsetEncodedThree;
|
||||
if (offsetOne < 0) {
|
||||
offsetEncodedOne = ((-offsetOne & ENCODE_MASK) | ENCODE_MASK_SIGN);
|
||||
} else {
|
||||
offsetEncodedOne = offsetOne & ENCODE_MASK;
|
||||
}
|
||||
offsetEncodedOne = offsetEncodedOne << (ENCODE_BITS * 2);
|
||||
|
||||
if (offsetTwo < 0) {
|
||||
offsetEncodedTwo = ((-offsetTwo & ENCODE_MASK) | ENCODE_MASK_SIGN);
|
||||
} else {
|
||||
offsetEncodedTwo = offsetTwo & ENCODE_MASK;
|
||||
}
|
||||
offsetEncodedTwo = offsetEncodedTwo << ENCODE_BITS;
|
||||
|
||||
if (offsetThree < 0) {
|
||||
offsetEncodedThree = ((-offsetThree & ENCODE_MASK) | ENCODE_MASK_SIGN);
|
||||
} else {
|
||||
offsetEncodedThree = offsetThree & ENCODE_MASK;
|
||||
}
|
||||
_children.offsetsThreeChildrenEncoded = offsetEncodedOne | offsetEncodedTwo | offsetEncodedThree;
|
||||
}
|
||||
|
||||
void OctreeElement::storeThreeChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree) {
|
||||
int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this;
|
||||
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
||||
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
||||
|
||||
const int64_t minOffset = -1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::min();
|
||||
const int64_t maxOffset = 1048576; // what can fit in 20 bits // std::numeric_limits<int16_t>::max();
|
||||
|
||||
bool forceExternal = true;
|
||||
if (!forceExternal &&
|
||||
isBetween(offsetOne, maxOffset, minOffset) &&
|
||||
isBetween(offsetTwo, maxOffset, minOffset) &&
|
||||
isBetween(offsetThree, maxOffset, minOffset)) {
|
||||
// if previously external, then clean it up...
|
||||
if (_childrenExternal) {
|
||||
delete[] _children.external;
|
||||
_children.external = NULL; // probably not needed!
|
||||
_childrenExternal = false;
|
||||
const int previousChildCount = 3;
|
||||
_externalChildrenMemoryUsage -= previousChildCount * sizeof(OctreeElement*);
|
||||
}
|
||||
// encode in union
|
||||
encodeThreeOffsets(offsetOne, offsetTwo, offsetThree);
|
||||
_threeChildrenOffsetCount++;
|
||||
} else {
|
||||
// encode in array
|
||||
|
||||
// if not previously external, then allocate appropriately
|
||||
if (!_childrenExternal) {
|
||||
_childrenExternal = true;
|
||||
const int newChildCount = 3;
|
||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||
_children.external = new OctreeElement*[newChildCount];
|
||||
memset(_children.external, 0, sizeof(OctreeElement*) * newChildCount);
|
||||
}
|
||||
_children.external[0] = childOne;
|
||||
_children.external[1] = childTwo;
|
||||
_children.external[2] = childThree;
|
||||
_threeChildrenExternalCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeElement::retrieveThreeChildren(OctreeElement*& childOne, OctreeElement*& childTwo, OctreeElement*& childThree) {
|
||||
// If we previously had an external array, then get the
|
||||
if (_childrenExternal) {
|
||||
childOne = _children.external[0];
|
||||
childTwo = _children.external[1];
|
||||
childThree = _children.external[2];
|
||||
delete[] _children.external;
|
||||
_children.external = NULL; // probably not needed!
|
||||
_childrenExternal = false;
|
||||
_threeChildrenExternalCount--;
|
||||
_externalChildrenMemoryUsage -= 3 * sizeof(OctreeElement*);
|
||||
} else {
|
||||
int64_t offsetOne, offsetTwo, offsetThree;
|
||||
decodeThreeOffsets(offsetOne, offsetTwo, offsetThree);
|
||||
|
||||
childOne = (OctreeElement*)((uint8_t*)this + offsetOne);
|
||||
childTwo = (OctreeElement*)((uint8_t*)this + offsetTwo);
|
||||
childThree = (OctreeElement*)((uint8_t*)this + offsetThree);
|
||||
_threeChildrenOffsetCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeElement::checkStoreFourChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree, OctreeElement* childFour) {
|
||||
int64_t offsetOne = (uint8_t*)childOne - (uint8_t*)this;
|
||||
int64_t offsetTwo = (uint8_t*)childTwo - (uint8_t*)this;
|
||||
int64_t offsetThree = (uint8_t*)childThree - (uint8_t*)this;
|
||||
int64_t offsetFour = (uint8_t*)childFour - (uint8_t*)this;
|
||||
|
||||
const int64_t minOffset = std::numeric_limits<int16_t>::min();
|
||||
const int64_t maxOffset = std::numeric_limits<int16_t>::max();
|
||||
|
||||
bool forceExternal = true;
|
||||
if (!forceExternal &&
|
||||
isBetween(offsetOne, maxOffset, minOffset) &&
|
||||
isBetween(offsetTwo, maxOffset, minOffset) &&
|
||||
isBetween(offsetThree, maxOffset, minOffset) &&
|
||||
isBetween(offsetFour, maxOffset, minOffset)
|
||||
) {
|
||||
_couldStoreFourChildrenInternally++;
|
||||
} else {
|
||||
_couldNotStoreFourChildrenInternally++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OctreeElement::deleteAllChildren() {
|
||||
// first delete all the OctreeElement objects...
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
|
@ -667,52 +290,6 @@ void OctreeElement::deleteAllChildren() {
|
|||
// if the children_t union represents _children.external we need to delete it here
|
||||
delete[] _children.external;
|
||||
}
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
// now, reset our internal state and ANY and all population data
|
||||
int childCount = getChildCount();
|
||||
switch (childCount) {
|
||||
case 0: {
|
||||
_singleChildrenCount--;
|
||||
_childrenCount[0]--;
|
||||
} break;
|
||||
case 1: {
|
||||
_singleChildrenCount--;
|
||||
_childrenCount[1]--;
|
||||
} break;
|
||||
|
||||
case 2: {
|
||||
if (_childrenExternal) {
|
||||
_twoChildrenExternalCount--;
|
||||
} else {
|
||||
_twoChildrenOffsetCount--;
|
||||
}
|
||||
_childrenCount[2]--;
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
if (_childrenExternal) {
|
||||
_threeChildrenExternalCount--;
|
||||
} else {
|
||||
_threeChildrenOffsetCount--;
|
||||
}
|
||||
_childrenCount[3]--;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
_externalChildrenCount--;
|
||||
_childrenCount[childCount]--;
|
||||
} break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// If we had externally stored children, clean them too.
|
||||
if (_childrenExternal && _children.external) {
|
||||
delete[] _children.external;
|
||||
}
|
||||
_children.single = NULL;
|
||||
#endif // BLENDED_UNION_CHILDREN
|
||||
}
|
||||
|
||||
void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
||||
|
@ -788,353 +365,6 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) {
|
|||
}
|
||||
|
||||
#endif // def SIMPLE_EXTERNAL_CHILDREN
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls);
|
||||
|
||||
// Here's how we store things...
|
||||
// If we have 0 or 1 children, then we just store them in the _children.single;
|
||||
// If we have 2 children,
|
||||
// then if we can we store them as 32 bit signed offsets from our own this pointer,
|
||||
// _children.offsetsTwoChildren[0]-[1]
|
||||
// these are 32 bit offsets
|
||||
|
||||
unsigned char previousChildMask = _childBitmask;
|
||||
int previousChildCount = getChildCount();
|
||||
if (child) {
|
||||
setAtBit(_childBitmask, childIndex);
|
||||
} else {
|
||||
clearAtBit(_childBitmask, childIndex);
|
||||
}
|
||||
int newChildCount = getChildCount();
|
||||
|
||||
// track our population data
|
||||
if (previousChildCount != newChildCount) {
|
||||
_childrenCount[previousChildCount]--;
|
||||
_childrenCount[newChildCount]++;
|
||||
}
|
||||
|
||||
// If we had 0 children and we still have 0 children, then there is nothing to do.
|
||||
if (previousChildCount == 0 && newChildCount == 0) {
|
||||
// nothing to do...
|
||||
} else if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 1) {
|
||||
// If we had 0 children, and we're setting our first child or if we had 1 child, or we're resetting the same child,
|
||||
// then we can just store it in _children.single
|
||||
_children.single = child;
|
||||
} else if (previousChildCount == 1 && newChildCount == 0) {
|
||||
// If we had 1 child, and we've removed our last child, then we can just store NULL in _children.single
|
||||
_children.single = NULL;
|
||||
} else if (previousChildCount == 1 && newChildCount == 2) {
|
||||
// If we had 1 child, and we're adding a second child, then we need to determine
|
||||
// if we can use offsets to store them
|
||||
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
|
||||
if (getNthBit(previousChildMask, 1) < childIndex) {
|
||||
childOne = _children.single;
|
||||
childTwo = child;
|
||||
} else {
|
||||
childOne = child;
|
||||
childTwo = _children.single;
|
||||
}
|
||||
|
||||
_singleChildrenCount--;
|
||||
storeTwoChildren(childOne, childTwo);
|
||||
} else if (previousChildCount == 2 && newChildCount == 1) {
|
||||
// If we had 2 children, and we're removing one, then we know we can go down to single mode
|
||||
//assert(child == NULL); // this is the only logical case
|
||||
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
bool keepChildOne = indexTwo == childIndex;
|
||||
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
|
||||
retrieveTwoChildren(childOne, childTwo);
|
||||
|
||||
_singleChildrenCount++;
|
||||
|
||||
if (keepChildOne) {
|
||||
_children.single = childOne;
|
||||
} else {
|
||||
_children.single = childTwo;
|
||||
}
|
||||
} else if (previousChildCount == 2 && newChildCount == 2) {
|
||||
// If we had 2 children, and still have 2, then we know we are resetting one of our existing children
|
||||
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
bool replaceChildOne = indexOne == childIndex;
|
||||
|
||||
// Get the existing two children out of their encoding...
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
retrieveTwoChildren(childOne, childTwo);
|
||||
|
||||
if (replaceChildOne) {
|
||||
childOne = child;
|
||||
} else {
|
||||
childTwo = child;
|
||||
}
|
||||
|
||||
storeTwoChildren(childOne, childTwo);
|
||||
|
||||
} else if (previousChildCount == 2 && newChildCount == 3) {
|
||||
// If we had 2 children, and now have 3, then we know we are going to an external case...
|
||||
|
||||
// First, decode the children...
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
OctreeElement* childThree;
|
||||
|
||||
// Get the existing two children out of their encoding...
|
||||
retrieveTwoChildren(childOne, childTwo);
|
||||
|
||||
// determine order of the existing children
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
|
||||
if (childIndex < indexOne) {
|
||||
childThree = childTwo;
|
||||
childTwo = childOne;
|
||||
childOne = child;
|
||||
} else if (childIndex < indexTwo) {
|
||||
childThree = childTwo;
|
||||
childTwo = child;
|
||||
} else {
|
||||
childThree = child;
|
||||
}
|
||||
storeThreeChildren(childOne, childTwo, childThree);
|
||||
} else if (previousChildCount == 3 && newChildCount == 2) {
|
||||
// If we had 3 children, and now have 2, then we know we are going from an external case to a potential internal case
|
||||
|
||||
// We need to determine which children we had, and which one we got rid of...
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
|
||||
bool removeChildOne = indexOne == childIndex;
|
||||
bool removeChildTwo = indexTwo == childIndex;
|
||||
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
OctreeElement* childThree;
|
||||
|
||||
// Get the existing two children out of their encoding...
|
||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||
|
||||
if (removeChildOne) {
|
||||
childOne = childTwo;
|
||||
childTwo = childThree;
|
||||
} else if (removeChildTwo) {
|
||||
childTwo = childThree;
|
||||
} else {
|
||||
// removing child three, nothing to do.
|
||||
}
|
||||
|
||||
storeTwoChildren(childOne, childTwo);
|
||||
} else if (previousChildCount == 3 && newChildCount == 3) {
|
||||
// If we had 3 children, and now have 3, then we need to determine which item we're replacing...
|
||||
|
||||
// We need to determine which children we had, and which one we got rid of...
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
|
||||
bool replaceChildOne = indexOne == childIndex;
|
||||
bool replaceChildTwo = indexTwo == childIndex;
|
||||
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
OctreeElement* childThree;
|
||||
|
||||
// Get the existing two children out of their encoding...
|
||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||
|
||||
if (replaceChildOne) {
|
||||
childOne = child;
|
||||
} else if (replaceChildTwo) {
|
||||
childTwo = child;
|
||||
} else {
|
||||
childThree = child;
|
||||
}
|
||||
|
||||
storeThreeChildren(childOne, childTwo, childThree);
|
||||
} else if (previousChildCount == 3 && newChildCount == 4) {
|
||||
// If we had 3 children, and now have 4, then we know we are going to an external case...
|
||||
|
||||
// First, decode the children...
|
||||
OctreeElement* childOne;
|
||||
OctreeElement* childTwo;
|
||||
OctreeElement* childThree;
|
||||
OctreeElement* childFour;
|
||||
|
||||
// Get the existing two children out of their encoding...
|
||||
retrieveThreeChildren(childOne, childTwo, childThree);
|
||||
|
||||
// determine order of the existing children
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
int indexThree = getNthBit(previousChildMask, 3);
|
||||
|
||||
if (childIndex < indexOne) {
|
||||
childFour = childThree;
|
||||
childThree = childTwo;
|
||||
childTwo = childOne;
|
||||
childOne = child;
|
||||
} else if (childIndex < indexTwo) {
|
||||
childFour = childThree;
|
||||
childThree = childTwo;
|
||||
childTwo = child;
|
||||
} else if (childIndex < indexThree) {
|
||||
childFour = childThree;
|
||||
childThree = child;
|
||||
} else {
|
||||
childFour = child;
|
||||
}
|
||||
|
||||
// now, allocate the external...
|
||||
_childrenExternal = true;
|
||||
const int newChildCount = 4;
|
||||
_children.external = new OctreeElement*[newChildCount];
|
||||
memset(_children.external, 0, sizeof(OctreeElement*) * newChildCount);
|
||||
|
||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||
|
||||
_children.external[0] = childOne;
|
||||
_children.external[1] = childTwo;
|
||||
_children.external[2] = childThree;
|
||||
_children.external[3] = childFour;
|
||||
_externalChildrenCount++;
|
||||
} else if (previousChildCount == 4 && newChildCount == 3) {
|
||||
// If we had 4 children, and now have 3, then we know we are going from an external case to a potential internal case
|
||||
//assert(_children.external && _childrenExternal && previousChildCount == 4);
|
||||
|
||||
// We need to determine which children we had, and which one we got rid of...
|
||||
int indexOne = getNthBit(previousChildMask, 1);
|
||||
int indexTwo = getNthBit(previousChildMask, 2);
|
||||
int indexThree = getNthBit(previousChildMask, 3);
|
||||
|
||||
bool removeChildOne = indexOne == childIndex;
|
||||
bool removeChildTwo = indexTwo == childIndex;
|
||||
bool removeChildThree = indexThree == childIndex;
|
||||
|
||||
OctreeElement* childOne = _children.external[0];
|
||||
OctreeElement* childTwo = _children.external[1];
|
||||
OctreeElement* childThree = _children.external[2];
|
||||
OctreeElement* childFour = _children.external[3];
|
||||
|
||||
if (removeChildOne) {
|
||||
childOne = childTwo;
|
||||
childTwo = childThree;
|
||||
childThree = childFour;
|
||||
} else if (removeChildTwo) {
|
||||
childTwo = childThree;
|
||||
childThree = childFour;
|
||||
} else if (removeChildThree) {
|
||||
childThree = childFour;
|
||||
} else {
|
||||
// removing child four, nothing to do.
|
||||
}
|
||||
|
||||
// clean up the external children...
|
||||
_childrenExternal = false;
|
||||
delete[] _children.external;
|
||||
_children.external = NULL;
|
||||
_externalChildrenCount--;
|
||||
_externalChildrenMemoryUsage -= previousChildCount * sizeof(OctreeElement*);
|
||||
storeThreeChildren(childOne, childTwo, childThree);
|
||||
} else if (previousChildCount == newChildCount) {
|
||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||
//assert(previousChildCount == newChildCount);
|
||||
|
||||
// 4 or more children, one item being replaced, we know we're stored externally, we just need to find the one
|
||||
// that needs to be replaced and replace it.
|
||||
for (int ordinal = 1; ordinal <= 8; ordinal++) {
|
||||
int index = getNthBit(previousChildMask, ordinal);
|
||||
if (index == childIndex) {
|
||||
// this is our child to be replaced
|
||||
int nthChild = ordinal-1;
|
||||
_children.external[nthChild] = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (previousChildCount < newChildCount) {
|
||||
// Growing case... previous must be 4 or greater
|
||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||
//assert(previousChildCount == newChildCount-1);
|
||||
|
||||
// 4 or more children, one item being added, we know we're stored externally, we just figure out where to insert
|
||||
// this child pointer into our external list
|
||||
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
||||
memset(newExternalList, 0, sizeof(OctreeElement*) * newChildCount);
|
||||
|
||||
int copiedCount = 0;
|
||||
for (int ordinal = 1; ordinal <= newChildCount; ordinal++) {
|
||||
int index = getNthBit(previousChildMask, ordinal);
|
||||
if (index != -1 && index < childIndex) {
|
||||
newExternalList[ordinal - 1] = _children.external[ordinal - 1];
|
||||
copiedCount++;
|
||||
} else {
|
||||
|
||||
// insert our new child here...
|
||||
newExternalList[ordinal - 1] = child;
|
||||
|
||||
// if we didn't copy all of our previous children, then we need to
|
||||
if (copiedCount < previousChildCount) {
|
||||
// our child needs to be inserted before this index, and everything else pushed out...
|
||||
for (int oldOrdinal = ordinal; oldOrdinal <= previousChildCount; oldOrdinal++) {
|
||||
newExternalList[oldOrdinal] = _children.external[oldOrdinal - 1];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] _children.external;
|
||||
_children.external = newExternalList;
|
||||
_externalChildrenMemoryUsage -= previousChildCount * sizeof(OctreeElement*);
|
||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||
|
||||
} else if (previousChildCount > newChildCount) {
|
||||
//assert(_children.external && _childrenExternal && previousChildCount >= 4);
|
||||
//assert(previousChildCount == newChildCount+1);
|
||||
|
||||
// 4 or more children, one item being removed, we know we're stored externally, we just figure out which
|
||||
// item to remove from our external list
|
||||
OctreeElement** newExternalList = new OctreeElement*[newChildCount];
|
||||
|
||||
for (int ordinal = 1; ordinal <= previousChildCount; ordinal++) {
|
||||
int index = getNthBit(previousChildMask, ordinal);
|
||||
//assert(index != -1);
|
||||
if (index < childIndex) {
|
||||
newExternalList[ordinal - 1] = _children.external[ordinal - 1];
|
||||
} else {
|
||||
// our child needs to be removed from here, and everything else pulled in...
|
||||
for (int moveOrdinal = ordinal; moveOrdinal <= newChildCount; moveOrdinal++) {
|
||||
newExternalList[moveOrdinal - 1] = _children.external[moveOrdinal];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete[] _children.external;
|
||||
_children.external = newExternalList;
|
||||
_externalChildrenMemoryUsage -= previousChildCount * sizeof(OctreeElement*);
|
||||
_externalChildrenMemoryUsage += newChildCount * sizeof(OctreeElement*);
|
||||
} else {
|
||||
//assert(false);
|
||||
qCDebug(octree, "THIS SHOULD NOT HAPPEN previousChildCount == %d && newChildCount == %d",previousChildCount, newChildCount);
|
||||
}
|
||||
|
||||
// check to see if we could store these 4 children locally
|
||||
if (getChildCount() == 4 && _childrenExternal && _children.external) {
|
||||
checkStoreFourChildren(_children.external[0], _children.external[1], _children.external[2], _children.external[3]);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
_childrenArray[childIndex] = child;
|
||||
auditChildren("setChildAtIndex()");
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#ifndef hifi_OctreeElement_h
|
||||
#define hifi_OctreeElement_h
|
||||
|
||||
//#define HAS_AUDIT_CHILDREN
|
||||
//#define SIMPLE_CHILD_ARRAY
|
||||
#define SIMPLE_EXTERNAL_CHILDREN
|
||||
|
||||
|
@ -204,25 +203,9 @@ public:
|
|||
static quint64 getSetChildAtIndexTime() { return _setChildAtIndexTime; }
|
||||
static quint64 getSetChildAtIndexCalls() { return _setChildAtIndexCalls; }
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
static quint64 getSingleChildrenCount() { return _singleChildrenCount; }
|
||||
static quint64 getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; }
|
||||
static quint64 getTwoChildrenExternalCount() { return _twoChildrenExternalCount; }
|
||||
static quint64 getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; }
|
||||
static quint64 getThreeChildrenExternalCount() { return _threeChildrenExternalCount; }
|
||||
static quint64 getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; }
|
||||
static quint64 getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; }
|
||||
#endif
|
||||
|
||||
static quint64 getExternalChildrenCount() { return _externalChildrenCount; }
|
||||
static quint64 getChildrenCount(int childCount) { return _childrenCount[childCount]; }
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
void auditChildren(const char* label) const;
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
#endif // def BLENDED_UNION_CHILDREN
|
||||
|
||||
enum ChildIndex {
|
||||
CHILD_BOTTOM_RIGHT_NEAR = 0,
|
||||
CHILD_BOTTOM_RIGHT_FAR = 1,
|
||||
|
@ -261,15 +244,6 @@ protected:
|
|||
void deleteAllChildren();
|
||||
void setChildAtIndex(int childIndex, OctreeElement* child);
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
void storeTwoChildren(OctreeElement* childOne, OctreeElement* childTwo);
|
||||
void retrieveTwoChildren(OctreeElement*& childOne, OctreeElement*& childTwo);
|
||||
void storeThreeChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree);
|
||||
void retrieveThreeChildren(OctreeElement*& childOne, OctreeElement*& childTwo, OctreeElement*& childThree);
|
||||
void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const;
|
||||
void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree);
|
||||
void checkStoreFourChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree, OctreeElement* childFour);
|
||||
#endif
|
||||
void calculateAACube();
|
||||
void notifyDeleteHooks();
|
||||
void notifyUpdateHooks();
|
||||
|
@ -296,19 +270,6 @@ protected:
|
|||
} _children;
|
||||
#endif
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
union children_t {
|
||||
OctreeElement* single;
|
||||
int32_t offsetsTwoChildren[2];
|
||||
quint64 offsetsThreeChildrenEncoded;
|
||||
OctreeElement** external;
|
||||
} _children;
|
||||
#ifdef HAS_AUDIT_CHILDREN
|
||||
OctreeElement* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding
|
||||
#endif // def HAS_AUDIT_CHILDREN
|
||||
|
||||
#endif //def BLENDED_UNION_CHILDREN
|
||||
|
||||
uint16_t _sourceUUIDKey; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
||||
|
||||
// Support for _sourceUUID, we use these static member variables to track the UUIDs that are
|
||||
|
@ -345,15 +306,6 @@ protected:
|
|||
static quint64 _setChildAtIndexTime;
|
||||
static quint64 _setChildAtIndexCalls;
|
||||
|
||||
#ifdef BLENDED_UNION_CHILDREN
|
||||
static quint64 _singleChildrenCount;
|
||||
static quint64 _twoChildrenOffsetCount;
|
||||
static quint64 _twoChildrenExternalCount;
|
||||
static quint64 _threeChildrenOffsetCount;
|
||||
static quint64 _threeChildrenExternalCount;
|
||||
static quint64 _couldStoreFourChildrenInternally;
|
||||
static quint64 _couldNotStoreFourChildrenInternally;
|
||||
#endif
|
||||
static quint64 _externalChildrenCount;
|
||||
static quint64 _childrenCount[NUMBER_OF_CHILDREN + 1];
|
||||
};
|
||||
|
|
|
@ -12,9 +12,11 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <PerfStat.h>
|
||||
#include <RenderArgs.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "OctreeLogging.h"
|
||||
#include "OctreeRenderer.h"
|
||||
|
||||
|
@ -101,6 +103,15 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Shar
|
|||
sequence, flightTime, packetLength, dataBytes);
|
||||
}
|
||||
|
||||
_packetsInLastWindow++;
|
||||
|
||||
int elementsPerPacket = 0;
|
||||
int entitiesPerPacket = 0;
|
||||
|
||||
quint64 totalWaitingForLock = 0;
|
||||
quint64 totalUncompress = 0;
|
||||
quint64 totalReadBitsteam = 0;
|
||||
|
||||
int subsection = 1;
|
||||
while (dataBytes > 0) {
|
||||
if (packetIsCompressed) {
|
||||
|
@ -120,7 +131,12 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Shar
|
|||
// ask the VoxelTree to read the bitstream into the tree
|
||||
ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL,
|
||||
sourceUUID, sourceNode, false, packetVersion);
|
||||
quint64 startLock = usecTimestampNow();
|
||||
|
||||
// FIXME STUTTER - there may be an opportunity to bump this lock outside of the
|
||||
// loop to reduce the amount of locking/unlocking we're doing
|
||||
_tree->lockForWrite();
|
||||
quint64 startUncompress = usecTimestampNow();
|
||||
OctreePacketData packetData(packetIsCompressed);
|
||||
packetData.loadFinalizedContent(dataAt, sectionLength);
|
||||
if (extraDebugging) {
|
||||
|
@ -134,17 +150,56 @@ void OctreeRenderer::processDatagram(const QByteArray& dataByteArray, const Shar
|
|||
if (extraDebugging) {
|
||||
qCDebug(octree) << "OctreeRenderer::processDatagram() ******* START _tree->readBitstreamToTree()...";
|
||||
}
|
||||
quint64 startReadBitsteam = usecTimestampNow();
|
||||
_tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args);
|
||||
quint64 endReadBitsteam = usecTimestampNow();
|
||||
if (extraDebugging) {
|
||||
qCDebug(octree) << "OctreeRenderer::processDatagram() ******* END _tree->readBitstreamToTree()...";
|
||||
}
|
||||
_tree->unlock();
|
||||
|
||||
|
||||
dataBytes -= sectionLength;
|
||||
dataAt += sectionLength;
|
||||
|
||||
elementsPerPacket += args.elementsPerPacket;
|
||||
entitiesPerPacket += args.entitiesPerPacket;
|
||||
|
||||
_elementsInLastWindow += args.elementsPerPacket;
|
||||
_entitiesInLastWindow += args.entitiesPerPacket;
|
||||
|
||||
totalWaitingForLock += (startUncompress - startLock);
|
||||
totalUncompress += (startReadBitsteam - startUncompress);
|
||||
totalReadBitsteam += (endReadBitsteam - startReadBitsteam);
|
||||
|
||||
}
|
||||
subsection++;
|
||||
}
|
||||
_elementsPerPacket.updateAverage(elementsPerPacket);
|
||||
_entitiesPerPacket.updateAverage(entitiesPerPacket);
|
||||
|
||||
_waitLockPerPacket.updateAverage(totalWaitingForLock);
|
||||
_uncompressPerPacket.updateAverage(totalUncompress);
|
||||
_readBitstreamPerPacket.updateAverage(totalReadBitsteam);
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
if (_lastWindowAt == 0) {
|
||||
_lastWindowAt = now;
|
||||
}
|
||||
quint64 sinceLastWindow = now - _lastWindowAt;
|
||||
|
||||
if (sinceLastWindow > USECS_PER_SECOND) {
|
||||
float packetsPerSecondInWindow = (float)_packetsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND);
|
||||
float elementsPerSecondInWindow = (float)_elementsInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND);
|
||||
float entitiesPerSecondInWindow = (float)_entitiesInLastWindow / (float)(sinceLastWindow / USECS_PER_SECOND);
|
||||
_packetsPerSecond.updateAverage(packetsPerSecondInWindow);
|
||||
_elementsPerSecond.updateAverage(elementsPerSecondInWindow);
|
||||
_entitiesPerSecond.updateAverage(entitiesPerSecondInWindow);
|
||||
|
||||
_lastWindowAt = now;
|
||||
_packetsInLastWindow = 0;
|
||||
_elementsInLastWindow = 0;
|
||||
_entitiesInLastWindow = 0;
|
||||
}
|
||||
subsection++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,12 +61,40 @@ public:
|
|||
/// clears the tree
|
||||
virtual void clear();
|
||||
|
||||
float getAverageElementsPerPacket() const { return _elementsPerPacket.getAverage(); }
|
||||
float getAverageEntitiesPerPacket() const { return _entitiesPerPacket.getAverage(); }
|
||||
|
||||
float getAveragePacketsPerSecond() const { return _packetsPerSecond.getAverage(); }
|
||||
float getAverageElementsPerSecond() const { return _elementsPerSecond.getAverage(); }
|
||||
float getAverageEntitiesPerSecond() const { return _entitiesPerSecond.getAverage(); }
|
||||
|
||||
float getAverageWaitLockPerPacket() const { return _waitLockPerPacket.getAverage(); }
|
||||
float getAverageUncompressPerPacket() const { return _uncompressPerPacket.getAverage(); }
|
||||
float getAverageReadBitstreamPerPacket() const { return _readBitstreamPerPacket.getAverage(); }
|
||||
|
||||
protected:
|
||||
virtual Octree* createTree() = 0;
|
||||
|
||||
Octree* _tree;
|
||||
bool _managedTree;
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
SimpleMovingAverage _elementsPerPacket;
|
||||
SimpleMovingAverage _entitiesPerPacket;
|
||||
|
||||
SimpleMovingAverage _packetsPerSecond;
|
||||
SimpleMovingAverage _elementsPerSecond;
|
||||
SimpleMovingAverage _entitiesPerSecond;
|
||||
|
||||
SimpleMovingAverage _waitLockPerPacket;
|
||||
SimpleMovingAverage _uncompressPerPacket;
|
||||
SimpleMovingAverage _readBitstreamPerPacket;
|
||||
|
||||
quint64 _lastWindowAt = 0;
|
||||
int _packetsInLastWindow = 0;
|
||||
int _elementsInLastWindow = 0;
|
||||
int _entitiesInLastWindow = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_OctreeRenderer_h
|
||||
|
|
|
@ -910,6 +910,38 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
|
|||
return somethingAdded;
|
||||
}
|
||||
|
||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) {
|
||||
if (!_meshGroupsKnown && isLoadedWithTextures()) {
|
||||
segregateMeshGroups();
|
||||
}
|
||||
|
||||
bool somethingAdded = false;
|
||||
|
||||
foreach (auto renderItem, _transparentRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
_renderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _opaqueRenderItems) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
||||
auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
_renderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
_readyWhenAdded = readyToAddToScene();
|
||||
|
||||
return somethingAdded;
|
||||
}
|
||||
|
||||
void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
foreach (auto item, _renderItems.keys()) {
|
||||
pendingChanges.removeItem(item);
|
||||
|
|
|
@ -118,6 +118,7 @@ public:
|
|||
bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); }
|
||||
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoadedWithTextures(); }
|
||||
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters);
|
||||
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
||||
/// Sets the URL of the model to render.
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "RenderArgs.h"
|
||||
#include "TextureCache.h"
|
||||
|
||||
#include "render/DrawStatus.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "overlay3D_vert.h"
|
||||
|
@ -49,6 +51,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
|||
)));
|
||||
_jobs.push_back(Job(new CullItems::JobModel("CullOpaque", _jobs.back().getOutput())));
|
||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput())));
|
||||
auto& renderedOpaques = _jobs.back().getOutput();
|
||||
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
|
||||
_jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
|
||||
_jobs.push_back(Job(new ResetGLState::JobModel()));
|
||||
|
@ -65,6 +68,11 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
|||
_jobs.push_back(Job(new CullItems::JobModel("CullTransparent", _jobs.back().getOutput())));
|
||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
|
||||
_jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
|
||||
|
||||
_jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques)));
|
||||
_jobs.back().setEnabled(false);
|
||||
_drawStatusJobIndex = _jobs.size() - 1;
|
||||
|
||||
_jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D")));
|
||||
_jobs.push_back(Job(new ResetGLState::JobModel()));
|
||||
}
|
||||
|
@ -85,6 +93,9 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
|
|||
return;
|
||||
}
|
||||
|
||||
// Make sure we turn the displayItemStatus on/off
|
||||
setDrawItemStatus(renderContext->_drawItemStatus);
|
||||
|
||||
renderContext->args->_context->syncCache();
|
||||
|
||||
for (auto job : _jobs) {
|
||||
|
@ -135,7 +146,6 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
|
|||
void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
auto& renderDetails = renderContext->args->_details;
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::Batch batch;
|
||||
|
|
|
@ -70,6 +70,11 @@ public:
|
|||
|
||||
render::Jobs _jobs;
|
||||
|
||||
int _drawStatusJobIndex = -1;
|
||||
|
||||
void setDrawItemStatus(bool draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw); } }
|
||||
bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } }
|
||||
|
||||
virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
};
|
||||
|
|
174
libraries/render/src/render/DrawStatus.cpp
Normal file
174
libraries/render/src/render/DrawStatus.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
//
|
||||
// DrawStatus.cpp
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Niraj Venkat on 6/29/15.
|
||||
// Copyright 2015 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 <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
#include "DrawStatus.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include "gpu/GPULogging.h"
|
||||
|
||||
|
||||
#include "gpu/Batch.h"
|
||||
#include "gpu/Context.h"
|
||||
|
||||
#include "ViewFrustum.h"
|
||||
#include "RenderArgs.h"
|
||||
|
||||
#include "drawItemBounds_vert.h"
|
||||
#include "drawItemBounds_frag.h"
|
||||
#include "drawItemStatus_vert.h"
|
||||
#include "drawItemStatus_frag.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
||||
|
||||
const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() {
|
||||
if (!_drawItemBoundsPipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag)));
|
||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
_drawItemBoundPosLoc = program->getUniforms().findLocation("inBoundPos");
|
||||
_drawItemBoundDimLoc = program->getUniforms().findLocation("inBoundDim");
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_drawItemBoundsPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
return _drawItemBoundsPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() {
|
||||
if (!_drawItemStatusPipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag)));
|
||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
_drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos");
|
||||
_drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim");
|
||||
_drawItemStatusValueLoc = program->getUniforms().findLocation("inStatus");
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_drawItemStatusPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
return _drawItemStatusPipeline;
|
||||
}
|
||||
|
||||
void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
RenderArgs* args = renderContext->args;
|
||||
auto& scene = sceneContext->_scene;
|
||||
|
||||
// FIrst thing, we collect the bound and the status for all the items we want to render
|
||||
int nbItems = 0;
|
||||
{
|
||||
if (!_itemBounds) {
|
||||
_itemBounds.reset(new gpu::Buffer());
|
||||
}
|
||||
if (!_itemStatus) {
|
||||
_itemStatus.reset(new gpu::Buffer());
|
||||
}
|
||||
|
||||
_itemBounds->resize((inItems.size() * sizeof(AABox)));
|
||||
_itemStatus->resize((inItems.size() * sizeof(glm::vec4)));
|
||||
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
||||
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
||||
for (auto& item : inItems) {
|
||||
if (!item.bounds.isInvalid()) {
|
||||
if (!item.bounds.isNull()) {
|
||||
(*itemAABox) = item.bounds;
|
||||
} else {
|
||||
(*itemAABox).setBox(item.bounds.getCorner(), 0.1f);
|
||||
}
|
||||
auto& itemScene = scene->getItem(item.id);
|
||||
(*itemStatus) = itemScene.getStatusPackedValues();
|
||||
|
||||
nbItems++;
|
||||
itemAABox++;
|
||||
itemStatus++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nbItems == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allright, something to render let's do it
|
||||
gpu::Batch batch;
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
viewMat.postScale(glm::vec3(-1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(getDrawItemBoundsPipeline());
|
||||
|
||||
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
||||
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
||||
|
||||
const unsigned int VEC3_ADRESS_OFFSET = 3;
|
||||
|
||||
for (int i = 0; i < nbItems; i++) {
|
||||
batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const GLfloat*) (itemAABox + i));
|
||||
batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const GLfloat*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
||||
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
}
|
||||
|
||||
batch.setPipeline(getDrawItemStatusPipeline());
|
||||
for (int i = 0; i < nbItems; i++) {
|
||||
batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const GLfloat*) (itemAABox + i));
|
||||
batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const GLfloat*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
||||
batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const GLint*) (itemStatus + i));
|
||||
|
||||
batch.draw(gpu::TRIANGLES, 24, 0);
|
||||
}
|
||||
|
||||
// Before rendering the batch make sure we re in sync with gl state
|
||||
args->_context->syncCache();
|
||||
renderContext->args->_context->syncCache();
|
||||
args->_context->render((batch));
|
||||
}
|
43
libraries/render/src/render/DrawStatus.h
Normal file
43
libraries/render/src/render/DrawStatus.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// DrawStatus.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Niraj Venkat on 6/29/15.
|
||||
// Copyright 2015 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_render_DrawStatus_h
|
||||
#define hifi_render_DrawStatus_h
|
||||
|
||||
#include "DrawTask.h"
|
||||
#include "gpu/Batch.h"
|
||||
|
||||
namespace render {
|
||||
class DrawStatus {
|
||||
int _drawItemBoundPosLoc = -1;
|
||||
int _drawItemBoundDimLoc = -1;
|
||||
int _drawItemStatusPosLoc = -1;
|
||||
int _drawItemStatusDimLoc = -1;
|
||||
int _drawItemStatusValueLoc = -1;
|
||||
|
||||
gpu::Stream::FormatPointer _drawItemFormat;
|
||||
gpu::PipelinePointer _drawItemBoundsPipeline;
|
||||
gpu::PipelinePointer _drawItemStatusPipeline;
|
||||
gpu::BufferPointer _itemBounds;
|
||||
gpu::BufferPointer _itemStatus;
|
||||
|
||||
public:
|
||||
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
||||
|
||||
typedef Job::ModelI<DrawStatus, ItemIDsBounds> JobModel;
|
||||
|
||||
const gpu::PipelinePointer& getDrawItemBoundsPipeline();
|
||||
const gpu::PipelinePointer& getDrawItemStatusPipeline();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // hifi_render_DrawStatus_h
|
|
@ -59,7 +59,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
|||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
auto& scene = sceneContext->_scene;
|
||||
RenderArgs* args = renderContext->args;
|
||||
auto renderDetails = renderContext->args->_details._item;
|
||||
|
||||
|
@ -101,7 +100,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
|||
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(_filter);
|
||||
auto& renderDetails = renderContext->args->_details;
|
||||
|
||||
outItems.clear();
|
||||
outItems.reserve(items.size());
|
||||
|
@ -128,9 +126,10 @@ struct ItemBound {
|
|||
float _nearDepth = 0.0f;
|
||||
float _farDepth = 0.0f;
|
||||
ItemID _id = 0;
|
||||
AABox _bounds;
|
||||
|
||||
ItemBound() {}
|
||||
ItemBound(float centerDepth, float nearDepth, float farDepth, ItemID id) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id) {}
|
||||
ItemBound(float centerDepth, float nearDepth, float farDepth, ItemID id, const AABox& bounds) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id), _bounds(bounds) {}
|
||||
};
|
||||
|
||||
struct FrontToBackSort {
|
||||
|
@ -167,7 +166,7 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende
|
|||
auto bound = itemDetails.bounds; // item.getBound();
|
||||
float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter());
|
||||
|
||||
itemBounds.emplace_back(ItemBound(distance, distance, distance, itemDetails.id));
|
||||
itemBounds.emplace_back(ItemBound(distance, distance, distance, itemDetails.id, bound));
|
||||
}
|
||||
|
||||
// sort against Z
|
||||
|
@ -181,7 +180,7 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende
|
|||
|
||||
// FInally once sorted result to a list of itemID
|
||||
for (auto& itemBound : itemBounds) {
|
||||
outItems.emplace_back(itemBound._id);
|
||||
outItems.emplace_back(ItemIDAndBounds(itemBound._id, itemBound._bounds));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,9 @@ public:
|
|||
Job(const Job& other) : _concept(other._concept) {}
|
||||
~Job();
|
||||
|
||||
bool isEnabled() const { return _concept->isEnabled(); }
|
||||
void setEnabled(bool isEnabled) { _concept->setEnabled(isEnabled); }
|
||||
|
||||
const std::string& getName() const { return _concept->getName(); }
|
||||
const Varying getInput() const { return _concept->getInput(); }
|
||||
const Varying getOutput() const { return _concept->getOutput(); }
|
||||
|
@ -92,6 +95,7 @@ public:
|
|||
|
||||
class Concept {
|
||||
std::string _name;
|
||||
bool _isEnabled = true;
|
||||
public:
|
||||
Concept() : _name() {}
|
||||
Concept(const std::string& name) : _name(name) {}
|
||||
|
@ -99,7 +103,10 @@ public:
|
|||
|
||||
void setName(const std::string& name) { _name = name; }
|
||||
const std::string& getName() const { return _name; }
|
||||
|
||||
|
||||
bool isEnabled() const { return _isEnabled; }
|
||||
void setEnabled(bool isEnabled) { _isEnabled = isEnabled; }
|
||||
|
||||
virtual const Varying getInput() const { return Varying(); }
|
||||
virtual const Varying getOutput() const { return Varying(); }
|
||||
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0;
|
||||
|
@ -119,7 +126,11 @@ public:
|
|||
Model(Data data): _data(data) {}
|
||||
Model(Data data, const std::string& name): Concept(name), _data(data) {}
|
||||
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRun(_data, sceneContext, renderContext); }
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
if (isEnabled()) {
|
||||
jobRun(_data, sceneContext, renderContext);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class I> class ModelI : public Concept {
|
||||
|
@ -135,7 +146,11 @@ public:
|
|||
ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {}
|
||||
ModelI(const std::string& name, Data data): Concept(name), _data(data) {}
|
||||
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunI(_data, sceneContext, renderContext, _input.get<I>()); }
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
if (isEnabled()) {
|
||||
jobRunI(_data, sceneContext, renderContext, _input.get<I>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class O> class ModelO : public Concept {
|
||||
|
@ -155,7 +170,9 @@ public:
|
|||
ModelO(const std::string& name, Data data): Concept(name), _data(data), _output(Output()) {}
|
||||
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
|
||||
if (isEnabled()) {
|
||||
jobRunO(_data, sceneContext, renderContext, _output.edit<O>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,7 +194,11 @@ public:
|
|||
|
||||
void setInput(const Varying& input) { _input = input; }
|
||||
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>()); }
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
if (isEnabled()) {
|
||||
jobRunIO(_data, sceneContext, renderContext, _input.get<I>(), _output.edit<O>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<Concept> _concept;
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
int _numDrawnOverlay3DItems = 0;
|
||||
int _maxDrawnOverlay3DItems = -1;
|
||||
|
||||
bool _drawItemStatus = false;
|
||||
|
||||
RenderContext() {}
|
||||
};
|
||||
typedef std::shared_ptr<RenderContext> RenderContextPointer;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
//
|
||||
#include "Scene.h"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
using namespace render;
|
||||
|
||||
void ItemBucketMap::insert(const ItemID& id, const ItemKey& key) {
|
||||
|
@ -53,6 +55,50 @@ void ItemBucketMap::allocateStandardOpaqueTranparentBuckets() {
|
|||
(*this)[ItemFilter::Builder::transparentShape().withLayered()];
|
||||
}
|
||||
|
||||
const Item::Status::Value Item::Status::Value::INVALID = Item::Status::Value();
|
||||
|
||||
const float Item::Status::Value::RED = 0.0f;
|
||||
const float Item::Status::Value::YELLOW = 60.0f;
|
||||
const float Item::Status::Value::GREEN = 120.0f;
|
||||
const float Item::Status::Value::CYAN = 180.0f;
|
||||
const float Item::Status::Value::BLUE = 240.0f;
|
||||
const float Item::Status::Value::MAGENTA = 300.0f;
|
||||
|
||||
void Item::Status::Value::setScale(float scale) {
|
||||
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));
|
||||
}
|
||||
|
||||
void Item::Status::Value::setColor(float hue) {
|
||||
// Convert the HUe from range [0, 360] to signed normalized value
|
||||
const float HUE_MAX = 360.0f;
|
||||
_color = (std::numeric_limits<unsigned short>::max() - 1) * 0.5f * (1.0f + std::max(std::min(hue, HUE_MAX), 0.0f) / HUE_MAX);
|
||||
}
|
||||
|
||||
void Item::Status::getPackedValues(glm::ivec4& values) const {
|
||||
for (unsigned int i = 0; i < values.length(); i++) {
|
||||
if (i < _values.size()) {
|
||||
values[i] = _values[i]().getPackedData();
|
||||
} else {
|
||||
values[i] = Value::INVALID.getPackedData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Item::PayloadInterface::addStatusGetter(const Status::Getter& getter) {
|
||||
if (!_status) {
|
||||
_status.reset(new Status());
|
||||
}
|
||||
_status->addGetter(getter);
|
||||
}
|
||||
|
||||
void Item::PayloadInterface::addStatusGetters(const Status::Getters& getters) {
|
||||
if (!_status) {
|
||||
_status.reset(new Status());
|
||||
}
|
||||
for (auto& g : getters) {
|
||||
_status->addGetter(g);
|
||||
}
|
||||
}
|
||||
|
||||
void Item::resetPayload(const PayloadPointer& payload) {
|
||||
if (!payload) {
|
||||
|
@ -63,6 +109,15 @@ void Item::resetPayload(const PayloadPointer& payload) {
|
|||
}
|
||||
}
|
||||
|
||||
glm::ivec4 Item::getStatusPackedValues() const {
|
||||
glm::ivec4 values(Status::Value::INVALID.getPackedData());
|
||||
auto& status = getStatus();
|
||||
if (status) {
|
||||
status->getPackedValues(values);
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||
_resetItems.push_back(id);
|
||||
_resetPayloads.push_back(payload);
|
||||
|
|
|
@ -196,12 +196,50 @@ public:
|
|||
// Bound is the AABBox fully containing this item
|
||||
typedef AABox Bound;
|
||||
|
||||
// Stats records the life history and performances of this item while performing at rendering and updating.
|
||||
// Status records the life history and performances of this item while performing at rendering and updating.
|
||||
// This is Used for monitoring and dynamically adjust the quality
|
||||
class Stats {
|
||||
class Status {
|
||||
public:
|
||||
int _firstFrame;
|
||||
|
||||
// Status::Value class is the data used to represent the transient information of a status as a square icon
|
||||
// The "icon" is a square displayed in the 3D scene over the render::Item AABB center.
|
||||
// It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue
|
||||
class Value {
|
||||
unsigned short _scale = 0xFFFF;
|
||||
unsigned short _color = 0xFFFF;
|
||||
public:
|
||||
const static Value INVALID; // Invalid value meanss the status won't show
|
||||
|
||||
Value() {}
|
||||
Value(float scale, float hue) { setScale(scale); setColor(hue); }
|
||||
|
||||
// It can be scaled in the range [0, 1]
|
||||
void setScale(float scale);
|
||||
// the color hue in the range [0, 360] representing the color wheel hue
|
||||
void setColor(float hue);
|
||||
|
||||
// Standard color Hue
|
||||
static const float RED; // 0.0f;
|
||||
static const float YELLOW; // 60.0f;
|
||||
static const float GREEN; // 120.0f;
|
||||
static const float CYAN; // 180.0f;
|
||||
static const float BLUE; // 240.0f;
|
||||
static const float MAGENTA; // 300.0f;
|
||||
|
||||
// Retreive the Value data tightely packed as an int
|
||||
int getPackedData() const { return *((const int*) this); }
|
||||
};
|
||||
|
||||
typedef std::function<Value()> Getter;
|
||||
typedef std::vector<Getter> Getters;
|
||||
|
||||
Getters _values;
|
||||
|
||||
void addGetter(const Getter& getter) { _values.push_back(getter); }
|
||||
|
||||
void getPackedValues(glm::ivec4& values) const;
|
||||
};
|
||||
typedef std::shared_ptr<Status> StatusPointer;
|
||||
|
||||
// Update Functor
|
||||
class UpdateFunctorInterface {
|
||||
|
@ -222,7 +260,15 @@ public:
|
|||
virtual const model::MaterialKey getMaterialKey() const = 0;
|
||||
|
||||
~PayloadInterface() {}
|
||||
|
||||
// Status interface is local to the base class
|
||||
const StatusPointer& getStatus() const { return _status; }
|
||||
void addStatusGetter(const Status::Getter& getter);
|
||||
void addStatusGetters(const Status::Getters& getters);
|
||||
|
||||
protected:
|
||||
StatusPointer _status;
|
||||
|
||||
friend class Item;
|
||||
virtual void update(const UpdateFunctorPointer& functor) = 0;
|
||||
};
|
||||
|
@ -253,6 +299,10 @@ public:
|
|||
// Shape Type Interface
|
||||
const model::MaterialKey getMaterialKey() const { return _payload->getMaterialKey(); }
|
||||
|
||||
// Access the status
|
||||
const StatusPointer& getStatus() const { return _payload->getStatus(); }
|
||||
glm::ivec4 getStatusPackedValues() const;
|
||||
|
||||
protected:
|
||||
PayloadPointer _payload;
|
||||
ItemKey _key;
|
||||
|
|
19
libraries/render/src/render/drawItemBounds.slf
Normal file
19
libraries/render/src/render/drawItemBounds.slf
Normal file
|
@ -0,0 +1,19 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// drawItemBounds.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/29/15.
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
varying vec4 varColor;
|
||||
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
57
libraries/render/src/render/drawItemBounds.slv
Normal file
57
libraries/render/src/render/drawItemBounds.slv
Normal file
|
@ -0,0 +1,57 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// drawItemBounds.slv
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/29/2015.
|
||||
// Copyright 2015 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 gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
uniform vec3 inBoundPos;
|
||||
uniform vec3 inBoundDim;
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_BOX[8] = vec4[8](
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(1.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 1.0, 0.0, 1.0),
|
||||
vec4(1.0, 1.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 1.0, 1.0),
|
||||
vec4(1.0, 0.0, 1.0, 1.0),
|
||||
vec4(0.0, 1.0, 1.0, 1.0),
|
||||
vec4(1.0, 1.0, 1.0, 1.0)
|
||||
);
|
||||
const int UNIT_BOX_LINE_INDICES[24] = int[24](
|
||||
0, 1,
|
||||
1, 3,
|
||||
3, 2,
|
||||
2, 0,
|
||||
4, 5,
|
||||
5, 7,
|
||||
7, 6,
|
||||
6, 4,
|
||||
2, 6,
|
||||
3, 7,
|
||||
0, 4,
|
||||
1, 5
|
||||
);
|
||||
vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]];
|
||||
|
||||
pos.xyz = inBoundPos + inBoundDim * pos.xyz;
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
|
||||
|
||||
// varTexcoord = (pos.xy + 1) * 0.5;
|
||||
}
|
19
libraries/render/src/render/drawItemStatus.slf
Normal file
19
libraries/render/src/render/drawItemStatus.slf
Normal file
|
@ -0,0 +1,19 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// drawItemStatus.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/30/15.
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
varying vec4 varColor;
|
||||
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = varColor;
|
||||
}
|
101
libraries/render/src/render/drawItemStatus.slv
Normal file
101
libraries/render/src/render/drawItemStatus.slv
Normal file
|
@ -0,0 +1,101 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// drawItemStatus.slv
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 6/30/2015.
|
||||
// Copyright 2015 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 gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
varying vec4 varColor;
|
||||
|
||||
uniform vec3 inBoundPos;
|
||||
uniform vec3 inBoundDim;
|
||||
uniform ivec4 inStatus;
|
||||
|
||||
vec3 paintRainbow(float nv) {
|
||||
float v = nv * 5.f;
|
||||
if (v < 0.f) {
|
||||
return vec3(0.f, 0.f, 0.f);
|
||||
} else if (v < 1.f) {
|
||||
return vec3(1.f, v, 0.f);
|
||||
} else if (v < 2.f) {
|
||||
return vec3(1.f - (v-1.f), 1.f, 0.f);
|
||||
} else if (v < 3.f) {
|
||||
return vec3(0.f, 1.f, (v-2.f));
|
||||
} else if (v < 4.f) {
|
||||
return vec3(0.f, 1.f - (v-3.f), 1.f );
|
||||
} else if (v < 5.f) {
|
||||
return vec3((v-4.f), 0.f, 1.f );
|
||||
} else {
|
||||
return vec3(1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
vec2 unpackStatus(int v) {
|
||||
return vec2(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0),
|
||||
clamp(float(int((v >> 16) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0));
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
const vec2 ICON_PIXEL_SIZE = vec2(10, 10);
|
||||
const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2);
|
||||
const int NUM_VERTICES = 6;
|
||||
const vec4 UNIT_QUAD[NUM_VERTICES] = vec4[NUM_VERTICES](
|
||||
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||
vec4(1.0, -1.0, 0.0, 1.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4(1.0, -1.0, 0.0, 1.0),
|
||||
vec4(1.0, 1.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
// anchor point in clip space
|
||||
vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0);
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$>
|
||||
|
||||
// Which icon are we dealing with ?
|
||||
int iconNum = gl_VertexID / NUM_VERTICES;
|
||||
|
||||
// if invalid, just kill
|
||||
if (inStatus[iconNum] == 0xFFFFFFFF) {
|
||||
gl_Position = anchorPoint;
|
||||
varColor = vec4(1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
// unpack to get x and y satus
|
||||
vec2 iconStatus = unpackStatus(inStatus[iconNum]);
|
||||
|
||||
// Use the status for showing a color
|
||||
varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0);
|
||||
|
||||
// Also changes the size of the notification
|
||||
vec2 iconScale = ICON_PIXEL_SIZE;
|
||||
iconScale = max(vec2(1, 1), (iconScale * iconStatus.x));
|
||||
|
||||
//Offset icon to the right based on the iconNum
|
||||
vec2 offset = vec2(iconNum * (ICON_PIXEL_SIZE.x + MARGIN_PIXEL_SIZE.x), 0);
|
||||
|
||||
// Final position in pixel space
|
||||
int twoTriID = gl_VertexID - iconNum * NUM_VERTICES;
|
||||
vec4 pos = UNIT_QUAD[twoTriID];
|
||||
vec2 quadPixelPos = offset.xy + pos.xy * 0.5 * iconScale;
|
||||
|
||||
vec4 viewport;
|
||||
<$transformCameraViewport(cam, viewport)$>;
|
||||
vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w);
|
||||
gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0));
|
||||
|
||||
}
|
|
@ -106,6 +106,10 @@ public:
|
|||
Q_INVOKABLE int getEngineMaxDrawnTransparentItems() { return _maxDrawnTransparentItems; }
|
||||
Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; }
|
||||
Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; }
|
||||
|
||||
Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; }
|
||||
Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; }
|
||||
|
||||
signals:
|
||||
void shouldRenderAvatarsChanged(bool shouldRenderAvatars);
|
||||
void shouldRenderEntitiesChanged(bool shouldRenderEntities);
|
||||
|
@ -136,6 +140,8 @@ protected:
|
|||
int _maxDrawnTransparentItems = -1;
|
||||
int _maxDrawnOverlay3DItems = -1;
|
||||
|
||||
bool _drawItemStatus = false;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_SceneScriptingInterface_h
|
||||
|
|
Loading…
Reference in a new issue