Merge branch 'master' of https://github.com/highfidelity/hifi into add_start_stop_animation_for_scripted_avatar

Conflicts:
	assignment-client/src/Agent.cpp
	examples/editModels.js
This commit is contained in:
Atlante45 2014-07-28 10:11:39 -07:00
commit 844e5d7e47
76 changed files with 1376 additions and 717 deletions

View file

@ -231,7 +231,8 @@ void Agent::run() {
// setup an Avatar for the script to use
ScriptableAvatar scriptedAvatar(&_scriptEngine);
scriptedAvatar.setForceFaceshiftConnected(true);
// call model URL setters with empty URLs so our avatar, if user, will have the default models
scriptedAvatar.setFaceModelURL(QUrl());
scriptedAvatar.setSkeletonModelURL(QUrl());

View file

@ -237,14 +237,6 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
_clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET] += delayBufferSample[1];
}
// The following code is pretty gross and redundant, but AFAIK it's the best way to avoid
// too many conditionals in handling the delay samples at the beginning of _clientSamples.
// Basically we try to take the samples in batches of four, and then handle the remainder
// conditionally to get rid of the rest.
const int DOUBLE_STEREO_OFFSET = 4;
const int TRIPLE_STEREO_OFFSET = 6;
if (numSamplesDelay > 0) {
// if there was a sample delay for this buffer, we need to pull samples prior to the nextOutput
// to stick at the beginning

View file

@ -90,12 +90,12 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
switch (packetArrivalInfo._status) {
case SequenceNumberStats::Early: {
int packetsLost = packetArrivalInfo._seqDiffFromExpected;
avatarRingBuffer->parseData(packet, packetsLost);
avatarRingBuffer->parseDataAndHandleDroppedPackets(packet, packetsLost);
break;
}
case SequenceNumberStats::OnTime: {
// ask the AvatarAudioRingBuffer instance to parse the data
avatarRingBuffer->parseData(packet);
avatarRingBuffer->parseDataAndHandleDroppedPackets(packet, 0);
break;
}
default: {
@ -134,12 +134,12 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
switch (packetArrivalInfo._status) {
case SequenceNumberStats::Early: {
int packetsLost = packetArrivalInfo._seqDiffFromExpected;
matchingInjectedRingBuffer->parseData(packet, packetsLost);
matchingInjectedRingBuffer->parseDataAndHandleDroppedPackets(packet, packetsLost);
break;
}
case SequenceNumberStats::OnTime: {
// ask the AvatarAudioRingBuffer instance to parse the data
matchingInjectedRingBuffer->parseData(packet);
matchingInjectedRingBuffer->parseDataAndHandleDroppedPackets(packet, 0);
break;
}
default: {

View file

@ -18,7 +18,7 @@ AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo, bool dynamicJitterBu
}
int AvatarAudioRingBuffer::parseData(const QByteArray& packet, int packetsSkipped) {
int AvatarAudioRingBuffer::parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) {
frameReceivedUpdateTimingStats();
_shouldLoopbackForNode = (packetTypeForPacket(packet) == PacketTypeMicrophoneAudioWithEcho);

View file

@ -20,7 +20,7 @@ class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
public:
AvatarAudioRingBuffer(bool isStereo = false, bool dynamicJitterBuffer = false);
int parseData(const QByteArray& packet, int packetsSkipped = 0);
int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped);
private:
// disallow copying of AvatarAudioRingBuffer objects
AvatarAudioRingBuffer(const AvatarAudioRingBuffer&);

View file

@ -0,0 +1,27 @@
#
# HifiLibrarySearchHints.cmake
#
# Created by Stephen Birarda on July 24th, 2014
# Copyright 2014 High Fidelity, Inc.
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(HIFI_LIBRARY_SEARCH_HINTS LIBRARY_FOLDER)
string(TOUPPER ${LIBRARY_FOLDER} LIBRARY_PREFIX)
set(${LIBRARY_PREFIX}_SEARCH_DIRS "")
if (${LIBRARY_PREFIX}_ROOT_DIR)
set(${LIBRARY_PREFIX}_SEARCH_DIRS "${${LIBRARY_PREFIX}_ROOT_DIR}")
endif ()
if (DEFINED ENV{${LIBRARY_PREFIX}_ROOT_DIR})
set(${LIBRARY_PREFIX}_SEARCH_DIRS "${${LIBRARY_PREFIX}_SEARCH_DIRS}" "$ENV{${LIBRARY_PREFIX}_ROOT_DIR}")
endif ()
if (DEFINED ENV{HIFI_LIB_DIR})
set(${LIBRARY_PREFIX}_SEARCH_DIRS "${${LIBRARY_PREFIX}_SEARCH_DIRS}" "$ENV{HIFI_LIB_DIR}/${LIBRARY_FOLDER}")
endif ()
endmacro(HIFI_LIBRARY_SEARCH_HINTS _library_folder)

View file

@ -18,7 +18,8 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(FACESHIFT_SEARCH_DIRS "${FACESHIFT_ROOT_DIR}" "$ENV{FACESHIFT_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/faceshift")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("faceshift")
find_path(FACESHIFT_INCLUDE_DIRS fsbinarystream.h PATH_SUFFIXES include HINTS ${FACESHIFT_SEARCH_DIRS})
@ -41,4 +42,4 @@ set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FACESHIFT DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES)
mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS)

View file

@ -19,12 +19,13 @@
#
if (WIN32)
set(WIN_GLEW_SEARCH_DIRS "${GLEW_ROOT_DIR}" "$ENV{GLEW_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/glew")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("glew")
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${WIN_GLEW_SEARCH_DIRS})
find_path(GLEW_INCLUDE_DIRS GL/glew.h PATH_SUFFIXES include HINTS ${GLEW_SEARCH_DIRS})
find_library(GLEW_LIBRARY_RELEASE glew32s PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${WIN_GLEW_SEARCH_DIRS})
find_library(GLEW_LIBRARY_DEBUG glew32s PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${WIN_GLEW_SEARCH_DIRS})
find_library(GLEW_LIBRARY_RELEASE glew32s PATH_SUFFIXES "lib/Release/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
find_library(GLEW_LIBRARY_DEBUG glew32s PATH_SUFFIXES "lib/Debug/Win32" "lib" HINTS ${GLEW_SEARCH_DIRS})
include(SelectLibraryConfigurations)
select_library_configurations(GLEW)
@ -35,4 +36,4 @@ set(GLEW_LIBRARIES "${GLEW_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
mark_as_advanced(GLEW_INCLUDE_DIRS GLEW_LIBRARIES)
mark_as_advanced(GLEW_INCLUDE_DIRS GLEW_LIBRARIES GLEW_SEARCH_DIRS)

View file

@ -14,13 +14,14 @@
#
# setup hints for GLM search
set(GLM_HEADER_SEARCH_HINTS "${GLM_ROOT_DIR}" "$ENV{GLM_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/glm")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("glm")
# locate header
find_path(GLM_INCLUDE_DIR "glm/glm.hpp" HINTS ${GLM_HEADER_SEARCH_HINTS})
find_path(GLM_INCLUDE_DIR "glm/glm.hpp" HINTS ${GLM_SEARCH_DIRS})
set(GLM_INCLUDE_DIRS "${GLM_INCLUDE_DIR}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLM DEFAULT_MSG GLM_INCLUDE_DIRS)
mark_as_advanced(GLM_INCLUDE_DIRS)
mark_as_advanced(GLM_INCLUDE_DIRS GLM_SEARCH_DIRS)

View file

@ -18,16 +18,17 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(GLUT_HINT_DIRS "${GLUT_ROOT_DIR}" "$ENV{GLUT_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/freeglut")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("freeglut")
if (WIN32)
set(GLUT_HINT_DIRS "${GLUT_HINT_DIRS}" "${OPENGL_INCLUDE_DIR}")
set(GLUT_HINT_DIRS "${FREEGLUT_SEARCH_DIRS} ${OPENGL_INCLUDE_DIR}")
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${GLUT_HINT_DIRS})
find_library(GLUT_LIBRARY freeglut PATH_SUFFIXES lib HINTS ${GLUT_HINT_DIRS})
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
find_library(GLUT_LIBRARY freeglut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
else ()
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${GLUT_HINT_DIRS})
find_library(GLUT_LIBRARY glut PATH_SUFFIXES lib HINTS ${GLUT_HINT_DIRS})
find_path(GLUT_INCLUDE_DIRS GL/glut.h PATH_SUFFIXES include HINTS ${FREEGLUT_SEARCH_DIRS})
find_library(GLUT_LIBRARY glut PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
endif ()
include(FindPackageHandleStandardArgs)
@ -35,12 +36,12 @@ include(FindPackageHandleStandardArgs)
set(GLUT_LIBRARIES "${GLUT_LIBRARY}" "${XMU_LIBRARY}" "${XI_LIBRARY}")
if (UNIX)
find_library(XI_LIBRARY Xi PATH_SUFFIXES lib HINTS ${GLUT_HINT_DIRS})
find_library(XMU_LIBRARY Xmu PATH_SUFFIXES lib HINTS ${GLUT_HINT_DIRS})
find_library(XI_LIBRARY Xi PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
find_library(XMU_LIBRARY Xmu PATH_SUFFIXES lib HINTS ${FREEGLUT_SEARCH_DIRS})
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES XI_LIBRARY XMU_LIBRARY)
else ()
find_package_handle_standard_args(GLUT DEFAULT_MSG GLUT_INCLUDE_DIRS GLUT_LIBRARIES)
endif ()
mark_as_advanced(GLUT_INCLUDE_DIRS GLUT_LIBRARIES GLUT_LIBRARY XI_LIBRARY XMU_LIBRARY)
mark_as_advanced(GLUT_INCLUDE_DIRS GLUT_LIBRARIES GLUT_LIBRARY XI_LIBRARY XMU_LIBRARY FREEGLUT_SEARCH_DIRS)

View file

@ -12,24 +12,24 @@
# Copyright (c) 2014 High Fidelity
#
set(LEAPMOTION_SEARCH_DIRS "${LEAPMOTION_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/leapmotion")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("leapmotion")
find_path(LEAPMOTION_INCLUDE_DIRS Leap.h PATH_SUFFIXES include HINTS ${LEAPMOTION_SEARCH_DIRS})
if (WIN32)
find_library(LEAPMOTION_LIBRARY_DEBUG "lib/x86/Leapd.lib" HINTS ${LEAPMOTION_SEARCH_DIRS})
find_library(LEAPMOTION_LIBRARY_RELEASE "lib/x86/Leap.lib" HINTS ${LEAPMOTION_SEARCH_DIRS})
endif (WIN32)
if (APPLE)
find_library(LEAPMOTION_LIBRARY_RELEASE "lib/libLeap.dylib" HINTS ${LEAPMOTION_SEARCH_DIRS})
endif (APPLE)
find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS})
elseif (APPLE)
find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib HINTS ${LEAPMOTION_SEARCH_DIRS})
endif ()
include(SelectLibraryConfigurations)
select_library_configurations(LEAPMOTION)
set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBARIES}")
set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LEAPMOTION DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES)
mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS)

View file

@ -18,10 +18,11 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(LIBOVR_SEARCH_DIRS "${LIBOVR_ROOT_DIR}" "$ENV{LIBOVR_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/oculus")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("oculus")
find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS})
find_path(LIBOVR_UTIL_INCLUDE_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS})
find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${OCULUS_SEARCH_DIRS})
find_path(LIBOVR_UTIL_INCLUDE_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCULUS_SEARCH_DIRS})
# add the util include dir to the general include dirs
set(LIBOVR_INCLUDE_DIRS "${LIBOVR_INCLUDE_DIRS}" "${LIBOVR_UTIL_INCLUDE_DIR}")
@ -29,8 +30,8 @@ set(LIBOVR_INCLUDE_DIRS "${LIBOVR_INCLUDE_DIRS}" "${LIBOVR_UTIL_INCLUDE_DIR}")
include(SelectLibraryConfigurations)
if (APPLE)
find_library(LIBOVR_LIBRARY_DEBUG "Lib/MacOS/Debug/libovr.a" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/MacOS/Release/libovr.a" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_DEBUG "Lib/MacOS/Debug/libovr.a" HINTS ${OCULUS_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/MacOS/Release/libovr.a" HINTS ${OCULUS_SEARCH_DIRS})
elseif (UNIX)
find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/)
find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/)
@ -41,15 +42,15 @@ elseif (UNIX)
set(LINUX_ARCH_DIR "x86_64")
endif()
find_library(LIBOVR_LIBRARY_DEBUG "Lib/Linux/Debug/${LINUX_ARCH_DIR}/libovr.a" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/Linux/Release/${LINUX_ARCH_DIR}/libovr.a" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_DEBUG "Lib/Linux/Debug/${LINUX_ARCH_DIR}/libovr.a" HINTS ${OCULUS_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/Linux/Release/${LINUX_ARCH_DIR}/libovr.a" HINTS ${OCULUS_SEARCH_DIRS})
select_library_configurations(UDEV)
select_library_configurations(XINERAMA)
elseif (WIN32)
find_library(LIBOVR_LIBRARY_DEBUG "Lib/Win32/libovrd.lib" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/Win32/libovr.lib" HINTS ${LIBOVR_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_DEBUG "Lib/Win32/libovrd.lib" HINTS ${OCULUS_SEARCH_DIRS})
find_library(LIBOVR_LIBRARY_RELEASE "Lib/Win32/libovr.lib" HINTS ${OCULUS_SEARCH_DIRS})
endif ()
select_library_configurations(LIBOVR)
@ -63,4 +64,4 @@ elseif ()
find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_UTIL_INCLUDE_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY)
endif ()
mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES)
mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS)

View file

@ -46,7 +46,10 @@ if (WIN32)
unset(_programfiles)
set(_OPENSSL_ROOT_HINTS_AND_PATHS HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS})
else ()
set(_OPENSSL_ROOT_HINTS_AND_PATHS ${OPENSSL_ROOT_DIR} $ENV{OPENSSL_ROOT_DIR} $ENV{HIFI_LIB_DIR}/openssl)
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("openssl")
set(_OPENSSL_ROOT_HINTS_AND_PATHS ${OPENSSL_SEARCH_DIRS})
endif ()
find_path(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h HINTS ${_OPENSSL_ROOT_HINTS_AND_PATHS} ${_OPENSSL_INCLUDEDIR} PATH_SUFFIXES include)
@ -228,4 +231,4 @@ else ()
)
endif ()
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES OPENSSL_SEARCH_DIRS)

View file

@ -18,7 +18,8 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(QXMPP_SEARCH_DIRS "${QXMPP_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/qxmpp")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("qxmpp")
find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${QXMPP_SEARCH_DIRS})
@ -33,4 +34,4 @@ set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES)
mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES)
mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS)

