mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 00:44:11 +02:00
Merge branch 'spectator-camera' of https://github.com/highfidelity/hifi into dk/spectatorCameraPreview
This commit is contained in:
commit
09d959bdeb
92 changed files with 970 additions and 824 deletions
assignment-client/src
domain-server/src
interface
resources
src
libraries
animation/src
AnimDefaultPose.cppAnimDefaultPose.hAnimInverseKinematics.cppAnimNode.hAnimNodeLoader.cppAnimOverlay.cppAnimOverlay.hAnimationCache.cppAnimationCache.hRig.cpp
audio-client/src
avatars/src
entities-renderer/src
EntityTreeRenderer.cppEntityTreeRenderer.hRenderableEntityItem.hRenderableModelEntityItem.cppRenderableModelEntityItem.hRenderablePolyVoxEntityItem.cppRenderablePolyVoxEntityItem.h
entities
fbx/src
gpu-gl/src/gpu/gl
gpu/src/gpu
model-networking/src/model-networking
model/src/model
networking/src
octree/src
procedural/src/procedural
render-utils/src
render/src/render
script-engine/src
FileScriptingInterface.cppModelScriptingInterface.cppModelScriptingInterface.hScriptCache.cppScriptEngine.cpp
shared/src
ui/src/ui
scripts/system
tests
tools
|
@ -62,7 +62,7 @@ Agent::Agent(ReceivedMessage& message) :
|
|||
_entityEditSender.setPacketsPerSecond(DEFAULT_ENTITY_PPS_PER_SCRIPT);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
ResourceManager::init();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||
|
||||
|
@ -199,7 +199,7 @@ void Agent::requestScript() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto request = ResourceManager::createResourceRequest(this, scriptURL);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
|
||||
|
||||
if (!request) {
|
||||
qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString();
|
||||
|
@ -779,7 +779,7 @@ void Agent::aboutToFinish() {
|
|||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
|
||||
ResourceManager::cleanup();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
|
|
@ -497,13 +497,14 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional
|
|||
// avatar: apply fixed off-axis attenuation to make them quieter as they turn away
|
||||
} else if (!isEcho && (streamToAdd.getType() == PositionalAudioStream::Microphone)) {
|
||||
glm::vec3 rotatedListenerPosition = glm::inverse(streamToAdd.getOrientation()) * relativePosition;
|
||||
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
|
||||
glm::normalize(rotatedListenerPosition));
|
||||
|
||||
// source directivity is based on angle of emission, in local coordinates
|
||||
glm::vec3 direction = glm::normalize(rotatedListenerPosition);
|
||||
float angleOfDelivery = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
|
||||
|
||||
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
|
||||
const float OFF_AXIS_ATTENUATION_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
|
||||
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
|
||||
(angleOfDelivery * (OFF_AXIS_ATTENUATION_STEP / PI_OVER_TWO));
|
||||
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (angleOfDelivery * (OFF_AXIS_ATTENUATION_STEP / PI_OVER_TWO));
|
||||
|
||||
gain *= offAxisCoefficient;
|
||||
}
|
||||
|
@ -545,7 +546,6 @@ float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const Positio
|
|||
const glm::vec3& relativePosition) {
|
||||
glm::quat inverseOrientation = glm::inverse(listeningNodeStream.getOrientation());
|
||||
|
||||
// Compute sample delay for the two ears to create phase panning
|
||||
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
|
||||
|
||||
// project the rotated source position vector onto the XZ plane
|
||||
|
@ -553,11 +553,16 @@ float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const Positio
|
|||
|
||||
const float SOURCE_DISTANCE_THRESHOLD = 1e-30f;
|
||||
|
||||
if (glm::length2(rotatedSourcePosition) > SOURCE_DISTANCE_THRESHOLD) {
|
||||
float rotatedSourcePositionLength2 = glm::length2(rotatedSourcePosition);
|
||||
if (rotatedSourcePositionLength2 > SOURCE_DISTANCE_THRESHOLD) {
|
||||
|
||||
// produce an oriented angle about the y-axis
|
||||
return glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, -1.0f, 0.0f));
|
||||
} else {
|
||||
// there is no distance between listener and source - return no azimuth
|
||||
return 0;
|
||||
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
|
||||
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
|
||||
return (direction.x < 0.0f) ? -angle : angle;
|
||||
|
||||
} else {
|
||||
// no azimuth if they are in same spot
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
|
|||
OctreeServer(message),
|
||||
_entitySimulation(NULL)
|
||||
{
|
||||
ResourceManager::init();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<ScriptCache>();
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
ResourceManager::init();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
|
||||
|
||||
|
@ -67,7 +67,6 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
|
|||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::ENTITY_SERVER_SCRIPT);
|
||||
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
|
||||
this, "handleOctreePacket");
|
||||
|
@ -493,7 +492,7 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool
|
|||
if (entity && (reload || notRunning || details.scriptText != entity->getServerScripts())) {
|
||||
QString scriptUrl = entity->getServerScripts();
|
||||
if (!scriptUrl.isEmpty()) {
|
||||
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
||||
scriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);
|
||||
qCDebug(entity_script_server) << "Loading entity server script" << scriptUrl << "for" << entityID;
|
||||
_entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, reload);
|
||||
}
|
||||
|
@ -551,7 +550,7 @@ void EntityScriptServer::aboutToFinish() {
|
|||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntityTree(nullptr);
|
||||
|
||||
ResourceManager::cleanup();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
|
|
@ -171,7 +171,7 @@ void DomainMetadata::maybeUpdateUsers() {
|
|||
if (linkedData) {
|
||||
auto nodeData = static_cast<DomainServerNodeData*>(linkedData);
|
||||
|
||||
if (!nodeData->wasAssigned()) {
|
||||
if (!nodeData->wasAssigned() && node->getType() == NodeType::Agent) {
|
||||
++numConnected;
|
||||
|
||||
if (nodeData->getUsername().isEmpty()) {
|
||||
|
|
|
@ -150,28 +150,19 @@
|
|||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "hipsManipulatorOverlay",
|
||||
"id": "defaultPoseOverlay",
|
||||
"type": "overlay",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"boneSet": "hipsOnly"
|
||||
"alphaVar": "defaultPoseOverlayAlpha",
|
||||
"boneSet": "fullBody",
|
||||
"boneSetVar": "defaultPoseOverlayBoneSet"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "hipsManipulator",
|
||||
"type": "manipulator",
|
||||
"id": "defaultPose",
|
||||
"type": "defaultPose",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"alphaVar": "hipsManipulatorAlpha",
|
||||
"joints": [
|
||||
{
|
||||
"jointName": "Hips",
|
||||
"rotationType": "absolute",
|
||||
"translationType": "absolute",
|
||||
"rotationVar": "hipsManipulatorRotation",
|
||||
"translationVar": "hipsManipulatorPosition"
|
||||
}
|
||||
]
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
|
|
|
@ -34,6 +34,8 @@ ModalWindow {
|
|||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property var filesModel: ListModel { }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
|
@ -253,7 +255,9 @@ ModalWindow {
|
|||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
||||
fileTableView.model.isFolder(row) :
|
||||
fileTableModel.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
|
@ -331,7 +335,12 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
Component {
|
||||
id: filesModelBuilder
|
||||
ListModel { }
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
|
@ -383,7 +392,11 @@ ModalWindow {
|
|||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
return filesModel.get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function get(row) {
|
||||
return filesModel.get(row)
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
@ -401,7 +414,7 @@ ModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
clear();
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -423,7 +436,7 @@ ModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -432,7 +445,7 @@ ModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
newFilesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -443,6 +456,7 @@ ModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
|
@ -469,7 +483,7 @@ ModalWindow {
|
|||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: fileTableModel
|
||||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
|
@ -561,11 +575,12 @@ ModalWindow {
|
|||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = model.isFolder(row);
|
||||
var file = model.get(row).filePath;
|
||||
var isFolder = currentModel.isFolder(row);
|
||||
var file = currentModel.get(row).filePath;
|
||||
if (isFolder) {
|
||||
fileTableView.model.folder = helper.pathToUrl(file);
|
||||
currentModel.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
|
@ -580,7 +595,8 @@ ModalWindow {
|
|||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
||||
filesModel.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
|
|
|
@ -25,11 +25,14 @@ import "fileDialog"
|
|||
//FIXME implement shortcuts for favorite location
|
||||
TabletModalWindow {
|
||||
id: root
|
||||
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
property var filesModel: ListModel { }
|
||||
|
||||
Settings {
|
||||
category: "FileDialog"
|
||||
property alias width: root.width
|
||||
|
@ -250,7 +253,9 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
||||
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
||||
fileTableView.model.isFolder(row) :
|
||||
fileTableModel.isFolder(row);
|
||||
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
||||
} else {
|
||||
|
@ -288,7 +293,7 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
fileTableModel.update(); // Update once the data from the folder change is available.
|
||||
fileTableModel.update()
|
||||
}
|
||||
|
||||
function getItem(index, field) {
|
||||
|
@ -328,7 +333,12 @@ TabletModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
Component {
|
||||
id: filesModelBuilder
|
||||
ListModel { }
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: fileTableModel
|
||||
|
||||
// FolderListModel has a couple of problems:
|
||||
|
@ -359,17 +369,16 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
onFolderChanged: {
|
||||
|
||||
if (folder === rootFolder) {
|
||||
model = driveListModel;
|
||||
helper.monitorDirectory("");
|
||||
update();
|
||||
} else {
|
||||
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
|
||||
|
||||
model = folderListModel;
|
||||
folderListModel.folder = folder;
|
||||
helper.monitorDirectory(helper.urlToPath(folder));
|
||||
|
||||
if (needsUpdate) {
|
||||
update();
|
||||
}
|
||||
|
@ -380,7 +389,11 @@ TabletModalWindow {
|
|||
if (row === -1) {
|
||||
return false;
|
||||
}
|
||||
return get(row).fileIsDir;
|
||||
return filesModel.get(row).fileIsDir;
|
||||
}
|
||||
|
||||
function get(row) {
|
||||
return filesModel.get(row)
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
@ -398,7 +411,7 @@ TabletModalWindow {
|
|||
rows = 0,
|
||||
i;
|
||||
|
||||
clear();
|
||||
var newFilesModel = filesModelBuilder.createObject(root);
|
||||
|
||||
comparisonFunction = sortOrder === Qt.AscendingOrder
|
||||
? function(a, b) { return a < b; }
|
||||
|
@ -420,7 +433,7 @@ TabletModalWindow {
|
|||
while (lower < upper) {
|
||||
middle = Math.floor((lower + upper) / 2);
|
||||
var lessThan;
|
||||
if (comparisonFunction(sortValue, get(middle)[sortField])) {
|
||||
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
||||
lessThan = true;
|
||||
upper = middle;
|
||||
} else {
|
||||
|
@ -429,7 +442,7 @@ TabletModalWindow {
|
|||
}
|
||||
}
|
||||
|
||||
insert(lower, {
|
||||
newFilesModel.insert(lower, {
|
||||
fileName: fileName,
|
||||
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
||||
fileSize: model.getItem(i, "fileSize"),
|
||||
|
@ -440,6 +453,7 @@ TabletModalWindow {
|
|||
|
||||
rows++;
|
||||
}
|
||||
filesModel = newFilesModel;
|
||||
|
||||
d.clearSelection();
|
||||
}
|
||||
|
@ -467,7 +481,7 @@ TabletModalWindow {
|
|||
sortIndicatorOrder: Qt.AscendingOrder
|
||||
sortIndicatorVisible: true
|
||||
|
||||
model: fileTableModel
|
||||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
|
@ -559,11 +573,12 @@ TabletModalWindow {
|
|||
}
|
||||
|
||||
function navigateToCurrentRow() {
|
||||
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
||||
var row = fileTableView.currentRow
|
||||
var isFolder = model.isFolder(row);
|
||||
var file = model.get(row).filePath;
|
||||
var isFolder = currentModel.isFolder(row);
|
||||
var file = currentModel.get(row).filePath;
|
||||
if (isFolder) {
|
||||
fileTableView.model.folder = helper.pathToUrl(file);
|
||||
currentModel.folder = helper.pathToUrl(file);
|
||||
} else {
|
||||
okAction.trigger();
|
||||
}
|
||||
|
@ -578,7 +593,8 @@ TabletModalWindow {
|
|||
var newPrefix = prefix + event.text.toLowerCase();
|
||||
var matchedIndex = -1;
|
||||
for (var i = 0; i < model.count; ++i) {
|
||||
var name = model.get(i).fileName.toLowerCase();
|
||||
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
||||
filesModel.get(i).fileName.toLowerCase();
|
||||
if (0 === name.indexOf(newPrefix)) {
|
||||
matchedIndex = i;
|
||||
break;
|
||||
|
|
|
@ -583,6 +583,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
DependencyManager::set<LocationBookmarks>();
|
||||
DependencyManager::set<Snapshot>();
|
||||
DependencyManager::set<CloseEventSender>();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
|
||||
return previousSessionCrashed;
|
||||
}
|
||||
|
@ -777,7 +778,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
connect(this, &Application::activeDisplayPluginChanged,
|
||||
reinterpret_cast<scripting::Audio*>(audioScriptingInterface.data()), &scripting::Audio::onContextChanged);
|
||||
|
||||
ResourceManager::init();
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -916,11 +916,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
_saveAvatarOverrideUrl = true;
|
||||
}
|
||||
|
||||
QString defaultScriptsLocation = getCmdOption(argc, constArgv, "--scripts");
|
||||
if (!defaultScriptsLocation.isEmpty()) {
|
||||
PathUtils::defaultScriptsLocation(defaultScriptsLocation);
|
||||
}
|
||||
|
||||
_glWidget = new GLCanvas();
|
||||
getApplicationCompositor().setRenderingWidget(_glWidget);
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
@ -1187,7 +1182,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// do this as late as possible so that all required subsystems are initialized
|
||||
// If we've overridden the default scripts location, just load default scripts
|
||||
// otherwise, load 'em all
|
||||
if (!defaultScriptsLocation.isEmpty()) {
|
||||
|
||||
// we just want to see if --scripts was set, we've already parsed it and done
|
||||
// the change in PathUtils. Rather than pass that in the constructor, lets just
|
||||
// look (this could be debated)
|
||||
QString scriptsSwitch = QString("--").append(SCRIPTS_SWITCH);
|
||||
QDir defaultScriptsLocation(getCmdOption(argc, constArgv, scriptsSwitch.toStdString().c_str()));
|
||||
if (!defaultScriptsLocation.exists()) {
|
||||
scriptEngines->loadDefaultScripts();
|
||||
scriptEngines->defaultScriptsLocationOverridden(true);
|
||||
} else {
|
||||
|
@ -1881,7 +1882,7 @@ Application::~Application() {
|
|||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<OctreeStatsProvider>();
|
||||
|
||||
ResourceManager::cleanup();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
|
@ -4096,7 +4097,10 @@ void Application::init() {
|
|||
EntityTreePointer tree = getEntities()->getTree();
|
||||
if (auto entity = tree->findEntityByEntityItemID(id)) {
|
||||
auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
|
||||
entity->setCollisionSound(sound);
|
||||
auto renderable = entity->getRenderableInterface();
|
||||
if (renderable) {
|
||||
renderable->setCollisionSound(sound);
|
||||
}
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {
|
||||
|
@ -5939,7 +5943,7 @@ void Application::addAssetToWorldFromURL(QString url) {
|
|||
|
||||
addAssetToWorldInfo(filename, "Downloading model file " + filename + ".");
|
||||
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, QUrl(url));
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, QUrl(url));
|
||||
connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished);
|
||||
request->send();
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@ static const UINT UWM_SHOW_APPLICATION =
|
|||
#endif
|
||||
|
||||
static const QString RUNNING_MARKER_FILENAME = "Interface.running";
|
||||
static const QString SCRIPTS_SWITCH = "scripts";
|
||||
|
||||
class Application;
|
||||
#if defined(qApp)
|
||||
|
|
|
@ -39,7 +39,7 @@ void SecondaryCameraRenderTaskConfig::resetSizeSpectatorCamera(int width, int he
|
|||
resetSize(width, height);
|
||||
}
|
||||
|
||||
class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view.
|
||||
class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and view.
|
||||
glm::vec3 _position{};
|
||||
glm::quat _orientation{};
|
||||
float _vFoV{};
|
||||
|
@ -79,6 +79,7 @@ public:
|
|||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.disableContextStereo();
|
||||
batch.disableContextViewCorrection();
|
||||
});
|
||||
|
||||
auto srcViewFrustum = args->getViewFrustum();
|
||||
|
@ -112,6 +113,7 @@ public:
|
|||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.restoreContextStereo();
|
||||
batch.restoreContextViewCorrection();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -106,7 +106,8 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
|
||||
jsonValue = entityObject;
|
||||
} else if (wantsToMigrateResource(migrationURL)) {
|
||||
auto request = ResourceManager::createResourceRequest(this, migrationURL);
|
||||
auto request =
|
||||
DependencyManager::get<ResourceManager>()->createResourceRequest(this, migrationURL);
|
||||
|
||||
if (request) {
|
||||
qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration";
|
||||
|
|
|
@ -73,12 +73,14 @@ int main(int argc, const char* argv[]) {
|
|||
QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
|
||||
QCommandLineOption allowMultipleInstancesOption("allowMultipleInstances", "Allow multiple instances to run");
|
||||
QCommandLineOption overrideAppLocalDataPathOption("cache", "set test cache <dir>", "dir");
|
||||
QCommandLineOption overrideScriptsPathOption(SCRIPTS_SWITCH, "set scripts <path>", "path");
|
||||
parser.addOption(urlOption);
|
||||
parser.addOption(noUpdaterOption);
|
||||
parser.addOption(checkMinSpecOption);
|
||||
parser.addOption(runServerOption);
|
||||
parser.addOption(serverContentPathOption);
|
||||
parser.addOption(overrideAppLocalDataPathOption);
|
||||
parser.addOption(overrideScriptsPathOption);
|
||||
parser.addOption(allowMultipleInstancesOption);
|
||||
parser.parse(arguments);
|
||||
|
||||
|
@ -99,6 +101,16 @@ int main(int argc, const char* argv[]) {
|
|||
if (allowMultipleInstances) {
|
||||
instanceMightBeRunning = false;
|
||||
}
|
||||
// this needs to be done here in main, as the mechanism for setting the
|
||||
// scripts directory appears not to work. See the bug report
|
||||
// https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine
|
||||
if (parser.isSet(overrideScriptsPathOption)) {
|
||||
QDir scriptsPath(parser.value(overrideScriptsPathOption));
|
||||
if (scriptsPath.exists()) {
|
||||
PathUtils::defaultScriptsLocation(scriptsPath.path());
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(overrideAppLocalDataPathOption)) {
|
||||
// get dir to use for cache
|
||||
QString cacheDir = parser.value(overrideAppLocalDataPathOption);
|
||||
|
@ -106,7 +118,7 @@ int main(int argc, const char* argv[]) {
|
|||
// tell everyone to use the right cache location
|
||||
//
|
||||
// this handles data8 and prepared
|
||||
ResourceManager::setCacheDir(cacheDir);
|
||||
DependencyManager::get<ResourceManager>()->setCacheDir(cacheDir);
|
||||
|
||||
// this does the ktx_cache
|
||||
PathUtils::getAppLocalDataPath(cacheDir);
|
||||
|
|
|
@ -62,7 +62,7 @@ bool TestScriptingInterface::loadTestScene(QString scene) {
|
|||
static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/";
|
||||
static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/";
|
||||
return DependencyManager::get<OffscreenUi>()->returnFromUiThread([scene]()->QVariant {
|
||||
ResourceManager::setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
|
||||
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
|
||||
auto tree = qApp->getEntities()->getTree();
|
||||
auto treeIsClient = tree->getIsClient();
|
||||
// Force the tree to accept the load regardless of permissions
|
||||
|
|
34
libraries/animation/src/AnimDefaultPose.cpp
Normal file
34
libraries/animation/src/AnimDefaultPose.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// AnimDefaultPose.cpp
|
||||
//
|
||||
// Created by Anthony J. Thibault on 6/26/17.
|
||||
// Copyright (c) 2017 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AnimDefaultPose.h"
|
||||
|
||||
AnimDefaultPose::AnimDefaultPose(const QString& id) :
|
||||
AnimNode(AnimNode::Type::DefaultPose, id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AnimDefaultPose::~AnimDefaultPose() {
|
||||
|
||||
}
|
||||
|
||||
const AnimPoseVec& AnimDefaultPose::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) {
|
||||
if (_skeleton) {
|
||||
_poses = _skeleton->getRelativeDefaultPoses();
|
||||
} else {
|
||||
_poses.clear();
|
||||
}
|
||||
return _poses;
|
||||
}
|
||||
|
||||
const AnimPoseVec& AnimDefaultPose::getPosesInternal() const {
|
||||
return _poses;
|
||||
}
|
36
libraries/animation/src/AnimDefaultPose.h
Normal file
36
libraries/animation/src/AnimDefaultPose.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// AnimDefaultPose.h
|
||||
//
|
||||
// Created by Anthony J. Thibault on 6/26/17.
|
||||
// Copyright (c) 2017 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
// 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_AnimDefaultPose_h
|
||||
#define hifi_AnimDefaultPose_h
|
||||
|
||||
#include <string>
|
||||
#include "AnimNode.h"
|
||||
|
||||
// Always returns the default pose of the current skeleton.
|
||||
|
||||
class AnimDefaultPose : public AnimNode {
|
||||
public:
|
||||
AnimDefaultPose(const QString& id);
|
||||
virtual ~AnimDefaultPose() override;
|
||||
|
||||
virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut) override;
|
||||
protected:
|
||||
// for AnimDebugDraw rendering
|
||||
virtual const AnimPoseVec& getPosesInternal() const override;
|
||||
|
||||
AnimPoseVec _poses;
|
||||
|
||||
// no copies
|
||||
AnimDefaultPose(const AnimDefaultPose&) = delete;
|
||||
AnimDefaultPose& operator=(const AnimDefaultPose&) = delete;
|
||||
};
|
||||
|
||||
#endif // hifi_AnimDefaultPose_h
|
|
@ -870,9 +870,9 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
||||
glm::vec3 hipsOffset = scaleFactor * _hipsOffset;
|
||||
if (_hipsParentIndex == -1) {
|
||||
_relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans() + hipsOffset;
|
||||
_relativePoses[_hipsIndex].trans() = _relativePoses[_hipsIndex].trans() + hipsOffset;
|
||||
} else {
|
||||
auto absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, underPoses);
|
||||
auto absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
|
||||
absHipsPose.trans() += hipsOffset;
|
||||
_relativePoses[_hipsIndex] = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
|
||||
}
|
||||
|
@ -1732,6 +1732,10 @@ void AnimInverseKinematics::initRelativePosesFromSolutionSource(SolutionSource s
|
|||
break;
|
||||
case SolutionSource::RelaxToLimitCenterPoses:
|
||||
blendToPoses(_limitCenterPoses, underPoses, RELAX_BLEND_FACTOR);
|
||||
// special case for hips: copy over hips pose whether or not IK is enabled.
|
||||
if (_hipsIndex >= 0 && _hipsIndex < (int)_relativePoses.size()) {
|
||||
_relativePoses[_hipsIndex] = _limitCenterPoses[_hipsIndex];
|
||||
}
|
||||
break;
|
||||
case SolutionSource::PreviousSolution:
|
||||
// do nothing... _relativePoses is already the previous solution
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
StateMachine,
|
||||
Manipulator,
|
||||
InverseKinematics,
|
||||
DefaultPose,
|
||||
NumTypes
|
||||
};
|
||||
using Pointer = std::shared_ptr<AnimNode>;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "AnimStateMachine.h"
|
||||
#include "AnimManipulator.h"
|
||||
#include "AnimInverseKinematics.h"
|
||||
#include "AnimDefaultPose.h"
|
||||
|
||||
using NodeLoaderFunc = AnimNode::Pointer (*)(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
using NodeProcessFunc = bool (*)(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
|
@ -35,6 +36,7 @@ static AnimNode::Pointer loadOverlayNode(const QJsonObject& jsonObj, const QStri
|
|||
static AnimNode::Pointer loadStateMachineNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
static AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl);
|
||||
|
||||
// called after children have been loaded
|
||||
// returns node on success, nullptr on failure.
|
||||
|
@ -50,6 +52,7 @@ static const char* animNodeTypeToString(AnimNode::Type type) {
|
|||
case AnimNode::Type::StateMachine: return "stateMachine";
|
||||
case AnimNode::Type::Manipulator: return "manipulator";
|
||||
case AnimNode::Type::InverseKinematics: return "inverseKinematics";
|
||||
case AnimNode::Type::DefaultPose: return "defaultPose";
|
||||
case AnimNode::Type::NumTypes: return nullptr;
|
||||
};
|
||||
return nullptr;
|
||||
|
@ -109,6 +112,7 @@ static NodeLoaderFunc animNodeTypeToLoaderFunc(AnimNode::Type type) {
|
|||
case AnimNode::Type::StateMachine: return loadStateMachineNode;
|
||||
case AnimNode::Type::Manipulator: return loadManipulatorNode;
|
||||
case AnimNode::Type::InverseKinematics: return loadInverseKinematicsNode;
|
||||
case AnimNode::Type::DefaultPose: return loadDefaultPoseNode;
|
||||
case AnimNode::Type::NumTypes: return nullptr;
|
||||
};
|
||||
return nullptr;
|
||||
|
@ -123,6 +127,7 @@ static NodeProcessFunc animNodeTypeToProcessFunc(AnimNode::Type type) {
|
|||
case AnimNode::Type::StateMachine: return processStateMachineNode;
|
||||
case AnimNode::Type::Manipulator: return processDoNothing;
|
||||
case AnimNode::Type::InverseKinematics: return processDoNothing;
|
||||
case AnimNode::Type::DefaultPose: return processDoNothing;
|
||||
case AnimNode::Type::NumTypes: return nullptr;
|
||||
};
|
||||
return nullptr;
|
||||
|
@ -347,7 +352,8 @@ static const char* boneSetStrings[AnimOverlay::NumBoneSets] = {
|
|||
"empty",
|
||||
"leftHand",
|
||||
"rightHand",
|
||||
"hipsOnly"
|
||||
"hipsOnly",
|
||||
"bothFeet"
|
||||
};
|
||||
|
||||
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {
|
||||
|
@ -517,6 +523,11 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS
|
|||
return node;
|
||||
}
|
||||
|
||||
static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) {
|
||||
auto node = std::make_shared<AnimDefaultPose>(id);
|
||||
return node;
|
||||
}
|
||||
|
||||
void buildChildMap(std::map<QString, int>& map, AnimNode::Pointer node) {
|
||||
for (int i = 0; i < (int)node->getChildCount(); ++i) {
|
||||
map.insert(std::pair<QString, int>(node->getChild(i)->getID(), i));
|
||||
|
|
|
@ -35,6 +35,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) {
|
|||
case LeftHandBoneSet: buildLeftHandBoneSet(); break;
|
||||
case RightHandBoneSet: buildRightHandBoneSet(); break;
|
||||
case HipsOnlyBoneSet: buildHipsOnlyBoneSet(); break;
|
||||
case BothFeetBoneSet: buildBothFeetBoneSet(); break;
|
||||
default:
|
||||
case EmptyBoneSet: buildEmptyBoneSet(); break;
|
||||
}
|
||||
|
@ -196,6 +197,20 @@ void AnimOverlay::buildHipsOnlyBoneSet() {
|
|||
_boneSetVec[hipsJoint] = 1.0f;
|
||||
}
|
||||
|
||||
void AnimOverlay::buildBothFeetBoneSet() {
|
||||
assert(_skeleton);
|
||||
buildEmptyBoneSet();
|
||||
int rightFoot = _skeleton->nameToJointIndex("RightFoot");
|
||||
for_each_child_joint(_skeleton, rightFoot, [&](int i) {
|
||||
_boneSetVec[i] = 1.0f;
|
||||
});
|
||||
int leftFoot = _skeleton->nameToJointIndex("LeftFoot");
|
||||
for_each_child_joint(_skeleton, leftFoot, [&](int i) {
|
||||
_boneSetVec[i] = 1.0f;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// for AnimDebugDraw rendering
|
||||
const AnimPoseVec& AnimOverlay::getPosesInternal() const {
|
||||
return _poses;
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
LeftHandBoneSet,
|
||||
RightHandBoneSet,
|
||||
HipsOnlyBoneSet,
|
||||
BothFeetBoneSet,
|
||||
NumBoneSets
|
||||
};
|
||||
|
||||
|
@ -77,6 +78,7 @@ public:
|
|||
void buildLeftHandBoneSet();
|
||||
void buildRightHandBoneSet();
|
||||
void buildHipsOnlyBoneSet();
|
||||
void buildBothFeetBoneSet();
|
||||
|
||||
// no copies
|
||||
AnimOverlay(const AnimOverlay&) = delete;
|
||||
|
|
|
@ -144,38 +144,3 @@ void Animation::animationParseError(int error, QString str) {
|
|||
finishedLoading(false);
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails() :
|
||||
role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false),
|
||||
startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), currentFrame(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame) :
|
||||
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
|
||||
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
|
||||
running(running), currentFrame(currentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("role", details.role);
|
||||
obj.setProperty("url", details.url.toString());
|
||||
obj.setProperty("fps", details.fps);
|
||||
obj.setProperty("priority", details.priority);
|
||||
obj.setProperty("loop", details.loop);
|
||||
obj.setProperty("hold", details.hold);
|
||||
obj.setProperty("startAutomatically", details.startAutomatically);
|
||||
obj.setProperty("firstFrame", details.firstFrame);
|
||||
obj.setProperty("lastFrame", details.lastFrame);
|
||||
obj.setProperty("running", details.running);
|
||||
obj.setProperty("currentFrame", details.currentFrame);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) {
|
||||
// nothing for now...
|
||||
}
|
||||
|
||||
|
|
|
@ -107,26 +107,5 @@ private:
|
|||
QByteArray _data;
|
||||
};
|
||||
|
||||
class AnimationDetails {
|
||||
public:
|
||||
AnimationDetails();
|
||||
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame);
|
||||
|
||||
QString role;
|
||||
QUrl url;
|
||||
float fps;
|
||||
float priority;
|
||||
bool loop;
|
||||
bool hold;
|
||||
bool startAutomatically;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
bool running;
|
||||
float currentFrame;
|
||||
};
|
||||
Q_DECLARE_METATYPE(AnimationDetails);
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event);
|
||||
|
||||
#endif // hifi_AnimationCache_h
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "AnimationLogging.h"
|
||||
#include "AnimClip.h"
|
||||
#include "AnimInverseKinematics.h"
|
||||
#include "AnimOverlay.h"
|
||||
#include "AnimSkeleton.h"
|
||||
#include "AnimUtil.h"
|
||||
#include "IKTarget.h"
|
||||
|
@ -1459,13 +1460,28 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
|
|||
updateFeet(leftFootEnabled, rightFootEnabled,
|
||||
params.controllerPoses[ControllerType_LeftFoot], params.controllerPoses[ControllerType_RightFoot]);
|
||||
|
||||
if (hipsEnabled) {
|
||||
// if the hips or the feet are being controlled.
|
||||
if (hipsEnabled || rightFootEnabled || leftFootEnabled) {
|
||||
// for more predictable IK solve from the center of the joint limits, not from the underpose
|
||||
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses);
|
||||
|
||||
// replace the feet animation with the default pose, this is to prevent unexpected toe wiggling.
|
||||
_animVars.set("defaultPoseOverlayAlpha", 1.0f);
|
||||
_animVars.set("defaultPoseOverlayBoneSet", (int)AnimOverlay::BothFeetBoneSet);
|
||||
} else {
|
||||
// augment the IK with the underPose.
|
||||
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses);
|
||||
|
||||
// feet should follow source animation
|
||||
_animVars.unset("defaultPoseOverlayAlpha");
|
||||
_animVars.unset("defaultPoseOverlayBoneSet");
|
||||
}
|
||||
|
||||
if (hipsEnabled) {
|
||||
_animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition);
|
||||
_animVars.set("hipsPosition", params.controllerPoses[ControllerType_Hips].trans());
|
||||
_animVars.set("hipsRotation", params.controllerPoses[ControllerType_Hips].rot());
|
||||
} else {
|
||||
_animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses);
|
||||
_animVars.set("hipsType", (int)IKTarget::Type::Unknown);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "AudioClientLogging.h"
|
||||
#include "AudioLogging.h"
|
||||
#include "AudioHelpers.h"
|
||||
|
||||
#include "AudioClient.h"
|
||||
|
||||
|
@ -1688,23 +1689,24 @@ int AudioClient::calculateNumberOfFrameSamples(int numBytes) const {
|
|||
}
|
||||
|
||||
float AudioClient::azimuthForSource(const glm::vec3& relativePosition) {
|
||||
// copied from AudioMixer, more or less
|
||||
glm::quat inverseOrientation = glm::inverse(_orientationGetter());
|
||||
|
||||
// compute sample delay for the 2 ears to create phase panning
|
||||
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
|
||||
|
||||
// project the rotated source position vector onto x-y plane
|
||||
// project the rotated source position vector onto the XZ plane
|
||||
rotatedSourcePosition.y = 0.0f;
|
||||
|
||||
static const float SOURCE_DISTANCE_THRESHOLD = 1e-30f;
|
||||
|
||||
if (glm::length2(rotatedSourcePosition) > SOURCE_DISTANCE_THRESHOLD) {
|
||||
float rotatedSourcePositionLength2 = glm::length2(rotatedSourcePosition);
|
||||
if (rotatedSourcePositionLength2 > SOURCE_DISTANCE_THRESHOLD) {
|
||||
|
||||
// produce an oriented angle about the y-axis
|
||||
return glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, -1.0f, 0.0f));
|
||||
} else {
|
||||
|
||||
glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2));
|
||||
float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward"
|
||||
return (direction.x < 0.0f) ? -angle : angle;
|
||||
|
||||
} else {
|
||||
// no azimuth if they are in same spot
|
||||
return 0.0f;
|
||||
}
|
||||
|
|
|
@ -1978,7 +1978,7 @@ JointData jointDataFromJsonValue(const QJsonValue& json) {
|
|||
result.rotation = quatFromJsonValue(array[0]);
|
||||
result.rotationSet = true;
|
||||
result.translation = vec3FromJsonValue(array[1]);
|
||||
result.translationSet = false;
|
||||
result.translationSet = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -2146,12 +2146,9 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
|
|||
QVector<JointData> jointArray;
|
||||
QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray();
|
||||
jointArray.reserve(jointArrayJson.size());
|
||||
int i = 0;
|
||||
for (const auto& jointJson : jointArrayJson) {
|
||||
auto joint = jointDataFromJsonValue(jointJson);
|
||||
jointArray.push_back(joint);
|
||||
setJointData(i, joint.rotation, joint.translation);
|
||||
i++;
|
||||
}
|
||||
setRawJointData(jointArray);
|
||||
}
|
||||
|
|
|
@ -163,7 +163,6 @@ void EntityTreeRenderer::reloadEntityScripts() {
|
|||
void EntityTreeRenderer::init() {
|
||||
OctreeProcessor::init();
|
||||
EntityTreePointer entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
entityTree->setFBXService(this);
|
||||
|
||||
if (_wantScripts) {
|
||||
resetEntitiesScriptEngine();
|
||||
|
@ -188,7 +187,6 @@ void EntityTreeRenderer::shutdown() {
|
|||
|
||||
void EntityTreeRenderer::setTree(OctreePointer newTree) {
|
||||
OctreeProcessor::setTree(newTree);
|
||||
std::static_pointer_cast<EntityTree>(_tree)->setFBXService(this);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::update() {
|
||||
|
@ -373,31 +371,6 @@ bool EntityTreeRenderer::applyLayeredZones() {
|
|||
return true;
|
||||
}
|
||||
|
||||
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
|
||||
const FBXGeometry* result = NULL;
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||
assert(modelEntityItem); // we need this!!!
|
||||
ModelPointer model = modelEntityItem->getModel(getSharedFromThis());
|
||||
if (model && model->isLoaded()) {
|
||||
result = &model->getFBXGeometry();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ModelPointer EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityItem) {
|
||||
ModelPointer result = nullptr;
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||
result = modelEntityItem->getModel(getSharedFromThis());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
|
||||
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
|
||||
}
|
||||
|
@ -880,7 +853,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
|
|||
entity->scriptHasUnloaded();
|
||||
}
|
||||
if (shouldLoad) {
|
||||
scriptUrl = ResourceManager::normalizeURL(scriptUrl);
|
||||
scriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);
|
||||
_entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, reload);
|
||||
entity->scriptHasPreloaded();
|
||||
}
|
||||
|
@ -889,7 +862,12 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
|
|||
|
||||
void EntityTreeRenderer::playEntityCollisionSound(EntityItemPointer entity, const Collision& collision) {
|
||||
assert((bool)entity);
|
||||
SharedSoundPointer collisionSound = entity->getCollisionSound();
|
||||
auto renderable = entity->getRenderableInterface();
|
||||
if (!renderable) {
|
||||
return;
|
||||
}
|
||||
|
||||
SharedSoundPointer collisionSound = renderable->getCollisionSound();
|
||||
if (!collisionSound) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ using ModelWeakPointer = std::weak_ptr<Model>;
|
|||
using CalculateEntityLoadingPriority = std::function<float(const EntityItem& item)>;
|
||||
|
||||
// Generic client side Octree renderer class.
|
||||
class EntityTreeRenderer : public OctreeProcessor, public EntityItemFBXService, public Dependency {
|
||||
class EntityTreeRenderer : public OctreeProcessor, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
|
@ -68,9 +68,6 @@ public:
|
|||
|
||||
virtual void init() override;
|
||||
|
||||
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) override;
|
||||
virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) override;
|
||||
|
||||
/// clears the tree
|
||||
virtual void clear() override;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <render/Scene.h>
|
||||
#include <EntityItem.h>
|
||||
#include <Sound.h>
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
@ -40,7 +41,11 @@ public:
|
|||
virtual void render(RenderArgs* args) {};
|
||||
virtual bool addToScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) = 0;
|
||||
virtual void removeFromScene(const EntityItemPointer& self, const render::ScenePointer& scene, render::Transaction& transaction) = 0;
|
||||
const SharedSoundPointer& getCollisionSound() { return _collisionSound; }
|
||||
void setCollisionSound(const SharedSoundPointer& sound) { _collisionSound = sound; }
|
||||
virtual RenderableEntityInterface* getRenderableInterface() { return nullptr; }
|
||||
private:
|
||||
SharedSoundPointer _collisionSound;
|
||||
};
|
||||
|
||||
class RenderableEntityItemProxy {
|
||||
|
|
|
@ -69,11 +69,9 @@ void RenderableModelEntityItem::setModelURL(const QString& url) {
|
|||
|
||||
void RenderableModelEntityItem::loader() {
|
||||
_needsModelReload = true;
|
||||
auto renderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
assert(renderer);
|
||||
{
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
getModel(renderer);
|
||||
getModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,8 +388,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
if (!_model || _needsModelReload) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
auto renderer = qSharedPointerCast<EntityTreeRenderer>(args->_renderData);
|
||||
getModel(renderer);
|
||||
getModel();
|
||||
|
||||
// Remap textures immediately after loading to avoid flicker
|
||||
remapTextures();
|
||||
|
@ -483,7 +480,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
auto& currentURL = getParsedModelURL();
|
||||
if (currentURL != _model->getURL()) {
|
||||
// Defer setting the url to the render thread
|
||||
getModel(_myRenderer);
|
||||
getModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -492,16 +489,11 @@ ModelPointer RenderableModelEntityItem::getModelNotSafe() {
|
|||
return _model;
|
||||
}
|
||||
|
||||
ModelPointer RenderableModelEntityItem::getModel(QSharedPointer<EntityTreeRenderer> renderer) {
|
||||
if (!renderer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModelPointer RenderableModelEntityItem::getModel() {
|
||||
// make sure our renderer is setup
|
||||
if (!_myRenderer) {
|
||||
_myRenderer = renderer;
|
||||
_myRenderer = DependencyManager::get<EntityTreeRenderer>();
|
||||
}
|
||||
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
||||
|
||||
if (!_myRenderer || QThread::currentThread() != _myRenderer->thread()) {
|
||||
return _model;
|
||||
|
@ -513,7 +505,7 @@ ModelPointer RenderableModelEntityItem::getModel(QSharedPointer<EntityTreeRender
|
|||
if (!getModelURL().isEmpty()) {
|
||||
// If we don't have a model, allocate one *immediately*
|
||||
if (!_model) {
|
||||
_model = _myRenderer->allocateModel(getModelURL(), renderer->getEntityLoadingPriority(*this), this);
|
||||
_model = _myRenderer->allocateModel(getModelURL(), _myRenderer->getEntityLoadingPriority(*this), this);
|
||||
_needsInitialSimulation = true;
|
||||
// If we need to change URLs, update it *after rendering* (to avoid access violations)
|
||||
} else if (QUrl(getModelURL()) != _model->getURL()) {
|
||||
|
@ -587,6 +579,17 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
properties.setRenderInfoHasTransparent(_model->getRenderInfoHasTransparent());
|
||||
}
|
||||
|
||||
|
||||
if (_model && _model->isLoaded()) {
|
||||
// TODO: improve naturalDimensions in the future,
|
||||
// for now we've added this hack for setting natural dimensions of models
|
||||
Extents meshExtents = _model->getFBXGeometry().getUnscaledMeshExtents();
|
||||
properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -1255,3 +1258,27 @@ QStringList RenderableModelEntityItem::getJointNames() const {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
||||
// if we don't have animation, or we're already joint mapped then bail early
|
||||
if (!hasAnimation() || jointsMapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_animation || _animation->getURL().toString() != getAnimationURL()) {
|
||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(getAnimationURL());
|
||||
}
|
||||
|
||||
if (_animation && _animation->isLoaded()) {
|
||||
QStringList animationJointNames = _animation->getJointNames();
|
||||
|
||||
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
|
||||
_jointMapping.resize(modelJointNames.size());
|
||||
for (int i = 0; i < modelJointNames.size(); i++) {
|
||||
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
|
||||
}
|
||||
_jointMappingCompleted = true;
|
||||
_jointMappingURL = _animationProperties.getURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QStringList>
|
||||
|
||||
#include <ModelEntityItem.h>
|
||||
#include <AnimationCache.h>
|
||||
|
||||
class Model;
|
||||
class EntityTreeRenderer;
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const override;
|
||||
ModelPointer getModel(QSharedPointer<EntityTreeRenderer> renderer);
|
||||
ModelPointer getModel();
|
||||
ModelPointer getModelNotSafe();
|
||||
|
||||
virtual bool needsToCallUpdate() const override;
|
||||
|
@ -106,6 +107,15 @@ public:
|
|||
// Transparency is handled in ModelMeshPartPayload
|
||||
bool isTransparent() override { return false; }
|
||||
|
||||
void mapJoints(const QStringList& modelJointNames);
|
||||
bool jointsMapped() const {
|
||||
return _jointMappingURL == getAnimationURL() && _jointMappingCompleted;
|
||||
}
|
||||
|
||||
AnimationPointer getAnimation() const {
|
||||
return _animation;
|
||||
}
|
||||
|
||||
private:
|
||||
QVariantMap parseTexturesToMap(QString textures);
|
||||
void remapTextures();
|
||||
|
@ -131,6 +141,12 @@ private:
|
|||
bool _needsJointSimulation { false };
|
||||
bool _showCollisionGeometry { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
|
||||
// used on client side
|
||||
bool _jointMappingCompleted { false };
|
||||
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
|
||||
QString _jointMappingURL;
|
||||
AnimationPointer _animation;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableModelEntityItem_h
|
||||
|
|
|
@ -9,11 +9,15 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "RenderablePolyVoxEntityItem.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
#include <model-networking/SimpleMeshProxy.h>
|
||||
#include "ModelScriptingInterface.h"
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
|
@ -52,7 +56,6 @@
|
|||
#include "EntityTreeRenderer.h"
|
||||
#include "polyvox_vert.h"
|
||||
#include "polyvox_frag.h"
|
||||
#include "RenderablePolyVoxEntityItem.h"
|
||||
#include "EntityEditPacketSender.h"
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
||||
|
@ -1626,6 +1629,7 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
|
|||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
|
||||
bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
||||
if (!updateDependents()) {
|
||||
return false;
|
||||
|
@ -1645,7 +1649,7 @@ bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
|
|||
} else {
|
||||
success = true;
|
||||
// the mesh will be in voxel-space. transform it into object-space
|
||||
meshProxy = new MeshProxy(
|
||||
meshProxy = new SimpleMeshProxy(
|
||||
_mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
|
||||
[=](glm::vec3 normal){ return glm::normalize(glm::vec3(transform * glm::vec4(normal, 0.0f))); },
|
||||
[&](uint32_t index){ return index; }));
|
||||
|
|
|
@ -12,17 +12,19 @@
|
|||
#ifndef hifi_RenderablePolyVoxEntityItem_h
|
||||
#define hifi_RenderablePolyVoxEntityItem_h
|
||||
|
||||
#include <QSemaphore>
|
||||
#include <atomic>
|
||||
|
||||
#include <QSemaphore>
|
||||
|
||||
#include <PolyVoxCore/SimpleVolume.h>
|
||||
#include <PolyVoxCore/Raycast.h>
|
||||
|
||||
#include <gpu/Context.h>
|
||||
#include <model/Forward.h>
|
||||
#include <TextureCache.h>
|
||||
#include <PolyVoxEntityItem.h>
|
||||
|
||||
#include "PolyVoxEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
#include "gpu/Context.h"
|
||||
|
||||
class PolyVoxPayload {
|
||||
public:
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
set(TARGET_NAME entities)
|
||||
setup_hifi_library(Network Script)
|
||||
link_hifi_libraries(avatars shared audio octree model model-networking fbx networking animation)
|
||||
include_hifi_library_headers(networking)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
||||
target_bullet()
|
||||
|
||||
include_hifi_library_headers(render)
|
||||
link_hifi_libraries(shared networking octree avatars)
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AnimationPropertyGroup.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <OctreePacketData.h>
|
||||
|
||||
#include <AnimationLoop.h>
|
||||
|
||||
#include "AnimationPropertyGroup.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include "AnimationLoop.h"
|
||||
#include <shared/types/AnimationLoop.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
#include "PropertyGroup.h"
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) {
|
|||
_filterDataMap.insert(entityID, filterData);
|
||||
_lock.unlock();
|
||||
|
||||
auto scriptRequest = ResourceManager::createResourceRequest(this, scriptURL);
|
||||
auto scriptRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, scriptURL);
|
||||
if (!scriptRequest) {
|
||||
qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString();
|
||||
scriptRequestFinished(entityID);
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <PhysicsHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h> // usecTimestampNow()
|
||||
#include <SoundCache.h>
|
||||
#include <LogHandler.h>
|
||||
#include <Extents.h>
|
||||
|
||||
#include "EntityScriptingInterface.h"
|
||||
#include "EntitiesLogging.h"
|
||||
|
@ -988,21 +988,6 @@ void EntityItem::setCollisionSoundURL(const QString& value) {
|
|||
}
|
||||
}
|
||||
|
||||
SharedSoundPointer EntityItem::getCollisionSound() {
|
||||
SharedSoundPointer result;
|
||||
withReadLock([&] {
|
||||
result = _collisionSound;
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
result = DependencyManager::get<SoundCache>()->getSound(_collisionSoundURL);
|
||||
withWriteLock([&] {
|
||||
_collisionSound = result;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::simulate(const quint64& now) {
|
||||
if (getLastSimulated() == 0) {
|
||||
setLastSimulated(now);
|
||||
|
@ -2650,12 +2635,6 @@ QString EntityItem::getCollisionSoundURL() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setCollisionSound(SharedSoundPointer sound) {
|
||||
withWriteLock([&] {
|
||||
_collisionSound = sound;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::getRegistrationPoint() const {
|
||||
glm::vec3 result;
|
||||
withReadLock([&] {
|
||||
|
|
|
@ -19,14 +19,13 @@
|
|||
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include <AnimationCache.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||
#include <shared/types/AnimationLoop.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
#include <PhysicsCollisionGroups.h>
|
||||
#include <ShapeInfo.h>
|
||||
#include <Transform.h>
|
||||
#include <Sound.h>
|
||||
#include <SpatiallyNestable.h>
|
||||
#include <Interpolate.h>
|
||||
|
||||
|
@ -260,9 +259,6 @@ public:
|
|||
QString getCollisionSoundURL() const;
|
||||
void setCollisionSoundURL(const QString& value);
|
||||
|
||||
SharedSoundPointer getCollisionSound();
|
||||
void setCollisionSound(SharedSoundPointer sound);
|
||||
|
||||
glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity
|
||||
|
||||
/// registration point as ratio of entity
|
||||
|
@ -526,7 +522,6 @@ protected:
|
|||
quint64 _loadedScriptTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 };
|
||||
|
||||
QString _collisionSoundURL;
|
||||
SharedSoundPointer _collisionSound;
|
||||
glm::vec3 _registrationPoint;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include <QtCore/QObject>
|
||||
#include <QDebug>
|
||||
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include <UUID.h>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
#include "EntityItemID.h"
|
||||
|
||||
int entityItemIDTypeID = qRegisterMetaType<EntityItemID>();
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <ByteCountCoding.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <Extents.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityItem.h"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QObject>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <VariantMapToScriptValue.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <SpatialParentFinder.h>
|
||||
#include <model-networking/MeshProxy.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityDynamicFactoryInterface.h"
|
||||
|
@ -298,18 +297,6 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
|
|||
}
|
||||
|
||||
results = entity->getProperties(desiredProperties);
|
||||
|
||||
// TODO: improve naturalDimensions in the future,
|
||||
// for now we've added this hack for setting natural dimensions of models
|
||||
if (entity->getType() == EntityTypes::Model) {
|
||||
const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity);
|
||||
if (geometry) {
|
||||
Extents meshExtents = geometry->getUnscaledMeshExtents();
|
||||
results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,11 +9,15 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <QDateTime>
|
||||
#include "EntityTree.h"
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QQueue>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include "EntityTree.h"
|
||||
#include <PerfStat.h>
|
||||
#include <Extents.h>
|
||||
|
||||
#include "EntitySimulation.h"
|
||||
#include "VariantMapToScriptValue.h"
|
||||
|
||||
|
@ -55,9 +59,7 @@ public:
|
|||
|
||||
|
||||
EntityTree::EntityTree(bool shouldReaverage) :
|
||||
Octree(shouldReaverage),
|
||||
_fbxService(NULL),
|
||||
_simulation(NULL)
|
||||
Octree(shouldReaverage)
|
||||
{
|
||||
resetClientEditStats();
|
||||
}
|
||||
|
|
|
@ -41,13 +41,6 @@ public:
|
|||
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) = 0;
|
||||
};
|
||||
|
||||
class EntityItemFBXService {
|
||||
public:
|
||||
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0;
|
||||
virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) = 0;
|
||||
};
|
||||
|
||||
|
||||
class SendEntitiesOperationArgs {
|
||||
public:
|
||||
glm::vec3 root;
|
||||
|
@ -189,15 +182,6 @@ public:
|
|||
int processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode);
|
||||
int processEraseMessageDetails(const QByteArray& buffer, const SharedNodePointer& sourceNode);
|
||||
|
||||
EntityItemFBXService* getFBXService() const { return _fbxService; }
|
||||
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
||||
const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) {
|
||||
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
|
||||
}
|
||||
ModelPointer getModelForEntityItem(EntityItemPointer entityItem) {
|
||||
return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL;
|
||||
}
|
||||
|
||||
EntityTreeElementPointer getContainingElement(const EntityItemID& entityItemID) /*const*/;
|
||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElementPointer element);
|
||||
void debugDumpMap();
|
||||
|
@ -325,8 +309,6 @@ protected:
|
|||
_deletedEntityItemIDs << id;
|
||||
}
|
||||
|
||||
EntityItemFBXService* _fbxService;
|
||||
|
||||
mutable QReadWriteLock _entityToElementLock;
|
||||
QHash<EntityItemID, EntityTreeElementPointer> _entityToElementMap;
|
||||
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "EntityTreeElement.h"
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <FBXReader.h>
|
||||
#include <GeometryUtil.h>
|
||||
#include <OctreeUtils.h>
|
||||
#include <Extents.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityNodeData.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
#include "EntityTypes.h"
|
||||
|
||||
EntityTreeElement::EntityTreeElement(unsigned char* octalCode) : OctreeElement() {
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "KeyLightPropertyGroup.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <OctreePacketData.h>
|
||||
|
||||
#include <AnimationLoop.h>
|
||||
|
||||
#include "KeyLightPropertyGroup.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(
|
|||
_animationLoop.setResetOnRunning(false);
|
||||
|
||||
_type = EntityTypes::Model;
|
||||
_jointMappingCompleted = false;
|
||||
_lastKnownCurrentFrame = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
}
|
||||
|
@ -204,30 +203,6 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
}
|
||||
|
||||
|
||||
void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
|
||||
// if we don't have animation, or we're already joint mapped then bail early
|
||||
if (!hasAnimation() || jointsMapped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_animation || _animation->getURL().toString() != getAnimationURL()) {
|
||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(getAnimationURL());
|
||||
}
|
||||
|
||||
if (_animation && _animation->isLoaded()) {
|
||||
QStringList animationJointNames = _animation->getJointNames();
|
||||
|
||||
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
|
||||
_jointMapping.resize(modelJointNames.size());
|
||||
for (int i = 0; i < modelJointNames.size(); i++) {
|
||||
_jointMapping[i] = animationJointNames.indexOf(modelJointNames[i]);
|
||||
}
|
||||
_jointMappingCompleted = true;
|
||||
_jointMappingURL = _animationProperties.getURL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
return getAnimationIsPlaying() &&
|
||||
getAnimationFPS() != 0.0f &&
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#ifndef hifi_ModelEntityItem_h
|
||||
#define hifi_ModelEntityItem_h
|
||||
|
||||
#include <AnimationLoop.h>
|
||||
|
||||
#include "EntityItem.h"
|
||||
#include "AnimationPropertyGroup.h"
|
||||
|
||||
|
@ -103,10 +101,7 @@ public:
|
|||
void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); }
|
||||
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
|
||||
|
||||
void mapJoints(const QStringList& modelJointNames);
|
||||
bool jointsMapped() const { return _jointMappingURL == getAnimationURL() && _jointMappingCompleted; }
|
||||
|
||||
AnimationPointer getAnimation() const { return _animation; }
|
||||
bool getAnimationIsPlaying() const { return _animationLoop.getRunning(); }
|
||||
float getAnimationCurrentFrame() const { return _animationLoop.getCurrentFrame(); }
|
||||
float getAnimationFPS() const { return _animationLoop.getFPS(); }
|
||||
|
@ -158,7 +153,6 @@ protected:
|
|||
QUrl _parsedModelURL;
|
||||
QString _compoundShapeURL;
|
||||
|
||||
AnimationPointer _animation;
|
||||
AnimationPropertyGroup _animationProperties;
|
||||
AnimationLoop _animationLoop;
|
||||
|
||||
|
@ -166,11 +160,6 @@ protected:
|
|||
QString _textures;
|
||||
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
|
||||
// used on client side
|
||||
bool _jointMappingCompleted;
|
||||
QVector<int> _jointMapping; // domain is index into model-joints, range is index into animation-joints
|
||||
QString _jointMappingURL;
|
||||
};
|
||||
|
||||
#endif // hifi_ModelEntityItem_h
|
||||
|
|
|
@ -202,7 +202,7 @@ bool OBJReader::isValidTexture(const QByteArray &filename) {
|
|||
}
|
||||
QUrl candidateUrl = _url.resolved(QUrl(filename));
|
||||
|
||||
return ResourceManager::resourceExists(candidateUrl);
|
||||
return DependencyManager::get<ResourceManager>()->resourceExists(candidateUrl);
|
||||
}
|
||||
|
||||
void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
||||
|
@ -267,7 +267,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) {
|
|||
}
|
||||
|
||||
std::tuple<bool, QByteArray> requestData(QUrl& url) {
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
|
||||
if (!request) {
|
||||
return std::make_tuple(false, QByteArray());
|
||||
|
|
|
@ -114,7 +114,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::gl::GLBackend::do_getQuery),
|
||||
|
||||
(&::gpu::gl::GLBackend::do_resetStages),
|
||||
|
||||
|
||||
(&::gpu::gl::GLBackend::do_disableContextViewCorrection),
|
||||
(&::gpu::gl::GLBackend::do_restoreContextViewCorrection),
|
||||
(&::gpu::gl::GLBackend::do_disableContextStereo),
|
||||
(&::gpu::gl::GLBackend::do_restoreContextStereo),
|
||||
|
||||
|
@ -374,6 +376,13 @@ void GLBackend::do_resetStages(const Batch& batch, size_t paramOffset) {
|
|||
resetStages();
|
||||
}
|
||||
|
||||
void GLBackend::do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) {
|
||||
_transform._viewCorrectionEnabled = false;
|
||||
}
|
||||
|
||||
void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) {
|
||||
_transform._viewCorrectionEnabled = true;
|
||||
}
|
||||
|
||||
void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) {
|
||||
|
||||
|
|
|
@ -143,6 +143,10 @@ public:
|
|||
// Reset stages
|
||||
virtual void do_resetStages(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
|
||||
virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final;
|
||||
|
||||
|
@ -333,6 +337,8 @@ protected:
|
|||
bool _skybox { false };
|
||||
Transform _view;
|
||||
CameraCorrection _correction;
|
||||
bool _viewCorrectionEnabled{ true };
|
||||
|
||||
|
||||
Mat4 _projection;
|
||||
Vec4i _viewport { 0, 0, 1, 1 };
|
||||
|
@ -400,6 +406,7 @@ protected:
|
|||
bool _invalidProgram { false };
|
||||
|
||||
BufferView _cameraCorrectionBuffer { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
||||
BufferView _cameraCorrectionBufferIdentity { gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(CameraCorrection), nullptr )) };
|
||||
|
||||
State::Data _stateCache{ State::DEFAULT };
|
||||
State::Signature _stateSignatureCache { 0 };
|
||||
|
@ -409,6 +416,8 @@ protected:
|
|||
|
||||
PipelineStageState() {
|
||||
_cameraCorrectionBuffer.edit<CameraCorrection>() = CameraCorrection();
|
||||
_cameraCorrectionBufferIdentity.edit<CameraCorrection>() = CameraCorrection();
|
||||
_cameraCorrectionBufferIdentity._buffer->flush();
|
||||
}
|
||||
} _pipeline;
|
||||
|
||||
|
|
|
@ -77,8 +77,14 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) {
|
|||
if (_pipeline._invalidProgram) {
|
||||
glUseProgram(_pipeline._program);
|
||||
if (_pipeline._cameraCorrectionLocation != -1) {
|
||||
auto cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer);
|
||||
gl::GLBuffer* cameraCorrectionBuffer = nullptr;
|
||||
if (_transform._viewCorrectionEnabled) {
|
||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBuffer._buffer);
|
||||
} else {
|
||||
cameraCorrectionBuffer = syncGPUObject(*_pipeline._cameraCorrectionBufferIdentity._buffer);
|
||||
}
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, _pipeline._cameraCorrectionLocation, cameraCorrectionBuffer->_id, 0, sizeof(CameraCorrection));
|
||||
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
_pipeline._invalidProgram = false;
|
||||
|
|
|
@ -102,7 +102,7 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
|
|||
|
||||
if (_invalidView) {
|
||||
// Apply the correction
|
||||
if (_viewIsCamera && _correction.correction != glm::mat4()) {
|
||||
if (_viewIsCamera && (_viewCorrectionEnabled && _correction.correction != glm::mat4())) {
|
||||
// FIXME should I switch to using the camera correction buffer in Transform.slf and leave this out?
|
||||
Transform result;
|
||||
_view.mult(result, _view, _correction.correction);
|
||||
|
|
|
@ -390,6 +390,13 @@ void Batch::resetStages() {
|
|||
ADD_COMMAND(resetStages);
|
||||
}
|
||||
|
||||
void Batch::disableContextViewCorrection() {
|
||||
ADD_COMMAND(disableContextViewCorrection);
|
||||
}
|
||||
|
||||
void Batch::restoreContextViewCorrection() {
|
||||
ADD_COMMAND(restoreContextViewCorrection);
|
||||
}
|
||||
|
||||
void Batch::disableContextStereo() {
|
||||
ADD_COMMAND(disableContextStereo);
|
||||
|
|
|
@ -217,6 +217,9 @@ public:
|
|||
// Reset the stage caches and states
|
||||
void resetStages();
|
||||
|
||||
void disableContextViewCorrection();
|
||||
void restoreContextViewCorrection();
|
||||
|
||||
void disableContextStereo();
|
||||
void restoreContextStereo();
|
||||
|
||||
|
@ -304,6 +307,9 @@ public:
|
|||
|
||||
COMMAND_resetStages,
|
||||
|
||||
COMMAND_disableContextViewCorrection,
|
||||
COMMAND_restoreContextViewCorrection,
|
||||
|
||||
COMMAND_disableContextStereo,
|
||||
COMMAND_restoreContextStereo,
|
||||
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
//
|
||||
// MeshFace.cpp
|
||||
// libraries/model/src/model/
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-23
|
||||
// Copyright 2017 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 <RegisteredMetaTypes.h>
|
||||
|
||||
#include "MeshFace.h"
|
||||
|
||||
|
||||
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult) {
|
||||
qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices);
|
||||
}
|
||||
|
||||
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector) {
|
||||
QScriptValue array = engine->newArray();
|
||||
for (int i = 0; i < vector.size(); i++) {
|
||||
array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result) {
|
||||
int length = array.property("length").toInteger();
|
||||
result.clear();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
MeshFace meshFace = MeshFace();
|
||||
meshFaceFromScriptValue(array.property(i), meshFace);
|
||||
result << meshFace;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// MeshFace.h
|
||||
// libraries/model/src/model/
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-23
|
||||
// Copyright 2017 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_MeshFace_h
|
||||
#define hifi_MeshFace_h
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||
|
||||
class MeshFace {
|
||||
|
||||
public:
|
||||
MeshFace() {}
|
||||
~MeshFace() {}
|
||||
|
||||
QVector<uint32_t> vertexIndices;
|
||||
// TODO -- material...
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MeshFace)
|
||||
Q_DECLARE_METATYPE(QVector<MeshFace>)
|
||||
|
||||
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace);
|
||||
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult);
|
||||
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector);
|
||||
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result);
|
||||
|
||||
|
||||
|
||||
#endif // hifi_MeshFace_h
|
|
@ -1,48 +0,0 @@
|
|||
//
|
||||
// MeshProxy.cpp
|
||||
// libraries/model/src/model/
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-22.
|
||||
// Copyright 2017 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 "MeshProxy.h"
|
||||
|
||||
|
||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
|
||||
return engine->newQObject(in, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
||||
}
|
||||
|
||||
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
|
||||
out = qobject_cast<MeshProxy*>(value.toQObject());
|
||||
}
|
||||
|
||||
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) {
|
||||
// QScriptValueList result;
|
||||
QScriptValue result = engine->newArray();
|
||||
int i = 0;
|
||||
foreach (MeshProxy* const meshProxy, in) {
|
||||
result.setProperty(i++, meshToScriptValue(engine, meshProxy));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) {
|
||||
QScriptValueIterator itr(value);
|
||||
|
||||
qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32();
|
||||
|
||||
while(itr.hasNext()) {
|
||||
itr.next();
|
||||
MeshProxy* meshProxy = qscriptvalue_cast<MeshProxyList::value_type>(itr.value());
|
||||
if (meshProxy) {
|
||||
out.append(meshProxy);
|
||||
} else {
|
||||
qDebug() << "null meshProxy";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
//
|
||||
// MeshProxy.h
|
||||
// libraries/model/src/model/
|
||||
//
|
||||
// Created by Seth Alves on 2017-1-27.
|
||||
// Copyright 2017 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_MeshProxy_h
|
||||
#define hifi_MeshProxy_h
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||
|
||||
class MeshProxy : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MeshProxy(MeshPointer mesh) : _mesh(mesh) {}
|
||||
~MeshProxy() {}
|
||||
|
||||
MeshPointer getMeshPointer() const { return _mesh; }
|
||||
|
||||
Q_INVOKABLE int getNumVertices() const { return (int)_mesh->getNumVertices(); }
|
||||
Q_INVOKABLE glm::vec3 getPos3(int index) const { return _mesh->getPos3(index); }
|
||||
|
||||
|
||||
protected:
|
||||
MeshPointer _mesh;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MeshProxy*);
|
||||
|
||||
class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
|
||||
Q_DECLARE_METATYPE(MeshProxyList);
|
||||
|
||||
|
||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
|
||||
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out);
|
||||
|
||||
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in);
|
||||
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out);
|
||||
|
||||
#endif // hifi_MeshProxy_h
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// SimpleMeshProxy.cpp
|
||||
// libraries/model-networking/src/model-networking/
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-22.
|
||||
// Copyright 2017 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 "SimpleMeshProxy.h"
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
MeshPointer SimpleMeshProxy::getMeshPointer() const {
|
||||
return _mesh;
|
||||
}
|
||||
|
||||
int SimpleMeshProxy::getNumVertices() const {
|
||||
return (int)_mesh->getNumVertices();
|
||||
}
|
||||
|
||||
glm::vec3 SimpleMeshProxy::getPos3(int index) const {
|
||||
return _mesh->getPos3(index);
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// SimpleMeshProxy.h
|
||||
// libraries/model-networking/src/model-networking/
|
||||
//
|
||||
// Created by Seth Alves on 2017-1-27.
|
||||
// Copyright 2017 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_SimpleMeshProxy_h
|
||||
#define hifi_SimpleMeshProxy_h
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
class SimpleMeshProxy : public MeshProxy {
|
||||
public:
|
||||
SimpleMeshProxy(const MeshPointer& mesh) : _mesh(mesh) { }
|
||||
|
||||
MeshPointer getMeshPointer() const override;
|
||||
|
||||
int getNumVertices() const override;
|
||||
|
||||
glm::vec3 getPos3(int index) const override;
|
||||
|
||||
|
||||
protected:
|
||||
const MeshPointer _mesh;
|
||||
};
|
||||
|
||||
#endif // hifi_SimpleMeshProxy_h
|
|
@ -384,7 +384,7 @@ void NetworkTexture::makeRequest() {
|
|||
// Add a fragment to the base url so we can identify the section of the ktx being requested when debugging
|
||||
// The actual requested url is _activeUrl and will not contain the fragment
|
||||
_url.setFragment("head");
|
||||
_ktxHeaderRequest = ResourceManager::createResourceRequest(this, _activeUrl);
|
||||
_ktxHeaderRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
|
||||
if (!_ktxHeaderRequest) {
|
||||
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
@ -454,7 +454,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
|
|||
|
||||
bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL;
|
||||
|
||||
_ktxMipRequest = ResourceManager::createResourceRequest(this, _activeUrl);
|
||||
_ktxMipRequest = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
|
||||
if (!_ktxMipRequest) {
|
||||
qCWarning(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
|
19
libraries/model/src/model/Forward.h
Normal file
19
libraries/model/src/model/Forward.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Forward.h
|
||||
// libraries/model/src/model
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2017/06/21
|
||||
// Copyright 2013-2017 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_model_Forward_h
|
||||
#define hifi_model_Forward_h
|
||||
|
||||
namespace model {
|
||||
class Mesh;
|
||||
using MeshPointer = std::shared_ptr<Mesh>;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -13,7 +13,7 @@
|
|||
#include "AtpReply.h"
|
||||
|
||||
AtpReply::AtpReply(const QUrl& url, QObject* parent) :
|
||||
_resourceRequest(ResourceManager::createResourceRequest(parent, url)) {
|
||||
_resourceRequest(DependencyManager::get<ResourceManager>()->createResourceRequest(parent, url)) {
|
||||
setOperation(QNetworkAccessManager::GetOperation);
|
||||
|
||||
connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress);
|
||||
|
|
|
@ -672,7 +672,7 @@ void Resource::makeRequest() {
|
|||
|
||||
PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } });
|
||||
|
||||
_request = ResourceManager::createResourceRequest(this, _activeUrl);
|
||||
_request = DependencyManager::get<ResourceManager>()->createResourceRequest(this, _activeUrl);
|
||||
|
||||
if (!_request) {
|
||||
qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString();
|
||||
|
|
|
@ -24,10 +24,16 @@
|
|||
#include "NetworkAccessManager.h"
|
||||
#include "NetworkLogging.h"
|
||||
|
||||
QThread ResourceManager::_thread;
|
||||
ResourceManager::PrefixMap ResourceManager::_prefixMap;
|
||||
QMutex ResourceManager::_prefixMapLock;
|
||||
QString ResourceManager::_cacheDir;
|
||||
|
||||
ResourceManager::ResourceManager() {
|
||||
_thread.setObjectName("Resource Manager Thread");
|
||||
|
||||
auto assetClient = DependencyManager::set<AssetClient>(_cacheDir);
|
||||
assetClient->moveToThread(&_thread);
|
||||
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
|
||||
|
||||
_thread.start();
|
||||
}
|
||||
|
||||
void ResourceManager::setUrlPrefixOverride(const QString& prefix, const QString& replacement) {
|
||||
QMutexLocker locker(&_prefixMapLock);
|
||||
|
@ -75,16 +81,6 @@ QUrl ResourceManager::normalizeURL(const QUrl& originalUrl) {
|
|||
return url;
|
||||
}
|
||||
|
||||
void ResourceManager::init() {
|
||||
_thread.setObjectName("Resource Manager Thread");
|
||||
|
||||
auto assetClient = DependencyManager::set<AssetClient>(_cacheDir);
|
||||
assetClient->moveToThread(&_thread);
|
||||
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
|
||||
|
||||
_thread.start();
|
||||
}
|
||||
|
||||
void ResourceManager::cleanup() {
|
||||
// cleanup the AssetClient thread
|
||||
DependencyManager::destroy<AssetClient>();
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QThread>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "ResourceRequest.h"
|
||||
|
||||
|
@ -24,34 +28,38 @@ const QString URL_SCHEME_HTTPS = "https";
|
|||
const QString URL_SCHEME_FTP = "ftp";
|
||||
const QString URL_SCHEME_ATP = "atp";
|
||||
|
||||
class ResourceManager {
|
||||
class ResourceManager: public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
ResourceManager();
|
||||
|
||||
static void setUrlPrefixOverride(const QString& prefix, const QString& replacement);
|
||||
static QString normalizeURL(const QString& urlString);
|
||||
static QUrl normalizeURL(const QUrl& url);
|
||||
void setUrlPrefixOverride(const QString& prefix, const QString& replacement);
|
||||
QString normalizeURL(const QString& urlString);
|
||||
QUrl normalizeURL(const QUrl& url);
|
||||
|
||||
static ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
||||
ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url);
|
||||
|
||||
static void init();
|
||||
static void cleanup();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
// Blocking call to check if a resource exists. This function uses a QEventLoop internally
|
||||
// to return to the calling thread so that events can still be processed.
|
||||
static bool resourceExists(const QUrl& url);
|
||||
bool resourceExists(const QUrl& url);
|
||||
|
||||
// adjust where we persist the cache
|
||||
static void setCacheDir(const QString& cacheDir);
|
||||
void setCacheDir(const QString& cacheDir);
|
||||
|
||||
private:
|
||||
static QThread _thread;
|
||||
QThread _thread;
|
||||
|
||||
using PrefixMap = std::map<QString, QString>;
|
||||
|
||||
static PrefixMap _prefixMap;
|
||||
static QMutex _prefixMapLock;
|
||||
PrefixMap _prefixMap;
|
||||
QMutex _prefixMapLock;
|
||||
|
||||
static QString _cacheDir;
|
||||
QString _cacheDir;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
#include "ResourceManager.h"
|
||||
|
||||
void ResourceScriptingInterface::overrideUrlPrefix(const QString& prefix, const QString& replacement) {
|
||||
ResourceManager::setUrlPrefixOverride(prefix, replacement);
|
||||
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride(prefix, replacement);
|
||||
}
|
||||
|
|
|
@ -1668,7 +1668,8 @@ bool Octree::readJSONFromGzippedFile(QString qFileName) {
|
|||
}
|
||||
|
||||
bool Octree::readFromURL(const QString& urlString) {
|
||||
auto request = std::unique_ptr<ResourceRequest>(ResourceManager::createResourceRequest(this, urlString));
|
||||
auto request =
|
||||
std::unique_ptr<ResourceRequest>(DependencyManager::get<ResourceManager>()->createResourceRequest(this, urlString));
|
||||
|
||||
if (!request) {
|
||||
return false;
|
||||
|
|
|
@ -103,7 +103,7 @@ bool Procedural::parseVersion(const QJsonValue& version) {
|
|||
}
|
||||
|
||||
bool Procedural::parseShader(const QUrl& shaderPath) {
|
||||
auto shaderUrl = ResourceManager::normalizeURL(shaderPath);
|
||||
auto shaderUrl = DependencyManager::get<ResourceManager>()->normalizeURL(shaderPath);
|
||||
|
||||
if (!shaderUrl.isValid()) {
|
||||
if (!shaderUrl.isEmpty()) {
|
||||
|
|
|
@ -39,7 +39,7 @@ void DeferredFrameTransform::update(RenderArgs* args) {
|
|||
args->getViewFrustum().evalProjectionMatrix(frameTransformBuffer.projectionMono);
|
||||
|
||||
// Running in stero ?
|
||||
bool isStereo = args->_context->isStereo();
|
||||
bool isStereo = args->isStereo();
|
||||
if (!isStereo) {
|
||||
frameTransformBuffer.projection[0] = frameTransformBuffer.projectionMono;
|
||||
frameTransformBuffer.stereoInfo = glm::vec4(0.0f, (float)args->_viewport.z, 0.0f, 0.0f);
|
||||
|
|
|
@ -406,7 +406,7 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
|
|||
batch.setFramebuffer(blitFbo);
|
||||
|
||||
if (renderArgs->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
if (renderArgs->_context->isStereo()) {
|
||||
if (renderArgs->isStereo()) {
|
||||
gpu::Vec4i srcRectLeft;
|
||||
srcRectLeft.z = width / 2;
|
||||
srcRectLeft.w = height;
|
||||
|
|
|
@ -459,7 +459,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext,
|
|||
auto diffuseVPipeline = _diffusePass.getBlurVPipeline();
|
||||
auto diffuseHPipeline = _diffusePass.getBlurHPipeline();
|
||||
|
||||
_diffusePass.getParameters()->setWidthHeight(curvatureViewport.z, curvatureViewport.w, args->_context->isStereo());
|
||||
_diffusePass.getParameters()->setWidthHeight(curvatureViewport.z, curvatureViewport.w, args->isStereo());
|
||||
glm::ivec2 textureSize(curvatureTexture->getDimensions());
|
||||
_diffusePass.getParameters()->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, curvatureViewport));
|
||||
_diffusePass.getParameters()->setDepthPerspective(args->getViewFrustum().getProjection()[1][1]);
|
||||
|
|
|
@ -99,6 +99,8 @@ namespace render {
|
|||
void pushViewFrustum(const ViewFrustum& viewFrustum) { _viewFrustums.push(viewFrustum); }
|
||||
void popViewFrustum() { _viewFrustums.pop(); }
|
||||
|
||||
bool isStereo() const { return _displayMode != MONO; }
|
||||
|
||||
std::shared_ptr<gpu::Context> _context;
|
||||
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer;
|
||||
std::shared_ptr<render::ShapePipeline> _pipeline;
|
||||
|
|
|
@ -217,7 +217,7 @@ void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::Fra
|
|||
auto blurVPipeline = getBlurVPipeline();
|
||||
auto blurHPipeline = getBlurHPipeline();
|
||||
|
||||
_parameters->setWidthHeight(args->_viewport.z, args->_viewport.w, args->_context->isStereo());
|
||||
_parameters->setWidthHeight(args->_viewport.z, args->_viewport.w, args->isStereo());
|
||||
glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions());
|
||||
_parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, args->_viewport));
|
||||
|
||||
|
@ -330,7 +330,7 @@ void BlurGaussianDepthAware::run(const RenderContextPointer& renderContext, cons
|
|||
|
||||
auto sourceViewport = args->_viewport;
|
||||
|
||||
_parameters->setWidthHeight(sourceViewport.z, sourceViewport.w, args->_context->isStereo());
|
||||
_parameters->setWidthHeight(sourceViewport.z, sourceViewport.w, args->isStereo());
|
||||
glm::ivec2 textureSize(blurringResources.sourceTexture->getDimensions());
|
||||
_parameters->setTexcoordTransform(gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(textureSize, sourceViewport));
|
||||
_parameters->setDepthPerspective(args->getViewFrustum().getProjection()[1][1]);
|
||||
|
|
|
@ -85,7 +85,7 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) {
|
|||
// this function is not in use
|
||||
void FileScriptingInterface::downloadZip(QString path, const QString link) {
|
||||
QUrl url = QUrl(link);
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
connect(request, &ResourceRequest::finished, this, [this, path]{
|
||||
unzipFile(path, ""); // so intellisense isn't mad
|
||||
});
|
||||
|
|
|
@ -9,17 +9,17 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ModelScriptingInterface.h"
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValueIterator>
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <model-networking/MeshFace.h>
|
||||
#include <model-networking/SimpleMeshProxy.h>
|
||||
#include "ScriptEngine.h"
|
||||
#include "ScriptEngineLogging.h"
|
||||
#include "ModelScriptingInterface.h"
|
||||
#include "OBJWriter.h"
|
||||
|
||||
ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
|
||||
_modelScriptEngine = qobject_cast<ScriptEngine*>(parent);
|
||||
_modelScriptEngine = qobject_cast<QScriptEngine*>(parent);
|
||||
|
||||
qScriptRegisterSequenceMetaType<QList<MeshProxy*>>(_modelScriptEngine);
|
||||
qScriptRegisterMetaType(_modelScriptEngine, meshFaceToScriptValue, meshFaceFromScriptValue);
|
||||
|
@ -118,7 +118,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) {
|
|||
(gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL));
|
||||
|
||||
|
||||
MeshProxy* resultProxy = new MeshProxy(result);
|
||||
MeshProxy* resultProxy = new SimpleMeshProxy(result);
|
||||
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshPro
|
|||
model::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
|
||||
[&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
|
||||
[&](uint32_t index){ return index; });
|
||||
MeshProxy* resultProxy = new MeshProxy(result);
|
||||
MeshProxy* resultProxy = new SimpleMeshProxy(result);
|
||||
return meshToScriptValue(_modelScriptEngine, resultProxy);
|
||||
}
|
||||
|
||||
|
@ -188,6 +188,6 @@ QScriptValue ModelScriptingInterface::newMesh(const QVector<glm::vec3>& vertices
|
|||
|
||||
|
||||
|
||||
MeshProxy* meshProxy = new MeshProxy(mesh);
|
||||
MeshProxy* meshProxy = new SimpleMeshProxy(mesh);
|
||||
return meshToScriptValue(_modelScriptEngine, meshProxy);
|
||||
}
|
||||
|
|
|
@ -9,19 +9,13 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_ModelScriptingInterface_h
|
||||
#define hifi_ModelScriptingInterface_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QScriptValue>
|
||||
#include <OBJWriter.h>
|
||||
#include <model/Geometry.h>
|
||||
#include <model-networking/MeshProxy.h>
|
||||
#include <model-networking/MeshFace.h>
|
||||
|
||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||
class ScriptEngine;
|
||||
#include <RegisteredMetaTypes.h>
|
||||
class QScriptEngine;
|
||||
|
||||
class ModelScriptingInterface : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -37,7 +31,7 @@ public:
|
|||
const QVector<MeshFace>& faces);
|
||||
|
||||
private:
|
||||
ScriptEngine* _modelScriptEngine { nullptr };
|
||||
QScriptEngine* _modelScriptEngine { nullptr };
|
||||
};
|
||||
|
||||
#endif // hifi_ModelScriptingInterface_h
|
||||
|
|
|
@ -57,7 +57,7 @@ void ScriptCache::clearATPScriptsFromCache() {
|
|||
}
|
||||
|
||||
void ScriptCache::deleteScript(const QUrl& unnormalizedURL) {
|
||||
QUrl url = ResourceManager::normalizeURL(unnormalizedURL);
|
||||
QUrl url = DependencyManager::get<ResourceManager>()->normalizeURL(unnormalizedURL);
|
||||
Lock lock(_containerLock);
|
||||
if (_scriptCache.contains(url)) {
|
||||
qCDebug(scriptengine) << "Delete script from cache:" << url.toString();
|
||||
|
@ -70,7 +70,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
|
|||
qCDebug(scriptengine) << "ScriptCache::getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
QUrl unnormalizedURL(scriptOrURL);
|
||||
QUrl url = ResourceManager::normalizeURL(unnormalizedURL);
|
||||
QUrl url = DependencyManager::get<ResourceManager>()->normalizeURL(unnormalizedURL);
|
||||
|
||||
// attempt to determine if this is a URL to a script, or if this is actually a script itself (which is valid in the
|
||||
// entityScript use case)
|
||||
|
@ -109,7 +109,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable
|
|||
#ifdef THREAD_DEBUGGING
|
||||
qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]";
|
||||
#endif
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
Q_ASSERT(request);
|
||||
request->setCacheEnabled(!forceDownload);
|
||||
connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); });
|
||||
|
@ -166,7 +166,7 @@ void ScriptCache::scriptContentAvailable(int maxRetries) {
|
|||
qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3")
|
||||
.arg(attempt).arg(maxRetries).arg(url.toString());
|
||||
|
||||
auto request = ResourceManager::createResourceRequest(nullptr, url);
|
||||
auto request = DependencyManager::get<ResourceManager>()->createResourceRequest(nullptr, url);
|
||||
Q_ASSERT(request);
|
||||
|
||||
// We've already made a request, so the cache must be disabled or it wasn't there, so enabling
|
||||
|
|
|
@ -1067,24 +1067,21 @@ void ScriptEngine::run() {
|
|||
// on shutdown and stop... so we want to loop and sleep until we've spent our time in
|
||||
// purgatory, constantly checking to see if our script was asked to end
|
||||
bool processedEvents = false;
|
||||
while (!_isFinished && clock::now() < sleepUntil) {
|
||||
|
||||
{
|
||||
PROFILE_RANGE(script, "processEvents-sleep");
|
||||
QCoreApplication::processEvents(); // before we sleep again, give events a chance to process
|
||||
if (!_isFinished) {
|
||||
PROFILE_RANGE(script, "processEvents-sleep");
|
||||
std::chrono::milliseconds sleepFor =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(sleepUntil - clock::now());
|
||||
if (sleepFor > std::chrono::milliseconds(0)) {
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
|
||||
timer.start(sleepFor.count());
|
||||
loop.exec();
|
||||
} else {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
processedEvents = true;
|
||||
|
||||
// If after processing events, we're past due, exit asap
|
||||
if (clock::now() >= sleepUntil) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We only want to sleep a small amount so that any pending events (like timers or invokeMethod events)
|
||||
// will be able to process quickly.
|
||||
static const int SMALL_SLEEP_AMOUNT = 100;
|
||||
auto smallSleepUntil = clock::now() + static_cast<std::chrono::microseconds>(SMALL_SLEEP_AMOUNT);
|
||||
std::this_thread::sleep_until(smallSleepUntil);
|
||||
}
|
||||
|
||||
PROFILE_RANGE(script, "ScriptMainLoop");
|
||||
|
@ -1765,7 +1762,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
|||
QList<QUrl> urls;
|
||||
|
||||
for (QString includeFile : includeFiles) {
|
||||
QString file = ResourceManager::normalizeURL(includeFile);
|
||||
QString file = DependencyManager::get<ResourceManager>()->normalizeURL(includeFile);
|
||||
QUrl thisURL;
|
||||
bool isStandardLibrary = false;
|
||||
if (file.startsWith("/~/")) {
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
const int IEEE754_MANT_BITS = 23;
|
||||
const int IEEE754_EXPN_BIAS = 127;
|
||||
|
||||
|
@ -66,6 +68,48 @@ static inline float fastExp2f(float x) {
|
|||
return x * xi.f;
|
||||
}
|
||||
|
||||
//
|
||||
// on x86 architecture, assume that SSE2 is present
|
||||
//
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
|
||||
|
||||
#include <xmmintrin.h>
|
||||
// inline sqrtss, without requiring /fp:fast
|
||||
static inline float fastSqrtf(float x) {
|
||||
return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(x)));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline float fastSqrtf(float x) {
|
||||
return sqrtf(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// for -1 <= x <= 1, returns acos(x)
|
||||
// otherwise, returns NaN
|
||||
//
|
||||
// abs |error| < 7e-5, smooth
|
||||
//
|
||||
static inline float fastAcosf(float x) {
|
||||
|
||||
union { float f; int32_t i; } xi = { x };
|
||||
|
||||
int32_t sign = xi.i & 0x80000000;
|
||||
xi.i ^= sign; // fabs(x)
|
||||
|
||||
// compute sqrt(1-x) in parallel
|
||||
float r = fastSqrtf(1.0f - xi.f);
|
||||
|
||||
// polynomial for acos(x)/sqrt(1-x) over x=[0,1]
|
||||
xi.f = ((-0.0198439236f * xi.f + 0.0762021306f) * xi.f + -0.212940971f) * xi.f + 1.57079633f;
|
||||
|
||||
xi.f *= r;
|
||||
return (sign ? PI - xi.f : xi.f);
|
||||
}
|
||||
|
||||
//
|
||||
// Quantize a non-negative gain value to the nearest 0.5dB, and pack to a byte.
|
||||
//
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
|
||||
// Bring the most commonly used GLM types into the default namespace
|
||||
using glm::ivec2;
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QRect>
|
||||
|
@ -17,10 +21,9 @@
|
|||
#include <QtGui/QVector2D>
|
||||
#include <QtGui/QVector3D>
|
||||
#include <QtGui/QQuaternion>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
#include <QtNetwork/QAbstractSocket>
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <QtScript/QScriptValueIterator>
|
||||
|
||||
int vec4MetaTypeId = qRegisterMetaType<glm::vec4>();
|
||||
int vec3MetaTypeId = qRegisterMetaType<glm::vec3>();
|
||||
|
@ -34,6 +37,8 @@ int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
|
|||
int collisionMetaTypeId = qRegisterMetaType<Collision>();
|
||||
int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
|
||||
int socketErrorMetaTypeId = qRegisterMetaType<QAbstractSocket::SocketError>();
|
||||
int voidLambdaType = qRegisterMetaType<std::function<void()>>();
|
||||
int variantLambdaType = qRegisterMetaType<std::function<QVariant()>>();
|
||||
|
||||
void registerMetaTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterMetaType(engine, mat4toScriptValue, mat4FromScriptValue);
|
||||
|
@ -796,3 +801,101 @@ void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF) {
|
|||
qSizeF.setWidth(object.property("width").toVariant().toFloat());
|
||||
qSizeF.setHeight(object.property("height").toVariant().toFloat());
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails() :
|
||||
role(), url(), fps(0.0f), priority(0.0f), loop(false), hold(false),
|
||||
startAutomatically(false), firstFrame(0.0f), lastFrame(0.0f), running(false), currentFrame(0.0f) {
|
||||
}
|
||||
|
||||
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame) :
|
||||
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
|
||||
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
|
||||
running(running), currentFrame(currentFrame) {
|
||||
}
|
||||
|
||||
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& details) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("role", details.role);
|
||||
obj.setProperty("url", details.url.toString());
|
||||
obj.setProperty("fps", details.fps);
|
||||
obj.setProperty("priority", details.priority);
|
||||
obj.setProperty("loop", details.loop);
|
||||
obj.setProperty("hold", details.hold);
|
||||
obj.setProperty("startAutomatically", details.startAutomatically);
|
||||
obj.setProperty("firstFrame", details.firstFrame);
|
||||
obj.setProperty("lastFrame", details.lastFrame);
|
||||
obj.setProperty("running", details.running);
|
||||
obj.setProperty("currentFrame", details.currentFrame);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& details) {
|
||||
// nothing for now...
|
||||
}
|
||||
|
||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
|
||||
return engine->newQObject(in, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
||||
}
|
||||
|
||||
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
|
||||
out = qobject_cast<MeshProxy*>(value.toQObject());
|
||||
}
|
||||
|
||||
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) {
|
||||
// QScriptValueList result;
|
||||
QScriptValue result = engine->newArray();
|
||||
int i = 0;
|
||||
foreach(MeshProxy* const meshProxy, in) {
|
||||
result.setProperty(i++, meshToScriptValue(engine, meshProxy));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) {
|
||||
QScriptValueIterator itr(value);
|
||||
|
||||
qDebug() << "in meshesFromScriptValue, value.length =" << value.property("length").toInt32();
|
||||
|
||||
while (itr.hasNext()) {
|
||||
itr.next();
|
||||
MeshProxy* meshProxy = qscriptvalue_cast<MeshProxyList::value_type>(itr.value());
|
||||
if (meshProxy) {
|
||||
out.append(meshProxy);
|
||||
} else {
|
||||
qDebug() << "null meshProxy";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace) {
|
||||
QScriptValue obj = engine->newObject();
|
||||
obj.setProperty("vertices", qVectorIntToScriptValue(engine, meshFace.vertexIndices));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult) {
|
||||
qVectorIntFromScriptValue(object.property("vertices"), meshFaceResult.vertexIndices);
|
||||
}
|
||||
|
||||
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector) {
|
||||
QScriptValue array = engine->newArray();
|
||||
for (int i = 0; i < vector.size(); i++) {
|
||||
array.setProperty(i, meshFaceToScriptValue(engine, vector.at(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result) {
|
||||
int length = array.property("length").toInteger();
|
||||
result.clear();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
MeshFace meshFace = MeshFace();
|
||||
meshFaceFromScriptValue(array.property(i), meshFace);
|
||||
result << meshFace;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
@ -33,6 +34,8 @@ Q_DECLARE_METATYPE(xColor)
|
|||
Q_DECLARE_METATYPE(QVector<glm::vec3>)
|
||||
Q_DECLARE_METATYPE(QVector<float>)
|
||||
Q_DECLARE_METATYPE(AACube)
|
||||
Q_DECLARE_METATYPE(std::function<void()>);
|
||||
Q_DECLARE_METATYPE(std::function<QVariant()>);
|
||||
|
||||
void registerMetaTypes(QScriptEngine* engine);
|
||||
|
||||
|
@ -167,4 +170,73 @@ void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid);
|
|||
QScriptValue qSizeFToScriptValue(QScriptEngine* engine, const QSizeF& qSizeF);
|
||||
void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF);
|
||||
|
||||
class AnimationDetails {
|
||||
public:
|
||||
AnimationDetails();
|
||||
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
|
||||
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame);
|
||||
|
||||
QString role;
|
||||
QUrl url;
|
||||
float fps;
|
||||
float priority;
|
||||
bool loop;
|
||||
bool hold;
|
||||
bool startAutomatically;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
bool running;
|
||||
float currentFrame;
|
||||
};
|
||||
Q_DECLARE_METATYPE(AnimationDetails);
|
||||
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);
|
||||
void animationDetailsFromScriptValue(const QScriptValue& object, AnimationDetails& event);
|
||||
|
||||
namespace model {
|
||||
class Mesh;
|
||||
}
|
||||
|
||||
using MeshPointer = std::shared_ptr<model::Mesh>;
|
||||
|
||||
|
||||
class MeshProxy : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
virtual MeshPointer getMeshPointer() const = 0;
|
||||
Q_INVOKABLE virtual int getNumVertices() const = 0;
|
||||
Q_INVOKABLE virtual glm::vec3 getPos3(int index) const = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MeshProxy*);
|
||||
|
||||
class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
|
||||
Q_DECLARE_METATYPE(MeshProxyList);
|
||||
|
||||
|
||||
QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
|
||||
void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out);
|
||||
|
||||
QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in);
|
||||
void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out);
|
||||
|
||||
class MeshFace {
|
||||
|
||||
public:
|
||||
MeshFace() {}
|
||||
~MeshFace() {}
|
||||
|
||||
QVector<uint32_t> vertexIndices;
|
||||
// TODO -- material...
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(MeshFace)
|
||||
Q_DECLARE_METATYPE(QVector<MeshFace>)
|
||||
|
||||
QScriptValue meshFaceToScriptValue(QScriptEngine* engine, const MeshFace &meshFace);
|
||||
void meshFaceFromScriptValue(const QScriptValue &object, MeshFace& meshFaceResult);
|
||||
QScriptValue qVectorMeshFaceToScriptValue(QScriptEngine* engine, const QVector<MeshFace>& vector);
|
||||
void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector<MeshFace>& result);
|
||||
|
||||
|
||||
#endif // hifi_RegisteredMetaTypes_h
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
|
||||
#include "AnimationCache.h"
|
||||
#include "AnimationLoop.h"
|
||||
|
||||
#include "../../NumericalConstants.h"
|
||||
#include "../../SharedUtil.h"
|
||||
#include "../../GLMHelpers.h"
|
||||
#include "../../RegisteredMetaTypes.h"
|
||||
|
||||
const float AnimationLoop::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
|
||||
|
||||
AnimationLoop::AnimationLoop() :
|
||||
|
@ -62,7 +64,7 @@ AnimationLoop::AnimationLoop(float fps, bool loop, bool hold, bool startAutomati
|
|||
{
|
||||
}
|
||||
|
||||
void AnimationLoop::simulateAtTime(quint64 now) {
|
||||
void AnimationLoop::simulateAtTime(uint64_t now) {
|
||||
float deltaTime = (float)(now - _lastSimulated) / (float)USECS_PER_SECOND;
|
||||
_lastSimulated = now;
|
||||
simulate(deltaTime);
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
class AnimationDetails;
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class AnimationLoop {
|
||||
public:
|
||||
static const float MAXIMUM_POSSIBLE_FRAME;
|
||||
|
@ -58,7 +61,7 @@ public:
|
|||
void stop() { setRunning(false); }
|
||||
void simulate(float deltaTime); /// call this with deltaTime if you as the caller are managing the delta time between calls
|
||||
|
||||
void simulateAtTime(quint64 now); /// call this with "now" if you want the animationLoop to handle delta times
|
||||
void simulateAtTime(uint64_t now); /// call this with "now" if you want the animationLoop to handle delta times
|
||||
|
||||
private:
|
||||
float _fps;
|
||||
|
@ -71,7 +74,7 @@ private:
|
|||
float _currentFrame;
|
||||
float _maxFrameIndexHint;
|
||||
bool _resetOnRunning;
|
||||
quint64 _lastSimulated;
|
||||
uint64_t _lastSimulated;
|
||||
};
|
||||
|
||||
#endif // hifi_AnimationLoop_h
|
|
@ -886,12 +886,6 @@ QQmlContext* OffscreenQmlSurface::getSurfaceContext() {
|
|||
return _qmlContext;
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(std::function<void()>);
|
||||
auto VoidLambdaType = qRegisterMetaType<std::function<void()>>();
|
||||
Q_DECLARE_METATYPE(std::function<QVariant()>);
|
||||
auto VariantLambdaType = qRegisterMetaType<std::function<QVariant()>>();
|
||||
|
||||
|
||||
void OffscreenQmlSurface::executeOnUiThread(std::function<void()> function, bool blocking ) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "executeOnUiThread", blocking ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
|
||||
|
|
|
@ -14,96 +14,77 @@
|
|||
|
||||
(function () { // BEGIN LOCAL_SCOPE
|
||||
|
||||
//
|
||||
// FUNCTION VAR DECLARATIONS
|
||||
//
|
||||
var sendToQml, addOrRemoveButton, onTabletScreenChanged, fromQml,
|
||||
onTabletButtonClicked, wireEventBridge, startup, shutdown, registerButtonMappings;
|
||||
|
||||
//
|
||||
// Function Name: inFrontOf()
|
||||
//
|
||||
// Description:
|
||||
// Spectator camera utility functions and variables.
|
||||
//
|
||||
// -Returns the position in front of the given "position" argument, where the forward vector is based off
|
||||
// the "orientation" argument and the amount in front is based off the "distance" argument.
|
||||
function inFrontOf(distance, position, orientation) {
|
||||
return Vec3.sum(position || MyAvatar.position,
|
||||
Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation)));
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: updateRenderFromCamera()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// spectatorFrameRenderConfig: The render configuration of the spectator camera
|
||||
// render job. Controls size.
|
||||
// beginSpectatorFrameRenderConfig: The render configuration of the spectator camera
|
||||
// render job. Controls position and orientation.
|
||||
// viewFinderOverlay: The in-world overlay that displays the spectator camera's view.
|
||||
// camera: The in-world entity that corresponds to the spectator camera.
|
||||
// cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays
|
||||
// drift with respect to their parent
|
||||
// lastCameraPosition: Holds the last known camera position
|
||||
// lastCameraRotation: Holds the last known camera rotation
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// The update function for the spectator camera. Modifies the camera's position
|
||||
// and orientation.
|
||||
// -The update function for the spectator camera. Modifies the camera's position
|
||||
// and orientation.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -spectatorFrameRenderConfig: The render configuration of the spectator camera
|
||||
// render job. It controls the rendered texture size of the spectator camera.
|
||||
// -beginSpectatorFrameRenderConfig: The render configuration of the spectator camera
|
||||
// render job. It controls the orientation and position of the secondary camera whose viewport is rendered to
|
||||
// the texture.
|
||||
// -viewFinderOverlay: The in-world overlay that displays the spectator camera's view.
|
||||
// -camera: The in-world entity that corresponds to the spectator camera.
|
||||
// -cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays
|
||||
// drift with respect to their parent.
|
||||
var spectatorFrameRenderConfig = Render.getConfig("SecondaryCameraFrame");
|
||||
var beginSpectatorFrameRenderConfig = Render.getConfig("BeginSecondaryCamera");
|
||||
var viewFinderOverlay = false;
|
||||
var camera = false;
|
||||
var cameraIsDynamic = false;
|
||||
var lastCameraPosition = false;
|
||||
var lastCameraRotation = false;
|
||||
function updateRenderFromCamera() {
|
||||
var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']);
|
||||
if (JSON.stringify(lastCameraRotation) !== JSON.stringify(cameraData.rotation)) {
|
||||
lastCameraRotation = cameraData.rotation;
|
||||
beginSpectatorFrameRenderConfig.orientation = lastCameraRotation;
|
||||
}
|
||||
if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) {
|
||||
lastCameraPosition = cameraData.position;
|
||||
beginSpectatorFrameRenderConfig.position = Vec3.sum(inFrontOf(0.17, lastCameraPosition, lastCameraRotation), {x: 0, y: 0.02, z: 0});
|
||||
}
|
||||
beginSpectatorFrameRenderConfig.orientation = cameraData.rotation;
|
||||
beginSpectatorFrameRenderConfig.position = cameraData.position;
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: spectatorCameraOn()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// isUpdateRenderWired: Bool storing whether or not the camera's update
|
||||
// function is wired.
|
||||
// vFoV: The vertical field of view of the spectator camera
|
||||
// nearClipPlaneDistance: The near clip plane distance of the spectator camera (aka "camera")
|
||||
// farClipPlaneDistance: The far clip plane distance of the spectator camera
|
||||
// cameraRotation: The rotation of the spectator camera
|
||||
// cameraPosition: The position of the spectator camera
|
||||
// glassPaneWidth: The width of the glass pane above the spectator camera that holds the viewFinderOverlay
|
||||
// viewFinderOverlayDim: The x, y, and z dimensions of the viewFinderOverlay
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// Call this function to set up the spectator camera and
|
||||
// spawn the camera entity.
|
||||
// -Call this function to set up the spectator camera and
|
||||
// spawn the camera entity.
|
||||
//
|
||||
var isUpdateRenderWired = false;
|
||||
// Relevant Variables:
|
||||
// -vFoV: The vertical field of view of the spectator camera.
|
||||
// -nearClipPlaneDistance: The near clip plane distance of the spectator camera (aka "camera").
|
||||
// -farClipPlaneDistance: The far clip plane distance of the spectator camera.
|
||||
// -cameraRotation: The rotation of the spectator camera.
|
||||
// -cameraPosition: The position of the spectator camera.
|
||||
// -glassPaneWidth: The width of the glass pane above the spectator camera that holds the viewFinderOverlay.
|
||||
// -viewFinderOverlayDim: The x, y, and z dimensions of the viewFinderOverlay.
|
||||
// -camera: The camera model which is grabbable.
|
||||
// -viewFinderOverlay: The preview of what the spectator camera is viewing, placed inside the glass pane.
|
||||
// -cameraUpdateInterval: Used when setting Script.setInterval()
|
||||
// -CAMERA_UPDATE_INTERVAL_MS: Defines the time between calls to updateRenderFromCamera()
|
||||
var vFoV = 45.0;
|
||||
var nearClipPlaneDistance = 0.1;
|
||||
var farClipPlaneDistance = 100.0;
|
||||
var cameraRotation;
|
||||
var cameraPosition;
|
||||
//The negative y dimension for viewFinderOverlay is necessary for now due to the way Image3DOverlay
|
||||
// draws textures, but should be looked into at some point. Also the z dimension shouldn't affect
|
||||
// the overlay since it is an Image3DOverlay so it is set to 0
|
||||
var glassPaneWidth = 0.16;
|
||||
// The negative y dimension for viewFinderOverlay is necessary for now due to the way Image3DOverlay
|
||||
// draws textures, but should be looked into at some point. Also the z dimension shouldn't affect
|
||||
// the overlay since it is an Image3DOverlay so it is set to 0.
|
||||
var viewFinderOverlayDim = { x: glassPaneWidth, y: -glassPaneWidth, z: 0 };
|
||||
var cameraUpdateInterval;
|
||||
var CAMERA_UPDATE_INTERVAL_MS = 11; // Result of (1000 (ms/s)) / (90 (hz)) rounded down
|
||||
function spectatorCameraOn() {
|
||||
// Sets the special texture size based on the window it is displayed in, which doesn't include the menu bar
|
||||
spectatorFrameRenderConfig.resetSizeSpectatorCamera(Window.innerWidth, Window.innerHeight);
|
||||
|
@ -112,51 +93,39 @@
|
|||
beginSpectatorFrameRenderConfig.nearClipPlaneDistance = nearClipPlaneDistance;
|
||||
beginSpectatorFrameRenderConfig.farClipPlaneDistance = farClipPlaneDistance;
|
||||
cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(1, Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 }));
|
||||
Script.update.connect(updateRenderFromCamera);
|
||||
isUpdateRenderWired = true;
|
||||
cameraUpdateInterval = Script.setInterval(updateRenderFromCamera, 11); // Update every 11ms (90.9hz)
|
||||
camera = Entities.addEntity({
|
||||
"angularDamping": 0.98000001907348633,
|
||||
"collisionsWillMove": 0,
|
||||
"damping": 0.98000001907348633,
|
||||
"angularDamping": 1,
|
||||
"damping": 1,
|
||||
"collidesWith": "static,dynamic,kinematic,",
|
||||
"collisionMask": 7,
|
||||
"dynamic": cameraIsDynamic,
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/spectator-camera.fbx?1",
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/spectator-camera.fbx?7",
|
||||
"registrationPoint": {
|
||||
"x": 0.53,
|
||||
"y": 0.545,
|
||||
"z": 0.16
|
||||
},
|
||||
"rotation": cameraRotation,
|
||||
"position": cameraPosition,
|
||||
"shapeType": "simple-compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true}}"
|
||||
}, true);
|
||||
// This image3d overlay acts as the camera's preview screen.
|
||||
viewFinderOverlay = Overlays.addOverlay("image3d", {
|
||||
url: "resource://spectatorCameraFrame",
|
||||
emissive: true,
|
||||
parentID: camera,
|
||||
alpha: 1,
|
||||
rotation: cameraRotation,
|
||||
localPosition: { x: 0.007, y: 0.15, z: -0.005 },
|
||||
dimensions: viewFinderOverlayDim
|
||||
});
|
||||
updateOverlay();
|
||||
setDisplay(monitorShowsCameraView);
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: spectatorCameraOff()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// Call this function to shut down the spectator camera and
|
||||
// destroy the camera entity.
|
||||
//
|
||||
// -Call this function to shut down the spectator camera and
|
||||
// destroy the camera entity.
|
||||
function spectatorCameraOff() {
|
||||
spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = false;
|
||||
if (isUpdateRenderWired) {
|
||||
Script.update.disconnect(updateRenderFromCamera);
|
||||
isUpdateRenderWired = false;
|
||||
if (cameraUpdateInterval) {
|
||||
Script.clearInterval(cameraUpdateInterval);
|
||||
cameraUpdateInterval = false;
|
||||
}
|
||||
if (camera) {
|
||||
Entities.deleteEntity(camera);
|
||||
|
@ -169,27 +138,25 @@
|
|||
setDisplay(monitorShowsCameraView);
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: addOrRemoveButton()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// button: The tablet button.
|
||||
// buttonName: The name of the button.
|
||||
// tablet: The tablet instance to be modified.
|
||||
// showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode
|
||||
//
|
||||
// Arguments:
|
||||
// isShuttingDown: Set to "true" if you're calling this function upon script shutdown
|
||||
// isHMDMode: "true" if user is in HMD; false otherwise
|
||||
//
|
||||
// Description:
|
||||
// Used to add or remove the "SPECTATOR" app button from the HUD/tablet
|
||||
// -Used to add or remove the "SPECTATOR" app button from the HUD/tablet. Set the "isShuttingDown" argument
|
||||
// to true if you're calling this function upon script shutdown. Set the "isHMDmode" to true if the user is
|
||||
// in HMD; otherwise set to false.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -button: The tablet button.
|
||||
// -buttonName: The name of the button.
|
||||
// -showInDesktop: Set to "true" to show the "SPECTATOR" app in desktop mode.
|
||||
var button = false;
|
||||
var buttonName = "SPECTATOR";
|
||||
var tablet = null;
|
||||
var showSpectatorInDesktop = true;
|
||||
function addOrRemoveButton(isShuttingDown, isHMDMode) {
|
||||
if (!tablet) {
|
||||
print("Warning in addOrRemoveButton(): 'tablet' undefined!");
|
||||
return;
|
||||
}
|
||||
if (!button) {
|
||||
if ((isHMDMode || showSpectatorInDesktop) && !isShuttingDown) {
|
||||
button = tablet.addButton({
|
||||
|
@ -198,7 +165,7 @@
|
|||
button.clicked.connect(onTabletButtonClicked);
|
||||
}
|
||||
} else if (button) {
|
||||
if ((!showSpectatorInDesktop || isShuttingDown) && !isHMDMode) {
|
||||
if (!showSpectatorInDesktop || isShuttingDown) {
|
||||
button.clicked.disconnect(onTabletButtonClicked);
|
||||
tablet.removeButton(button);
|
||||
button = false;
|
||||
|
@ -208,18 +175,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: startup()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// startup() will be called when the script is loaded.
|
||||
// -startup() will be called when the script is loaded.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -tablet: The tablet instance to be modified.
|
||||
var tablet = null;
|
||||
function startup() {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
addOrRemoveButton(false, HMD.active);
|
||||
|
@ -233,20 +196,20 @@
|
|||
registerButtonMappings();
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: wireEventBridge()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// hasEventBridge: true/false depending on whether we've already connected the event bridge
|
||||
//
|
||||
// Arguments:
|
||||
// on: Enable or disable the event bridge
|
||||
//
|
||||
// Description:
|
||||
// Used to connect/disconnect the script's response to the tablet's "fromQml" signal.
|
||||
// -Used to connect/disconnect the script's response to the tablet's "fromQml" signal. Set the "on" argument to enable or
|
||||
// disable to event bridge.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -hasEventBridge: true/false depending on whether we've already connected the event bridge.
|
||||
var hasEventBridge = false;
|
||||
function wireEventBridge(on) {
|
||||
if (!tablet) {
|
||||
print("Warning in wireEventBridge(): 'tablet' undefined!");
|
||||
return;
|
||||
}
|
||||
if (on) {
|
||||
if (!hasEventBridge) {
|
||||
tablet.fromQml.connect(fromQml);
|
||||
|
@ -260,9 +223,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Function Name: setDisplay()
|
||||
//
|
||||
// Description:
|
||||
// -There are two bool variables that determine what the "url" argument to "setDisplayTexture(url)" should be:
|
||||
// Camera on/off switch, and the "Monitor Shows" on/off switch.
|
||||
// This results in four possible cases for the argument. Those four cases are:
|
||||
// 1. Camera is off; "Monitor Shows" is "HMD Preview": "url" is ""
|
||||
// 2. Camera is off; "Monitor Shows" is "Camera View": "url" is ""
|
||||
// 3. Camera is on; "Monitor Shows" is "HMD Preview": "url" is ""
|
||||
// 4. Camera is on; "Monitor Shows" is "Camera View": "url" is "resource://spectatorCameraFrame"
|
||||
function setDisplay(showCameraView) {
|
||||
// It would be fancy if (showCameraView && !isUpdateRenderWired) would show instructions, but that's out of scope for now.
|
||||
var url = (showCameraView && isUpdateRenderWired) ? "resource://spectatorCameraFrame" : "";
|
||||
// It would be fancy if the app would show instructions when (url === ""), but that's out of scope for now.
|
||||
var url = (camera && showCameraView && cameraUpdateInterval) ? "resource://spectatorCameraFrame" : "";
|
||||
Window.setDisplayTexture(url);
|
||||
}
|
||||
const MONITOR_SHOWS_CAMERA_VIEW_DEFAULT = false;
|
||||
|
@ -284,23 +257,35 @@
|
|||
setMonitorShowsCameraViewAndSendToQml(!monitorShowsCameraView);
|
||||
}
|
||||
}
|
||||
function updateOverlay() {
|
||||
// The only way I found to update the viewFinderOverlay without turning the spectator camera on and off is to delete and recreate the
|
||||
// overlay, which is inefficient but resizing the window shouldn't be performed often
|
||||
if (viewFinderOverlay) {
|
||||
Overlays.deleteOverlay(viewFinderOverlay);
|
||||
}
|
||||
viewFinderOverlay = Overlays.addOverlay("image3d", {
|
||||
url: "resource://spectatorCameraFrame",
|
||||
emissive: true,
|
||||
parentID: camera,
|
||||
alpha: 1,
|
||||
localRotation: { w: 1, x: 0, y: 0, z: 0 },
|
||||
localPosition: { x: 0, y: 0.13, z: 0.126 },
|
||||
dimensions: viewFinderOverlayDim
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: resizeViewFinderOverlay()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// glassPaneRatio: The aspect ratio of the glass pane, currently set as a 16:9 aspect ratio (change if model changes)
|
||||
// verticalScale: The amount the viewFinderOverlay should be scaled if the window size is vertical
|
||||
// squareScale: The amount the viewFinderOverlay should be scaled if the window size is not vertical but is more square than the
|
||||
// glass pane's aspect ratio
|
||||
//
|
||||
// Arguments:
|
||||
// geometryChanged: The signal argument that gives information on how the window changed, including x, y, width, and height
|
||||
//
|
||||
// Description:
|
||||
// A function called when the window is moved/resized, which changes the viewFinderOverlay's texture and dimensions to be
|
||||
// appropriately altered to fit inside the glass pane while not distorting the texture
|
||||
// -A function called when the window is moved/resized, which changes the viewFinderOverlay's texture and dimensions to be
|
||||
// appropriately altered to fit inside the glass pane while not distorting the texture. The "geometryChanged" argument gives information
|
||||
// on how the window changed, including x, y, width, and height.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -glassPaneRatio: The aspect ratio of the glass pane, currently set as a 16:9 aspect ratio (change if model changes).
|
||||
// -verticalScale: The amount the viewFinderOverlay should be scaled if the window size is vertical.
|
||||
// -squareScale: The amount the viewFinderOverlay should be scaled if the window size is not vertical but is more square than the
|
||||
// glass pane's aspect ratio.
|
||||
function resizeViewFinderOverlay(geometryChanged) {
|
||||
var glassPaneRatio = 16 / 9;
|
||||
var verticalScale = 1 / glassPaneRatio;
|
||||
|
@ -313,19 +298,7 @@
|
|||
} else { //horizontal window size
|
||||
viewFinderOverlayDim = { x: glassPaneWidth, y: -glassPaneWidth, z: 0 };
|
||||
}
|
||||
|
||||
// The only way I found to update the viewFinderOverlay without turning the spectator camera on and off is to delete and recreate the
|
||||
// overlay, which is inefficient but resizing the window shouldn't be performed often
|
||||
Overlays.deleteOverlay(viewFinderOverlay);
|
||||
viewFinderOverlay = Overlays.addOverlay("image3d", {
|
||||
url: "resource://spectatorCameraFrame",
|
||||
emissive: true,
|
||||
parentID: camera,
|
||||
alpha: 1,
|
||||
rotation: cameraRotation,
|
||||
localPosition: { x: 0.007, y: 0.15, z: -0.005 },
|
||||
dimensions: viewFinderOverlayDim
|
||||
});
|
||||
updateOverlay();
|
||||
spectatorFrameRenderConfig.resetSizeSpectatorCamera(geometryChanged.width, geometryChanged.height);
|
||||
setDisplay(monitorShowsCameraView);
|
||||
}
|
||||
|
@ -348,20 +321,15 @@
|
|||
Settings.setValue('spectatorCamera/switchViewFromController', setting);
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: registerButtonMappings()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// controllerMappingName: The name of the controller mapping
|
||||
// controllerMapping: The controller mapping itself
|
||||
// controllerType: "OculusTouch", "Vive", "Other"
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// Updates controller button mappings for Spectator Camera.
|
||||
// -Updates controller button mappings for Spectator Camera.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -controllerMappingName: The name of the controller mapping.
|
||||
// -controllerMapping: The controller mapping itself.
|
||||
// -controllerType: "OculusTouch", "Vive", "Other".
|
||||
var controllerMappingName;
|
||||
var controllerMapping;
|
||||
var controllerType = "Other";
|
||||
|
@ -394,30 +362,26 @@
|
|||
sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType });
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: onTabletButtonClicked()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app
|
||||
// shouldActivateButton: true/false depending on whether we should show the button as white or gray the
|
||||
// next time we edit the button's properties
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// Fired when the Spectator Camera app button is pressed.
|
||||
// -Fired when the Spectator Camera app button is pressed.
|
||||
//
|
||||
// Relevant Variables:
|
||||
// -SPECTATOR_CAMERA_QML_SOURCE: The path to the SpectatorCamera QML
|
||||
// -onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app.
|
||||
var SPECTATOR_CAMERA_QML_SOURCE = "../SpectatorCamera.qml";
|
||||
var onSpectatorCameraScreen = false;
|
||||
var shouldActivateButton = false;
|
||||
function onTabletButtonClicked() {
|
||||
if (!tablet) {
|
||||
print("Warning in onTabletButtonClicked(): 'tablet' undefined!");
|
||||
return;
|
||||
}
|
||||
if (onSpectatorCameraScreen) {
|
||||
// for toolbar-mode: go back to home screen, this will close the window.
|
||||
tablet.gotoHomeScreen();
|
||||
} else {
|
||||
shouldActivateButton = true;
|
||||
tablet.loadQMLSource("../SpectatorCamera.qml");
|
||||
onSpectatorCameraScreen = true;
|
||||
tablet.loadQMLSource(SPECTATOR_CAMERA_QML_SOURCE);
|
||||
sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera });
|
||||
sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView });
|
||||
sendToQml({ method: 'updateControllerMappingCheckbox', setting: switchViewFromController, controller: controllerType });
|
||||
|
@ -425,59 +389,34 @@
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: onTabletScreenChanged()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// type: "Home", "Web", "Menu", "QML", "Closed"
|
||||
// url: Only valid for Web and QML.
|
||||
//
|
||||
// Description:
|
||||
// Called when the TabletScriptingInterface::screenChanged() signal is emitted.
|
||||
//
|
||||
// -Called when the TabletScriptingInterface::screenChanged() signal is emitted. The "type" argument can be either the string
|
||||
// value of "Home", "Web", "Menu", "QML", or "Closed". The "url" argument is only valid for Web and QML.
|
||||
function onTabletScreenChanged(type, url) {
|
||||
wireEventBridge(shouldActivateButton);
|
||||
onSpectatorCameraScreen = (type === "QML" && url === SPECTATOR_CAMERA_QML_SOURCE);
|
||||
wireEventBridge(onSpectatorCameraScreen);
|
||||
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
||||
if (button) {
|
||||
button.editProperties({ isActive: shouldActivateButton });
|
||||
button.editProperties({ isActive: onSpectatorCameraScreen });
|
||||
}
|
||||
shouldActivateButton = false;
|
||||
onSpectatorCameraScreen = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: sendToQml()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// message: The message to send to the SpectatorCamera QML.
|
||||
// Messages are in format "{method, params}", like json-rpc. See also fromQml().
|
||||
//
|
||||
// Description:
|
||||
// Use this function to send a message to the QML (i.e. to change appearances).
|
||||
//
|
||||
// -Use this function to send a message to the QML (i.e. to change appearances). The "message" argument is what is sent to
|
||||
// SpectatorCamera QML in the format "{method, params}", like json-rpc. See also fromQml().
|
||||
function sendToQml(message) {
|
||||
tablet.sendToQml(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: fromQml()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// message: The message sent from the SpectatorCamera QML.
|
||||
// Messages are in format "{method, params}", like json-rpc. See also sendToQml().
|
||||
//
|
||||
// Description:
|
||||
// Called when a message is received from SpectatorCamera.qml.
|
||||
//
|
||||
// -Called when a message is received from SpectatorCamera.qml. The "message" argument is what is sent from the SpectatorCamera QML
|
||||
// in the format "{method, params}", like json-rpc. See also sendToQml().
|
||||
function fromQml(message) {
|
||||
switch (message.method) {
|
||||
case 'spectatorCameraOn':
|
||||
|
@ -497,18 +436,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: onHMDChanged()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// isHMDMode: "true" if HMD is on; "false" otherwise
|
||||
//
|
||||
// Description:
|
||||
// Called from C++ when HMD mode is changed
|
||||
//
|
||||
// -Called from C++ when HMD mode is changed. The argument "isHMDMode" should be true if HMD is on; false otherwise.
|
||||
function onHMDChanged(isHMDMode) {
|
||||
setDisplay(monitorShowsCameraView);
|
||||
addOrRemoveButton(false, isHMDMode);
|
||||
|
@ -517,32 +448,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Function Name: shutdown()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// None
|
||||
//
|
||||
// Description:
|
||||
// shutdown() will be called when the script ends (i.e. is stopped).
|
||||
//
|
||||
// -shutdown() will be called when the script ends (i.e. is stopped).
|
||||
function shutdown() {
|
||||
spectatorCameraOff();
|
||||
Window.domainChanged.disconnect(spectatorCameraOff);
|
||||
Window.geometryChanged.disconnect(resizeViewFinderOverlay);
|
||||
addOrRemoveButton(true, HMD.active);
|
||||
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||
if (tablet) {
|
||||
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||
if (onSpectatorCameraScreen) {
|
||||
tablet.gotoHomeScreen();
|
||||
}
|
||||
}
|
||||
HMD.displayModeChanged.disconnect(onHMDChanged);
|
||||
Controller.keyPressEvent.disconnect(keyPressEvent);
|
||||
controllerMapping.disable();
|
||||
}
|
||||
|
||||
//
|
||||
// These functions will be called when the script is loaded.
|
||||
//
|
||||
startup();
|
||||
Script.scriptEnding.connect(shutdown);
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <gpu/gl/GLTexture.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include <AnimationCache.h>
|
||||
#include <SimpleEntitySimulation.h>
|
||||
#include <EntityDynamicInterface.h>
|
||||
#include <EntityDynamicFactoryInterface.h>
|
||||
|
@ -519,7 +520,7 @@ public:
|
|||
_entitySimulation = simpleSimulation;
|
||||
}
|
||||
|
||||
ResourceManager::init();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
|
||||
setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint);
|
||||
_size = QSize(800, 600);
|
||||
|
@ -574,7 +575,7 @@ public:
|
|||
DependencyManager::destroy<ModelCache>();
|
||||
DependencyManager::destroy<GeometryCache>();
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
ResourceManager::cleanup();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
}
|
||||
|
@ -997,7 +998,7 @@ private:
|
|||
QFileInfo atpPathInfo(atpPath);
|
||||
if (atpPathInfo.exists()) {
|
||||
QString atpUrl = QUrl::fromLocalFile(atpPath).toString();
|
||||
ResourceManager::setUrlPrefixOverride("atp:/", atpUrl + "/");
|
||||
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", atpUrl + "/");
|
||||
}
|
||||
_octree->clear();
|
||||
_octree->getTree()->readFromURL(fileName);
|
||||
|
|
|
@ -329,7 +329,7 @@ public:
|
|||
installEventFilter(this);
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(2);
|
||||
QThread::currentThread()->setPriority(QThread::HighestPriority);
|
||||
ResourceManager::init();
|
||||
DependencyManager::set<ResourceManager>();
|
||||
setFlags(Qt::MSWindowsOwnDC | Qt::Window | Qt::Dialog | Qt::WindowMinMaxButtonsHint | Qt::WindowTitleHint);
|
||||
_size = QSize(800, 600);
|
||||
_renderThread._size = _size;
|
||||
|
@ -369,7 +369,7 @@ public:
|
|||
DependencyManager::destroy<TextureCache>();
|
||||
DependencyManager::destroy<ModelCache>();
|
||||
DependencyManager::destroy<GeometryCache>();
|
||||
ResourceManager::cleanup();
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
27
tools/avatar-json-to-dot.js
Normal file
27
tools/avatar-json-to-dot.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
// usage:
|
||||
// node avatar-json-to-dot.js /path/to/avatar-animaton.json > out.dot
|
||||
//
|
||||
// Then if you have graphviz installed you can run the following command to generate a png.
|
||||
// dot -Tpng out.dot > out.png
|
||||
|
||||
var fs = require('fs');
|
||||
var filename = process.argv[2];
|
||||
|
||||
function dumpNodes(node) {
|
||||
node.children.forEach(function (child) {
|
||||
console.log(' ' + node.id + ' -> ' + child.id + ';');
|
||||
dumpNodes(child);
|
||||
});
|
||||
}
|
||||
|
||||
fs.readFile(filename, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
console.log('error opening ' + filename + ', err = ' + err);
|
||||
} else {
|
||||
var graph = JSON.parse(data);
|
||||
console.log('digraph graphname {');
|
||||
console.log(' rankdir = "LR";');
|
||||
dumpNodes(graph.root);
|
||||
console.log('}');
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue