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

This commit is contained in:
Sam Gateau 2015-07-14 18:38:21 -07:00
commit 98a3141e11
50 changed files with 308 additions and 899 deletions

View file

@ -53,7 +53,7 @@ AnimationDetails ScriptableAvatar::getAnimationDetails() {
void ScriptableAvatar::update(float deltatime) {
// Run animation
if (_animation != NULL && _animation->isValid() && _animation->getFrames().size() > 0) {
if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0) {
QStringList modelJoints = getJointNames();
QStringList animationJoints = _animation->getJointNames();

View file

@ -175,10 +175,12 @@ function positionStick(stickOrientation) {
inHand = false;
Entities.updateAction(stickID, actionID, {
relativePosition: offset,
relativeRotation: stickOrientation
relativeRotation: stickOrientation,
hand: "right"
});
}
function resetToHand() { // Maybe coordinate with positionStick?
function resetToHand() { // For use with controllers, puts the sword in contact with the hand.
// Maybe coordinate with positionStick?
if (inHand) { // Optimization: bail if we're already inHand.
return;
}
@ -191,14 +193,14 @@ function resetToHand() { // Maybe coordinate with positionStick?
});
inHand = true;
}
function isControllerActive() {
// I don't think the hydra API provides any reliable way to know whether a particular controller is active. Ask for both.
controllerActive = (Vec3.length(Controller.getSpatialControlPosition(3)) > 0) || Vec3.length(Controller.getSpatialControlPosition(4)) > 0;
return controllerActive;
}
function mouseMoveEvent(event) {
if (event.deviceID) { // Not a MOUSE mouse event, but a (e.g., hydra) mouse event, with x/y that is not meaningful for us.
resetToHand(); // Can only happen when controller is uncradled, so let's drive with that, resetting our attachement.
return;
}
controllerActive = (Vec3.length(Controller.getSpatialControlPosition(controllerID)) > 0);
//print("Mouse move with hand controller " + (controllerActive ? "active" : "inactive") + JSON.stringify(event));
if (controllerActive || !isFighting()) {
// When a controller like the hydra gives a mouse event, the x/y is not meaningful to us, but we can detect with a truty deviceID
if (event.deviceID || !isFighting() || isControllerActive()) {
print('Attempting attachment reset');
resetToHand();
return;
@ -244,12 +246,20 @@ function cleanUp(leaveButtons) {
}
function makeSword() {
initControls();
var swordPosition;
if (!isControllerActive()) { // Dont' knock yourself with sword
swordPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation)));
} else if (hand === 'right') {
swordPosition = MyAvatar.getRightPalmPosition();
} else {
swordPosition = MyAvatar.getLeftPalmPosition();
}
stickID = Entities.addEntity({
type: "Model",
modelURL: swordModel,
compoundShapeURL: swordCollisionShape,
dimensions: dimensions,
position: (hand === 'right') ? MyAvatar.getRightPalmPosition() : MyAvatar.getLeftPalmPosition(), // initial position doesn't matter, as long as it's close
position: swordPosition,
rotation: MyAvatar.orientation,
damping: 0.1,
collisionSoundURL: swordCollisionSoundURL,

View file

@ -43,9 +43,10 @@ var gMaxGrabDistance;
// elevationAzimuth
var gGrabMode = "xzplane";
// gGrabOffset allows the user to grab an object off-center. It points from ray's intersection
// with the move-plane to object center (at the moment the grab is initiated). Future target positions
// are relative to the ray's intersection by the same offset.
// gGrabOffset allows the user to grab an object off-center. It points from the object's center
// to the point where the ray intersects the grab plane (at the moment the grab is initiated).
// Future target positions of the ray intersection are on the same plane, and the offset is subtracted
// to compute the target position of the object's center.
var gGrabOffset = { x: 0, y: 0, z: 0 };
var gTargetPosition;
@ -152,7 +153,6 @@ function computeNewGrabPlane() {
maybeResetMousePosition = true;
}
gGrabMode = "xzPlane";
gPointOnPlane = gCurrentPosition;
gPlaneNormal = { x: 0, y: 1, z: 0 };
if (gLiftKey) {
if (!gRotateKey) {
@ -163,7 +163,7 @@ function computeNewGrabPlane() {
gGrabMode = "rotate";
}
gPointOnPlane = Vec3.subtract(gCurrentPosition, gGrabOffset);
gPointOnPlane = Vec3.sum(gCurrentPosition, gGrabOffset);
var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
xzOffset.y = 0;
gXzDistanceToGrab = Vec3.length(xzOffset);
@ -220,8 +220,8 @@ function mousePressEvent(event) {
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
gPointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
// compute the grab offset
gGrabOffset = Vec3.subtract(gStartPosition, gPointOnPlane);
// compute the grab offset (points from object center to point of grab)
gGrabOffset = Vec3.subtract(gPointOnPlane, gStartPosition);
computeNewGrabPlane();
@ -258,6 +258,7 @@ function mouseMoveEvent(event) {
if (Vec3.length(entityProperties.gravity) != 0) {
gOriginalGravity = entityProperties.gravity;
}
gCurrentPosition = entityProperties.position;
var actionArgs = {};
@ -287,6 +288,7 @@ function mouseMoveEvent(event) {
var pointOnCylinder = Vec3.multiply(planeNormal, gXzDistanceToGrab);
pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder);
newTargetPosition = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, event);
gPointOnPlane = Vec3.sum(newTargetPosition, gGrabOffset);
} else {
var cameraPosition = Camera.getPosition();
newTargetPosition = mouseIntersectionWithPlane(gPointOnPlane, gPlaneNormal, event);
@ -298,7 +300,7 @@ function mouseMoveEvent(event) {
newTargetPosition = Vec3.sum(relativePosition, cameraPosition);
}
}
gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
gTargetPosition = Vec3.subtract(newTargetPosition, gGrabOffset);
actionArgs = {targetPosition: gTargetPosition, linearTimeScale: 0.1};
}
gPreviousMouse = { x: event.x, y: event.y };

View file

@ -337,7 +337,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_mousePressed(false),
_enableProcessOctreeThread(true),
_octreeProcessor(),
_nodeBoundsDisplay(this),
_runningScriptsWidget(NULL),
_runningScriptsWidgetWasVisible(false),
_trayIcon(new QSystemTrayIcon(_window)),
@ -702,6 +701,14 @@ void Application::cleanupBeforeQuit() {
#endif
}
void Application::emptyLocalCache() {
QNetworkDiskCache* cache = qobject_cast<QNetworkDiskCache*>(NetworkAccessManager::getInstance().cache());
if (cache) {
qDebug() << "DiskCacheEditor::clear(): Clearing disk cache.";
cache->clear();
}
}
Application::~Application() {
EntityTree* tree = _entities.getTree();
tree->lockForWrite();
@ -1853,7 +1860,7 @@ void Application::idle() {
}
// After finishing all of the above work, ensure the idle timer is set to the proper interval,
// depending on whether we're throttling or not
idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 0);
idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 1);
}
// check for any requested background downloads.
@ -2407,6 +2414,15 @@ void Application::cameraMenuChanged() {
}
}
void Application::reloadResourceCaches() {
emptyLocalCache();
DependencyManager::get<AnimationCache>()->refreshAll();
DependencyManager::get<GeometryCache>()->refreshAll();
DependencyManager::get<SoundCache>()->refreshAll();
DependencyManager::get<TextureCache>()->refreshAll();
}
void Application::rotationModeChanged() {
if (!Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
_myAvatar->setHeadPitch(0);
@ -3570,25 +3586,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
}
if (!selfAvatarOnly) {
_nodeBoundsDisplay.draw();
// render octree fades if they exist
if (_octreeFades.size() > 0) {
PerformanceTimer perfTimer("octreeFades");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... octree fades...");
_octreeFadesLock.lockForWrite();
for(std::vector<OctreeFade>::iterator fade = _octreeFades.begin(); fade != _octreeFades.end();) {
fade->render(renderArgs);
if(fade->isDone()) {
fade = _octreeFades.erase(fade);
} else {
++fade;
}
}
_octreeFadesLock.unlock();
}
// give external parties a change to hook in
{
PerformanceTimer perfTimer("inWorldInterface");
@ -3880,17 +3877,6 @@ void Application::nodeKilled(SharedNodePointer node) {
qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
// Add the jurisditionDetails object to the list of "fade outs"
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
OctreeFade fade(OctreeFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
fade.voxelDetails = rootDetails;
const float slightly_smaller = 0.99f;
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
_octreeFadesLock.lockForWrite();
_octreeFades.push_back(fade);
_octreeFadesLock.unlock();
}
// If the model server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server
_entityServerJurisdictions.lockForWrite();
_entityServerJurisdictions.erase(_entityServerJurisdictions.find(nodeUUID));
@ -3967,16 +3953,6 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
qPrintable(serverType),
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
// Add the jurisditionDetails object to the list of "fade outs"
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
OctreeFade fade(OctreeFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
fade.voxelDetails = rootDetails;
const float slightly_smaller = 0.99f;
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
_octreeFadesLock.lockForWrite();
_octreeFades.push_back(fade);
_octreeFadesLock.unlock();
}
} else {
jurisdiction->unlock();
}

View file

@ -60,7 +60,6 @@
#include "ui/BandwidthDialog.h"
#include "ui/HMDToolsDialog.h"
#include "ui/ModelsBrowser.h"
#include "ui/NodeBounds.h"
#include "ui/OctreeStatsDialog.h"
#include "ui/SnapshotShareDialog.h"
#include "ui/LodToolsDialog.h"
@ -72,7 +71,6 @@
#include "ui/ToolWindow.h"
#include "ui/UserInputMapper.h"
#include "devices/KeyboardMouseDevice.h"
#include "octree/OctreeFade.h"
#include "octree/OctreePacketProcessor.h"
#include "UndoStackScriptingInterface.h"
@ -91,13 +89,6 @@ class Node;
class ProgramObject;
class ScriptEngine;
static const float NODE_ADDED_RED = 0.0f;
static const float NODE_ADDED_GREEN = 1.0f;
static const float NODE_ADDED_BLUE = 0.0f;
static const float NODE_KILLED_RED = 1.0f;
static const float NODE_KILLED_GREEN = 0.0f;
static const float NODE_KILLED_BLUE = 0.0f;
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo";
static const QString SVO_JSON_EXTENSION = ".svo.json";
@ -311,8 +302,6 @@ public:
virtual void endOverrideEnvironmentData() { _environment.endOverride(); }
virtual qreal getDevicePixelRatio();
NodeBounds& getNodeBoundsDisplay() { return _nodeBoundsDisplay; }
FileLogger* getLogger() { return _logger; }
glm::vec2 getViewportDimensions() const;
@ -450,6 +439,8 @@ public slots:
void domainConnectionDenied(const QString& reason);
void cameraMenuChanged();
void reloadResourceCaches();
private slots:
void clearDomainOctreeDetails();
@ -495,6 +486,8 @@ private:
void init();
void cleanupBeforeQuit();
void emptyLocalCache();
void update(float deltaTime);
@ -625,10 +618,6 @@ private:
NodeToOctreeSceneStats _octreeServerSceneStats;
QReadWriteLock _octreeSceneStatsLock;
NodeBounds _nodeBoundsDisplay;
std::vector<OctreeFade> _octreeFades;
QReadWriteLock _octreeFadesLock;
ControllerScriptingInterface _controllerScriptingInterface;
QPointer<LogDialog> _logDialog;
QPointer<SnapshotShareDialog> _snapshotShareDialog;

View file

@ -37,7 +37,6 @@
#include "SpeechRecognizer.h"
#endif
#include "ui/DialogsManager.h"
#include "ui/NodeBounds.h"
#include "ui/StandAloneJSConsole.h"
#include "InterfaceLogging.h"
@ -256,6 +255,8 @@ Menu::Menu() {
avatar, SLOT(updateMotionBehavior()));
MenuWrapper* viewMenu = addMenu("View");
addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
addCheckableActionToQMenuAndActionHash(viewMenu,
MenuOption::Fullscreen,
@ -314,13 +315,6 @@ Menu::Menu() {
qApp,
SLOT(setEnable3DTVMode(bool)));
MenuWrapper* nodeBordersMenu = viewMenu->addMenu("Server Borders");
NodeBounds& nodeBounds = qApp->getNodeBoundsDisplay();
addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
&nodeBounds, SLOT(setShowEntityNodes(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats);
@ -340,7 +334,6 @@ Menu::Menu() {
0, // QML Qt::SHIFT | Qt::Key_A,
true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);

View file

@ -179,7 +179,6 @@ namespace MenuOption {
const QString DisplayModelElementProxy = "Display Model Element Bounds";
const QString DisplayDebugTimingDetails = "Display Timing Details";
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes";
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
const QString EchoLocalAudio = "Echo Local Audio";
const QString EchoServerAudio = "Echo Server Audio";
@ -230,6 +229,7 @@ namespace MenuOption {
const QString Preferences = "Preferences...";
const QString Quit = "Quit";
const QString ReloadAllScripts = "Reload All Scripts";
const QString ReloadContent = "Reload Content (Clears all caches)";
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
const QString RenderFocusIndicator = "Show Eye Focus";
const QString RenderHeadCollisionShapes = "Show Head Collision Shapes";

View file

@ -636,7 +636,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
_billboardTexture = DependencyManager::get<TextureCache>()->getTexture(
uniqueUrl, DEFAULT_TEXTURE, false, _billboard);
}
if (!_billboardTexture->isLoaded()) {
if (!_billboardTexture || !_billboardTexture->isLoaded()) {
return;
}
// rotate about vertical to face the camera

View file

@ -56,18 +56,14 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
joint.preTransform * glm::mat4_cast(joint.preRotation)));
glm::vec3 pitchYawRoll = safeEulerAngles(_owningHead->getFinalOrientationInLocalFrame());
if (owningAvatar->isMyAvatar()) {
glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(),
_owningHead->getTorsoTwist(),
_owningHead->getFinalLeanSideways()));
pitchYawRoll -= lean;
}
glm::vec3 lean = glm::radians(glm::vec3(_owningHead->getFinalLeanForward(),
_owningHead->getTorsoTwist(),
_owningHead->getFinalLeanSideways()));
pitchYawRoll -= lean;
state.setRotationInConstrainedFrame(glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2]))
* glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1]))
* glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0]))
* joint.rotation, DEFAULT_PRIORITY);
}
void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentState, const FBXJoint& joint, JointState& state) {

View file

@ -1,68 +0,0 @@
//
// OctreeFade.cpp
// interface/src/octree
//
// Created by Brad Hefta-Gaub on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InterfaceConfig.h"
#include <GlowEffect.h>
#include <GeometryCache.h>
#include <OctreeConstants.h>
#include "Application.h"
#include "OctreeFade.h"
const float OctreeFade::FADE_OUT_START = 0.5f;
const float OctreeFade::FADE_OUT_END = 0.05f;
const float OctreeFade::FADE_OUT_STEP = 0.9f;
const float OctreeFade::FADE_IN_START = 0.05f;
const float OctreeFade::FADE_IN_END = 0.5f;
const float OctreeFade::FADE_IN_STEP = 1.1f;
const float OctreeFade::DEFAULT_RED = 0.5f;
const float OctreeFade::DEFAULT_GREEN = 0.5f;
const float OctreeFade::DEFAULT_BLUE = 0.5f;
OctreeFade::OctreeFade(FadeDirection direction, float red, float green, float blue) :
direction(direction),
red(red),
green(green),
blue(blue)
{
opacity = (direction == FADE_OUT) ? FADE_OUT_START : FADE_IN_START;
}
void OctreeFade::render(RenderArgs* renderArgs) {
DependencyManager::get<GlowEffect>()->begin(renderArgs);
glDisable(GL_LIGHTING);
glPushMatrix();
glScalef(1.0f, 1.0f, 1.0f);
glTranslatef(voxelDetails.x + voxelDetails.s * 0.5f,
voxelDetails.y + voxelDetails.s * 0.5f,
voxelDetails.z + voxelDetails.s * 0.5f);
glLineWidth(1.0f);
DependencyManager::get<GeometryCache>()->renderSolidCube(voxelDetails.s, glm::vec4(red, green, blue, opacity));
glLineWidth(1.0f);
glPopMatrix();
glEnable(GL_LIGHTING);
DependencyManager::get<GlowEffect>()->end(renderArgs);
opacity *= (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
}
bool OctreeFade::isDone() const {
if (direction == FADE_OUT) {
return opacity <= FADE_OUT_END;
} else {
return opacity >= FADE_IN_END;
}
return true; // unexpected case, assume we're done
}

View file

@ -1,46 +0,0 @@
//
// OctreeFade.h
// interface/src/octree
//
// Created by Brad Hefta-Gaub on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_OctreeFade_h
#define hifi_OctreeFade_h
#include <OctalCode.h> // for VoxelPositionSize
class OctreeFade {
public:
enum FadeDirection { FADE_OUT, FADE_IN};
static const float FADE_OUT_START;
static const float FADE_OUT_END;
static const float FADE_OUT_STEP;
static const float FADE_IN_START;
static const float FADE_IN_END;
static const float FADE_IN_STEP;
static const float DEFAULT_RED;
static const float DEFAULT_GREEN;
static const float DEFAULT_BLUE;
VoxelPositionSize voxelDetails;
FadeDirection direction;
float opacity;
float red;
float green;
float blue;
OctreeFade(FadeDirection direction = FADE_OUT, float red = DEFAULT_RED,
float green = DEFAULT_GREEN, float blue = DEFAULT_BLUE);
void render(RenderArgs* renderArgs);
bool isDone() const;
};
#endif // hifi_OctreeFade_h

View file

@ -165,19 +165,6 @@ void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) {
drawText(canvasSize.x - 100, canvasSize.y - timerBottom,
0.30f, 0.0f, 0, frameTimer.toUtf8().constData(), WHITE_TEXT);
}
glPointSize(1.0f);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
NodeBounds& nodeBoundsDisplay = qApp->getNodeBoundsDisplay();
nodeBoundsDisplay.drawOverlay();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
fboViewport(_overlayFramebuffer);
*/
}

