mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 17:46:47 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
f61c746b4a
35 changed files with 873 additions and 630 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -42,5 +42,9 @@ interface/external/visage/*
|
|||
interface/resources/visage/*
|
||||
!interface/resources/visage/tracker.cfg
|
||||
|
||||
# Ignore Faceplus
|
||||
interface/external/faceplus/*
|
||||
!interface/external/faceplus/readme.txt
|
||||
|
||||
# Ignore interfaceCache for Linux users
|
||||
interface/interfaceCache/
|
||||
|
|
42
cmake/modules/FindFaceplus.cmake
Normal file
42
cmake/modules/FindFaceplus.cmake
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Try to find the Faceplus library
|
||||
#
|
||||
# You must provide a FACEPLUS_ROOT_DIR which contains lib and include directories
|
||||
#
|
||||
# Once done this will define
|
||||
#
|
||||
# FACEPLUS_FOUND - system found Faceplus
|
||||
# FACEPLUS_INCLUDE_DIRS - the Faceplus include directory
|
||||
# FACEPLUS_LIBRARIES - Link this to use Faceplus
|
||||
#
|
||||
# Created on 4/8/2014 by Andrzej Kapolka
|
||||
# Copyright (c) 2014 High Fidelity
|
||||
#
|
||||
|
||||
if (FACEPLUS_LIBRARIES AND FACEPLUS_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(FACEPLUS_FOUND TRUE)
|
||||
else (FACEPLUS_LIBRARIES AND FACEPLUS_INCLUDE_DIRS)
|
||||
find_path(FACEPLUS_INCLUDE_DIRS faceplus.h ${FACEPLUS_ROOT_DIR}/include)
|
||||
|
||||
if (WIN32)
|
||||
find_library(FACEPLUS_LIBRARIES faceplus.lib ${FACEPLUS_ROOT_DIR}/win32/)
|
||||
endif (WIN32)
|
||||
|
||||
if (FACEPLUS_INCLUDE_DIRS AND FACEPLUS_LIBRARIES)
|
||||
set(FACEPLUS_FOUND TRUE)
|
||||
endif (FACEPLUS_INCLUDE_DIRS AND FACEPLUS_LIBRARIES)
|
||||
|
||||
if (FACEPLUS_FOUND)
|
||||
if (NOT FACEPLUS_FIND_QUIETLY)
|
||||
message(STATUS "Found Faceplus... ${FACEPLUS_LIBRARIES}")
|
||||
endif (NOT FACEPLUS_FIND_QUIETLY)
|
||||
else ()
|
||||
if (FACEPLUS_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find Faceplus")
|
||||
endif (FACEPLUS_FIND_REQUIRED)
|
||||
endif ()
|
||||
|
||||
# show the FACEPLUS_INCLUDE_DIRS and FACEPLUS_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES)
|
||||
|
||||
endif (FACEPLUS_LIBRARIES AND FACEPLUS_INCLUDE_DIRS)
|
68
examples/avatarCollision.js
Normal file
68
examples/avatarCollision.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// avatarCollision.js
|
||||
// examples
|
||||
//
|
||||
// Created by Andrew Meadows on 2014-04-09
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Play a sound on collisions with your avatar
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var SOUND_TRIGGER_CLEAR = 1000; // milliseconds
|
||||
var SOUND_TRIGGER_DELAY = 200; // milliseconds
|
||||
var soundExpiry = 0;
|
||||
var DateObj = new Date();
|
||||
var audioOptions = new AudioInjectionOptions();
|
||||
audioOptions.volume = 0.5;
|
||||
audioOptions.position = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var hitSounds = new Array();
|
||||
hitSounds[0] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit1.raw");
|
||||
hitSounds[1] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit2.raw");
|
||||
hitSounds[2] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit3.raw");
|
||||
hitSounds[3] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit4.raw");
|
||||
hitSounds[4] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit5.raw");
|
||||
hitSounds[5] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit6.raw");
|
||||
hitSounds[6] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit7.raw");
|
||||
hitSounds[7] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit8.raw");
|
||||
hitSounds[8] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit9.raw");
|
||||
hitSounds[9] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit10.raw");
|
||||
hitSounds[10] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit11.raw");
|
||||
hitSounds[11] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit12.raw");
|
||||
hitSounds[12] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit13.raw");
|
||||
hitSounds[13] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit14.raw");
|
||||
hitSounds[14] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit15.raw");
|
||||
hitSounds[15] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit16.raw");
|
||||
hitSounds[16] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit17.raw");
|
||||
hitSounds[17] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit18.raw");
|
||||
hitSounds[18] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit19.raw");
|
||||
hitSounds[19] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit20.raw");
|
||||
hitSounds[20] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit21.raw");
|
||||
hitSounds[21] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit22.raw");
|
||||
|
||||
function playHitSound(mySessionID, theirSessionID, collision) {
|
||||
var now = new Date();
|
||||
var msec = now.getTime();
|
||||
if (msec > soundExpiry) {
|
||||
// this is a new contact --> play a new sound
|
||||
var soundIndex = Math.floor((Math.random() * hitSounds.length) % hitSounds.length);
|
||||
audioOptions.position = collision.contactPoint;
|
||||
Audio.playSound(hitSounds[soundIndex], audioOptions);
|
||||
|
||||
// bump the expiry
|
||||
soundExpiry = msec + SOUND_TRIGGER_CLEAR;
|
||||
|
||||
// log the collision info
|
||||
Uuid.print("my sessionID = ", mySessionID);
|
||||
Uuid.print(" their sessionID = ", theirSessionID);
|
||||
Vec3.print(" penetration = ", collision.penetration);
|
||||
Vec3.print(" contactPoint = ", collision.contactPoint);
|
||||
} else {
|
||||
// this is a recurring contact --> continue to delay sound trigger
|
||||
soundExpiry = msec + SOUND_TRIGGER_DELAY;
|
||||
}
|
||||
}
|
||||
MyAvatar.collisionWithAvatar.connect(playHitSound);
|
|
@ -12,6 +12,7 @@ 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(SIXENSE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense")
|
||||
|
@ -130,6 +131,7 @@ link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}")
|
|||
link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}")
|
||||
|
||||
# find any optional libraries
|
||||
find_package(Faceplus)
|
||||
find_package(Faceshift)
|
||||
find_package(LibOVR)
|
||||
find_package(Sixense)
|
||||
|
@ -163,6 +165,13 @@ if (VISAGE_FOUND AND NOT DISABLE_VISAGE)
|
|||
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)
|
||||
|
|
11
interface/external/faceplus/readme.txt
vendored
Normal file
11
interface/external/faceplus/readme.txt
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
Instructions for adding the Faceplus driver to Interface
|
||||
Andrzej Kapolka, April 8, 2014
|
||||
|
||||
1. Copy the Faceplus sdk folders (include, win32) into the interface/external/faceplus folder.
|
||||
This readme.txt should be there as well.
|
||||
|
||||
2. Copy the Faceplus DLLs from the win32 folder into your path.
|
||||
|
||||
3. Delete your build directory, run cmake and build, and you should be all set.
|
||||
|
|
@ -150,7 +150,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_viewFrustum(),
|
||||
_lastQueriedViewFrustum(),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_audioScope(256, 200, true),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_mouseX(0),
|
||||
_mouseY(0),
|
||||
|
@ -161,7 +160,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_touchAvgY(0.0f),
|
||||
_isTouchPressed(false),
|
||||
_mousePressed(false),
|
||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||
_audio(STARTUP_JITTER_SAMPLES),
|
||||
_enableProcessVoxelsThread(true),
|
||||
_voxelProcessor(),
|
||||
_voxelHideShowThread(&_voxels),
|
||||
|
@ -342,11 +341,15 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
// clear the scripts, and set out script to our default scripts
|
||||
clearScriptsBeforeRunning();
|
||||
loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
|
||||
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->setValue("firstRun",QVariant(false));
|
||||
} else {
|
||||
// do this as late as possible so that all required subsystems are inialized
|
||||
loadScripts();
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,16 +359,12 @@ Application::~Application() {
|
|||
|
||||
// make sure we don't call the idle timer any more
|
||||
delete idleTimer;
|
||||
|
||||
Menu::getInstance()->saveSettings();
|
||||
_rearMirrorTools->saveSettings(_settings);
|
||||
|
||||
|
||||
_sharedVoxelSystem.changeTree(new VoxelTree);
|
||||
if (_voxelImporter) {
|
||||
_voxelImporter->saveSettings(_settings);
|
||||
delete _voxelImporter;
|
||||
}
|
||||
_settings->sync();
|
||||
|
||||
saveSettings();
|
||||
|
||||
delete _voxelImporter;
|
||||
|
||||
// let the avatar mixer know we're out
|
||||
MyAvatar::sendKillAvatar();
|
||||
|
@ -399,35 +398,45 @@ Application::~Application() {
|
|||
AccountManager::getInstance().destroy();
|
||||
}
|
||||
|
||||
void Application::saveSettings() {
|
||||
Menu::getInstance()->saveSettings();
|
||||
_rearMirrorTools->saveSettings(_settings);
|
||||
|
||||
if (_voxelImporter) {
|
||||
_voxelImporter->saveSettings(_settings);
|
||||
}
|
||||
_settings->sync();
|
||||
}
|
||||
|
||||
|
||||
void Application::restoreSizeAndPosition() {
|
||||
QSettings* settings = new QSettings(this);
|
||||
QRect available = desktop()->availableGeometry();
|
||||
|
||||
settings->beginGroup("Window");
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginGroup("Window");
|
||||
|
||||
int x = (int)loadSetting(settings, "x", 0);
|
||||
int y = (int)loadSetting(settings, "y", 0);
|
||||
int x = (int)loadSetting(_settings, "x", 0);
|
||||
int y = (int)loadSetting(_settings, "y", 0);
|
||||
_window->move(x, y);
|
||||
|
||||
int width = (int)loadSetting(settings, "width", available.width());
|
||||
int height = (int)loadSetting(settings, "height", available.height());
|
||||
int width = (int)loadSetting(_settings, "width", available.width());
|
||||
int height = (int)loadSetting(_settings, "height", available.height());
|
||||
_window->resize(width, height);
|
||||
|
||||
settings->endGroup();
|
||||
_settings->endGroup();
|
||||
}
|
||||
|
||||
void Application::storeSizeAndPosition() {
|
||||
QSettings* settings = new QSettings(this);
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginGroup("Window");
|
||||
|
||||
settings->beginGroup("Window");
|
||||
_settings->setValue("width", _window->rect().width());
|
||||
_settings->setValue("height", _window->rect().height());
|
||||
|
||||
settings->setValue("width", _window->rect().width());
|
||||
settings->setValue("height", _window->rect().height());
|
||||
_settings->setValue("x", _window->pos().x());
|
||||
_settings->setValue("y", _window->pos().y());
|
||||
|
||||
settings->setValue("x", _window->pos().x());
|
||||
settings->setValue("y", _window->pos().y());
|
||||
|
||||
settings->endGroup();
|
||||
_settings->endGroup();
|
||||
}
|
||||
|
||||
void Application::initializeGL() {
|
||||
|
@ -757,9 +766,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
case Qt::Key_Period:
|
||||
Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key());
|
||||
break;
|
||||
case Qt::Key_Apostrophe:
|
||||
_audioScope.inputPaused = !_audioScope.inputPaused;
|
||||
break;
|
||||
case Qt::Key_L:
|
||||
if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::LodTools);
|
||||
|
@ -1358,6 +1364,12 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox
|
|||
(mouseVoxel.z + mouseVoxel.s / 2.f) * TREE_SCALE);
|
||||
}
|
||||
|
||||
FaceTracker* Application::getActiveFaceTracker() {
|
||||
return _faceshift.isActive() ? static_cast<FaceTracker*>(&_faceshift) :
|
||||
(_faceplus.isActive() ? static_cast<FaceTracker*>(&_faceplus) :
|
||||
(_visage.isActive() ? static_cast<FaceTracker*>(&_visage) : NULL));
|
||||
}
|
||||
|
||||
struct SendVoxelsOperationArgs {
|
||||
const unsigned char* newBaseOctCode;
|
||||
};
|
||||
|
@ -1577,8 +1589,9 @@ void Application::init() {
|
|||
}
|
||||
qDebug("Loaded settings");
|
||||
|
||||
// initialize Visage and Faceshift after loading the menu settings
|
||||
// initialize our face trackers after loading the menu settings
|
||||
_faceshift.init();
|
||||
_faceplus.init();
|
||||
_visage.init();
|
||||
|
||||
// fire off an immediate domain-server check in now that settings are loaded
|
||||
|
@ -1742,19 +1755,11 @@ void Application::updateMyAvatarLookAtPosition() {
|
|||
glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition()));
|
||||
lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance);
|
||||
}
|
||||
bool trackerActive = false;
|
||||
float eyePitch, eyeYaw;
|
||||
if (_faceshift.isActive()) {
|
||||
eyePitch = _faceshift.getEstimatedEyePitch();
|
||||
eyeYaw = _faceshift.getEstimatedEyeYaw();
|
||||
trackerActive = true;
|
||||
|
||||
} else if (_visage.isActive()) {
|
||||
eyePitch = _visage.getEstimatedEyePitch();
|
||||
eyeYaw = _visage.getEstimatedEyeYaw();
|
||||
trackerActive = true;
|
||||
}
|
||||
if (trackerActive) {
|
||||
FaceTracker* tracker = getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
float eyePitch = tracker->getEstimatedEyePitch();
|
||||
float eyeYaw = tracker->getEstimatedEyeYaw();
|
||||
|
||||
// deflect using Faceshift gaze data
|
||||
glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition();
|
||||
float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
|
||||
|
@ -1840,15 +1845,15 @@ void Application::updateCamera(float deltaTime) {
|
|||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateCamera()");
|
||||
|
||||
if (!OculusManager::isConnected() && !TV3DManager::isConnected()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
|
||||
float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f;
|
||||
if (_faceshift.isActive()) {
|
||||
const float EYE_OFFSET_SCALE = 0.025f;
|
||||
glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE;
|
||||
_myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
if (!OculusManager::isConnected() && !TV3DManager::isConnected() &&
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
|
||||
FaceTracker* tracker = getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
const float EYE_OFFSET_SCALE = 0.025f;
|
||||
glm::vec3 position = tracker->getHeadTranslation() * EYE_OFFSET_SCALE;
|
||||
float xSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? 1.0f : -1.0f;
|
||||
_myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2522,15 +2527,6 @@ void Application::displayOverlay() {
|
|||
}
|
||||
}
|
||||
|
||||
// Audio Scope
|
||||
const int AUDIO_SCOPE_Y_OFFSET = 135;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
|
||||
int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET;
|
||||
_audioScope.render(MIRROR_VIEW_LEFT_PADDING, oscilloscopeTop);
|
||||
}
|
||||
}
|
||||
|
||||
// Audio VU Meter and Mute Icon
|
||||
const int MUTE_ICON_SIZE = 24;
|
||||
const int AUDIO_METER_INSET = 2;
|
||||
|
@ -3194,35 +3190,36 @@ void Application::packetSent(quint64 length) {
|
|||
|
||||
void Application::loadScripts() {
|
||||
// loads all saved scripts
|
||||
QSettings* settings = new QSettings(this);
|
||||
int size = settings->beginReadArray("Settings");
|
||||
|
||||
int size = lockSettings()->beginReadArray("Settings");
|
||||
unlockSettings();
|
||||
for (int i = 0; i < size; ++i){
|
||||
settings->setArrayIndex(i);
|
||||
QString string = settings->value("script").toString();
|
||||
loadScript(string);
|
||||
lockSettings()->setArrayIndex(i);
|
||||
QString string = _settings->value("script").toString();
|
||||
unlockSettings();
|
||||
if (!string.isEmpty()) {
|
||||
loadScript(string);
|
||||
}
|
||||
}
|
||||
|
||||
settings->endArray();
|
||||
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->endArray();
|
||||
}
|
||||
|
||||
void Application::clearScriptsBeforeRunning() {
|
||||
// clears all scripts from the settings
|
||||
QSettings* settings = new QSettings(this);
|
||||
settings->beginWriteArray("Settings");
|
||||
settings->endArray();
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->remove("Settings");
|
||||
}
|
||||
|
||||
void Application::saveScripts() {
|
||||
// saves all current running scripts
|
||||
QSettings* settings = new QSettings(this);
|
||||
settings->beginWriteArray("Settings");
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->beginWriteArray("Settings");
|
||||
for (int i = 0; i < getRunningScripts().size(); ++i){
|
||||
settings->setArrayIndex(i);
|
||||
settings->setValue("script", getRunningScripts().at(i));
|
||||
_settings->setArrayIndex(i);
|
||||
_settings->setValue("script", getRunningScripts().at(i));
|
||||
}
|
||||
|
||||
settings->endArray();
|
||||
_settings->endArray();
|
||||
}
|
||||
|
||||
void Application::stopAllScripts() {
|
||||
|
@ -3363,7 +3360,10 @@ void Application::loadDialog() {
|
|||
|
||||
if (_previousScriptLocation.isEmpty()) {
|
||||
QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475
|
||||
#ifdef __APPLE__
|
||||
suggestedName = desktopLocation.append("/script.js");
|
||||
#endif
|
||||
} else {
|
||||
suggestedName = _previousScriptLocation;
|
||||
}
|
||||
|
@ -3372,9 +3372,11 @@ void Application::loadDialog() {
|
|||
tr("JavaScript Files (*.js)"));
|
||||
if (!fileNameString.isEmpty()) {
|
||||
_previousScriptLocation = fileNameString;
|
||||
QMutexLocker locker(&_settingsMutex);
|
||||
_settings->setValue("LastScriptLocation", _previousScriptLocation);
|
||||
|
||||
loadScript(fileNameString);
|
||||
}
|
||||
|
||||
loadScript(fileNameString);
|
||||
}
|
||||
|
||||
void Application::loadScriptURLDialog() {
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "avatar/Avatar.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "devices/Faceplus.h"
|
||||
#include "devices/Faceshift.h"
|
||||
#include "devices/SixenseManager.h"
|
||||
#include "devices/Visage.h"
|
||||
|
@ -176,8 +177,10 @@ public:
|
|||
bool isMouseHidden() const { return _mouseHidden; }
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
Faceplus* getFaceplus() { return &_faceplus; }
|
||||
Faceshift* getFaceshift() { return &_faceshift; }
|
||||
Visage* getVisage() { return &_visage; }
|
||||
FaceTracker* getActiveFaceTracker();
|
||||
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
||||
BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; }
|
||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||
|
@ -185,6 +188,8 @@ public:
|
|||
/// if you need to access the application settings, use lockSettings()/unlockSettings()
|
||||
QSettings* lockSettings() { _settingsMutex.lock(); return _settings; }
|
||||
void unlockSettings() { _settingsMutex.unlock(); }
|
||||
|
||||
void saveSettings();
|
||||
|
||||
QMainWindow* getWindow() { return _window; }
|
||||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
|
@ -316,6 +321,7 @@ private:
|
|||
// Various helper functions called during update()
|
||||
void updateLOD();
|
||||
void updateMouseRay();
|
||||
void updateFaceplus();
|
||||
void updateFaceshift();
|
||||
void updateVisage();
|
||||
void updateMyAvatarLookAtPosition();
|
||||
|
@ -407,7 +413,6 @@ private:
|
|||
ViewFrustum _shadowViewFrustum;
|
||||
quint64 _lastQueriedTime;
|
||||
|
||||
Oscilloscope _audioScope;
|
||||
float _trailingAudioLoudness;
|
||||
|
||||
OctreeQuery _octreeQuery; // NodeData derived class for querying voxels from voxel server
|
||||
|
@ -415,9 +420,10 @@ private:
|
|||
AvatarManager _avatarManager;
|
||||
MyAvatar* _myAvatar; // TODO: move this and relevant code to AvatarManager (or MyAvatar as the case may be)
|
||||
|
||||
Faceplus _faceplus;
|
||||
Faceshift _faceshift;
|
||||
Visage _visage;
|
||||
|
||||
|
||||
SixenseManager _sixenseManager;
|
||||
|
||||
Camera _myCamera; // My view onto the world
|
||||
|
|
|
@ -50,7 +50,7 @@ static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300;
|
|||
// Mute icon configration
|
||||
static const int MUTE_ICON_SIZE = 24;
|
||||
|
||||
Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent) :
|
||||
Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
|
||||
AbstractAudioInterface(parent),
|
||||
_audioInput(NULL),
|
||||
_desiredInputFormat(),
|
||||
|
@ -67,7 +67,6 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p
|
|||
_proceduralOutputDevice(NULL),
|
||||
_inputRingBuffer(0),
|
||||
_ringBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL),
|
||||
_scope(scope),
|
||||
_averagedLatency(0.0),
|
||||
_measuredJitter(0),
|
||||
_jitterBufferSamples(initialJitterBufferSamples),
|
||||
|
@ -555,12 +554,6 @@ void Audio::handleAudioInput() {
|
|||
_lastInputLoudness = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// add input data just written to the scope
|
||||
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, QByteArray((char*) monoAudioSamples,
|
||||
NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL)),
|
||||
Q_ARG(bool, false), Q_ARG(bool, true));
|
||||
} else {
|
||||
// our input loudness is 0, since we're muted
|
||||
_lastInputLoudness = 0;
|
||||
|
@ -724,11 +717,6 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
|
|||
|
||||
if (_outputDevice) {
|
||||
_outputDevice->write(outputBuffer);
|
||||
|
||||
// add output (@speakers) data just written to the scope
|
||||
QMetaObject::invokeMethod(_scope, "addSamples", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, QByteArray((char*) ringBufferSamples, numNetworkOutputSamples)),
|
||||
Q_ARG(bool, true), Q_ARG(bool, false));
|
||||
}
|
||||
delete[] ringBufferSamples;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
#include <AudioRingBuffer.h>
|
||||
#include <StdDev.h>
|
||||
|
||||
#include "ui/Oscilloscope.h"
|
||||
|
||||
|
||||
static const int NUM_AUDIO_CHANNELS = 2;
|
||||
|
||||
class QAudioInput;
|
||||
|
@ -47,7 +44,7 @@ class Audio : public AbstractAudioInterface {
|
|||
Q_OBJECT
|
||||
public:
|
||||
// setup for audio I/O
|
||||
Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||
Audio(int16_t initialJitterBufferSamples, QObject* parent = 0);
|
||||
|
||||
float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); }
|
||||
float getTimeSinceLastClip() const { return _timeSinceLastClip; }
|
||||
|
@ -126,7 +123,6 @@ private:
|
|||
QString _inputAudioDeviceName;
|
||||
QString _outputAudioDeviceName;
|
||||
|
||||
Oscilloscope* _scope;
|
||||
StDev _stdev;
|
||||
timeval _lastReceiveTime;
|
||||
float _averagedLatency;
|
||||
|
|
|
@ -252,7 +252,6 @@ Menu::Menu() :
|
|||
addDisabledActionAndSeparator(viewMenu, "Stats");
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Oscilloscope, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
|
||||
|
@ -304,6 +303,11 @@ Menu::Menu() :
|
|||
true,
|
||||
appInstance->getFaceshift(),
|
||||
SLOT(setTCPEnabled(bool)));
|
||||
#ifdef HAVE_FACEPLUS
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceplus, 0, true,
|
||||
appInstance->getFaceplus(), SLOT(updateEnabled()));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, true,
|
||||
appInstance->getVisage(), SLOT(updateEnabled()));
|
||||
|
|
|
@ -253,6 +253,7 @@ namespace MenuOption {
|
|||
const QString EchoLocalAudio = "Echo Local Audio";
|
||||
const QString EchoServerAudio = "Echo Server Audio";
|
||||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||
const QString Faceplus = "Faceplus";
|
||||
const QString Faceshift = "Faceshift";
|
||||
const QString FilterSixense = "Smooth Sixense Movement";
|
||||
const QString FirstPerson = "First Person";
|
||||
|
@ -287,7 +288,6 @@ namespace MenuOption {
|
|||
const QString OctreeStats = "Voxel and Particle Statistics";
|
||||
const QString OffAxisProjection = "Off-Axis Projection";
|
||||
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
|
||||
const QString Oscilloscope = "Audio Oscilloscope";
|
||||
const QString Pair = "Pair";
|
||||
const QString Particles = "Particles";
|
||||
const QString PasteToVoxel = "Paste to Voxel...";
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
#include <AccountManager.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
|
||||
#include "ModelUploader.h"
|
||||
|
||||
|
||||
|
@ -34,6 +36,8 @@ static const QString LOD_FIELD = "lod";
|
|||
static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com";
|
||||
static const QString MODEL_URL = "/api/v1/models";
|
||||
|
||||
static const QString SETTING_NAME = "LastModelUploadLocation";
|
||||
|
||||
static const int MAX_SIZE = 10 * 1024 * 1024; // 10 MB
|
||||
static const int TIMEOUT = 1000;
|
||||
static const int MAX_CHECK = 30;
|
||||
|
@ -59,14 +63,27 @@ ModelUploader::~ModelUploader() {
|
|||
|
||||
bool ModelUploader::zip() {
|
||||
// File Dialog
|
||||
QString filename = QFileDialog::getOpenFileName(NULL,
|
||||
"Select your .fst file ...",
|
||||
QStandardPaths::writableLocation(QStandardPaths::HomeLocation),
|
||||
"*.fst");
|
||||
QSettings* settings = Application::getInstance()->lockSettings();
|
||||
QString lastLocation = settings->value(SETTING_NAME).toString();
|
||||
|
||||
if (lastLocation.isEmpty()) {
|
||||
lastLocation = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475
|
||||
#ifdef __APPLE__
|
||||
lastLocation.append("/model.fst");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
QString filename = QFileDialog::getOpenFileName(NULL, "Select your .fst file ...", lastLocation, "*.fst");
|
||||
if (filename == "") {
|
||||
// If the user canceled we return.
|
||||
Application::getInstance()->unlockSettings();
|
||||
return false;
|
||||
}
|
||||
settings->setValue(SETTING_NAME, filename);
|
||||
Application::getInstance()->unlockSettings();
|
||||
|
||||
bool _nameIsPresent = false;
|
||||
QString texDir;
|
||||
QString fbxFile;
|
||||
|
|
|
@ -233,22 +233,22 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
|
||||
// quick check before falling into the code below:
|
||||
// (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m)
|
||||
const float MIN_VOICE_SPHERE_DISTANCE = 12.f;
|
||||
const float MIN_VOICE_SPHERE_DISTANCE = 12.0f;
|
||||
if (distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) {
|
||||
// render voice intensity sphere for avatars that are farther away
|
||||
const float MAX_SPHERE_ANGLE = 10.f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_ANGLE = 1.f * RADIANS_PER_DEGREE;
|
||||
const float MAX_SPHERE_ANGLE = 10.0f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_ANGLE = 1.0f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_SIZE = 0.01f;
|
||||
const float SPHERE_LOUDNESS_SCALING = 0.0005f;
|
||||
const float SPHERE_COLOR[] = { 0.5f, 0.8f, 0.8f };
|
||||
float height = getSkeletonHeight();
|
||||
glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.f;
|
||||
glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.0f;
|
||||
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
|
||||
float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING;
|
||||
|
||||
if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
|
||||
(angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
|
||||
glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.f - angle / MAX_SPHERE_ANGLE);
|
||||
glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE);
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(height, height, height);
|
||||
|
@ -280,9 +280,9 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
glm::vec3 chatAxis = glm::axis(chatRotation);
|
||||
glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
|
||||
glColor3f(0.f, 0.8f, 0.f);
|
||||
glRotatef(180.f, 0.f, 1.f, 0.f);
|
||||
glRotatef(180.f, 0.f, 0.f, 1.f);
|
||||
glColor3f(0.0f, 0.8f, 0.0f);
|
||||
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
|
||||
glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -298,7 +298,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
_chatMessage[lastIndex] = '\0';
|
||||
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
||||
_chatMessage[lastIndex] = lastChar;
|
||||
glColor3f(0.f, 1.f, 0.f);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
@ -555,7 +555,7 @@ bool Avatar::findParticleCollisions(const glm::vec3& particleCenter, float parti
|
|||
const PalmData* palm = handData->getPalm(i);
|
||||
if (palm && palm->hasPaddle()) {
|
||||
// create a disk collision proxy where the hand is
|
||||
glm::vec3 fingerAxis(0.f);
|
||||
glm::vec3 fingerAxis(0.0f);
|
||||
for (size_t f = 0; f < palm->getNumFingers(); ++f) {
|
||||
const FingerData& finger = (palm->getFingers())[f];
|
||||
if (finger.isActive()) {
|
||||
|
@ -697,8 +697,8 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
|||
glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin));
|
||||
perpSin = glm::cross(perpCos, axis);
|
||||
|
||||
float anglea = 0.f;
|
||||
float angleb = 0.f;
|
||||
float anglea = 0.0f;
|
||||
float angleb = 0.0f;
|
||||
|
||||
for (int i = 0; i < NUM_BODY_CONE_SIDES; i ++) {
|
||||
|
||||
|
@ -748,8 +748,8 @@ void Avatar::updateCollisionFlags() {
|
|||
void Avatar::setScale(float scale) {
|
||||
_scale = scale;
|
||||
|
||||
if (_targetScale * (1.f - RESCALING_TOLERANCE) < _scale &&
|
||||
_scale < _targetScale * (1.f + RESCALING_TOLERANCE)) {
|
||||
if (_targetScale * (1.0f - RESCALING_TOLERANCE) < _scale &&
|
||||
_scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) {
|
||||
_scale = _targetScale;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ enum ScreenTintLayer {
|
|||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found)
|
||||
// this is basically in the center of the ground plane. Slightly adjusted. This was asked for by
|
||||
// Grayson as he's building a street around here for demo dinner 2
|
||||
const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.f, 0.5f * TREE_SCALE);
|
||||
const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.0f, 0.5f * TREE_SCALE);
|
||||
|
||||
class Texture;
|
||||
|
||||
|
@ -149,8 +149,6 @@ public:
|
|||
|
||||
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
||||
|
||||
|
||||
|
||||
/// \return true if we expect the avatar would move as a result of the collision
|
||||
bool collisionWouldMoveAvatar(CollisionInfo& collision) const;
|
||||
|
||||
|
@ -163,6 +161,9 @@ public:
|
|||
public slots:
|
||||
void updateCollisionFlags();
|
||||
|
||||
signals:
|
||||
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
||||
|
||||
protected:
|
||||
SkeletonModel _skeletonModel;
|
||||
float _bodyYawDelta;
|
||||
|
|
|
@ -163,6 +163,11 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
|||
// TODO: submit collision info to MyAvatar which should lean accordingly
|
||||
averageContactPoint /= (float)handCollisions.size();
|
||||
avatar->applyCollision(averageContactPoint, totalPenetration);
|
||||
|
||||
CollisionInfo collision;
|
||||
collision._penetration = totalPenetration;
|
||||
collision._contactPoint = averageContactPoint;
|
||||
emit avatar->collisionWithAvatar(avatar->getSessionUUID(), _owningAvatar->getSessionUUID(), collision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,17 +64,11 @@ void Head::reset() {
|
|||
|
||||
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||
// Update audio trailing average for rendering facial animations
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
Visage* visage = Application::getInstance()->getVisage();
|
||||
if (isMine) {
|
||||
_isFaceshiftConnected = false;
|
||||
if (faceshift->isActive()) {
|
||||
_blendshapeCoefficients = faceshift->getBlendshapeCoefficients();
|
||||
_isFaceshiftConnected = true;
|
||||
|
||||
} else if (visage->isActive()) {
|
||||
_blendshapeCoefficients = visage->getBlendshapeCoefficients();
|
||||
_isFaceshiftConnected = true;
|
||||
FaceTracker* faceTracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if ((_isFaceshiftConnected = faceTracker)) {
|
||||
_blendshapeCoefficients = faceTracker->getBlendshapeCoefficients();
|
||||
_isFaceshiftConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,8 +150,9 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
|||
const float BROW_LIFT_SCALE = 500.0f;
|
||||
const float JAW_OPEN_SCALE = 0.01f;
|
||||
const float JAW_OPEN_DEAD_ZONE = 0.75f;
|
||||
faceshift->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, min(1.0f, _browAudioLift * BROW_LIFT_SCALE),
|
||||
glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients);
|
||||
Application::getInstance()->getFaceshift()->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink,
|
||||
min(1.0f, _browAudioLift * BROW_LIFT_SCALE), glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) -
|
||||
JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients);
|
||||
}
|
||||
|
||||
if (!isMine) {
|
||||
|
|
|
@ -65,7 +65,8 @@ MyAvatar::MyAvatar() :
|
|||
_moveTargetStepCounter(0),
|
||||
_lookAtTargetAvatar(),
|
||||
_shouldRender(true),
|
||||
_billboardValid(false)
|
||||
_billboardValid(false),
|
||||
_oculusYawOffset(0.0f)
|
||||
{
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
@ -88,10 +89,11 @@ void MyAvatar::reset() {
|
|||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
getHand()->reset();
|
||||
_oculusYawOffset = 0.0f;
|
||||
|
||||
setVelocity(glm::vec3(0.f));
|
||||
setThrust(glm::vec3(0.f));
|
||||
setOrientation(glm::quat(glm::vec3(0.f)));
|
||||
setVelocity(glm::vec3(0.0f));
|
||||
setThrust(glm::vec3(0.0f));
|
||||
setOrientation(glm::quat(glm::vec3(0.0f)));
|
||||
}
|
||||
|
||||
void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
|
||||
|
@ -114,8 +116,8 @@ void MyAvatar::update(float deltaTime) {
|
|||
// TODO? resurrect headMouse stuff?
|
||||
//glm::vec3 headVelocity = faceshift->getHeadAngularVelocity();
|
||||
//// sets how quickly head angular rotation moves the head mouse
|
||||
//const float HEADMOUSE_FACESHIFT_YAW_SCALE = 40.f;
|
||||
//const float HEADMOUSE_FACESHIFT_PITCH_SCALE = 30.f;
|
||||
//const float HEADMOUSE_FACESHIFT_YAW_SCALE = 40.0f;
|
||||
//const float HEADMOUSE_FACESHIFT_PITCH_SCALE = 30.0f;
|
||||
//_headMouseX -= headVelocity.y * HEADMOUSE_FACESHIFT_YAW_SCALE;
|
||||
//_headMouseY -= headVelocity.x * HEADMOUSE_FACESHIFT_PITCH_SCALE;
|
||||
//
|
||||
|
@ -124,16 +126,6 @@ void MyAvatar::update(float deltaTime) {
|
|||
//_headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height());
|
||||
}
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
float yaw, pitch, roll; // these angles will be in radians
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
|
||||
// but these euler angles are stored in degrees
|
||||
head->setBaseYaw(yaw * DEGREES_PER_RADIAN);
|
||||
head->setBasePitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setBaseRoll(roll * DEGREES_PER_RADIAN);
|
||||
}
|
||||
|
||||
// Get audio loudness data from audio input device
|
||||
Audio* audio = Application::getInstance()->getAudio();
|
||||
head->setAudioLoudness(audio->getLastInputLoudness());
|
||||
|
@ -156,15 +148,15 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
_elapsedTimeSinceCollision += deltaTime;
|
||||
const float VELOCITY_MOVEMENT_TIMER_THRESHOLD = 0.2f;
|
||||
if (glm::length(_velocity) < VELOCITY_MOVEMENT_TIMER_THRESHOLD) {
|
||||
_elapsedTimeMoving = 0.f;
|
||||
_elapsedTimeMoving = 0.0f;
|
||||
_elapsedTimeStopped += deltaTime;
|
||||
} else {
|
||||
_elapsedTimeStopped = 0.f;
|
||||
_elapsedTimeStopped = 0.0f;
|
||||
_elapsedTimeMoving += deltaTime;
|
||||
}
|
||||
|
||||
if (_scale != _targetScale) {
|
||||
float scale = (1.f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
|
||||
float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
|
||||
setScale(scale);
|
||||
Application::getInstance()->getCamera()->setScale(scale);
|
||||
}
|
||||
|
@ -192,19 +184,19 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
// decay body rotation momentum
|
||||
|
||||
const float BODY_SPIN_FRICTION = 7.5f;
|
||||
float bodySpinMomentum = 1.f - BODY_SPIN_FRICTION * deltaTime;
|
||||
float bodySpinMomentum = 1.0f - BODY_SPIN_FRICTION * deltaTime;
|
||||
if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; }
|
||||
_bodyPitchDelta *= bodySpinMomentum;
|
||||
_bodyYawDelta *= bodySpinMomentum;
|
||||
_bodyRollDelta *= bodySpinMomentum;
|
||||
|
||||
float MINIMUM_ROTATION_RATE = 2.0f;
|
||||
if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.f; }
|
||||
if (fabs(_bodyRollDelta) < MINIMUM_ROTATION_RATE) { _bodyRollDelta = 0.f; }
|
||||
if (fabs(_bodyPitchDelta) < MINIMUM_ROTATION_RATE) { _bodyPitchDelta = 0.f; }
|
||||
if (fabs(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { _bodyYawDelta = 0.0f; }
|
||||
if (fabs(_bodyRollDelta) < MINIMUM_ROTATION_RATE) { _bodyRollDelta = 0.0f; }
|
||||
if (fabs(_bodyPitchDelta) < MINIMUM_ROTATION_RATE) { _bodyPitchDelta = 0.0f; }
|
||||
|
||||
const float MAX_STATIC_FRICTION_SPEED = 0.5f;
|
||||
const float STATIC_FRICTION_STRENGTH = _scale * 20.f;
|
||||
const float STATIC_FRICTION_STRENGTH = _scale * 20.0f;
|
||||
applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_SPEED, STATIC_FRICTION_STRENGTH);
|
||||
|
||||
// Damp avatar velocity
|
||||
|
@ -212,11 +204,11 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
const float SPEED_BRAKE_POWER = _scale * 10.0f;
|
||||
const float SQUARED_DAMPING_STRENGTH = 0.007f;
|
||||
|
||||
const float SLOW_NEAR_RADIUS = 5.f;
|
||||
const float SLOW_NEAR_RADIUS = 5.0f;
|
||||
float linearDamping = LINEAR_DAMPING_STRENGTH;
|
||||
const float NEAR_AVATAR_DAMPING_FACTOR = 50.f;
|
||||
const float NEAR_AVATAR_DAMPING_FACTOR = 50.0f;
|
||||
if (_distanceToNearestAvatar < _scale * SLOW_NEAR_RADIUS) {
|
||||
linearDamping *= 1.f + NEAR_AVATAR_DAMPING_FACTOR *
|
||||
linearDamping *= 1.0f + NEAR_AVATAR_DAMPING_FACTOR *
|
||||
((SLOW_NEAR_RADIUS - _distanceToNearestAvatar) / SLOW_NEAR_RADIUS);
|
||||
}
|
||||
if (_speedBrakes) {
|
||||
|
@ -225,6 +217,54 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
applyDamping(deltaTime, _velocity, linearDamping, SQUARED_DAMPING_STRENGTH);
|
||||
}
|
||||
|
||||
if (OculusManager::isConnected()) {
|
||||
// these angles will be in radians
|
||||
float yaw, pitch, roll;
|
||||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
// ... so they need to be converted to degrees before we do math...
|
||||
|
||||
// The neck is limited in how much it can yaw, so we check its relative
|
||||
// yaw from the body and yaw the body if necessary.
|
||||
yaw *= DEGREES_PER_RADIAN;
|
||||
float bodyToHeadYaw = yaw - _oculusYawOffset;
|
||||
const float MAX_NECK_YAW = 85.0f; // degrees
|
||||
if ((fabs(bodyToHeadYaw) > 2.0f * MAX_NECK_YAW) && (yaw * _oculusYawOffset < 0.0f)) {
|
||||
// We've wrapped around the range for yaw so adjust
|
||||
// the measured yaw to be relative to _oculusYawOffset.
|
||||
if (yaw > 0.0f) {
|
||||
yaw -= 360.0f;
|
||||
} else {
|
||||
yaw += 360.0f;
|
||||
}
|
||||
bodyToHeadYaw = yaw - _oculusYawOffset;
|
||||
}
|
||||
|
||||
float delta = fabs(bodyToHeadYaw) - MAX_NECK_YAW;
|
||||
if (delta > 0.0f) {
|
||||
yaw = MAX_NECK_YAW;
|
||||
if (bodyToHeadYaw < 0.0f) {
|
||||
delta *= -1.0f;
|
||||
bodyToHeadYaw = -MAX_NECK_YAW;
|
||||
} else {
|
||||
bodyToHeadYaw = MAX_NECK_YAW;
|
||||
}
|
||||
// constrain _oculusYawOffset to be within range [-180,180]
|
||||
_oculusYawOffset = fmod((_oculusYawOffset + delta) + 180.0f, 360.0f) - 180.0f;
|
||||
|
||||
// We must adjust the body orientation using a delta rotation (rather than
|
||||
// doing yaw math) because the body's yaw ranges are not the same
|
||||
// as what the Oculus API provides.
|
||||
glm::vec3 UP_AXIS = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), UP_AXIS);
|
||||
orientation = orientation * bodyCorrection;
|
||||
}
|
||||
Head* head = getHead();
|
||||
head->setBaseYaw(bodyToHeadYaw);
|
||||
|
||||
head->setBasePitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setBaseRoll(roll * DEGREES_PER_RADIAN);
|
||||
}
|
||||
|
||||
// update the euler angles
|
||||
setOrientation(orientation);
|
||||
|
||||
|
@ -243,7 +283,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
// If a move target is set, update position explicitly
|
||||
const float MOVE_FINISHED_TOLERANCE = 0.1f;
|
||||
const float MOVE_SPEED_FACTOR = 2.f;
|
||||
const float MOVE_SPEED_FACTOR = 2.0f;
|
||||
const int MOVE_TARGET_MAX_STEPS = 250;
|
||||
if ((glm::length(_moveTarget) > EPSILON) && (_moveTargetStepCounter < MOVE_TARGET_MAX_STEPS)) {
|
||||
if (glm::length(_position - _moveTarget) > MOVE_FINISHED_TOLERANCE) {
|
||||
|
@ -283,7 +323,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
head->simulate(deltaTime, true);
|
||||
|
||||
// Zero thrust out now that we've added it to velocity in this frame
|
||||
_thrust = glm::vec3(0.f);
|
||||
_thrust = glm::vec3(0.0f);
|
||||
|
||||
// now that we're done stepping the avatar forward in time, compute new collisions
|
||||
if (_collisionFlags != 0) {
|
||||
|
@ -291,7 +331,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
|
||||
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
|
||||
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f));
|
||||
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f));
|
||||
radius *= COLLISION_RADIUS_SCALAR;
|
||||
}
|
||||
|
||||
|
@ -312,45 +352,35 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
// Update avatar head rotation with sensor data
|
||||
void MyAvatar::updateFromGyros(float deltaTime) {
|
||||
Faceshift* faceshift = Application::getInstance()->getFaceshift();
|
||||
Visage* visage = Application::getInstance()->getVisage();
|
||||
glm::vec3 estimatedPosition, estimatedRotation;
|
||||
|
||||
bool trackerActive = false;
|
||||
if (faceshift->isActive()) {
|
||||
estimatedPosition = faceshift->getHeadTranslation();
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(faceshift->getHeadRotation()));
|
||||
trackerActive = true;
|
||||
|
||||
} else if (visage->isActive()) {
|
||||
estimatedPosition = visage->getHeadTranslation();
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(visage->getHeadRotation()));
|
||||
trackerActive = true;
|
||||
}
|
||||
|
||||
Head* head = getHead();
|
||||
if (trackerActive) {
|
||||
FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker();
|
||||
if (tracker) {
|
||||
estimatedPosition = tracker->getHeadTranslation();
|
||||
estimatedRotation = glm::degrees(safeEulerAngles(tracker->getHeadRotation()));
|
||||
|
||||
// Rotate the body if the head is turned beyond the screen
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
|
||||
const float TRACKER_YAW_TURN_SENSITIVITY = 0.5f;
|
||||
const float TRACKER_MIN_YAW_TURN = 15.f;
|
||||
const float TRACKER_MAX_YAW_TURN = 50.f;
|
||||
const float TRACKER_MIN_YAW_TURN = 15.0f;
|
||||
const float TRACKER_MAX_YAW_TURN = 50.0f;
|
||||
if ( (fabs(estimatedRotation.y) > TRACKER_MIN_YAW_TURN) &&
|
||||
(fabs(estimatedRotation.y) < TRACKER_MAX_YAW_TURN) ) {
|
||||
if (estimatedRotation.y > 0.f) {
|
||||
if (estimatedRotation.y > 0.0f) {
|
||||
_bodyYawDelta += (estimatedRotation.y - TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
} else {
|
||||
_bodyYawDelta += (estimatedRotation.y + TRACKER_MIN_YAW_TURN) * TRACKER_YAW_TURN_SENSITIVITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the rotation of the avatar's head (as seen by others, not affecting view frustum)
|
||||
// to be scaled. Pitch is greater to emphasize nodding behavior / synchrony.
|
||||
const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f;
|
||||
const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f;
|
||||
Head* head = getHead();
|
||||
head->setDeltaPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
|
||||
head->setDeltaYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
|
||||
head->setDeltaRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
|
||||
|
@ -375,20 +405,20 @@ void MyAvatar::moveWithLean() {
|
|||
float leanSideways = head->getLeanSideways();
|
||||
|
||||
// Degrees of 'dead zone' when leaning, and amount of acceleration to apply to lean angle
|
||||
const float LEAN_FWD_DEAD_ZONE = 15.f;
|
||||
const float LEAN_SIDEWAYS_DEAD_ZONE = 10.f;
|
||||
const float LEAN_FWD_THRUST_SCALE = 4.f;
|
||||
const float LEAN_SIDEWAYS_THRUST_SCALE = 3.f;
|
||||
const float LEAN_FWD_DEAD_ZONE = 15.0f;
|
||||
const float LEAN_SIDEWAYS_DEAD_ZONE = 10.0f;
|
||||
const float LEAN_FWD_THRUST_SCALE = 4.0f;
|
||||
const float LEAN_SIDEWAYS_THRUST_SCALE = 3.0f;
|
||||
|
||||
if (fabs(leanForward) > LEAN_FWD_DEAD_ZONE) {
|
||||
if (leanForward > 0.f) {
|
||||
if (leanForward > 0.0f) {
|
||||
addThrust(front * -(leanForward - LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE);
|
||||
} else {
|
||||
addThrust(front * -(leanForward + LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE);
|
||||
}
|
||||
}
|
||||
if (fabs(leanSideways) > LEAN_SIDEWAYS_DEAD_ZONE) {
|
||||
if (leanSideways > 0.f) {
|
||||
if (leanSideways > 0.0f) {
|
||||
addThrust(right * -(leanSideways - LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE);
|
||||
} else {
|
||||
addThrust(right * -(leanSideways + LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE);
|
||||
|
@ -435,7 +465,7 @@ void MyAvatar::renderHeadMouse() const {
|
|||
// TODO? resurrect headMouse stuff?
|
||||
/*
|
||||
// Display small target box at center or head mouse target that can also be used to measure LOD
|
||||
glColor3f(1.f, 1.f, 1.f);
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
const int PIXEL_BOX = 16;
|
||||
glBegin(GL_LINES);
|
||||
|
@ -445,7 +475,7 @@ void MyAvatar::renderHeadMouse() const {
|
|||
glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2);
|
||||
glEnd();
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glColor3f(1.f, 0.f, 0.f);
|
||||
glColor3f(1.0f, 0.0f, 0.0f);
|
||||
glPointSize(3.0f);
|
||||
glDisable(GL_POINT_SMOOTH);
|
||||
glBegin(GL_POINTS);
|
||||
|
@ -457,7 +487,7 @@ void MyAvatar::renderHeadMouse() const {
|
|||
int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||
int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||
|
||||
glColor3f(0.f, 1.f, 1.f);
|
||||
glColor3f(0.0f, 1.0f, 1.0f);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(eyeTargetX - PIXEL_BOX/2, eyeTargetY);
|
||||
|
@ -578,11 +608,6 @@ void MyAvatar::clearLookAtTargetAvatar() {
|
|||
_lookAtTargetAvatar.clear();
|
||||
}
|
||||
|
||||
float MyAvatar::getAbsoluteHeadYaw() const {
|
||||
const Head* head = static_cast<const Head*>(_headData);
|
||||
return glm::yaw(head->getOrientation());
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::getUprightHeadPosition() const {
|
||||
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f);
|
||||
}
|
||||
|
@ -641,11 +666,11 @@ void MyAvatar::updateThrust(float deltaTime) {
|
|||
glm::vec3 up = orientation * IDENTITY_UP;
|
||||
|
||||
const float THRUST_MAG_UP = 800.0f;
|
||||
const float THRUST_MAG_DOWN = 300.f;
|
||||
const float THRUST_MAG_FWD = 500.f;
|
||||
const float THRUST_MAG_BACK = 300.f;
|
||||
const float THRUST_MAG_LATERAL = 250.f;
|
||||
const float THRUST_JUMP = 120.f;
|
||||
const float THRUST_MAG_DOWN = 300.0f;
|
||||
const float THRUST_MAG_FWD = 500.0f;
|
||||
const float THRUST_MAG_BACK = 300.0f;
|
||||
const float THRUST_MAG_LATERAL = 250.0f;
|
||||
const float THRUST_JUMP = 120.0f;
|
||||
|
||||
// Add Thrusts from keyboard
|
||||
_thrust += _driveKeys[FWD] * _scale * THRUST_MAG_FWD * _thrustMultiplier * deltaTime * front;
|
||||
|
@ -656,25 +681,25 @@ void MyAvatar::updateThrust(float deltaTime) {
|
|||
_thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;
|
||||
|
||||
// attenuate thrust when in penetration
|
||||
if (glm::dot(_thrust, _lastBodyPenetration) > 0.f) {
|
||||
if (glm::dot(_thrust, _lastBodyPenetration) > 0.0f) {
|
||||
const float MAX_BODY_PENETRATION_DEPTH = 0.6f * _skeletonModel.getBoundingShapeRadius();
|
||||
float penetrationFactor = glm::min(1.f, glm::length(_lastBodyPenetration) / MAX_BODY_PENETRATION_DEPTH);
|
||||
float penetrationFactor = glm::min(1.0f, glm::length(_lastBodyPenetration) / MAX_BODY_PENETRATION_DEPTH);
|
||||
glm::vec3 penetrationDirection = glm::normalize(_lastBodyPenetration);
|
||||
// attenuate parallel component
|
||||
glm::vec3 parallelThrust = glm::dot(_thrust, penetrationDirection) * penetrationDirection;
|
||||
// attenuate perpendicular component (friction)
|
||||
glm::vec3 perpendicularThrust = _thrust - parallelThrust;
|
||||
// recombine to get the final thrust
|
||||
_thrust = (1.f - penetrationFactor) * parallelThrust + (1.f - penetrationFactor * penetrationFactor) * perpendicularThrust;
|
||||
_thrust = (1.0f - penetrationFactor) * parallelThrust + (1.0f - penetrationFactor * penetrationFactor) * perpendicularThrust;
|
||||
|
||||
// attenuate the growth of _thrustMultiplier when in penetration
|
||||
// otherwise the avatar will eventually be able to tunnel through the obstacle
|
||||
_thrustMultiplier *= (1.f - penetrationFactor * penetrationFactor);
|
||||
} else if (_thrustMultiplier < 1.f) {
|
||||
_thrustMultiplier *= (1.0f - penetrationFactor * penetrationFactor);
|
||||
} else if (_thrustMultiplier < 1.0f) {
|
||||
// rapid healing of attenuated thrustMultiplier after penetration event
|
||||
_thrustMultiplier = 1.f;
|
||||
_thrustMultiplier = 1.0f;
|
||||
}
|
||||
_lastBodyPenetration = glm::vec3(0.f);
|
||||
_lastBodyPenetration = glm::vec3(0.0f);
|
||||
|
||||
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
|
||||
_bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime;
|
||||
|
@ -684,12 +709,12 @@ void MyAvatar::updateThrust(float deltaTime) {
|
|||
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
||||
const float THRUST_INCREASE_RATE = 1.05f;
|
||||
const float MAX_THRUST_MULTIPLIER = 75.0f;
|
||||
_thrustMultiplier *= 1.f + deltaTime * THRUST_INCREASE_RATE;
|
||||
_thrustMultiplier *= 1.0f + deltaTime * THRUST_INCREASE_RATE;
|
||||
if (_thrustMultiplier > MAX_THRUST_MULTIPLIER) {
|
||||
_thrustMultiplier = MAX_THRUST_MULTIPLIER;
|
||||
}
|
||||
} else {
|
||||
_thrustMultiplier = 1.f;
|
||||
_thrustMultiplier = 1.0f;
|
||||
}
|
||||
|
||||
// Add one time jumping force if requested
|
||||
|
@ -794,11 +819,11 @@ void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity
|
|||
if (penetrationLength > EPSILON) {
|
||||
_elapsedTimeSinceCollision = 0.0f;
|
||||
glm::vec3 direction = penetration / penetrationLength;
|
||||
_velocity -= glm::dot(_velocity, direction) * direction * (1.f + elasticity);
|
||||
_velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
|
||||
if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.f)) {
|
||||
_velocity -= glm::dot(_velocity, direction) * direction * (1.0f + elasticity);
|
||||
_velocity *= glm::clamp(1.0f - damping, 0.0f, 1.0f);
|
||||
if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.0f)) {
|
||||
// If moving really slowly after a collision, and not applying forces, stop altogether
|
||||
_velocity *= 0.f;
|
||||
_velocity *= 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -806,7 +831,7 @@ void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity
|
|||
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
||||
// consider whether to have the collision make a sound
|
||||
const float AUDIBLE_COLLISION_THRESHOLD = 0.02f;
|
||||
const float COLLISION_LOUDNESS = 1.f;
|
||||
const float COLLISION_LOUDNESS = 1.0f;
|
||||
const float DURATION_SCALING = 0.004f;
|
||||
const float NOISE_SCALING = 0.1f;
|
||||
glm::vec3 velocity = _velocity;
|
||||
|
@ -826,10 +851,10 @@ void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTim
|
|||
// Noise is a function of the angle of collision
|
||||
// Duration of the sound is a function of both base frequency and velocity of impact
|
||||
Application::getInstance()->getAudio()->startCollisionSound(
|
||||
std::min(COLLISION_LOUDNESS * velocityTowardCollision, 1.f),
|
||||
frequency * (1.f + velocityTangentToCollision / velocityTowardCollision),
|
||||
std::min(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f),
|
||||
1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, true);
|
||||
std::min(COLLISION_LOUDNESS * velocityTowardCollision, 1.0f),
|
||||
frequency * (1.0f + velocityTangentToCollision / velocityTowardCollision),
|
||||
std::min(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.0f),
|
||||
1.0f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -842,8 +867,8 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
|||
float halfHeights = 0.5 * (heightA + heightB);
|
||||
if (yDistance < halfHeights) {
|
||||
// cylinders collide
|
||||
if (xzDistance > 0.f) {
|
||||
positionBA.y = 0.f;
|
||||
if (xzDistance > 0.0f) {
|
||||
positionBA.y = 0.0f;
|
||||
// note, penetration should point from A into B
|
||||
penetration = positionBA * ((radiusA + radiusB - xzDistance) / xzDistance);
|
||||
return true;
|
||||
|
@ -853,7 +878,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
|||
}
|
||||
} else if (yDistance < halfHeights + radiusA + radiusB) {
|
||||
// caps collide
|
||||
if (positionBA.y < 0.f) {
|
||||
if (positionBA.y < 0.0f) {
|
||||
// A is above B
|
||||
positionBA.y += halfHeights;
|
||||
float BA = glm::length(positionBA);
|
||||
|
@ -871,8 +896,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
|||
return false;
|
||||
}
|
||||
|
||||
static CollisionList bodyCollisions(16);
|
||||
const float BODY_COLLISION_RESOLVE_TIMESCALE = 0.5f; // seconds
|
||||
const float BODY_COLLISION_RESOLUTION_TIMESCALE = 0.5f; // seconds
|
||||
|
||||
void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
||||
// Reset detector for nearest avatar
|
||||
|
@ -885,7 +909,7 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
|||
updateShapePositions();
|
||||
float myBoundingRadius = getBoundingRadius();
|
||||
|
||||
const float BODY_COLLISION_RESOLVE_FACTOR = deltaTime / BODY_COLLISION_RESOLVE_TIMESCALE;
|
||||
const float BODY_COLLISION_RESOLUTION_FACTOR = deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE;
|
||||
|
||||
foreach (const AvatarSharedPointer& avatarPointer, avatars) {
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
|
||||
|
@ -905,26 +929,19 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
|||
_skeletonModel.getBodyShapes(myShapes);
|
||||
QVector<const Shape*> theirShapes;
|
||||
avatar->getSkeletonModel().getBodyShapes(theirShapes);
|
||||
bodyCollisions.clear();
|
||||
// TODO: add method to ShapeCollider for colliding lists of shapes
|
||||
foreach (const Shape* myShape, myShapes) {
|
||||
foreach (const Shape* theirShape, theirShapes) {
|
||||
ShapeCollider::shapeShape(myShape, theirShape, bodyCollisions);
|
||||
|
||||
CollisionInfo collision;
|
||||
if (ShapeCollider::collideShapesCoarse(myShapes, theirShapes, collision)) {
|
||||
if (glm::length2(collision._penetration) > EPSILON) {
|
||||
setPosition(getPosition() - BODY_COLLISION_RESOLUTION_FACTOR * collision._penetration);
|
||||
_lastBodyPenetration += collision._penetration;
|
||||
emit collisionWithAvatar(getSessionUUID(), avatar->getSessionUUID(), collision);
|
||||
}
|
||||
}
|
||||
glm::vec3 totalPenetration(0.f);
|
||||
for (int j = 0; j < bodyCollisions.size(); ++j) {
|
||||
CollisionInfo* collision = bodyCollisions.getCollision(j);
|
||||
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
|
||||
}
|
||||
if (glm::length2(totalPenetration) > EPSILON) {
|
||||
setPosition(getPosition() - BODY_COLLISION_RESOLVE_FACTOR * totalPenetration);
|
||||
}
|
||||
_lastBodyPenetration += totalPenetration;
|
||||
|
||||
// collide our hands against them
|
||||
// TODO: make this work when we can figure out when the other avatar won't yeild
|
||||
// (for example, we're colling against their chest or leg)
|
||||
// (for example, we're colliding against their chest or leg)
|
||||
//getHand()->collideAgainstAvatar(avatar, true);
|
||||
|
||||
// collide their hands against us
|
||||
|
@ -1076,15 +1093,15 @@ void MyAvatar::goHome() {
|
|||
}
|
||||
|
||||
void MyAvatar::increaseSize() {
|
||||
if ((1.f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
|
||||
_targetScale *= (1.f + SCALING_RATIO);
|
||||
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
|
||||
_targetScale *= (1.0f + SCALING_RATIO);
|
||||
qDebug("Changed scale to %f", _targetScale);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::decreaseSize() {
|
||||
if (MIN_AVATAR_SCALE < (1.f - SCALING_RATIO) * _targetScale) {
|
||||
_targetScale *= (1.f - SCALING_RATIO);
|
||||
if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) {
|
||||
_targetScale *= (1.0f - SCALING_RATIO);
|
||||
qDebug("Changed scale to %f", _targetScale);
|
||||
}
|
||||
}
|
||||
|
@ -1160,8 +1177,8 @@ void MyAvatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& pe
|
|||
if (leverLength > EPSILON) {
|
||||
// compute lean perturbation angles
|
||||
glm::quat bodyRotation = getOrientation();
|
||||
glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f);
|
||||
glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f);
|
||||
glm::vec3 xAxis = bodyRotation * glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 zAxis = bodyRotation * glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
|
||||
leverAxis = leverAxis / leverLength;
|
||||
glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis;
|
||||
|
|
|
@ -57,7 +57,6 @@ public:
|
|||
float getLeanScale() const { return _leanScale; }
|
||||
float getElapsedTimeStopped() const { return _elapsedTimeStopped; }
|
||||
float getElapsedTimeMoving() const { return _elapsedTimeMoving; }
|
||||
float getAbsoluteHeadYaw() const; // degrees
|
||||
const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; }
|
||||
const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; }
|
||||
glm::vec3 getGravity() const { return _gravity; }
|
||||
|
@ -128,8 +127,8 @@ private:
|
|||
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
bool _shouldRender;
|
||||
|
||||
bool _billboardValid;
|
||||
float _oculusYawOffset;
|
||||
|
||||
// private methods
|
||||
void updateThrust(float deltaTime);
|
||||
|
|
17
interface/src/devices/FaceTracker.cpp
Normal file
17
interface/src/devices/FaceTracker.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// FaceTracker.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/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
|
||||
//
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
FaceTracker::FaceTracker() :
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f) {
|
||||
}
|
46
interface/src/devices/FaceTracker.h
Normal file
46
interface/src/devices/FaceTracker.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// FaceTracker.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/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
|
||||
//
|
||||
|
||||
#ifndef hifi_FaceTracker_h
|
||||
#define hifi_FaceTracker_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
/// Base class for face trackers (Faceshift, Visage, Faceplus).
|
||||
class FaceTracker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
FaceTracker();
|
||||
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
|
||||
protected:
|
||||
|
||||
glm::vec3 _headTranslation;
|
||||
glm::quat _headRotation;
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
};
|
||||
|
||||
#endif // hifi_FaceTracker_h
|
230
interface/src/devices/Faceplus.cpp
Normal file
230
interface/src/devices/Faceplus.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
//
|
||||
// Faceplus.cpp
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/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
|
||||
//
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
#include <faceplus.h>
|
||||
#endif
|
||||
|
||||
#include "Application.h"
|
||||
#include "Faceplus.h"
|
||||
#include "renderer/FBXReader.h"
|
||||
|
||||
static int floatVectorMetaTypeId = qRegisterMetaType<QVector<float> >();
|
||||
|
||||
Faceplus::Faceplus() :
|
||||
_enabled(false),
|
||||
_active(false) {
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
// these are ignored--any values will do
|
||||
faceplus_log_in("username", "password");
|
||||
#endif
|
||||
}
|
||||
|
||||
Faceplus::~Faceplus() {
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void Faceplus::init() {
|
||||
connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
void Faceplus::setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients) {
|
||||
_headRotation = headRotation;
|
||||
_estimatedEyePitch = estimatedEyePitch;
|
||||
_estimatedEyeYaw = estimatedEyeYaw;
|
||||
_blendshapeCoefficients = blendshapeCoefficients;
|
||||
_active = true;
|
||||
}
|
||||
|
||||
void Faceplus::updateEnabled() {
|
||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) &&
|
||||
!(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) &&
|
||||
Application::getInstance()->getFaceshift()->isConnectedOrConnecting()));
|
||||
}
|
||||
|
||||
void Faceplus::setEnabled(bool enabled) {
|
||||
if (_enabled == enabled) {
|
||||
return;
|
||||
}
|
||||
if ((_enabled = enabled)) {
|
||||
_reader = new FaceplusReader();
|
||||
QThread* readerThread = new QThread(this);
|
||||
_reader->moveToThread(readerThread);
|
||||
readerThread->start();
|
||||
QMetaObject::invokeMethod(_reader, "init");
|
||||
|
||||
} else {
|
||||
QThread* readerThread = _reader->thread();
|
||||
QMetaObject::invokeMethod(_reader, "shutdown");
|
||||
readerThread->wait();
|
||||
delete readerThread;
|
||||
_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
static QMultiHash<QByteArray, QPair<int, float> > createChannelNameMap() {
|
||||
QMultiHash<QByteArray, QPair<QByteArray, float> > blendshapeMap;
|
||||
blendshapeMap.insert("EyeBlink_L", QPair<QByteArray, float>("Mix::Blink_Left", 1.0f));
|
||||
blendshapeMap.insert("EyeBlink_R", QPair<QByteArray, float>("Mix::Blink_Right", 1.0f));
|
||||
blendshapeMap.insert("BrowsD_L", QPair<QByteArray, float>("Mix::BrowsDown_Left", 1.0f));
|
||||
blendshapeMap.insert("BrowsD_R", QPair<QByteArray, float>("Mix::BrowsDown_Right", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::BrowsIn_Left", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::BrowsIn_Right", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::BrowsOuterLower_Left", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::BrowsOuterLower_Right", 1.0f));
|
||||
blendshapeMap.insert("BrowsU_L", QPair<QByteArray, float>("Mix::BrowsUp_Left", 10.0f));
|
||||
blendshapeMap.insert("BrowsU_R", QPair<QByteArray, float>("Mix::BrowsUp_Right", 10.0f));
|
||||
blendshapeMap.insert("EyeOpen_L", QPair<QByteArray, float>("Mix::EyesWide_Left", 1.0f));
|
||||
blendshapeMap.insert("EyeOpen_R", QPair<QByteArray, float>("Mix::EyesWide_Right", 1.0f));
|
||||
blendshapeMap.insert("MouthFrown_L", QPair<QByteArray, float>("Mix::Frown_Left", 1.0f));
|
||||
blendshapeMap.insert("MouthFrown_R", QPair<QByteArray, float>("Mix::Frown_Right", 1.0f));
|
||||
blendshapeMap.insert("JawLeft", QPair<QByteArray, float>("Mix::Jaw_RotateY_Left", 1.0f));
|
||||
blendshapeMap.insert("JawRight", QPair<QByteArray, float>("Mix::Jaw_RotateY_Right", 1.0f));
|
||||
blendshapeMap.insert("LipsLowerDown", QPair<QByteArray, float>("Mix::LowerLipDown_Left", 0.5f));
|
||||
blendshapeMap.insert("LipsLowerDown", QPair<QByteArray, float>("Mix::LowerLipDown_Right", 0.5f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::LowerLipIn", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::LowerLipOut", 1.0f));
|
||||
blendshapeMap.insert("MouthLeft", QPair<QByteArray, float>("Mix::Midmouth_Left", 1.0f));
|
||||
blendshapeMap.insert("MouthRight", QPair<QByteArray, float>("Mix::Midmouth_Right", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::MouthDown", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::MouthNarrow_Left", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::MouthNarrow_Right", 1.0f));
|
||||
blendshapeMap.insert("JawOpen", QPair<QByteArray, float>("Mix::MouthOpen", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::MouthUp", 1.0f));
|
||||
blendshapeMap.insert("LipsPucker", QPair<QByteArray, float>("Mix::MouthWhistle_NarrowAdjust_Left", 0.5f));
|
||||
blendshapeMap.insert("LipsPucker", QPair<QByteArray, float>("Mix::MouthWhistle_NarrowAdjust_Right", 0.5f));
|
||||
blendshapeMap.insert("Sneer", QPair<QByteArray, float>("Mix::NoseScrunch_Left", 0.5f));
|
||||
blendshapeMap.insert("Sneer", QPair<QByteArray, float>("Mix::NoseScrunch_Right", 0.5f));
|
||||
blendshapeMap.insert("MouthSmile_L", QPair<QByteArray, float>("Mix::Smile_Left", 1.0f));
|
||||
blendshapeMap.insert("MouthSmile_R", QPair<QByteArray, float>("Mix::Smile_Right", 1.0f));
|
||||
blendshapeMap.insert("EyeSquint_L", QPair<QByteArray, float>("Mix::Squint_Left", 1.0f));
|
||||
blendshapeMap.insert("EyeSquint_R", QPair<QByteArray, float>("Mix::Squint_Right", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::UpperLipIn", 1.0f));
|
||||
blendshapeMap.insert("...", QPair<QByteArray, float>("Mix::UpperLipOut", 1.0f));
|
||||
blendshapeMap.insert("LipsUpperUp", QPair<QByteArray, float>("Mix::UpperLipUp_Left", 0.5f));
|
||||
blendshapeMap.insert("LipsUpperUp", QPair<QByteArray, float>("Mix::UpperLipUp_Right", 0.5f));
|
||||
|
||||
QMultiHash<QByteArray, QPair<int, float> > channelNameMap;
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray blendshape = FACESHIFT_BLENDSHAPES[i];
|
||||
if (blendshape.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
for (QMultiHash<QByteArray, QPair<QByteArray, float> >::const_iterator it = blendshapeMap.constFind(blendshape);
|
||||
it != blendshapeMap.constEnd() && it.key() == blendshape; it++) {
|
||||
channelNameMap.insert(it.value().first, QPair<int, float>(i, it.value().second));
|
||||
}
|
||||
}
|
||||
|
||||
return channelNameMap;
|
||||
}
|
||||
|
||||
static const QMultiHash<QByteArray, QPair<int, float> >& getChannelNameMap() {
|
||||
static QMultiHash<QByteArray, QPair<int, float> > channelNameMap = createChannelNameMap();
|
||||
return channelNameMap;
|
||||
}
|
||||
#endif
|
||||
|
||||
FaceplusReader::~FaceplusReader() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (faceplus_teardown()) {
|
||||
qDebug() << "Faceplus torn down.";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FaceplusReader::init() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!faceplus_init("VGA")) {
|
||||
qDebug() << "Failed to initialized Faceplus.";
|
||||
return;
|
||||
}
|
||||
qDebug() << "Faceplus initialized.";
|
||||
|
||||
int channelCount = faceplus_output_channels_count();
|
||||
_outputVector.resize(channelCount);
|
||||
|
||||
int maxIndex = -1;
|
||||
_channelIndexMap.clear();
|
||||
for (int i = 0; i < channelCount; i++) {
|
||||
QByteArray name = faceplus_output_channel_name(i);
|
||||
if (name == "Head_Joint::Rotation_X") {
|
||||
_headRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Y") {
|
||||
_headRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Head_Joint::Rotation_Z") {
|
||||
_headRotationIndices[2] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_X") {
|
||||
_leftEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Left_Eye_Joint::Rotation_Y") {
|
||||
_leftEyeRotationIndices[1] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_X") {
|
||||
_rightEyeRotationIndices[0] = i;
|
||||
|
||||
} else if (name == "Right_Eye_Joint::Rotation_Y") {
|
||||
_rightEyeRotationIndices[1] = i;
|
||||
}
|
||||
for (QMultiHash<QByteArray, QPair<int, float> >::const_iterator it = getChannelNameMap().constFind(name);
|
||||
it != getChannelNameMap().constEnd() && it.key() == name; it++) {
|
||||
_channelIndexMap.insert(i, it.value());
|
||||
maxIndex = qMax(maxIndex, it.value().first);
|
||||
}
|
||||
}
|
||||
_blendshapeCoefficients.resize(maxIndex + 1);
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FaceplusReader::shutdown() {
|
||||
deleteLater();
|
||||
thread()->quit();
|
||||
}
|
||||
|
||||
void FaceplusReader::update() {
|
||||
#ifdef HAVE_FACEPLUS
|
||||
if (!(faceplus_synchronous_track() && faceplus_current_output_vector(_outputVector.data()))) {
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
glm::quat headRotation(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]),
|
||||
_outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2]))));
|
||||
float estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) +
|
||||
_outputVector.at(_rightEyeRotationIndices[0])) * -0.5f;
|
||||
float estimatedEyeYaw = (_outputVector.at(_leftEyeRotationIndices[1]) +
|
||||
_outputVector.at(_rightEyeRotationIndices[1])) * 0.5f;
|
||||
|
||||
qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f);
|
||||
for (int i = 0; i < _outputVector.size(); i++) {
|
||||
for (QMultiHash<int, QPair<int, float> >::const_iterator it = _channelIndexMap.constFind(i);
|
||||
it != _channelIndexMap.constEnd() && it.key() == i; it++) {
|
||||
_blendshapeCoefficients[it.value().first] += _outputVector.at(i) * it.value().second;
|
||||
}
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getFaceplus(), "setState", Q_ARG(const glm::quat&, headRotation),
|
||||
Q_ARG(float, estimatedEyePitch), Q_ARG(float, estimatedEyeYaw), Q_ARG(const QVector<float>&, _blendshapeCoefficients));
|
||||
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
#endif
|
||||
}
|
||||
|
79
interface/src/devices/Faceplus.h
Normal file
79
interface/src/devices/Faceplus.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Faceplus.h
|
||||
// interface/src/devices
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/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
|
||||
//
|
||||
|
||||
#ifndef hifi_Faceplus_h
|
||||
#define hifi_Faceplus_h
|
||||
|
||||
#include <QMultiHash>
|
||||
#include <QPair>
|
||||
#include <QVector>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
class FaceplusReader;
|
||||
|
||||
/// Interface for Mixamo FacePlus.
|
||||
class Faceplus : public FaceTracker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Faceplus();
|
||||
virtual ~Faceplus();
|
||||
|
||||
void init();
|
||||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
Q_INVOKABLE void setState(const glm::quat& headRotation, float estimatedEyePitch, float estimatedEyeYaw,
|
||||
const QVector<float>& blendshapeCoefficients);
|
||||
|
||||
public slots:
|
||||
|
||||
void updateEnabled();
|
||||
|
||||
private:
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
bool _enabled;
|
||||
bool _active;
|
||||
|
||||
FaceplusReader* _reader;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QVector<float>)
|
||||
|
||||
/// The reader object that lives in its own thread.
|
||||
class FaceplusReader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
virtual ~FaceplusReader();
|
||||
|
||||
Q_INVOKABLE void init();
|
||||
Q_INVOKABLE void shutdown();
|
||||
Q_INVOKABLE void update();
|
||||
|
||||
private:
|
||||
|
||||
#ifdef HAVE_FACEPLUS
|
||||
QMultiHash<int, QPair<int, float> > _channelIndexMap;
|
||||
QVector<float> _outputVector;
|
||||
int _headRotationIndices[3];
|
||||
int _leftEyeRotationIndices[2];
|
||||
int _rightEyeRotationIndices[2];
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // hifi_Faceplus_h
|
|
@ -45,9 +45,7 @@ Faceshift::Faceshift() :
|
|||
_jawOpenIndex(21),
|
||||
_longTermAverageEyePitch(0.0f),
|
||||
_longTermAverageEyeYaw(0.0f),
|
||||
_longTermAverageInitialized(false),
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f)
|
||||
_longTermAverageInitialized(false)
|
||||
{
|
||||
connect(&_tcpSocket, SIGNAL(connected()), SLOT(noteConnected()));
|
||||
connect(&_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(noteError(QAbstractSocket::SocketError)));
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
#include <QTcpSocket>
|
||||
#include <QUdpSocket>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <fsbinarystream.h>
|
||||
|
||||
#include "FaceTracker.h"
|
||||
|
||||
/// Handles interaction with the Faceshift software, which provides head position/orientation and facial features.
|
||||
class Faceshift : public QObject {
|
||||
class Faceshift : public FaceTracker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -34,9 +33,7 @@ public:
|
|||
|
||||
bool isActive() const;
|
||||
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
const glm::vec3& getHeadAngularVelocity() const { return _headAngularVelocity; }
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
|
||||
// these pitch/yaw angles are in degrees
|
||||
float getEyeGazeLeftPitch() const { return _eyeGazeLeftPitch; }
|
||||
|
@ -45,11 +42,6 @@ public:
|
|||
float getEyeGazeRightPitch() const { return _eyeGazeRightPitch; }
|
||||
float getEyeGazeRightYaw() const { return _eyeGazeRightYaw; }
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
|
||||
float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); }
|
||||
float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); }
|
||||
float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); }
|
||||
|
@ -102,9 +94,7 @@ private:
|
|||
bool _tracking;
|
||||
quint64 _lastTrackingStateReceived;
|
||||
|
||||
glm::quat _headRotation;
|
||||
glm::vec3 _headAngularVelocity;
|
||||
glm::vec3 _headTranslation;
|
||||
|
||||
// degrees
|
||||
float _eyeGazeLeftPitch;
|
||||
|
@ -112,8 +102,6 @@ private:
|
|||
float _eyeGazeRightPitch;
|
||||
float _eyeGazeRightYaw;
|
||||
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
int _leftBlinkIndex;
|
||||
int _rightBlinkIndex;
|
||||
int _leftEyeOpenIndex;
|
||||
|
@ -135,10 +123,6 @@ private:
|
|||
float _longTermAverageEyePitch;
|
||||
float _longTermAverageEyeYaw;
|
||||
bool _longTermAverageInitialized;
|
||||
|
||||
// degrees
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
};
|
||||
|
||||
#endif // hifi_Faceshift_h
|
||||
|
|
|
@ -30,7 +30,6 @@ int OculusManager::_scaleLocation;
|
|||
int OculusManager::_scaleInLocation;
|
||||
int OculusManager::_hmdWarpParamLocation;
|
||||
bool OculusManager::_isConnected = false;
|
||||
float OculusManager::_yawOffset = 0.0f; // radians
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
using namespace OVR;
|
||||
|
@ -190,18 +189,9 @@ void OculusManager::reset() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::updateYawOffset() {
|
||||
#ifdef HAVE_LIBOVR
|
||||
float yaw, pitch, roll;
|
||||
_sensorFusion->GetOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||
_yawOffset = yaw;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
|
||||
#ifdef HAVE_LIBOVR
|
||||
_sensorFusion->GetOrientation().GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
|
||||
yaw = yaw - _yawOffset;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ private:
|
|||
static int _scaleInLocation;
|
||||
static int _hmdWarpParamLocation;
|
||||
static bool _isConnected;
|
||||
static float _yawOffset;
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
static OVR::Ptr<OVR::DeviceManager> _deviceManager;
|
||||
|
|
|
@ -37,9 +37,7 @@ const glm::vec3 DEFAULT_HEAD_ORIGIN(0.0f, 0.0f, 0.7f);
|
|||
Visage::Visage() :
|
||||
_enabled(false),
|
||||
_active(false),
|
||||
_headOrigin(DEFAULT_HEAD_ORIGIN),
|
||||
_estimatedEyePitch(0.0f),
|
||||
_estimatedEyeYaw(0.0f) {
|
||||
_headOrigin(DEFAULT_HEAD_ORIGIN) {
|
||||
|
||||
#ifdef HAVE_VISAGE
|
||||
QByteArray licensePath = Application::resourcesPath().toLatin1() + "visage/license.vlc";
|
||||
|
@ -164,6 +162,7 @@ void Visage::reset() {
|
|||
|
||||
void Visage::updateEnabled() {
|
||||
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
|
||||
!Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) &&
|
||||
!(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) &&
|
||||
Application::getInstance()->getFaceshift()->isConnectedOrConnecting()));
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
#include <QPair>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include "FaceTracker.h"
|
||||
|
||||
namespace VisageSDK {
|
||||
class VisageTracker2;
|
||||
|
@ -25,7 +24,7 @@ namespace VisageSDK {
|
|||
}
|
||||
|
||||
/// Handles input from the Visage webcam feature tracking software.
|
||||
class Visage : public QObject {
|
||||
class Visage : public FaceTracker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -37,14 +36,6 @@ public:
|
|||
|
||||
bool isActive() const { return _active; }
|
||||
|
||||
const glm::quat& getHeadRotation() const { return _headRotation; }
|
||||
const glm::vec3& getHeadTranslation() const { return _headTranslation; }
|
||||
|
||||
float getEstimatedEyePitch() const { return _estimatedEyePitch; }
|
||||
float getEstimatedEyeYaw() const { return _estimatedEyeYaw; }
|
||||
|
||||
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
|
||||
|
||||
void update();
|
||||
void reset();
|
||||
|
||||
|
@ -64,15 +55,8 @@ private:
|
|||
|
||||
bool _enabled;
|
||||
bool _active;
|
||||
glm::quat _headRotation;
|
||||
glm::vec3 _headTranslation;
|
||||
|
||||
|
||||
glm::vec3 _headOrigin;
|
||||
|
||||
float _estimatedEyePitch;
|
||||
float _estimatedEyeYaw;
|
||||
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
};
|
||||
|
||||
#endif // hifi_Visage_h
|
||||
|
|
|
@ -595,7 +595,7 @@ bool Model::findCollisions(const QVector<const Shape*> shapes, CollisionList& co
|
|||
const Shape* theirShape = shapes[i];
|
||||
for (int j = 0; j < _jointShapes.size(); ++j) {
|
||||
const Shape* ourShape = _jointShapes[j];
|
||||
if (ShapeCollider::shapeShape(theirShape, ourShape, collisions)) {
|
||||
if (ShapeCollider::collideShapes(theirShape, ourShape, collisions)) {
|
||||
collided = true;
|
||||
}
|
||||
}
|
||||
|
@ -622,7 +622,7 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi
|
|||
} while (ancestorIndex != -1);
|
||||
}
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&sphere, _jointShapes[i], collisions)) {
|
||||
if (ShapeCollider::collideShapes(&sphere, _jointShapes[i], collisions)) {
|
||||
CollisionInfo* collision = collisions.getLastCollision();
|
||||
collision->_type = MODEL_COLLISION;
|
||||
collision->_data = (void*)(this);
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
//
|
||||
// Oscilloscope.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Philip on 1/28/13.
|
||||
// Copyright 2013 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 <limits>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include "Oscilloscope.h"
|
||||
|
||||
// Reimplemented 4/26/13 (tosh) - don't blame Philip for bugs
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace { // everything in here only exists while compiling this .cpp file
|
||||
|
||||
// one sample buffer per channel
|
||||
unsigned const MAX_SAMPLES = Oscilloscope::MAX_SAMPLES_PER_CHANNEL * Oscilloscope::MAX_CHANNELS;
|
||||
|
||||
// adding an x-coordinate yields twice the amount of vertices
|
||||
unsigned const MAX_COORDS_PER_CHANNEL = Oscilloscope::MAX_SAMPLES_PER_CHANNEL * 2;
|
||||
// allocated once for each channel
|
||||
unsigned const MAX_COORDS = MAX_COORDS_PER_CHANNEL * Oscilloscope::MAX_CHANNELS;
|
||||
|
||||
// total amount of memory to allocate (in 16-bit integers)
|
||||
unsigned const N_INT16_TO_ALLOC = MAX_SAMPLES + MAX_COORDS;
|
||||
}
|
||||
|
||||
|
||||
Oscilloscope::Oscilloscope(int w, int h, bool isEnabled) :
|
||||
enabled(isEnabled),
|
||||
inputPaused(false),
|
||||
_width(w),
|
||||
_height(h),
|
||||
_samples(0l),
|
||||
_vertices(0l),
|
||||
// some filtering (see details in Log.h)
|
||||
_lowPassCoeff(0.4f),
|
||||
// three in -> one out
|
||||
_downsampleRatio(3) {
|
||||
|
||||
// allocate enough space for the sample data and to turn it into
|
||||
// vertices and since they're all 'short', do so in one shot
|
||||
_samples = new short[N_INT16_TO_ALLOC];
|
||||
memset(_samples, 0, N_INT16_TO_ALLOC * sizeof(short));
|
||||
_vertices = _samples + MAX_SAMPLES;
|
||||
|
||||
// initialize write positions to start of each channel's region
|
||||
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||
_writePos[ch] = MAX_SAMPLES_PER_CHANNEL * ch;
|
||||
}
|
||||
|
||||
_colors[0] = 0xffffff;
|
||||
_colors[1] = 0x00ffff;
|
||||
_colors[2] = 0x00ffff;
|
||||
}
|
||||
|
||||
Oscilloscope::~Oscilloscope() {
|
||||
|
||||
delete[] _samples;
|
||||
}
|
||||
|
||||
void Oscilloscope::addSamples(const QByteArray& audioByteArray, bool isStereo, bool isInput) {
|
||||
|
||||
if (! enabled || inputPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned numSamplesPerChannel = audioByteArray.size() / (sizeof(int16_t) * (isStereo ? 2 : 1));
|
||||
int16_t* samples = (int16_t*) audioByteArray.data();
|
||||
|
||||
for (int channel = 0; channel < (isStereo ? 2 : 1); channel++) {
|
||||
// add samples for each of the channels
|
||||
|
||||
// determine start/end offset of this channel's region
|
||||
unsigned baseOffs = MAX_SAMPLES_PER_CHANNEL * (channel + !isInput);
|
||||
unsigned endOffs = baseOffs + MAX_SAMPLES_PER_CHANNEL;
|
||||
|
||||
// fetch write position for this channel
|
||||
unsigned writePos = _writePos[channel + !isInput];
|
||||
|
||||
// determine write position after adding the samples
|
||||
unsigned newWritePos = writePos + numSamplesPerChannel;
|
||||
unsigned n2 = 0;
|
||||
if (newWritePos >= endOffs) {
|
||||
// passed boundary of the circular buffer? -> we need to copy two blocks
|
||||
n2 = newWritePos - endOffs;
|
||||
newWritePos = baseOffs + n2;
|
||||
numSamplesPerChannel -= n2;
|
||||
}
|
||||
|
||||
if (!isStereo) {
|
||||
// copy data
|
||||
memcpy(_samples + writePos, samples, numSamplesPerChannel * sizeof(int16_t));
|
||||
if (n2 > 0) {
|
||||
memcpy(_samples + baseOffs, samples + numSamplesPerChannel, n2 * sizeof(int16_t));
|
||||
}
|
||||
} else {
|
||||
// we have interleaved samples we need to separate into two channels
|
||||
for (unsigned i = 0; i < numSamplesPerChannel + n2; i++) {
|
||||
if (i < numSamplesPerChannel - n2) {
|
||||
_samples[writePos] = samples[(i * 2) + channel];
|
||||
} else {
|
||||
_samples[baseOffs] = samples[(i * 2) + channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set new write position for this channel
|
||||
_writePos[channel + !isInput] = newWritePos;
|
||||
}
|
||||
}
|
||||
|
||||
void Oscilloscope::render(int x, int y) {
|
||||
|
||||
if (! enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fetch low pass factor (and convert to fix point) / downsample factor
|
||||
int lowPassFixPt = -(int)(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
||||
unsigned downsample = _downsampleRatio;
|
||||
// keep half of the buffer for writing and ensure an even vertex count
|
||||
unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u;
|
||||
unsigned usedSamples = usedWidth * downsample;
|
||||
|
||||
// expand samples to vertex data
|
||||
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||
// for each channel: determine memory regions
|
||||
short const* basePtr = _samples + MAX_SAMPLES_PER_CHANNEL * ch;
|
||||
short const* endPtr = basePtr + MAX_SAMPLES_PER_CHANNEL;
|
||||
short const* inPtr = _samples + _writePos[ch];
|
||||
short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
|
||||
int sample = 0, x = usedWidth;
|
||||
for (int i = (int)usedSamples; --i >= 0 ;) {
|
||||
if (inPtr == basePtr) {
|
||||
// handle boundary, reading the circular sample buffer
|
||||
inPtr = endPtr;
|
||||
}
|
||||
// read and (eventually) filter sample
|
||||
sample += ((*--inPtr - sample) * lowPassFixPt) >> 15;
|
||||
// write every nth as y with a corresponding x-coordinate
|
||||
if (i % downsample == 0) {
|
||||
*outPtr++ = short(--x);
|
||||
*outPtr++ = short(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set up rendering state (vertex data lives at _vertices)
|
||||
glLineWidth(1.0);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glPushMatrix();
|
||||
glTranslatef((float)x + 0.0f, (float)y + _height / 2.0f, 0.0f);
|
||||
glScaled(1.0f, _height / 32767.0f, 1.0f);
|
||||
glVertexPointer(2, GL_SHORT, 0, _vertices);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_INDEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
// render channel 0
|
||||
glColor3ub(GLubyte(_colors[0] >> 16), GLubyte((_colors[0] >> 8) & 0xff), GLubyte(_colors[0] & 0xff));
|
||||
glDrawArrays(GL_LINES, MAX_SAMPLES_PER_CHANNEL * 0, usedWidth);
|
||||
|
||||
// render channel 1
|
||||
glColor3f(0.0f, 1.0f ,1.0f);
|
||||
glColor3ub(GLubyte(_colors[1] >> 16), GLubyte((_colors[1] >> 8) & 0xff), GLubyte(_colors[1] & 0xff));
|
||||
glDrawArrays(GL_LINES, MAX_SAMPLES_PER_CHANNEL * 1, usedWidth);
|
||||
|
||||
// render channel 2
|
||||
glColor3ub(GLubyte(_colors[2] >> 16), GLubyte((_colors[2] >> 8) & 0xff), GLubyte(_colors[2] & 0xff));
|
||||
glDrawArrays(GL_LINES, MAX_SAMPLES_PER_CHANNEL * 2, usedWidth);
|
||||
|
||||
// reset rendering state
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
// Oscilloscope.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Philip on 1/28/13.
|
||||
// Copyright 2013 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_Oscilloscope_h
|
||||
#define hifi_Oscilloscope_h
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class Oscilloscope : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Oscilloscope(int width, int height, bool isEnabled);
|
||||
~Oscilloscope();
|
||||
|
||||
void render(int x, int y);
|
||||
|
||||
// Switches: On/Off, Stop Time
|
||||
volatile bool enabled;
|
||||
volatile bool inputPaused;
|
||||
|
||||
// Limits
|
||||
static unsigned const MAX_CHANNELS = 3;
|
||||
static unsigned const MAX_SAMPLES_PER_CHANNEL = 4096;
|
||||
|
||||
// Sets the color for a specific channel.
|
||||
void setColor(unsigned ch, unsigned rgb) { assert(ch < MAX_CHANNELS); if (! inputPaused) { _colors[ch] = rgb; } }
|
||||
|
||||
// Controls a simple one pole IIR low pass filter that is provided to
|
||||
// reduce high frequencies aliasing (to lower ones) when downsampling.
|
||||
//
|
||||
// The parameter sets the influence of the input in respect to the
|
||||
// feed-back signal on the output.
|
||||
//
|
||||
// +---------+
|
||||
// in O--------------|+ ideal |--o--------------O out
|
||||
// .---|- op amp | |
|
||||
// | +---------+ |
|
||||
// | |
|
||||
// o-------||-------o
|
||||
// | |
|
||||
// | __V__
|
||||
// -------------|_____|-------+
|
||||
// : : |
|
||||
// 0.0 - 1.0 (GND)
|
||||
//
|
||||
// The values in range 0.0 - 1.0 correspond to "all closed" (input has
|
||||
// no influence on the output) to "all open" (feedback has no influence
|
||||
// on the output) configurations.
|
||||
void setLowpassOpenness(float w) { assert(w >= 0.0f && w <= 1.0f); _lowPassCoeff = w; }
|
||||
|
||||
// Sets the number of input samples per output sample. Without filtering
|
||||
// just uses every nTh sample.
|
||||
void setDownsampleRatio(unsigned n) { assert(n > 0); _downsampleRatio = n; }
|
||||
public slots:
|
||||
void addSamples(const QByteArray& audioByteArray, bool isStereo, bool isInput);
|
||||
private:
|
||||
// don't copy/assign
|
||||
Oscilloscope(Oscilloscope const&); // = delete;
|
||||
Oscilloscope& operator=(Oscilloscope const&); // = delete;
|
||||
|
||||
// state variables
|
||||
|
||||
unsigned _width;
|
||||
unsigned _height;
|
||||
short* _samples;
|
||||
short* _vertices;
|
||||
unsigned _writePos[MAX_CHANNELS];
|
||||
|
||||
float _lowPassCoeff;
|
||||
unsigned _downsampleRatio;
|
||||
unsigned _colors[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif // hifi_Oscilloscope_h
|
|
@ -116,7 +116,6 @@ private:
|
|||
|
||||
static VoxelsScriptingInterface _voxelsScriptingInterface;
|
||||
static ParticlesScriptingInterface _particlesScriptingInterface;
|
||||
static int _scriptNumber;
|
||||
|
||||
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||
AudioScriptingInterface _audioScriptingInterface;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
namespace ShapeCollider {
|
||||
|
||||
bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions) {
|
||||
bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions) {
|
||||
// ATM we only have two shape types so we just check every case.
|
||||
// TODO: make a fast lookup for correct method
|
||||
int typeA = shapeA->getType();
|
||||
|
@ -68,6 +68,30 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi
|
|||
return false;
|
||||
}
|
||||
|
||||
static CollisionList tempCollisions(32);
|
||||
|
||||
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision) {
|
||||
tempCollisions.clear();
|
||||
foreach (const Shape* shapeA, shapesA) {
|
||||
foreach (const Shape* shapeB, shapesB) {
|
||||
ShapeCollider::collideShapes(shapeA, shapeB, tempCollisions);
|
||||
}
|
||||
}
|
||||
if (tempCollisions.size() > 0) {
|
||||
glm::vec3 totalPenetration(0.0f);
|
||||
glm::vec3 averageContactPoint(0.0f);
|
||||
for (int j = 0; j < tempCollisions.size(); ++j) {
|
||||
CollisionInfo* c = tempCollisions.getCollision(j);
|
||||
totalPenetration = addPenetrations(totalPenetration, c->_penetration);
|
||||
averageContactPoint += c->_contactPoint;
|
||||
}
|
||||
collision._penetration = totalPenetration;
|
||||
collision._contactPoint = averageContactPoint / (float)(tempCollisions.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, CollisionList& collisions) {
|
||||
glm::vec3 BA = sphereB->getPosition() - sphereA->getPosition();
|
||||
float distanceSquared = glm::dot(BA, BA);
|
||||
|
@ -77,7 +101,7 @@ bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, Collis
|
|||
float distance = sqrtf(distanceSquared);
|
||||
if (distance < EPSILON) {
|
||||
// the spheres are on top of each other, so we pick an arbitrary penetration direction
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
distance = totalRadius;
|
||||
} else {
|
||||
BA /= distance;
|
||||
|
@ -112,7 +136,7 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
}
|
||||
if (absAxialDistance > capsuleB->getHalfHeight()) {
|
||||
// sphere hits capsule on a cap --> recompute radialAxis to point from spherA to cap center
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
radialAxis = BA + (sign * capsuleB->getHalfHeight()) * capsuleAxis;
|
||||
radialDistance2 = glm::length2(radialAxis);
|
||||
if (radialDistance2 > totalRadius2) {
|
||||
|
@ -144,12 +168,12 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
return false;
|
||||
}
|
||||
// ... but still defined for the cap case
|
||||
if (axialDistance < 0.f) {
|
||||
if (axialDistance < 0.0f) {
|
||||
// we're hitting the start cap, so we negate the capsuleAxis
|
||||
capsuleAxis *= -1;
|
||||
}
|
||||
// penetration points from A into B
|
||||
float sign = (axialDistance > 0.f) ? -1.f : 1.f;
|
||||
float sign = (axialDistance > 0.0f) ? -1.0f : 1.0f;
|
||||
collision->_penetration = (sign * (totalRadius + capsuleB->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = sphereA->getPosition() + (sign * sphereA->getRadius()) * capsuleAxis;
|
||||
|
@ -196,7 +220,7 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
if (absAxialDistance > capsuleA->getHalfHeight()) {
|
||||
// sphere hits capsule on a cap
|
||||
// --> recompute radialAxis and closestApproach
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
closestApproach = capsuleA->getPosition() + (sign * capsuleA->getHalfHeight()) * capsuleAxis;
|
||||
radialAxis = closestApproach - sphereB->getPosition();
|
||||
radialDistance2 = glm::length2(radialAxis);
|
||||
|
@ -229,11 +253,11 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
return false;
|
||||
}
|
||||
// ... but still defined for the cap case
|
||||
if (axialDistance < 0.f) {
|
||||
if (axialDistance < 0.0f) {
|
||||
// we're hitting the start cap, so we negate the capsuleAxis
|
||||
capsuleAxis *= -1;
|
||||
}
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
collision->_penetration = (sign * (totalRadius + capsuleA->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = closestApproach + (sign * capsuleA->getRadius()) * capsuleAxis;
|
||||
|
@ -256,7 +280,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
// d = [(B - A) . (a - (a.b)b)] / (1 - (a.b)^2)
|
||||
|
||||
float aDotB = glm::dot(axisA, axisB);
|
||||
float denominator = 1.f - aDotB * aDotB;
|
||||
float denominator = 1.0f - aDotB * aDotB;
|
||||
float totalRadius = capsuleA->getRadius() + capsuleB->getRadius();
|
||||
if (denominator > EPSILON) {
|
||||
// distances to points of closest approach
|
||||
|
@ -266,12 +290,12 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
// clamp the distances to the ends of the capsule line segments
|
||||
float absDistanceA = fabs(distanceA);
|
||||
if (absDistanceA > capsuleA->getHalfHeight() + capsuleA->getRadius()) {
|
||||
float signA = distanceA < 0.f ? -1.f : 1.f;
|
||||
float signA = distanceA < 0.0f ? -1.0f : 1.0f;
|
||||
distanceA = signA * capsuleA->getHalfHeight();
|
||||
}
|
||||
float absDistanceB = fabs(distanceB);
|
||||
if (absDistanceB > capsuleB->getHalfHeight() + capsuleB->getRadius()) {
|
||||
float signB = distanceB < 0.f ? -1.f : 1.f;
|
||||
float signB = distanceB < 0.0f ? -1.0f : 1.0f;
|
||||
distanceB = signB * capsuleB->getHalfHeight();
|
||||
}
|
||||
|
||||
|
@ -298,7 +322,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
{
|
||||
// the capsule centers are on top of each other!
|
||||
// give up on a valid penetration direction and just use the yAxis
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
distance = glm::max(capsuleB->getRadius(), capsuleA->getRadius());
|
||||
}
|
||||
} else {
|
||||
|
@ -330,7 +354,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
float distance = sqrtf(distanceSquared);
|
||||
if (distance < EPSILON) {
|
||||
// the spheres are on top of each other, so we pick an arbitrary penetration direction
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
} else {
|
||||
BA /= distance;
|
||||
}
|
||||
|
@ -496,7 +520,7 @@ bool listList(const ListShape* listA, const ListShape* listB, CollisionList& col
|
|||
for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) {
|
||||
const Shape* subShape = listA->getSubShape(i);
|
||||
for (int j = 0; j < listB->size() && !collisions.isFull(); ++j) {
|
||||
touching = shapeShape(subShape, listB->getSubShape(j), collisions) || touching;
|
||||
touching = collideShapes(subShape, listB->getSubShape(j), collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
|
|
@ -23,9 +23,15 @@ namespace ShapeCollider {
|
|||
|
||||
/// \param shapeA pointer to first shape
|
||||
/// \param shapeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \param collisions[out] collision details
|
||||
/// \return true if shapes collide
|
||||
bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
|
||||
/// \param shapesA list of shapes
|
||||
/// \param shapeB list of shapes
|
||||
/// \param collisions[out] average collision details
|
||||
/// \return true if any shapes collide
|
||||
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision);
|
||||
|
||||
/// \param sphereA pointer to first shape
|
||||
/// \param sphereB pointer to second shape
|
||||
|
|
|
@ -43,7 +43,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// collide A to B...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereA, &sphereB, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -52,7 +52,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// collide B to A...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -61,7 +61,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// also test shapeShape
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -93,7 +93,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
|||
|
||||
// collide A to B...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereA, &sphereB, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions);
|
||||
if (!touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should touch" << std::endl;
|
||||
|
@ -136,7 +136,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
|||
|
||||
// collide B to A...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (!touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should touch" << std::endl;
|
||||
|
@ -199,7 +199,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
|||
sphereA.setPosition(rotation * localPosition + translation);
|
||||
|
||||
// sphereA agains capsuleB
|
||||
if (ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should NOT touch"
|
||||
|
@ -207,7 +207,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB against sphereA
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should NOT touch"
|
||||
|
@ -241,7 +241,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
{ // sphereA collides with capsuleB's cylindrical wall
|
||||
sphereA.setPosition(radialOffset * xAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -272,7 +272,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -308,7 +308,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
|
||||
sphereA.setPosition(axialOffset * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -339,7 +339,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -375,7 +375,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
|
||||
sphereA.setPosition(axialOffset * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -406,7 +406,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -462,13 +462,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
|
||||
// side by side
|
||||
capsuleB.setPosition((1.01f * totalRadius) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -477,13 +477,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
|
||||
// end to end
|
||||
capsuleB.setPosition((1.01f * totalHalfLength) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -494,13 +494,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis);
|
||||
capsuleB.setRotation(rotation);
|
||||
capsuleB.setPosition((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -532,7 +532,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
|
||||
{ // side by side
|
||||
capsuleB.setPosition((0.99f * totalRadius) * xAxis);
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -540,7 +540,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -553,7 +553,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
{ // end to end
|
||||
capsuleB.setPosition((0.99f * totalHalfLength) * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -561,7 +561,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -576,7 +576,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setRotation(rotation);
|
||||
capsuleB.setPosition((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -584,7 +584,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -602,7 +602,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setPosition(positionB);
|
||||
|
||||
// capsuleA vs capsuleB
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -631,7 +631,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB vs capsuleA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -669,7 +669,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setPosition(positionB);
|
||||
|
||||
// capsuleA vs capsuleB
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
|
Loading…
Reference in a new issue