View file

@ -18,7 +18,8 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("rtmidi")
find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS})
find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS})
@ -26,4 +27,4 @@ find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEAR
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES)
mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS)

View file

@ -18,7 +18,8 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(SIXENSE_SEARCH_DIRS "${SIXENSE_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/sixense")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("sixense")
find_path(SIXENSE_INCLUDE_DIRS sixense.h PATH_SUFFIXES include HINTS ${SIXENSE_SEARCH_DIRS})
@ -41,4 +42,4 @@ set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SIXENSE DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES)
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS)
mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS)

View file

@ -18,7 +18,8 @@
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
set(VISAGE_SEARCH_DIRS "${VISAGE_ROOT_DIR}" "$ENV{VISAGE_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/visage")
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("visage")
find_path(VISAGE_BASE_INCLUDE_DIR VisageTracker2.h PATH_SUFFIXES include HINTS ${VISAGE_SEARCH_DIRS})
@ -53,5 +54,5 @@ set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISA
mark_as_advanced(
VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES
VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY
VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY VISAGE_SEARCH_DIRS
)

View file

@ -0,0 +1,144 @@
//
// bot_randomExpression.js
// examples
//
// Created by Ben Arnold on 7/23/14.
// Copyright 2014 High Fidelity, Inc.
//
// This is an example script that demonstrates an NPC avatar with
// random facial expressions.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
}
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function printVector(string, vector) {
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
}
var timePassed = 0.0;
var updateSpeed = 3.0;
var X_MIN = 5.0;
var X_MAX = 15.0;
var Z_MIN = 5.0;
var Z_MAX = 15.0;
var Y_PELVIS = 1.0;
// pick an integer between 1 and 100 for the body model for this bot
botNumber = getRandomInt(1, 100);
newFaceFilePrefix = "ron";
newBodyFilePrefix = "bot" + botNumber;
// set the face model fst using the bot number
// there is no need to change the body model - we're using the default
Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newFaceFilePrefix + ".fst";
Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + ".fst";
Avatar.billboardURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/billboards/bot" + botNumber + ".png";
Agent.isAvatar = true;
Agent.isListeningToAudioStream = true;
// change the avatar's position to the random one
Avatar.position = { x: getRandomFloat(X_MIN, X_MAX), y: Y_PELVIS, z: getRandomFloat(Z_MIN, Z_MAX) };;
printVector("New bot, position = ", Avatar.position);
var allBlendShapes = [];
var targetBlendCoefficient = [];
var currentBlendCoefficient = [];
function addBlendShape(s) {
allBlendShapes[allBlendShapes.length] = s;
}
//It is imperative that the following blendshapes are all present and are in the correct order
addBlendShape("EyeBlink_L");
addBlendShape("EyeBlink_R");
addBlendShape("EyeSquint_L");
addBlendShape("EyeSquint_R");
addBlendShape("EyeDown_L");
addBlendShape("EyeDown_R");
addBlendShape("EyeIn_L");
addBlendShape("EyeIn_R");
addBlendShape("EyeOpen_L");
addBlendShape("EyeOpen_R");
addBlendShape("EyeOut_L");
addBlendShape("EyeOut_R");
addBlendShape("EyeUp_L");
addBlendShape("EyeUp_R");
addBlendShape("BrowsD_L");
addBlendShape("BrowsD_R");
addBlendShape("BrowsU_C");
addBlendShape("BrowsU_L");
addBlendShape("BrowsU_R");
addBlendShape("JawFwd");
addBlendShape("JawLeft");
addBlendShape("JawOpen");
addBlendShape("JawChew");
addBlendShape("JawRight");
addBlendShape("MouthLeft");
addBlendShape("MouthRight");
addBlendShape("MouthFrown_L");
addBlendShape("MouthFrown_R");
addBlendShape("MouthSmile_L");
addBlendShape("MouthSmile_R");
addBlendShape("MouthDimple_L");
addBlendShape("MouthDimple_R");
addBlendShape("LipsStretch_L");
addBlendShape("LipsStretch_R");
addBlendShape("LipsUpperClose");
addBlendShape("LipsLowerClose");
addBlendShape("LipsUpperUp");
addBlendShape("LipsLowerDown");
addBlendShape("LipsUpperOpen");
addBlendShape("LipsLowerOpen");
addBlendShape("LipsFunnel");
addBlendShape("LipsPucker");
addBlendShape("ChinLowerRaise");
addBlendShape("ChinUpperRaise");
addBlendShape("Sneer");
addBlendShape("Puff");
addBlendShape("CheekSquint_L");
addBlendShape("CheekSquint_R");
for (var i = 0; i < allBlendShapes.length; i++) {
targetBlendCoefficient[i] = 0;
currentBlendCoefficient[i] = 0;
}
function setRandomExpression() {
for (var i = 0; i < allBlendShapes.length; i++) {
targetBlendCoefficient[i] = Math.random();
}
}
var expressionChangeSpeed = 0.1;
function updateBlendShapes(deltaTime) {
for (var i = 0; i < allBlendShapes.length; i++) {
currentBlendCoefficient[i] += (targetBlendCoefficient[i] - currentBlendCoefficient[i]) * expressionChangeSpeed;
Avatar.setBlendshape(allBlendShapes[i], currentBlendCoefficient[i]);
}
}
function update(deltaTime) {
timePassed += deltaTime;
if (timePassed > updateSpeed) {
timePassed = 0;
setRandomExpression();
}
updateBlendShapes(deltaTime);
}
Script.update.connect(update);

View file

