mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge with master
This commit is contained in:
commit
b062295ecb
25 changed files with 972 additions and 69 deletions
|
@ -138,7 +138,7 @@ int main(int argc, const char* argv[]) {
|
|||
const char MIXER_LOGSTASH_METRIC_NAME[] = "audio-mixer-frame-time-usage";
|
||||
|
||||
float averageFrameTimePercentage = sumFrameTimePercentages / numStatCollections;
|
||||
Logstash::stashValue(MIXER_LOGSTASH_METRIC_NAME, averageFrameTimePercentage);
|
||||
Logstash::stashValue(STAT_TYPE_GAUGE, MIXER_LOGSTASH_METRIC_NAME, averageFrameTimePercentage);
|
||||
|
||||
sumFrameTimePercentages = 0.0f;
|
||||
numStatCollections = 0;
|
||||
|
|
|
@ -32,9 +32,9 @@ else (LEAP_LIBRARIES AND LEAP_INCLUDE_DIRS)
|
|||
endif ()
|
||||
|
||||
# If we're using the Leap stubs, there's only a header, no lib.
|
||||
if (LEAP_INCLUDE_DIRS)
|
||||
if (LEAP_LIBRARIES AND LEAP_INCLUDE_DIRS)
|
||||
set(LEAP_FOUND TRUE)
|
||||
endif (LEAP_INCLUDE_DIRS)
|
||||
endif (LEAP_LIBRARIES AND LEAP_INCLUDE_DIRS)
|
||||
|
||||
if (LEAP_FOUND)
|
||||
if (NOT Leap_FIND_QUIETLY)
|
||||
|
|
|
@ -17,35 +17,23 @@
|
|||
// M - Audio Mixer
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
|
||||
#include "AgentList.h"
|
||||
#include "AgentTypes.h"
|
||||
#include <PacketHeaders.h>
|
||||
#include "Logstash.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Syssocket.h"
|
||||
#include "Systime.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
|
||||
const int DOMAIN_LISTEN_PORT = 40102;
|
||||
unsigned char packetData[MAX_PACKET_SIZE];
|
||||
|
||||
const int LOGOFF_CHECK_INTERVAL = 5000;
|
||||
|
||||
int lastActiveCount = 0;
|
||||
const int NODE_COUNT_STAT_INTERVAL_MSECS = 5000;
|
||||
|
||||
unsigned char* addAgentToBroadcastPacket(unsigned char* currentPosition, Agent* agentToAdd) {
|
||||
*currentPosition++ = agentToAdd->getType();
|
||||
|
@ -94,6 +82,8 @@ int main(int argc, const char * argv[])
|
|||
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
|
||||
timeval lastStatSendTime = {};
|
||||
|
||||
while (true) {
|
||||
if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) &&
|
||||
(packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) {
|
||||
|
@ -185,6 +175,17 @@ int main(int argc, const char * argv[])
|
|||
broadcastPacket,
|
||||
(currentBufferPos - startPointer) + 1);
|
||||
}
|
||||
|
||||
if (Logstash::shouldSendStats()) {
|
||||
if (usecTimestampNow() - usecTimestamp(&lastStatSendTime) >= (NODE_COUNT_STAT_INTERVAL_MSECS * 1000)) {
|
||||
// time to send our count of agents and servers to logstash
|
||||
const char NODE_COUNT_LOGSTASH_KEY[] = "ds-node-count";
|
||||
|
||||
Logstash::stashValue(STAT_TYPE_GAUGE, NODE_COUNT_LOGSTASH_KEY, agentList->getNumAliveAgents());
|
||||
|
||||
gettimeofday(&lastStatSendTime, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -74,7 +74,7 @@ add_subdirectory(external/fervor/)
|
|||
include_directories(external/fervor/)
|
||||
|
||||
# run qt moc on qt-enabled headers
|
||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h)
|
||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h src/ui/BandwidthDialog.h)
|
||||
|
||||
# create the executable, make it a bundle on OS X
|
||||
add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS})
|
||||
|
@ -112,6 +112,7 @@ include_directories(
|
|||
${OPENCV_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${OPENCV_INCLUDE_DIRS}")
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${QT_LIBRARIES}
|
||||
|
@ -153,8 +154,12 @@ if (APPLE)
|
|||
${QuartzCore}
|
||||
${UVCCAMERACONTROL_LIBRARIES}
|
||||
${LIBOVR_LIBRARIES}
|
||||
${LEAP_LIBRARIES}
|
||||
)
|
||||
|
||||
if (LEAP_FOUND)
|
||||
target_link_libraries(${TARGET_NAME} ${LEAP_LIBRARIES})
|
||||
endif(LEAP_FOUND)
|
||||
|
||||
else (APPLE)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
#include <QGLWidget>
|
||||
#include <QImage>
|
||||
#include <QKeyEvent>
|
||||
#include <QLineEdit>
|
||||
#include <QMainWindow>
|
||||
|
@ -72,6 +73,8 @@ using namespace std;
|
|||
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
||||
static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
||||
|
||||
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
|
||||
|
||||
const glm::vec3 START_LOCATION(4.f, 0.f, 5.f); // Where one's own agent begins in the world
|
||||
// (will be overwritten if avatar data file is found)
|
||||
|
||||
|
@ -162,6 +165,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
QApplication(argc, argv),
|
||||
_window(new QMainWindow(desktop())),
|
||||
_glWidget(new GLCanvas()),
|
||||
_bandwidthDialog(NULL),
|
||||
_displayLevels(false),
|
||||
_frameCount(0),
|
||||
_fps(120.0f),
|
||||
|
@ -350,7 +354,7 @@ void Application::initializeGL() {
|
|||
const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
|
||||
|
||||
// ask the Logstash class to record the startup time
|
||||
Logstash::stashValue(LOGSTASH_INTERFACE_START_TIME_KEY, startupTime);
|
||||
Logstash::stashValue(STAT_TYPE_TIMER, LOGSTASH_INTERFACE_START_TIME_KEY, startupTime);
|
||||
}
|
||||
|
||||
// update before the first render
|
||||
|
@ -451,7 +455,7 @@ void Application::resizeGL(int width, int height) {
|
|||
}
|
||||
} else {
|
||||
camera.setAspectRatio(aspectRatio);
|
||||
camera.setFieldOfView(fov = 60);
|
||||
camera.setFieldOfView(fov = _horizontalFieldOfView);
|
||||
}
|
||||
|
||||
// Tell our viewFrustum about this change
|
||||
|
@ -482,11 +486,30 @@ void Application::resizeGL(int width, int height) {
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
static void sendVoxelServerAddScene() {
|
||||
void Application::broadcastToAgents(unsigned char* data, size_t bytes, const char type) {
|
||||
|
||||
int n = AgentList::getInstance()->broadcastToAgents(data, bytes, &type, 1);
|
||||
|
||||
BandwidthMeter::ChannelIndex channel;
|
||||
switch (type) {
|
||||
case AGENT_TYPE_AVATAR:
|
||||
case AGENT_TYPE_AVATAR_MIXER:
|
||||
channel = BandwidthMeter::AVATARS;
|
||||
break;
|
||||
case AGENT_TYPE_VOXEL_SERVER:
|
||||
channel = BandwidthMeter::VOXELS;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
getInstance()->_bandwidthMeter.outputStream(channel).updateValue(n * bytes);
|
||||
}
|
||||
|
||||
void Application::sendVoxelServerAddScene() {
|
||||
char message[100];
|
||||
sprintf(message,"%c%s",'Z',"add scene");
|
||||
int messageSize = strlen(message) + 1;
|
||||
AgentList::getInstance()->broadcastToAgents((unsigned char*)message, messageSize, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents((unsigned char*)message, messageSize, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
void Application::keyPressEvent(QKeyEvent* event) {
|
||||
|
@ -813,6 +836,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
|
|||
_mouseX = event->x();
|
||||
_mouseY = event->y();
|
||||
_mousePressed = false;
|
||||
checkBandwidthMeterClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -953,7 +977,7 @@ void Application::terminate() {
|
|||
}
|
||||
}
|
||||
|
||||
static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||
void Application::sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
||||
|
||||
if (ownerID == UNKNOWN_AGENT_ID) {
|
||||
|
@ -964,10 +988,10 @@ static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
|||
message.append((const char*)&ownerID, sizeof(ownerID));
|
||||
message.append(url.toEncoded());
|
||||
|
||||
AgentList::getInstance()->broadcastToAgents((unsigned char*)message.data(), message.size(), &AGENT_TYPE_AVATAR_MIXER, 1);
|
||||
broadcastToAgents((unsigned char*)message.data(), message.size(), AGENT_TYPE_AVATAR_MIXER);
|
||||
}
|
||||
|
||||
static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
|
||||
void Application::processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes) {
|
||||
// skip the header
|
||||
packetData++;
|
||||
dataBytes--;
|
||||
|
@ -992,6 +1016,37 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB
|
|||
QMetaObject::invokeMethod(avatar->getVoxels(), "setVoxelURL", Q_ARG(QUrl, url));
|
||||
}
|
||||
|
||||
void Application::checkBandwidthMeterClick() {
|
||||
// ... to be called upon button release
|
||||
|
||||
if (_bandwidthDisplayOn->isChecked() &&
|
||||
glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH &&
|
||||
_bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) {
|
||||
|
||||
// The bandwidth meter is visible, the click didn't get dragged too far and
|
||||
// we actually hit the bandwidth meter
|
||||
bandwidthDetails();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::bandwidthDetails() {
|
||||
|
||||
if (! _bandwidthDialog) {
|
||||
_bandwidthDialog = new BandwidthDialog(_glWidget, getBandwidthMeter());
|
||||
connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed()));
|
||||
|
||||
_bandwidthDialog->show();
|
||||
}
|
||||
_bandwidthDialog->raise();
|
||||
}
|
||||
|
||||
void Application::bandwidthDetailsClosed() {
|
||||
|
||||
QDialog* dlg = _bandwidthDialog;
|
||||
_bandwidthDialog = NULL;
|
||||
delete dlg;
|
||||
}
|
||||
|
||||
void Application::editPreferences() {
|
||||
QDialog dialog(_glWidget);
|
||||
dialog.setWindowTitle("Interface Preferences");
|
||||
|
@ -1005,6 +1060,12 @@ void Application::editPreferences() {
|
|||
avatarURL->setMinimumWidth(400);
|
||||
form->addRow("Avatar URL:", avatarURL);
|
||||
|
||||
QSpinBox* horizontalFieldOfView = new QSpinBox();
|
||||
horizontalFieldOfView->setMaximum(180);
|
||||
horizontalFieldOfView->setMinimum(1);
|
||||
horizontalFieldOfView->setValue(_horizontalFieldOfView);
|
||||
form->addRow("Horizontal field of view (degrees):", horizontalFieldOfView);
|
||||
|
||||
QDoubleSpinBox* headCameraPitchYawScale = new QDoubleSpinBox();
|
||||
headCameraPitchYawScale->setValue(_headCameraPitchYawScale);
|
||||
form->addRow("Head Camera Pitch/Yaw Scale:", headCameraPitchYawScale);
|
||||
|
@ -1036,6 +1097,9 @@ void Application::editPreferences() {
|
|||
if (!shouldDynamicallySetJitterBuffer()) {
|
||||
_audio.setJitterBufferSamples(_audioJitterBufferSamples);
|
||||
}
|
||||
_horizontalFieldOfView = horizontalFieldOfView->value();
|
||||
resizeGL(_glWidget->width(), _glWidget->height());
|
||||
|
||||
}
|
||||
|
||||
void Application::pair() {
|
||||
|
@ -1152,12 +1216,12 @@ void Application::updateVoxelModeActions() {
|
|||
}
|
||||
}
|
||||
|
||||
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||
void Application::sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||
unsigned char* bufferOut;
|
||||
int sizeOut;
|
||||
|
||||
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){
|
||||
AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
Application::broadcastToAgents(bufferOut, sizeOut, AGENT_TYPE_VOXEL_SERVER);
|
||||
delete[] bufferOut;
|
||||
}
|
||||
}
|
||||
|
@ -1233,10 +1297,16 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
|||
codeColorBuffer[bytesInCode + RED_INDEX ] = node->getColor()[RED_INDEX ];
|
||||
codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX];
|
||||
codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ];
|
||||
|
||||
// TODO: sendVoxelsOperation() is sending voxels too fast.
|
||||
// This printf function accidently slowed down sending
|
||||
// and hot-fixed the bug when importing
|
||||
// large PNG models (256x256 px and more)
|
||||
static unsigned int sendVoxelsOperationCalled = 0; printf("sending voxel #%u\n", ++sendVoxelsOperationCalled);
|
||||
|
||||
// if we have room don't have room in the buffer, then send the previously generated message first
|
||||
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
|
||||
AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args->messageBuffer, args->bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset
|
||||
}
|
||||
|
||||
|
@ -1269,14 +1339,31 @@ void Application::exportVoxels() {
|
|||
void Application::importVoxels() {
|
||||
QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
|
||||
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), desktopLocation,
|
||||
tr("Sparse Voxel Octree Files (*.svo)"));
|
||||
tr("Sparse Voxel Octree Files, Square PNG (*.svo *.png)"));
|
||||
QByteArray fileNameAscii = fileNameString.toAscii();
|
||||
const char* fileName = fileNameAscii.data();
|
||||
|
||||
// Read the file into a tree
|
||||
|
||||
VoxelTree importVoxels;
|
||||
importVoxels.readFromSVOFile(fileName);
|
||||
|
||||
if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) {
|
||||
QImage pngImage = QImage(fileName);
|
||||
if (pngImage.height() != pngImage.width()) {
|
||||
printLog("ERROR: Bad PNG size: height != width.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t* pixels;
|
||||
if (pngImage.format() == QImage::Format_ARGB32) {
|
||||
pixels = reinterpret_cast<const uint32_t*>(pngImage.constBits());
|
||||
} else {
|
||||
QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32);
|
||||
pixels = reinterpret_cast<const uint32_t*>(tmp.constBits());
|
||||
}
|
||||
|
||||
importVoxels.readFromSquareARGB32Pixels(pixels, pngImage.height());
|
||||
} else {
|
||||
importVoxels.readFromSVOFile(fileName);
|
||||
}
|
||||
|
||||
VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
||||
|
||||
// Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to
|
||||
|
@ -1300,7 +1387,7 @@ void Application::importVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1352,7 +1439,7 @@ void Application::pasteVoxels() {
|
|||
|
||||
// If we have voxels left in the packet, then send the packet
|
||||
if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) {
|
||||
AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1);
|
||||
broadcastToAgents(args.messageBuffer, args.bufferInUse, AGENT_TYPE_VOXEL_SERVER);
|
||||
}
|
||||
|
||||
if (calculatedOctCode) {
|
||||
|
@ -1429,7 +1516,11 @@ void Application::initMenu() {
|
|||
(_logOn = toolsMenu->addAction("Log"))->setCheckable(true);
|
||||
_logOn->setChecked(false);
|
||||
_logOn->setShortcut(Qt::CTRL | Qt::Key_L);
|
||||
|
||||
(_bandwidthDisplayOn = toolsMenu->addAction("Bandwidth Display"))->setCheckable(true);
|
||||
_bandwidthDisplayOn->setChecked(true);
|
||||
toolsMenu->addAction("Bandwidth Details", this, SLOT(bandwidthDetails()));
|
||||
|
||||
|
||||
QMenu* voxelMenu = menuBar->addMenu("Voxels");
|
||||
_voxelModeActions = new QActionGroup(this);
|
||||
_voxelModeActions->setExclusive(false); // exclusivity implies one is always checked
|
||||
|
@ -1561,7 +1652,7 @@ void Application::init() {
|
|||
|
||||
_myAvatar.init();
|
||||
_myAvatar.setPosition(START_LOCATION);
|
||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
_myCamera.setModeShiftRate(1.0f);
|
||||
_myAvatar.setDisplayingLookatVectors(false);
|
||||
|
||||
|
@ -1627,7 +1718,7 @@ void Application::update(float deltaTime) {
|
|||
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
||||
|
||||
// If we are dragging on a voxel, add thrust according to the amount the mouse is dragging
|
||||
const float VOXEL_GRAB_THRUST = 5.0f;
|
||||
const float VOXEL_GRAB_THRUST = 0.0f;
|
||||
if (_mousePressed && (_mouseVoxel.s != 0)) {
|
||||
glm::vec2 mouseDrag(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY);
|
||||
glm::quat orientation = _myAvatar.getOrientation();
|
||||
|
@ -1801,7 +1892,7 @@ void Application::update(float deltaTime) {
|
|||
_myCamera.setModeShiftRate(1.0f);
|
||||
}
|
||||
} else {
|
||||
const float THIRD_PERSON_SHIFT_VELOCITY = 2.0f;
|
||||
const float THIRD_PERSON_SHIFT_VELOCITY = 1000.0f;
|
||||
const float TIME_BEFORE_SHIFT_INTO_FIRST_PERSON = 0.75f;
|
||||
const float TIME_BEFORE_SHIFT_INTO_THIRD_PERSON = 0.1f;
|
||||
|
||||
|
@ -1818,6 +1909,11 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update bandwidth dialog, if any
|
||||
if (_bandwidthDialog) {
|
||||
_bandwidthDialog->update();
|
||||
}
|
||||
|
||||
// Update audio stats for procedural sounds
|
||||
#ifndef _WIN32
|
||||
|
@ -1901,8 +1997,8 @@ void Application::updateAvatar(float deltaTime) {
|
|||
|
||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||
|
||||
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL_SERVER, AGENT_TYPE_AVATAR_MIXER};
|
||||
AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers));
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_VOXEL_SERVER);
|
||||
broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, AGENT_TYPE_AVATAR_MIXER);
|
||||
|
||||
// once in a while, send my voxel url
|
||||
const float AVATAR_VOXEL_URL_SEND_INTERVAL = 1.0f; // seconds
|
||||
|
@ -2290,6 +2386,9 @@ void Application::displayOverlay() {
|
|||
glPointSize(1.0f);
|
||||
|
||||
if (_renderStatsOn->isChecked()) { displayStats(); }
|
||||
|
||||
if (_bandwidthDisplayOn->isChecked()) { _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); }
|
||||
|
||||
if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); }
|
||||
|
||||
// Show chat entry field
|
||||
|
@ -2851,6 +2950,7 @@ void* Application::networkReceive(void* args) {
|
|||
AgentList::getInstance()->processBulkAgentData(&senderAddress,
|
||||
app->_incomingPacket,
|
||||
bytesReceived);
|
||||
getInstance()->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(bytesReceived);
|
||||
break;
|
||||
case PACKET_HEADER_AVATAR_VOXEL_URL:
|
||||
processAvatarVoxelURLMessage(app->_incomingPacket, bytesReceived);
|
||||
|
@ -2914,6 +3014,8 @@ void Application::loadSettings(QSettings* settings) {
|
|||
|
||||
_headCameraPitchYawScale = loadSetting(settings, "headCameraPitchYawScale", 0.0f);
|
||||
_audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0);
|
||||
_horizontalFieldOfView = loadSetting(settings, "horizontalFieldOfView", HORIZONTAL_FIELD_OF_VIEW_DEGREES);
|
||||
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
// in case settings is corrupt or missing loadSetting() will check for NaN
|
||||
_viewFrustumOffsetYaw = loadSetting(settings, "viewFrustumOffsetYaw" , 0.0f);
|
||||
|
@ -2936,6 +3038,7 @@ void Application::saveSettings(QSettings* settings) {
|
|||
|
||||
settings->setValue("headCameraPitchYawScale", _headCameraPitchYawScale);
|
||||
settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples);
|
||||
settings->setValue("horizontalFieldOfView", _horizontalFieldOfView);
|
||||
settings->beginGroup("View Frustum Offset Camera");
|
||||
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffsetYaw);
|
||||
settings->setValue("viewFrustumOffsetPitch", _viewFrustumOffsetPitch);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include <AgentList.h>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "Audio.h"
|
||||
#endif
|
||||
|
@ -32,6 +35,7 @@
|
|||
#include "Stars.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "VoxelSystem.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "Webcam.h"
|
||||
#include "renderer/GeometryCache.h"
|
||||
#include "ui/ChatEntry.h"
|
||||
|
@ -86,6 +90,7 @@ public:
|
|||
Environment* getEnvironment() { return &_environment; }
|
||||
SerialInterface* getSerialHeadSensor() { return &_serialHeadSensor; }
|
||||
Webcam* getWebcam() { return &_webcam; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
bool shouldEchoAudio() { return _echoAudioMode->isChecked(); }
|
||||
bool shouldLowPassFilter() { return _shouldLowPassFilter->isChecked(); }
|
||||
|
||||
|
@ -99,8 +104,10 @@ private slots:
|
|||
void timer();
|
||||
void idle();
|
||||
void terminate();
|
||||
|
||||
|
||||
void bandwidthDetails();
|
||||
void editPreferences();
|
||||
void bandwidthDetailsClosed();
|
||||
|
||||
void pair();
|
||||
|
||||
|
@ -148,7 +155,12 @@ private slots:
|
|||
void runTests();
|
||||
private:
|
||||
|
||||
static void broadcastToAgents(unsigned char* data, size_t bytes, const char type);
|
||||
static void sendVoxelServerAddScene();
|
||||
static bool sendVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
static void sendAvatarVoxelURLMessage(const QUrl& url);
|
||||
static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataBytes);
|
||||
static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail);
|
||||
|
||||
void initMenu();
|
||||
void updateFrustumRenderModeAction();
|
||||
|
@ -164,7 +176,9 @@ private:
|
|||
void displayOverlay();
|
||||
void displayStats();
|
||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||
|
||||
|
||||
void checkBandwidthMeterClick();
|
||||
|
||||
void setupPaintingVoxel();
|
||||
void shiftPaintingColor();
|
||||
void maybeEditVoxelUnderCursor();
|
||||
|
@ -215,6 +229,7 @@ private:
|
|||
QAction* _manualFirstPerson; // Whether to force first-person mode
|
||||
QAction* _manualThirdPerson; // Whether to force third-person mode
|
||||
QAction* _logOn; // Whether to show on-screen log
|
||||
QAction* _bandwidthDisplayOn; // Whether to show on-screen bandwidth bars
|
||||
QActionGroup* _voxelModeActions; // The group of voxel edit mode actions
|
||||
QAction* _addVoxelMode; // Whether add voxel mode is enabled
|
||||
QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled
|
||||
|
@ -229,6 +244,9 @@ private:
|
|||
QAction* _frustumRenderModeAction;
|
||||
QAction* _settingsAutosave; // Whether settings are saved automatically
|
||||
|
||||
BandwidthMeter _bandwidthMeter;
|
||||
BandwidthDialog* _bandwidthDialog;
|
||||
|
||||
SerialInterface _serialHeadSensor;
|
||||
QNetworkAccessManager* _networkAccessManager;
|
||||
QSettings* _settings;
|
||||
|
@ -243,7 +261,7 @@ private:
|
|||
timeval _timerStart, _timerEnd;
|
||||
timeval _lastTimeIdle;
|
||||
bool _justStarted;
|
||||
|
||||
|
||||
Stars _stars;
|
||||
|
||||
VoxelSystem _voxels;
|
||||
|
@ -282,6 +300,8 @@ private:
|
|||
|
||||
int _audioJitterBufferSamples; // Number of extra samples to wait before starting audio playback
|
||||
|
||||
float _horizontalFieldOfView; // In Degrees, doesn't apply to HMD like Oculus
|
||||
|
||||
HandControl _handControl;
|
||||
|
||||
int _mouseX;
|
||||
|
|
|
@ -120,10 +120,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
|||
|
||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||
|
||||
agentList->getAgentSocket()->send(audioMixer->getActiveSocket(),
|
||||
dataPacket,
|
||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
|
||||
interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO)
|
||||
.updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -335,16 +337,23 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
|||
// Manually initialize the portaudio stream to ask for minimum latency
|
||||
PaStreamParameters inputParameters, outputParameters;
|
||||
|
||||
inputParameters.device = Pa_GetDefaultInputDevice();
|
||||
inputParameters.device = Pa_GetDefaultInputDevice();
|
||||
outputParameters.device = Pa_GetDefaultOutputDevice();
|
||||
|
||||
if (inputParameters.device == -1 || outputParameters.device == -1) {
|
||||
printLog("Audio: Missing device.\n");
|
||||
outputPortAudioError(Pa_Terminate());
|
||||
return;
|
||||
}
|
||||
|
||||
inputParameters.channelCount = 2; // Stereo input
|
||||
inputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
||||
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
|
||||
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
|
||||
inputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
outputParameters.device = Pa_GetDefaultOutputDevice();
|
||||
outputParameters.channelCount = 2; // Stereo output
|
||||
outputParameters.sampleFormat = (paInt16 | paNonInterleaved);
|
||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
|
||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
|
||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
outputPortAudioError(Pa_OpenStream(&_stream,
|
||||
|
@ -438,7 +447,10 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy
|
|||
//printf("Got audio packet %d\n", _packetsReceivedThisPlayback);
|
||||
|
||||
_ringBuffer.parseData((unsigned char*) receivedData, PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO)
|
||||
.updateValue(PACKET_LENGTH_BYTES + sizeof(PACKET_HEADER));
|
||||
|
||||
_lastReceiveTime = currentReceiveTime;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#define __interface__Audio__
|
||||
|
||||
#include <portaudio.h>
|
||||
|
||||
#include <AudioRingBuffer.h>
|
||||
#include <StdDev.h>
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "world.h"
|
||||
|
||||
const float INITIAL_AREA = 0.2f;
|
||||
const float BALL_RADIUS = 0.025f;
|
||||
const float BALL_RADIUS = 0.016f;
|
||||
const glm::vec3 INITIAL_COLOR(0.62f, 0.74f, 0.91f);
|
||||
|
||||
Balls::Balls(int numberOfBalls) {
|
||||
|
@ -83,8 +83,9 @@ void Balls::render() {
|
|||
}
|
||||
|
||||
const float CONSTANT_VELOCITY_DAMPING = 1.0f;
|
||||
const float NOISE_SCALE = 0.00;
|
||||
const float SPRING_FORCE = 1.0;
|
||||
const float NOISE_SCALE = 0.06;
|
||||
const float SPRING_FORCE = 30.0;
|
||||
const float ORIGIN_DISTANCE = 0.1;
|
||||
const float SPRING_DAMPING = 1.0;
|
||||
|
||||
void Balls::simulate(float deltaTime) {
|
||||
|
@ -100,10 +101,21 @@ void Balls::simulate(float deltaTime) {
|
|||
// Add noise
|
||||
_balls[i].velocity += randVector() * NOISE_SCALE;
|
||||
|
||||
// spring force to origin
|
||||
float separation = glm::distance(_balls[i].position,
|
||||
_origin);
|
||||
|
||||
_balls[i].velocity +=
|
||||
glm::normalize(_balls[i].position - _origin)
|
||||
* deltaTime
|
||||
*
|
||||
SPRING_FORCE *
|
||||
(ORIGIN_DISTANCE - separation);
|
||||
|
||||
// Approach target position
|
||||
for (unsigned int i = 0; i < _numberOfBalls; ++i) {
|
||||
_balls[i].position += randFloat() * deltaTime * (_balls[i].targetPosition - _balls[i].position);
|
||||
}
|
||||
// for (unsigned int i = 0; i < _numberOfBalls; ++i) {
|
||||
// _balls[i].position += randFloat() * deltaTime * (_balls[i].targetPosition - _balls[i].position);
|
||||
// }
|
||||
|
||||
// Spring Force
|
||||
|
||||
|
|
230
interface/src/BandwidthMeter.cpp
Normal file
230
interface/src/BandwidthMeter.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
//
|
||||
// BandwidthMeter.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
|
||||
namespace { // .cpp-local
|
||||
|
||||
int const AREA_WIDTH = -400; // Width of the area used. Aligned to the right when negative.
|
||||
int const AREA_HEIGHT = 40; // Height of the area used. Aligned to the bottom when negative.
|
||||
int const BORDER_DISTANCE_HORIZ = -20; // Distance to edge of screen (use negative value when width is negative).
|
||||
int const BORDER_DISTANCE_VERT = 40; // Distance to edge of screen (use negative value when height is negative).
|
||||
|
||||
int SPACING_VERT_BARS = 2; // Vertical distance between input and output bar
|
||||
int SPACING_RIGHT_CAPTION_IN_OUT = 4; // IN/OUT <--> |######## : |
|
||||
int SPACING_LEFT_CAPTION_UNIT = 4; // |######## : | <--> UNIT
|
||||
int PADDING_HORIZ_VALUE = 2; // |<-->X.XX<:-># |
|
||||
|
||||
unsigned const COLOR_TEXT = 0xe0e0e0e0; // ^ ^ ^ ^ ^ ^
|
||||
unsigned const COLOR_FRAME = 0xe0e0e0b0; // | | |
|
||||
unsigned const COLOR_INDICATOR = 0xc0c0c0b0; // |
|
||||
|
||||
char const* CAPTION_IN = "IN";
|
||||
char const* CAPTION_OUT = "OUT";
|
||||
char const* CAPTION_UNIT = "Mbps";
|
||||
|
||||
double const UNIT_SCALE = 8000.0 / (1024.0 * 1024.0); // Bytes/ms -> Mbps
|
||||
int const INITIAL_SCALE_MAXIMUM_INDEX = 250; // / 9: exponent, % 9: mantissa - 2, 0 o--o 2 * 10^-10
|
||||
}
|
||||
|
||||
BandwidthMeter::ChannelInfo BandwidthMeter::_CHANNELS[] = {
|
||||
{ "Audio" , "Kbps", 8000.0 / 1024.0, 0x40ff40d0 },
|
||||
{ "Avatars" , "Kbps", 8000.0 / 1024.0, 0xffef40c0 },
|
||||
{ "Voxels" , "Kbps", 8000.0 / 1024.0, 0xd0d0d0a0 }
|
||||
};
|
||||
|
||||
BandwidthMeter::BandwidthMeter() :
|
||||
_textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT),
|
||||
_scaleMaxIndex(INITIAL_SCALE_MAXIMUM_INDEX) {
|
||||
|
||||
_channels = static_cast<ChannelInfo*>( malloc(sizeof(_CHANNELS)) );
|
||||
memcpy(_channels, _CHANNELS, sizeof(_CHANNELS));
|
||||
}
|
||||
|
||||
BandwidthMeter::~BandwidthMeter() {
|
||||
|
||||
free(_channels);
|
||||
}
|
||||
|
||||
BandwidthMeter::Stream::Stream(float msToAverage) :
|
||||
_value(0.0f),
|
||||
_msToAverage(msToAverage) {
|
||||
|
||||
gettimeofday(& _prevTime, NULL);
|
||||
}
|
||||
|
||||
void BandwidthMeter::Stream::updateValue(double amount) {
|
||||
|
||||
// Determine elapsed time
|
||||
timeval now;
|
||||
gettimeofday(& now, NULL);
|
||||
double dt = diffclock(& _prevTime, & now);
|
||||
memcpy(& _prevTime, & now, sizeof(timeval));
|
||||
|
||||
// Compute approximate average
|
||||
_value = glm::mix(_value, amount / dt,
|
||||
glm::clamp(dt / _msToAverage, 0.0, 1.0));
|
||||
}
|
||||
|
||||
void BandwidthMeter::setColorRGBA(unsigned c) {
|
||||
|
||||
glColor4ub(GLubyte( c >> 24),
|
||||
GLubyte((c >> 16) & 0xff),
|
||||
GLubyte((c >> 8) & 0xff),
|
||||
GLubyte( c & 0xff));
|
||||
}
|
||||
|
||||
void BandwidthMeter::renderBox(int x, int y, int w, int h) {
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2i(x, y);
|
||||
glVertex2i(x + w, y);
|
||||
glVertex2i(x + w, y + h);
|
||||
glVertex2i(x, y + h);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void BandwidthMeter::renderVerticalLine(int x, int y, int h) {
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex2i(x, y);
|
||||
glVertex2i(x, y + h);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
inline int BandwidthMeter::centered(int subject, int object) {
|
||||
return (object - subject) / 2;
|
||||
}
|
||||
|
||||
bool BandwidthMeter::isWithinArea(int x, int y, int screenWidth, int screenHeight) {
|
||||
|
||||
int minX = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH);
|
||||
int minY = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT);
|
||||
|
||||
return x >= minX && x < minX + glm::abs(AREA_WIDTH) &&
|
||||
y >= minY && y < minY + glm::abs(AREA_HEIGHT);
|
||||
}
|
||||
|
||||
void BandwidthMeter::render(int screenWidth, int screenHeight) {
|
||||
|
||||
int x = BORDER_DISTANCE_HORIZ + (AREA_WIDTH >= 0 ? 0 : screenWidth + AREA_WIDTH);
|
||||
int y = BORDER_DISTANCE_VERT + (AREA_HEIGHT >= 0 ? 0 : screenHeight + AREA_HEIGHT);
|
||||
int w = glm::abs(AREA_WIDTH), h = glm::abs(AREA_HEIGHT);
|
||||
|
||||
// Determine total
|
||||
float totalIn = 0.0f, totalOut = 0.0f;
|
||||
for (int i = 0; i < N_CHANNELS; ++i) {
|
||||
|
||||
totalIn += inputStream(ChannelIndex(i)).getValue();
|
||||
totalOut += outputStream(ChannelIndex(i)).getValue();
|
||||
}
|
||||
totalIn *= UNIT_SCALE;
|
||||
totalOut *= UNIT_SCALE;
|
||||
float totalMax = glm::max(totalIn, totalOut);
|
||||
|
||||
// Get font / caption metrics
|
||||
QFontMetrics const& fontMetrics = _textRenderer.metrics();
|
||||
int fontDescent = fontMetrics.descent();
|
||||
int labelWidthIn = fontMetrics.width(CAPTION_IN);
|
||||
int labelWidthOut = fontMetrics.width(CAPTION_OUT);
|
||||
int labelWidthInOut = glm::max(labelWidthIn, labelWidthOut);
|
||||
int labelHeight = fontMetrics.ascent() + fontDescent;
|
||||
int labelWidthUnit = fontMetrics.width(CAPTION_UNIT);
|
||||
int labelsWidth = labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT + SPACING_LEFT_CAPTION_UNIT + labelWidthUnit;
|
||||
|
||||
// Calculate coordinates and dimensions
|
||||
int barX = x + labelWidthInOut + SPACING_RIGHT_CAPTION_IN_OUT;
|
||||
int barWidth = w - labelsWidth;
|
||||
int barHeight = (h - SPACING_VERT_BARS) / 2;
|
||||
int textYcenteredLine = h - centered(labelHeight, h) - fontDescent;
|
||||
int textYupperLine = barHeight - centered(labelHeight, barHeight) - fontDescent;
|
||||
int textYlowerLine = h - centered(labelHeight, barHeight) - fontDescent;
|
||||
|
||||
// Center of coordinate system -> upper left of bar
|
||||
glPushMatrix();
|
||||
glTranslatef(float(barX), float(y), 0.0f);
|
||||
|
||||
// Render captions
|
||||
setColorRGBA(COLOR_TEXT);
|
||||
_textRenderer.draw(barWidth + SPACING_LEFT_CAPTION_UNIT, textYcenteredLine, CAPTION_UNIT);
|
||||
_textRenderer.draw(-labelWidthIn - SPACING_RIGHT_CAPTION_IN_OUT, textYupperLine, CAPTION_IN);
|
||||
_textRenderer.draw(-labelWidthOut - SPACING_RIGHT_CAPTION_IN_OUT, textYlowerLine, CAPTION_OUT);
|
||||
|
||||
// Render vertical lines for the frame
|
||||
setColorRGBA(COLOR_FRAME);
|
||||
renderVerticalLine(0, 0, h);
|
||||
renderVerticalLine(barWidth, 0, h);
|
||||
|
||||
// Adjust scale
|
||||
int steps;
|
||||
double step, scaleMax;
|
||||
bool commit = false;
|
||||
do {
|
||||
steps = (_scaleMaxIndex % 9) + 2;
|
||||
step = pow(10.0, (_scaleMaxIndex / 9) - 10);
|
||||
scaleMax = step * steps;
|
||||
if (commit) {
|
||||
// printLog("Bandwidth meter scale: %d\n", _scaleMaxIndex);
|
||||
break;
|
||||
}
|
||||
if (totalMax < scaleMax * 0.5) {
|
||||
_scaleMaxIndex = glm::max(0, _scaleMaxIndex-1);
|
||||
commit = true;
|
||||
} else if (totalMax > scaleMax) {
|
||||
_scaleMaxIndex += 1;
|
||||
commit = true;
|
||||
}
|
||||
} while (commit);
|
||||
|
||||
// Render scale indicators
|
||||
setColorRGBA(COLOR_INDICATOR);
|
||||
for (int j = int((scaleMax + step - 0.000001) / step); --j > 0;) {
|
||||
renderVerticalLine(int(barWidth * j * step / scaleMax), 0, h);
|
||||
}
|
||||
|
||||
// Render bars
|
||||
int xIn = 0, xOut = 0;
|
||||
for (int i = 0; i < N_CHANNELS; ++i) {
|
||||
|
||||
ChannelIndex chIdx = ChannelIndex(i);
|
||||
int wIn = int(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||
int wOut = int(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
|
||||
|
||||
setColorRGBA(channelInfo(chIdx).colorRGBA);
|
||||
|
||||
if (wIn > 0) {
|
||||
renderBox(xIn, 0, wIn, barHeight);
|
||||
}
|
||||
xIn += wIn;
|
||||
|
||||
if (wOut > 0) {
|
||||
renderBox(xOut, h - barHeight, wOut, barHeight);
|
||||
}
|
||||
xOut += wOut;
|
||||
}
|
||||
|
||||
// Render numbers
|
||||
char fmtBuf[8];
|
||||
setColorRGBA(COLOR_TEXT);
|
||||
sprintf(fmtBuf, "%0.2f", totalIn);
|
||||
_textRenderer.draw(glm::max(xIn - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE,
|
||||
PADDING_HORIZ_VALUE),
|
||||
textYupperLine, fmtBuf);
|
||||
sprintf(fmtBuf, "%0.2f", totalOut);
|
||||
_textRenderer.draw(glm::max(xOut - fontMetrics.width(fmtBuf) - PADDING_HORIZ_VALUE,
|
||||
PADDING_HORIZ_VALUE),
|
||||
textYlowerLine, fmtBuf);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
83
interface/src/BandwidthMeter.h
Normal file
83
interface/src/BandwidthMeter.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// BandwidthMeter.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/20/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__BandwidthMeter__
|
||||
#define __interface__BandwidthMeter__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "ui/TextRenderer.h"
|
||||
|
||||
|
||||
class BandwidthMeter {
|
||||
|
||||
public:
|
||||
|
||||
BandwidthMeter();
|
||||
~BandwidthMeter();
|
||||
|
||||
void render(int screenWidth, int screenHeight);
|
||||
bool isWithinArea(int x, int y, int screenWidth, int screenHeight);
|
||||
|
||||
// Number of channels / streams.
|
||||
static size_t const N_CHANNELS = 3;
|
||||
static size_t const N_STREAMS = N_CHANNELS * 2;
|
||||
|
||||
// Channel usage.
|
||||
enum ChannelIndex { AUDIO, AVATARS, VOXELS };
|
||||
|
||||
// Meta information held for a communication channel (bidirectional).
|
||||
struct ChannelInfo {
|
||||
|
||||
char const* const caption;
|
||||
char const* unitCaption;
|
||||
double unitScale;
|
||||
unsigned colorRGBA;
|
||||
};
|
||||
|
||||
// Representation of a data stream (unidirectional; input or output).
|
||||
class Stream {
|
||||
|
||||
public:
|
||||
|
||||
Stream(float msToAverage = 3000.0f);
|
||||
void updateValue(double amount);
|
||||
double getValue() const { return _value; }
|
||||
|
||||
private:
|
||||
double _value; // Current value.
|
||||
double _msToAverage; // Milliseconds to average.
|
||||
timeval _prevTime; // Time of last feed.
|
||||
};
|
||||
|
||||
// Data model accessors
|
||||
Stream& inputStream(ChannelIndex i) { return _streams[i * 2]; }
|
||||
Stream const& inputStream(ChannelIndex i) const { return _streams[i * 2]; }
|
||||
Stream& outputStream(ChannelIndex i) { return _streams[i * 2 + 1]; }
|
||||
Stream const& outputStream(ChannelIndex i) const { return _streams[i * 2 + 1]; }
|
||||
ChannelInfo& channelInfo(ChannelIndex i) { return _channels[i]; }
|
||||
ChannelInfo const& channelInfo(ChannelIndex i) const { return _channels[i]; }
|
||||
|
||||
private:
|
||||
static void setColorRGBA(unsigned c);
|
||||
static void renderBox(int x, int y, int w, int h);
|
||||
static void renderVerticalLine(int x, int y, int h);
|
||||
|
||||
static inline int centered(int subject, int object);
|
||||
|
||||
|
||||
static ChannelInfo _CHANNELS[];
|
||||
|
||||
TextRenderer _textRenderer;
|
||||
ChannelInfo* _channels;
|
||||
Stream _streams[N_STREAMS];
|
||||
int _scaleMaxIndex;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__BandwidthMeter__) */
|
||||
|
|
@ -25,6 +25,7 @@ const float CAMERA_MIRROR_MODE_UP_SHIFT = 0.0f;
|
|||
const float CAMERA_MIRROR_MODE_DISTANCE = 0.3f;
|
||||
const float CAMERA_MIRROR_MODE_TIGHTNESS = 100.0f;
|
||||
|
||||
|
||||
Camera::Camera() {
|
||||
|
||||
_needsToInitialize = true;
|
||||
|
@ -35,7 +36,7 @@ Camera::Camera() {
|
|||
_linearModeShift = 0.0f;
|
||||
_mode = CAMERA_MODE_THIRD_PERSON;
|
||||
_tightness = 10.0f; // default
|
||||
_fieldOfView = 60.0f; // default
|
||||
_fieldOfView = HORIZONTAL_FIELD_OF_VIEW_DEGREES;
|
||||
_nearClip = 0.08f; // default
|
||||
_farClip = 50.0f * TREE_SCALE; // default
|
||||
_upShift = 0.0f;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
const float HORIZONTAL_FIELD_OF_VIEW_DEGREES = 90.0f;
|
||||
|
||||
enum CameraMode
|
||||
{
|
||||
CAMERA_MODE_NULL = -1,
|
||||
|
|
|
@ -160,7 +160,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
setupNewVoxelsForDrawing();
|
||||
|
||||
pthread_mutex_unlock(&_treeLock);
|
||||
|
||||
|
||||
Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes);
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
|
|
72
interface/src/ui/BandwidthDialog.cpp
Normal file
72
interface/src/ui/BandwidthDialog.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
#include "ui/BandwidthDialog.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) :
|
||||
QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint),
|
||||
_model(model) {
|
||||
|
||||
char strBuf[64];
|
||||
|
||||
this->setWindowTitle("Bandwidth Details");
|
||||
|
||||
// Create layouter
|
||||
QFormLayout* form = new QFormLayout();
|
||||
this->QDialog::setLayout(form);
|
||||
|
||||
// Setup labels
|
||||
for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(BandwidthMeter::ChannelIndex(i / 2));
|
||||
QLabel* label = _labels[i] = new QLabel();
|
||||
label->setAlignment(Qt::AlignRight);
|
||||
|
||||
// Set foreground color to 62.5% brightness of the meter (otherwise will be hard to read on the bright background)
|
||||
QPalette palette = label->palette();
|
||||
unsigned rgb = ch.colorRGBA >> 8;
|
||||
rgb = ((rgb & 0xfefefeu) >> 1) + ((rgb & 0xf8f8f8) >> 3);
|
||||
palette.setColor(QPalette::WindowText, QColor::fromRgb(rgb));
|
||||
label->setPalette(palette);
|
||||
|
||||
snprintf(strBuf, sizeof(strBuf), " %s %s Bandwidth:", input ? "Input" : "Output", ch.caption);
|
||||
form->addRow(strBuf, label);
|
||||
}
|
||||
}
|
||||
|
||||
void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
||||
|
||||
// Update labels
|
||||
char strBuf[64];
|
||||
for (int i = 0; i < BandwidthMeter::N_STREAMS; ++i) {
|
||||
BandwidthMeter::ChannelIndex chIdx = BandwidthMeter::ChannelIndex(i / 2);
|
||||
bool input = i % 2 == 0;
|
||||
BandwidthMeter::ChannelInfo& ch = _model->channelInfo(chIdx);
|
||||
BandwidthMeter::Stream& s = input ? _model->inputStream(chIdx) : _model->outputStream(chIdx);
|
||||
QLabel* label = _labels[i];
|
||||
snprintf(strBuf, sizeof(strBuf), "%0.2f %s", s.getValue() * ch.unitScale, ch.unitCaption);
|
||||
label->setText(strBuf);
|
||||
}
|
||||
|
||||
this->QDialog::paintEvent(event);
|
||||
this->setFixedSize(this->width(), this->height());
|
||||
}
|
||||
|
||||
void BandwidthDialog::reject() {
|
||||
|
||||
// Just regularly close upon ESC
|
||||
this->QDialog::close();
|
||||
}
|
||||
|
||||
void BandwidthDialog::closeEvent(QCloseEvent* event) {
|
||||
|
||||
this->QDialog::closeEvent(event);
|
||||
emit closed();
|
||||
}
|
||||
|
47
interface/src/ui/BandwidthDialog.h
Normal file
47
interface/src/ui/BandwidthDialog.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// BandwidthDialog.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 6/21/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__BandwidthDialog__
|
||||
#define __hifi__BandwidthDialog__
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
|
||||
#include "BandwidthMeter.h"
|
||||
|
||||
|
||||
class BandwidthDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
// Sets up the UI based on the configuration of the BandwidthMeter
|
||||
BandwidthDialog(QWidget* parent, BandwidthMeter* model);
|
||||
|
||||
signals:
|
||||
|
||||
void closed();
|
||||
|
||||
public slots:
|
||||
|
||||
void reject();
|
||||
|
||||
protected:
|
||||
|
||||
// State <- data model held by BandwidthMeter
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
// Emits a 'closed' signal when this dialog is closed.
|
||||
void closeEvent(QCloseEvent*);
|
||||
|
||||
private:
|
||||
BandwidthMeter* _model;
|
||||
QLabel* _labels[BandwidthMeter::N_STREAMS];
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__BandwidthDialog__) */
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <UDPSocket.h>
|
||||
|
||||
|
|
|
@ -191,6 +191,18 @@ Agent* AgentList::agentWithID(uint16_t agentID) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int AgentList::getNumAliveAgents() const {
|
||||
int numAliveAgents = 0;
|
||||
|
||||
for (AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
if (agent->isAlive()) {
|
||||
++numAliveAgents;
|
||||
}
|
||||
}
|
||||
|
||||
return numAliveAgents;
|
||||
}
|
||||
|
||||
void AgentList::setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest) {
|
||||
delete _agentTypesOfInterest;
|
||||
|
||||
|
@ -350,14 +362,17 @@ void AgentList::addAgentToList(Agent* newAgent) {
|
|||
Agent::printLog(*newAgent);
|
||||
}
|
||||
|
||||
void AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
|
||||
unsigned AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes) {
|
||||
unsigned n = 0;
|
||||
for(AgentList::iterator agent = begin(); agent != end(); agent++) {
|
||||
// only send to the AgentTypes we are asked to send to.
|
||||
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
||||
// we know which socket is good for this agent, send there
|
||||
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void AgentList::handlePingReply(sockaddr *agentAddress) {
|
||||
|
|
|
@ -63,6 +63,7 @@ public:
|
|||
void(*linkedDataCreateCallback)(Agent *);
|
||||
|
||||
int size() { return _numAgents; }
|
||||
int getNumAliveAgents() const;
|
||||
|
||||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
|
@ -82,7 +83,7 @@ public:
|
|||
int updateAgentWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
||||
|
||||
void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
unsigned broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
|
||||
Agent* soloAgentOfType(char agentType);
|
||||
|
||||
|
|
|
@ -45,12 +45,12 @@ bool Logstash::shouldSendStats() {
|
|||
return shouldSendStats;
|
||||
}
|
||||
|
||||
void Logstash::stashValue(const char* key, float value) {
|
||||
void Logstash::stashValue(char statType, const char* key, float value) {
|
||||
static char logstashPacket[MAX_PACKET_SIZE];
|
||||
|
||||
// load up the logstash packet with the key and the passed float value
|
||||
// send it to 4 decimal places
|
||||
int numPacketBytes = sprintf(logstashPacket, "%s %.4f", key, value);
|
||||
int numPacketBytes = sprintf(logstashPacket, "%c %s %.4f", statType, key, value);
|
||||
|
||||
AgentList *agentList = AgentList::getInstance();
|
||||
|
||||
|
|
|
@ -14,11 +14,15 @@
|
|||
const int LOGSTASH_UDP_PORT = 9500;
|
||||
const char LOGSTASH_HOSTNAME[] = "graphite.highfidelity.io";
|
||||
|
||||
const char STAT_TYPE_TIMER = 't';
|
||||
const char STAT_TYPE_COUNTER = 'c';
|
||||
const char STAT_TYPE_GAUGE = 'g';
|
||||
|
||||
class Logstash {
|
||||
public:
|
||||
static sockaddr* socket();
|
||||
static bool shouldSendStats();
|
||||
static void stashValue(const char* key, float value);
|
||||
static void stashValue(char statType, const char* key, float value);
|
||||
private:
|
||||
static sockaddr_in logstashSocket;
|
||||
};
|
||||
|
|
239
libraries/voxels/src/SquarePixelMap.cpp
Normal file
239
libraries/voxels/src/SquarePixelMap.cpp
Normal file
|
@ -0,0 +1,239 @@
|
|||
//
|
||||
// SquarePixelMap.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Tomáš Horáček on 6/25/13.
|
||||
//
|
||||
//
|
||||
|
||||
#include "SquarePixelMap.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CHILD_COORD_X_IS_1 0x1
|
||||
#define CHILD_COORD_Y_IS_1 0x2
|
||||
#define ALPHA_CHANNEL_RANGE_FLOAT 256.f
|
||||
#define ALPHA_CHANNEL_BIT_OFFSET 24
|
||||
#define RED_CHANNEL_BIT_OFFSET 16
|
||||
#define GREEN_CHANNEL_BIT_OFFSET 8
|
||||
|
||||
unsigned int numberOfBitsForSize(unsigned int size) {
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size--;
|
||||
|
||||
unsigned int ans = 1;
|
||||
while (size >>= 1) {
|
||||
ans++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
struct PixelQuadTreeCoordinates {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
class PixelQuadTreeNode {
|
||||
public:
|
||||
PixelQuadTreeCoordinates _coord;
|
||||
uint32_t _color; // undefined value for _allChildrenHasSameColor = false
|
||||
bool _allChildrenHasSameColor;
|
||||
uint8_t _minimumNeighbourhoodAplha;
|
||||
|
||||
// 0 x -> 1
|
||||
// +---+---+
|
||||
// y | 0 | 1 | <- child index
|
||||
// | +---+---+
|
||||
// v | 2 | 3 |
|
||||
// +---+---+
|
||||
// 1
|
||||
PixelQuadTreeNode* _children[4];
|
||||
|
||||
PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap);
|
||||
~PixelQuadTreeNode() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
delete _children[i];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void updateChildCoordinates(int i, PixelQuadTreeCoordinates& childCoord) {
|
||||
childCoord.x = _coord.x;
|
||||
childCoord.y = _coord.y;
|
||||
|
||||
if (i & CHILD_COORD_X_IS_1) {
|
||||
childCoord.x += childCoord.size;
|
||||
}
|
||||
if (i & CHILD_COORD_Y_IS_1) {
|
||||
childCoord.y += childCoord.size;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasAllChildrenSameColor() {
|
||||
return false; //turn off import voxel grouping
|
||||
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (!_children[i]->_allChildrenHasSameColor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t firstColor = _children[0]->_color;
|
||||
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (firstColor != _children[i]->_color) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
PixelQuadTreeNode::PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap) : _coord(coord), _minimumNeighbourhoodAplha(-1) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
_children[i] = NULL;
|
||||
}
|
||||
|
||||
if (_coord.size == 1) {
|
||||
_color = pixelMap->getPixelAt(_coord.x, _coord.y);
|
||||
|
||||
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x + 1, _coord.y), _minimumNeighbourhoodAplha);
|
||||
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x - 1, _coord.y), _minimumNeighbourhoodAplha);
|
||||
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x, _coord.y + 1), _minimumNeighbourhoodAplha);
|
||||
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x, _coord.y - 1), _minimumNeighbourhoodAplha);
|
||||
|
||||
_allChildrenHasSameColor = true;
|
||||
} else {
|
||||
PixelQuadTreeCoordinates childCoord = PixelQuadTreeCoordinates();
|
||||
childCoord.size = _coord.size / 2;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
this->updateChildCoordinates(i, childCoord);
|
||||
|
||||
|
||||
if (childCoord.x < pixelMap->dimension() &&
|
||||
childCoord.y < pixelMap->dimension()) {
|
||||
|
||||
_children[i] = new PixelQuadTreeNode(childCoord, pixelMap);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->hasAllChildrenSameColor()) {
|
||||
_allChildrenHasSameColor = true;
|
||||
_color = _children[0]->_color;
|
||||
|
||||
_minimumNeighbourhoodAplha = _children[0]->_minimumNeighbourhoodAplha;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
_minimumNeighbourhoodAplha = std::min<uint8_t>(_children[i]->_minimumNeighbourhoodAplha, _minimumNeighbourhoodAplha);
|
||||
delete _children[i];
|
||||
_children[i] = NULL;
|
||||
}
|
||||
} else {
|
||||
_allChildrenHasSameColor = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SquarePixelMap::SquarePixelMap(const uint32_t* pixels, int dimension) : _rootPixelQuadTreeNode(NULL) {
|
||||
_data = new SquarePixelMapData();
|
||||
_data->dimension = dimension;
|
||||
_data->reference_counter = 1;
|
||||
|
||||
size_t pixels_size = dimension * dimension;
|
||||
_data->pixels = new uint32_t[pixels_size];
|
||||
memcpy((void*)_data->pixels, (void*)pixels, sizeof(uint32_t) * pixels_size);
|
||||
}
|
||||
|
||||
SquarePixelMap::SquarePixelMap(const SquarePixelMap& other) {
|
||||
this->_data = other._data;
|
||||
this->_data->reference_counter++;
|
||||
}
|
||||
|
||||
SquarePixelMap::~SquarePixelMap() {
|
||||
delete _rootPixelQuadTreeNode;
|
||||
|
||||
if (--_data->reference_counter == 0) {
|
||||
delete _data->pixels;
|
||||
delete _data;
|
||||
}
|
||||
}
|
||||
|
||||
void SquarePixelMap::addVoxelsToVoxelTree(VoxelTree* voxelTree) {
|
||||
this->generateRootPixelQuadTreeNode();
|
||||
this->createVoxelsFromPixelQuadTreeToVoxelTree(_rootPixelQuadTreeNode, voxelTree);
|
||||
}
|
||||
|
||||
int SquarePixelMap::dimension() {
|
||||
return _data->dimension;
|
||||
}
|
||||
|
||||
uint32_t SquarePixelMap::getPixelAt(unsigned int x, unsigned int y) {
|
||||
return _data->pixels[x + y * _data->dimension];
|
||||
}
|
||||
|
||||
uint8_t SquarePixelMap::getAlphaAt(int x, int y) {
|
||||
int max_coord = this->dimension() - 1;
|
||||
|
||||
if (x < 0 || y < 0 || x > max_coord || y > max_coord) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return this->getPixelAt(x, y) >> ALPHA_CHANNEL_BIT_OFFSET;
|
||||
}
|
||||
|
||||
void SquarePixelMap::generateRootPixelQuadTreeNode() {
|
||||
delete _rootPixelQuadTreeNode;
|
||||
|
||||
PixelQuadTreeCoordinates rootNodeCoord = PixelQuadTreeCoordinates();
|
||||
rootNodeCoord.size = 1 << numberOfBitsForSize(_data->dimension);
|
||||
rootNodeCoord.x = rootNodeCoord.y = 0;
|
||||
|
||||
_rootPixelQuadTreeNode = new PixelQuadTreeNode(rootNodeCoord, this);
|
||||
}
|
||||
|
||||
void SquarePixelMap::createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree) {
|
||||
if (pixelQuadTreeNode->_allChildrenHasSameColor) {
|
||||
VoxelDetail voxel = this->getVoxelDetail(pixelQuadTreeNode);
|
||||
|
||||
unsigned char minimumNeighbourhoodAplha = std::max<int>(0, pixelQuadTreeNode->_minimumNeighbourhoodAplha - 1);
|
||||
|
||||
float minimumNeighbourhoodY = voxel.s * (floor(minimumNeighbourhoodAplha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5);
|
||||
|
||||
do {
|
||||
voxelTree->createVoxel(voxel.x, voxel.y, voxel.z, voxel.s, voxel.red, voxel.green, voxel.blue, true);
|
||||
} while ((voxel.y -= voxel.s) > minimumNeighbourhoodY);
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
PixelQuadTreeNode* child = pixelQuadTreeNode->_children[i];
|
||||
if (child) {
|
||||
this->createVoxelsFromPixelQuadTreeToVoxelTree(child, voxelTree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelDetail SquarePixelMap::getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode) {
|
||||
VoxelDetail voxel = VoxelDetail();
|
||||
|
||||
uint32_t color = pixelQuadTreeNode->_color;
|
||||
unsigned char alpha = std::max<int>(0, (color >> ALPHA_CHANNEL_BIT_OFFSET) - 1);
|
||||
|
||||
voxel.red = color >> RED_CHANNEL_BIT_OFFSET;
|
||||
voxel.green = color >> GREEN_CHANNEL_BIT_OFFSET;
|
||||
voxel.blue = color;
|
||||
|
||||
|
||||
float rootSize = _rootPixelQuadTreeNode->_coord.size;
|
||||
|
||||
voxel.s = pixelQuadTreeNode->_coord.size / rootSize;
|
||||
voxel.y = voxel.s * (floor(alpha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5);
|
||||
voxel.x = pixelQuadTreeNode->_coord.x / rootSize + voxel.s / 2;
|
||||
voxel.z = pixelQuadTreeNode->_coord.y / rootSize + voxel.s / 2;
|
||||
|
||||
return voxel;
|
||||
}
|
44
libraries/voxels/src/SquarePixelMap.h
Normal file
44
libraries/voxels/src/SquarePixelMap.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// SquarePixelMap.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Tomáš Horáček on 6/25/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__SquarePixelMap__
|
||||
#define __hifi__SquarePixelMap__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "VoxelTree.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
class PixelQuadTreeNode;
|
||||
|
||||
struct SquarePixelMapData {
|
||||
const uint32_t* pixels;
|
||||
int dimension;
|
||||
int reference_counter;
|
||||
};
|
||||
|
||||
class SquarePixelMap {
|
||||
public:
|
||||
SquarePixelMap(const uint32_t* pixels, int dimension);
|
||||
SquarePixelMap(const SquarePixelMap& other);
|
||||
~SquarePixelMap();
|
||||
|
||||
void addVoxelsToVoxelTree(VoxelTree* voxelTree);
|
||||
|
||||
int dimension();
|
||||
uint32_t getPixelAt(unsigned int x, unsigned int y);
|
||||
uint8_t getAlphaAt(int x, int y);
|
||||
private:
|
||||
SquarePixelMapData* _data;
|
||||
PixelQuadTreeNode* _rootPixelQuadTreeNode;
|
||||
|
||||
void generateRootPixelQuadTreeNode();
|
||||
void createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree);
|
||||
VoxelDetail getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode);
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__SquarePixelMap__) */
|
|
@ -23,6 +23,8 @@
|
|||
#include <fstream> // to load voxels from file
|
||||
#include "VoxelConstants.h"
|
||||
#include "CoverageMap.h"
|
||||
#include "SquarePixelMap.h"
|
||||
|
||||
|
||||
#include <glm/gtc/noise.hpp>
|
||||
|
||||
|
@ -1447,6 +1449,12 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool VoxelTree::readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension) {
|
||||
SquarePixelMap pixelMap = SquarePixelMap(pixels, dimension);
|
||||
pixelMap.addVoxelsToVoxelTree(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const {
|
||||
|
||||
std::ofstream file(fileName, std::ios::out|std::ios::binary);
|
||||
|
|
|
@ -133,6 +133,8 @@ public:
|
|||
// these will read/write files that match the wireformat, excluding the 'V' leading
|
||||
void writeToSVOFile(const char* filename, VoxelNode* node = NULL) const;
|
||||
bool readFromSVOFile(const char* filename);
|
||||
// reads voxels from square image with alpha as a Y-axis
|
||||
bool readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension);
|
||||
|
||||
unsigned long getVoxelCount();
|
||||
|
||||
|
|
Loading…
Reference in a new issue