mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 01:04:06 +02:00
Working on overlays / stats
This commit is contained in:
parent
02d33f6086
commit
659fa2387c
12 changed files with 671 additions and 638 deletions
147
interface/resources/qml/Stats.qml
Normal file
147
interface/resources/qml/Stats.qml
Normal file
|
@ -0,0 +1,147 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
Hifi.Stats {
|
||||
id: root
|
||||
objectName: "Stats"
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
readonly property int sTATS_GENERAL_MIN_WIDTH: 165
|
||||
readonly property int sTATS_PING_MIN_WIDTH: 190
|
||||
readonly property int sTATS_GEO_MIN_WIDTH: 240
|
||||
readonly property int sTATS_OCTREE_MIN_WIDTH: 410
|
||||
|
||||
onParentChanged: {
|
||||
root.x = parent.width - root.width;
|
||||
}
|
||||
|
||||
Row {
|
||||
z: 100
|
||||
id: row
|
||||
spacing: 8
|
||||
Rectangle {
|
||||
width: generalCol.width + 8;
|
||||
height: generalCol.height + 8;
|
||||
color: "#99333333";
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
}
|
||||
|
||||
Column {
|
||||
id: generalCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
width: sTATS_GENERAL_MIN_WIDTH
|
||||
Text { color: "white"; text: "Servers: " + root.serverCount }
|
||||
Text { color: "white"; text: "Avatars: " + root.avatarCount }
|
||||
Text { color: "white"; text: "Framerate: " + root.framerate }
|
||||
Text { color: "white"; text: "Packets In/Out: " + root.packetInCount + "/" + root.packetOutCount }
|
||||
Text { color: "white"; text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2) }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: pingCol.width + 8
|
||||
height: pingCol.height + 8
|
||||
color: "#99333333"
|
||||
visible: root.audioPing != -2
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
}
|
||||
Column {
|
||||
id: pingCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
width: sTATS_PING_MIN_WIDTH
|
||||
Text { color: "white"; text: "Audio ping: " + root.audioPing }
|
||||
Text { color: "white"; text: "Avatar ping: " + root.avatarPing }
|
||||
Text { color: "white"; text: "Entities avg ping: " + root.entitiesPing }
|
||||
Text { color: "white"; text: "Voxel max ping: " + 0; visible: root.expanded; }
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
width: geoCol.width
|
||||
height: geoCol.height
|
||||
color: "#99333333"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
}
|
||||
Column {
|
||||
spacing: 4
|
||||
id: geoCol
|
||||
width: sTATS_GEO_MIN_WIDTH
|
||||
Text {
|
||||
color: "white";
|
||||
text: "Position: " + root.position.x.toFixed(1) + ", " +
|
||||
root.position.y.toFixed(1) + ", " + root.position.z.toFixed(1)
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
text: "Velocity: " + root.velocity.toFixed(1)
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
text: "Yaw: " + root.yaw.toFixed(1)
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
visible: root.expanded;
|
||||
text: "Avatar Mixer: " + root.avatarMixerKbps + " kbps, " +
|
||||
root.avatarMixerPps + "pps";
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
visible: root.expanded;
|
||||
text: "Downloads: ";
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
width: octreeCol.width + 8
|
||||
height: octreeCol.height + 8
|
||||
color: "#99333333"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: { root.expanded = !root.expanded; }
|
||||
}
|
||||
Column {
|
||||
id: octreeCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
width: sTATS_OCTREE_MIN_WIDTH
|
||||
Text {
|
||||
color: "white";
|
||||
text: "Triangles: " + root.triangles +
|
||||
" / Quads: " + root.quads + " / Material Switches: " + root.materialSwitches
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
visible: root.expanded;
|
||||
text: "\tMesh Parts Rendered Opaque: " + root.meshOpaque +
|
||||
" / Translucent: " + root.meshTranslucent;
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
visible: root.expanded;
|
||||
text: "\tOpaque considered: " + root.opaqueConsidered +
|
||||
" / Out of view: " + root.opaqueOutOfView + " / Too small: " + root.opaqueTooSmall;
|
||||
}
|
||||
Text {
|
||||
color: "white";
|
||||
visible: !root.expanded
|
||||
text: "Octree Elements Server: ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.parent
|
||||
onWidthChanged: {
|
||||
root.x = root.parent.width - root.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
interface/resources/qml/Tooltip.qml
Normal file
29
interface/resources/qml/Tooltip.qml
Normal file
|
@ -0,0 +1,29 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.3 as Original
|
||||
import "controls"
|
||||
import "styles"
|
||||
|
||||
Hifi.Tooltip {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
x: lastMousePosition.x
|
||||
y: lastMousePosition.y
|
||||
implicitWidth: border.implicitWidth
|
||||
implicitHeight: border.implicitHeight
|
||||
|
||||
Border {
|
||||
id: border
|
||||
anchors.fill: parent
|
||||
implicitWidth: text.implicitWidth
|
||||
implicitHeight: Math.max(text.implicitHeight, 64)
|
||||
|
||||
Text {
|
||||
id: text
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
font.pixelSize: hifi.fonts.pixelSize / 2
|
||||
text: root.text
|
||||
wrapMode: Original.Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
|
@ -88,6 +88,7 @@
|
|||
#include <SettingHandle.h>
|
||||
#include <SoundCache.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <Tooltip.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UUID.h>
|
||||
#include <VrMenu.h>
|
||||
|
@ -822,6 +823,7 @@ void Application::initializeUi() {
|
|||
LoginDialog::registerType();
|
||||
MessageDialog::registerType();
|
||||
VrMenu::registerType();
|
||||
Tooltip::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <OffscreenUi.h>
|
||||
#include <CursorManager.h>
|
||||
#include <PerfStat.h>
|
||||
#include <Tooltip.h>
|
||||
|
||||
|
||||
#include "AudioClient.h"
|
||||
|
@ -41,7 +42,7 @@
|
|||
static const float MAG_SPEED = 0.08f;
|
||||
|
||||
static const quint64 MSECS_TO_USECS = 1000ULL;
|
||||
static const quint64 TOOLTIP_DELAY = 2000000ULL;
|
||||
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 };
|
||||
|
@ -59,7 +60,7 @@ static gpu::BufferPointer _hemiVertices;
|
|||
static gpu::BufferPointer _hemiIndices;
|
||||
static int _hemiIndexCount{ 0 };
|
||||
EntityItemID ApplicationCompositor::_noItemId;
|
||||
|
||||
static QString _tooltipId;
|
||||
|
||||
// Return a point's cartesian coordinates on a sphere from pitch and yaw
|
||||
glm::vec3 getPoint(float yaw, float pitch) {
|
||||
|
@ -159,6 +160,11 @@ ApplicationCompositor::ApplicationCompositor() {
|
|||
_hoverItemHref.clear();
|
||||
auto cursor = Cursor::Manager::instance().getCursor();
|
||||
cursor->setIcon(Cursor::Icon::DEFAULT);
|
||||
if (!_tooltipId.isEmpty()) {
|
||||
qDebug() << "Closing tooltip " << _tooltipId;
|
||||
Tooltip::closeTip(_tooltipId);
|
||||
_tooltipId.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -166,6 +172,7 @@ ApplicationCompositor::ApplicationCompositor() {
|
|||
ApplicationCompositor::~ApplicationCompositor() {
|
||||
}
|
||||
|
||||
|
||||
void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) {
|
||||
auto& cursorManager = Cursor::Manager::instance();
|
||||
auto cursor = cursorManager.getCursor(cursorIndex);
|
||||
|
@ -184,17 +191,10 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
|
|||
return;
|
||||
}
|
||||
|
||||
updateTooltips();
|
||||
|
||||
vec2 canvasSize = qApp->getCanvasSize();
|
||||
|
||||
_textureAspectRatio = aspect(canvasSize);
|
||||
|
||||
if (_hoverItemId != _noItemId) {
|
||||
quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs;
|
||||
if (!_hoverItemHref.isEmpty() && hoverDuration > TOOLTIP_DELAY) {
|
||||
// TODO Enable and position the tooltip
|
||||
}
|
||||
}
|
||||
|
||||
//Handle fading and deactivation/activation of UI
|
||||
gpu::Batch batch;
|
||||
|
||||
|
@ -262,6 +262,11 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
|||
return;
|
||||
}
|
||||
|
||||
vec2 canvasSize = qApp->getCanvasSize();
|
||||
_textureAspectRatio = aspect(canvasSize);
|
||||
|
||||
updateTooltips();
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
|
@ -392,13 +397,6 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi
|
|||
|
||||
//Renders optional pointers
|
||||
void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
|
||||
//glEnable(GL_TEXTURE_2D);
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
//bindCursorTexture();
|
||||
|
||||
if (qApp->isHMDMode() && !qApp->getLastMouseMoveWasSimulated() && !qApp->isMouseHidden()) {
|
||||
//If we are in oculus, render reticle later
|
||||
if (_lastMouseMove == 0) {
|
||||
|
@ -442,8 +440,6 @@ void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
|
|||
_magActive[MOUSE] = false;
|
||||
renderControllerPointers(batch);
|
||||
}
|
||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
||||
//glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
|
@ -718,7 +714,6 @@ void ApplicationCompositor::drawSphereSection(gpu::Batch& batch) {
|
|||
batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount);
|
||||
}
|
||||
|
||||
|
||||
glm::vec2 ApplicationCompositor::directionToSpherical(const glm::vec3& direction) {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
|
@ -788,127 +783,13 @@ glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) co
|
|||
return sphericalToScreen(overlayToSpherical(overlayPos));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
gpu::PipelinePointer ApplicationOverlay::getDrawPipeline() {
|
||||
if (!_standardDrawPipeline) {
|
||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)));
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag)));
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// enable decal blend
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
|
||||
_standardDrawPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
|
||||
return _standardDrawPipeline;
|
||||
}
|
||||
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
void ApplicationOverlay::displayOverlayTexture(RenderArgs* renderArgs) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
|
||||
gpu::Batch batch;
|
||||
Transform model;
|
||||
//DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true);
|
||||
batch.setPipeline(getDrawPipeline());
|
||||
batch.setModelTransform(Transform());
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setViewTransform(model);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(vec3(1), _alpha));
|
||||
|
||||
//draw the mouse pointer
|
||||
glm::vec2 canvasSize = qApp->getCanvasSize();
|
||||
|
||||
// Get the mouse coordinates and convert to NDC [-1, 1]
|
||||
vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
|
||||
mousePosition /= canvasSize;
|
||||
mousePosition *= 2.0f;
|
||||
mousePosition -= 1.0f;
|
||||
mousePosition.y *= -1.0f;
|
||||
model.setTranslation(vec3(mousePosition, 0));
|
||||
glm::vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
|
||||
model.setScale(vec3(mouseSize, 1.0f));
|
||||
batch.setModelTransform(model);
|
||||
bindCursorTexture(batch);
|
||||
glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
|
||||
DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(1));
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
void ApplicationOverlay::displayOverlayTextureHmd(RenderArgs* renderArgs, Camera& whichCamera) {
|
||||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
|
||||
gpu::Batch batch;
|
||||
batch.setPipeline(getDrawPipeline());
|
||||
batch._glDisable(GL_DEPTH_TEST);
|
||||
batch._glDisable(GL_CULL_FACE);
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
batch.setProjectionTransform(whichCamera.getProjection());
|
||||
batch.setViewTransform(Transform());
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const quat& avatarOrientation = myAvatar->getOrientation();
|
||||
quat hmdOrientation = qApp->getCamera()->getHmdRotation();
|
||||
vec3 hmdPosition = glm::inverse(avatarOrientation) * qApp->getCamera()->getHmdPosition();
|
||||
mat4 overlayXfm = glm::mat4_cast(glm::inverse(hmdOrientation)) * glm::translate(mat4(), -hmdPosition);
|
||||
batch.setModelTransform(Transform(overlayXfm));
|
||||
drawSphereSection(batch);
|
||||
|
||||
|
||||
bindCursorTexture(batch);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize);
|
||||
//Controller Pointers
|
||||
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
|
||||
PalmData& palm = myAvatar->getHand()->getPalms()[i];
|
||||
if (palm.isActive()) {
|
||||
glm::vec2 polar = getPolarCoordinates(palm);
|
||||
// Convert to quaternion
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
// Render reticle at location
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
void ApplicationCompositor::updateTooltips() {
|
||||
if (_hoverItemId != _noItemId) {
|
||||
quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs;
|
||||
if (_hoverItemEnterUsecs != UINT64_MAX && !_hoverItemHref.isEmpty() && hoverDuration > TOOLTIP_DELAY) {
|
||||
// TODO Enable and position the tooltip
|
||||
_hoverItemEnterUsecs = UINT64_MAX;
|
||||
_tooltipId = Tooltip::showTip("URL: " + _hoverItemHref);
|
||||
}
|
||||
}
|
||||
|
||||
//Mouse Pointer
|
||||
if (_reticleActive[MOUSE]) {
|
||||
glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(),
|
||||
_reticlePosition[MOUSE].y()));
|
||||
mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1));
|
||||
mat4 reticleXfm = overlayXfm * pointerXfm;
|
||||
reticleXfm = glm::scale(reticleXfm, reticleScale);
|
||||
batch.setModelTransform(reticleXfm);
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad);
|
||||
}
|
||||
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -74,6 +74,7 @@ private:
|
|||
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
|
||||
void buildHemiVertices(const float fov, const float aspectRatio, const int slices, const int stacks);
|
||||
void drawSphereSection(gpu::Batch& batch);
|
||||
void updateTooltips();
|
||||
|
||||
void renderPointers(gpu::Batch& batch);
|
||||
void renderMagnifier(gpu::Batch& batch, const glm::vec2& magPos, float sizeMult, bool showBorder);
|
||||
|
|
|
@ -50,6 +50,8 @@ static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f;
|
|||
static const float MIRROR_REARVIEW_DISTANCE = 0.722f;
|
||||
static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.56f;
|
||||
static const float MIRROR_FIELD_OF_VIEW = 30.0f;
|
||||
static const float ORTHO_NEAR_CLIP = -10000;
|
||||
static const float ORTHO_FAR_CLIP = 10000;
|
||||
|
||||
|
||||
ApplicationOverlay::ApplicationOverlay() :
|
||||
|
@ -85,6 +87,7 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
|
||||
Stats::getInstance()->updateStats();
|
||||
glm::vec2 size = qApp->getCanvasSize();
|
||||
// TODO Handle fading and deactivation/activation of UI
|
||||
|
||||
|
@ -98,41 +101,38 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
|
|||
glViewport(0, 0, size.x, size.y);
|
||||
|
||||
// Now render the overlay components together into a single texture
|
||||
gpu::Batch batch;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch._glDisable(GL_DEPTH);
|
||||
batch._glDisable(GL_LIGHTING);
|
||||
batch._glEnable(GL_BLEND);
|
||||
//renderOverlays(renderArgs);
|
||||
//renderAudioMeter(renderArgs);
|
||||
//renderCameraToggle(renderArgs);
|
||||
//renderStatsAndLogs(renderArgs);
|
||||
|
||||
renderOverlays(batch, renderArgs);
|
||||
|
||||
renderAudioMeter(batch);
|
||||
renderCameraToggle(batch);
|
||||
renderStatsAndLogs(batch);
|
||||
renderDomainConnectionStatusBorder(batch);
|
||||
renderQmlUi(batch);
|
||||
renderDomainConnectionStatusBorder(renderArgs);
|
||||
renderQmlUi(renderArgs);
|
||||
|
||||
renderArgs->_context->syncCache();
|
||||
renderArgs->_context->render(batch);
|
||||
_overlayFramebuffer->release();
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderQmlUi(gpu::Batch& batch) {
|
||||
void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
||||
if (_uiTexture) {
|
||||
gpu::Batch batch;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch._glDisable(GL_DEPTH_TEST);
|
||||
batch._glDisable(GL_LIGHTING);
|
||||
batch._glEnable(GL_BLEND);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setModelTransform(mat4());
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _uiTexture);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1));
|
||||
renderArgs->_context->syncCache();
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderOverlays(gpu::Batch& batch, RenderArgs* renderArgs) {
|
||||
static const float NEAR_CLIP = -10000;
|
||||
static const float FAR_CLIP = 10000;
|
||||
void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
|
||||
glm::vec2 size = qApp->getCanvasSize();
|
||||
mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, NEAR_CLIP, FAR_CLIP);
|
||||
mat4 legacyProjection = glm::ortho<float>(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadMatrixf(glm::value_ptr(legacyProjection));
|
||||
|
@ -152,8 +152,7 @@ void ApplicationOverlay::renderOverlays(gpu::Batch& batch, RenderArgs* renderArg
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderCameraToggle(gpu::Batch& batch) {
|
||||
/*
|
||||
void ApplicationOverlay::renderCameraToggle(RenderArgs* renderArgs) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)) {
|
||||
return;
|
||||
}
|
||||
|
@ -169,11 +168,9 @@ void ApplicationOverlay::renderCameraToggle(gpu::Batch& batch) {
|
|||
}
|
||||
|
||||
DependencyManager::get<CameraToolBox>()->render(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed);
|
||||
*/
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderAudioMeter(gpu::Batch& batch) {
|
||||
/*
|
||||
void ApplicationOverlay::renderAudioMeter(RenderArgs* renderArgs) {
|
||||
auto audio = DependencyManager::get<AudioClient>();
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
|
@ -287,10 +284,9 @@ void ApplicationOverlay::renderAudioMeter(gpu::Batch& batch) {
|
|||
audioLevel, AUDIO_METER_HEIGHT, quadColor,
|
||||
_audioBlueQuad);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderRearView(gpu::Batch& batch) {
|
||||
void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
||||
// // Grab current viewport to reset it at the end
|
||||
// int viewport[4];
|
||||
// glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
|
@ -369,37 +365,18 @@ void ApplicationOverlay::renderRearView(gpu::Batch& batch) {
|
|||
//}
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderStatsAndLogs(gpu::Batch& batch) {
|
||||
/*
|
||||
Application* application = Application::getInstance();
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
||||
const OctreePacketProcessor& octreePacketProcessor = application->getOctreePacketProcessor();
|
||||
NodeBounds& nodeBoundsDisplay = application->getNodeBoundsDisplay();
|
||||
void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
|
||||
|
||||
// Display stats and log text onscreen
|
||||
batch._glLineWidth(1.0f);
|
||||
glPointSize(1.0f);
|
||||
|
||||
// Determine whether to compute timing details
|
||||
bool shouldDisplayTimingDetail = Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
|
||||
Stats::getInstance()->isExpanded();
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::Stats); //&&
|
||||
// Stats::getInstance()->isExpanded();
|
||||
if (shouldDisplayTimingDetail != PerformanceTimer::isActive()) {
|
||||
PerformanceTimer::setActive(shouldDisplayTimingDetail);
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
// let's set horizontal offset to give stats some margin to mirror
|
||||
int voxelPacketsToProcess = octreePacketProcessor.packetsToProcessCount();
|
||||
// Onscreen text about position, servers, etc
|
||||
Stats::getInstance()->display(WHITE_TEXT, STATS_HORIZONTAL_OFFSET, application->getFps(),
|
||||
bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond(),
|
||||
bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond(),
|
||||
bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond(),
|
||||
bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond(),
|
||||
voxelPacketsToProcess);
|
||||
}
|
||||
Stats::getInstance()->updateStats();
|
||||
|
||||
// Show on-screen msec timer
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) {
|
||||
|
@ -412,16 +389,26 @@ void ApplicationOverlay::renderStatsAndLogs(gpu::Batch& batch) {
|
|||
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
|
||||
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
|
||||
}
|
||||
|
||||
glPointSize(1.0f);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay();
|
||||
nodeBoundsDisplay.drawOverlay();
|
||||
*/
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderDomainConnectionStatusBorder(gpu::Batch& batch) {
|
||||
void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderArgs) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
QVector<vec2> points;
|
||||
static const float B = 0.99;
|
||||
static const float B = 0.99f;
|
||||
points.push_back(vec2(-B));
|
||||
points.push_back(vec2(B, -B));
|
||||
points.push_back(vec2(B));
|
||||
|
@ -430,9 +417,13 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(gpu::Batch& batch) {
|
|||
geometryCache->updateVertices(_domainStatusBorder, points, CONNECTION_STATUS_BORDER_COLOR);
|
||||
});
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
|
||||
if (nodeList && !nodeList->getDomainHandler().isConnected()) {
|
||||
gpu::Batch batch;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->useSimpleDrawPipeline(batch);
|
||||
batch._glDisable(GL_DEPTH);
|
||||
batch._glDisable(GL_LIGHTING);
|
||||
batch._glEnable(GL_BLEND);
|
||||
batch.setProjectionTransform(mat4());
|
||||
batch.setModelTransform(mat4());
|
||||
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
|
@ -445,6 +436,8 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(gpu::Batch& batch) {
|
|||
//batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount)));
|
||||
|
||||
geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder);
|
||||
renderArgs->_context->syncCache();
|
||||
renderArgs->_context->render(batch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,13 +29,13 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void renderAudioMeter(gpu::Batch& batch);
|
||||
void renderCameraToggle(gpu::Batch& batch);
|
||||
void renderStatsAndLogs(gpu::Batch& batch);
|
||||
void renderDomainConnectionStatusBorder(gpu::Batch& batch);
|
||||
void renderRearView(gpu::Batch& batch);
|
||||
void renderQmlUi(gpu::Batch& batch);
|
||||
void renderOverlays(gpu::Batch& batch, RenderArgs* renderArgs);
|
||||
void renderAudioMeter(RenderArgs* renderArgs);
|
||||
void renderCameraToggle(RenderArgs* renderArgs);
|
||||
void renderStatsAndLogs(RenderArgs* renderArgs);
|
||||
void renderDomainConnectionStatusBorder(RenderArgs* renderArgs);
|
||||
void renderRearView(RenderArgs* renderArgs);
|
||||
void renderQmlUi(RenderArgs* renderArgs);
|
||||
void renderOverlays(RenderArgs* renderArgs);
|
||||
void buildFramebufferObject();
|
||||
|
||||
float _alpha{ 1.0f };
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <sstream>
|
||||
#include <gpu/GPUConfig.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "Stats.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
@ -25,147 +25,30 @@
|
|||
#include <LODManager.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Stats.h"
|
||||
#include "BandwidthRecorder.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Menu.h"
|
||||
#include "Util.h"
|
||||
#include "SequenceNumberStats.h"
|
||||
|
||||
HIFI_QML_DEF(Stats)
|
||||
|
||||
using namespace std;
|
||||
|
||||
const int STATS_PELS_PER_LINE = 16;
|
||||
const int STATS_PELS_INITIALOFFSET = 12;
|
||||
|
||||
const int STATS_GENERAL_MIN_WIDTH = 165;
|
||||
const int STATS_PING_MIN_WIDTH = 190;
|
||||
const int STATS_GEO_MIN_WIDTH = 240;
|
||||
const int STATS_OCTREE_MIN_WIDTH = 410;
|
||||
static Stats* INSTANCE{ nullptr };
|
||||
|
||||
Stats* Stats::getInstance() {
|
||||
static Stats stats;
|
||||
return &stats;
|
||||
if (!INSTANCE) {
|
||||
Stats::registerType();
|
||||
Stats::show();
|
||||
//Stats::toggle();
|
||||
Q_ASSERT(INSTANCE);
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
Stats::Stats():
|
||||
_expanded(false),
|
||||
_recentMaxPackets(0),
|
||||
_resetRecentMaxPacketsSoon(true),
|
||||
_generalStatsWidth(STATS_GENERAL_MIN_WIDTH),
|
||||
_pingStatsWidth(STATS_PING_MIN_WIDTH),
|
||||
_geoStatsWidth(STATS_GEO_MIN_WIDTH),
|
||||
_octreeStatsWidth(STATS_OCTREE_MIN_WIDTH),
|
||||
_lastHorizontalOffset(0)
|
||||
{
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
resetWidth(canvasSize.x, 0);
|
||||
}
|
||||
|
||||
void Stats::toggleExpanded() {
|
||||
_expanded = !_expanded;
|
||||
}
|
||||
|
||||
// called on mouse click release
|
||||
// check for clicks over stats in order to expand or contract them
|
||||
void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset) {
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
|
||||
if (0 != glm::compMax(glm::abs(glm::ivec2(mouseX - mouseDragStartedX, mouseY - mouseDragStartedY)))) {
|
||||
// not worried about dragging on stats
|
||||
return;
|
||||
}
|
||||
|
||||
int statsHeight = 0,
|
||||
statsWidth = 0,
|
||||
statsX = 0,
|
||||
statsY = 0,
|
||||
lines = 0;
|
||||
|
||||
statsX = horizontalOffset;
|
||||
|
||||
// top-left stats click
|
||||
lines = _expanded ? 5 : 3;
|
||||
statsHeight = lines * STATS_PELS_PER_LINE + 10;
|
||||
if (mouseX > statsX && mouseX < statsX + _generalStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
|
||||
toggleExpanded();
|
||||
return;
|
||||
}
|
||||
statsX += _generalStatsWidth;
|
||||
|
||||
// ping stats click
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
lines = _expanded ? 4 : 3;
|
||||
statsHeight = lines * STATS_PELS_PER_LINE + 10;
|
||||
if (mouseX > statsX && mouseX < statsX + _pingStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
|
||||
toggleExpanded();
|
||||
return;
|
||||
}
|
||||
statsX += _pingStatsWidth;
|
||||
}
|
||||
|
||||
// geo stats panel click
|
||||
lines = _expanded ? 4 : 3;
|
||||
statsHeight = lines * STATS_PELS_PER_LINE + 10;
|
||||
if (mouseX > statsX && mouseX < statsX + _geoStatsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
|
||||
toggleExpanded();
|
||||
return;
|
||||
}
|
||||
statsX += _geoStatsWidth;
|
||||
|
||||
// top-right stats click
|
||||
lines = _expanded ? 11 : 3;
|
||||
statsHeight = lines * STATS_PELS_PER_LINE + 10;
|
||||
statsWidth = canvasSize.x - statsX;
|
||||
if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) {
|
||||
toggleExpanded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Stats::resetWidth(int width, int horizontalOffset) {
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
int extraSpace = canvasSize.x - horizontalOffset - 2
|
||||
- STATS_GENERAL_MIN_WIDTH
|
||||
- (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0)
|
||||
- STATS_GEO_MIN_WIDTH
|
||||
- STATS_OCTREE_MIN_WIDTH;
|
||||
|
||||
int panels = 4;
|
||||
|
||||
_generalStatsWidth = STATS_GENERAL_MIN_WIDTH;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
_pingStatsWidth = STATS_PING_MIN_WIDTH;
|
||||
} else {
|
||||
_pingStatsWidth = 0;
|
||||
panels = 3;
|
||||
}
|
||||
_geoStatsWidth = STATS_GEO_MIN_WIDTH;
|
||||
_octreeStatsWidth = STATS_OCTREE_MIN_WIDTH;
|
||||
|
||||
if (extraSpace > panels) {
|
||||
_generalStatsWidth += (int) extraSpace / panels;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
_pingStatsWidth += (int) extraSpace / panels;
|
||||
}
|
||||
_geoStatsWidth += (int) extraSpace / panels;
|
||||
_octreeStatsWidth += canvasSize.x -
|
||||
(_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// translucent background box that makes stats more readable
|
||||
void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int height) {
|
||||
glm::vec4 color(((rgba >> 24) & 0xff) / 255.0f,
|
||||
((rgba >> 16) & 0xff) / 255.0f,
|
||||
((rgba >> 8) & 0xff) / 255.0f,
|
||||
(rgba & 0xff) / 255.0f);
|
||||
|
||||
// FIX ME: is this correct? It seems to work to fix textures bleeding into us...
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(x, y, width, height, color);
|
||||
Stats::Stats(QQuickItem* parent) : QQuickItem(parent) {
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
bool Stats::includeTimingRecord(const QString& name) {
|
||||
|
@ -190,161 +73,63 @@ bool Stats::includeTimingRecord(const QString& name) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// display expanded or contracted stats
|
||||
void Stats::display(
|
||||
const float* color,
|
||||
int horizontalOffset,
|
||||
float fps,
|
||||
int inPacketsPerSecond,
|
||||
int outPacketsPerSecond,
|
||||
int inKbitsPerSecond,
|
||||
int outKbitsPerSecond,
|
||||
int voxelPacketsToProcess)
|
||||
{
|
||||
auto canvasSize = Application::getInstance()->getCanvasSize();
|
||||
|
||||
unsigned int backgroundColor = 0x33333399;
|
||||
int verticalOffset = 0, lines = 0;
|
||||
float scale = 0.10f;
|
||||
float rotation = 0.0f;
|
||||
int font = 2;
|
||||
|
||||
QLocale locale(QLocale::English);
|
||||
std::stringstream octreeStats;
|
||||
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
||||
if (_lastHorizontalOffset != horizontalOffset) {
|
||||
resetWidth(canvasSize.x, horizontalOffset);
|
||||
_lastHorizontalOffset = horizontalOffset;
|
||||
#define STAT_UPDATE(name, src) \
|
||||
{ \
|
||||
auto val = src; \
|
||||
if (_##name != val) { \
|
||||
_##name = val; \
|
||||
emit name##Changed(); \
|
||||
} \
|
||||
}
|
||||
|
||||
glPointSize(1.0f);
|
||||
#define STAT_UPDATE_FLOAT(name, src, epsilon) \
|
||||
{ \
|
||||
float val = src; \
|
||||
if (abs(_##name - val) >= epsilon) { \
|
||||
_##name = val; \
|
||||
emit name##Changed(); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
void Stats::updateStats() {
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
if (isVisible()) {
|
||||
setVisible(false);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (!isVisible()) {
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
// we need to take one avatar out so we don't include ourselves
|
||||
int totalAvatars = DependencyManager::get<AvatarManager>()->size() - 1;
|
||||
int totalServers = DependencyManager::get<NodeList>()->size();
|
||||
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
||||
STAT_UPDATE(serverCount, nodeList->size());
|
||||
STAT_UPDATE(framerate, (int)qApp->getFps());
|
||||
|
||||
lines = 5;
|
||||
int columnOneWidth = _generalStatsWidth;
|
||||
|
||||
bool performanceTimerIsActive = PerformanceTimer::isActive();
|
||||
bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
|
||||
if (displayPerf && performanceTimerIsActive) {
|
||||
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
|
||||
|
||||
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
|
||||
// we will also include room for 1 line per timing record and a header of 4 lines
|
||||
lines += 4;
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
int statsLines = 0;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
statsLines++;
|
||||
if (onlyDisplayTopTen && statsLines == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, columnOneWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
int columnOneHorizontalOffset = horizontalOffset;
|
||||
|
||||
QString serverNodes = QString("Servers: %1").arg(totalServers);
|
||||
QString avatarNodes = QString("Avatars: %1").arg(totalAvatars);
|
||||
QString framesPerSecond = QString("Framerate: %1 FPS").arg(fps, 3, 'f', 0);
|
||||
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET; // first one is offset by less than a line
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, serverNodes.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarNodes.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, framesPerSecond.toUtf8().constData(), color);
|
||||
|
||||
QString packetsPerSecondString = QString("Packets In/Out: %1/%2").arg(inPacketsPerSecond).arg(outPacketsPerSecond);
|
||||
QString averageMegabitsPerSecond = QString("Mbps In/Out: %1/%2").
|
||||
arg((float)inKbitsPerSecond * 1.0f / 1000.0f).
|
||||
arg((float)outKbitsPerSecond * 1.0f / 1000.0f);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, packetsPerSecondString.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, averageMegabitsPerSecond.toUtf8().constData(), color);
|
||||
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (displayPerf && performanceTimerIsActive) {
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
// Timing details...
|
||||
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"-------------------------------------------------------- Function "
|
||||
"------------------------------------------------------- --msecs- -calls--", color);
|
||||
|
||||
// First iterate all the records, and for the ones that should be included, insert them into
|
||||
// a new Map sorted by average time...
|
||||
QMap<float, QString> sortedRecords;
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
sortedRecords.insertMulti(averageTime, i.key());
|
||||
}
|
||||
}
|
||||
|
||||
int linesDisplayed = 0;
|
||||
QMapIterator<float, QString> j(sortedRecords);
|
||||
j.toBack();
|
||||
while (j.hasPrevious()) {
|
||||
j.previous();
|
||||
QChar noBreakingSpace = QChar::Nbsp;
|
||||
QString functionName = j.value();
|
||||
const PerformanceTimerRecord& record = allRecords.value(functionName);
|
||||
|
||||
QString perfLine = QString("%1: %2 [%3]").
|
||||
arg(QString(qPrintable(functionName)), 120, noBreakingSpace).
|
||||
arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
|
||||
arg((int)record.getCount(), 6, 10, noBreakingSpace);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
|
||||
linesDisplayed++;
|
||||
if (onlyDisplayTopTen && linesDisplayed == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + 1;
|
||||
auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
STAT_UPDATE(packetInCount, bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond());
|
||||
STAT_UPDATE(packetOutCount, bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond());
|
||||
STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f);
|
||||
STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f);
|
||||
|
||||
// Second column: ping
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
|
||||
int pingAudio = -1, pingAvatar = -1, pingVoxel = -1, pingOctreeMax = -1;
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
STAT_UPDATE(audioPing, audioMixerNode ? audioMixerNode->getPingMs() : -1);
|
||||
STAT_UPDATE(avatarPing, avatarMixerNode ? avatarMixerNode->getPingMs() : -1);
|
||||
|
||||
pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : -1;
|
||||
pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
|
||||
|
||||
// Now handle voxel servers, since there could be more than one, we average their ping times
|
||||
//// Now handle voxel servers, since there could be more than one, we average their ping times
|
||||
unsigned long totalPingOctree = 0;
|
||||
int octreeServerCount = 0;
|
||||
|
||||
nodeList->eachNode([&totalPingOctree, &pingOctreeMax, &octreeServerCount](const SharedNodePointer& node){
|
||||
int pingOctreeMax = 0;
|
||||
int pingVoxel;
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
// TODO: this should also support entities
|
||||
if (node->getType() == NodeType::EntityServer) {
|
||||
totalPingOctree += node->getPingMs();
|
||||
|
@ -359,146 +144,101 @@ void Stats::display(
|
|||
pingVoxel = totalPingOctree / octreeServerCount;
|
||||
}
|
||||
|
||||
lines = _expanded ? 4 : 3;
|
||||
|
||||
// only draw our background if column one didn't draw a wide background
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
||||
QString audioPing;
|
||||
if (pingAudio >= 0) {
|
||||
audioPing = QString("Audio ping: %1").arg(pingAudio);
|
||||
} else {
|
||||
audioPing = QString("Audio ping: --");
|
||||
}
|
||||
|
||||
QString avatarPing;
|
||||
if (pingAvatar >= 0) {
|
||||
avatarPing = QString("Avatar ping: %1").arg(pingAvatar);
|
||||
} else {
|
||||
avatarPing = QString("Avatar ping: --");
|
||||
}
|
||||
|
||||
QString voxelAvgPing;
|
||||
if (pingVoxel >= 0) {
|
||||
voxelAvgPing = QString("Entities avg ping: %1").arg(pingVoxel);
|
||||
} else {
|
||||
voxelAvgPing = QString("Entities avg ping: --");
|
||||
}
|
||||
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioPing.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPing.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelAvgPing.toUtf8().constData(), color);
|
||||
|
||||
if (_expanded) {
|
||||
QString voxelMaxPing;
|
||||
if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
|
||||
voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
|
||||
} else {
|
||||
voxelMaxPing = QString("Voxel max ping: --");
|
||||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing.toUtf8().constData(), color);
|
||||
}
|
||||
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + 2;
|
||||
STAT_UPDATE(entitiesPing, pingVoxel);
|
||||
//if (_expanded) {
|
||||
// QString voxelMaxPing;
|
||||
// if (pingVoxel >= 0) { // Average is only meaningful if pingVoxel is valid.
|
||||
// voxelMaxPing = QString("Voxel max ping: %1").arg(pingOctreeMax);
|
||||
// } else {
|
||||
// voxelMaxPing = QString("Voxel max ping: --");
|
||||
// }
|
||||
} else {
|
||||
// -2 causes the QML to hide the ping column
|
||||
STAT_UPDATE(audioPing, -2);
|
||||
}
|
||||
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
|
||||
// Third column, avatar stats
|
||||
MyAvatar* myAvatar = avatarManager->getMyAvatar();
|
||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||
|
||||
lines = _expanded ? 7 : 3;
|
||||
|
||||
if (columnOneWidth == _generalStatsWidth) {
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, _geoStatsWidth, (lines + 1) * STATS_PELS_PER_LINE);
|
||||
}
|
||||
horizontalOffset += 5;
|
||||
|
||||
QString avatarPosition = QString("Position: %1, %2, %3").
|
||||
arg(avatarPos.x, -1, 'f', 1).
|
||||
arg(avatarPos.y, -1, 'f', 1).
|
||||
arg(avatarPos.z, -1, 'f', 1);
|
||||
QString avatarVelocity = QString("Velocity: %1").arg(glm::length(myAvatar->getVelocity()), -1, 'f', 1);
|
||||
QString avatarBodyYaw = QString("Yaw: %1").arg(myAvatar->getBodyYaw(), -1, 'f', 1);
|
||||
QString avatarMixerStats;
|
||||
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarPosition.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarVelocity.toUtf8().constData(), color);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarBodyYaw.toUtf8().constData(), color);
|
||||
|
||||
STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
|
||||
STAT_UPDATE_FLOAT(velocity, glm::length(myAvatar->getVelocity()), 0.1f);
|
||||
STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f);
|
||||
if (_expanded) {
|
||||
SharedNodePointer avatarMixer = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::AvatarMixer);
|
||||
SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
if (avatarMixer) {
|
||||
avatarMixerStats = QString("Avatar Mixer: %1 kbps, %2 pps").
|
||||
arg(roundf(bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
||||
bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))).
|
||||
arg(roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
||||
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||
STAT_UPDATE(avatarMixerKbps, roundf(
|
||||
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AvatarMixer) +
|
||||
bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AvatarMixer)));
|
||||
STAT_UPDATE(avatarMixerPps, roundf(
|
||||
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AvatarMixer) +
|
||||
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AvatarMixer)));
|
||||
} else {
|
||||
avatarMixerStats = QString("No Avatar Mixer");
|
||||
STAT_UPDATE(avatarMixerKbps, -1);
|
||||
STAT_UPDATE(avatarMixerPps, -1);
|
||||
}
|
||||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
if (audioMixerNode) {
|
||||
STAT_UPDATE(audioMixerKbps, roundf(
|
||||
bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AudioMixer) +
|
||||
bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer)));
|
||||
STAT_UPDATE(audioMixerPps, roundf(
|
||||
bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer) +
|
||||
bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer)));
|
||||
} else {
|
||||
STAT_UPDATE(audioMixerKbps, -1);
|
||||
STAT_UPDATE(audioMixerPps, -1);
|
||||
}
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, avatarMixerStats.toUtf8().constData(), color);
|
||||
|
||||
stringstream downloads;
|
||||
downloads << "Downloads: ";
|
||||
foreach (Resource* resource, ResourceCache::getLoadingRequests()) {
|
||||
downloads << (int)(resource->getProgress() * 100.0f) << "% ";
|
||||
}
|
||||
downloads << "(" << ResourceCache::getPendingRequestCount() << " pending)";
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
||||
}
|
||||
STAT_UPDATE(downloads, ResourceCache::getLoadingRequests().size());
|
||||
STAT_UPDATE(downloadsPending, ResourceCache::getPendingRequestCount());
|
||||
// TODO fix to match original behavior
|
||||
//stringstream downloads;
|
||||
//downloads << "Downloads: ";
|
||||
//foreach(Resource* resource, ) {
|
||||
// downloads << (int)(resource->getProgress() * 100.0f) << "% ";
|
||||
//}
|
||||
//downloads << "(" << << " pending)";
|
||||
} // expanded avatar column
|
||||
|
||||
verticalOffset = STATS_PELS_INITIALOFFSET;
|
||||
horizontalOffset = _lastHorizontalOffset + _generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3;
|
||||
|
||||
lines = _expanded ? 10 : 3;
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, canvasSize.x - horizontalOffset,
|
||||
(lines + 1) * STATS_PELS_PER_LINE);
|
||||
horizontalOffset += 5;
|
||||
|
||||
// Model/Entity render details
|
||||
octreeStats.str("");
|
||||
octreeStats << "Triangles: " << _renderDetails._trianglesRendered
|
||||
<< " / Quads:" << _renderDetails._quadsRendered
|
||||
<< " / Material Switches:" << _renderDetails._materialSwitches;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
// Fourth column, octree stats
|
||||
}
|
||||
|
||||
void Stats::setRenderDetails(const RenderDetails& details) {
|
||||
//STATS_PROPERTY(int, triangles, 0)
|
||||
//STATS_PROPERTY(int, quads, 0)
|
||||
//STATS_PROPERTY(int, materialSwitches, 0)
|
||||
//STATS_PROPERTY(int, meshOpaque, 0)
|
||||
//STATS_PROPERTY(int, meshTranslucent, 0)
|
||||
//STATS_PROPERTY(int, opaqueConsidered, 0)
|
||||
//STATS_PROPERTY(int, opaqueOutOfView, 0)
|
||||
//STATS_PROPERTY(int, opaqueTooSmall, 0)
|
||||
//STATS_PROPERTY(int, translucentConsidered, 0)
|
||||
//STATS_PROPERTY(int, translucentOutOfView, 0)
|
||||
//STATS_PROPERTY(int, translucentTooSmall, 0)
|
||||
//STATS_PROPERTY(int, octreeElementsServer, 0)
|
||||
//STATS_PROPERTY(int, octreeElementsLocal, 0)
|
||||
STAT_UPDATE(triangles, details._trianglesRendered);
|
||||
STAT_UPDATE(quads, details._quadsRendered);
|
||||
STAT_UPDATE(materialSwitches, details._materialSwitches);
|
||||
if (_expanded) {
|
||||
octreeStats.str("");
|
||||
octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered
|
||||
<< " / Translucent:" << _renderDetails._translucent._rendered;
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
|
||||
octreeStats.str("");
|
||||
octreeStats << " Opaque considered: " << _renderDetails._opaque._considered
|
||||
<< " / Out of view:" << _renderDetails._opaque._outOfView
|
||||
<< " / Too small:" << _renderDetails._opaque._tooSmall;
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
|
||||
octreeStats.str("");
|
||||
octreeStats << " Translucent considered: " << _renderDetails._translucent._considered
|
||||
<< " / Out of view:" << _renderDetails._translucent._outOfView
|
||||
<< " / Too small:" << _renderDetails._translucent._tooSmall;
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
STAT_UPDATE(meshOpaque, details._opaque._rendered);
|
||||
STAT_UPDATE(meshTranslucent, details._opaque._rendered);
|
||||
STAT_UPDATE(opaqueConsidered, details._opaque._considered);
|
||||
STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
|
||||
STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
|
||||
STAT_UPDATE(translucentConsidered, details._translucent._considered);
|
||||
STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
|
||||
STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// display expanded or contracted stats
|
||||
void Stats::display(
|
||||
int voxelPacketsToProcess)
|
||||
{
|
||||
// iterate all the current voxel stats, and list their sending modes, and total voxel counts
|
||||
std::stringstream sendingMode("");
|
||||
sendingMode << "Octree Sending Mode: [";
|
||||
|
@ -619,3 +359,81 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
|
||||
//// Performance timer
|
||||
|
||||
|
||||
bool performanceTimerIsActive = PerformanceTimer::isActive();
|
||||
bool displayPerf = _expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails);
|
||||
if (displayPerf && performanceTimerIsActive) {
|
||||
PerformanceTimer::tallyAllTimerRecords(); // do this even if we're not displaying them, so they don't stack up
|
||||
columnOneWidth = _generalStatsWidth + _pingStatsWidth + _geoStatsWidth; // 3 columns wide...
|
||||
// we will also include room for 1 line per timing record and a header of 4 lines
|
||||
lines += 4;
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
int statsLines = 0;
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
statsLines++;
|
||||
if (onlyDisplayTopTen && statsLines == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (displayPerf && performanceTimerIsActive) {
|
||||
bool onlyDisplayTopTen = Menu::getInstance()->isOptionChecked(MenuOption::OnlyDisplayTopTen);
|
||||
// Timing details...
|
||||
verticalOffset += STATS_PELS_PER_LINE * 4; // skip 3 lines to be under the other columns
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"-------------------------------------------------------- Function "
|
||||
"------------------------------------------------------- --msecs- -calls--", color);
|
||||
|
||||
// First iterate all the records, and for the ones that should be included, insert them into
|
||||
// a new Map sorted by average time...
|
||||
QMap<float, QString> sortedRecords;
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
float averageTime = (float)i.value().getMovingAverage() / (float)USECS_PER_MSEC;
|
||||
sortedRecords.insertMulti(averageTime, i.key());
|
||||
}
|
||||
}
|
||||
|
||||
int linesDisplayed = 0;
|
||||
QMapIterator<float, QString> j(sortedRecords);
|
||||
j.toBack();
|
||||
while (j.hasPrevious()) {
|
||||
j.previous();
|
||||
QChar noBreakingSpace = QChar::Nbsp;
|
||||
QString functionName = j.value();
|
||||
const PerformanceTimerRecord& record = allRecords.value(functionName);
|
||||
|
||||
QString perfLine = QString("%1: %2 [%3]").
|
||||
arg(QString(qPrintable(functionName)), 120, noBreakingSpace).
|
||||
arg((float)record.getMovingAverage() / (float)USECS_PER_MSEC, 8, 'f', 3, noBreakingSpace).
|
||||
arg((int)record.getCount(), 6, 10, noBreakingSpace);
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(columnOneHorizontalOffset, verticalOffset, scale, rotation, font, perfLine.toUtf8().constData(), color);
|
||||
linesDisplayed++;
|
||||
if (onlyDisplayTopTen && linesDisplayed == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
*/
|
|
@ -13,47 +13,113 @@
|
|||
#define hifi_Stats_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QQuickItem>
|
||||
#include <QVector3D>
|
||||
|
||||
#include <OffscreenUi.h>
|
||||
#include <RenderArgs.h>
|
||||
|
||||
class Stats: public QObject {
|
||||
#define STATS_PROPERTY(type, name, initialValue) \
|
||||
Q_PROPERTY(type name READ name NOTIFY name##Changed) \
|
||||
public: \
|
||||
type name() { return _##name; }; \
|
||||
private: \
|
||||
type _##name{ initialValue };
|
||||
|
||||
|
||||
class Stats : public QQuickItem {
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
Q_PROPERTY(bool expanded READ isExpanded NOTIFY expandedChanged)
|
||||
STATS_PROPERTY(int, serverCount, 0)
|
||||
STATS_PROPERTY(int, framerate, 0)
|
||||
STATS_PROPERTY(int, avatarCount, 0)
|
||||
STATS_PROPERTY(int, packetInCount, 0)
|
||||
STATS_PROPERTY(int, packetOutCount, 0)
|
||||
STATS_PROPERTY(float, mbpsIn, 0)
|
||||
STATS_PROPERTY(float, mbpsOut, 0)
|
||||
STATS_PROPERTY(int, audioPing, 0)
|
||||
STATS_PROPERTY(int, avatarPing, 0)
|
||||
STATS_PROPERTY(int, entitiesPing, 0)
|
||||
STATS_PROPERTY(QVector3D, position, QVector3D(0, 0, 0) )
|
||||
STATS_PROPERTY(float, velocity, 0)
|
||||
STATS_PROPERTY(float, yaw, 0)
|
||||
STATS_PROPERTY(int, avatarMixerKbps, 0)
|
||||
STATS_PROPERTY(int, avatarMixerPps, 0)
|
||||
STATS_PROPERTY(int, audioMixerKbps, 0)
|
||||
STATS_PROPERTY(int, audioMixerPps, 0)
|
||||
STATS_PROPERTY(int, downloads, 0)
|
||||
STATS_PROPERTY(int, downloadsPending, 0)
|
||||
STATS_PROPERTY(int, triangles, 0)
|
||||
STATS_PROPERTY(int, quads, 0)
|
||||
STATS_PROPERTY(int, materialSwitches, 0)
|
||||
STATS_PROPERTY(int, meshOpaque, 0)
|
||||
STATS_PROPERTY(int, meshTranslucent, 0)
|
||||
STATS_PROPERTY(int, opaqueConsidered, 0)
|
||||
STATS_PROPERTY(int, opaqueOutOfView, 0)
|
||||
STATS_PROPERTY(int, opaqueTooSmall, 0)
|
||||
STATS_PROPERTY(int, translucentConsidered, 0)
|
||||
STATS_PROPERTY(int, translucentOutOfView, 0)
|
||||
STATS_PROPERTY(int, translucentTooSmall, 0)
|
||||
STATS_PROPERTY(int, octreeElementsServer, 0)
|
||||
STATS_PROPERTY(int, octreeElementsLocal, 0)
|
||||
|
||||
public:
|
||||
static Stats* getInstance();
|
||||
|
||||
Stats();
|
||||
|
||||
static void drawBackground(unsigned int rgba, int x, int y, int width, int height);
|
||||
|
||||
void toggleExpanded();
|
||||
bool isExpanded() { return _expanded; }
|
||||
|
||||
void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
|
||||
void resetWidth(int width, int horizontalOffset);
|
||||
void display(const float* color, int horizontalOffset, float fps, int inPacketsPerSecond, int outPacketsPerSecond,
|
||||
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
|
||||
Stats(QQuickItem* parent = nullptr);
|
||||
bool includeTimingRecord(const QString& name);
|
||||
|
||||
void setRenderDetails(const RenderDetails& details) { _renderDetails = details; }
|
||||
|
||||
void setRenderDetails(const RenderDetails& details);
|
||||
|
||||
void updateStats();
|
||||
|
||||
bool isExpanded() { return _expanded; }
|
||||
|
||||
void setExpanded(bool expanded) {
|
||||
if (expanded != _expanded) {
|
||||
_expanded = expanded;
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void expandedChanged();
|
||||
void serverCountChanged();
|
||||
void framerateChanged();
|
||||
void avatarCountChanged();
|
||||
void packetInCountChanged();
|
||||
void packetOutCountChanged();
|
||||
void mbpsInChanged();
|
||||
void mbpsOutChanged();
|
||||
void audioPingChanged();
|
||||
void avatarPingChanged();
|
||||
void entitiesPingChanged();
|
||||
void positionChanged();
|
||||
void velocityChanged();
|
||||
void yawChanged();
|
||||
void avatarMixerKbpsChanged();
|
||||
void avatarMixerPpsChanged();
|
||||
void audioMixerKbpsChanged();
|
||||
void audioMixerPpsChanged();
|
||||
void downloadsChanged();
|
||||
void downloadsPendingChanged();
|
||||
void trianglesChanged();
|
||||
void quadsChanged();
|
||||
void materialSwitchesChanged();
|
||||
void meshOpaqueChanged();
|
||||
void meshTranslucentChanged();
|
||||
void opaqueConsideredChanged();
|
||||
void opaqueOutOfViewChanged();
|
||||
void opaqueTooSmallChanged();
|
||||
void translucentConsideredChanged();
|
||||
void translucentOutOfViewChanged();
|
||||
void translucentTooSmallChanged();
|
||||
void octreeElementsServerChanged();
|
||||
void octreeElementsLocalChanged();
|
||||
|
||||
private:
|
||||
static Stats* _sharedInstance;
|
||||
|
||||
bool _expanded;
|
||||
|
||||
int _recentMaxPackets; // recent max incoming voxel packets to process
|
||||
bool _resetRecentMaxPacketsSoon;
|
||||
|
||||
int _generalStatsWidth;
|
||||
int _bandwidthStatsWidth;
|
||||
int _pingStatsWidth;
|
||||
int _geoStatsWidth;
|
||||
int _octreeStatsWidth;
|
||||
|
||||
int _lastHorizontalOffset;
|
||||
|
||||
RenderDetails _renderDetails;
|
||||
int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process
|
||||
bool _resetRecentMaxPacketsSoon{ true };
|
||||
bool _expanded{ false };
|
||||
};
|
||||
|
||||
#endif // hifi_Stats_h
|
||||
|
|
|
@ -91,6 +91,7 @@ void OffscreenQmlSurface::resize(const QSize& newSize) {
|
|||
// Qt bug in 5.4 forces this check of pixel ratio,
|
||||
// even though we're rendering offscreen.
|
||||
qreal pixelRatio = 1.0;
|
||||
_qmlEngine->rootContext()->setContextProperty("surfaceSize", newSize);
|
||||
if (_renderControl && _renderControl->_renderWindow) {
|
||||
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
||||
} else {
|
||||
|
@ -111,7 +112,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize) {
|
|||
_quickWindow->contentItem()->setSize(newSize);
|
||||
}
|
||||
|
||||
|
||||
// Update our members
|
||||
if (_rootItem) {
|
||||
_rootItem->setSize(newSize);
|
||||
|
@ -376,4 +376,4 @@ void OffscreenQmlSurface::setProxyWindow(QWindow* window) {
|
|||
|
||||
QQuickWindow* OffscreenQmlSurface::getWindow() {
|
||||
return _quickWindow;
|
||||
}
|
||||
}
|
||||
|
|
51
libraries/ui/src/Tooltip.cpp
Normal file
51
libraries/ui/src/Tooltip.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// Tooltip.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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 "Tooltip.h"
|
||||
#include <QUuid>
|
||||
|
||||
HIFI_QML_DEF(Tooltip)
|
||||
|
||||
Tooltip::Tooltip(QQuickItem* parent) : QQuickItem(parent) {
|
||||
}
|
||||
|
||||
Tooltip::~Tooltip() {
|
||||
}
|
||||
|
||||
QString Tooltip::text() const {
|
||||
return _text;
|
||||
}
|
||||
|
||||
void Tooltip::setText(const QString& arg) {
|
||||
if (arg != _text) {
|
||||
_text = arg;
|
||||
emit textChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Tooltip::setVisible(bool visible) {
|
||||
QQuickItem::setVisible(visible);
|
||||
}
|
||||
|
||||
QString Tooltip::showTip(const QString& text) {
|
||||
const QString newTipId = QUuid().createUuid().toString();
|
||||
Tooltip::show([&](QQmlContext*, QObject* object) {
|
||||
object->setObjectName(newTipId);
|
||||
object->setProperty("text", text);
|
||||
});
|
||||
return newTipId;
|
||||
}
|
||||
|
||||
void Tooltip::closeTip(const QString& tipId) {
|
||||
auto rootItem = DependencyManager::get<OffscreenUi>()->getRootItem();
|
||||
QQuickItem* that = rootItem->findChild<QQuickItem*>(tipId);
|
||||
if (that) {
|
||||
that->deleteLater();
|
||||
}
|
||||
}
|
45
libraries/ui/src/Tooltip.h
Normal file
45
libraries/ui/src/Tooltip.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Tooltip.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_Tooltip_h
|
||||
#define hifi_Tooltip_h
|
||||
|
||||
#include "OffscreenQmlDialog.h"
|
||||
|
||||
class Tooltip : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
HIFI_QML_DECL
|
||||
|
||||
private:
|
||||
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
|
||||
|
||||
public:
|
||||
Tooltip(QQuickItem* parent = 0);
|
||||
virtual ~Tooltip();
|
||||
|
||||
QString text() const;
|
||||
|
||||
static QString showTip(const QString& text);
|
||||
static void closeTip(const QString& tipId);
|
||||
|
||||
public slots:
|
||||
virtual void setVisible(bool v);
|
||||
void setText(const QString& arg);
|
||||
|
||||
signals:
|
||||
void textChanged();
|
||||
|
||||
private:
|
||||
QString _text;
|
||||
};
|
||||
|
||||
#endif // hifi_Tooltip_h
|
Loading…
Reference in a new issue