@ -805,7 +805,7 @@ function mousePressEvent(event) {
}
} else if (browser == toolBar.clicked(clickedOverlay)) {
var url = Window.s3Browse();
var url = Window.s3Browse(".*(fbx|FBX)");
if (url == null || url == "") {
return;
}
@ -1172,7 +1172,6 @@ function handeMenuEvent(menuItem){
angles.z = array[index++].value;
selectedModelProperties.modelRotation = Quat.fromVec3Degrees(angles);
selectedModelProperties.radius = array[index++].value / 2;
print(selectedModelProperties.radius);
Models.editModel(selectedModelID, selectedModelProperties);
}

View file

@ -37,7 +37,7 @@ var WHITE_COLOR = { red: 255, green: 255, blue: 255 };
var MAX_PASTE_VOXEL_SCALE = 256;
var MIN_PASTE_VOXEL_SCALE = .256;
var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting
var zFightingSizeAdjustRatio = 0.004; // used to adjust preview voxels to prevent z fighting
var previewLineWidth = 1.5;
var inspectJsIsRunning = false;
@ -51,7 +51,6 @@ var lastVoxelScale = 0;
var dragStart = { x: 0, y: 0 };
var wheelPixelsMoved = 0;
var mouseX = 0;
var mouseY = 0;
@ -168,7 +167,16 @@ var voxelPreview = Overlays.addOverlay("cube", {
lineWidth: 4
});
var linePreviewTop = Overlays.addOverlay("line3d", {
var linePreviewTop = [];
var linePreviewBottom = [];
var linePreviewLeft = [];
var linePreviewRight = [];
// Currend cursor index
var currentCursor = 0;
function addLineOverlay() {
return Overlays.addOverlay("line3d", {
position: { x: 0, y: 0, z: 0},
end: { x: 0, y: 0, z: 0},
color: { red: 255, green: 255, blue: 255},
@ -176,34 +184,24 @@ var linePreviewTop = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: previewLineWidth
});
}
//Cursor line previews for up to three cursors
linePreviewTop[0] = addLineOverlay();
linePreviewTop[1] = addLineOverlay();
linePreviewTop[2] = addLineOverlay();
var linePreviewBottom = Overlays.addOverlay("line3d", {
position: { x: 0, y: 0, z: 0},
end: { x: 0, y: 0, z: 0},
color: { red: 255, green: 255, blue: 255},
alpha: 1,
visible: false,
lineWidth: previewLineWidth
});
var linePreviewLeft = Overlays.addOverlay("line3d", {
position: { x: 0, y: 0, z: 0},
end: { x: 0, y: 0, z: 0},
color: { red: 255, green: 255, blue: 255},
alpha: 1,
visible: false,
lineWidth: previewLineWidth
});
var linePreviewRight = Overlays.addOverlay("line3d", {
position: { x: 0, y: 0, z: 0},
end: { x: 0, y: 0, z: 0},
color: { red: 255, green: 255, blue: 255},
alpha: 1,
visible: false,
lineWidth: previewLineWidth
});
linePreviewBottom[0] = addLineOverlay();
linePreviewBottom[1] = addLineOverlay();
linePreviewBottom[2] = addLineOverlay();
linePreviewLeft[0] = addLineOverlay();
linePreviewLeft[1] = addLineOverlay();
linePreviewLeft[2] = addLineOverlay();
linePreviewRight[0] = addLineOverlay();
linePreviewRight[1] = addLineOverlay();
linePreviewRight[2] = addLineOverlay();
// these will be used below
var scaleSelectorWidth = 144;
@ -698,79 +696,99 @@ function calculateVoxelFromIntersection(intersection, operation) {
if (wantDebug) {
print("wantAddAdjust="+wantAddAdjust);
}
var zFightingSizeAdjust = zFightingSizeAdjustRatio * intersection.distance;
// now we also want to calculate the "edge square" for the face for this voxel
if (intersection.face == "MIN_X_FACE") {
highlightAt.x = x - zFightingSizeAdjust;
highlightAt.y = y + zFightingSizeAdjust;
highlightAt.z = z + zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.x -= voxelSize;
}
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize };
} else if (intersection.face == "MAX_X_FACE") {
highlightAt.x = x + voxelSize + zFightingSizeAdjust;
highlightAt.y = y + zFightingSizeAdjust;
highlightAt.z = z + zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.x += resultVoxel.s;
}
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize };
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize };
} else if (intersection.face == "MIN_Y_FACE") {
highlightAt.x = x + zFightingSizeAdjust;
highlightAt.y = y - zFightingSizeAdjust;
highlightAt.z = z + zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.y -= voxelSize;
}
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
resultVoxel.topRight = {x: highlightAt.x , y: highlightAt.y, z: highlightAt.z };
resultVoxel.topLeft = {x: highlightAt.x + voxelSize, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomRight = {x: highlightAt.x , y: highlightAt.y, z: highlightAt.z + voxelSize };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z + voxelSize };
} else if (intersection.face == "MAX_Y_FACE") {
highlightAt.x = x + zFightingSizeAdjust;
highlightAt.y = y + voxelSize + zFightingSizeAdjust;
highlightAt.z = z + zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.y += voxelSize;
}
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust};
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust};
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust};
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize, y: highlightAt.y, z: highlightAt.z};
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize};
resultVoxel.topLeft = {x: highlightAt.x + voxelSize, y: highlightAt.y, z: highlightAt.z + voxelSize};
} else if (intersection.face == "MIN_Z_FACE") {
highlightAt.x = x + zFightingSizeAdjust;
highlightAt.y = y + zFightingSizeAdjust;
highlightAt.z = z - zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.z -= voxelSize;
}
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z};
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z };
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z};
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize, y: highlightAt.y, z: highlightAt.z};
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
resultVoxel.topLeft = {x: highlightAt.x + voxelSize, y: highlightAt.y + voxelSize, z: highlightAt.z};
} else if (intersection.face == "MAX_Z_FACE") {
highlightAt.x = x + zFightingSizeAdjust;
highlightAt.y = y + zFightingSizeAdjust;
highlightAt.z = z + voxelSize + zFightingSizeAdjust;
voxelSize -= 2 * zFightingSizeAdjust;
if (wantAddAdjust) {
resultVoxel.z += voxelSize;
}
resultVoxel.bottomLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z };
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z};
resultVoxel.topLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z };
resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z};
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z };
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize, y: highlightAt.y, z: highlightAt.z};
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z };
resultVoxel.topRight = {x: highlightAt.x + voxelSize, y: highlightAt.y + voxelSize, z: highlightAt.z};
}
@ -809,21 +827,21 @@ function showPreviewLines() {
var pasteVoxel = getNewPasteVoxel(pickRay);
// X axis
Overlays.editOverlay(linePreviewBottom, {
Overlays.editOverlay(linePreviewBottom[currentCursor], {
position: pasteVoxel.origin,
end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z },
visible: true
});
// Y axis
Overlays.editOverlay(linePreviewRight, {
Overlays.editOverlay(linePreviewRight[currentCursor], {
position: pasteVoxel.origin,
end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z },
visible: true
});
// Z axis
Overlays.editOverlay(linePreviewTop, {
Overlays.editOverlay(linePreviewTop[currentCursor], {
position: pasteVoxel.origin,
end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize },
visible: true
@ -837,22 +855,22 @@ function showPreviewLines() {
if (intersection.intersects) {
resultVoxel = calculateVoxelFromIntersection(intersection,"");
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
Overlays.editOverlay(linePreviewTop[currentCursor], { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
Overlays.editOverlay(linePreviewBottom[currentCursor], { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
Overlays.editOverlay(linePreviewLeft[currentCursor], { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
Overlays.editOverlay(linePreviewRight[currentCursor], { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
colors[0] = {red: intersection.voxel.red, green: intersection.voxel.green , blue: intersection.voxel.blue };
if (copyScale) {
scaleSelector.setScale(intersection.voxel.s);
}
moveTools();
} else {
} else if (intersection.accurate) {
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { visible: false });
Overlays.editOverlay(linePreviewBottom, { visible: false });
Overlays.editOverlay(linePreviewLeft, { visible: false });
Overlays.editOverlay(linePreviewRight, { visible: false });
Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false });
}
}
@ -862,20 +880,20 @@ function showPreviewGuides() {
showPreviewVoxel();
// make sure alternative is hidden
Overlays.editOverlay(linePreviewTop, { visible: false });
Overlays.editOverlay(linePreviewBottom, { visible: false });
Overlays.editOverlay(linePreviewLeft, { visible: false });
Overlays.editOverlay(linePreviewRight, { visible: false });
Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false });
} else {
showPreviewLines();
}
} else {
// make sure all previews are off
Overlays.editOverlay(voxelPreview, { visible: false });
Overlays.editOverlay(linePreviewTop, { visible: false });
Overlays.editOverlay(linePreviewBottom, { visible: false });
Overlays.editOverlay(linePreviewLeft, { visible: false });
Overlays.editOverlay(linePreviewRight, { visible: false });
Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false });
Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false });
}
}
@ -968,6 +986,14 @@ function mousePressEvent(event) {
return;
}
if (event.deviceID == 1500) { // Left Hydra Controller
currentCursor = 0;
} else if (event.deviceID == 1501) { // Right Hydra Controller
currentCursor = 1;
} else {
currentCursor = 2;
}
var clickedOnSomething = false;
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
@ -1220,11 +1246,16 @@ function menuItemEvent(menuItem) {
}
function mouseMoveEvent(event) {
if (!editToolsOn) {
return;
if (!editToolsOn || inspectJsIsRunning) {
return;
}
if (inspectJsIsRunning) {
return;
if (event.deviceID == 1500) { // Left Hydra Controller
currentCursor = 0;
} else if (event.deviceID == 1501) { // Right Hydra Controller
currentCursor = 1;
} else {
currentCursor = 2;
}
// Move Import Preview
@ -1475,10 +1506,12 @@ Controller.captureKeyEvents({ text: "-" });
function scriptEnding() {
Overlays.deleteOverlay(voxelPreview);
Overlays.deleteOverlay(linePreviewTop);
Overlays.deleteOverlay(linePreviewBottom);
Overlays.deleteOverlay(linePreviewLeft);
Overlays.deleteOverlay(linePreviewRight);
for (var i = 0; i < linePreviewTop.length; i++) {
Overlays.deleteOverlay(linePreviewTop[i]);
Overlays.deleteOverlay(linePreviewBottom[i]);
Overlays.deleteOverlay(linePreviewLeft[i]);
Overlays.deleteOverlay(linePreviewRight[i]);
}
for (s = 0; s < numColors; s++) {
Overlays.deleteOverlay(swatches[s]);
}

23
examples/laserPointer.js Normal file
View file

@ -0,0 +1,23 @@
//
// laserPointer.js
// examples
//
// Created by Clément Brisset on 7/18/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var LEFT = 0;
var RIGHT = 1;
var LEFT_HAND_FLAG = 1;
var RIGHT_HAND_FLAG = 2;
function update() {
var state = ((Controller.getTriggerValue(LEFT) > 0.9) ? LEFT_HAND_FLAG : 0) +
((Controller.getTriggerValue(RIGHT) > 0.9) ? RIGHT_HAND_FLAG : 0);
MyAvatar.setHandState(state);
}
Script.update.connect(update);

View file

@ -12,15 +12,15 @@ project(${TARGET_NAME})
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
set(FACEPLUS_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/faceplus")
set(FACESHIFT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/faceshift")
set(LIBOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/oculus")
set(PRIOVR_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/priovr")
set(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/sixense")
set(VISAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/visage")
set(LEAPMOTION_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/leapmotion")
set(RTMIDI_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/rtmidi")
# set a default root dir for each of our optional externals if it was not passed
set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp")
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)
if (NOT ${UPPER_EXTERNAL}_ROOT_DIR)
set(${UPPER_EXTERNAL}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${EXTERNAL}")
endif ()
endforeach()
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5LinguistToolsMacros)
@ -134,105 +134,54 @@ find_package(Qxmpp)
find_package(RtMidi)
find_package(OpenSSL REQUIRED)
# include the Sixense library for Razer Hydra if available
if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
add_definitions(-DHAVE_SIXENSE)
include_directories(SYSTEM "${SIXENSE_INCLUDE_DIRS}")
if (APPLE OR UNIX)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}")
endif (APPLE OR UNIX)
target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES})
endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE)
# likewise with Visage library for webcam feature tracking
if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
add_definitions(-DHAVE_VISAGE -DVISAGE_STATIC)
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
if (APPLE)
add_definitions(-DMAC_OS_X)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
include_directories(SYSTEM "${VISAGE_INCLUDE_DIRS}")
find_library(AVFoundation AVFoundation)
find_library(CoreMedia CoreMedia)
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
endif (APPLE)
target_link_libraries(${TARGET_NAME} "${VISAGE_LIBRARIES}")
endif (VISAGE_FOUND AND NOT DISABLE_VISAGE)
# and with Faceplus library, also for webcam feature tracking
if (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
add_definitions(-DHAVE_FACEPLUS)
include_directories(SYSTEM "${FACEPLUS_INCLUDE_DIRS}")
target_link_libraries(${TARGET_NAME} "${FACEPLUS_LIBRARIES}")
endif (FACEPLUS_FOUND AND NOT DISABLE_FACEPLUS)
# and with LibOVR for Oculus Rift
if (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
add_definitions(-DHAVE_LIBOVR)
include_directories(SYSTEM ${LIBOVR_INCLUDE_DIRS})
# perform standard include and linking for found externals
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL)
if (APPLE)
foreach(LIBOVR_DIR ${LIBOVR_INCLUDE_DIRS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LIBOVR_DIR}")
endforeach()
if (${UPPER_EXTERNAL} MATCHES "OCULUS")
# the oculus directory is named OCULUS and not LIBOVR so hack to fix that here
set(UPPER_EXTERNAL "LIBOVR")
endif ()
target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
endif (LIBOVR_FOUND AND NOT DISABLE_LIBOVR)
# and with PrioVR library
if (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
add_definitions(-DHAVE_PRIOVR)
include_directories(SYSTEM "${PRIOVR_INCLUDE_DIRS}")
target_link_libraries(${TARGET_NAME} "${PRIOVR_LIBRARIES}")
endif (PRIOVR_FOUND AND NOT DISABLE_PRIOVR)
# and with LeapMotion library
if (LEAPMOTION_FOUND AND NOT DISABLE_LEAPMOTION)
add_definitions(-DHAVE_LEAPMOTION)
include_directories(SYSTEM "${LEAPMOTION_INCLUDE_DIRS}")
if (${UPPER_EXTERNAL}_FOUND AND NOT DISABLE_${UPPER_EXTERNAL})
add_definitions(-DHAVE_${UPPER_EXTERNAL})
# include the library directories (ignoring warnings)
include_directories(SYSTEM ${${UPPER_EXTERNAL}_INCLUDE_DIRS})
# perform the system include hack for OS X to ignore warnings
if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${LEAPMOTION_INCLUDE_DIRS}")
foreach(EXTERNAL_INCLUDE_DIR ${${UPPER_EXTERNAL}_INCLUDE_DIRS})
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}")
endforeach()
endif ()
target_link_libraries(${TARGET_NAME} ${LEAPMOTION_LIBRARIES})
endif (LEAPMOTION_FOUND AND NOT DISABLE_LEAPMOTION)
target_link_libraries(${TARGET_NAME} ${${UPPER_EXTERNAL}_LIBRARIES})
endif ()
endforeach()
# and with SDL for joysticks
if (SDL_FOUND AND NOT DISABLE_SDL)
add_definitions(-DHAVE_SDL)
include_directories(SYSTEM "${SDL_INCLUDE_DIR}")
target_link_libraries(${TARGET_NAME} "${SDL_LIBRARY}")
endif (SDL_FOUND AND NOT DISABLE_SDL)
# special APPLE modifications for Visage library
if (VISAGE_FOUND AND NOT DISABLE_VISAGE AND APPLE)
add_definitions(-DMAC_OS_X)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-comment")
find_library(AVFoundation AVFoundation)
find_library(CoreMedia CoreMedia)
find_library(NEW_STD_LIBRARY libc++.dylib /usr/lib/)
target_link_libraries(${TARGET_NAME} ${AVFoundation} ${CoreMedia} ${NEW_STD_LIBRARY})
endif ()
# and with qxmpp for chat
if (QXMPP_FOUND AND NOT DISABLE_QXMPP)
add_definitions(-DHAVE_QXMPP -DQXMPP_STATIC)
include_directories(SYSTEM "${QXMPP_INCLUDE_DIRS}")
# special OS X modifications for RtMidi library
if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE)
find_library(CoreMIDI CoreMIDI)
add_definitions(-D__MACOSX_CORE__)
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
endif ()
target_link_libraries(${TARGET_NAME} ${QXMPP_LIBRARIES})
endif (QXMPP_FOUND AND NOT DISABLE_QXMPP)
# and with RtMidi for RtMidi control
if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI)
add_definitions(-DHAVE_RTMIDI)
include_directories(SYSTEM "${RTMIDI_INCLUDE_DIRS}")
target_link_libraries(${TARGET_NAME} ${RTMIDI_LIBRARIES})
if (APPLE)
find_library(CoreMIDI CoreMIDI)
add_definitions(-D__MACOSX_CORE__)
target_link_libraries(${TARGET_NAME} ${CoreMIDI})
endif()
endif()
# and with Faceshift for depth camera face tracking
if (FACESHIFT_FOUND AND NOT DISABLE_FACESHIFT)
add_definitions(-DHAVE_FACESHIFT)
include_directories(SYSTEM "${FACESHIFT_INCLUDE_DIRS}")
target_link_libraries(${TARGET_NAME} ${FACESHIFT_LIBRARIES})
endif()
if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32)
# assume we're linking a static Qt on windows
add_definitions(-DQXMPP_STATIC)
endif ()
# include headers for interface and InterfaceConfig.
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")

View file

@ -524,8 +524,8 @@ void Application::initializeGL() {
// Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large
// field of view and near and far clip to make it interesting.
//viewFrustumOffsetCamera.setFieldOfView(90.0);
_viewFrustumOffsetCamera.setNearClip(0.1f);
_viewFrustumOffsetCamera.setFarClip(500.0f * TREE_SCALE);
_viewFrustumOffsetCamera.setNearClip(DEFAULT_NEAR_CLIP);
_viewFrustumOffsetCamera.setFarClip(DEFAULT_FAR_CLIP);
initDisplay();
qDebug( "Initialized Display.");
@ -592,7 +592,7 @@ void Application::paintGL() {
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
_myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
_myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition());
_myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
@ -611,10 +611,10 @@ void Application::paintGL() {
if (OculusManager::isConnected()) {
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
_myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
_myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0));
} else {
_myCamera.setTightness(0.0f);
glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition();
glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition();
float headHeight = eyePosition.y - _myAvatar->getPosition().y;
_myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
_myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0));
@ -1911,17 +1911,9 @@ void Application::updateMyAvatarLookAtPosition() {
}
} else {
// I am not looking at anyone else, so just look forward
lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() +
lookAtSpot = _myAvatar->getHead()->getEyePosition() +
(_myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.f, 0.f, -TREE_SCALE));
}
// TODO: Add saccade to mouse pointer when stable, IF not looking at someone (since we know we are looking at it)
/*
const float FIXED_MIN_EYE_DISTANCE = 0.3f;
float minEyeDistance = FIXED_MIN_EYE_DISTANCE + (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON ? 0.0f :
glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition()));
lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance);
*/
}
//
// Deflect the eyes a bit to match the detected Gaze from 3D camera if active
@ -1931,7 +1923,7 @@ void Application::updateMyAvatarLookAtPosition() {
float eyeYaw = tracker->getEstimatedEyeYaw();
const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f;
// deflect using Faceshift gaze data
glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition();
glm::vec3 origin = _myAvatar->getHead()->getEyePosition();
float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
float deflection = Menu::getInstance()->getFaceshiftEyeDeflection();
if (isLookingAtSomeone) {
@ -2935,7 +2927,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_mirrorCamera.setTargetPosition(glm::vec3());
} else {
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition());
}
}
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
@ -2964,7 +2956,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_myAvatar->getSkeletonModel().getNeckPosition(neckPosition);
// get the eye position relative to the body
glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition();
glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition();
float eyeHeight = eyePosition.y - _myAvatar->getPosition().y;
// set the translation of the face relative to the neck position
@ -3355,7 +3347,7 @@ void Application::nodeKilled(SharedNodePointer node) {
_modelEditSender.nodeKilled(node);
if (node->getType() == NodeType::AudioMixer) {
QMetaObject::invokeMethod(&_audio, "resetIncomingMixedAudioSequenceNumberStats");
QMetaObject::invokeMethod(&_audio, "audioMixerKilled");
}
if (node->getType() == NodeType::VoxelServer) {
@ -3641,7 +3633,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript
scriptEngine->getModelsScriptingInterface()->setModelTree(_models.getTree());
// model has some custom types
Model::registerMetaTypes(scriptEngine->getEngine());
Model::registerMetaTypes(scriptEngine);
// hook our avatar object into this script engine
scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features

View file

@ -43,6 +43,7 @@
#include "Audio.h"
#include "Menu.h"
#include "Util.h"
#include "AudioRingBuffer.h"
static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0;
@ -125,14 +126,16 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
_scopeInput(0),
_scopeOutputLeft(0),
_scopeOutputRight(0),
_statsEnabled(false),
_starveCount(0),
_consecutiveNotMixedCount(0),
_outgoingAvatarAudioSequenceNumber(0),
_incomingMixedAudioSequenceNumberStats(INCOMING_SEQ_STATS_HISTORY_LENGTH),
_interframeTimeGapStats(TIME_GAPS_STATS_INTERVAL_SAMPLES, TIME_GAP_STATS_WINDOW_INTERVALS),
_inputRingBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
_audioInputMsecsReadStats(MSECS_PER_SECOND / (float)AUDIO_CALLBACK_MSECS * CALLBACK_ACCELERATOR_RATIO, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
_inputRingBufferMsecsAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
_outputRingBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS),
_audioOutputBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS)
_audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS)
{
// clear the array of locally injected samples
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
@ -148,15 +151,34 @@ void Audio::init(QGLWidget *parent) {
void Audio::reset() {
_ringBuffer.reset();
// we don't want to reset seq numbers when space-bar reset occurs.
//_outgoingAvatarAudioSequenceNumber = 0;
resetStats();
}
void Audio::resetStats() {
_starveCount = 0;
_consecutiveNotMixedCount = 0;
_audioMixerAvatarStreamAudioStats = AudioStreamStats();
_audioMixerInjectedStreamAudioStatsMap.clear();
//_outgoingAvatarAudioSequenceNumber = 0;
_incomingMixedAudioSequenceNumberStats.reset();
_interframeTimeGapStats.reset();
_audioInputMsecsReadStats.reset();
_inputRingBufferMsecsAvailableStats.reset();
_outputRingBufferFramesAvailableStats.reset();
_audioOutputMsecsUnplayedStats.reset();
}
void Audio::audioMixerKilled() {
_outgoingAvatarAudioSequenceNumber = 0;
resetStats();
}
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
@ -499,8 +521,11 @@ void Audio::handleAudioInput() {
}
_inputRingBuffer.writeData(inputByteArray.data(), inputByteArray.size());
float audioInputMsecsRead = inputByteArray.size() / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
_audioInputMsecsReadStats.update(audioInputMsecsRead);
while (_inputRingBuffer.samplesAvailable() > inputSamplesRequired) {
while (_inputRingBuffer.samplesAvailable() >= inputSamplesRequired) {
int16_t* inputAudioSamples = new int16_t[inputSamplesRequired];
_inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired);
@ -811,11 +836,12 @@ AudioStreamStats Audio::getDownstreamAudioStreamStats() const {
void Audio::sendDownstreamAudioStatsPacket() {
_inputRingBufferFramesAvailableStats.update(getInputRingBufferFramesAvailable());
// since this function is called every second, we'll sample some of our stats here
_inputRingBufferMsecsAvailableStats.update(getInputRingBufferMsecsAvailable());
// since this function is called every second, we'll sample the number of audio frames available here.
_outputRingBufferFramesAvailableStats.update(_ringBuffer.framesAvailable());
_audioOutputBufferFramesAvailableStats.update(getOutputRingBufferFramesAvailable());
_audioOutputMsecsUnplayedStats.update(getAudioOutputMsecsUnplayed());
// push the current seq number stats into history, which moves the history window forward 1s
// (since that's how often pushStatsToHistory() is called)
@ -1286,6 +1312,10 @@ void Audio::toggleScopePause() {
_scopeEnabledPause = !_scopeEnabledPause;
}
void Audio::toggleStats() {
_statsEnabled = !_statsEnabled;
}
void Audio::selectAudioScopeFiveFrames() {
if (Menu::getInstance()->isOptionChecked(MenuOption::AudioScopeFiveFrames)) {
reallocateScope(5);
@ -1365,6 +1395,174 @@ void Audio::addBufferToScope(
}
}
void Audio::renderStats(const float* color, int width, int height) {
if (!_statsEnabled) {
return;
}
const int LINES_WHEN_CENTERED = 30;
const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * LINES_WHEN_CENTERED;
int lines = _audioMixerInjectedStreamAudioStatsMap.size() * 7 + 23;
int statsHeight = STATS_HEIGHT_PER_LINE * lines;
static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f };
int x = std::max((width - (int)STATS_WIDTH) / 2, 0);
int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0);
int w = STATS_WIDTH;
int h = statsHeight;
renderBackground(backgroundColor, x, y, w, h);
int horizontalOffset = x + 5;
int verticalOffset = y;
float scale = 0.10f;
float rotation = 0.0f;
int font = 2;
char latencyStatString[512];
const float BUFFER_SEND_INTERVAL_MSECS = BUFFER_SEND_INTERVAL_USECS / (float)USECS_PER_MSEC;
float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f;
SharedNodePointer audioMixerNodePointer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer);
if (!audioMixerNodePointer.isNull()) {
audioInputBufferLatency = _audioInputMsecsReadStats.getWindowAverage();
inputRingBufferLatency = getInputRingBufferAverageMsecsAvailable();
networkRoundtripLatency = audioMixerNodePointer->getPingMs();
mixerRingBufferLatency = _audioMixerAvatarStreamAudioStats._ringBufferFramesAvailableAverage * BUFFER_SEND_INTERVAL_MSECS;
outputRingBufferLatency = _outputRingBufferFramesAvailableStats.getWindowAverage() * BUFFER_SEND_INTERVAL_MSECS;
audioOutputBufferLatency = _audioOutputMsecsUnplayedStats.getWindowAverage();
}
float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency;
sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color);
verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
char downstreamLabelString[] = "Downstream mixed audio stats:";
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color);
renderAudioStreamStats(getDownstreamAudioStreamStats(), horizontalOffset, verticalOffset, scale, rotation, font, color, true);
verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
char upstreamMicLabelString[] = "Upstream mic audio stats:";
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color);
renderAudioStreamStats(_audioMixerAvatarStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color);
foreach(const AudioStreamStats& injectedStreamAudioStats, _audioMixerInjectedStreamAudioStatsMap) {
verticalOffset += STATS_HEIGHT_PER_LINE; // blank line
char upstreamInjectedLabelString[512];
sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s",
injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data());
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color);
renderAudioStreamStats(injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color);
}
}
void Audio::renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset,
float scale, float rotation, int font, const float* color, bool isDownstreamStats) {
char stringBuffer[512];
sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)",
streamStats._packetStreamStats.getLostRate() * 100.0f,
streamStats._packetStreamStats._numLost,
streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
streamStats._packetStreamWindowStats._numLost);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
if (isDownstreamStats) {
const float BUFFER_SEND_INTERVAL_MSECS = BUFFER_SEND_INTERVAL_USECS / (float)USECS_PER_MSEC;
sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d",
streamStats._ringBufferDesiredJitterBufferFrames,
streamStats._ringBufferFramesAvailableAverage,
(int)(getAudioOutputAverageMsecsUnplayed() / BUFFER_SEND_INTERVAL_MSECS),
streamStats._ringBufferFramesAvailable,
(int)(getAudioOutputMsecsUnplayed() / BUFFER_SEND_INTERVAL_MSECS));
} else {
sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u",
streamStats._ringBufferDesiredJitterBufferFrames,
streamStats._ringBufferFramesAvailableAverage,
streamStats._ringBufferFramesAvailable);
}
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u",
streamStats._ringBufferStarveCount,
streamStats._ringBufferConsecutiveNotMixedCount,
streamStats._ringBufferSilentFramesDropped,
streamStats._ringBufferOverflowCount);
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s",
formatUsecTime(streamStats._timeGapMin).toLatin1().data(),
formatUsecTime(streamStats._timeGapMax).toLatin1().data(),
formatUsecTime(streamStats._timeGapAverage).toLatin1().data());
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s",
formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(),
formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(),
formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data());
verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);
}
void Audio::renderScope(int width, int height) {
if (!_scopeEnabled)
@ -1622,15 +1820,14 @@ int Audio::calculateNumberOfFrameSamples(int numBytes) const {
return frameSamples;
}
int Audio::getOutputRingBufferFramesAvailable() const {
float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float)_outputFormat.sampleRate())
* (_desiredOutputFormat.channelCount() / (float)_outputFormat.channelCount());
return (_audioOutput->bufferSize() - _audioOutput->bytesFree()) * networkOutputToOutputRatio
/ (sizeof(int16_t) * _ringBuffer.getNumFrameSamples());
float Audio::getAudioOutputMsecsUnplayed() const {
int bytesAudioOutputUnplayed = _audioOutput->bufferSize() - _audioOutput->bytesFree();
float msecsAudioOutputUnplayed = bytesAudioOutputUnplayed / (float)_outputFormat.bytesForDuration(USECS_PER_MSEC);
return msecsAudioOutputUnplayed;
}
int Audio::getInputRingBufferFramesAvailable() const {
float inputToNetworkInputRatio = calculateDeviceToNetworkInputRatio(_numInputCallbackBytes);
return _inputRingBuffer.samplesAvailable() / inputToNetworkInputRatio / _inputRingBuffer.getNumFrameSamples();
float Audio::getInputRingBufferMsecsAvailable() const {
int bytesInInputRingBuffer = _inputRingBuffer.samplesAvailable() * sizeof(int16_t);
float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC));
return msecsInInputRingBuffer;
}