View file

@ -1,183 +0,0 @@
//
// NodeBounds.cpp
// interface/src/ui
//
// Created by Ryan Huffman on 05/14/14.
// Copyright 2014 High Fidelity, Inc.
//
// This class draws a border around the different Entity nodes on the current domain,
// and a semi-transparent cube around the currently mouse-overed node.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <DependencyManager.h>
#include <GeometryCache.h>
#include "Application.h"
#include "Util.h"
#include "NodeBounds.h"
NodeBounds::NodeBounds(QObject* parent) :
QObject(parent),
_showEntityNodes(false),
_overlayText() {
}
void NodeBounds::draw() {
if (!_showEntityNodes) {
_overlayText[0] = '\0';
return;
}
NodeToJurisdictionMap& entityServerJurisdictions = Application::getInstance()->getEntityServerJurisdictions();
NodeToJurisdictionMap* serverJurisdictions;
// Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers
// itself after the cursor disappears.
PickRay pickRay = qApp->computePickRay();
// Variables to keep track of the selected node and properties to draw the cube later if needed
Node* selectedNode = NULL;
float selectedDistance = FLT_MAX;
bool selectedIsInside = true;
glm::vec3 selectedCenter;
float selectedScale = 0;
auto nodeList = DependencyManager::get<NodeList>();
nodeList->eachNode([&](const SharedNodePointer& node){
NodeType_t nodeType = node->getType();
if (nodeType == NodeType::EntityServer && _showEntityNodes) {
serverJurisdictions = &entityServerJurisdictions;
} else {
return;
}
QUuid nodeUUID = node->getUUID();
serverJurisdictions->lockForRead();
if (serverJurisdictions->find(nodeUUID) != serverJurisdictions->end()) {
const JurisdictionMap& map = (*serverJurisdictions)[nodeUUID];
unsigned char* rootCode = map.getRootOctalCode();
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
serverJurisdictions->unlock();
glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
AACube serverBounds(location, rootDetails.s);
glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
+ ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);
const float ENTITY_NODE_SCALE = 0.99f;
float scaleFactor = rootDetails.s;
// Scale by 0.92 - 1.00 depending on the scale of the node. This allows smaller nodes to scale in
// a bit and not overlap larger nodes.
scaleFactor *= 0.92f + (rootDetails.s * 0.08f);
// Scale different node types slightly differently because it's common for them to overlap.
if (nodeType == NodeType::EntityServer) {
scaleFactor *= ENTITY_NODE_SCALE;
}
float red, green, blue;
getColorForNodeType(nodeType, red, green, blue);
drawNodeBorder(center, scaleFactor, red, green, blue);
float distance;
BoxFace face;
bool inside = serverBounds.contains(pickRay.origin);
bool colliding = serverBounds.findRayIntersection(pickRay.origin, pickRay.direction, distance, face);
// If the camera is inside a node it will be "selected" if you don't have your cursor over another node
// that you aren't inside.
if (colliding && (!selectedNode || (!inside && (distance < selectedDistance || selectedIsInside)))) {
selectedNode = node.data();
selectedDistance = distance;
selectedIsInside = inside;
selectedCenter = center;
selectedScale = scaleFactor;
}
} else {
serverJurisdictions->unlock();
}
} else {
serverJurisdictions->unlock();
}
});
if (selectedNode) {
glPushMatrix();
glTranslatef(selectedCenter.x, selectedCenter.y, selectedCenter.z);
glScalef(selectedScale, selectedScale, selectedScale);
float red, green, blue;
getColorForNodeType(selectedNode->getType(), red, green, blue);
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(red, green, blue, 0.2f));
glPopMatrix();
HifiSockAddr addr = selectedNode->getPublicSocket();
QString overlay = QString("%1:%2 %3ms")
.arg(addr.getAddress().toString())
.arg(addr.getPort())
.arg(selectedNode->getPingMs())
.left(MAX_OVERLAY_TEXT_LENGTH);
// Ideally we'd just use a QString, but I ran into weird blinking issues using
// constData() directly, as if the data was being overwritten.
strcpy(_overlayText, overlay.toLocal8Bit().constData());
} else {
_overlayText[0] = '\0';
}
}
void NodeBounds::drawNodeBorder(const glm::vec3& center, float scale, float red, float green, float blue) {
glPushMatrix();
glTranslatef(center.x, center.y, center.z);
glScalef(scale, scale, scale);
glLineWidth(2.5);
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, glm::vec4(red, green, blue, 1.0f));
glPopMatrix();
}
void NodeBounds::getColorForNodeType(NodeType_t nodeType, float& red, float& green, float& blue) {
red = nodeType == 0.0;
green = 0.0;
blue = nodeType == NodeType::EntityServer ? 1.0 : 0.0;
}
void NodeBounds::drawOverlay() {
if (strlen(_overlayText) > 0) {
Application* application = Application::getInstance();
const float TEXT_COLOR[] = { 0.90f, 0.90f, 0.90f };
const float TEXT_SCALE = 0.1f;
const int TEXT_HEIGHT = 10;
const float ROTATION = 0.0f;
const int FONT = 2;
const int PADDING = 10;
const int MOUSE_OFFSET = 10;
const int BACKGROUND_BEVEL = 3;
int mouseX = application->getTrueMouseX(),
mouseY = application->getTrueMouseY(),
textWidth = widthText(TEXT_SCALE, 0, _overlayText);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(
mouseX + MOUSE_OFFSET, mouseY - TEXT_HEIGHT - PADDING,
textWidth + (2 * PADDING), TEXT_HEIGHT + (2 * PADDING), BACKGROUND_BEVEL,
glm::vec4(0.4f, 0.4f, 0.4f, 0.6f));
drawText(mouseX + MOUSE_OFFSET + PADDING, mouseY, TEXT_SCALE, ROTATION, FONT, _overlayText, TEXT_COLOR);
}
}

