mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-17 23:26:50 +02:00
merge
This commit is contained in:
parent
6e69c4fbbb
commit
7693165578
51 changed files with 849 additions and 254 deletions
|
@ -10,6 +10,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_subdirectory(animation-server)
|
||||
add_subdirectory(assignment-server)
|
||||
add_subdirectory(avatar-mixer)
|
||||
add_subdirectory(audio-mixer)
|
||||
add_subdirectory(domain-server)
|
||||
|
|
13
assignment-server/CMakeLists.txt
Normal file
13
assignment-server/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(TARGET_NAME assignment-server)
|
||||
|
||||
set(ROOT_DIR ..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
# link in the shared library
|
||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
57
assignment-server/src/main.cpp
Normal file
57
assignment-server/src/main.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// main.cpp
|
||||
// assignment-server
|
||||
//
|
||||
// Created by Stephen Birarda on 7/1/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <UDPSocket.h>
|
||||
|
||||
const int MAX_PACKET_SIZE_BYTES = 1400;
|
||||
|
||||
struct Assignment {};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
||||
std::queue<Assignment> assignmentQueue;
|
||||
|
||||
sockaddr_in senderSocket;
|
||||
unsigned char senderData[MAX_PACKET_SIZE_BYTES] = {};
|
||||
ssize_t receivedBytes = 0;
|
||||
|
||||
UDPSocket serverSocket(ASSIGNMENT_SERVER_PORT);
|
||||
|
||||
int numHeaderBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_SEND_ASSIGNMENT);
|
||||
unsigned char assignmentPacket[numHeaderBytes + sizeof(char)];
|
||||
populateTypeAndVersion(assignmentPacket, PACKET_TYPE_SEND_ASSIGNMENT);
|
||||
|
||||
while (true) {
|
||||
if (serverSocket.receive((sockaddr*) &senderSocket, &senderData, &receivedBytes)) {
|
||||
|
||||
// int numHeaderBytes = numBytesForPacketHeader(senderData);
|
||||
|
||||
if (senderData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
||||
// grab the FI assignment in the queue, if it exists
|
||||
if (assignmentQueue.size() > 0) {
|
||||
// Assignment firstAssignment = assignmentQueue.front();
|
||||
assignmentQueue.pop();
|
||||
|
||||
// send the assignment
|
||||
serverSocket.send((sockaddr*) &senderSocket, assignmentPacket, sizeof(assignmentPacket));
|
||||
}
|
||||
} else if (senderData[0] == PACKET_TYPE_SEND_ASSIGNMENT) {
|
||||
Assignment newAssignment;
|
||||
|
||||
// add this assignment to the queue
|
||||
assignmentQueue.push(newAssignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -375,7 +375,7 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) node->getLinkedData();
|
||||
if (memcmp(ringBuffer->getStreamIdentifier(),
|
||||
packetData + 1,
|
||||
packetData + numBytesForPacketHeader(packetData),
|
||||
STREAM_IDENTIFIER_NUM_BYTES) == 0) {
|
||||
// this is the matching stream, assign to matchingInjector and stop looking
|
||||
matchingInjector = &*node;
|
||||
|
|
|
@ -18,4 +18,4 @@ include_glm(${TARGET_NAME} ${ROOT_DIR})
|
|||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||
|
|
15
hifi.podspec
15
hifi.podspec
|
@ -35,17 +35,24 @@ Pod::Spec.new do |s|
|
|||
# s.exclude_files = 'Classes/Exclude'
|
||||
|
||||
s.subspec "shared" do |sp|
|
||||
sp.source_files = "libraries/shared/src"
|
||||
sp.public_header_files = "librares/shared/src"
|
||||
sp.source_files = 'libraries/shared/src', 'libraries/shared/moc_*'
|
||||
sp.exclude_files = "libraries/shared/src/UrlReader.*"
|
||||
sp.dependency 'glm'
|
||||
sp.xcconfig = { 'CLANG_CXX_LIBRARY' => "libc++" }
|
||||
end
|
||||
|
||||
s.subspec "audio" do |sp|
|
||||
sp.source_files = "libraries/audio/src"
|
||||
sp.public_header_files = "libraries/audio/src"
|
||||
sp.xcconfig = { 'CLANG_CXX_LIBRARY' => "libc++" }
|
||||
sp.dependency 'glm'
|
||||
end
|
||||
|
||||
s.subspec "avatars" do |sp|
|
||||
sp.source_files = 'libraries/avatars/src', 'libraries/avatars/moc_*'
|
||||
sp.dependency 'glm'
|
||||
end
|
||||
|
||||
s.xcconfig = { 'HEADER_SEARCH_PATHS' => '${PODS_ROOT}/../../qt5-device/qtbase/include' }
|
||||
s.libraries = 'libQtCoreCombined', 'libQt5Network', 'libQt5Script'
|
||||
|
||||
# A list of file patterns which select the header files that should be
|
||||
# made available to the application. If the pattern is a directory then the
|
||||
|
|
|
@ -570,8 +570,9 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
if (_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()) {
|
||||
_myAvatar.getHand().setRaveGloveEffectsMode((QKeyEvent*)event);
|
||||
}
|
||||
|
||||
bool shifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
|
||||
bool isMeta = event->modifiers().testFlag(Qt::MetaModifier);
|
||||
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
switch (event->key()) {
|
||||
case Qt::Key_BracketLeft:
|
||||
_viewFrustumOffsetYaw -= 0.5;
|
||||
|
@ -644,7 +645,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_C:
|
||||
_myAvatar.setDriveKeys(DOWN, 1);
|
||||
if (isShifted) {
|
||||
_occlusionCulling->trigger();
|
||||
} else if (isMeta) {
|
||||
chooseVoxelPaintColor();
|
||||
} else {
|
||||
_myAvatar.setDriveKeys(DOWN, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_W:
|
||||
|
@ -652,7 +659,11 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_S:
|
||||
_myAvatar.setDriveKeys(BACK, 1);
|
||||
if (isShifted) {
|
||||
doTreeStats();
|
||||
} else {
|
||||
_myAvatar.setDriveKeys(BACK, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Space:
|
||||
|
@ -661,11 +672,19 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_G:
|
||||
goHome();
|
||||
if (isShifted) {
|
||||
_gravityUse->trigger();
|
||||
} else {
|
||||
_eyedropperMode->trigger();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_A:
|
||||
_myAvatar.setDriveKeys(ROT_LEFT, 1);
|
||||
if (isShifted) {
|
||||
_renderAtmosphereOn->trigger();
|
||||
} else {
|
||||
_myAvatar.setDriveKeys(ROT_LEFT, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_D:
|
||||
|
@ -681,23 +700,23 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
_myAvatar.setDriveKeys(shifted ? UP : FWD, 1);
|
||||
_myAvatar.setDriveKeys(isShifted ? UP : FWD, 1);
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
_myAvatar.setDriveKeys(shifted ? DOWN : BACK, 1);
|
||||
_myAvatar.setDriveKeys(isShifted ? DOWN : BACK, 1);
|
||||
break;
|
||||
|
||||
case Qt::Key_Left:
|
||||
_myAvatar.setDriveKeys(shifted ? LEFT : ROT_LEFT, 1);
|
||||
_myAvatar.setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1);
|
||||
break;
|
||||
|
||||
case Qt::Key_Right:
|
||||
_myAvatar.setDriveKeys(shifted ? RIGHT : ROT_RIGHT, 1);
|
||||
_myAvatar.setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1);
|
||||
break;
|
||||
|
||||
case Qt::Key_I:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -707,7 +726,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_K:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(-0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -717,7 +736,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_J:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, 0.002f, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -727,7 +746,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_M:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, -0.002f, 0)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -737,7 +756,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_U:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, 0, -0.002f)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -747,7 +766,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_Y:
|
||||
if (shifted) {
|
||||
if (isShifted) {
|
||||
_myCamera.setEyeOffsetOrientation(glm::normalize(
|
||||
glm::quat(glm::vec3(0, 0, 0.002f)) * _myCamera.getEyeOffsetOrientation()));
|
||||
} else {
|
||||
|
@ -755,12 +774,62 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
resizeGL(_glWidget->width(), _glWidget->height());
|
||||
break;
|
||||
case Qt::Key_N:
|
||||
_noise->trigger();
|
||||
break;
|
||||
case Qt::Key_H:
|
||||
_lookingInMirror->trigger();
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
if (isShifted) {
|
||||
_frustumOn->trigger();
|
||||
} else {
|
||||
_fullScreenMode->trigger();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_V:
|
||||
if (isShifted) {
|
||||
_renderVoxels->trigger();
|
||||
} else {
|
||||
_addVoxelMode->trigger();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_P:
|
||||
_manualFirstPerson->trigger();
|
||||
break;
|
||||
case Qt::Key_R:
|
||||
if (isShifted) {
|
||||
_frustumRenderModeAction->trigger();
|
||||
} else {
|
||||
_deleteVoxelMode->trigger();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_B:
|
||||
_colorVoxelMode->trigger();
|
||||
break;
|
||||
case Qt::Key_O:
|
||||
if (isShifted) {
|
||||
_viewFrustumFromOffset->trigger();
|
||||
} else {
|
||||
_selectVoxelMode->trigger();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Slash:
|
||||
_renderStatsOn->trigger();
|
||||
break;
|
||||
case Qt::Key_Backspace:
|
||||
case Qt::Key_Delete:
|
||||
if (_selectVoxelMode->isChecked()) {
|
||||
deleteVoxelUnderCursor();
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Plus:
|
||||
increaseAvatarSize();
|
||||
break;
|
||||
case Qt::Key_Minus:
|
||||
decreaseAvatarSize();
|
||||
break;
|
||||
|
||||
case Qt::Key_1:
|
||||
case Qt::Key_2:
|
||||
case Qt::Key_3:
|
||||
|
@ -859,7 +928,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
|||
|
||||
const bool MAKE_SOUND_ON_VOXEL_HOVER = false;
|
||||
const bool MAKE_SOUND_ON_VOXEL_CLICK = true;
|
||||
const float HOVER_VOXEL_FREQUENCY = 14080.f;
|
||||
const float HOVER_VOXEL_FREQUENCY = 7040.f;
|
||||
const float HOVER_VOXEL_DECAY = 0.999f;
|
||||
|
||||
void Application::mousePressEvent(QMouseEvent* event) {
|
||||
|
@ -872,8 +941,9 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
|||
_mouseVoxelDragging = _mouseVoxel;
|
||||
_mousePressed = true;
|
||||
|
||||
maybeEditVoxelUnderCursor();
|
||||
|
||||
if (!maybeEditVoxelUnderCursor()) {
|
||||
if (!_palette.isActive()) {
|
||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||
}
|
||||
|
||||
|
@ -1617,14 +1687,25 @@ void Application::importVoxels() {
|
|||
const int SVO_TYPE_NAME_LENGTH = 4;
|
||||
const int SCH_TYPE_NAME_LENGTH = 10;
|
||||
|
||||
// assume this is where we'll place it if filename doesn't have tiling
|
||||
int unspecifiedColumnNum = 1;
|
||||
int unspecifiedRowNum = 1;
|
||||
|
||||
// if they select multiple files, but they don't specify the tiling, we
|
||||
// will tile them to this size
|
||||
int unspecifiedSquare = (sqrt(fileNameStringList.size()) + 0.5);
|
||||
qDebug("unspecifiedSquare: %d\n", unspecifiedSquare);
|
||||
|
||||
for (int i = 0; i < fileNameStringList.size(); i++) {
|
||||
QString fileNameString = fileNameStringList.at(i);
|
||||
QString extension;
|
||||
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
|
||||
const char* fileName = fileNameAscii.data();
|
||||
|
||||
int fileTypeNameLength = 0;
|
||||
VoxelTree importVoxels;
|
||||
if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) {
|
||||
extension = QString(".png");
|
||||
QImage pngImage = QImage(fileName);
|
||||
fileTypeNameLength = PNG_TYPE_NAME_LENGTH;
|
||||
if (pngImage.height() != pngImage.width()) {
|
||||
|
@ -1642,25 +1723,67 @@ void Application::importVoxels() {
|
|||
|
||||
importVoxels.readFromSquareARGB32Pixels(pixels, pngImage.height());
|
||||
} else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) {
|
||||
extension = QString(".svo");
|
||||
importVoxels.readFromSVOFile(fileName);
|
||||
fileTypeNameLength = SVO_TYPE_NAME_LENGTH;
|
||||
} else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) {
|
||||
extension = QString(".schematic");
|
||||
importVoxels.readFromSchematicFile(fileName);
|
||||
fileTypeNameLength = SCH_TYPE_NAME_LENGTH;
|
||||
}
|
||||
|
||||
// Where we plan to place this
|
||||
int columnNum = 1;
|
||||
int rowNum = 1;
|
||||
bool isTileLocationUnspecified = false;
|
||||
|
||||
int indexOfFirstPeriod = fileNameString.indexOf('.');
|
||||
// If we're in multi-file mode, then look for tiling specification in the file name
|
||||
if (fileNameStringList.size() > 1) {
|
||||
int indexOfFirstPeriod = fileNameString.indexOf('.');
|
||||
|
||||
QString fileCoord = fileNameString.mid(indexOfFirstPeriod + 1,
|
||||
fileNameString.length() - indexOfFirstPeriod - fileTypeNameLength - 1);
|
||||
//qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod);
|
||||
|
||||
indexOfFirstPeriod = fileCoord.indexOf('.');
|
||||
QString columnNumString = fileCoord.right(fileCoord.length() - indexOfFirstPeriod - 1);
|
||||
QString rowNumString = fileCoord.left(indexOfFirstPeriod);
|
||||
// If the first period, is the extension, then this is not a grid name;
|
||||
if (fileNameString.mid(indexOfFirstPeriod, fileNameString.length() - indexOfFirstPeriod) == extension) {
|
||||
qDebug("not a valid grid name... treat like tile Location Unspecified\n");
|
||||
isTileLocationUnspecified = true;
|
||||
} else {
|
||||
QString fileCoord = fileNameString.mid(indexOfFirstPeriod + 1,
|
||||
fileNameString.length() - indexOfFirstPeriod - fileTypeNameLength - 1);
|
||||
|
||||
int columnNum = columnNumString.toFloat();
|
||||
int rowNum = rowNumString.toFloat();
|
||||
//qDebug() << "fileCoord: " << fileCoord << "\n";
|
||||
indexOfFirstPeriod = fileCoord.indexOf('.');
|
||||
|
||||
//qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod);
|
||||
|
||||
QString columnNumString = fileCoord.right(fileCoord.length() - indexOfFirstPeriod - 1);
|
||||
QString rowNumString = fileCoord.left(indexOfFirstPeriod);
|
||||
|
||||
//qDebug() << "columnNumString: " << columnNumString << "\n";
|
||||
//qDebug() << "rowNumString: " << rowNumString << "\n";
|
||||
|
||||
columnNum = columnNumString.toFloat();
|
||||
rowNum = rowNumString.toFloat();
|
||||
|
||||
// If there are no "grid sections" in the filename, then we're going to get
|
||||
if (columnNum < 1 || rowNum < 1) {
|
||||
qDebug("not a valid grid name... treat like tile Location Unspecified\n");
|
||||
isTileLocationUnspecified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isTileLocationUnspecified) {
|
||||
qDebug("tile Location is Unspecified... \n");
|
||||
columnNum = unspecifiedColumnNum;
|
||||
rowNum = unspecifiedRowNum;
|
||||
|
||||
unspecifiedColumnNum++;
|
||||
if (unspecifiedColumnNum > unspecifiedSquare) {
|
||||
unspecifiedColumnNum = 1;
|
||||
unspecifiedRowNum++;
|
||||
}
|
||||
}
|
||||
qDebug("columnNum: %d\t rowNum: %d\n", columnNum, rowNum);
|
||||
|
||||
_mouseVoxel.x = originalX + (columnNum - 1) * _mouseVoxel.s;
|
||||
|
@ -1791,19 +1914,21 @@ void Application::initMenu() {
|
|||
_window->setMenuBar(menuBar);
|
||||
|
||||
QMenu* fileMenu = menuBar->addMenu("File");
|
||||
fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q);
|
||||
QAction* quitAction = fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q);
|
||||
quitAction->setMenuRole(QAction::QuitRole);
|
||||
|
||||
QMenu* editMenu = menuBar->addMenu("Edit");
|
||||
editMenu->addAction("Preferences...", this, SLOT(editPreferences()));
|
||||
QAction* preferencesAction = editMenu->addAction("Preferences...", this, SLOT(editPreferences()), Qt::CTRL | Qt::Key_Comma);
|
||||
preferencesAction->setMenuRole(QAction::PreferencesRole);
|
||||
|
||||
QMenu* pairMenu = menuBar->addMenu("Pair");
|
||||
pairMenu->addAction("Pair", this, SLOT(pair()));
|
||||
|
||||
QMenu* optionsMenu = menuBar->addMenu("Options");
|
||||
(_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setRenderMirrored(bool)), Qt::Key_H))->setCheckable(true);
|
||||
(_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true);
|
||||
|
||||
optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N)->setCheckable(true);
|
||||
|
||||
(_noise = optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N))->setCheckable(true);
|
||||
(_gyroLook = optionsMenu->addAction("Smooth Gyro Look"))->setCheckable(true);
|
||||
_gyroLook->setChecked(true);
|
||||
(_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true);
|
||||
|
@ -1819,7 +1944,11 @@ void Application::initMenu() {
|
|||
optionsMenu->addAction("Webcam", &_webcam, SLOT(setEnabled(bool)))->setCheckable(true);
|
||||
optionsMenu->addAction("Toggle Skeleton Tracking", &_webcam, SLOT(setSkeletonTrackingOn(bool)))->setCheckable(true);
|
||||
optionsMenu->addAction("Cycle Webcam Send Mode", _webcam.getGrabber(), SLOT(cycleVideoSendMode()));
|
||||
optionsMenu->addAction("Go Home", this, SLOT(goHome()));
|
||||
optionsMenu->addAction("Go Home", this, SLOT(goHome()), Qt::CTRL | Qt::Key_G);
|
||||
|
||||
QMenu* audioMenu = menuBar->addMenu("Audio");
|
||||
(_echoAudioMode = audioMenu->addAction("Echo Audio"))->setCheckable(true);
|
||||
_rawAudioMicrophoneMix = audioMenu->addAction("Mix RAW Song", this, SLOT(toggleMixedSong()));
|
||||
|
||||
QMenu* renderMenu = menuBar->addMenu("Render");
|
||||
(_renderVoxels = renderMenu->addAction("Voxels", this, SLOT(setRenderVoxels(bool)), Qt::SHIFT | Qt::Key_V))->setCheckable(true);
|
||||
|
@ -1850,8 +1979,8 @@ void Application::initMenu() {
|
|||
"First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true);
|
||||
(_manualThirdPerson = renderMenu->addAction(
|
||||
"Third Person", this, SLOT(setRenderThirdPerson(bool))))->setCheckable(true);
|
||||
renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::ALT | Qt::Key_Plus);
|
||||
renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::ALT | Qt::Key_Minus);
|
||||
renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::Key_Plus);
|
||||
renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::Key_Minus);
|
||||
|
||||
|
||||
QMenu* toolsMenu = menuBar->addMenu("Tools");
|
||||
|
@ -1888,8 +2017,8 @@ void Application::initMenu() {
|
|||
"Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_G))->setCheckable(true);
|
||||
_voxelModeActions->addAction(_eyedropperMode);
|
||||
|
||||
voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut);
|
||||
voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn);
|
||||
voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut);
|
||||
voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn);
|
||||
voxelMenu->addAction("Reset Swatch Colors", this, SLOT(resetSwatchColors()));
|
||||
|
||||
_voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this,
|
||||
|
@ -1916,7 +2045,7 @@ void Application::initMenu() {
|
|||
(_viewFrustumFromOffset = frustumMenu->addAction(
|
||||
"Use Offset Camera", this, SLOT(setFrustumOffset(bool)), Qt::SHIFT | Qt::Key_O))->setCheckable(true);
|
||||
_frustumRenderModeAction = frustumMenu->addAction(
|
||||
"Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R);
|
||||
"Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R);
|
||||
updateFrustumRenderModeAction();
|
||||
|
||||
debugMenu->addAction("Run Timing Tests", this, SLOT(runTests()));
|
||||
|
@ -1940,8 +2069,8 @@ void Application::initMenu() {
|
|||
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
|
||||
debugMenu->addAction("Use Lower Resolution While Moving", this, SLOT(setWantsLowResMoving(bool)))->setCheckable(true);
|
||||
debugMenu->addAction("Disable Delta Sending", this, SLOT(disableDeltaSending(bool)))->setCheckable(true);
|
||||
debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)),
|
||||
Qt::SHIFT | Qt::Key_C)->setCheckable(true);
|
||||
(_occlusionCulling = debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)),
|
||||
Qt::SHIFT | Qt::Key_C))->setCheckable(true);
|
||||
|
||||
(_renderCoverageMap = debugMenu->addAction("Render Coverage Map"))->setCheckable(true);
|
||||
_renderCoverageMap->setShortcut(Qt::SHIFT | Qt::CTRL | Qt::Key_O);
|
||||
|
@ -1990,6 +2119,22 @@ void Application::setListenModeSingleSource() {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::toggleMixedSong() {
|
||||
if (_audio.getSongFileBytes() == 0) {
|
||||
QString filename = QFileDialog::getOpenFileName(_glWidget,
|
||||
tr("Choose RAW Audio file"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
|
||||
tr("RAW Audio file (*.raw)"));
|
||||
|
||||
QByteArray filenameArray = filename.toLocal8Bit();
|
||||
_audio.importSongToMixWithMicrophone(filenameArray.data());
|
||||
_rawAudioMicrophoneMix->setText("Stop Mixing Song");
|
||||
} else {
|
||||
_audio.stopMixingSongWithMicrophone();
|
||||
_rawAudioMicrophoneMix->setText("Mix RAW Song");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Application::updateFrustumRenderModeAction() {
|
||||
switch (_frustumDrawingMode) {
|
||||
|
@ -2100,7 +2245,7 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3
|
|||
Avatar* avatar = (Avatar *) node->getLinkedData();
|
||||
glm::vec3 headPosition = avatar->getHead().getPosition();
|
||||
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS)) {
|
||||
eyePosition = avatar->getHead().getEyeLevelPosition();
|
||||
eyePosition = avatar->getHead().getEyePosition();
|
||||
_lookatIndicatorScale = avatar->getScale();
|
||||
_lookatOtherPosition = headPosition;
|
||||
nodeID = avatar->getOwningNode()->getNodeID();
|
||||
|
@ -2149,21 +2294,21 @@ void Application::update(float deltaTime) {
|
|||
_myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||
|
||||
// Set where I am looking based on my mouse ray (so that other people can see)
|
||||
glm::vec3 eyePosition;
|
||||
glm::vec3 lookAtSpot;
|
||||
|
||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePosition);
|
||||
_isLookingAtOtherAvatar = isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
|
||||
if (_isLookingAtOtherAvatar) {
|
||||
// If the mouse is over another avatar's head...
|
||||
glm::vec3 myLookAtFromMouse(eyePosition);
|
||||
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
||||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||
} else if (_isHoverVoxel) {
|
||||
// Look at the hovered voxel
|
||||
glm::vec3 lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
||||
lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
||||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||
} else {
|
||||
// Just look in direction of the mouse ray
|
||||
glm::vec3 myLookAtFromMouse(mouseRayOrigin + mouseRayDirection);
|
||||
_myAvatar.getHead().setLookAtPosition(myLookAtFromMouse);
|
||||
const float FAR_AWAY_STARE = TREE_SCALE;
|
||||
lookAtSpot = mouseRayOrigin + mouseRayDirection * FAR_AWAY_STARE;
|
||||
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
|
||||
}
|
||||
|
||||
// Find the voxel we are hovering over, and respond if clicked
|
||||
|
@ -2173,15 +2318,21 @@ void Application::update(float deltaTime) {
|
|||
// If we have clicked on a voxel, update it's color
|
||||
if (_isHoverVoxelSounding) {
|
||||
VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||
float bright = _audio.getCollisionSoundMagnitude();
|
||||
nodeColor clickColor = { 255 * bright + _hoverVoxelOriginalColor[0] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[1] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[2] * (1.f - bright), 1 };
|
||||
hoveredNode->setColor(clickColor);
|
||||
if (bright < 0.01f) {
|
||||
hoveredNode->setColor(_hoverVoxelOriginalColor);
|
||||
if (hoveredNode) {
|
||||
float bright = _audio.getCollisionSoundMagnitude();
|
||||
nodeColor clickColor = { 255 * bright + _hoverVoxelOriginalColor[0] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[1] * (1.f - bright),
|
||||
_hoverVoxelOriginalColor[2] * (1.f - bright), 1 };
|
||||
hoveredNode->setColor(clickColor);
|
||||
if (bright < 0.01f) {
|
||||
hoveredNode->setColor(_hoverVoxelOriginalColor);
|
||||
_isHoverVoxelSounding = false;
|
||||
}
|
||||
} else {
|
||||
// Voxel is not found, clear all
|
||||
_isHoverVoxelSounding = false;
|
||||
}
|
||||
_isHoverVoxel = false;
|
||||
}
|
||||
} else {
|
||||
// Check for a new hover voxel
|
||||
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||
|
@ -2732,7 +2883,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z);
|
||||
|
||||
glTranslatef(-whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z);
|
||||
|
||||
|
||||
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
|
||||
|
@ -2849,6 +3000,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
_myAvatar.getHead().setLookAtPosition(_myCamera.getPosition());
|
||||
}
|
||||
_myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked());
|
||||
_myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
||||
|
||||
if (_renderLookatIndicatorOn->isChecked() && _isLookingAtOtherAvatar) {
|
||||
renderLookatIndicator(_lookatOtherPosition, whichCamera);
|
||||
|
@ -2862,7 +3014,7 @@ void Application::displaySide(Camera& whichCamera) {
|
|||
}
|
||||
|
||||
// Render the world box
|
||||
if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { render_world_box(); }
|
||||
if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { renderWorldBox(); }
|
||||
|
||||
// brad's frustum for debugging
|
||||
if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum);
|
||||
|
|
|
@ -177,6 +177,7 @@ private slots:
|
|||
void setListenModeNormal();
|
||||
void setListenModePoint();
|
||||
void setListenModeSingleSource();
|
||||
void toggleMixedSong();
|
||||
|
||||
|
||||
void renderCoverageMap();
|
||||
|
@ -288,6 +289,9 @@ private:
|
|||
QAction* _fullScreenMode; // whether we are in full screen mode
|
||||
QAction* _frustumRenderModeAction;
|
||||
QAction* _settingsAutosave; // Whether settings are saved automatically
|
||||
QAction* _rawAudioMicrophoneMix; // Mixing of a RAW audio file with microphone stream for rave gloves
|
||||
QAction* _noise;
|
||||
QAction* _occlusionCulling;
|
||||
|
||||
QAction* _renderCoverageMapV2;
|
||||
QAction* _renderCoverageMap;
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
#ifndef _WIN32
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#include <AngleUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <NodeTypes.h>
|
||||
|
@ -155,8 +153,38 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
|||
memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation));
|
||||
currentPacketPtr += sizeof(headOrientation);
|
||||
|
||||
// check if we have a song to add to our audio
|
||||
if (_songFileBytes > 0 && _songFileStream->tellg() <= _songFileBytes) {
|
||||
// iterate over BUFFER_LENGTH_SAMPLES_PER_CHANNEL from the song file and add that to our audio
|
||||
for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||
int16_t songSample = 0;
|
||||
|
||||
_songFileStream->read((char*) &songSample, sizeof(songSample));
|
||||
|
||||
// attenuate the song samples since they will be loud
|
||||
const float SONG_SAMPLE_ATTENUATION = 0.25;
|
||||
songSample *= SONG_SAMPLE_ATTENUATION;
|
||||
|
||||
// add the song sample to the output and input buffersg
|
||||
inputLeft[i] = inputLeft[i] + songSample;
|
||||
outputLeft[i] = outputLeft[i] + songSample;
|
||||
outputRight[i] = outputLeft[i] + songSample;
|
||||
}
|
||||
} else if (_songFileStream) {
|
||||
// close the stream
|
||||
_songFileStream->close();
|
||||
|
||||
// delete the _songFileStream
|
||||
delete _songFileStream;
|
||||
_songFileStream = NULL;
|
||||
|
||||
// reset the _songFileBytes back to zero
|
||||
_songFileBytes = 0;
|
||||
}
|
||||
|
||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||
|
||||
nodeList->getNodeSocket()->send((sockaddr*) &audioSocket,
|
||||
dataPacket,
|
||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||
|
@ -384,6 +412,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
|||
_collisionSoundDuration(0.0f),
|
||||
_proceduralEffectSample(0),
|
||||
_heartbeatMagnitude(0.0f),
|
||||
_songFileStream(NULL),
|
||||
_songFileBytes(0),
|
||||
_listenMode(AudioRingBuffer::NORMAL),
|
||||
_listenRadius(0.0f)
|
||||
{
|
||||
|
@ -456,6 +486,25 @@ Audio::~Audio() {
|
|||
delete[] _echoSamplesLeft;
|
||||
}
|
||||
|
||||
|
||||
void Audio::importSongToMixWithMicrophone(const char* filename) {
|
||||
_songFileStream = new std::ifstream(filename);
|
||||
|
||||
long begin = _songFileStream->tellg();
|
||||
_songFileStream->seekg(0, std::ios::end);
|
||||
long end = _songFileStream->tellg();
|
||||
|
||||
// go back to the beginning
|
||||
_songFileStream->seekg(0);
|
||||
|
||||
_songFileBytes = end - begin;
|
||||
}
|
||||
|
||||
void Audio::stopMixingSongWithMicrophone() {
|
||||
qDebug("Stop mixing called!");
|
||||
_songFileBytes = 0;
|
||||
}
|
||||
|
||||
void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes) {
|
||||
const int NUM_INITIAL_PACKETS_DISCARD = 3;
|
||||
const int STANDARD_DEVIATION_SAMPLE_COUNT = 500;
|
||||
|
|
|
@ -9,8 +9,13 @@
|
|||
#ifndef __interface__Audio__
|
||||
#define __interface__Audio__
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <portaudio.h>
|
||||
|
||||
#include <AudioRingBuffer.h>
|
||||
#include <StdDev.h>
|
||||
|
||||
|
@ -23,7 +28,8 @@ static const int PACKET_LENGTH_BYTES_PER_CHANNEL = PACKET_LENGTH_BYTES / 2;
|
|||
static const int PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t);
|
||||
static const int PACKET_LENGTH_SAMPLES_PER_CHANNEL = PACKET_LENGTH_SAMPLES / 2;
|
||||
|
||||
class Audio {
|
||||
class Audio : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
// initializes audio I/O
|
||||
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples);
|
||||
|
@ -47,6 +53,7 @@ public:
|
|||
void startCollisionSound(float magnitude, float frequency, float noise, float duration);
|
||||
float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; };
|
||||
|
||||
int getSongFileBytes() { return _songFileBytes; }
|
||||
|
||||
void ping();
|
||||
|
||||
|
@ -60,8 +67,13 @@ public:
|
|||
void addListenSource(int sourceID);
|
||||
void removeListenSource(int sourceID);
|
||||
void clearListenSources();
|
||||
|
||||
void importSongToMixWithMicrophone(const char* filename);
|
||||
|
||||
public slots:
|
||||
void stopMixingSongWithMicrophone();
|
||||
|
||||
private:
|
||||
private:
|
||||
PaStream* _stream;
|
||||
AudioRingBuffer _ringBuffer;
|
||||
Oscilloscope* _scope;
|
||||
|
@ -96,6 +108,8 @@ private:
|
|||
float _collisionSoundDuration;
|
||||
int _proceduralEffectSample;
|
||||
float _heartbeatMagnitude;
|
||||
std::ifstream* _songFileStream;
|
||||
int _songFileBytes;
|
||||
|
||||
AudioRingBuffer::ListenMode _listenMode;
|
||||
float _listenRadius;
|
||||
|
|
|
@ -77,3 +77,12 @@ void ToolsPalette::render(int screenWidth, int screenHeight) {
|
|||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
bool ToolsPalette::isActive() {
|
||||
for (unsigned int i = 0; i < _tools.size(); ++i) {
|
||||
if (_tools[i]->isActive()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ public:
|
|||
void addTool(Tool* tool);
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
||||
bool isActive();
|
||||
|
||||
private:
|
||||
QImage _textureImage;
|
||||
GLuint _textureID;
|
||||
|
|
|
@ -223,39 +223,54 @@ void noiseTest(int w, int h) {
|
|||
glEnd();
|
||||
}
|
||||
|
||||
void render_world_box() {
|
||||
// Show edge of world
|
||||
void renderWorldBox() {
|
||||
// Show edge of world
|
||||
float red[] = {1, 0, 0};
|
||||
float green[] = {0, 1, 0};
|
||||
float blue[] = {0, 0, 1};
|
||||
float gray[] = {0.5, 0.5, 0.5};
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
glLineWidth(1.0);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1, 0, 0);
|
||||
glColor3fv(red);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(WORLD_SIZE, 0, 0);
|
||||
glColor3f(0, 1, 0);
|
||||
glVertex3f(TREE_SCALE, 0, 0);
|
||||
glColor3fv(green);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(0, WORLD_SIZE, 0);
|
||||
glColor3f(0, 0, 1);
|
||||
glVertex3f(0, TREE_SCALE, 0);
|
||||
glColor3fv(blue);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(0, 0, WORLD_SIZE);
|
||||
glVertex3f(0, 0, TREE_SCALE);
|
||||
glColor3fv(gray);
|
||||
glVertex3f(0, 0, TREE_SCALE);
|
||||
glVertex3f(TREE_SCALE, 0, TREE_SCALE);
|
||||
glVertex3f(TREE_SCALE, 0, TREE_SCALE);
|
||||
glVertex3f(TREE_SCALE, 0, 0);
|
||||
glEnd();
|
||||
// Draw little marker dots along the axis
|
||||
// Draw marker dots at very end
|
||||
glEnable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
glTranslatef(WORLD_SIZE, 0, 0);
|
||||
glColor3f(1, 0, 0);
|
||||
glTranslatef(TREE_SCALE, 0, 0);
|
||||
glColor3fv(red);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0, WORLD_SIZE, 0);
|
||||
glColor3f(0, 1, 0);
|
||||
glTranslatef(0, TREE_SCALE, 0);
|
||||
glColor3fv(green);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0, 0, WORLD_SIZE);
|
||||
glColor3f(0, 0, 1);
|
||||
glTranslatef(0, 0, TREE_SCALE);
|
||||
glColor3fv(blue);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glColor3fv(gray);
|
||||
glTranslatef(TREE_SCALE, 0, TREE_SCALE);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
double diffclock(timeval *clock1,timeval *clock2)
|
||||
|
|
|
@ -33,7 +33,7 @@ float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float
|
|||
float randFloat();
|
||||
const glm::vec3 randVector();
|
||||
|
||||
void render_world_box();
|
||||
void renderWorldBox();
|
||||
int widthText(float scale, int mono, char const* string);
|
||||
float widthChar(float scale, int mono, char ch);
|
||||
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||
|
|
|
@ -73,10 +73,29 @@ void VoxelSystem::nodeDeleted(VoxelNode* node) {
|
|||
}
|
||||
}
|
||||
|
||||
// returns an available index, starts by reusing a previously freed index, but if there isn't one available
|
||||
// it will use the end of the VBO array and grow our accounting of that array.
|
||||
// and makes the index available for some other node to use
|
||||
glBufferIndex VoxelSystem::getNextBufferIndex() {
|
||||
glBufferIndex output = GLBUFFER_INDEX_UNKNOWN;
|
||||
// if there's a free index, use it...
|
||||
if (_freeIndexes.size() > 0) {
|
||||
output = _freeIndexes.back();
|
||||
_freeIndexes.pop_back();
|
||||
} else {
|
||||
output = _voxelsInWriteArrays;
|
||||
_voxelsInWriteArrays++;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Doesn't actually clean up the VBOs for the index, but does release responsibility of the index from the VoxelNode,
|
||||
// and makes the index available for some other node to use
|
||||
void VoxelSystem::freeBufferIndex(glBufferIndex index) {
|
||||
_freeIndexes.push_back(index);
|
||||
}
|
||||
|
||||
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
|
||||
void VoxelSystem::clearFreeBufferIndexes() {
|
||||
for (int i = 0; i < _freeIndexes.size(); i++) {
|
||||
glBufferIndex nodeIndex = _freeIndexes[i];
|
||||
|
@ -246,12 +265,13 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
_callsToTreesToArrays++;
|
||||
if (_writeRenderFullVBO) {
|
||||
_voxelsInWriteArrays = 0; // reset our VBO
|
||||
_freeIndexes.clear(); // reset our free indexes
|
||||
}
|
||||
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
|
||||
_tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean
|
||||
|
||||
if (_writeRenderFullVBO) {
|
||||
_abandonedVBOSlots = 0; // reset the count of our abandoned slots
|
||||
_abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier????
|
||||
}
|
||||
|
||||
// since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are
|
||||
|
@ -399,15 +419,13 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) {
|
|||
if (node->getShouldRender()) {
|
||||
glm::vec3 startVertex = node->getCorner();
|
||||
float voxelScale = node->getScale();
|
||||
glBufferIndex nodeIndex = _voxelsInWriteArrays;
|
||||
glBufferIndex nodeIndex = getNextBufferIndex();
|
||||
|
||||
// populate the array with points for the 8 vertices
|
||||
// and RGB color for each added vertex
|
||||
updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor());
|
||||
node->setBufferIndex(nodeIndex);
|
||||
node->setVoxelSystem(this);
|
||||
_writeVoxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode
|
||||
_voxelsInWriteArrays++; // our know vertices in the arrays
|
||||
return 1; // rendered
|
||||
} else {
|
||||
node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
|
||||
|
@ -444,10 +462,9 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) {
|
|||
if (node->isKnownBufferIndex()) {
|
||||
nodeIndex = node->getBufferIndex();
|
||||
} else {
|
||||
nodeIndex = _voxelsInWriteArrays;
|
||||
nodeIndex = getNextBufferIndex();
|
||||
node->setBufferIndex(nodeIndex);
|
||||
node->setVoxelSystem(this);
|
||||
_voxelsInWriteArrays++;
|
||||
}
|
||||
_writeVoxelDirtyArray[nodeIndex] = true;
|
||||
|
||||
|
@ -843,13 +860,18 @@ bool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraDat
|
|||
void VoxelSystem::falseColorizeBySource() {
|
||||
_nodeCount = 0;
|
||||
colorizeBySourceArgs args;
|
||||
const int NUMBER_OF_COLOR_GROUPS = 3;
|
||||
const int NUMBER_OF_COLOR_GROUPS = 6;
|
||||
const unsigned char MIN_COLOR = 128;
|
||||
int voxelServerCount = 0;
|
||||
groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { groupColor(255, 0, 0),
|
||||
groupColor(0, 255, 0),
|
||||
groupColor(0, 0, 255)};
|
||||
|
||||
groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = {
|
||||
groupColor(255, 0, 0),
|
||||
groupColor( 0, 255, 0),
|
||||
groupColor( 0, 0, 255),
|
||||
groupColor(255, 0, 255),
|
||||
groupColor( 0, 255, 255),
|
||||
groupColor(255, 255, 255)
|
||||
};
|
||||
|
||||
// create a bunch of colors we'll use during colorization
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
|
|
|
@ -200,6 +200,7 @@ private:
|
|||
|
||||
void freeBufferIndex(glBufferIndex index);
|
||||
void clearFreeBufferIndexes();
|
||||
glBufferIndex getNextBufferIndex();
|
||||
|
||||
bool _falseColorizeBySource;
|
||||
int _dataSourceID;
|
||||
|
|
|
@ -47,11 +47,11 @@ void Webcam::setEnabled(bool enabled) {
|
|||
_grabberThread.start();
|
||||
_startTimestamp = 0;
|
||||
_frameCount = 0;
|
||||
|
||||
|
||||
// let the grabber know we're ready for the first frame
|
||||
QMetaObject::invokeMethod(_grabber, "reset");
|
||||
QMetaObject::invokeMethod(_grabber, "grabFrame");
|
||||
|
||||
|
||||
} else {
|
||||
QMetaObject::invokeMethod(_grabber, "shutdown");
|
||||
_active = false;
|
||||
|
@ -63,7 +63,7 @@ const float UNINITIALIZED_FACE_DEPTH = 0.0f;
|
|||
void Webcam::reset() {
|
||||
_initialFaceRect = RotatedRect();
|
||||
_initialFaceDepth = UNINITIALIZED_FACE_DEPTH;
|
||||
|
||||
|
||||
if (_enabled) {
|
||||
// send a message to the grabber
|
||||
QMetaObject::invokeMethod(_grabber, "reset");
|
||||
|
@ -80,7 +80,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) {
|
|||
int previewWidth = _textureSize.width * PREVIEW_HEIGHT / _textureSize.height;
|
||||
int top = screenHeight - 600;
|
||||
int left = screenWidth - previewWidth - 10;
|
||||
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(left, top);
|
||||
glTexCoord2f(1, 0);
|
||||
|
@ -90,7 +90,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) {
|
|||
glTexCoord2f(0, 1);
|
||||
glVertex2f(left, top + PREVIEW_HEIGHT);
|
||||
glEnd();
|
||||
|
||||
|
||||
if (_depthTextureID != 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, _depthTextureID);
|
||||
glBegin(GL_QUADS);
|
||||
|
@ -103,10 +103,10 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) {
|
|||
glTexCoord2f(0, 1);
|
||||
glVertex2f(left, top);
|
||||
glEnd();
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
|
||||
if (!_joints.isEmpty()) {
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glPointSize(4.0f);
|
||||
|
@ -125,7 +125,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) {
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
Point2f facePoints[4];
|
||||
|
@ -137,7 +137,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) {
|
|||
glVertex2f(left + facePoints[2].x * xScale, top + facePoints[2].y * yScale);
|
||||
glVertex2f(left + facePoints[3].x * xScale, top + facePoints[3].y * yScale);
|
||||
glEnd();
|
||||
|
||||
|
||||
const int MAX_FPS_CHARACTERS = 30;
|
||||
char fps[MAX_FPS_CHARACTERS];
|
||||
sprintf(fps, "FPS: %d", (int)(roundf(_frameCount * 1000000.0f / (usecTimestampNow() - _startTimestamp))));
|
||||
|
@ -149,7 +149,7 @@ Webcam::~Webcam() {
|
|||
// stop the grabber thread
|
||||
_grabberThread.quit();
|
||||
_grabberThread.wait();
|
||||
|
||||
|
||||
delete _grabber;
|
||||
}
|
||||
|
||||
|
@ -166,13 +166,13 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
0, format, GL_UNSIGNED_BYTE, colorImage.imageData);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
qDebug("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height);
|
||||
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _textureSize.width, _textureSize.height, format,
|
||||
GL_UNSIGNED_BYTE, colorImage.imageData);
|
||||
}
|
||||
|
||||
|
||||
if (!depth.empty()) {
|
||||
IplImage depthImage = depth;
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, depthImage.widthStep);
|
||||
|
@ -183,23 +183,23 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
GL_LUMINANCE, GL_UNSIGNED_BYTE, depthImage.imageData);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, _depthTextureID);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _textureSize.width, _textureSize.height, GL_LUMINANCE,
|
||||
GL_UNSIGNED_BYTE, depthImage.imageData);
|
||||
GL_UNSIGNED_BYTE, depthImage.imageData);
|
||||
}
|
||||
}
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
||||
// store our various data, update our frame count for fps computation
|
||||
_aspectRatio = aspectRatio;
|
||||
_faceRect = faceRect;
|
||||
_sending = sending;
|
||||
_joints = _skeletonTrackingOn ? joints : JointVector();
|
||||
_frameCount++;
|
||||
|
||||
|
||||
const int MAX_FPS = 60;
|
||||
const int MIN_FRAME_DELAY = 1000000 / MAX_FPS;
|
||||
uint64_t now = usecTimestampNow();
|
||||
|
@ -210,14 +210,14 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
remaining -= (now - _lastFrameTimestamp);
|
||||
}
|
||||
_lastFrameTimestamp = now;
|
||||
|
||||
|
||||
// see if we have joint data
|
||||
if (!_joints.isEmpty()) {
|
||||
_estimatedJoints.resize(NUM_AVATAR_JOINTS);
|
||||
glm::vec3 origin;
|
||||
if (_joints[AVATAR_JOINT_LEFT_HIP].isValid && _joints[AVATAR_JOINT_RIGHT_HIP].isValid) {
|
||||
origin = glm::mix(_joints[AVATAR_JOINT_LEFT_HIP].position, _joints[AVATAR_JOINT_RIGHT_HIP].position, 0.5f);
|
||||
|
||||
|
||||
} else if (_joints[AVATAR_JOINT_TORSO].isValid) {
|
||||
const glm::vec3 TORSO_TO_PELVIS = glm::vec3(0.0f, -0.09f, -0.01f);
|
||||
origin = _joints[AVATAR_JOINT_TORSO].position + TORSO_TO_PELVIS;
|
||||
|
@ -235,27 +235,27 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
}
|
||||
_estimatedRotation = safeEulerAngles(_estimatedJoints[AVATAR_JOINT_HEAD_BASE].rotation);
|
||||
_estimatedPosition = _estimatedJoints[AVATAR_JOINT_HEAD_BASE].position;
|
||||
|
||||
|
||||
} else {
|
||||
// roll is just the angle of the face rect
|
||||
const float ROTATION_SMOOTHING = 0.95f;
|
||||
_estimatedRotation.z = glm::mix(_faceRect.angle, _estimatedRotation.z, ROTATION_SMOOTHING);
|
||||
|
||||
|
||||
// determine position based on translation and scaling of the face rect/mean face depth
|
||||
if (_initialFaceRect.size.area() == 0) {
|
||||
_initialFaceRect = _faceRect;
|
||||
_estimatedPosition = glm::vec3();
|
||||
_initialFaceDepth = midFaceDepth;
|
||||
|
||||
|
||||
} else {
|
||||
float proportion, z;
|
||||
if (midFaceDepth == UNINITIALIZED_FACE_DEPTH) {
|
||||
proportion = sqrtf(_initialFaceRect.size.area() / (float)_faceRect.size.area());
|
||||
const float INITIAL_DISTANCE_TO_CAMERA = 0.333f;
|
||||
z = INITIAL_DISTANCE_TO_CAMERA * proportion - INITIAL_DISTANCE_TO_CAMERA;
|
||||
|
||||
z = INITIAL_DISTANCE_TO_CAMERA * proportion - INITIAL_DISTANCE_TO_CAMERA;
|
||||
|
||||
} else {
|
||||
z = (midFaceDepth - _initialFaceDepth) * METERS_PER_MM;
|
||||
z = (midFaceDepth - _initialFaceDepth) * METERS_PER_MM;
|
||||
proportion = midFaceDepth / _initialFaceDepth;
|
||||
}
|
||||
const float POSITION_SCALE = 0.5f;
|
||||
|
@ -265,10 +265,10 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF
|
|||
z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// note that we have data
|
||||
_active = true;
|
||||
|
||||
|
||||
// let the grabber know we're ready for the next frame
|
||||
QTimer::singleShot(qMax((int)remaining / 1000, 0), _grabber, SLOT(grabFrame()));
|
||||
}
|
||||
|
@ -289,21 +289,21 @@ static AvatarJointID xnToAvatarJoint(XnSkeletonJoint joint) {
|
|||
case XN_SKEL_HEAD: return AVATAR_JOINT_HEAD_TOP;
|
||||
case XN_SKEL_NECK: return AVATAR_JOINT_HEAD_BASE;
|
||||
case XN_SKEL_TORSO: return AVATAR_JOINT_CHEST;
|
||||
|
||||
|
||||
case XN_SKEL_LEFT_SHOULDER: return AVATAR_JOINT_RIGHT_ELBOW;
|
||||
case XN_SKEL_LEFT_ELBOW: return AVATAR_JOINT_RIGHT_WRIST;
|
||||
|
||||
|
||||
case XN_SKEL_RIGHT_SHOULDER: return AVATAR_JOINT_LEFT_ELBOW;
|
||||
case XN_SKEL_RIGHT_ELBOW: return AVATAR_JOINT_LEFT_WRIST;
|
||||
|
||||
|
||||
case XN_SKEL_LEFT_HIP: return AVATAR_JOINT_RIGHT_KNEE;
|
||||
case XN_SKEL_LEFT_KNEE: return AVATAR_JOINT_RIGHT_HEEL;
|
||||
case XN_SKEL_LEFT_FOOT: return AVATAR_JOINT_RIGHT_TOES;
|
||||
|
||||
|
||||
case XN_SKEL_RIGHT_HIP: return AVATAR_JOINT_LEFT_KNEE;
|
||||
case XN_SKEL_RIGHT_KNEE: return AVATAR_JOINT_LEFT_HEEL;
|
||||
case XN_SKEL_RIGHT_FOOT: return AVATAR_JOINT_LEFT_TOES;
|
||||
|
||||
|
||||
default: return AVATAR_JOINT_NULL;
|
||||
}
|
||||
}
|
||||
|
@ -312,19 +312,19 @@ static int getParentJoint(XnSkeletonJoint joint) {
|
|||
switch (joint) {
|
||||
case XN_SKEL_HEAD: return XN_SKEL_NECK;
|
||||
case XN_SKEL_TORSO: return -1;
|
||||
|
||||
|
||||
case XN_SKEL_LEFT_ELBOW: return XN_SKEL_LEFT_SHOULDER;
|
||||
case XN_SKEL_LEFT_HAND: return XN_SKEL_LEFT_ELBOW;
|
||||
|
||||
|
||||
case XN_SKEL_RIGHT_ELBOW: return XN_SKEL_RIGHT_SHOULDER;
|
||||
case XN_SKEL_RIGHT_HAND: return XN_SKEL_RIGHT_ELBOW;
|
||||
|
||||
|
||||
case XN_SKEL_LEFT_KNEE: return XN_SKEL_LEFT_HIP;
|
||||
case XN_SKEL_LEFT_FOOT: return XN_SKEL_LEFT_KNEE;
|
||||
|
||||
|
||||
case XN_SKEL_RIGHT_KNEE: return XN_SKEL_RIGHT_HIP;
|
||||
case XN_SKEL_RIGHT_FOOT: return XN_SKEL_RIGHT_KNEE;
|
||||
|
||||
|
||||
default: return XN_SKEL_TORSO;
|
||||
}
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability
|
|||
if (status == XN_CALIBRATION_STATUS_OK) {
|
||||
qDebug("Calibration completed for user %d.\n", id);
|
||||
capability.StartTracking(id);
|
||||
|
||||
|
||||
} else {
|
||||
qDebug("Calibration failed to user %d.\n", id);
|
||||
capability.RequestCalibration(id, true);
|
||||
|
@ -370,7 +370,7 @@ static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability
|
|||
void FrameGrabber::cycleVideoSendMode() {
|
||||
_videoSendMode = (VideoSendMode)((_videoSendMode + 1) % VIDEO_SEND_MODE_COUNT);
|
||||
_searchWindow = cv::Rect(0, 0, 0, 0);
|
||||
|
||||
|
||||
destroyCodecs();
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@ void FrameGrabber::shutdown() {
|
|||
}
|
||||
destroyCodecs();
|
||||
_initialized = false;
|
||||
|
||||
|
||||
thread()->quit();
|
||||
}
|
||||
|
||||
|
@ -407,17 +407,17 @@ void FrameGrabber::grabFrame() {
|
|||
int format = GL_BGR;
|
||||
Mat color, depth;
|
||||
JointVector joints;
|
||||
|
||||
|
||||
#ifdef HAVE_OPENNI
|
||||
if (_depthGenerator.IsValid()) {
|
||||
_xnContext.WaitAnyUpdateAll();
|
||||
color = Mat(_imageMetaData.YRes(), _imageMetaData.XRes(), CV_8UC3, (void*)_imageGenerator.GetImageMap());
|
||||
format = GL_RGB;
|
||||
|
||||
|
||||
depth = Mat(_depthMetaData.YRes(), _depthMetaData.XRes(), CV_16UC1, (void*)_depthGenerator.GetDepthMap());
|
||||
|
||||
|
||||
_userID = 0;
|
||||
XnUInt16 userCount = 1;
|
||||
XnUInt16 userCount = 1;
|
||||
_userGenerator.GetUsers(&_userID, userCount);
|
||||
if (userCount > 0 && _userGenerator.GetSkeletonCap().IsTracking(_userID)) {
|
||||
joints.resize(NUM_AVATAR_JOINTS);
|
||||
|
@ -464,10 +464,13 @@ void FrameGrabber::grabFrame() {
|
|||
}
|
||||
color = image;
|
||||
}
|
||||
|
||||
|
||||
const int ENCODED_FACE_WIDTH = 128;
|
||||
const int ENCODED_FACE_HEIGHT = 128;
|
||||
int encodedWidth;
|
||||
int encodedHeight;
|
||||
int depthBitrateMultiplier = 1;
|
||||
float colorBitrateMultiplier = 1.0f;
|
||||
float depthBitrateMultiplier = 1.0f;
|
||||
Mat faceTransform;
|
||||
float aspectRatio;
|
||||
if (_videoSendMode == FULL_FRAME_VIDEO) {
|
||||
|
@ -476,7 +479,8 @@ void FrameGrabber::grabFrame() {
|
|||
encodedWidth = color.cols;
|
||||
encodedHeight = color.rows;
|
||||
aspectRatio = FULL_FRAME_ASPECT;
|
||||
|
||||
colorBitrateMultiplier = 4.0f;
|
||||
|
||||
} else {
|
||||
// if we don't have a search window (yet), try using the face cascade
|
||||
int channels = 0;
|
||||
|
@ -488,7 +492,7 @@ void FrameGrabber::grabFrame() {
|
|||
if (!faces.empty()) {
|
||||
_searchWindow = faces.front();
|
||||
updateHSVFrame(color, format);
|
||||
|
||||
|
||||
Mat faceHsv(_hsvFrame, _searchWindow);
|
||||
Mat faceMask(_mask, _searchWindow);
|
||||
int sizes = 30;
|
||||
|
@ -501,42 +505,40 @@ void FrameGrabber::grabFrame() {
|
|||
RotatedRect faceRect;
|
||||
if (_searchWindow.area() > 0) {
|
||||
updateHSVFrame(color, format);
|
||||
|
||||
|
||||
calcBackProject(&_hsvFrame, 1, &channels, _histogram, _backProject, &range);
|
||||
bitwise_and(_backProject, _mask, _backProject);
|
||||
|
||||
|
||||
faceRect = CamShift(_backProject, _searchWindow, TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1));
|
||||
Rect faceBounds = faceRect.boundingRect();
|
||||
Rect imageBounds(0, 0, color.cols, color.rows);
|
||||
_searchWindow = Rect(clip(faceBounds.tl(), imageBounds), clip(faceBounds.br(), imageBounds));
|
||||
}
|
||||
const int ENCODED_FACE_WIDTH = 128;
|
||||
const int ENCODED_FACE_HEIGHT = 128;
|
||||
encodedWidth = ENCODED_FACE_WIDTH;
|
||||
encodedHeight = ENCODED_FACE_HEIGHT;
|
||||
depthBitrateMultiplier = 2;
|
||||
|
||||
depthBitrateMultiplier = 2.0f;
|
||||
|
||||
// correct for 180 degree rotations
|
||||
if (faceRect.angle < -90.0f) {
|
||||
faceRect.angle += 180.0f;
|
||||
|
||||
|
||||
} else if (faceRect.angle > 90.0f) {
|
||||
faceRect.angle -= 180.0f;
|
||||
}
|
||||
|
||||
|
||||
// compute the smoothed face rect
|
||||
if (_smoothedFaceRect.size.area() == 0) {
|
||||
_smoothedFaceRect = faceRect;
|
||||
|
||||
|
||||
} else {
|
||||
const float FACE_RECT_SMOOTHING = 0.9f;
|
||||
_smoothedFaceRect.center.x = glm::mix(faceRect.center.x, _smoothedFaceRect.center.x, FACE_RECT_SMOOTHING);
|
||||
_smoothedFaceRect.center.y = glm::mix(faceRect.center.y, _smoothedFaceRect.center.y, FACE_RECT_SMOOTHING);
|
||||
_smoothedFaceRect.size.width = glm::mix(faceRect.size.width, _smoothedFaceRect.size.width, FACE_RECT_SMOOTHING);
|
||||
_smoothedFaceRect.size.height = glm::mix(faceRect.size.height, _smoothedFaceRect.size.height, FACE_RECT_SMOOTHING);
|
||||
_smoothedFaceRect.size.height = glm::mix(faceRect.size.height, _smoothedFaceRect.size.height, FACE_RECT_SMOOTHING);
|
||||
_smoothedFaceRect.angle = glm::mix(faceRect.angle, _smoothedFaceRect.angle, FACE_RECT_SMOOTHING);
|
||||
}
|
||||
|
||||
|
||||
// use the face rect to compute the face transform, aspect ratio
|
||||
Point2f sourcePoints[4];
|
||||
_smoothedFaceRect.points(sourcePoints);
|
||||
|
@ -544,7 +546,7 @@ void FrameGrabber::grabFrame() {
|
|||
faceTransform = getAffineTransform(sourcePoints, destPoints);
|
||||
aspectRatio = _smoothedFaceRect.size.width / _smoothedFaceRect.size.height;
|
||||
}
|
||||
|
||||
|
||||
const ushort ELEVEN_BIT_MINIMUM = 0;
|
||||
const uchar EIGHT_BIT_MIDPOINT = 128;
|
||||
double depthOffset;
|
||||
|
@ -553,12 +555,12 @@ void FrameGrabber::grabFrame() {
|
|||
// warp the face depth without interpolation (because it will contain invalid zero values)
|
||||
_faceDepth.create(encodedHeight, encodedWidth, CV_16UC1);
|
||||
warpAffine(depth, _faceDepth, faceTransform, _faceDepth.size(), INTER_NEAREST);
|
||||
|
||||
|
||||
} else {
|
||||
_faceDepth = depth;
|
||||
}
|
||||
_smoothedFaceDepth.create(encodedHeight, encodedWidth, CV_16UC1);
|
||||
|
||||
|
||||
// smooth the depth over time
|
||||
const ushort ELEVEN_BIT_MAXIMUM = 2047;
|
||||
const float DEPTH_SMOOTHING = 0.25f;
|
||||
|
@ -578,7 +580,7 @@ void FrameGrabber::grabFrame() {
|
|||
const ushort MINIMUM_DEPTH_OFFSET = 64;
|
||||
const float FIXED_MID_DEPTH = 640.0f;
|
||||
float midFaceDepth = (_videoSendMode == FACE_VIDEO) ? (minimumDepth + MINIMUM_DEPTH_OFFSET) : FIXED_MID_DEPTH;
|
||||
|
||||
|
||||
// smooth the mid face depth over time
|
||||
const float MID_FACE_DEPTH_SMOOTHING = 0.5f;
|
||||
_smoothedMidFaceDepth = (_smoothedMidFaceDepth == UNINITIALIZED_FACE_DEPTH) ? midFaceDepth :
|
||||
|
@ -588,35 +590,35 @@ void FrameGrabber::grabFrame() {
|
|||
depthOffset = EIGHT_BIT_MIDPOINT - _smoothedMidFaceDepth;
|
||||
depth.convertTo(_grayDepthFrame, CV_8UC1, 1.0, depthOffset);
|
||||
}
|
||||
|
||||
|
||||
QByteArray payload;
|
||||
if (_videoSendMode != NO_VIDEO) {
|
||||
if (_colorCodec.name == 0) {
|
||||
// initialize encoder context(s)
|
||||
vpx_codec_enc_cfg_t codecConfig;
|
||||
vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &codecConfig, 0);
|
||||
codecConfig.rc_target_bitrate = encodedWidth * encodedHeight *
|
||||
codecConfig.rc_target_bitrate = ENCODED_FACE_WIDTH * ENCODED_FACE_HEIGHT * colorBitrateMultiplier *
|
||||
codecConfig.rc_target_bitrate / codecConfig.g_w / codecConfig.g_h;
|
||||
codecConfig.g_w = encodedWidth;
|
||||
codecConfig.g_h = encodedHeight;
|
||||
vpx_codec_enc_init(&_colorCodec, vpx_codec_vp8_cx(), &codecConfig, 0);
|
||||
|
||||
|
||||
if (!depth.empty()) {
|
||||
codecConfig.rc_target_bitrate *= depthBitrateMultiplier;
|
||||
vpx_codec_enc_init(&_depthCodec, vpx_codec_vp8_cx(), &codecConfig, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Mat transform;
|
||||
if (_videoSendMode == FACE_VIDEO) {
|
||||
// resize/rotate face into encoding rectangle
|
||||
_faceColor.create(encodedHeight, encodedWidth, CV_8UC3);
|
||||
warpAffine(color, _faceColor, faceTransform, _faceColor.size());
|
||||
|
||||
|
||||
} else {
|
||||
_faceColor = color;
|
||||
}
|
||||
|
||||
|
||||
// convert from RGB to YV12: see http://www.fourcc.org/yuv.php and
|
||||
// http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
|
||||
const int ENCODED_BITS_PER_Y = 8;
|
||||
|
@ -651,7 +653,7 @@ void FrameGrabber::grabFrame() {
|
|||
uchar* tr = _faceColor.ptr(i, j + 1);
|
||||
uchar* bl = _faceColor.ptr(i + 1, j);
|
||||
uchar* br = _faceColor.ptr(i + 1, j + 1);
|
||||
|
||||
|
||||
ydest[0] = (tl[redIndex] * Y_RED_WEIGHT + tl[1] * Y_GREEN_WEIGHT + tl[blueIndex] * Y_BLUE_WEIGHT) >> 8;
|
||||
ydest[1] = (tr[redIndex] * Y_RED_WEIGHT + tr[1] * Y_GREEN_WEIGHT + tr[blueIndex] * Y_BLUE_WEIGHT) >> 8;
|
||||
ydest[vpxImage.stride[0]] = (bl[redIndex] * Y_RED_WEIGHT + bl[greenIndex] *
|
||||
|
@ -659,12 +661,12 @@ void FrameGrabber::grabFrame() {
|
|||
ydest[vpxImage.stride[0] + 1] = (br[redIndex] * Y_RED_WEIGHT + br[greenIndex] *
|
||||
Y_GREEN_WEIGHT + br[blueIndex] * Y_BLUE_WEIGHT) >> 8;
|
||||
ydest += 2;
|
||||
|
||||
|
||||
int totalRed = tl[redIndex] + tr[redIndex] + bl[redIndex] + br[redIndex];
|
||||
int totalGreen = tl[greenIndex] + tr[greenIndex] + bl[greenIndex] + br[greenIndex];
|
||||
int totalBlue = tl[blueIndex] + tr[blueIndex] + bl[blueIndex] + br[blueIndex];
|
||||
int totalY = (totalRed * Y_RED_WEIGHT + totalGreen * Y_GREEN_WEIGHT + totalBlue * Y_BLUE_WEIGHT) >> 8;
|
||||
|
||||
|
||||
*vdest++ = (((totalRed - totalY) * V_RED_WEIGHT) >> 10) + 128;
|
||||
*udest++ = (((totalBlue - totalY) * U_BLUE_WEIGHT) >> 10) + 128;
|
||||
}
|
||||
|
@ -672,7 +674,7 @@ void FrameGrabber::grabFrame() {
|
|||
vline += vpxImage.stride[1];
|
||||
uline += vpxImage.stride[2];
|
||||
}
|
||||
|
||||
|
||||
// encode the frame
|
||||
vpx_codec_encode(&_colorCodec, &vpxImage, ++_frameCount, 1, 0, VPX_DL_REALTIME);
|
||||
|
||||
|
@ -689,7 +691,7 @@ void FrameGrabber::grabFrame() {
|
|||
payload.append((const char*)packet->data.frame.buf, packet->data.frame.sz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!depth.empty()) {
|
||||
// convert with mask
|
||||
uchar* yline = vpxImage.planes[0];
|
||||
|
@ -705,9 +707,9 @@ void FrameGrabber::grabFrame() {
|
|||
ushort tr = *_smoothedFaceDepth.ptr<ushort>(i, j + 1);
|
||||
ushort bl = *_smoothedFaceDepth.ptr<ushort>(i + 1, j);
|
||||
ushort br = *_smoothedFaceDepth.ptr<ushort>(i + 1, j + 1);
|
||||
|
||||
|
||||
uchar mask = EIGHT_BIT_MAXIMUM;
|
||||
|
||||
|
||||
ydest[0] = (tl == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) :
|
||||
saturate_cast<uchar>(tl + depthOffset);
|
||||
ydest[1] = (tr == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) :
|
||||
|
@ -717,7 +719,7 @@ void FrameGrabber::grabFrame() {
|
|||
ydest[vpxImage.stride[0] + 1] = (br == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) :
|
||||
saturate_cast<uchar>(br + depthOffset);
|
||||
ydest += 2;
|
||||
|
||||
|
||||
*vdest++ = mask;
|
||||
*udest++ = EIGHT_BIT_MIDPOINT;
|
||||
}
|
||||
|
@ -725,7 +727,7 @@ void FrameGrabber::grabFrame() {
|
|||
vline += vpxImage.stride[1];
|
||||
uline += vpxImage.stride[2];
|
||||
}
|
||||
|
||||
|
||||
// encode the frame
|
||||
vpx_codec_encode(&_depthCodec, &vpxImage, _frameCount, 1, 0, VPX_DL_REALTIME);
|
||||
|
||||
|
@ -739,10 +741,10 @@ void FrameGrabber::grabFrame() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "sendAvatarFaceVideoMessage",
|
||||
Q_ARG(int, _frameCount), Q_ARG(QByteArray, payload));
|
||||
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getWebcam(), "setFrame",
|
||||
Q_ARG(cv::Mat, color), Q_ARG(int, format), Q_ARG(cv::Mat, _grayDepthFrame), Q_ARG(float, _smoothedMidFaceDepth),
|
||||
Q_ARG(float, aspectRatio), Q_ARG(cv::RotatedRect, _smoothedFaceRect), Q_ARG(bool, !payload.isEmpty()),
|
||||
|
@ -768,19 +770,19 @@ bool FrameGrabber::init() {
|
|||
_depthGenerator.GetMetaData(_depthMetaData);
|
||||
_imageGenerator.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
|
||||
_imageGenerator.GetMetaData(_imageMetaData);
|
||||
|
||||
|
||||
XnCallbackHandle userCallbacks, calibrationStartCallback, calibrationCompleteCallback;
|
||||
_userGenerator.RegisterUserCallbacks(newUser, lostUser, 0, userCallbacks);
|
||||
_userGenerator.GetSkeletonCap().RegisterToCalibrationStart(calibrationStarted, 0, calibrationStartCallback);
|
||||
_userGenerator.GetSkeletonCap().RegisterToCalibrationComplete(calibrationCompleted, 0, calibrationCompleteCallback);
|
||||
|
||||
|
||||
_userGenerator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_UPPER);
|
||||
|
||||
|
||||
// make the depth viewpoint match that of the video image
|
||||
if (_depthGenerator.IsCapabilitySupported(XN_CAPABILITY_ALTERNATIVE_VIEW_POINT)) {
|
||||
_depthGenerator.GetAlternativeViewPointCap().SetViewPoint(_imageGenerator);
|
||||
}
|
||||
|
||||
|
||||
_xnContext.StartGeneratingAll();
|
||||
return true;
|
||||
}
|
||||
|
@ -795,7 +797,7 @@ bool FrameGrabber::init() {
|
|||
const int IDEAL_FRAME_HEIGHT = 240;
|
||||
cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH, IDEAL_FRAME_WIDTH);
|
||||
cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT, IDEAL_FRAME_HEIGHT);
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
configureCamera(0x5ac, 0x8510, false, 0.975, 0.5, 1.0, 0.5, true, 0.5);
|
||||
#else
|
||||
|
|
|
@ -38,9 +38,9 @@ typedef QVector<Joint> JointVector;
|
|||
|
||||
class Webcam : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Webcam();
|
||||
~Webcam();
|
||||
|
||||
|
@ -49,34 +49,34 @@ public:
|
|||
bool isActive() const { return _active; }
|
||||
|
||||
bool isSending() const { return _sending; }
|
||||
|
||||
|
||||
GLuint getColorTextureID() const { return _colorTextureID; }
|
||||
GLuint getDepthTextureID() const { return _depthTextureID; }
|
||||
const cv::Size2f& getTextureSize() const { return _textureSize; }
|
||||
|
||||
|
||||
float getAspectRatio() const { return _aspectRatio; }
|
||||
|
||||
|
||||
const cv::RotatedRect& getFaceRect() const { return _faceRect; }
|
||||
|
||||
|
||||
const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; }
|
||||
const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; }
|
||||
const JointVector& getEstimatedJoints() const { return _estimatedJoints; }
|
||||
|
||||
void reset();
|
||||
void renderPreview(int screenWidth, int screenHeight);
|
||||
void renderPreview(int screenWidth, int screenHeight);
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
void setFrame(const cv::Mat& color, int format, const cv::Mat& depth, float midFaceDepth,
|
||||
float aspectRatio, const cv::RotatedRect& faceRect, bool sending, const JointVector& joints);
|
||||
void setSkeletonTrackingOn(bool toggle) { _skeletonTrackingOn = toggle; };
|
||||
|
||||
private:
|
||||
|
||||
|
||||
QThread _grabberThread;
|
||||
FrameGrabber* _grabber;
|
||||
|
||||
|
||||
bool _enabled;
|
||||
bool _active;
|
||||
bool _sending;
|
||||
|
@ -88,12 +88,12 @@ private:
|
|||
cv::RotatedRect _initialFaceRect;
|
||||
float _initialFaceDepth;
|
||||
JointVector _joints;
|
||||
|
||||
|
||||
uint64_t _startTimestamp;
|
||||
int _frameCount;
|
||||
|
||||
|
||||
uint64_t _lastFrameTimestamp;
|
||||
|
||||
|
||||
glm::vec3 _estimatedPosition;
|
||||
glm::vec3 _estimatedRotation;
|
||||
JointVector _estimatedJoints;
|
||||
|
@ -103,27 +103,27 @@ private:
|
|||
|
||||
class FrameGrabber : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
FrameGrabber();
|
||||
virtual ~FrameGrabber();
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
void cycleVideoSendMode();
|
||||
void reset();
|
||||
void shutdown();
|
||||
void grabFrame();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
enum VideoSendMode { NO_VIDEO, FACE_VIDEO, FULL_FRAME_VIDEO, VIDEO_SEND_MODE_COUNT };
|
||||
|
||||
|
||||
bool init();
|
||||
void updateHSVFrame(const cv::Mat& frame, int format);
|
||||
void destroyCodecs();
|
||||
|
||||
|
||||
bool _initialized;
|
||||
VideoSendMode _videoSendMode;
|
||||
CvCapture* _capture;
|
||||
|
@ -135,7 +135,7 @@ private:
|
|||
cv::Rect _searchWindow;
|
||||
cv::Mat _grayDepthFrame;
|
||||
float _smoothedMidFaceDepth;
|
||||
|
||||
|
||||
vpx_codec_ctx_t _colorCodec;
|
||||
vpx_codec_ctx_t _depthCodec;
|
||||
int _frameCount;
|
||||
|
@ -144,7 +144,7 @@ private:
|
|||
cv::Mat _smoothedFaceDepth;
|
||||
QByteArray _encodedFace;
|
||||
cv::RotatedRect _smoothedFaceRect;
|
||||
|
||||
|
||||
#ifdef HAVE_OPENNI
|
||||
xn::Context _xnContext;
|
||||
xn::DepthGenerator _depthGenerator;
|
||||
|
@ -158,10 +158,10 @@ private:
|
|||
|
||||
class Joint {
|
||||
public:
|
||||
|
||||
|
||||
Joint(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& projected);
|
||||
Joint();
|
||||
|
||||
|
||||
bool isValid;
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
|
|
|
@ -101,8 +101,8 @@ Avatar::Avatar(Node* owningNode) :
|
|||
_lastCollisionPosition(0, 0, 0),
|
||||
_speedBrakes(false),
|
||||
_isThrustOn(false),
|
||||
_voxels(this),
|
||||
_leadingAvatar(NULL)
|
||||
_leadingAvatar(NULL),
|
||||
_voxels(this)
|
||||
{
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = &_head;
|
||||
|
@ -369,11 +369,24 @@ glm::vec3 Avatar::getUprightHeadPosition() const {
|
|||
}
|
||||
|
||||
glm::vec3 Avatar::getUprightEyeLevelPosition() const {
|
||||
const float EYE_UP_OFFSET = 0.36f;
|
||||
const float EYE_UP_OFFSET = 0.36f;
|
||||
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
||||
return _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET + glm::vec3(0.0f, _pelvisToHeadLength, 0.0f);
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getEyePosition() {
|
||||
const float EYE_UP_OFFSET = 0.36f;
|
||||
const float EYE_FRONT_OFFSET = 0.8f;
|
||||
|
||||
glm::quat orientation = getWorldAlignedOrientation();
|
||||
glm::vec3 up = orientation * IDENTITY_UP;
|
||||
glm::vec3 front = orientation * IDENTITY_FRONT;
|
||||
|
||||
float scale = _scale * BODY_BALL_RADIUS_HEAD_BASE;
|
||||
|
||||
return getHead().getPosition() + up * scale * EYE_UP_OFFSET + front * scale * EYE_FRONT_OFFSET;
|
||||
}
|
||||
|
||||
void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) {
|
||||
//
|
||||
// Gather thrust information from keyboard and sensors to apply to avatar motion
|
||||
|
|
|
@ -171,6 +171,7 @@ public:
|
|||
|
||||
glm::vec3 getUprightHeadPosition() const;
|
||||
glm::vec3 getUprightEyeLevelPosition() const;
|
||||
glm::vec3 getEyePosition();
|
||||
|
||||
AvatarVoxelSystem* getVoxels() { return &_voxels; }
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class QNetworkReply;
|
|||
|
||||
class Avatar;
|
||||
|
||||
class AvatarVoxelSystem : public QObject, public VoxelSystem {
|
||||
class AvatarVoxelSystem : public VoxelSystem {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -163,21 +163,21 @@ int Face::processVideoMessage(unsigned char* packetData, size_t dataBytes) {
|
|||
int ybr = ysrc[image->w + 1];
|
||||
ysrc += 2;
|
||||
|
||||
tl[0] = ytl + redOffset;
|
||||
tl[1] = ytl - greenOffset;
|
||||
tl[2] = ytl + blueOffset;
|
||||
tl[0] = saturate_cast<uchar>(ytl + redOffset);
|
||||
tl[1] = saturate_cast<uchar>(ytl - greenOffset);
|
||||
tl[2] = saturate_cast<uchar>(ytl + blueOffset);
|
||||
|
||||
tr[0] = ytr + redOffset;
|
||||
tr[1] = ytr - greenOffset;
|
||||
tr[2] = ytr + blueOffset;
|
||||
tr[0] = saturate_cast<uchar>(ytr + redOffset);
|
||||
tr[1] = saturate_cast<uchar>(ytr - greenOffset);
|
||||
tr[2] = saturate_cast<uchar>(ytr + blueOffset);
|
||||
|
||||
bl[0] = ybl + redOffset;
|
||||
bl[1] = ybl - greenOffset;
|
||||
bl[2] = ybl + blueOffset;
|
||||
bl[0] = saturate_cast<uchar>(ybl + redOffset);
|
||||
bl[1] = saturate_cast<uchar>(ybl - greenOffset);
|
||||
bl[2] = saturate_cast<uchar>(ybl + blueOffset);
|
||||
|
||||
br[0] = ybr + redOffset;
|
||||
br[1] = ybr - greenOffset;
|
||||
br[2] = ybr + blueOffset;
|
||||
br[0] = saturate_cast<uchar>(ybr + redOffset);
|
||||
br[1] = saturate_cast<uchar>(ybr - greenOffset);
|
||||
br[2] = saturate_cast<uchar>(ybr + blueOffset);
|
||||
}
|
||||
yline += image->stride[0] * 2;
|
||||
vline += image->stride[1];
|
||||
|
|
|
@ -59,7 +59,7 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_rotation(0.0f, 0.0f, 0.0f),
|
||||
_leftEyePosition(0.0f, 0.0f, 0.0f),
|
||||
_rightEyePosition(0.0f, 0.0f, 0.0f),
|
||||
_eyeLevelPosition(0.0f, 0.0f, 0.0f),
|
||||
_eyePosition(0.0f, 0.0f, 0.0f),
|
||||
_leftEyeBrowPosition(0.0f, 0.0f, 0.0f),
|
||||
_rightEyeBrowPosition(0.0f, 0.0f, 0.0f),
|
||||
_leftEarPosition(0.0f, 0.0f, 0.0f),
|
||||
|
@ -280,7 +280,7 @@ void Head::calculateGeometry() {
|
|||
+ up * scale * EYE_UP_OFFSET
|
||||
+ front * scale * EYE_FRONT_OFFSET;
|
||||
|
||||
_eyeLevelPosition = _rightEyePosition - right * scale * EYE_RIGHT_OFFSET;
|
||||
_eyePosition = _rightEyePosition - right * scale * EYE_RIGHT_OFFSET;
|
||||
|
||||
//calculate the eyebrow positions
|
||||
_leftEyeBrowPosition = _leftEyePosition;
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
|
||||
float getScale() const { return _scale; }
|
||||
glm::vec3 getPosition() const { return _position; }
|
||||
const glm::vec3& getEyeLevelPosition() const { return _eyeLevelPosition; }
|
||||
const glm::vec3& getEyePosition() const { return _eyePosition; }
|
||||
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
|
||||
glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; }
|
||||
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||
|
@ -96,7 +96,7 @@ private:
|
|||
glm::vec3 _rotation;
|
||||
glm::vec3 _leftEyePosition;
|
||||
glm::vec3 _rightEyePosition;
|
||||
glm::vec3 _eyeLevelPosition;
|
||||
glm::vec3 _eyePosition;
|
||||
glm::vec3 _leftEyeBrowPosition;
|
||||
glm::vec3 _rightEyeBrowPosition;
|
||||
glm::vec3 _leftEarPosition;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#define __interface__world__
|
||||
|
||||
|
||||
const float WORLD_SIZE = 10.0;
|
||||
#define PIf 3.14159265f
|
||||
|
||||
const float GRAVITY_EARTH = 9.80665f;
|
||||
|
|
|
@ -61,6 +61,8 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) {
|
|||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
if (audioMixer) {
|
||||
_destinationSocket = *audioMixer->getActiveSocket();
|
||||
} else {
|
||||
pthread_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <UDPSocket.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
|
@ -21,7 +21,8 @@ AudioInjector::AudioInjector(const char* filename) :
|
|||
_radius(0.0f),
|
||||
_volume(MAX_INJECTOR_VOLUME),
|
||||
_indexOfNextSlot(0),
|
||||
_isInjectingAudio(false)
|
||||
_isInjectingAudio(false),
|
||||
_lastFrameIntensity(0.0f)
|
||||
{
|
||||
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
|
||||
|
||||
|
@ -51,7 +52,8 @@ AudioInjector::AudioInjector(int maxNumSamples) :
|
|||
_radius(0.0f),
|
||||
_volume(MAX_INJECTOR_VOLUME),
|
||||
_indexOfNextSlot(0),
|
||||
_isInjectingAudio(false)
|
||||
_isInjectingAudio(false),
|
||||
_lastFrameIntensity(0.0f)
|
||||
{
|
||||
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
|
||||
|
||||
|
@ -114,6 +116,18 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
|||
|
||||
injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket));
|
||||
|
||||
// calculate the intensity for this frame
|
||||
float lastRMS = 0;
|
||||
|
||||
for (int j = 0; j < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; j++) {
|
||||
lastRMS += _audioSampleArray[i + j] * _audioSampleArray[i + j];
|
||||
}
|
||||
|
||||
lastRMS /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
lastRMS = sqrtf(lastRMS);
|
||||
|
||||
_lastFrameIntensity = lastRMS / std::numeric_limits<int16_t>::max();
|
||||
|
||||
int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * INJECT_INTERVAL_USECS) - usecTimestampNow();
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
|
@ -131,8 +145,8 @@ void AudioInjector::addSample(const int16_t sample) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) {
|
||||
if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + (_numTotalSamples / sizeof(int16_t))) {
|
||||
void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) {
|
||||
if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + _numTotalSamples) {
|
||||
// only copy the audio from the sample buffer if there's space
|
||||
memcpy(_audioSampleArray + _indexOfNextSlot, sampleBuffer, numSamples * sizeof(int16_t));
|
||||
_indexOfNextSlot += numSamples;
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
#ifndef __hifi__AudioInjector__
|
||||
#define __hifi__AudioInjector__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <UDPSocket.h>
|
||||
|
@ -36,6 +35,8 @@ public:
|
|||
unsigned char getVolume() const { return _volume; }
|
||||
void setVolume(unsigned char volume) { _volume = volume; }
|
||||
|
||||
float getLastFrameIntensity() const { return _lastFrameIntensity; }
|
||||
|
||||
const glm::vec3& getPosition() const { return _position; }
|
||||
void setPosition(const glm::vec3& position) { _position = position; }
|
||||
|
||||
|
@ -57,6 +58,7 @@ private:
|
|||
unsigned char _volume;
|
||||
int _indexOfNextSlot;
|
||||
bool _isInjectingAudio;
|
||||
float _lastFrameIntensity;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AudioInjector__) */
|
||||
|
|
88
libraries/avatars/src/Agent.cpp
Normal file
88
libraries/avatars/src/Agent.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Agent.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 7/1/13.
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <QtScript/QScriptEngine>
|
||||
#import <QtNetwork/QtNetwork>
|
||||
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
|
||||
#include "Agent.h"
|
||||
|
||||
Agent::Agent() :
|
||||
_shouldStop(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Agent::run(QUrl scriptURL) {
|
||||
NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT);
|
||||
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AVATAR_MIXER, 1);
|
||||
|
||||
QNetworkAccessManager* manager = new QNetworkAccessManager();
|
||||
|
||||
qDebug() << "Attemping download of " << scriptURL;
|
||||
|
||||
QNetworkReply* reply = manager->get(QNetworkRequest(scriptURL));
|
||||
|
||||
QEventLoop loop;
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
|
||||
QString scriptString = QString(reply->readAll());
|
||||
|
||||
QScriptEngine engine;
|
||||
|
||||
AvatarData *testAvatarData = new AvatarData;
|
||||
|
||||
QScriptValue avatarDataValue = engine.newQObject(testAvatarData);
|
||||
engine.globalObject().setProperty("AvatarData", avatarDataValue);
|
||||
|
||||
QScriptValue agentValue = engine.newQObject(this);
|
||||
engine.globalObject().setProperty("Agent", agentValue);
|
||||
|
||||
qDebug() << "Downloaded script:" << scriptString;
|
||||
|
||||
qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString();
|
||||
|
||||
timeval thisSend;
|
||||
timeval lastDomainServerCheckIn = {};
|
||||
int numMicrosecondsSleep = 0;
|
||||
|
||||
const float DATA_SEND_INTERVAL_USECS = (1 / 60) * 1000 * 1000;
|
||||
|
||||
sockaddr_in senderAddress;
|
||||
unsigned char receivedData[MAX_PACKET_SIZE];
|
||||
ssize_t receivedBytes;
|
||||
|
||||
while (!_shouldStop) {
|
||||
// update the thisSend timeval to the current time
|
||||
gettimeofday(&thisSend, NULL);
|
||||
|
||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
emit preSendCallback();
|
||||
|
||||
testAvatarData->sendData();
|
||||
|
||||
if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) {
|
||||
NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
|
||||
}
|
||||
|
||||
// sleep for the correct amount of time to have data send be consistently timed
|
||||
if ((numMicrosecondsSleep = DATA_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
|
||||
usleep(numMicrosecondsSleep);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
libraries/avatars/src/Agent.h
Normal file
32
libraries/avatars/src/Agent.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Agent.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 7/1/13.
|
||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __hifi__Agent__
|
||||
#define __hifi__Agent__
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
class Agent : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Agent();
|
||||
|
||||
bool volatile _shouldStop;
|
||||
|
||||
void run(QUrl scriptUrl);
|
||||
signals:
|
||||
void preSendCallback();
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__Operative__) */
|
|
@ -10,8 +10,9 @@
|
|||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include <VoxelConstants.h>
|
||||
|
@ -50,6 +51,22 @@ AvatarData::~AvatarData() {
|
|||
delete _handData;
|
||||
}
|
||||
|
||||
void AvatarData::sendData() {
|
||||
|
||||
// called from Agent visual loop to send data
|
||||
if (Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER)) {
|
||||
unsigned char packet[MAX_PACKET_SIZE];
|
||||
|
||||
unsigned char* endOfPacket = packet;
|
||||
endOfPacket += populateTypeAndVersion(endOfPacket, PACKET_TYPE_HEAD_DATA);
|
||||
endOfPacket += packNodeId(endOfPacket, NodeList::getInstance()->getOwnerID());
|
||||
|
||||
int numPacketBytes = (endOfPacket - packet) + getBroadcastData(endOfPacket);
|
||||
|
||||
NodeList::getInstance()->getNodeSocket()->send(avatarMixer->getActiveSocket(), packet, numPacketBytes);
|
||||
}
|
||||
}
|
||||
|
||||
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
||||
unsigned char* bufferStart = destinationBuffer;
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <NodeData.h>
|
||||
#include "HeadData.h"
|
||||
#include "HandData.h"
|
||||
|
@ -39,6 +41,7 @@ enum KeyState
|
|||
class JointData;
|
||||
|
||||
class AvatarData : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AvatarData(Node* owningNode = NULL);
|
||||
~AvatarData();
|
||||
|
@ -53,7 +56,6 @@ public:
|
|||
|
||||
// Body Rotation
|
||||
float getBodyYaw() const { return _bodyYaw; }
|
||||
void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; }
|
||||
float getBodyPitch() const { return _bodyPitch; }
|
||||
void setBodyPitch(float bodyPitch) { _bodyPitch = bodyPitch; }
|
||||
float getBodyRoll() const {return _bodyRoll; }
|
||||
|
@ -103,6 +105,11 @@ public:
|
|||
void setHeadData(HeadData* headData) { _headData = headData; }
|
||||
void setHandData(HandData* handData) { _handData = handData; }
|
||||
|
||||
public slots:
|
||||
void setPosition(float x, float y, float z) { _position = glm::vec3(x, y, z); }
|
||||
void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; }
|
||||
void sendData();
|
||||
|
||||
protected:
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _handPosition;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
class AvatarData;
|
||||
class FingerData;
|
||||
|
|
|
@ -26,3 +26,6 @@ if (UNIX AND NOT APPLE)
|
|||
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif (UNIX AND NOT APPLE)
|
||||
|
||||
# include GLM
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "SharedUtil.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) {
|
||||
memcpy(nodeId, packedData, sizeof(uint16_t));
|
||||
|
@ -75,6 +75,7 @@ const char* NODE_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
|
|||
const char* NODE_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
|
||||
const char* NODE_TYPE_NAME_AUDIO_INJECTOR = "Audio Injector";
|
||||
const char* NODE_TYPE_NAME_ANIMATION_SERVER = "Animation Server";
|
||||
const char* NODE_TYPE_NAME_UNASSIGNED = "Unassigned";
|
||||
const char* NODE_TYPE_NAME_UNKNOWN = "Unknown";
|
||||
|
||||
const char* Node::getTypeName() const {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "NodeData.h"
|
||||
#include "SimpleMovingAverage.h"
|
||||
|
|
|
@ -9,9 +9,12 @@
|
|||
#ifndef hifi_NodeData_h
|
||||
#define hifi_NodeData_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class Node;
|
||||
|
||||
class NodeData {
|
||||
class NodeData : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeData(Node* owningNode);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "NodeList.h"
|
||||
#include "NodeTypes.h"
|
||||
|
@ -366,6 +366,15 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
|||
return readNodes;
|
||||
}
|
||||
|
||||
void NodeList::sendAssignmentRequest() {
|
||||
const char ASSIGNMENT_SERVER_HOSTNAME[] = "assignment.highfidelity.io";
|
||||
|
||||
static sockaddr_in assignmentServerSocket = socketForHostname(ASSIGNMENT_SERVER_HOSTNAME);
|
||||
assignmentServerSocket.sin_port = htons(ASSIGNMENT_SERVER_PORT);
|
||||
|
||||
_nodeSocket.send((sockaddr*) &assignmentServerSocket, &PACKET_TYPE_REQUEST_ASSIGNMENT, 1);
|
||||
}
|
||||
|
||||
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
|
||||
NodeList::iterator node = end();
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
#include <iterator>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QSettings>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include "Node.h"
|
||||
#include "NodeTypes.h"
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -54,14 +55,16 @@ public:
|
|||
NodeListIterator begin() const;
|
||||
NodeListIterator end() const;
|
||||
|
||||
|
||||
NODE_TYPE getOwnerType() const { return _ownerType; }
|
||||
void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; }
|
||||
|
||||
const char* getDomainHostname() const { return _domainHostname; };
|
||||
void setDomainHostname(const char* domainHostname);
|
||||
|
||||
void setDomainIP(const char* domainIP);
|
||||
void setDomainIPToLocalhost();
|
||||
|
||||
char getOwnerType() const { return _ownerType; }
|
||||
|
||||
|
||||
uint16_t getLastNodeID() const { return _lastNodeID; }
|
||||
void increaseNodeID() { ++_lastNodeID; }
|
||||
|
||||
|
@ -80,9 +83,12 @@ public:
|
|||
void clear();
|
||||
|
||||
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
||||
|
||||
void sendDomainServerCheckIn();
|
||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||
|
||||
void sendAssignmentRequest();
|
||||
|
||||
Node* nodeWithAddress(sockaddr *senderAddress);
|
||||
Node* nodeWithID(uint16_t nodeID);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
#include "OctalCode.h"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ const PACKET_TYPE PACKET_TYPE_TRANSMITTER_DATA_V2 = 'T';
|
|||
const PACKET_TYPE PACKET_TYPE_ENVIRONMENT_DATA = 'e';
|
||||
const PACKET_TYPE PACKET_TYPE_DOMAIN_LIST_REQUEST = 'L';
|
||||
const PACKET_TYPE PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY = 'C';
|
||||
const PACKET_TYPE PACKET_TYPE_REQUEST_ASSIGNMENT = 'r';
|
||||
const PACKET_TYPE PACKET_TYPE_SEND_ASSIGNMENT = 's';
|
||||
const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#';
|
||||
|
||||
typedef char PACKET_VERSION;
|
||||
|
@ -52,4 +54,6 @@ const int MAX_PACKET_HEADER_BYTES = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)
|
|||
#define ADD_SCENE_COMMAND "add scene"
|
||||
#define TEST_COMMAND "a message"
|
||||
|
||||
const int ASSIGNMENT_SERVER_PORT = 7007;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "PerfStat.h"
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "OctalCode.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Systime.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "UDPSocket.h"
|
||||
|
||||
|
@ -118,6 +118,17 @@ unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) {
|
|||
}
|
||||
}
|
||||
|
||||
sockaddr_in socketForHostname(const char* hostname) {
|
||||
struct hostent* pHostInfo;
|
||||
sockaddr_in newSocket;
|
||||
|
||||
if ((pHostInfo = gethostbyname(hostname))) {
|
||||
memcpy(&newSocket.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
|
||||
}
|
||||
|
||||
return newSocket;
|
||||
}
|
||||
|
||||
UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking(true) {
|
||||
init();
|
||||
// create the socket
|
||||
|
|
|
@ -42,5 +42,6 @@ int packSocket(unsigned char* packStore, sockaddr* socketToPack);
|
|||
int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket);
|
||||
int getLocalAddress();
|
||||
unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket);
|
||||
sockaddr_in socketForHostname(const char* hostname);
|
||||
|
||||
#endif /* defined(__interface__UDPSocket__) */
|
||||
|
|
|
@ -44,12 +44,28 @@ JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) {
|
|||
readFromFile(filename);
|
||||
}
|
||||
|
||||
|
||||
JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes)
|
||||
: _rootOctalCode(NULL) {
|
||||
init(rootOctalCode, endNodes);
|
||||
}
|
||||
|
||||
JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) {
|
||||
_rootOctalCode = hexStringToOctalCode(QString(rootHexCode));
|
||||
|
||||
QString endNodesHexStrings(endNodesHexCodes);
|
||||
QString delimiterPattern(",");
|
||||
QStringList endNodeList = endNodesHexStrings.split(delimiterPattern);
|
||||
|
||||
for (int i = 0; i < endNodeList.size(); i++) {
|
||||
QString endNodeHexString = endNodeList.at(i);
|
||||
|
||||
unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString);
|
||||
//printOctalCode(endNodeOctcode);
|
||||
_endNodes.push_back(endNodeOctcode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes) {
|
||||
clear(); // clean up our own memory
|
||||
_rootOctalCode = rootOctalCode;
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
JurisdictionMap();
|
||||
JurisdictionMap(const char* filename);
|
||||
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);
|
||||
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
||||
~JurisdictionMap();
|
||||
|
||||
Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const;
|
||||
|
|
|
@ -15,6 +15,12 @@ OPTIONS
|
|||
--local
|
||||
This will run the voxel server in "local domain mode" and will look for a domain-server running on the same IP
|
||||
address as the voxel server
|
||||
|
||||
--jurisdictionRoot [hex string of root octcode]
|
||||
Tells the server to honor jurisdiction from the specified root node and below
|
||||
|
||||
--jurisdictionEndNodes [<octcode>(<,octcode>...)]
|
||||
Tells the server to honor jurisdiction from the root down to the octcodes included in the comma separated list
|
||||
|
||||
--jurisdictionFile [filename]
|
||||
Tells the server to load it's jurisdiction from the specified file. When a voxel server is running with a limited
|
||||
|
|
|
@ -456,11 +456,22 @@ int main(int argc, const char * argv[]) {
|
|||
printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
jurisdiction = new JurisdictionMap(jurisdictionFile);
|
||||
printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
} else {
|
||||
const char* JURISDICTION_ROOT = "--jurisdictionRoot";
|
||||
const char* jurisdictionRoot = getCmdOption(argc, argv, JURISDICTION_ROOT);
|
||||
if (jurisdictionRoot) {
|
||||
printf("jurisdictionRoot=%s\n", jurisdictionRoot);
|
||||
}
|
||||
|
||||
// test writing the file...
|
||||
printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
jurisdiction->writeToFile(jurisdictionFile);
|
||||
printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||
const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
|
||||
const char* jurisdictionEndNodes = getCmdOption(argc, argv, JURISDICTION_ENDNODES);
|
||||
if (jurisdictionEndNodes) {
|
||||
printf("jurisdictionEndNodes=%s\n", jurisdictionEndNodes);
|
||||
}
|
||||
|
||||
if (jurisdictionRoot || jurisdictionEndNodes) {
|
||||
jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
|
||||
}
|
||||
}
|
||||
|
||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort);
|
||||
|
|
Loading…
Reference in a new issue