View file

@ -71,6 +71,7 @@ public:
void renderToolBox(int x, int y, bool boxed);
void renderScope(int width, int height);
void renderStats(const float* color, int width, int height);
int getNetworkSampleRate() { return SAMPLE_RATE; }
int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; }
@ -78,12 +79,12 @@ public:
bool getProcessSpatialAudio() const { return _processSpatialAudio; }
const SequenceNumberStats& getIncomingMixedAudioSequenceNumberStats() const { return _incomingMixedAudioSequenceNumberStats; }
float getInputRingBufferMsecsAvailable() const;
float getInputRingBufferAverageMsecsAvailable() const { return (float)_inputRingBufferMsecsAvailableStats.getWindowAverage(); }
int getInputRingBufferFramesAvailable() const;
int getInputRingBufferAverageFramesAvailable() const { return (int)_inputRingBufferFramesAvailableStats.getWindowAverage(); }
int getOutputRingBufferFramesAvailable() const;
int getOutputRingBufferAverageFramesAvailable() const { return (int)_audioOutputBufferFramesAvailableStats.getWindowAverage(); }
float getAudioOutputMsecsUnplayed() const;
float getAudioOutputAverageMsecsUnplayed() const { return (float)_audioOutputMsecsUnplayedStats.getWindowAverage(); }
public slots:
void start();
@ -93,12 +94,14 @@ public slots:
void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples);
void handleAudioInput();
void reset();
void resetIncomingMixedAudioSequenceNumberStats() { _incomingMixedAudioSequenceNumberStats.reset(); }
void resetStats();
void audioMixerKilled();
void toggleMute();
void toggleAudioNoiseReduction();
void toggleToneInjection();
void toggleScope();
void toggleScopePause();
void toggleStats();
void toggleAudioSpatialProcessing();
void toggleStereoInput();
void selectAudioScopeFiveFrames();
@ -245,6 +248,10 @@ private:
void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);
void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray);
// audio stats methods for rendering
void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset,
float scale, float rotation, int font, const float* color, bool isDownstreamStats = false);
// Audio scope data
static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5;
@ -261,6 +268,13 @@ private:
QByteArray* _scopeInput;
QByteArray* _scopeOutputLeft;
QByteArray* _scopeOutputRight;
#ifdef _WIN32
static const unsigned int STATS_WIDTH = 1500;
#else
static const unsigned int STATS_WIDTH = 650;
#endif
static const unsigned int STATS_HEIGHT_PER_LINE = 20;
bool _statsEnabled;
int _starveCount;
int _consecutiveNotMixedCount;
@ -273,10 +287,11 @@ private:
MovingMinMaxAvg<quint64> _interframeTimeGapStats;
MovingMinMaxAvg<int> _inputRingBufferFramesAvailableStats;
MovingMinMaxAvg<float> _audioInputMsecsReadStats;
MovingMinMaxAvg<float> _inputRingBufferMsecsAvailableStats;
MovingMinMaxAvg<int> _outputRingBufferFramesAvailableStats;
MovingMinMaxAvg<int> _audioOutputBufferFramesAvailableStats;
MovingMinMaxAvg<float> _audioOutputMsecsUnplayedStats;
};

View file

@ -47,8 +47,8 @@ Camera::Camera() :
_targetPosition(0.0f, 0.0f, 0.0f),
_fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES),
_aspectRatio(16.0f/9.0f),
_nearClip(0.08f), // default
_farClip(50.0f * TREE_SCALE), // default
_nearClip(DEFAULT_NEAR_CLIP), // default
_farClip(DEFAULT_FAR_CLIP), // default
_upShift(0.0f),
_distance(0.0f),
_tightness(10.0f), // default

View file

@ -242,8 +242,8 @@ Menu::Menu() :
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
toggleChat();
connect(&xmppClient, SIGNAL(connected()), this, SLOT(toggleChat()));
connect(&xmppClient, SIGNAL(disconnected()), this, SLOT(toggleChat()));
connect(&xmppClient, &QXmppClient::connected, this, &Menu::toggleChat);
connect(&xmppClient, &QXmppClient::disconnected, this, &Menu::toggleChat);
QDir::setCurrent(Application::resourcesPath());
// init chat window to listen chat
@ -593,6 +593,12 @@ Menu::Menu() :
Qt::CTRL | Qt::SHIFT | Qt::Key_U,
false);
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats,
0,
false,
appInstance->getAudio(),
SLOT(toggleStats()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, true);
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,

View file

@ -315,6 +315,7 @@ namespace MenuOption {
const QString AudioScopeFrames = "Display Frames";
const QString AudioScopePause = "Pause Audio Scope";
const QString AudioScopeTwentyFrames = "Twenty";
const QString AudioStats = "Audio Stats";
const QString AudioSpatialProcessingAlternateDistanceAttenuate = "Alternate distance attenuation";
const QString AudioSpatialProcessing = "Audio Spatial Processing";
const QString AudioSpatialProcessingDontDistanceAttenuate = "Don't calculate distance attenuation";

View file

@ -9,7 +9,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifdef HAVE_QXMPP
#include <AccountManager.h>
@ -18,6 +17,7 @@
const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io";
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
#ifdef HAVE_QXMPP
XmppClient::XmppClient() :
_xmppClient(),
_xmppMUCManager()
@ -26,6 +26,11 @@ XmppClient::XmppClient() :
connect(&accountManager, SIGNAL(profileChanged()), this, SLOT(connectToServer()));
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
}
#else
XmppClient::XmppClient() {
}
#endif
XmppClient& XmppClient::getInstance() {
static XmppClient sharedInstance;
@ -33,18 +38,23 @@ XmppClient& XmppClient::getInstance() {
}
void XmppClient::xmppConnected() {
#ifdef HAVE_QXMPP
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
_publicChatRoom->setNickName(AccountManager::getInstance().getAccountInfo().getUsername());
_publicChatRoom->join();
emit joinedPublicChatRoom();
#endif
}
void XmppClient::xmppError(QXmppClient::Error error) {
#ifdef HAVE_QXMPP
qDebug() << "Error connnecting to XMPP for user "
<< AccountManager::getInstance().getAccountInfo().getUsername() << ": " << error;
#endif
}
void XmppClient::connectToServer() {
#ifdef HAVE_QXMPP
disconnectFromServer();
if (_xmppClient.addExtension(&_xmppMUCManager)) {
@ -55,12 +65,15 @@ void XmppClient::connectToServer() {
QString user = accountManager.getAccountInfo().getUsername();
const QString& password = accountManager.getAccountInfo().getXMPPPassword();
_xmppClient.connectToServer(user + "@" + DEFAULT_XMPP_SERVER, password);
#endif
}
void XmppClient::disconnectFromServer() {
#ifdef HAVE_QXMPP
if (_xmppClient.isConnected()) {
_xmppClient.disconnectFromServer();
}
#endif
}
XmppClient::XmppClient(const XmppClient& other) {
@ -70,5 +83,3 @@ XmppClient::XmppClient(const XmppClient& other) {
void XmppClient::operator =(XmppClient const& other) {
Q_UNUSED(other);
}
#endif

View file

@ -9,25 +9,27 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifdef HAVE_QXMPP
#ifndef hifi_XmppClient_h
#define hifi_XmppClient_h
#include <QObject>
#ifdef HAVE_QXMPP
#include <QXmppClient.h>
#include <QXmppMucManager.h>
#endif
/// Generalized threaded processor for handling received inbound packets.
class XmppClient : public QObject {
Q_OBJECT
public:
static XmppClient& getInstance();
#ifdef HAVE_QXMPP
QXmppClient& getXMPPClient() { return _xmppClient; }
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
#endif
signals:
void joinedPublicChatRoom();
@ -43,11 +45,11 @@ private:
XmppClient(XmppClient const& other); // not implemented
void operator=(XmppClient const& other); // not implemented
#ifdef HAVE_QXMPP
QXmppClient _xmppClient;
QXmppMucManager _xmppMUCManager;
QXmppMucRoom* _publicChatRoom;
#endif
};
#endif // __interface__XmppClient__
#endif // hifi_XmppClient_h

View file

@ -218,6 +218,52 @@ static TextRenderer* textRenderer(TextRendererType type) {
}
void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
if (glm::distance(Application::getInstance()->getAvatar()->getPosition(),
_position) < 10.0f) {
// render pointing lasers
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
float laserLength = 50.0f;
if (_handState == HAND_STATE_LEFT_POINTING ||
_handState == HAND_STATE_BOTH_POINTING) {
int leftIndex = _skeletonModel.getLeftHandJointIndex();
glm::vec3 leftPosition;
glm::quat leftRotation;
_skeletonModel.getJointPositionInWorldFrame(leftIndex, leftPosition);
_skeletonModel.getJointRotationInWorldFrame(leftIndex, leftRotation);
glPushMatrix(); {
glTranslatef(leftPosition.x, leftPosition.y, leftPosition.z);
float angle = glm::degrees(glm::angle(leftRotation));
glm::vec3 axis = glm::axis(leftRotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
}
if (_handState == HAND_STATE_RIGHT_POINTING ||
_handState == HAND_STATE_BOTH_POINTING) {
int rightIndex = _skeletonModel.getRightHandJointIndex();
glm::vec3 rightPosition;
glm::quat rightRotation;
_skeletonModel.getJointPositionInWorldFrame(rightIndex, rightPosition);
_skeletonModel.getJointRotationInWorldFrame(rightIndex, rightRotation);
glPushMatrix(); {
glTranslatef(rightPosition.x, rightPosition.y, rightPosition.z);
float angle = glm::degrees(glm::angle(rightRotation));
glm::vec3 axis = glm::axis(rightRotation);
glRotatef(angle, axis.x, axis.y, axis.z);
glBegin(GL_LINES);
glColor3f(laserColor.x, laserColor.y, laserColor.z);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, laserLength, 0.0f);
glEnd();
} glPopMatrix();
}
}
// simple frustum check
float boundingRadius = getBillboardSize();
ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ?

View file

@ -125,7 +125,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_RESCALE_NORMAL);
}
}
void Hand::renderHandTargets(bool isMine) {
glPushMatrix();

View file

@ -159,6 +159,10 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
}
}
_eyePosition = calculateAverageEyePosition();
float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f);
_filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition;
}
void Head::relaxLean(float deltaTime) {

View file

@ -88,8 +88,7 @@ public:
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
float getAverageLoudness() const { return _averageLoudness; }
glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; }
glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; }
/// \return the point about which scaling occurs.
glm::vec3 getScalePivot() const;
@ -110,6 +109,8 @@ public:
void addLeanDeltas(float sideways, float forward);
private:
glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; }
// disallow copies of the Head, copy of owning Avatar is disallowed too
Head(const Head&);
Head& operator= (const Head&);
@ -120,6 +121,8 @@ private:
glm::vec3 _leftEyePosition;
glm::vec3 _rightEyePosition;
glm::vec3 _eyePosition;
glm::vec3 _filteredEyePosition; // velocity filtered world space eye position
float _scale;
float _lastLoudness;
float _audioAttack;

View file

@ -0,0 +1,34 @@
//
// MuscleConstraint.cpp
// interface/src/avatar
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <SharedUtil.h>
#include <VerletPoint.h>
#include "MuscleConstraint.h"
const float DEFAULT_MUSCLE_STRENGTH = 0.5f * MAX_MUSCLE_STRENGTH;
MuscleConstraint::MuscleConstraint(VerletPoint* parent, VerletPoint* child)
: _rootPoint(parent), _childPoint(child),
_parentIndex(-1), _childndex(-1), _strength(DEFAULT_MUSCLE_STRENGTH) {
_childOffset = child->_position - parent->_position;
}
float MuscleConstraint::enforce() {
_childPoint->_position = (1.0f - _strength) * _childPoint->_position + _strength * (_rootPoint->_position + _childOffset);
return 0.0f;
}
void MuscleConstraint::setIndices(int parent, int child) {
_parentIndex = parent;
_childndex = child;
}

View file

@ -0,0 +1,43 @@
//
// MuscleConstraint.h
// interface/src/avatar
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_MuscleConstraint_h
#define hifi_MuscleConstraint_h
#include <Constraint.h>
// MuscleConstraint is a simple constraint that pushes the child toward an offset relative to the parent.
// It does NOT push the parent.
const float MAX_MUSCLE_STRENGTH = 0.5f;
class MuscleConstraint : public Constraint {
public:
MuscleConstraint(VerletPoint* parent, VerletPoint* child);
MuscleConstraint(const MuscleConstraint& other);
float enforce();
void setIndices(int parent, int child);
int getParentIndex() const { return _parentIndex; }
int getChildIndex() const { return _childndex; }
void setChildOffset(const glm::vec3& offset) { _childOffset = offset; }
void setStrength(float strength) { _strength = glm::clamp(strength, 0.0f, MAX_MUSCLE_STRENGTH); }
float getStrength() const { return _strength; }
private:
VerletPoint* _rootPoint;
VerletPoint* _childPoint;
int _parentIndex;
int _childndex;
glm::vec3 _childOffset;
float _strength; // a value in range [0,MAX_MUSCLE_STRENGTH]
};
#endif // hifi_MuscleConstraint_h

View file

@ -137,9 +137,6 @@ void MyAvatar::simulate(float deltaTime) {
}
_skeletonModel.setShowTrueJointTransforms(! Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll));
// no extra movement of the hand here any more ...
_handState = HAND_STATE_NULL;
{
PerformanceTimer perfTimer("transform");
updateOrientation(deltaTime);
@ -165,9 +162,16 @@ void MyAvatar::simulate(float deltaTime) {
PerformanceTimer perfTimer("joints");
// copy out the skeleton joints from the model
_jointData.resize(_skeletonModel.getJointStateCount());
for (int i = 0; i < _jointData.size(); i++) {
JointData& data = _jointData[i];
data.valid = _skeletonModel.getJointState(i, data.rotation);
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
for (int i = 0; i < _jointData.size(); i++) {
JointData& data = _jointData[i];
data.valid = _skeletonModel.getVisibleJointState(i, data.rotation);
}
} else {
for (int i = 0; i < _jointData.size(); i++) {
JointData& data = _jointData[i];
data.valid = _skeletonModel.getJointState(i, data.rotation);
}
}
}
@ -908,7 +912,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const {
const Head* head = getHead();
return (renderMode != NORMAL_RENDER_MODE) ||
(glm::length(cameraPosition - head->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
(glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
}
float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) {

View file

@ -21,9 +21,9 @@
enum AvatarHandState
{
HAND_STATE_NULL = 0,
HAND_STATE_OPEN,
HAND_STATE_GRASPING,
HAND_STATE_POINTING,
HAND_STATE_LEFT_POINTING,
HAND_STATE_RIGHT_POINTING,
HAND_STATE_BOTH_POINTING,
NUM_HAND_STATES
};

View file

@ -14,11 +14,14 @@
#include <VerletCapsuleShape.h>
#include <VerletSphereShape.h>
#include <DistanceConstraint.h>
#include <FixedConstraint.h>
#include "Application.h"
#include "Avatar.h"
#include "Hand.h"
#include "Menu.h"
#include "MuscleConstraint.h"
#include "SkeletonModel.h"
SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
@ -505,6 +508,7 @@ void SkeletonModel::renderRagdoll() {
// virtual
void SkeletonModel::initRagdollPoints() {
clearRagdollConstraintsAndPoints();
_muscleConstraints.clear();
// one point for each joint
int numJoints = _jointStates.size();
@ -512,8 +516,7 @@ void SkeletonModel::initRagdollPoints() {
for (int i = 0; i < numJoints; ++i) {
const JointState& state = _jointStates.at(i);
glm::vec3 position = state.getPosition();
_ragdollPoints[i]._position = position;
_ragdollPoints[i]._lastPosition = position;
_ragdollPoints[i].initPosition(position);
}
}
@ -523,33 +526,74 @@ void SkeletonModel::buildRagdollConstraints() {
const int numPoints = _ragdollPoints.size();
assert(numPoints == _jointStates.size());
float minBone = FLT_MAX;
float maxBone = -FLT_MAX;
QMultiMap<int, int> families;
for (int i = 0; i < numPoints; ++i) {
const JointState& state = _jointStates.at(i);
const FBXJoint& joint = state.getFBXJoint();
int parentIndex = joint.parentIndex;
int parentIndex = state.getParentIndex();
if (parentIndex == -1) {
FixedConstraint* anchor = new FixedConstraint(&(_ragdollPoints[i]), glm::vec3(0.0f));
_ragdollConstraints.push_back(anchor);
} else {
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex]));
bone->setDistance(state.getDistanceToParent());
_ragdollConstraints.push_back(bone);
families.insert(parentIndex, i);
}
float boneLength = glm::length(state.getPositionInParentFrame());
if (boneLength > maxBone) {
maxBone = boneLength;
} else if (boneLength < minBone) {
minBone = boneLength;
}
}
// Joints that have multiple children effectively have rigid constraints between the children
// in the parent frame, so we add constraints between children in the same family.
// in the parent frame, so we add DistanceConstraints between children in the same family.
QMultiMap<int, int>::iterator itr = families.begin();
while (itr != families.end()) {
QList<int> children = families.values(itr.key());
if (children.size() > 1) {
for (int i = 1; i < children.size(); ++i) {
int numChildren = children.size();
if (numChildren > 1) {
for (int i = 1; i < numChildren; ++i) {
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]]));
_ragdollConstraints.push_back(bone);
}
if (numChildren > 2) {
DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]]));
_ragdollConstraints.push_back(bone);
}
}
++itr;
}
float MAX_STRENGTH = 0.3f;
float MIN_STRENGTH = 0.005f;
// each joint gets a MuscleConstraint to its parent
for (int i = 1; i < numPoints; ++i) {
const JointState& state = _jointStates.at(i);
int p = state.getParentIndex();
if (p == -1) {
continue;
}
MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i]));
_ragdollConstraints.push_back(constraint);
_muscleConstraints.push_back(constraint);
// Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length:
// long = weak and short = strong.
constraint->setIndices(p, i);
float boneLength = glm::length(state.getPositionInParentFrame());
float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone);
if (!families.contains(i)) {
// Although muscles only pull on the children not parents, nevertheless those joints that have
// parents AND children are more stable than joints at the end such as fingers. For such joints we
// bestow maximum strength which helps reduce wiggle.
strength = MAX_MUSCLE_STRENGTH;
}
constraint->setStrength(strength);
}
}
@ -597,11 +641,8 @@ void SkeletonModel::updateVisibleJointStates() {
// virtual
void SkeletonModel::stepRagdollForward(float deltaTime) {
// NOTE: increasing this timescale reduces vibrations in the ragdoll solution and reduces tunneling
// but makes the shapes slower to follow the body (introduces lag).
const float RAGDOLL_FOLLOWS_JOINTS_TIMESCALE = 0.05f;
float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f);
moveShapesTowardJoints(fraction);
Ragdoll::stepRagdollForward(deltaTime);
updateMuscles();
}
float DENSITY_OF_WATER = 1000.0f; // kg/m^3
@ -669,24 +710,46 @@ void SkeletonModel::buildShapes() {
if (_ragdollPoints.size() == numStates) {
int numJoints = _jointStates.size();
for (int i = 0; i < numJoints; ++i) {
_ragdollPoints[i]._lastPosition = _ragdollPoints.at(i)._position;
_ragdollPoints[i]._position = _jointStates.at(i).getPosition();
_ragdollPoints[i].initPosition(_jointStates.at(i).getPosition());
}
}
enforceRagdollConstraints();
}
void SkeletonModel::moveShapesTowardJoints(float fraction) {
void SkeletonModel::moveShapesTowardJoints(float deltaTime) {
// KEEP: although we don't currently use this method we may eventually need it to help
// unravel a skelton that has become tangled in its constraints. So let's keep this
// around for a while just in case.
const int numStates = _jointStates.size();
assert(_jointStates.size() == _ragdollPoints.size());
assert(fraction >= 0.0f && fraction <= 1.0f);
if (_ragdollPoints.size() == numStates) {
float oneMinusFraction = 1.0f - fraction;
int numJoints = _jointStates.size();
for (int i = 0; i < numJoints; ++i) {
_ragdollPoints[i]._lastPosition = _ragdollPoints[i]._position;
_ragdollPoints[i]._position = oneMinusFraction * _ragdollPoints[i]._position + fraction * _jointStates.at(i).getPosition();
if (_ragdollPoints.size() != numStates) {
return;
}
// fraction = 0 means keep old position, = 1 means slave 100% to target position
const float RAGDOLL_FOLLOWS_JOINTS_TIMESCALE = 0.05f;
float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f);
float oneMinusFraction = 1.0f - fraction;
for (int i = 0; i < numStates; ++i) {
_ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position +
fraction * _jointStates.at(i).getPosition());
}
}
void SkeletonModel::updateMuscles() {
int numConstraints = _muscleConstraints.size();
for (int i = 0; i < numConstraints; ++i) {
MuscleConstraint* constraint = _muscleConstraints[i];
int j = constraint->getParentIndex();
if (j == -1) {
continue;
}
int k = constraint->getChildIndex();
if (k == -1) {
continue;
}
constraint->setChildOffset(_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition());
}
}
@ -706,8 +769,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
int parentIndex = joint.parentIndex;
if (parentIndex == -1) {
transforms[i] = _jointStates[i].getTransform();
_ragdollPoints[i]._position = extractTranslation(transforms[i]);
_ragdollPoints[i]._lastPosition = _ragdollPoints[i]._position;
_ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
continue;
}
@ -715,8 +777,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
// setting the ragdollPoints here slams the VerletShapes into their default positions
_ragdollPoints[i]._position = extractTranslation(transforms[i]);
_ragdollPoints[i]._lastPosition = _ragdollPoints[i]._position;
_ragdollPoints[i].initPosition(extractTranslation(transforms[i]));
}
// compute bounding box that encloses all shapes

View file

@ -18,6 +18,7 @@
#include <Ragdoll.h>
class Avatar;
class MuscleConstraint;
/// A skeleton loaded from a model.
class SkeletonModel : public Model, public Ragdoll {
@ -100,6 +101,7 @@ public:
virtual void stepRagdollForward(float deltaTime);
void moveShapesTowardJoints(float fraction);
void updateMuscles();
void computeBoundingShape(const FBXGeometry& geometry);
void renderBoundingCollisionShapes(float alpha);
@ -144,6 +146,7 @@ private:
CapsuleShape _boundingShape;
glm::vec3 _boundingShapeLocalOffset;
QVector<MuscleConstraint*> _muscleConstraints;
};
#endif // hifi_SkeletonModel_h

View file

@ -27,6 +27,7 @@
// Generic client side Octree renderer class.
class ModelTreeRenderer : public OctreeRenderer, public ModelItemFBXService {
Q_OBJECT
public:
ModelTreeRenderer();
virtual ~ModelTreeRenderer();
@ -56,7 +57,7 @@ public:
protected:
void clearModelsCache();
Model* getModel(const ModelItem& modelItem);
Q_INVOKABLE Model* getModel(const ModelItem& modelItem);
QMap<uint32_t, Model*> _knownModelsItemModels;
QMap<uint32_t, Model*> _unknownModelsItemModels;
};

View file

@ -20,6 +20,7 @@
JointState::JointState() :
_animationPriority(0.0f),
_positionInParentFrame(0.0f),
_distanceToParent(0.0f),
_fbxJoint(NULL),
_constraint(NULL) {
}
@ -29,6 +30,7 @@ JointState::JointState(const JointState& other) : _constraint(NULL) {
_rotation = other._rotation;
_rotationInConstrainedFrame = other._rotationInConstrainedFrame;
_positionInParentFrame = other._positionInParentFrame;
_distanceToParent = other._distanceToParent;
_animationPriority = other._animationPriority;
_fbxJoint = other._fbxJoint;
// DO NOT copy _constraint
@ -72,6 +74,7 @@ void JointState::copyState(const JointState& state) {
_rotation = extractRotation(_transform);
_rotationInConstrainedFrame = state._rotationInConstrainedFrame;
_positionInParentFrame = state._positionInParentFrame;
_distanceToParent = state._distanceToParent;
_visibleTransform = state._visibleTransform;
_visibleRotation = extractRotation(_visibleTransform);
@ -82,6 +85,7 @@ void JointState::copyState(const JointState& state) {
void JointState::initTransform(const glm::mat4& parentTransform) {
computeTransform(parentTransform);
_positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));
_distanceToParent = glm::length(_positionInParentFrame);
}
void JointState::computeTransform(const glm::mat4& parentTransform) {
@ -214,6 +218,14 @@ void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRot
_visibleRotation = parentRotation * _fbxJoint->preRotation * _visibleRotationInConstrainedFrame * _fbxJoint->postRotation;
}
const bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const {
glm::quat defaultRotation = _fbxJoint->rotation;
return glm::abs(rotation.x - defaultRotation.x) < tolerance &&
glm::abs(rotation.y - defaultRotation.y) < tolerance &&
glm::abs(rotation.z - defaultRotation.z) < tolerance &&
glm::abs(rotation.w - defaultRotation.w) < tolerance;
}
const glm::vec3& JointState::getDefaultTranslationInConstrainedFrame() const {
assert(_fbxJoint != NULL);
return _fbxJoint->translation;

View file

@ -51,6 +51,7 @@ public:
glm::quat getRotationInParentFrame() const;
glm::quat getVisibleRotationInParentFrame() const;
const glm::vec3& getPositionInParentFrame() const { return _positionInParentFrame; }
float getDistanceToParent() const { return _distanceToParent; }
int getParentIndex() const { return _fbxJoint->parentIndex; }
@ -81,6 +82,9 @@ public:
void setRotationInConstrainedFrame(const glm::quat& targetRotation);
void setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation);
const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; }
const glm::quat& getVisibleRotationInConstrainedFrame() const { return _visibleRotationInConstrainedFrame; }
const bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const;
const glm::vec3& getDefaultTranslationInConstrainedFrame() const;
@ -104,6 +108,7 @@ private:
glm::quat _rotation; // joint- to model-frame
glm::quat _rotationInConstrainedFrame; // rotation in frame where angular constraints would be applied
glm::vec3 _positionInParentFrame; // only changes when the Model is scaled
float _distanceToParent;
glm::mat4 _visibleTransform;
glm::quat _visibleRotation;

View file

@ -676,12 +676,18 @@ bool Model::getJointState(int index, glm::quat& rotation) const {
if (index == -1 || index >= _jointStates.size()) {
return false;
}
rotation = _jointStates.at(index).getRotationInConstrainedFrame();
const glm::quat& defaultRotation = _geometry->getFBXGeometry().joints.at(index).rotation;
return glm::abs(rotation.x - defaultRotation.x) >= EPSILON ||
glm::abs(rotation.y - defaultRotation.y) >= EPSILON ||
glm::abs(rotation.z - defaultRotation.z) >= EPSILON ||
glm::abs(rotation.w - defaultRotation.w) >= EPSILON;
const JointState& state = _jointStates.at(index);
rotation = state.getRotationInConstrainedFrame();
return !state.rotationIsDefault(rotation);
}
bool Model::getVisibleJointState(int index, glm::quat& rotation) const {
if (index == -1 || index >= _jointStates.size()) {
return false;
}
const JointState& state = _jointStates.at(index);
rotation = state.getVisibleRotationInConstrainedFrame();
return !state.rotationIsDefault(rotation);
}
void Model::setJointState(int index, bool valid, const glm::quat& rotation, float priority) {

View file

@ -113,6 +113,10 @@ public:
/// Fetches the joint state at the specified index.
/// \return whether or not the joint state is "valid" (that is, non-default)
bool getJointState(int index, glm::quat& rotation) const;
/// Fetches the visible joint state at the specified index.
/// \return whether or not the joint state is "valid" (that is, non-default)
bool getVisibleJointState(int index, glm::quat& rotation) const;
/// Sets the joint state at the specified index.
void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f);

View file

@ -178,7 +178,7 @@ void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direc
float dist = sqrt(x * x + y * y);
float z = -sqrt(1.0f - dist * dist);
glm::vec3 relativePosition = myAvatar->getHead()->calculateAverageEyePosition() +
glm::vec3 relativePosition = myAvatar->getHead()->getEyePosition() +
glm::normalize(myAvatar->getOrientation() * glm::vec3(x, y, z));
//Rotate the UI pick ray by the avatar orientation
@ -274,7 +274,7 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
MyAvatar* myAvatar = application->getAvatar();
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition();
glm::vec3 eyePos = myAvatar->getHead()->getEyePosition();
glm::quat orientation = glm::inverse(myAvatar->getOrientation());
glm::vec3 dir = orientation * glm::normalize(application->getCamera()->getPosition() - tip); //direction of ray goes towards camera
glm::vec3 tipPos = orientation * (tip - eyePos);
@ -331,7 +331,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
glm::quat orientation = myAvatar->getOrientation();
glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->calculateAverageEyePosition());
glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition());
glm::vec3 relativeDirection = orientation * direction;
float t;
@ -375,7 +375,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
glPushMatrix();
const glm::quat& orientation = myAvatar->getOrientation();
const glm::vec3& position = myAvatar->getHead()->calculateAverageEyePosition();
const glm::vec3& position = myAvatar->getHead()->getEyePosition();
glm::mat4 rotation = glm::toMat4(orientation);
@ -1022,6 +1022,8 @@ void ApplicationOverlay::renderAudioMeter() {
audio->renderScope(glWidget->width(), glWidget->height());
audio->renderStats(WHITE_TEXT, glWidget->width(), glWidget->height());
glBegin(GL_QUADS);
if (isClipping) {
glColor3f(1, 0, 0);
@ -1210,7 +1212,7 @@ void ApplicationOverlay::renderTexturedHemisphere() {
Application* application = Application::getInstance();
MyAvatar* myAvatar = application->getAvatar();
const glm::quat& orientation = myAvatar->getOrientation();
const glm::vec3& position = myAvatar->getHead()->calculateAverageEyePosition();
const glm::vec3& position = myAvatar->getHead()->getEyePosition();
glm::mat4 rotation = glm::toMat4(orientation);

View file

@ -182,7 +182,7 @@ ModelHandler::ModelHandler(ModelType modelsType, QWidget* parent) :
QObject(parent),
_initiateExit(false),
_type(modelsType),
_nameFilter(".*(fst|fbx|FST|FBX)")
_nameFilter(".*fst")
{
// set headers data
QStringList headerData;
@ -253,7 +253,6 @@ void ModelHandler::downloadFinished() {
parseHeaders(reply);
}
reply->deleteLater();
sender()->deleteLater();
}
void ModelHandler::queryNewFiles(QString marker) {

View file

@ -23,7 +23,6 @@
#include "Menu.h"
#include "ScriptsModel.h"
RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
FramelessDialog(parent, 0, POSITION_LEFT),
ui(new Ui::RunningScriptsWidget),
@ -104,13 +103,21 @@ void RunningScriptsWidget::setRunningScripts(const QStringList& list) {
delete widget->widget();
delete widget;
}
QHash<QString, int> hash;
const int CLOSE_ICON_HEIGHT = 12;
for (int i = 0; i < list.size(); i++) {
if (!hash.contains(list.at(i))) {
hash.insert(list.at(i), 1);
}
QWidget* row = new QWidget(ui->scrollAreaWidgetContents);
row->setLayout(new QHBoxLayout(row));
QUrl url = QUrl(list.at(i));
QLabel* name = new QLabel(url.fileName(), row);
if (hash.find(list.at(i)).value() != 1) {
name->setText(name->text() + "(" + QString::number(hash.find(list.at(i)).value()) + ")");
}
++hash[list.at(i)];
QPushButton* closeButton = new QPushButton(row);
closeButton->setFlat(true);
closeButton->setIcon(

View file

@ -278,9 +278,8 @@ void Stats::display(
Audio* audio = Application::getInstance()->getAudio();
const QHash<QUuid, AudioStreamStats>& audioMixerInjectedStreamAudioStatsMap = audio->getAudioMixerInjectedStreamAudioStatsMap();
lines = _expanded ? 13 + (audioMixerInjectedStreamAudioStatsMap.size() + 2) * 3 : 3;
lines = _expanded ? 4 : 3;
drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10);
horizontalOffset += 5;
@ -313,128 +312,6 @@ void Stats::display(
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing, color);
char inputAudioLabelString[] = "Input: avail_avg_10s/avail";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, inputAudioLabelString, color);
char inputAudioStatsString[512];
sprintf(inputAudioStatsString, " %d/%d", audio->getInputRingBufferAverageFramesAvailable(),
audio->getInputRingBufferFramesAvailable());
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, inputAudioStatsString, color);
char audioMixerStatsLabelString[] = "AudioMixer stats:";
char streamStatsFormatLabelString[] = "lost%/lost_30s%";
char streamStatsFormatLabelString2[] = "desired/avail_avg_10s/avail";
char streamStatsFormatLabelString3[] = "gaps: min/max/avg, starv/ovfl";
char streamStatsFormatLabelString4[] = "gaps_30s: (same), notmix/sdrop";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioMixerStatsLabelString, color);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString, color);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString2, color);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString3, color);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString4, color);
char downstreamLabelString[] = " Downstream:";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color);
char downstreamAudioStatsString[512];
AudioStreamStats downstreamAudioStreamStats = audio->getDownstreamAudioStreamStats();
sprintf(downstreamAudioStatsString, " mix: %.2f%%/%.2f%%, %u/%u+%d/%u+%d", downstreamAudioStreamStats._packetStreamStats.getLostRate()*100.0f,
downstreamAudioStreamStats._packetStreamWindowStats.getLostRate() * 100.0f,
downstreamAudioStreamStats._ringBufferDesiredJitterBufferFrames, downstreamAudioStreamStats._ringBufferFramesAvailableAverage,
audio->getOutputRingBufferAverageFramesAvailable(),
downstreamAudioStreamStats._ringBufferFramesAvailable, audio->getOutputRingBufferFramesAvailable());
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color);
sprintf(downstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(downstreamAudioStreamStats._timeGapMin).toLatin1().data(),
formatUsecTime(downstreamAudioStreamStats._timeGapMax).toLatin1().data(),
formatUsecTime(downstreamAudioStreamStats._timeGapAverage).toLatin1().data(),
downstreamAudioStreamStats._ringBufferStarveCount, downstreamAudioStreamStats._ringBufferOverflowCount);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color);
sprintf(downstreamAudioStatsString, " %s/%s/%s, %u/?", formatUsecTime(downstreamAudioStreamStats._timeGapWindowMin).toLatin1().data(),
formatUsecTime(downstreamAudioStreamStats._timeGapWindowMax).toLatin1().data(),
formatUsecTime(downstreamAudioStreamStats._timeGapWindowAverage).toLatin1().data(),
downstreamAudioStreamStats._ringBufferConsecutiveNotMixedCount);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color);
char upstreamLabelString[] = " Upstream:";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamLabelString, color);
char upstreamAudioStatsString[512];
const AudioStreamStats& audioMixerAvatarAudioStreamStats = audio->getAudioMixerAvatarStreamAudioStats();
sprintf(upstreamAudioStatsString, " mic: %.2f%%/%.2f%%, %u/%u/%u", audioMixerAvatarAudioStreamStats._packetStreamStats.getLostRate()*100.0f,
audioMixerAvatarAudioStreamStats._packetStreamWindowStats.getLostRate() * 100.0f,
audioMixerAvatarAudioStreamStats._ringBufferDesiredJitterBufferFrames, audioMixerAvatarAudioStreamStats._ringBufferFramesAvailableAverage,
audioMixerAvatarAudioStreamStats._ringBufferFramesAvailable);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapMin).toLatin1().data(),
formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapMax).toLatin1().data(),
formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapAverage).toLatin1().data(),
audioMixerAvatarAudioStreamStats._ringBufferStarveCount, audioMixerAvatarAudioStreamStats._ringBufferOverflowCount);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowMin).toLatin1().data(),
formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowMax).toLatin1().data(),
formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowAverage).toLatin1().data(),
audioMixerAvatarAudioStreamStats._ringBufferConsecutiveNotMixedCount, audioMixerAvatarAudioStreamStats._ringBufferSilentFramesDropped);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
foreach(const AudioStreamStats& injectedStreamAudioStats, audioMixerInjectedStreamAudioStatsMap) {
sprintf(upstreamAudioStatsString, " inj: %.2f%%/%.2f%%, %u/%u/%u", injectedStreamAudioStats._packetStreamStats.getLostRate()*100.0f,
injectedStreamAudioStats._packetStreamWindowStats.getLostRate() * 100.0f,
injectedStreamAudioStats._ringBufferDesiredJitterBufferFrames, injectedStreamAudioStats._ringBufferFramesAvailableAverage,
injectedStreamAudioStats._ringBufferFramesAvailable);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(injectedStreamAudioStats._timeGapMin).toLatin1().data(),
formatUsecTime(injectedStreamAudioStats._timeGapMax).toLatin1().data(),
formatUsecTime(injectedStreamAudioStats._timeGapAverage).toLatin1().data(),
injectedStreamAudioStats._ringBufferStarveCount, injectedStreamAudioStats._ringBufferOverflowCount);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(injectedStreamAudioStats._timeGapWindowMin).toLatin1().data(),
formatUsecTime(injectedStreamAudioStats._timeGapWindowMax).toLatin1().data(),
formatUsecTime(injectedStreamAudioStats._timeGapWindowAverage).toLatin1().data(),
injectedStreamAudioStats._ringBufferConsecutiveNotMixedCount, injectedStreamAudioStats._ringBufferSilentFramesDropped);
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color);
}
}
verticalOffset = 0;

