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

This commit is contained in:
Sam Gateau 2017-06-29 10:29:05 +02:00
commit b766c256db
75 changed files with 703 additions and 550 deletions

View file

@ -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>();

View file

@ -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;
}
}

View file

@ -31,7 +31,7 @@ EntityServer::EntityServer(ReceivedMessage& message) :
OctreeServer(message),
_entitySimulation(NULL)
{
ResourceManager::init();
DependencyManager::set<ResourceManager>();
DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<ScriptCache>();

View file

@ -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>();

View file

@ -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": []
},

View file

@ -582,6 +582,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<LocationBookmarks>();
DependencyManager::set<Snapshot>();
DependencyManager::set<CloseEventSender>();
DependencyManager::set<ResourceManager>();
return previousSessionCrashed;
}
@ -776,7 +777,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();
@ -915,11 +915,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);
@ -1186,7 +1181,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 {
@ -1880,7 +1881,7 @@ Application::~Application() {
DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<OctreeStatsProvider>();
ResourceManager::cleanup();
DependencyManager::get<ResourceManager>()->cleanup();
// remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>();
@ -4094,7 +4095,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) {
@ -5937,7 +5941,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();
}

View file

@ -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)

View file

@ -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";

View file

@ -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);

View file

@ -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

View 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;
}

View 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

View file

@ -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

View file

@ -44,6 +44,7 @@ public:
StateMachine,
Manipulator,
InverseKinematics,
DefaultPose,
NumTypes
};
using Pointer = std::shared_ptr<AnimNode>;

View file

@ -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));

View file

@ -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;

View file

@ -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;

View file

@ -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...
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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 {

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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; }));

View file

@ -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:

View file

@ -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)

View file

@ -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"

View file

@ -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"

View file

@ -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);

View file

@ -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([&] {

View file

@ -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;

View file

@ -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>();

View file

@ -17,6 +17,7 @@
#include <ByteCountCoding.h>
#include <GLMHelpers.h>
#include <RegisteredMetaTypes.h>
#include <Extents.h>
#include "EntitiesLogging.h"
#include "EntityItem.h"

View file

@ -15,6 +15,7 @@
#include <stdint.h>
#include <glm/glm.hpp>
#include <glm/gtx/component_wise.hpp>
#include <QtScript/QScriptEngine>
#include <QtCore/QObject>

View file

@ -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);
}
}
}
});
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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() {

View file

@ -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"

View file

@ -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 &&

View file

@ -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

View file

@ -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());

View file

@ -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;
}
}

View file

@ -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

View file

@ -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";
}
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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();

View 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

View file

@ -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);

View file

@ -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();

View file

@ -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>();

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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()) {

View file

@ -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
});

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -1762,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("/~/")) {

View file

@ -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.
//

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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:

View 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('}');
}
});