mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 20:16:16 +02:00
235 lines
8.4 KiB
C++
235 lines
8.4 KiB
C++
//
|
|
// NodeBounds.cpp
|
|
// interface/src/ui
|
|
//
|
|
// Created by Ryan Huffman on 05/14/14.
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// This class draws a border around the different Voxel, Entity nodes on the current domain,
|
|
// and a semi-transparent cube around the currently mouse-overed node.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "Application.h"
|
|
#include "Util.h"
|
|
|
|
#include "NodeBounds.h"
|
|
|
|
NodeBounds::NodeBounds(QObject* parent) :
|
|
QObject(parent),
|
|
_showVoxelNodes(false),
|
|
_showEntityNodes(false),
|
|
_overlayText() {
|
|
|
|
}
|
|
|
|
void NodeBounds::draw() {
|
|
if (!(_showVoxelNodes || _showEntityNodes)) {
|
|
_overlayText[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
NodeToJurisdictionMap& voxelServerJurisdictions = Application::getInstance()->getVoxelServerJurisdictions();
|
|
NodeToJurisdictionMap& entityServerJurisdictions = Application::getInstance()->getEntityServerJurisdictions();
|
|
NodeToJurisdictionMap* serverJurisdictions;
|
|
|
|
// Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers
|
|
// itself after the cursor disappears.
|
|
Application* application = Application::getInstance();
|
|
GLCanvas* glWidget = application->getGLWidget();
|
|
float mouseX = application->getMouseX() / (float)glWidget->width();
|
|
float mouseY = application->getMouseY() / (float)glWidget->height();
|
|
glm::vec3 mouseRayOrigin;
|
|
glm::vec3 mouseRayDirection;
|
|
application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection);
|
|
|
|
// Variables to keep track of the selected node and properties to draw the cube later if needed
|
|
Node* selectedNode = NULL;
|
|
float selectedDistance = FLT_MAX;
|
|
bool selectedIsInside = true;
|
|
glm::vec3 selectedCenter;
|
|
float selectedScale = 0;
|
|
|
|
NodeList* nodeList = NodeList::getInstance();
|
|
nodeList->eachNode([&](const SharedNodePointer& node){
|
|
NodeType_t nodeType = node->getType();
|
|
|
|
if (nodeType == NodeType::VoxelServer && _showVoxelNodes) {
|
|
serverJurisdictions = &voxelServerJurisdictions;
|
|
} else if (nodeType == NodeType::EntityServer && _showEntityNodes) {
|
|
serverJurisdictions = &entityServerJurisdictions;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
QUuid nodeUUID = node->getUUID();
|
|
serverJurisdictions->lockForRead();
|
|
if (serverJurisdictions->find(nodeUUID) != serverJurisdictions->end()) {
|
|
const JurisdictionMap& map = (*serverJurisdictions)[nodeUUID];
|
|
|
|
unsigned char* rootCode = map.getRootOctalCode();
|
|
|
|
if (rootCode) {
|
|
VoxelPositionSize rootDetails;
|
|
voxelDetailsForCode(rootCode, rootDetails);
|
|
serverJurisdictions->unlock();
|
|
glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
|
|
location *= (float)TREE_SCALE;
|
|
|
|
AACube serverBounds(location, rootDetails.s * TREE_SCALE);
|
|
|
|
glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
|
|
+ ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);
|
|
|
|
const float VOXEL_NODE_SCALE = 1.00f;
|
|
const float ENTITY_NODE_SCALE = 0.99f;
|
|
|
|
float scaleFactor = rootDetails.s * TREE_SCALE;
|
|
|
|
// Scale by 0.92 - 1.00 depending on the scale of the node. This allows smaller nodes to scale in
|
|
// a bit and not overlap larger nodes.
|
|
scaleFactor *= 0.92 + (rootDetails.s * 0.08);
|
|
|
|
// Scale different node types slightly differently because it's common for them to overlap.
|
|
if (nodeType == NodeType::VoxelServer) {
|
|
scaleFactor *= VOXEL_NODE_SCALE;
|
|
} else if (nodeType == NodeType::EntityServer) {
|
|
scaleFactor *= ENTITY_NODE_SCALE;
|
|
}
|
|
|
|
float red, green, blue;
|
|
getColorForNodeType(nodeType, red, green, blue);
|
|
drawNodeBorder(center, scaleFactor, red, green, blue);
|
|
|
|
float distance;
|
|
BoxFace face;
|
|
bool inside = serverBounds.contains(mouseRayOrigin);
|
|
bool colliding = serverBounds.findRayIntersection(mouseRayOrigin, mouseRayDirection, distance, face);
|
|
|
|
// If the camera is inside a node it will be "selected" if you don't have your cursor over another node
|
|
// that you aren't inside.
|
|
if (colliding && (!selectedNode || (!inside && (distance < selectedDistance || selectedIsInside)))) {
|
|
selectedNode = node.data();
|
|
selectedDistance = distance;
|
|
selectedIsInside = inside;
|
|
selectedCenter = center;
|
|
selectedScale = scaleFactor;
|
|
}
|
|
} else {
|
|
serverJurisdictions->unlock();
|
|
}
|
|
} else {
|
|
serverJurisdictions->unlock();
|
|
}
|
|
});
|
|
|
|
if (selectedNode) {
|
|
glPushMatrix();
|
|
|
|
glTranslatef(selectedCenter.x, selectedCenter.y, selectedCenter.z);
|
|
glScalef(selectedScale, selectedScale, selectedScale);
|
|
|
|
float red, green, blue;
|
|
getColorForNodeType(selectedNode->getType(), red, green, blue);
|
|
|
|
glColor4f(red, green, blue, 0.2f);
|
|
glutSolidCube(1.0);
|
|
|
|
glPopMatrix();
|
|
|
|
HifiSockAddr addr = selectedNode->getPublicSocket();
|
|
QString overlay = QString("%1:%2 %3ms")
|
|
.arg(addr.getAddress().toString())
|
|
.arg(addr.getPort())
|
|
.arg(selectedNode->getPingMs())
|
|
.left(MAX_OVERLAY_TEXT_LENGTH);
|
|
|
|
// Ideally we'd just use a QString, but I ran into weird blinking issues using
|
|
// constData() directly, as if the data was being overwritten.
|
|
strcpy(_overlayText, overlay.toLocal8Bit().constData());
|
|
} else {
|
|
_overlayText[0] = '\0';
|
|
}
|
|
}
|
|
|
|
void NodeBounds::drawNodeBorder(const glm::vec3& center, float scale, float red, float green, float blue) {
|
|
glPushMatrix();
|
|
|
|
glTranslatef(center.x, center.y, center.z);
|
|
glScalef(scale, scale, scale);
|
|
|
|
glLineWidth(2.5);
|
|
glColor3f(red, green, blue);
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f( 0.5, -0.5, -0.5);
|
|
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
glVertex3f( 0.5, 0.5, -0.5);
|
|
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
|
|
glVertex3f( 0.5, 0.5, 0.5);
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
|
|
glVertex3f( 0.5, 0.5, 0.5);
|
|
glVertex3f( 0.5, -0.5, 0.5);
|
|
|
|
glVertex3f( 0.5, 0.5, 0.5);
|
|
glVertex3f( 0.5, 0.5, -0.5);
|
|
|
|
glVertex3f( 0.5, -0.5, 0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
|
|
glVertex3f( 0.5, -0.5, 0.5);
|
|
glVertex3f( 0.5, -0.5, -0.5);
|
|
|
|
glVertex3f( 0.5, 0.5, -0.5);
|
|
glVertex3f( 0.5, -0.5, -0.5);
|
|
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
void NodeBounds::getColorForNodeType(NodeType_t nodeType, float& red, float& green, float& blue) {
|
|
red = nodeType == NodeType::VoxelServer ? 1.0 : 0.0;
|
|
green = 0.0;
|
|
blue = nodeType == NodeType::EntityServer ? 1.0 : 0.0;
|
|
}
|
|
|
|
void NodeBounds::drawOverlay() {
|
|
if (strlen(_overlayText) > 0) {
|
|
Application* application = Application::getInstance();
|
|
|
|
const float TEXT_COLOR[] = { 0.90f, 0.90f, 0.90f };
|
|
const float TEXT_SCALE = 0.1f;
|
|
const int TEXT_HEIGHT = 10;
|
|
const float ROTATION = 0.0f;
|
|
const int FONT = 2;
|
|
const int PADDING = 10;
|
|
const int MOUSE_OFFSET = 10;
|
|
const int BACKGROUND_BEVEL = 3;
|
|
|
|
int mouseX = application->getMouseX(),
|
|
mouseY = application->getMouseY(),
|
|
textWidth = widthText(TEXT_SCALE, 0, _overlayText);
|
|
glColor4f(0.4f, 0.4f, 0.4f, 0.6f);
|
|
renderBevelCornersRect(mouseX + MOUSE_OFFSET, mouseY - TEXT_HEIGHT - PADDING,
|
|
textWidth + (2 * PADDING), TEXT_HEIGHT + (2 * PADDING), BACKGROUND_BEVEL);
|
|
drawText(mouseX + MOUSE_OFFSET + PADDING, mouseY, TEXT_SCALE, ROTATION, FONT, _overlayText, TEXT_COLOR);
|
|
}
|
|
}
|