View file

@ -30,7 +30,7 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier,
const uchar MAX_INJECTOR_VOLUME = 255;
int InjectedAudioRingBuffer::parseData(const QByteArray& packet, int packetsSkipped) {
int InjectedAudioRingBuffer::parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) {
frameReceivedUpdateTimingStats();
// setup a data stream to read from this packet

View file

@ -20,7 +20,7 @@ class InjectedAudioRingBuffer : public PositionalAudioRingBuffer {
public:
InjectedAudioRingBuffer(const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false);
int parseData(const QByteArray& packet, int packetsSkipped = 0);
int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped);
const QUuid& getStreamIdentifier() const { return _streamIdentifier; }
float getRadius() const { return _radius; }

View file

@ -45,7 +45,7 @@ public:
PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false, bool dynamicJitterBuffers = false);
virtual int parseData(const QByteArray& packet, int packetsSkipped = 0) = 0;
virtual int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) = 0;
int parsePositionalData(const QByteArray& positionalByteArray);
int parseListenModeData(const QByteArray& listenModeByteArray);

View file

@ -43,6 +43,7 @@ AvatarData::AvatarData() :
_handState(0),
_keyState(NO_KEY_DOWN),
_isChatCirclingEnabled(false),
_forceFaceshiftConnected(false),
_hasNewJointRotations(true),
_headData(NULL),
_handData(NULL),
@ -80,6 +81,9 @@ QByteArray AvatarData::toByteArray() {
// lazily allocate memory for HeadData in case we're not an Avatar instance
if (!_headData) {
_headData = new HeadData(this);
if (_forceFaceshiftConnected) {
_headData->_isFaceshiftConnected = true;
}
}
QByteArray avatarDataByteArray;

View file

@ -185,8 +185,8 @@ public:
void setClampedTargetScale(float targetScale);
// Hand State
void setHandState(char s) { _handState = s; }
char getHandState() const { return _handState; }
Q_INVOKABLE void setHandState(char s) { _handState = s; }
Q_INVOKABLE char getHandState() const { return _handState; }
const QVector<JointData>& getJointData() const { return _jointData; }
void setJointData(const QVector<JointData>& jointData) { _jointData = jointData; }
@ -206,6 +206,10 @@ public:
Q_INVOKABLE virtual QStringList getJointNames() const { return _jointNames; }
Q_INVOKABLE void setBlendshape(QString name, float val) { _headData->setBlendshape(name, val); }
void setForceFaceshiftConnected(bool connected) { _forceFaceshiftConnected = connected; }
// key state
void setKeyState(KeyState s) { _keyState = s; }
KeyState keyState() const { return _keyState; }
@ -300,7 +304,7 @@ protected:
std::string _chatMessage;
bool _isChatCirclingEnabled;
bool _forceFaceshiftConnected;
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
HeadData* _headData;

View file

@ -16,6 +16,8 @@
#include "AvatarData.h"
#include "HeadData.h"
#include "../fbx/src/FBXReader.h"
HeadData::HeadData(AvatarData* owningAvatar) :
_baseYaw(0.0f),
_basePitch(0.0f),
@ -52,6 +54,26 @@ void HeadData::setOrientation(const glm::quat& orientation) {
_baseRoll = eulers.z;
}
void HeadData::setBlendshape(QString name, float val) {
static bool hasInitializedLookupMap = false;
static QMap<QString, int> blendshapeLookupMap;
//Lazily construct a lookup map from the blendshapes
if (!hasInitializedLookupMap) {
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
blendshapeLookupMap[FACESHIFT_BLENDSHAPES[i]] = i;
}
}
//Check to see if the named blendshape exists, and then set its value if it does
QMap<QString, int>::iterator it = blendshapeLookupMap.find(name);
if (it != blendshapeLookupMap.end()) {
if (_blendshapeCoefficients.size() <= it.value()) {
_blendshapeCoefficients.resize(it.value() + 1);
}
_blendshapeCoefficients[it.value()] = val;
}
}
void HeadData::addYaw(float yaw) {
setBaseYaw(_baseYaw + yaw);
}

View file

@ -54,6 +54,7 @@ public:
float getAudioAverageLoudness() const { return _audioAverageLoudness; }
void setAudioAverageLoudness(float audioAverageLoudness) { _audioAverageLoudness = audioAverageLoudness; }
void setBlendshape(QString name, float val);
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
float getPupilDilation() const { return _pupilDilation; }

View file

@ -577,6 +577,8 @@ const char* FACESHIFT_BLENDSHAPES[] = {
""
};
const int NUM_FACESHIFT_BLENDSHAPES = sizeof(FACESHIFT_BLENDSHAPES) / sizeof(char*);
const char* HUMANIK_JOINTS[] = {
"RightHand",
"RightForeArm",

View file

@ -29,6 +29,8 @@ typedef QList<FBXNode> FBXNodeList;
/// The names of the blendshapes expected by Faceshift, terminated with an empty string.
extern const char* FACESHIFT_BLENDSHAPES[];
/// The size of FACESHIFT_BLENDSHAPES
extern const int NUM_FACESHIFT_BLENDSHAPES;
/// The names of the joints in the Maya HumanIK rig, terminated with an empty string.
extern const char* HUMANIK_JOINTS[];

View file

@ -70,7 +70,7 @@ ModelItemProperties ModelsScriptingInterface::getModelProperties(ModelItemID mod
if (_modelTree) {
_modelTree->lockForRead();
ModelItem* model = const_cast<ModelItem*>(_modelTree->findModelByID(identity.id, true));
if (model) {
if (model && _modelTree->getGeometryForModel(*model)) {
model->setSittingPoints(_modelTree->getGeometryForModel(*model)->sittingPoints);
results.copyFromModelItem(*model);
} else {

View file

@ -22,7 +22,7 @@ OctreeHeadlessViewer::OctreeHeadlessViewer() :
_viewFrustum.setFieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES);
_viewFrustum.setAspectRatio(DEFAULT_ASPECT_RATIO);
_viewFrustum.setNearClip(DEFAULT_NEAR_CLIP);
_viewFrustum.setFarClip(TREE_SCALE);
_viewFrustum.setFarClip(DEFAULT_FAR_CLIP);
}
OctreeHeadlessViewer::~OctreeHeadlessViewer() {

View file

@ -36,8 +36,8 @@ ViewFrustum::ViewFrustum() :
_height(1.0f),
_fieldOfView(0.0),
_aspectRatio(1.0f),
_nearClip(0.1f),
_farClip(500.0f),
_nearClip(DEFAULT_NEAR_CLIP),
_farClip(DEFAULT_FAR_CLIP),
_focalLength(0.25f),
_keyholeRadius(DEFAULT_KEYHOLE_RADIUS),
_farTopLeft(0,0,0),

View file

@ -28,7 +28,7 @@ const float DEFAULT_FIELD_OF_VIEW_DEGREES = 90.0f;
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.f;
const float DEFAULT_ASPECT_RATIO = 16.f/9.f;
const float DEFAULT_NEAR_CLIP = 0.08f;
const float DEFAULT_FAR_CLIP = 50.0f * TREE_SCALE;
const float DEFAULT_FAR_CLIP = TREE_SCALE;
class ViewFrustum {
public:

View file

@ -23,8 +23,8 @@ static const QString CLASS_NAME = "ArrayBuffer";
Q_DECLARE_METATYPE(QByteArray*)
ArrayBufferClass::ArrayBufferClass(ScriptEngine* scriptEngine) :
QObject(scriptEngine->getEngine()),
QScriptClass(scriptEngine->getEngine()),
QObject(scriptEngine),
QScriptClass(scriptEngine),
_scriptEngine(scriptEngine) {
qScriptRegisterMetaType<QByteArray>(engine(), toScriptValue, fromScriptValue);
QScriptValue global = engine()->globalObject();

View file

@ -14,8 +14,8 @@
Q_DECLARE_METATYPE(QByteArray*)
ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngine* scriptEngine) :
QObject(scriptEngine->getEngine()),
QScriptClass(scriptEngine->getEngine()),
QObject(scriptEngine),
QScriptClass(scriptEngine),
_scriptEngine(scriptEngine) {
// Save string handles for quick lookup
_bufferName = engine()->toStringHandle(BUFFER_PROPERTY_NAME.toLatin1());

View file

@ -87,7 +87,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam
_isFinished(false),
_isRunning(false),
_isInitialized(false),
_engine(),
_isAvatar(false),
_avatarIdentityTimer(NULL),
_avatarBillboardTimer(NULL),
@ -113,7 +112,6 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL,
_isFinished(false),
_isRunning(false),
_isInitialized(false),
_engine(),
_isAvatar(false),
_avatarIdentityTimer(NULL),
_avatarBillboardTimer(NULL),
@ -194,7 +192,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa
_avatarData = avatarData;
// remove the old Avatar property, if it exists
_engine.globalObject().setProperty(objectName, QScriptValue());
globalObject().setProperty(objectName, QScriptValue());
// give the script engine the new Avatar script property
registerGlobalObject(objectName, _avatarData);
@ -202,7 +200,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa
void ScriptEngine::setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName) {
// remove the old Avatar property, if it exists
_engine.globalObject().setProperty(objectName, QScriptValue());
globalObject().setProperty(objectName, QScriptValue());
// give the script engine the new avatar hash map
registerGlobalObject(objectName, avatarHashMap);
@ -231,48 +229,48 @@ void ScriptEngine::init() {
_particlesScriptingInterface.init();
// register various meta-types
registerMetaTypes(&_engine);
registerMIDIMetaTypes(&_engine);
registerVoxelMetaTypes(&_engine);
registerEventTypes(&_engine);
registerMenuItemProperties(&_engine);
registerAnimationTypes(&_engine);
registerAvatarTypes(&_engine);
Bitstream::registerTypes(&_engine);
registerMetaTypes(this);
registerMIDIMetaTypes(this);
registerVoxelMetaTypes(this);
registerEventTypes(this);
registerMenuItemProperties(this);
registerAnimationTypes(this);
registerAvatarTypes(this);
Bitstream::registerTypes(this);
qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine);
qScriptRegisterMetaType(this, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
qScriptRegisterMetaType(this, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(this);
qScriptRegisterMetaType(&_engine, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue);
qScriptRegisterMetaType(&_engine, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue);
qScriptRegisterMetaType(&_engine, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ModelItemID> >(&_engine);
qScriptRegisterMetaType(this, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue);
qScriptRegisterMetaType(this, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue);
qScriptRegisterMetaType(this, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ModelItemID> >(this);
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(&_engine);
qScriptRegisterSequenceMetaType<QVector<glm::quat> >(&_engine);
qScriptRegisterSequenceMetaType<QVector<QString> >(&_engine);
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(this);
qScriptRegisterSequenceMetaType<QVector<glm::quat> >(this);
qScriptRegisterSequenceMetaType<QVector<QString> >(this);
QScriptValue xmlHttpRequestConstructorValue = _engine.newFunction(XMLHttpRequestClass::constructor);
_engine.globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue);
QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor);
globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue);
QScriptValue printConstructorValue = _engine.newFunction(debugPrint);
_engine.globalObject().setProperty("print", printConstructorValue);
QScriptValue printConstructorValue = newFunction(debugPrint);
globalObject().setProperty("print", printConstructorValue);
QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor);
QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
_engine.globalObject().setProperty("Sound", soundMetaObject);
QScriptValue soundConstructorValue = newFunction(soundConstructor);
QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue);
globalObject().setProperty("Sound", soundMetaObject);
QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject<AudioInjectorOptions>();
_engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
QScriptValue injectionOptionValue = scriptValueFromQMetaObject<AudioInjectorOptions>();
globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject<LocalVoxels>();
_engine.globalObject().setProperty("LocalVoxels", localVoxelsValue);
QScriptValue localVoxelsValue = scriptValueFromQMetaObject<LocalVoxels>();
globalObject().setProperty("LocalVoxels", localVoxelsValue);
qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue);
qScriptRegisterMetaType( &_engine, injectorToScriptValueInputController, injectorFromScriptValueInputController);
qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue);
qScriptRegisterMetaType( this, injectorToScriptValueInputController, injectorFromScriptValueInputController);
qScriptRegisterMetaType(&_engine, animationDetailsToScriptValue, animationDetailsFromScriptValue);
qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue);
registerGlobalObject("Script", this);
registerGlobalObject("Audio", &_audioScriptingInterface);
@ -287,15 +285,14 @@ void ScriptEngine::init() {
registerGlobalObject("Voxels", &_voxelsScriptingInterface);
// constants
QScriptValue globalObject = _engine.globalObject();
globalObject.setProperty("TREE_SCALE", _engine.newVariant(QVariant(TREE_SCALE)));
globalObject.setProperty("COLLISION_GROUP_ENVIRONMENT", _engine.newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
globalObject.setProperty("COLLISION_GROUP_AVATARS", _engine.newVariant(QVariant(COLLISION_GROUP_AVATARS)));
globalObject.setProperty("COLLISION_GROUP_VOXELS", _engine.newVariant(QVariant(COLLISION_GROUP_VOXELS)));
globalObject.setProperty("COLLISION_GROUP_PARTICLES", _engine.newVariant(QVariant(COLLISION_GROUP_PARTICLES)));
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
globalObject().setProperty("COLLISION_GROUP_VOXELS", newVariant(QVariant(COLLISION_GROUP_VOXELS)));
globalObject().setProperty("COLLISION_GROUP_PARTICLES", newVariant(QVariant(COLLISION_GROUP_PARTICLES)));
globalObject.setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY)));
globalObject.setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY)));
globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY)));
globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY)));
// let the VoxelPacketSender know how frequently we plan to call it
_voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS);
@ -304,8 +301,8 @@ void ScriptEngine::init() {
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
if (object) {
QScriptValue value = _engine.newQObject(object);
_engine.globalObject().setProperty(name, value);
QScriptValue value = newQObject(object);
globalObject().setProperty(name, value);
return value;
}
return QScriptValue::NullValue;
@ -313,15 +310,15 @@ QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* ob
void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter,
QScriptEngine::FunctionSignature setter, QScriptValue object) {
QScriptValue setterFunction = _engine.newFunction(setter, 1);
QScriptValue getterFunction = _engine.newFunction(getter);
QScriptValue setterFunction = newFunction(setter, 1);
QScriptValue getterFunction = newFunction(getter);
if (!object.isNull()) {
object.setProperty(name, setterFunction, QScriptValue::PropertySetter);
object.setProperty(name, getterFunction, QScriptValue::PropertyGetter);
} else {
_engine.globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter);
_engine.globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter);
globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter);
globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter);
}
}
@ -330,25 +327,24 @@ void ScriptEngine::evaluate() {
init();
}
QScriptValue result = _engine.evaluate(_scriptContents);
QScriptValue result = evaluate(_scriptContents);
if (_engine.hasUncaughtException()) {
int line = _engine.uncaughtExceptionLineNumber();
if (hasUncaughtException()) {
int line = uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString();
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString());
_engine.clearExceptions();
clearExceptions();
}
}
QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) {
QScriptValue result = _engine.evaluate(program, fileName, lineNumber);
bool hasUncaughtException = _engine.hasUncaughtException();
if (hasUncaughtException) {
int line = _engine.uncaughtExceptionLineNumber();
QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber);
if (hasUncaughtException()) {
int line = uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString();
}
emit evaluationFinished(result, hasUncaughtException);
_engine.clearExceptions();
emit evaluationFinished(result, hasUncaughtException());
clearExceptions();
return result;
}
@ -372,12 +368,12 @@ void ScriptEngine::run() {
_isFinished = false;
emit runningStateChanged();
QScriptValue result = _engine.evaluate(_scriptContents);
if (_engine.hasUncaughtException()) {
int line = _engine.uncaughtExceptionLineNumber();
QScriptValue result = evaluate(_scriptContents);
if (hasUncaughtException()) {
int line = uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString();
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString());
_engine.clearExceptions();
clearExceptions();
}
QElapsedTimer startTime;
@ -532,11 +528,11 @@ void ScriptEngine::run() {
qint64 now = usecTimestampNow();
float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
if (_engine.hasUncaughtException()) {
int line = _engine.uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << _engine.uncaughtException().toString();
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString());
_engine.clearExceptions();
if (hasUncaughtException()) {
int line = uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString();
emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString());
clearExceptions();
}
emit update(deltaTime);
@ -694,12 +690,12 @@ void ScriptEngine::include(const QString& includeFile) {
}
}
QScriptValue result = _engine.evaluate(includeContents);
if (_engine.hasUncaughtException()) {
int line = _engine.uncaughtExceptionLineNumber();
QScriptValue result = evaluate(includeContents);
if (hasUncaughtException()) {
int line = uncaughtExceptionLineNumber();
qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString();
emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString());
_engine.clearExceptions();
clearExceptions();
}
}