View file

@ -1,47 +0,0 @@
//
// NodeBounds.h
// interface/src/ui
//
// Created by Ryan Huffman on 05/14/14.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_NodeBounds_h
#define hifi_NodeBounds_h
#include <QObject>
#include <NodeList.h>
const int MAX_OVERLAY_TEXT_LENGTH = 64;
class NodeBounds : public QObject {
Q_OBJECT
public:
NodeBounds(QObject* parent = NULL);
bool getShowEntityNodes() { return _showEntityNodes; }
bool getShowParticleNodes() { return _showParticleNodes; }
void draw();
void drawOverlay();
public slots:
void setShowEntityNodes(bool value) { _showEntityNodes = value; }
void setShowParticleNodes(bool value) { _showParticleNodes = value; }
protected:
void drawNodeBorder(const glm::vec3& center, float scale, float red, float green, float blue);
void getColorForNodeType(NodeType_t nodeType, float& red, float& green, float& blue);
private:
bool _showEntityNodes;
bool _showParticleNodes;
char _overlayText[MAX_OVERLAY_TEXT_LENGTH + 1];
};
#endif // hifi_NodeBounds_h

View file

@ -28,12 +28,12 @@ BillboardOverlay::BillboardOverlay(const BillboardOverlay* billboardOverlay) :
}
void BillboardOverlay::render(RenderArgs* args) {
if (!_isLoaded) {
if (!_texture) {
_isLoaded = true;
_texture = DependencyManager::get<TextureCache>()->getTexture(_url);
}
if (!_visible || !_texture->isLoaded()) {
if (!_visible || !_texture || !_texture->isLoaded()) {
return;
}
@ -170,7 +170,7 @@ void BillboardOverlay::setBillboardURL(const QString& url) {
bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) {
if (_texture) {
if (_texture && _texture->isLoaded()) {
glm::quat rotation = getRotation();
if (_isFacingAvatar) {
// rotate about vertical to face the camera

View file

@ -104,93 +104,6 @@ void Cube3DOverlay::render(RenderArgs* args) {
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(*batch, 1.0f, cubeColor);
}
}
} else {
float glowLevel = getGlowLevel();
Glower* glower = NULL;
if (glowLevel > 0.0f) {
glower = new Glower(glowLevel);
}
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glPushMatrix();
glm::vec3 positionToCenter = center - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
if (_isSolid) {
if (_borderSize > 0) {
// Draw a cube at a larger size behind the main cube, creating
// a border effect.
// Disable writing to the depth mask so that the "border" cube will not
// occlude the main cube. This means the border could be covered by
// overlays that are further back and drawn later, but this is good
// enough for the use-case.
glDepthMask(GL_FALSE);
glPushMatrix();
glScalef(dimensions.x * _borderSize, dimensions.y * _borderSize, dimensions.z * _borderSize);
if (_drawOnHUD) {
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
} else {
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
}
glPopMatrix();
glDepthMask(GL_TRUE);
}
glPushMatrix();
glScalef(dimensions.x, dimensions.y, dimensions.z);
if (_drawOnHUD) {
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
} else {
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
}
glPopMatrix();
} else {
glLineWidth(_lineWidth);
if (getIsDashedLine()) {
glm::vec3 halfDimensions = dimensions / 2.0f;
glm::vec3 bottomLeftNear(-halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
glm::vec3 bottomRightNear(halfDimensions.x, -halfDimensions.y, -halfDimensions.z);
glm::vec3 topLeftNear(-halfDimensions.x, halfDimensions.y, -halfDimensions.z);
glm::vec3 topRightNear(halfDimensions.x, halfDimensions.y, -halfDimensions.z);
glm::vec3 bottomLeftFar(-halfDimensions.x, -halfDimensions.y, halfDimensions.z);
glm::vec3 bottomRightFar(halfDimensions.x, -halfDimensions.y, halfDimensions.z);
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->renderDashedLine(bottomLeftNear, bottomRightNear, cubeColor);
geometryCache->renderDashedLine(bottomRightNear, bottomRightFar, cubeColor);
geometryCache->renderDashedLine(bottomRightFar, bottomLeftFar, cubeColor);
geometryCache->renderDashedLine(bottomLeftFar, bottomLeftNear, cubeColor);
geometryCache->renderDashedLine(topLeftNear, topRightNear, cubeColor);
geometryCache->renderDashedLine(topRightNear, topRightFar, cubeColor);
geometryCache->renderDashedLine(topRightFar, topLeftFar, cubeColor);
geometryCache->renderDashedLine(topLeftFar, topLeftNear, cubeColor);
geometryCache->renderDashedLine(bottomLeftNear, topLeftNear, cubeColor);
geometryCache->renderDashedLine(bottomRightNear, topRightNear, cubeColor);
geometryCache->renderDashedLine(bottomLeftFar, topLeftFar, cubeColor);
geometryCache->renderDashedLine(bottomRightFar, topRightFar, cubeColor);
} else {
glScalef(dimensions.x, dimensions.y, dimensions.z);
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
}
}
glPopMatrix();
glPopMatrix();
if (glower) {
delete glower;
}
}
}

View file

@ -53,7 +53,6 @@ void Line3DOverlay::render(RenderArgs* args) {
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
auto batch = args->_batch;
if (batch) {
batch->setModelTransform(_transform);
@ -63,38 +62,6 @@ void Line3DOverlay::render(RenderArgs* args) {
} else {
DependencyManager::get<GeometryCache>()->renderLine(*batch, _start, _end, colorv4, _geometryCacheID);
}
} else {
float glowLevel = getGlowLevel();
Glower* glower = NULL;
if (glowLevel > 0.0f) {
glower = new Glower(glowLevel);
}
glPushMatrix();
glDisable(GL_LIGHTING);
glLineWidth(_lineWidth);
glm::vec3 position = getPosition();
glm::quat rotation = getRotation();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
if (getIsDashedLine()) {
// TODO: add support for color to renderDashedLine()
DependencyManager::get<GeometryCache>()->renderDashedLine(_start, _end, colorv4, _geometryCacheID);
} else {
DependencyManager::get<GeometryCache>()->renderLine(_start, _end, colorv4, _geometryCacheID);
}
glEnable(GL_LIGHTING);
glPopMatrix();
if (glower) {
delete glower;
}
}
}

View file

@ -38,10 +38,7 @@ QSharedPointer<Resource> AnimationCache::createResource(const QUrl& url, const Q
return QSharedPointer<Resource>(new Animation(url), &Resource::allReferencesCleared);
}
Animation::Animation(const QUrl& url) :
Resource(url),
_isValid(false) {
}
Animation::Animation(const QUrl& url) : Resource(url) {}
class AnimationReader : public QRunnable {
public:
@ -97,7 +94,6 @@ QVector<FBXAnimationFrame> Animation::getFrames() const {
void Animation::setGeometry(const FBXGeometry& geometry) {
_geometry = geometry;
finishedLoading(true);
_isValid = true;
}
void Animation::downloadFinished(QNetworkReply* reply) {

View file

@ -57,8 +57,6 @@ public:
Q_INVOKABLE QStringList getJointNames() const;
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
bool isValid() const { return _isValid; }
protected:
@ -69,7 +67,6 @@ protected:
private:
FBXGeometry _geometry;
bool _isValid;
};

View file

@ -294,7 +294,7 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
if (soundCache.isNull()) {
return NULL;
}
SharedSoundPointer sound = soundCache.data()->getSound(QUrl(soundUrl));
SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl));
if (sound.isNull() || !sound->isReady()) {
return NULL;
}

View file

@ -161,19 +161,15 @@ QByteArray AvatarData::toByteArray() {
// Body scale
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale);
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
glm::vec3 pitchYawRoll = glm::vec3(_headData->getFinalPitch(),
_headData->getFinalYaw(),
_headData->getFinalRoll());
if (this->isMyAvatar()) {
glm::vec3 lean = glm::vec3(_headData->getFinalLeanForward(),
_headData->getTorsoTwist(),
_headData->getFinalLeanSideways());
pitchYawRoll -= lean;
}
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.x);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.y);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, pitchYawRoll.z);
// Head rotation
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalPitch());
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalYaw());
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalRoll());
// Body lean
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_leanForward);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_leanSideways);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_torsoTwist);
// Lookat Position
memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition));
@ -291,13 +287,16 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// headPitch = 2 (compressed float)
// headYaw = 2 (compressed float)
// headRoll = 2 (compressed float)
// leanForward = 2 (compressed float)
// leanSideways = 2 (compressed float)
// torsoTwist = 2 (compressed float)
// lookAt = 12
// audioLoudness = 4
// }
// + 1 byte for pupilSize
// + 1 byte for numJoints (0)
// = 45 bytes
int minPossibleSize = 45;
// = 51 bytes
int minPossibleSize = 51;
int maxAvailableSize = packet.size() - offset;
if (minPossibleSize > maxAvailableSize) {
@ -371,6 +370,22 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
_headData->setBaseYaw(headYaw);
_headData->setBaseRoll(headRoll);
} // 6 bytes
{ // Head lean (relative to pelvis)
float leanForward, leanSideways, torsoTwist;
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &leanForward);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &leanSideways);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*)sourceBuffer, &torsoTwist);
if (glm::isnan(leanForward) || glm::isnan(leanSideways)) {
if (shouldLogError(now)) {
qCDebug(avatars) << "Discard nan AvatarData::leanForward,leanSideways,torsoTwise; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->_leanForward = leanForward;
_headData->_leanSideways = leanSideways;
_headData->_torsoTwist = torsoTwist;
} // 6 bytes
{ // Lookat Position
glm::vec3 lookAt;

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtCore/QDataStream>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>

View file

@ -546,7 +546,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
Model* model = modelEntityItem->getModel(this);
if (model) {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
if (!collisionNetworkGeometry.isNull()) {
if (collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) {
result = &collisionNetworkGeometry->getFBXGeometry();
}
}

View file

@ -63,11 +63,11 @@ void RenderableModelEntityItem::remapTextures() {
return; // nothing to do if we don't have a model
}
if (!_model->isLoadedWithTextures()) {
return; // nothing to do if the model has not yet loaded its default textures
if (!_model->isLoaded()) {
return; // nothing to do if the model has not yet loaded
}
if (!_originalTexturesRead && _model->isLoadedWithTextures()) {
if (!_originalTexturesRead) {
const QSharedPointer<NetworkGeometry>& networkGeometry = _model->getGeometry();
if (networkGeometry) {
_originalTextures = networkGeometry->getTextureNames();
@ -119,7 +119,7 @@ bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
getModel(renderer);
}
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoadedWithTextures()) {
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
@ -401,8 +401,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
if ((! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) &&
(! renderNetworkGeometry.isNull() && renderNetworkGeometry->isLoadedWithTextures())) {
if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
(renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
// we have both URLs AND both geometries AND they are both fully loaded.
return true;
}
@ -423,7 +423,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
// should never fall in here when collision model not fully loaded
// hence we assert collisionNetworkGeometry is not NULL
assert(!collisionNetworkGeometry.isNull());
assert(collisionNetworkGeometry);
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();

View file

@ -610,6 +610,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
int bytesRead = parser.offset();
#endif
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) {
// pack SimulationOwner and terse update properties near each other
@ -632,10 +635,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
// but since we're using macros below we have to temporarily modify overwriteLocalData.
auto nodeList = DependencyManager::get<NodeList>();
bool weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID());
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnIt;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
@ -657,6 +658,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
} else {
// legacy order of packing here
// TODO: purge this logic in a few months from now (2015.07)
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
@ -702,7 +704,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
{ // When we own the simulation we don't accept updates to the entity's actions
// but since we're using macros below we have to temporarily modify overwriteLocalData.
// NOTE: this prevents userB from adding an action to an object1 when UserA
// has simulation ownership of it.
// TODO: figure out how to allow multiple users to update actions simultaneously
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
overwriteLocalData = oldOverwrite;
}
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData);
@ -713,7 +724,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
// by doing this parsing here... but it's not likely going to fully recover the content.
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
// TODO: Remove this code once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
@ -738,8 +749,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
}
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
if (overwriteLocalData) {
if (!_simulationOwner.matchesValidID(myNodeID)) {

View file

@ -184,7 +184,7 @@ void ModelEntityItem::cleanupLoadedAnimations() {
_loadedAnimations.clear();
}
Animation* ModelEntityItem::getAnimation(const QString& url) {
AnimationPointer ModelEntityItem::getAnimation(const QString& url) {
AnimationPointer animation;
// if we don't already have this model then create it and initialize it
@ -194,7 +194,7 @@ Animation* ModelEntityItem::getAnimation(const QString& url) {
} else {
animation = _loadedAnimations[url];
}
return animation.data();
return animation;
}
void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
@ -203,9 +203,8 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
return;
}
Animation* myAnimation = getAnimation(_animationURL);
if (!_jointMappingCompleted) {
AnimationPointer myAnimation = getAnimation(_animationURL);
if (myAnimation && myAnimation->isLoaded()) {
QStringList animationJointNames = myAnimation->getJointNames();
if (modelJointNames.size() > 0 && animationJointNames.size() > 0) {
@ -220,8 +219,12 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) {
QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
QVector<glm::quat> frameData;
if (hasAnimation() && _jointMappingCompleted) {
Animation* myAnimation = getAnimation(_animationURL);
if (!hasAnimation() || !_jointMappingCompleted) {
return frameData;
}
AnimationPointer myAnimation = getAnimation(_animationURL);
if (myAnimation && myAnimation->isLoaded()) {
QVector<FBXAnimationFrame> frames = myAnimation->getFrames();
int frameCount = frames.size();
if (frameCount > 0) {

View file

@ -141,7 +141,7 @@ protected:
bool _jointMappingCompleted;
QVector<int> _jointMapping;
static Animation* getAnimation(const QString& url);
static AnimationPointer getAnimation(const QString& url);
static QMap<QString, AnimationPointer> _loadedAnimations;
static AnimationCache _animationCache;

View file

@ -93,7 +93,16 @@ QByteArray FSTReader::writeMapping(const QVariantHash& mapping) {
for (auto key : PREFERED_ORDER) {
auto it = mapping.find(key);
if (it != mapping.constEnd()) {
writeVariant(buffer, it);
if (key == FREE_JOINT_FIELD) { // writeVariant does not handle strings added using insertMulti.
for (auto multi : mapping.values(key)) {
buffer.write(key.toUtf8());
buffer.write(" = ");
buffer.write(multi.toByteArray());
buffer.write("\n");
}
} else {
writeVariant(buffer, it);
}
}
}

View file

@ -13,6 +13,7 @@
#include <qjsondocument.h>
#include <QtCore/QDebug>
#include <QtCore/QDataStream>
#include "NetworkLogging.h"
#include "DataServerAccountInfo.h"

View file

@ -12,6 +12,7 @@
#include <math.h>
#include <QtCore/QJsonDocument>
#include <QtCore/QDataStream>
#include "Assignment.h"
#include "HifiSockAddr.h"

View file

@ -17,6 +17,7 @@
#include <QtCore/QJsonValue>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariantMap>
class JSONBreakableMarshal {
public:

View file

@ -40,16 +40,3 @@ NetworkPacket& NetworkPacket::operator=(NetworkPacket const& other) {
copyContents(other.getNode(), other.getByteArray());
return *this;
}
#ifdef HAS_MOVE_SEMANTICS
// move, same as copy, but other packet won't be used further
NetworkPacket::NetworkPacket(NetworkPacket && packet) {
copyContents(packet.getNode(), packet.getByteArray());
}
// move assignment
NetworkPacket& NetworkPacket::operator=(NetworkPacket&& other) {
copyContents(other.getNode(), other.getByteArray());
return *this;
}
#endif

View file

@ -22,12 +22,6 @@ public:
NetworkPacket() { }
NetworkPacket(const NetworkPacket& packet); // copy constructor
NetworkPacket& operator= (const NetworkPacket& other); // copy assignment
#ifdef HAS_MOVE_SEMANTICS
NetworkPacket(NetworkPacket&& packet); // move?? // same as copy, but other packet won't be used further
NetworkPacket& operator= (NetworkPacket&& other); // move assignment
#endif
NetworkPacket(const SharedNodePointer& node, const QByteArray& byteArray);
const SharedNodePointer& getNode() const { return _node; }

View file

@ -13,6 +13,7 @@
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QDataStream>
#include <SharedUtil.h>
#include <UUID.h>

View file

@ -55,7 +55,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketTypeInjectAudio:
return 1;
case PacketTypeAvatarData:
return 6;
return 7;
case PacketTypeAvatarIdentity:
return 1;
case PacketTypeEnvironmentData:

View file

@ -34,13 +34,18 @@ ResourceCache::ResourceCache(QObject* parent) :
}
ResourceCache::~ResourceCache() {
// the unused resources may themselves reference resources that will be added to the unused
// list on destruction, so keep clearing until there are no references left
while (!_unusedResources.isEmpty()) {
foreach (const QSharedPointer<Resource>& resource, _unusedResources) {
resource->setCache(nullptr);
clearUnusedResource();
}
void ResourceCache::refreshAll() {
// Clear all unused resources so we don't have to reload them
clearUnusedResource();
// Refresh all remaining resources in use
foreach (auto resource, _resources) {
if (!resource.isNull()) {
resource.data()->refresh();
}
_unusedResources.clear();
}
}
@ -48,6 +53,8 @@ void ResourceCache::refresh(const QUrl& url) {
QSharedPointer<Resource> resource = _resources.value(url);
if (!resource.isNull()) {
resource->refresh();
} else {
_resources.remove(url);
}
}
@ -134,6 +141,17 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) {
}
}
void ResourceCache::clearUnusedResource() {
// the unused resources may themselves reference resources that will be added to the unused
// list on destruction, so keep clearing until there are no references left
while (!_unusedResources.isEmpty()) {
foreach (const QSharedPointer<Resource>& resource, _unusedResources) {
resource->setCache(nullptr);
}
_unusedResources.clear();
}
}
void ResourceCache::attemptRequest(Resource* resource) {
auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>();
if (_requestLimit <= 0) {
@ -253,19 +271,20 @@ void Resource::refresh() {
_replyTimer->deleteLater();
_replyTimer = nullptr;
}
init();
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
if (!_startedLoading) {
attemptRequest();
}
ensureLoading();
emit onRefresh();
}
void Resource::allReferencesCleared() {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allReferencesCleared");
return;
}
if (_cache) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "allReferencesCleared");
return;
}
// create and reinsert new shared pointer
QSharedPointer<Resource> self(this, &Resource::allReferencesCleared);
setSelf(self);
@ -312,8 +331,7 @@ void Resource::reinsert() {
_cache->_resources.insert(_url, _self);
}
const int REPLY_TIMEOUT_MS = 5000;
static const int REPLY_TIMEOUT_MS = 5000;
void Resource::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
if (!_reply->isFinished()) {
_bytesReceived = bytesReceived;

View file

@ -51,7 +51,7 @@ static const qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES;
class ResourceCacheSharedItems : public Dependency {
SINGLETON_DEPENDENCY
public:
QList<QPointer<Resource> > _pendingRequests;
QList<QPointer<Resource>> _pendingRequests;
QList<Resource*> _loadingRequests;
private:
ResourceCacheSharedItems() { }
@ -78,17 +78,14 @@ public:
ResourceCache(QObject* parent = NULL);
virtual ~ResourceCache();
void refreshAll();
void refresh(const QUrl& url);
public slots:
void checkAsynchronousGets();
protected:
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0;
QMap<int, QSharedPointer<Resource> > _unusedResources;
/// Loads a resource from the specified URL.
/// \param fallback a fallback URL to load if the desired one is unavailable
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
@ -103,6 +100,7 @@ protected:
void addUnusedResource(const QSharedPointer<Resource>& resource);
void removeUnusedResource(const QSharedPointer<Resource>& resource);
void reserveUnusedResource(qint64 resourceSize);
void clearUnusedResource();
static void attemptRequest(Resource* resource);
static void requestCompleted(Resource* resource);
@ -110,7 +108,7 @@ protected:
private:
friend class Resource;
QHash<QUrl, QWeakPointer<Resource> > _resources;
QHash<QUrl, QWeakPointer<Resource>> _resources;
int _lastLRUKey = 0;
static int _requestLimit;
@ -118,7 +116,10 @@ private:
void getResourceAsynchronously(const QUrl& url);
QReadWriteLock _resourcesToBeGottenLock;
QQueue<QUrl> _resourcesToBeGotten;
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
qint64 _unusedResourcesSize = 0;
QMap<int, QSharedPointer<Resource>> _unusedResources;
};
/// Base class for resources.
@ -172,12 +173,11 @@ public:
const QUrl& getURL() const { return _url; }
signals:
/// Fired when the resource has been loaded.
void loaded();
void onRefresh();
protected slots:
void attemptRequest();
/// Refreshes the resource if the last modified date on the network
@ -185,7 +185,6 @@ protected slots:
void maybeRefresh();
protected:
virtual void init();
/// Called when the download has finished. The recipient should delete the reply when done with it.
@ -207,14 +206,12 @@ protected:
QPointer<ResourceCache> _cache;
private slots:
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void handleReplyError();
void handleReplyFinished();
void handleReplyTimeout();
private:
void setLRUKey(int lruKey) { _lruKey = lruKey; }
void makeRequest();

View file

@ -30,23 +30,6 @@ JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) {
return *this;
}
#ifdef HAS_MOVE_SEMANTICS
// Move constructor
JurisdictionMap::JurisdictionMap(JurisdictionMap&& other) : _rootOctalCode(NULL) {
init(other._rootOctalCode, other._endNodes);
other._rootOctalCode = NULL;
other._endNodes.clear();
}
// move assignment
JurisdictionMap& JurisdictionMap::operator=(JurisdictionMap&& other) {
init(other._rootOctalCode, other._endNodes);
other._rootOctalCode = NULL;
other._endNodes.clear();
return *this;
}
#endif
// Copy constructor
JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(NULL) {
copyContents(other);

View file

@ -37,12 +37,6 @@ public:
// standard assignment
JurisdictionMap& operator=(const JurisdictionMap& other); // copy assignment
#ifdef HAS_MOVE_SEMANTICS
// move constructor and assignment
JurisdictionMap(JurisdictionMap&& other); // move constructor
JurisdictionMap& operator= (JurisdictionMap&& other); // move assignment
#endif
// application constructors
JurisdictionMap(const char* filename);
JurisdictionMap(unsigned char* rootOctalCode, const std::vector<unsigned char*>& endNodes);

View file

@ -15,6 +15,7 @@
void AnimationHandle::setURL(const QUrl& url) {
if (_url != url) {
_animation = DependencyManager::get<AnimationCache>()->getAnimation(_url = url);
QObject::connect(_animation.data(), &Resource::onRefresh, this, &AnimationHandle::clearJoints);
_jointMappings.clear();
}
}
@ -110,11 +111,15 @@ void AnimationHandle::setAnimationDetails(const AnimationDetails& details) {
void AnimationHandle::simulate(float deltaTime) {
if (!_animation || !_animation->isLoaded()) {
return;
}
_animationLoop.simulate(deltaTime);
// update the joint mappings if necessary/possible
if (_jointMappings.isEmpty()) {
if (_model->isActive()) {
if (_model && _model->isActive()) {
_jointMappings = _model->getGeometry()->getJointMappings(_animation);
}
if (_jointMappings.isEmpty()) {
@ -146,6 +151,10 @@ void AnimationHandle::simulate(float deltaTime) {
}
void AnimationHandle::applyFrame(float frameIndex) {
if (!_animation || !_animation->isLoaded()) {
return;
}
const FBXGeometry& animationGeometry = _animation->getGeometry();
int frameCount = animationGeometry.animationFrames.size();
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);

View file

@ -94,6 +94,8 @@ private:
void replaceMatchingPriorities(float newPriority);
void restoreJoints();
void clearJoints() { _jointMappings.clear(); }
Model* _model;
WeakAnimationHandlePointer _self;
AnimationPointer _animation;

View file

@ -55,8 +55,6 @@ const int NUM_VERTICES_PER_TRIANGLE = 3;
const int NUM_TRIANGLES_PER_QUAD = 2;
const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;
const int NUM_COORDS_PER_VERTEX = 3;
const int NUM_BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat);
const int NUM_BYTES_PER_INDEX = sizeof(GLushort);
void GeometryCache::renderSphere(float radius, int slices, int stacks, const glm::vec4& color, bool solid, int id) {
gpu::Batch batch;
@ -308,106 +306,6 @@ void GeometryCache::renderSphere(gpu::Batch& batch, float radius, int slices, in
}
}
void GeometryCache::renderCone(float base, float height, int slices, int stacks) {
VerticesIndices& vbo = _coneVBOs[IntPair(slices, stacks)];
int vertices = (stacks + 2) * slices;
int baseTriangles = slices - 2;
int indices = NUM_VERTICES_PER_TRIANGULATED_QUAD * slices * stacks + NUM_VERTICES_PER_TRIANGLE * baseTriangles;
if (vbo.first == 0) {
GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX * 2];
GLfloat* vertex = vertexData;
// cap
for (int i = 0; i < slices; i++) {
float theta = TWO_PI * i / slices;
//normals
*(vertex++) = 0.0f;
*(vertex++) = 0.0f;
*(vertex++) = -1.0f;
// vertices
*(vertex++) = cosf(theta);
*(vertex++) = sinf(theta);
*(vertex++) = 0.0f;
}
// body
for (int i = 0; i <= stacks; i++) {
float z = (float)i / stacks;
float radius = 1.0f - z;
for (int j = 0; j < slices; j++) {
float theta = TWO_PI * j / slices;
//normals
*(vertex++) = cosf(theta) / SQUARE_ROOT_OF_2;
*(vertex++) = sinf(theta) / SQUARE_ROOT_OF_2;
*(vertex++) = 1.0f / SQUARE_ROOT_OF_2;
// vertices
*(vertex++) = radius * cosf(theta);
*(vertex++) = radius * sinf(theta);
*(vertex++) = z;
}
}
glGenBuffers(1, &vbo.first);
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
delete[] vertexData;
GLushort* indexData = new GLushort[indices];
GLushort* index = indexData;
for (int i = 0; i < baseTriangles; i++) {
*(index++) = 0;
*(index++) = i + 2;
*(index++) = i + 1;
}
for (int i = 1; i <= stacks; i++) {
GLushort bottom = i * slices;
GLushort top = bottom + slices;
for (int j = 0; j < slices; j++) {
int next = (j + 1) % slices;
*(index++) = bottom + j;
*(index++) = top + next;
*(index++) = top + j;
*(index++) = bottom + j;
*(index++) = bottom + next;
*(index++) = top + next;
}
}
glGenBuffers(1, &vbo.second);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
delete[] indexData;
} else {
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
int stride = NUM_VERTICES_PER_TRIANGULATED_QUAD * sizeof(float);
glNormalPointer(GL_FLOAT, stride, 0);
glVertexPointer(NUM_COORDS_PER_VERTEX, GL_FLOAT, stride, (const void *)(NUM_COORDS_PER_VERTEX * sizeof(float)));
glPushMatrix();
glScalef(base, base, height);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void GeometryCache::renderGrid(int xDivisions, int yDivisions, const glm::vec4& color) {
gpu::Batch batch;
renderGrid(batch, xDivisions, yDivisions, color);
@ -1942,7 +1840,7 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
}
}
}
if (lod->isLoaded()) {
if (lod && lod->isLoaded()) {
hysteresis = lodDistance;
return lod;
}
@ -2061,21 +1959,16 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
if (part.diffuseTextureName == name) {
part.diffuseTexture =
textureCache->getTexture(url, DEFAULT_TEXTURE,
_geometry.meshes[i].isEye, QByteArray());
part.diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE, _geometry.meshes[i].isEye);
part.diffuseTexture->setLoadPriorities(_loadPriorities);
} else if (part.normalTextureName == name) {
part.normalTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.normalTexture = textureCache->getTexture(url);
part.normalTexture->setLoadPriorities(_loadPriorities);
} else if (part.specularTextureName == name) {
part.specularTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.specularTexture = textureCache->getTexture(url);
part.specularTexture->setLoadPriorities(_loadPriorities);
} else if (part.emissiveTextureName == name) {
part.emissiveTexture = textureCache->getTexture(url, DEFAULT_TEXTURE,
false, QByteArray());
part.emissiveTexture = textureCache->getTexture(url);
part.emissiveTexture->setLoadPriorities(_loadPriorities);
}
}
@ -2095,22 +1988,22 @@ QStringList NetworkGeometry::getTextureNames() const {
for (int j = 0; j < mesh.parts.size(); j++) {
const NetworkMeshPart& part = mesh.parts[j];
if (!part.diffuseTextureName.isEmpty()) {
if (!part.diffuseTextureName.isEmpty() && part.diffuseTexture) {
QString textureURL = part.diffuseTexture->getURL().toString();
result << part.diffuseTextureName + ":" + textureURL;
}
if (!part.normalTextureName.isEmpty()) {
if (!part.normalTextureName.isEmpty() && part.normalTexture) {
QString textureURL = part.normalTexture->getURL().toString();
result << part.normalTextureName + ":" + textureURL;
}
if (!part.specularTextureName.isEmpty()) {
if (!part.specularTextureName.isEmpty() && part.specularTexture) {
QString textureURL = part.specularTexture->getURL().toString();
result << part.specularTextureName + ":" + textureURL;
}
if (!part.emissiveTextureName.isEmpty()) {
if (!part.emissiveTextureName.isEmpty() && part.emissiveTexture) {
QString textureURL = part.emissiveTexture->getURL().toString();
result << part.emissiveTextureName + ":" + textureURL;
}

View file

@ -133,8 +133,6 @@ public:
int allocateID() { return _nextID++; }
static const int UNKNOWN_ID;
void renderCone(float base, float height, int slices, int stacks);
void renderSphere(float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID)
{ renderSphere(radius, slices, stacks, glm::vec4(color, 1.0f), solid, id); }
void renderSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec3& color, bool solid = true, int id = UNKNOWN_ID)

View file

@ -457,7 +457,8 @@ bool Model::updateGeometry() {
}
deleteGeometry();
_dilatedTextures.clear();
_geometry = geometry;
setGeometry(geometry);
_meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
@ -824,7 +825,7 @@ void Model::renderSetup(RenderArgs* args) {
}
}
if (!_meshGroupsKnown && isLoadedWithTextures()) {
if (!_meshGroupsKnown && isLoaded()) {
segregateMeshGroups();
}
}
@ -883,7 +884,7 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
if (!_meshGroupsKnown && isLoadedWithTextures()) {
if (!_meshGroupsKnown && isLoaded()) {
segregateMeshGroups();
}
@ -913,7 +914,7 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
}
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) {
if (!_meshGroupsKnown && isLoadedWithTextures()) {
if (!_meshGroupsKnown && isLoaded()) {
segregateMeshGroups();
}
@ -1142,13 +1143,32 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
onInvalidate();
// if so instructed, keep the current geometry until the new one is loaded
_nextBaseGeometry = _nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
_nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
if (!retainCurrent || !isActive() || (_nextGeometry && _nextGeometry->isLoaded())) {
applyNextGeometry();
}
}
void Model::geometryRefreshed() {
QObject* sender = QObject::sender();
if (sender == _geometry) {
_readyWhenAdded = false; // reset out render items.
_needsReload = true;
invalidCalculatedMeshBoxes();
onInvalidate();
// if so instructed, keep the current geometry until the new one is loaded
_nextGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_url);
_nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS;
applyNextGeometry();
} else {
sender->disconnect(this, SLOT(geometryRefreshed()));
}
}
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
{
@ -1156,7 +1176,11 @@ const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad);
}
return _collisionGeometry;
if (_collisionGeometry && _collisionGeometry->isLoaded()) {
return _collisionGeometry;
}
return QSharedPointer<NetworkGeometry>();
}
void Model::setCollisionModelURL(const QUrl& url) {
@ -1776,6 +1800,18 @@ void Model::setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeomet
}
}
void Model::setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry) {
if (_geometry == newGeometry) {
return;
}
if (_geometry) {
_geometry->disconnect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed);
}
_geometry = newGeometry;
QObject::connect(_geometry.data(), &Resource::onRefresh, this, &Model::geometryRefreshed);
}
void Model::applyNextGeometry() {
// delete our local geometry and custom textures
deleteGeometry();
@ -1783,13 +1819,12 @@ void Model::applyNextGeometry() {
_lodHysteresis = _nextLODHysteresis;
// we retain a reference to the base geometry so that its reference count doesn't fall to zero
_baseGeometry = _nextBaseGeometry;
_geometry = _nextGeometry;
setGeometry(_nextGeometry);
_meshGroupsKnown = false;
_readyWhenAdded = false; // in case any of our users are using scenes
_needsReload = false; // we are loaded now!
invalidCalculatedMeshBoxes();
_nextBaseGeometry.reset();
_nextGeometry.reset();
}
@ -2029,12 +2064,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
}
}
}
static bool showDiffuse = true;
if (showDiffuse && diffuseMap) {
if (diffuseMap && static_cast<NetworkTexture*>(diffuseMap)->isLoaded()) {
batch.setResourceTexture(0, diffuseMap->getGPUTexture());
} else {
batch.setResourceTexture(0, textureCache->getWhiteTexture());
batch.setResourceTexture(0, textureCache->getGrayTexture());
}
if (locations->texcoordMatrices >= 0) {
@ -2049,16 +2082,15 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
}
if (!mesh.tangents.isEmpty()) {
Texture* normalMap = networkPart.normalTexture.data();
batch.setResourceTexture(1, !normalMap ?
textureCache->getBlueTexture() : normalMap->getGPUTexture());
NetworkTexture* normalMap = networkPart.normalTexture.data();
batch.setResourceTexture(1, (!normalMap || !normalMap->isLoaded()) ?
textureCache->getBlueTexture() : normalMap->getGPUTexture());
}
if (locations->specularTextureUnit >= 0) {
Texture* specularMap = networkPart.specularTexture.data();
batch.setResourceTexture(locations->specularTextureUnit, !specularMap ?
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
NetworkTexture* specularMap = networkPart.specularTexture.data();
batch.setResourceTexture(locations->specularTextureUnit, (!specularMap || !specularMap->isLoaded()) ?
textureCache->getBlackTexture() : specularMap->getGPUTexture());
}
if (args) {
@ -2073,9 +2105,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
float emissiveScale = part.emissiveParams.y;
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
Texture* emissiveMap = networkPart.emissiveTexture.data();
batch.setResourceTexture(locations->emissiveTextureUnit, !emissiveMap ?
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
NetworkTexture* emissiveMap = networkPart.emissiveTexture.data();
batch.setResourceTexture(locations->emissiveTextureUnit, (!emissiveMap || !emissiveMap->isLoaded()) ?
textureCache->getGrayTexture() : emissiveMap->getGPUTexture());
}
if (translucent && locations->lightBufferUnit >= 0) {
@ -2188,7 +2220,7 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f
}
bool Model::initWhenReady(render::ScenePointer scene) {
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoadedWithTextures()) {
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) {
segregateMeshGroups();
render::PendingChanges pendingChanges;

View file

@ -106,6 +106,7 @@ public:
void setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scene);
bool isVisible() const { return _isVisible; }
bool isLoaded() const { return _geometry && _geometry->isLoaded(); }
bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); }
void init();
@ -116,7 +117,7 @@ public:
// new Scene/Engine rendering support
bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); }
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoadedWithTextures(); }
bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); }
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters);
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
@ -245,6 +246,7 @@ public:
protected:
QSharedPointer<NetworkGeometry> _geometry;
void setGeometry(const QSharedPointer<NetworkGeometry>& newGeometry);
glm::vec3 _scale;
glm::vec3 _offset;
@ -321,6 +323,9 @@ protected:
// hook for derived classes to be notified when setUrl invalidates the current model.
virtual void onInvalidate() {};
protected slots:
void geometryRefreshed();
private:
friend class AnimationHandle;
@ -330,15 +335,12 @@ private:
QVector<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms();
QSharedPointer<NetworkGeometry> _baseGeometry; ///< reference required to prevent collection of base
QSharedPointer<NetworkGeometry> _nextBaseGeometry;
QSharedPointer<NetworkGeometry> _nextGeometry;
float _lodDistance;
float _lodHysteresis;
float _nextLODHysteresis;
QSharedPointer<NetworkGeometry> _collisionGeometry;
QSharedPointer<NetworkGeometry> _saveNonCollisionGeometry;
float _pupilDilation;
QVector<float> _blendshapeCoefficients;
@ -524,7 +526,6 @@ private:
QMap<render::ItemID, render::PayloadPointer> _renderItems;
bool _readyWhenAdded = false;
bool _needsReload = true;
};
Q_DECLARE_METATYPE(QPointer<Model>)

View file

@ -15,54 +15,4 @@
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);
template <typename F, GLenum matrix>
void withMatrixPush(F f) {
glMatrixMode(matrix);
glPushMatrix();
f();
glPopMatrix();
}
template <typename F>
void withProjectionPush(F f) {
withMatrixPush<GL_PROJECTION>(f);
}
template <typename F>
void withProjectionIdentity(F f) {
withProjectionPush([&] {
glLoadIdentity();
f();
});
}
template <typename F>
void withProjectionMatrix(GLfloat* matrix, F f) {
withProjectionPush([&] {
glLoadMatrixf(matrix);
f();
});
}
template <typename F>
void withModelviewPush(F f) {
withMatrixPush<GL_MODELVIEW>(f);
}
template <typename F>
void withModelviewIdentity(F f) {
withModelviewPush([&] {
glLoadIdentity();
f();
});
}
template <typename F>
void withModelviewMatrix(GLfloat* matrix, F f) {
withModelviewPush([&] {
glLoadMatrixf(matrix);
f();
});
}
#endif // hifi_RenderUtil_h

View file

@ -118,9 +118,9 @@ const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() {
}
const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF };
//const unsigned char TRANSPARENT_WHITE[] = { 0xFF, 0xFF, 0xFF, 0x0 };
//const unsigned char OPAQUE_BLACK[] = { 0x0, 0x0, 0x0, 0xFF };
const unsigned char OPAQUE_GRAY[] = { 0x80, 0x80, 0x80, 0xFF };
const unsigned char OPAQUE_BLUE[] = { 0x80, 0x80, 0xFF, 0xFF };
const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF };
/*
static void loadSingleColorTexture(const unsigned char* color) {
@ -137,6 +137,14 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() {
return _whiteTexture;
}
const gpu::TexturePointer& TextureCache::getGrayTexture() {
if (!_grayTexture) {
_grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
_grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY);
}
return _grayTexture;
}
const gpu::TexturePointer& TextureCache::getBlueTexture() {
if (!_blueTexture) {
_blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
@ -145,6 +153,14 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() {
return _blueTexture;
}
const gpu::TexturePointer& TextureCache::getBlackTexture() {
if (!_blackTexture) {
_blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
_blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK);
}
return _blackTexture;
}
/// Extra data for creating textures.
class TextureExtra {
public:

View file

@ -52,9 +52,15 @@ public:
/// Returns an opaque white texture (useful for a default).
const gpu::TexturePointer& getWhiteTexture();
/// Returns an opaque gray texture (useful for a default).
const gpu::TexturePointer& getGrayTexture();
/// Returns the a pale blue texture (useful for a normal map).
const gpu::TexturePointer& getBlueTexture();
/// Returns the a black texture (useful for a default).
const gpu::TexturePointer& getBlackTexture();
/// Returns a texture version of an image file
static gpu::TexturePointer getImageTexture(const QString& path);
@ -112,7 +118,9 @@ private:
gpu::TexturePointer _permutationNormalTexture;
gpu::TexturePointer _whiteTexture;
gpu::TexturePointer _grayTexture;
gpu::TexturePointer _blueTexture;
gpu::TexturePointer _blackTexture;
QHash<QUrl, QWeakPointer<NetworkTexture> > _dilatableNetworkTextures;

View file

@ -102,13 +102,15 @@ class QQuickMenuItem;
QObject* addItem(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts
QQuickMenuItem* returnedValue{ nullptr };
#ifndef QT_NO_DEBUG
bool invokeResult =
#endif
QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection, Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(QString, text));
#ifndef QT_NO_DEBUG
Q_ASSERT(invokeResult);
#else
Q_UNUSED(invokeResult);
#endif
QObject* result = reinterpret_cast<QObject*>(returnedValue);
return result;
}
@ -206,12 +208,14 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
result = ::addItem(menu, action->text());
} else {
QQuickMenuItem* returnedValue{ nullptr };
#ifndef QT_NO_DEBUG
bool invokeResult =
#endif
QMetaObject::invokeMethod(menu, "insertItem", Qt::DirectConnection, Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(int, index), Q_ARG(QString, action->text()));
#ifndef QT_NO_DEBUG
Q_ASSERT(invokeResult);
#else
Q_UNUSED(invokeResult);
#endif
result = reinterpret_cast<QObject*>(returnedValue);
}
Q_ASSERT(result);

View file

@ -125,7 +125,6 @@ public:
DisplayModelElementProxy,
DisplayDebugTimingDetails,
DontDoPrecisionPicking,
DontFadeOnOctreeServerChanges,
DontRenderEntitiesAsScene,
EchoLocalAudio,
EchoServerAudio,