View file

@ -38,7 +38,7 @@ const QString NO_SCRIPT("");
const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5);
class ScriptEngine : public QObject {
class ScriptEngine : public QScriptEngine {
Q_OBJECT
public:
ScriptEngine(const QUrl& scriptURL,
@ -57,7 +57,6 @@ public:
/// Access the ModelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
static ModelsScriptingInterface* getModelsScriptingInterface() { return &_modelsScriptingInterface; }
QScriptEngine* getEngine() { return &_engine; }
ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; }
AnimationCache* getAnimationCache() { return &_animationCache; }
@ -122,7 +121,6 @@ protected:
bool _isFinished;
bool _isRunning;
bool _isInitialized;
QScriptEngine _engine;
bool _isAvatar;
QTimer* _avatarIdentityTimer;
QTimer* _avatarBillboardTimer;

View file

@ -0,0 +1,28 @@
//
// Constraint.h
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_Constraint_h
#define hifi_Constraint_h
class Constraint {
public:
Constraint() {}
virtual ~Constraint() {}
/// Enforce contraint by moving relevant points.
/// \return max distance of point movement
virtual float enforce() = 0;
protected:
int _type;
};
#endif // hifi_Constraint_h

View file

@ -0,0 +1,43 @@
//
// DistanceConstraint.cpp
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "DistanceConstraint.h"
#include "SharedUtil.h" // for EPSILON
#include "VerletPoint.h"
DistanceConstraint::DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint) : _distance(-1.0f) {
_points[0] = startPoint;
_points[1] = endPoint;
_distance = glm::distance(_points[0]->_position, _points[1]->_position);
}
DistanceConstraint::DistanceConstraint(const DistanceConstraint& other) {
_distance = other._distance;
_points[0] = other._points[0];
_points[1] = other._points[1];
}
void DistanceConstraint::setDistance(float distance) {
_distance = fabsf(distance);
}
float DistanceConstraint::enforce() {
// TODO: use a fast distance approximation
float newDistance = glm::distance(_points[0]->_position, _points[1]->_position);
glm::vec3 direction(0.0f, 1.0f, 0.0f);
if (newDistance > EPSILON) {
direction = (_points[0]->_position - _points[1]->_position) / newDistance;
}
glm::vec3 center = 0.5f * (_points[0]->_position + _points[1]->_position);
_points[0]->_position = center + (0.5f * _distance) * direction;
_points[1]->_position = center - (0.5f * _distance) * direction;
return glm::abs(newDistance - _distance);
}

View file

@ -0,0 +1,31 @@
//
// DistanceConstraint.h
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_DistanceConstraint_h
#define hifi_DistanceConstraint_h
#include "Constraint.h"
class VerletPoint;
class DistanceConstraint : public Constraint {
public:
DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint);
DistanceConstraint(const DistanceConstraint& other);
float enforce();
void setDistance(float distance);
float getDistance() const { return _distance; }
private:
float _distance;
VerletPoint* _points[2];
};
#endif // hifi_DistanceConstraint_h

View file

@ -0,0 +1,35 @@
//
// FixedConstraint.cpp
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "FixedConstraint.h"
#include "Shape.h" // for MAX_SHAPE_MASS
#include "VerletPoint.h"
FixedConstraint::FixedConstraint(VerletPoint* point, const glm::vec3& anchor) : _point(point), _anchor(anchor) {
}
float FixedConstraint::enforce() {
assert(_point != NULL);
// TODO: use fast approximate sqrt here
float distance = glm::distance(_anchor, _point->_position);
_point->_position = _anchor;
return distance;
}
void FixedConstraint::setPoint(VerletPoint* point) {
assert(point);
_point = point;
_point->_mass = MAX_SHAPE_MASS;
}
void FixedConstraint::setAnchor(const glm::vec3& anchor) {
_anchor = anchor;
}

View file

@ -0,0 +1,32 @@
//
// FixedConstraint.h
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_FixedConstraint_h
#define hifi_FixedConstraint_h
#include <glm/glm.hpp>
#include "Constraint.h"
class VerletPoint;
class FixedConstraint : public Constraint {
public:
FixedConstraint(VerletPoint* point, const glm::vec3& anchor);
float enforce();
void setPoint(VerletPoint* point);
void setAnchor(const glm::vec3& anchor);
private:
VerletPoint* _point;
glm::vec3 _anchor;
};
#endif // hifi_FixedConstraint_h

View file

@ -11,86 +11,9 @@
#include "Ragdoll.h"
#include "CapsuleShape.h"
#include "CollisionInfo.h"
#include "SharedUtil.h"
#include "SphereShape.h"
// ----------------------------------------------------------------------------
// VerletPoint
// ----------------------------------------------------------------------------
void VerletPoint::accumulateDelta(const glm::vec3& delta) {
_accumulatedDelta += delta;
++_numDeltas;
}
void VerletPoint::applyAccumulatedDelta() {
if (_numDeltas > 0) {
_position += _accumulatedDelta / (float)_numDeltas;
_accumulatedDelta = glm::vec3(0.0f);
_numDeltas = 0;
}
}
// ----------------------------------------------------------------------------
// FixedConstraint
// ----------------------------------------------------------------------------
FixedConstraint::FixedConstraint(VerletPoint* point, const glm::vec3& anchor) : _point(point), _anchor(anchor) {
}
float FixedConstraint::enforce() {
assert(_point != NULL);
// TODO: use fast approximate sqrt here
float distance = glm::distance(_anchor, _point->_position);
_point->_position = _anchor;
return distance;
}
void FixedConstraint::setPoint(VerletPoint* point) {
assert(point);
_point = point;
_point->_mass = MAX_SHAPE_MASS;
}
void FixedConstraint::setAnchor(const glm::vec3& anchor) {
_anchor = anchor;
}
// ----------------------------------------------------------------------------
// DistanceConstraint
// ----------------------------------------------------------------------------
DistanceConstraint::DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint) : _distance(-1.0f) {
_points[0] = startPoint;
_points[1] = endPoint;
_distance = glm::distance(_points[0]->_position, _points[1]->_position);
}
DistanceConstraint::DistanceConstraint(const DistanceConstraint& other) {
_distance = other._distance;
_points[0] = other._points[0];
_points[1] = other._points[1];
}
void DistanceConstraint::setDistance(float distance) {
_distance = fabsf(distance);
}
float DistanceConstraint::enforce() {
// TODO: use a fast distance approximation
float newDistance = glm::distance(_points[0]->_position, _points[1]->_position);
glm::vec3 direction(0.0f, 1.0f, 0.0f);
if (newDistance > EPSILON) {
direction = (_points[0]->_position - _points[1]->_position) / newDistance;
}
glm::vec3 center = 0.5f * (_points[0]->_position + _points[1]->_position);
_points[0]->_position = center + (0.5f * _distance) * direction;
_points[1]->_position = center - (0.5f * _distance) * direction;
return glm::abs(newDistance - _distance);
}
// ----------------------------------------------------------------------------
// Ragdoll
// ----------------------------------------------------------------------------
#include "Constraint.h"
#include "DistanceConstraint.h"
#include "FixedConstraint.h"
Ragdoll::Ragdoll() {
}
@ -98,6 +21,13 @@ Ragdoll::Ragdoll() {
Ragdoll::~Ragdoll() {
clearRagdollConstraintsAndPoints();
}
void Ragdoll::stepRagdollForward(float deltaTime) {
int numPoints = _ragdollPoints.size();
for (int i = 0; i < numPoints; ++i) {
_ragdollPoints[i].integrateForward();
}
}
void Ragdoll::clearRagdollConstraintsAndPoints() {
int numConstraints = _ragdollConstraints.size();
@ -118,4 +48,3 @@ float Ragdoll::enforceRagdollConstraints() {
}
return maxDistance;
}

View file

@ -14,71 +14,11 @@
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include "VerletPoint.h"
#include <QVector>
class Shape;
// TODO: Andrew to move VerletPoint class to its own file
class VerletPoint {
public:
VerletPoint() : _position(0.0f), _lastPosition(0.0f), _mass(1.0f), _accumulatedDelta(0.0f), _numDeltas(0) {}
void accumulateDelta(const glm::vec3& delta);
void applyAccumulatedDelta();
glm::vec3 getAccumulatedDelta() const {
glm::vec3 foo(0.0f);
if (_numDeltas > 0) {
foo = _accumulatedDelta / (float)_numDeltas;
}
return foo;
}
glm::vec3 _position;
glm::vec3 _lastPosition;
float _mass;
private:
glm::vec3 _accumulatedDelta;
int _numDeltas;
};
class Constraint {
public:
Constraint() {}
virtual ~Constraint() {}
/// Enforce contraint by moving relevant points.
/// \return max distance of point movement
virtual float enforce() = 0;
protected:
int _type;
};
class FixedConstraint : public Constraint {
public:
FixedConstraint(VerletPoint* point, const glm::vec3& anchor);
float enforce();
void setPoint(VerletPoint* point);
void setAnchor(const glm::vec3& anchor);
private:
VerletPoint* _point;
glm::vec3 _anchor;
};
class DistanceConstraint : public Constraint {
public:
DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint);
DistanceConstraint(const DistanceConstraint& other);
float enforce();
void setDistance(float distance);
float getDistance() const { return _distance; }
private:
float _distance;
VerletPoint* _points[2];
};
class Constraint;
class Ragdoll {
public:
@ -86,7 +26,7 @@ public:
Ragdoll();
virtual ~Ragdoll();
virtual void stepRagdollForward(float deltaTime) = 0;
virtual void stepRagdollForward(float deltaTime);
/// \return max distance of point movement
float enforceRagdollConstraints();

View file

@ -733,6 +733,13 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
}
} else {
axis = glm::normalize(glm::cross(v1, v2));
// It is possible for axis to be nan even when angle is not less than EPSILON.
// For example when angle is small but not tiny but v1 and v2 and have very short lengths.
if (glm::isnan(glm::dot(axis, axis))) {
// set angle and axis to values that will generate an identity rotation
angle = 0.0f;
axis = glm::vec3(1.0f, 0.0f, 0.0f);
}
}
return glm::angleAxis(angle, axis);
}

View file

@ -0,0 +1,31 @@
//
// VerletPoint.cpp
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "VerletPoint.h"
void VerletPoint::integrateForward() {
glm::vec3 oldPosition = _position;
_position += 0.6f * (_position - _lastPosition);
_lastPosition = oldPosition;
}
void VerletPoint::accumulateDelta(const glm::vec3& delta) {
_accumulatedDelta += delta;
++_numDeltas;
}
void VerletPoint::applyAccumulatedDelta() {
if (_numDeltas > 0) {
_position += _accumulatedDelta / (float)_numDeltas;
_accumulatedDelta = glm::vec3(0.0f);
_numDeltas = 0;
}
}

View file

@ -0,0 +1,39 @@
//
// VerletPoint.h
// libraries/shared/src
//
// Created by Andrew Meadows 2014.07.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_VerletPoint_h
#define hifi_VerletPoint_h
#include <glm/glm.hpp>
class VerletPoint {
public:
VerletPoint() : _position(0.0f), _lastPosition(0.0f), _mass(1.0f), _accumulatedDelta(0.0f), _numDeltas(0) {}
void initPosition(const glm::vec3& position) { _position = position; _lastPosition = position; }
void integrateForward();
void accumulateDelta(const glm::vec3& delta);
void applyAccumulatedDelta();
glm::vec3 getAccumulatedDelta() const {
return (_numDeltas > 0) ? _accumulatedDelta / (float)_numDeltas : glm::vec3(0.0f);
}
glm::vec3 _position;
glm::vec3 _lastPosition;
float _mass;
private:
glm::vec3 _accumulatedDelta;
int _numDeltas;
};
#endif // hifi_VerletPoint_h