mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 16:23:16 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into fix-grabbing-problem
This commit is contained in:
commit
30b4815bf9
18 changed files with 105 additions and 634 deletions
|
@ -344,8 +344,6 @@ void Agent::scriptRequestFinished() {
|
|||
void Agent::executeScript() {
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine);
|
||||
|
||||
// setup an Avatar for the script to use
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
|
||||
|
|
|
@ -4844,12 +4844,6 @@ void Application::loadSettings() {
|
|||
|
||||
isFirstPerson = (qApp->isHMDMode());
|
||||
|
||||
// Flying should be disabled by default in HMD mode on first run, and it
|
||||
// should be enabled by default in desktop mode.
|
||||
|
||||
auto myAvatar = getMyAvatar();
|
||||
myAvatar->setFlyingEnabled(!isFirstPerson);
|
||||
|
||||
} else {
|
||||
// if this is not the first run, the camera will be initialized differently depending on user settings
|
||||
|
||||
|
@ -6201,6 +6195,9 @@ PickRay Application::computePickRay(float x, float y) const {
|
|||
getApplicationCompositor().computeHmdPickRay(pickPoint, result.origin, result.direction);
|
||||
} else {
|
||||
pickPoint /= getCanvasSize();
|
||||
if (_myCamera.getMode() == CameraMode::CAMERA_MODE_MIRROR) {
|
||||
pickPoint.x = 1.0f - pickPoint.x;
|
||||
}
|
||||
QMutexLocker viewLocker(&_viewMutex);
|
||||
_viewFrustum.computePickRay(pickPoint.x, pickPoint.y, result.origin, result.direction);
|
||||
}
|
||||
|
@ -6536,9 +6533,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
entityScriptingInterface->setPacketSender(&_entityEditSender);
|
||||
entityScriptingInterface->setEntityTree(getEntities()->getTree());
|
||||
|
||||
// give the script engine to the RecordingScriptingInterface for its callbacks
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
|
||||
|
||||
if (property(hifi::properties::TEST).isValid()) {
|
||||
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
||||
}
|
||||
|
|
|
@ -577,9 +577,11 @@ void MyAvatar::updateChildCauterization(SpatiallyNestablePointer object, bool ca
|
|||
|
||||
void MyAvatar::simulate(float deltaTime) {
|
||||
PerformanceTimer perfTimer("simulate");
|
||||
|
||||
|
||||
animateScaleChanges(deltaTime);
|
||||
|
||||
setFlyingEnabled(getFlyingEnabled());
|
||||
|
||||
if (_cauterizationNeedsUpdate) {
|
||||
_cauterizationNeedsUpdate = false;
|
||||
|
||||
|
@ -724,16 +726,18 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
properties.setQueryAACubeDirty();
|
||||
properties.setLastEdited(now);
|
||||
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entity->getID(), properties);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree,
|
||||
entity->getID(), properties);
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
|
||||
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
|
||||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
if (!entityDescendant->getClientOnly() && descendant->updateQueryAACube()) {
|
||||
EntityItemPointer entityDescendant = std::dynamic_pointer_cast<EntityItem>(descendant);
|
||||
if (entityDescendant && !entityDescendant->getClientOnly() && descendant->updateQueryAACube()) {
|
||||
EntityItemProperties descendantProperties;
|
||||
descendantProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
descendantProperties.setLastEdited(now);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entityDescendant->getID(), descendantProperties);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree,
|
||||
entityDescendant->getID(), descendantProperties);
|
||||
entityDescendant->setLastBroadcast(now); // for debug/physics status icons
|
||||
}
|
||||
});
|
||||
|
@ -1131,6 +1135,8 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("userHeight", getUserHeight());
|
||||
settings.setValue("flyingDesktop", getFlyingDesktopPref());
|
||||
settings.setValue("flyingHMD", getFlyingHMDPref());
|
||||
settings.setValue("enabledFlying", getFlyingEnabled());
|
||||
|
||||
settings.endGroup();
|
||||
|
@ -1281,8 +1287,13 @@ void MyAvatar::loadData() {
|
|||
settings.remove("avatarEntityData");
|
||||
}
|
||||
setAvatarEntityDataChanged(true);
|
||||
|
||||
// Flying preferences must be loaded before calling setFlyingEnabled()
|
||||
Setting::Handle<bool> firstRunVal { Settings::firstRun, true };
|
||||
setFlyingEnabled(firstRunVal.get() ? getFlyingEnabled() : settings.value("enabledFlying").toBool());
|
||||
setFlyingDesktopPref(firstRunVal.get() ? true : settings.value("flyingDesktop").toBool());
|
||||
setFlyingHMDPref(firstRunVal.get() ? false : settings.value("flyingHMD").toBool());
|
||||
setFlyingEnabled(getFlyingEnabled());
|
||||
|
||||
setDisplayName(settings.value("displayName").toString());
|
||||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||
|
@ -2825,6 +2836,12 @@ void MyAvatar::setFlyingEnabled(bool enabled) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (qApp->isHMDMode()) {
|
||||
setFlyingHMDPref(enabled);
|
||||
} else {
|
||||
setFlyingDesktopPref(enabled);
|
||||
}
|
||||
|
||||
_enableFlying = enabled;
|
||||
}
|
||||
|
||||
|
@ -2840,7 +2857,33 @@ bool MyAvatar::isInAir() {
|
|||
|
||||
bool MyAvatar::getFlyingEnabled() {
|
||||
// May return true even if client is not allowed to fly in the zone.
|
||||
return _enableFlying;
|
||||
return (qApp->isHMDMode() ? getFlyingHMDPref() : getFlyingDesktopPref());
|
||||
}
|
||||
|
||||
void MyAvatar::setFlyingDesktopPref(bool enabled) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setFlyingDesktopPref", Q_ARG(bool, enabled));
|
||||
return;
|
||||
}
|
||||
|
||||
_flyingPrefDesktop = enabled;
|
||||
}
|
||||
|
||||
bool MyAvatar::getFlyingDesktopPref() {
|
||||
return _flyingPrefDesktop;
|
||||
}
|
||||
|
||||
void MyAvatar::setFlyingHMDPref(bool enabled) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setFlyingHMDPref", Q_ARG(bool, enabled));
|
||||
return;
|
||||
}
|
||||
|
||||
_flyingPrefHMD = enabled;
|
||||
}
|
||||
|
||||
bool MyAvatar::getFlyingHMDPref() {
|
||||
return _flyingPrefHMD;
|
||||
}
|
||||
|
||||
// Public interface for targetscale
|
||||
|
@ -3042,7 +3085,7 @@ static glm::vec3 dampenCgMovement(glm::vec3 cgUnderHeadHandsAvatarSpace, float b
|
|||
}
|
||||
|
||||
// computeCounterBalance returns the center of gravity in Avatar space
|
||||
glm::vec3 MyAvatar::computeCounterBalance() const {
|
||||
glm::vec3 MyAvatar::computeCounterBalance() {
|
||||
struct JointMass {
|
||||
QString name;
|
||||
float weight;
|
||||
|
@ -3060,7 +3103,8 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
JointMass cgLeftHandMass(QString("LeftHand"), DEFAULT_AVATAR_LEFTHAND_MASS, glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
JointMass cgRightHandMass(QString("RightHand"), DEFAULT_AVATAR_RIGHTHAND_MASS, glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
glm::vec3 tposeHead = DEFAULT_AVATAR_HEAD_POS;
|
||||
glm::vec3 tposeHips = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
glm::vec3 tposeHips = DEFAULT_AVATAR_HIPS_POS;
|
||||
glm::vec3 tposeRightFoot = DEFAULT_AVATAR_RIGHTFOOT_POS;
|
||||
|
||||
if (_skeletonModel->getRig().indexOfJoint(cgHeadMass.name) != -1) {
|
||||
cgHeadMass.position = getAbsoluteJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint(cgHeadMass.name));
|
||||
|
@ -3079,6 +3123,9 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
if (_skeletonModel->getRig().indexOfJoint("Hips") != -1) {
|
||||
tposeHips = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("Hips"));
|
||||
}
|
||||
if (_skeletonModel->getRig().indexOfJoint("RightFoot") != -1) {
|
||||
tposeRightFoot = getAbsoluteDefaultJointTranslationInObjectFrame(_skeletonModel->getRig().indexOfJoint("RightFoot"));
|
||||
}
|
||||
|
||||
// find the current center of gravity position based on head and hand moments
|
||||
glm::vec3 sumOfMoments = (cgHeadMass.weight * cgHeadMass.position) + (cgLeftHandMass.weight * cgLeftHandMass.position) + (cgRightHandMass.weight * cgRightHandMass.position);
|
||||
|
@ -3099,9 +3146,12 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
glm::vec3 counterBalancedCg = (1.0f / DEFAULT_AVATAR_HIPS_MASS) * counterBalancedForHead;
|
||||
|
||||
// find the height of the hips
|
||||
const float UPPER_LEG_FRACTION = 0.3333f;
|
||||
glm::vec3 xzDiff((cgHeadMass.position.x - counterBalancedCg.x), 0.0f, (cgHeadMass.position.z - counterBalancedCg.z));
|
||||
float headMinusHipXz = glm::length(xzDiff);
|
||||
float headHipDefault = glm::length(tposeHead - tposeHips);
|
||||
float hipFootDefault = tposeHips.y - tposeRightFoot.y;
|
||||
float sitSquatThreshold = tposeHips.y - (UPPER_LEG_FRACTION * hipFootDefault);
|
||||
float hipHeight = 0.0f;
|
||||
if (headHipDefault > headMinusHipXz) {
|
||||
hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz));
|
||||
|
@ -3113,6 +3163,10 @@ glm::vec3 MyAvatar::computeCounterBalance() const {
|
|||
if (counterBalancedCg.y > (tposeHips.y + 0.05f)) {
|
||||
// if the height is higher than default hips, clamp to default hips
|
||||
counterBalancedCg.y = tposeHips.y + 0.05f;
|
||||
} else if (counterBalancedCg.y < sitSquatThreshold) {
|
||||
//do a height reset
|
||||
setResetMode(true);
|
||||
_follow.activate(FollowHelper::Vertical);
|
||||
}
|
||||
return counterBalancedCg;
|
||||
}
|
||||
|
@ -3162,7 +3216,7 @@ static void drawBaseOfSupport(float baseOfSupportScale, float footLocal, glm::ma
|
|||
// this function finds the hips position using a center of gravity model that
|
||||
// balances the head and hands with the hips over the base of support
|
||||
// returns the rotation (-z forward) and position of the Avatar in Sensor space
|
||||
glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
||||
glm::mat4 MyAvatar::deriveBodyUsingCgModel() {
|
||||
glm::mat4 sensorToWorldMat = getSensorToWorldMatrix();
|
||||
glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat);
|
||||
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
|
@ -3180,7 +3234,7 @@ glm::mat4 MyAvatar::deriveBodyUsingCgModel() const {
|
|||
}
|
||||
|
||||
// get the new center of gravity
|
||||
const glm::vec3 cgHipsPosition = computeCounterBalance();
|
||||
glm::vec3 cgHipsPosition = computeCounterBalance();
|
||||
|
||||
// find the new hips rotation using the new head-hips axis as the up axis
|
||||
glm::mat4 avatarHipsMat = computeNewHipsMatrix(glmExtractRotation(avatarHeadMat), extractTranslation(avatarHeadMat), cgHipsPosition);
|
||||
|
|
|
@ -955,6 +955,30 @@ public:
|
|||
*/
|
||||
Q_INVOKABLE bool getFlyingEnabled();
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setFlyingDesktopPref
|
||||
* @param {boolean} enabled
|
||||
*/
|
||||
Q_INVOKABLE void setFlyingDesktopPref(bool enabled);
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.getFlyingDesktopPref
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Q_INVOKABLE bool getFlyingDesktopPref();
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.setFlyingDesktopPref
|
||||
* @param {boolean} enabled
|
||||
*/
|
||||
Q_INVOKABLE void setFlyingHMDPref(bool enabled);
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.getFlyingDesktopPref
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Q_INVOKABLE bool getFlyingHMDPref();
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.getAvatarScale
|
||||
|
@ -1019,12 +1043,12 @@ public:
|
|||
// results are in sensor frame (-z forward)
|
||||
glm::mat4 deriveBodyFromHMDSensor() const;
|
||||
|
||||
glm::vec3 computeCounterBalance() const;
|
||||
glm::vec3 computeCounterBalance();
|
||||
|
||||
// derive avatar body position and orientation from using the current HMD Sensor location in relation to the previous
|
||||
// location of the base of support of the avatar.
|
||||
// results are in sensor frame (-z foward)
|
||||
glm::mat4 deriveBodyUsingCgModel() const;
|
||||
glm::mat4 deriveBodyUsingCgModel();
|
||||
|
||||
/**jsdoc
|
||||
* @function MyAvatar.isUp
|
||||
|
@ -1505,6 +1529,8 @@ private:
|
|||
std::bitset<MAX_DRIVE_KEYS> _disabledDriveKeys;
|
||||
|
||||
bool _enableFlying { false };
|
||||
bool _flyingPrefDesktop { true };
|
||||
bool _flyingPrefHMD { false };
|
||||
bool _wasPushing { false };
|
||||
bool _isPushing { false };
|
||||
bool _isBeingPushed { false };
|
||||
|
|
|
@ -313,8 +313,8 @@ void setupPreferences() {
|
|||
getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->bool { return myAvatar->getFlyingEnabled(); };
|
||||
auto setter = [=](bool value) { myAvatar->setFlyingEnabled(value); };
|
||||
auto getter = [=]()->bool { return myAvatar->getFlyingHMDPref(); };
|
||||
auto setter = [=](bool value) { myAvatar->setFlyingHMDPref(value); };
|
||||
preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Flying & jumping", getter, setter));
|
||||
}
|
||||
{
|
||||
|
|
|
@ -699,14 +699,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
adjustShapeInfoByRegistration(shapeInfo);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) {
|
||||
const void* key = static_cast<const void*>(shape);
|
||||
if (_collisionMeshKey != key) {
|
||||
_collisionMeshKey = key;
|
||||
emit requestCollisionGeometryUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setJointMap(std::vector<int> jointMap) {
|
||||
if (jointMap.size() > 0) {
|
||||
_jointMap = jointMap;
|
||||
|
@ -1278,10 +1270,6 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
return false;
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
|
||||
_collisionMeshKey = key;
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
|
||||
if (_hasModel != entity->hasModel()) {
|
||||
|
|
|
@ -78,8 +78,6 @@ public:
|
|||
virtual bool isReadyToComputeShape() const override;
|
||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo) override;
|
||||
|
||||
void setCollisionShape(const btCollisionShape* shape) override;
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const override;
|
||||
void stopModelOverrideIfNoParent();
|
||||
|
||||
|
@ -112,10 +110,6 @@ public:
|
|||
virtual QStringList getJointNames() const override;
|
||||
|
||||
bool getMeshes(MeshProxyList& result) override; // deprecated
|
||||
const void* getCollisionMeshKey() const { return _collisionMeshKey; }
|
||||
|
||||
signals:
|
||||
void requestCollisionGeometryUpdate();
|
||||
|
||||
private:
|
||||
bool needsUpdateModelBounds() const;
|
||||
|
@ -130,7 +124,6 @@ private:
|
|||
QVariantMap _originalTextures;
|
||||
bool _dimensionsInitialized { true };
|
||||
bool _needsJointSimulation { false };
|
||||
const void* _collisionMeshKey { nullptr };
|
||||
};
|
||||
|
||||
namespace render { namespace entities {
|
||||
|
@ -161,7 +154,6 @@ protected:
|
|||
virtual bool needsRenderUpdate() const override;
|
||||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||
void setCollisionMeshKey(const void* key);
|
||||
|
||||
render::hifi::Tag getTagMask() const override;
|
||||
|
||||
|
|
|
@ -378,8 +378,6 @@ public:
|
|||
/// return preferred shape type (actual physical shape may differ)
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
||||
|
||||
virtual void setCollisionShape(const btCollisionShape* shape) {}
|
||||
|
||||
void setPosition(const glm::vec3& value);
|
||||
virtual void setParentID(const QUuid& parentID) override;
|
||||
virtual void setShapeType(ShapeType type) { /* do nothing */ }
|
||||
|
|
|
@ -1,217 +0,0 @@
|
|||
//
|
||||
// CollisionRenderMeshCache.cpp
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows 2016.07.13
|
||||
// Copyright 2016 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 "CollisionRenderMeshCache.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletCollision/CollisionShapes/btShapeHull.h>
|
||||
|
||||
#include <ShapeInfo.h> // for MAX_HULL_POINTS
|
||||
|
||||
const int32_t MAX_HULL_INDICES = 6 * MAX_HULL_POINTS;
|
||||
const int32_t MAX_HULL_NORMALS = MAX_HULL_INDICES;
|
||||
float tempVertices[MAX_HULL_NORMALS];
|
||||
graphics::Index tempIndexBuffer[MAX_HULL_INDICES];
|
||||
|
||||
bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape,
|
||||
gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts,
|
||||
gpu::BufferView& normals) {
|
||||
assert(shape);
|
||||
|
||||
btShapeHull hull(shape);
|
||||
if (!hull.buildHull(shape->getMargin())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t numHullIndices = hull.numIndices();
|
||||
assert(numHullIndices <= MAX_HULL_INDICES);
|
||||
|
||||
int32_t numHullVertices = hull.numVertices();
|
||||
assert(numHullVertices <= MAX_HULL_POINTS);
|
||||
|
||||
{ // new part
|
||||
graphics::Mesh::Part part;
|
||||
part._startIndex = (graphics::Index)indices.getNumElements();
|
||||
part._numIndices = (graphics::Index)numHullIndices;
|
||||
// FIXME: the render code cannot handle the case where part._baseVertex != 0
|
||||
//part._baseVertex = vertices.getNumElements(); // DOES NOT WORK
|
||||
part._baseVertex = 0;
|
||||
|
||||
gpu::BufferView::Size numBytes = sizeof(graphics::Mesh::Part);
|
||||
const gpu::Byte* data = reinterpret_cast<const gpu::Byte*>(&part);
|
||||
parts._buffer->append(numBytes, data);
|
||||
parts._size = parts._buffer->getSize();
|
||||
}
|
||||
|
||||
const int32_t SIZE_OF_VEC3 = 3 * sizeof(float);
|
||||
graphics::Index indexOffset = (graphics::Index)vertices.getNumElements();
|
||||
|
||||
{ // new indices
|
||||
const uint32_t* hullIndices = hull.getIndexPointer();
|
||||
// FIXME: the render code cannot handle the case where part._baseVertex != 0
|
||||
// so we must add an offset to each index
|
||||
for (int32_t i = 0; i < numHullIndices; ++i) {
|
||||
tempIndexBuffer[i] = hullIndices[i] + indexOffset;
|
||||
}
|
||||
const gpu::Byte* data = reinterpret_cast<const gpu::Byte*>(tempIndexBuffer);
|
||||
gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(graphics::Index) * numHullIndices);
|
||||
indices._buffer->append(numBytes, data);
|
||||
indices._size = indices._buffer->getSize();
|
||||
}
|
||||
{ // new vertices
|
||||
const btVector3* hullVertices = hull.getVertexPointer();
|
||||
assert(numHullVertices <= MAX_HULL_POINTS);
|
||||
for (int32_t i = 0; i < numHullVertices; ++i) {
|
||||
btVector3 transformedPoint = transform * hullVertices[i];
|
||||
memcpy(tempVertices + 3 * i, transformedPoint.m_floats, SIZE_OF_VEC3);
|
||||
}
|
||||
gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices);
|
||||
const gpu::Byte* data = reinterpret_cast<const gpu::Byte*>(tempVertices);
|
||||
vertices._buffer->append(numBytes, data);
|
||||
vertices._size = vertices._buffer->getSize();
|
||||
}
|
||||
{ // new normals
|
||||
// compute average point
|
||||
btVector3 avgVertex(0.0f, 0.0f, 0.0f);
|
||||
const btVector3* hullVertices = hull.getVertexPointer();
|
||||
for (int i = 0; i < numHullVertices; ++i) {
|
||||
avgVertex += hullVertices[i];
|
||||
}
|
||||
avgVertex = transform * (avgVertex * (1.0f / (float)numHullVertices));
|
||||
|
||||
for (int i = 0; i < numHullVertices; ++i) {
|
||||
btVector3 norm = transform * hullVertices[i] - avgVertex;
|
||||
btScalar normLength = norm.length();
|
||||
if (normLength > FLT_EPSILON) {
|
||||
norm /= normLength;
|
||||
}
|
||||
memcpy(tempVertices + 3 * i, norm.m_floats, SIZE_OF_VEC3);
|
||||
}
|
||||
gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices);
|
||||
const gpu::Byte* data = reinterpret_cast<const gpu::Byte*>(tempVertices);
|
||||
normals._buffer->append(numBytes, data);
|
||||
normals._size = vertices._buffer->getSize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
graphics::MeshPointer createMeshFromShape(const void* pointer) {
|
||||
graphics::MeshPointer mesh;
|
||||
if (!pointer) {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// pointer must be a const btCollisionShape* (cast to void*), but it only
|
||||
// needs to be valid here when its render mesh is created, after this call
|
||||
// the cache doesn't care what happens to the shape behind the pointer
|
||||
const btCollisionShape* shape = static_cast<const btCollisionShape*>(pointer);
|
||||
|
||||
int32_t shapeType = shape->getShapeType();
|
||||
if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) {
|
||||
// allocate buffers for it
|
||||
gpu::BufferView vertices(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
gpu::BufferView indices(new gpu::Buffer(), gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::INDEX));
|
||||
gpu::BufferView parts(new gpu::Buffer(), gpu::Element(gpu::VEC4, gpu::UINT32, gpu::PART));
|
||||
gpu::BufferView normals(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
|
||||
|
||||
int32_t numSuccesses = 0;
|
||||
if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) {
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
|
||||
int32_t numSubShapes = compoundShape->getNumChildShapes();
|
||||
for (int32_t i = 0; i < numSubShapes; ++i) {
|
||||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
if (childShape->isConvex()) {
|
||||
const btConvexShape* convexShape = static_cast<const btConvexShape*>(childShape);
|
||||
if (copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts, normals)) {
|
||||
numSuccesses++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// shape is convex
|
||||
const btConvexShape* convexShape = static_cast<const btConvexShape*>(shape);
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
if (copyShapeToMesh(transform, convexShape, vertices, indices, parts, normals)) {
|
||||
numSuccesses++;
|
||||
}
|
||||
}
|
||||
if (numSuccesses > 0) {
|
||||
mesh = std::make_shared<graphics::Mesh>();
|
||||
mesh->setVertexBuffer(vertices);
|
||||
mesh->setIndexBuffer(indices);
|
||||
mesh->setPartBuffer(parts);
|
||||
mesh->addAttribute(gpu::Stream::NORMAL, normals);
|
||||
} else {
|
||||
// TODO: log failure message here
|
||||
}
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
CollisionRenderMeshCache::CollisionRenderMeshCache() {
|
||||
}
|
||||
|
||||
CollisionRenderMeshCache::~CollisionRenderMeshCache() {
|
||||
_meshMap.clear();
|
||||
_pendingGarbage.clear();
|
||||
}
|
||||
|
||||
graphics::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) {
|
||||
graphics::MeshPointer mesh;
|
||||
if (key) {
|
||||
CollisionMeshMap::const_iterator itr = _meshMap.find(key);
|
||||
if (itr == _meshMap.end()) {
|
||||
// make mesh and add it to map
|
||||
mesh = createMeshFromShape(key);
|
||||
if (mesh) {
|
||||
_meshMap.insert(std::make_pair(key, mesh));
|
||||
}
|
||||
} else {
|
||||
mesh = itr->second;
|
||||
}
|
||||
}
|
||||
const uint32_t MAX_NUM_PENDING_GARBAGE = 20;
|
||||
if (_pendingGarbage.size() > MAX_NUM_PENDING_GARBAGE) {
|
||||
collectGarbage();
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) {
|
||||
if (!key) {
|
||||
return false;
|
||||
}
|
||||
CollisionMeshMap::const_iterator itr = _meshMap.find(key);
|
||||
if (itr != _meshMap.end()) {
|
||||
_pendingGarbage.push_back(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CollisionRenderMeshCache::collectGarbage() {
|
||||
uint32_t numShapes = (uint32_t)_pendingGarbage.size();
|
||||
for (uint32_t i = 0; i < numShapes; ++i) {
|
||||
CollisionRenderMeshCache::Key key = _pendingGarbage[i];
|
||||
CollisionMeshMap::const_iterator itr = _meshMap.find(key);
|
||||
if (itr != _meshMap.end()) {
|
||||
if ((*itr).second.use_count() == 1) {
|
||||
// we hold the only reference
|
||||
_meshMap.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
_pendingGarbage.clear();
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
//
|
||||
// CollisionRenderMeshCache.h
|
||||
// libraries/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows 2016.07.13
|
||||
// Copyright 2016 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_CollisionRenderMeshCache_h
|
||||
#define hifi_CollisionRenderMeshCache_h
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <graphics/Geometry.h>
|
||||
|
||||
|
||||
class CollisionRenderMeshCache {
|
||||
public:
|
||||
using Key = const void*; // must actually be a const btCollisionShape*
|
||||
|
||||
CollisionRenderMeshCache();
|
||||
~CollisionRenderMeshCache();
|
||||
|
||||
/// \return pointer to geometry
|
||||
graphics::MeshPointer getMesh(Key key);
|
||||
|
||||
/// \return true if geometry was found and released
|
||||
bool releaseMesh(Key key);
|
||||
|
||||
/// delete geometries that have zero references
|
||||
void collectGarbage();
|
||||
|
||||
// validation methods
|
||||
uint32_t getNumMeshes() const { return (uint32_t)_meshMap.size(); }
|
||||
bool hasMesh(Key key) const { return _meshMap.find(key) == _meshMap.end(); }
|
||||
|
||||
private:
|
||||
using CollisionMeshMap = std::unordered_map<Key, graphics::MeshPointer>;
|
||||
CollisionMeshMap _meshMap;
|
||||
std::vector<Key> _pendingGarbage;
|
||||
};
|
||||
|
||||
#endif // hifi_CollisionRenderMeshCache_h
|
|
@ -307,13 +307,6 @@ const btCollisionShape* EntityMotionState::computeNewShape() {
|
|||
return getShapeManager()->getShape(shapeInfo);
|
||||
}
|
||||
|
||||
void EntityMotionState::setShape(const btCollisionShape* shape) {
|
||||
if (_shape != shape) {
|
||||
ObjectMotionState::setShape(shape);
|
||||
_entity->setCollisionShape(_shape);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||
// NOTE: this method is only ever called when the entity simulation is locally owned
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "CheckOutOfSync");
|
||||
|
|
|
@ -118,7 +118,6 @@ protected:
|
|||
|
||||
bool isReadyToComputeShape() const override;
|
||||
const btCollisionShape* computeNewShape() override;
|
||||
void setShape(const btCollisionShape* shape) override;
|
||||
void setMotionType(PhysicsMotionType motionType) override;
|
||||
|
||||
// EntityMotionState keeps a SharedPointer to its EntityItem which is only set in the CTOR
|
||||
|
|
|
@ -59,7 +59,7 @@ void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader,
|
|||
|
||||
if (callback.isFunction()) {
|
||||
QScriptValueList args { true, url };
|
||||
callback.call(_scriptEngine->globalObject(), args);
|
||||
callback.call(QScriptValue(), args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue
|
|||
auto weakClipLoader = clipLoader.toWeakRef();
|
||||
|
||||
// when clip loaded, call the callback with the URL and success boolean
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this,
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, callback.engine(),
|
||||
[this, weakClipLoader, url, callback]() mutable {
|
||||
|
||||
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||
|
@ -92,12 +92,12 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue
|
|||
});
|
||||
|
||||
// when clip load fails, call the callback with the URL and failure boolean
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::failed, this, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable {
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::failed, callback.engine(), [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable {
|
||||
qCDebug(scriptengine) << "Failed to load recording from" << url;
|
||||
|
||||
if (callback.isFunction()) {
|
||||
QScriptValueList args { false, url };
|
||||
callback.call(_scriptEngine->currentContext()->thisObject(), args);
|
||||
callback.call(QScriptValue(), args);
|
||||
}
|
||||
|
||||
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||
|
|
|
@ -36,8 +36,6 @@ class RecordingScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
RecordingScriptingInterface();
|
||||
|
||||
void setScriptEngine(QSharedPointer<BaseScriptEngine> scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
public slots:
|
||||
|
||||
/**jsdoc
|
||||
|
@ -246,7 +244,6 @@ protected:
|
|||
Flag _useSkeletonModel { false };
|
||||
recording::ClipPointer _lastClip;
|
||||
|
||||
QSharedPointer<BaseScriptEngine> _scriptEngine;
|
||||
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
|
||||
|
||||
private:
|
||||
|
|
|
@ -23,10 +23,10 @@ const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_E
|
|||
const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f;
|
||||
const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f;
|
||||
const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f;
|
||||
const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.10f;
|
||||
const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.12f;
|
||||
const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.10f;
|
||||
const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.04f;
|
||||
const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.07f;
|
||||
const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.05f;
|
||||
const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.3f;
|
||||
const float DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD = -0.02f;
|
||||
const float DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD = 0.4f;
|
||||
|
|
|
@ -325,7 +325,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
} else if (target === TARGET.SURFACE) {
|
||||
var offset = getAvatarFootOffset();
|
||||
result.intersection.y += offset;
|
||||
MyAvatar.goToLocation(result.intersection, false, {x: 0, y: 0, z: 0, w: 1}, false);
|
||||
MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false);
|
||||
HMD.centerUI();
|
||||
MyAvatar.centerBody();
|
||||
}
|
||||
|
|
|
@ -1,277 +0,0 @@
|
|||
//
|
||||
// CollisionRenderMeshCacheTests.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.10.30
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "CollisionRenderMeshCacheTests.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletCollision/CollisionShapes/btShapeHull.h>
|
||||
|
||||
#include <CollisionRenderMeshCache.h>
|
||||
#include <ShapeInfo.h> // for MAX_HULL_POINTS
|
||||
|
||||
#include "MeshUtil.h"
|
||||
|
||||
|
||||
QTEST_MAIN(CollisionRenderMeshCacheTests)
|
||||
|
||||
const float INV_SQRT_THREE = 0.577350269f;
|
||||
|
||||
const uint32_t numSphereDirections = 6 + 8;
|
||||
btVector3 sphereDirections[] = {
|
||||
btVector3(1.0f, 0.0f, 0.0f),
|
||||
btVector3(-1.0f, 0.0f, 0.0f),
|
||||
btVector3(0.0f, 1.0f, 0.0f),
|
||||
btVector3(0.0f, -1.0f, 0.0f),
|
||||
btVector3(0.0f, 0.0f, 1.0f),
|
||||
btVector3(0.0f, 0.0f, -1.0f),
|
||||
btVector3(INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE),
|
||||
btVector3(INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE),
|
||||
btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE),
|
||||
btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE),
|
||||
btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE),
|
||||
btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE),
|
||||
btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE),
|
||||
btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE)
|
||||
};
|
||||
|
||||
float randomFloat() {
|
||||
return 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f;
|
||||
}
|
||||
|
||||
btBoxShape* createBoxShape(const btVector3& extent) {
|
||||
btBoxShape* shape = new btBoxShape(0.5f * extent);
|
||||
return shape;
|
||||
}
|
||||
|
||||
btConvexHullShape* createConvexHull(float radius) {
|
||||
btConvexHullShape* hull = new btConvexHullShape();
|
||||
for (uint32_t i = 0; i < numSphereDirections; ++i) {
|
||||
btVector3 point = radius * sphereDirections[i];
|
||||
hull->addPoint(point, false);
|
||||
}
|
||||
hull->recalcLocalAabb();
|
||||
return hull;
|
||||
}
|
||||
|
||||
void CollisionRenderMeshCacheTests::testShapeHullManifold() {
|
||||
// make a box shape
|
||||
btVector3 extent(1.0f, 2.0f, 3.0f);
|
||||
btBoxShape* box = createBoxShape(extent);
|
||||
|
||||
// wrap it with a ShapeHull
|
||||
btShapeHull hull(box);
|
||||
const float MARGIN = 0.0f;
|
||||
hull.buildHull(MARGIN);
|
||||
|
||||
// verify the vertex count is capped
|
||||
uint32_t numVertices = (uint32_t)hull.numVertices();
|
||||
QVERIFY(numVertices <= MAX_HULL_POINTS);
|
||||
|
||||
// verify the mesh is inside the radius
|
||||
btVector3 halfExtents = box->getHalfExtentsWithMargin();
|
||||
float ACCEPTABLE_EXTENTS_ERROR = 0.01f;
|
||||
float maxRadius = halfExtents.length() + ACCEPTABLE_EXTENTS_ERROR;
|
||||
const btVector3* meshVertices = hull.getVertexPointer();
|
||||
for (uint32_t i = 0; i < numVertices; ++i) {
|
||||
btVector3 vertex = meshVertices[i];
|
||||
QVERIFY(vertex.length() <= maxRadius);
|
||||
}
|
||||
|
||||
// verify the index count is capped
|
||||
uint32_t numIndices = (uint32_t)hull.numIndices();
|
||||
QVERIFY(numIndices < 6 * MAX_HULL_POINTS);
|
||||
|
||||
// verify the index count is a multiple of 3
|
||||
QVERIFY(numIndices % 3 == 0);
|
||||
|
||||
// verify the mesh is closed
|
||||
const uint32_t* meshIndices = hull.getIndexPointer();
|
||||
bool isClosed = MeshUtil::isClosedManifold(meshIndices, numIndices);
|
||||
QVERIFY(isClosed);
|
||||
|
||||
// verify the triangle normals are outward using right-hand-rule
|
||||
const uint32_t INDICES_PER_TRIANGLE = 3;
|
||||
for (uint32_t i = 0; i < numIndices; i += INDICES_PER_TRIANGLE) {
|
||||
btVector3 A = meshVertices[meshIndices[i]];
|
||||
btVector3 B = meshVertices[meshIndices[i+1]];
|
||||
btVector3 C = meshVertices[meshIndices[i+2]];
|
||||
|
||||
btVector3 face = (B - A).cross(C - B);
|
||||
btVector3 center = (A + B + C) / 3.0f;
|
||||
QVERIFY(face.dot(center) > 0.0f);
|
||||
}
|
||||
|
||||
// delete unmanaged memory
|
||||
delete box;
|
||||
}
|
||||
|
||||
void CollisionRenderMeshCacheTests::testCompoundShape() {
|
||||
uint32_t numSubShapes = 3;
|
||||
|
||||
btVector3 centers[] = {
|
||||
btVector3(1.0f, 0.0f, 0.0f),
|
||||
btVector3(0.0f, -2.0f, 0.0f),
|
||||
btVector3(0.0f, 0.0f, 3.0f),
|
||||
};
|
||||
|
||||
float radii[] = { 3.0f, 2.0f, 1.0f };
|
||||
|
||||
btCompoundShape* compoundShape = new btCompoundShape();
|
||||
for (uint32_t i = 0; i < numSubShapes; ++i) {
|
||||
btTransform transform;
|
||||
transform.setOrigin(centers[i]);
|
||||
btConvexHullShape* hull = createConvexHull(radii[i]);
|
||||
compoundShape->addChildShape(transform, hull);
|
||||
}
|
||||
|
||||
// create the cache
|
||||
CollisionRenderMeshCache cache;
|
||||
QVERIFY(cache.getNumMeshes() == 0);
|
||||
|
||||
// get the mesh once
|
||||
graphics::MeshPointer mesh = cache.getMesh(compoundShape);
|
||||
QVERIFY((bool)mesh);
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
|
||||
// get the mesh again
|
||||
graphics::MeshPointer mesh2 = cache.getMesh(compoundShape);
|
||||
QVERIFY(mesh2 == mesh);
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
|
||||
// forget the mesh once
|
||||
cache.releaseMesh(compoundShape);
|
||||
mesh.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
|
||||
// collect garbage (should still cache mesh)
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
|
||||
// forget the mesh a second time (should still cache mesh)
|
||||
cache.releaseMesh(compoundShape);
|
||||
mesh2.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
|
||||
// collect garbage (should no longer cache mesh)
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 0);
|
||||
|
||||
// delete unmanaged memory
|
||||
for (int i = 0; i < compoundShape->getNumChildShapes(); ++i) {
|
||||
delete compoundShape->getChildShape(i);
|
||||
}
|
||||
delete compoundShape;
|
||||
}
|
||||
|
||||
void CollisionRenderMeshCacheTests::testMultipleShapes() {
|
||||
// shapeA is compound of hulls
|
||||
uint32_t numSubShapes = 3;
|
||||
btVector3 centers[] = {
|
||||
btVector3(1.0f, 0.0f, 0.0f),
|
||||
btVector3(0.0f, -2.0f, 0.0f),
|
||||
btVector3(0.0f, 0.0f, 3.0f),
|
||||
};
|
||||
float radii[] = { 3.0f, 2.0f, 1.0f };
|
||||
btCompoundShape* shapeA = new btCompoundShape();
|
||||
for (uint32_t i = 0; i < numSubShapes; ++i) {
|
||||
btTransform transform;
|
||||
transform.setOrigin(centers[i]);
|
||||
btConvexHullShape* hull = createConvexHull(radii[i]);
|
||||
shapeA->addChildShape(transform, hull);
|
||||
}
|
||||
|
||||
// shapeB is compound of boxes
|
||||
btVector3 extents[] = {
|
||||
btVector3(1.0f, 2.0f, 3.0f),
|
||||
btVector3(2.0f, 3.0f, 1.0f),
|
||||
btVector3(3.0f, 1.0f, 2.0f),
|
||||
};
|
||||
btCompoundShape* shapeB = new btCompoundShape();
|
||||
for (uint32_t i = 0; i < numSubShapes; ++i) {
|
||||
btTransform transform;
|
||||
transform.setOrigin(centers[i]);
|
||||
btBoxShape* box = createBoxShape(extents[i]);
|
||||
shapeB->addChildShape(transform, box);
|
||||
}
|
||||
|
||||
// shapeC is just a box
|
||||
btVector3 extentC(7.0f, 3.0f, 5.0f);
|
||||
btBoxShape* shapeC = createBoxShape(extentC);
|
||||
|
||||
// create the cache
|
||||
CollisionRenderMeshCache cache;
|
||||
QVERIFY(cache.getNumMeshes() == 0);
|
||||
|
||||
// get the meshes
|
||||
graphics::MeshPointer meshA = cache.getMesh(shapeA);
|
||||
graphics::MeshPointer meshB = cache.getMesh(shapeB);
|
||||
graphics::MeshPointer meshC = cache.getMesh(shapeC);
|
||||
QVERIFY((bool)meshA);
|
||||
QVERIFY((bool)meshB);
|
||||
QVERIFY((bool)meshC);
|
||||
QVERIFY(cache.getNumMeshes() == 3);
|
||||
|
||||
// get the meshes again
|
||||
graphics::MeshPointer meshA2 = cache.getMesh(shapeA);
|
||||
graphics::MeshPointer meshB2 = cache.getMesh(shapeB);
|
||||
graphics::MeshPointer meshC2 = cache.getMesh(shapeC);
|
||||
QVERIFY(meshA == meshA2);
|
||||
QVERIFY(meshB == meshB2);
|
||||
QVERIFY(meshC == meshC2);
|
||||
QVERIFY(cache.getNumMeshes() == 3);
|
||||
|
||||
// forget the meshes once
|
||||
cache.releaseMesh(shapeA);
|
||||
cache.releaseMesh(shapeB);
|
||||
cache.releaseMesh(shapeC);
|
||||
meshA2.reset();
|
||||
meshB2.reset();
|
||||
meshC2.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 3);
|
||||
|
||||
// collect garbage (should still cache mesh)
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 3);
|
||||
|
||||
// forget again, one mesh at a time...
|
||||
// shapeA...
|
||||
cache.releaseMesh(shapeA);
|
||||
meshA.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 3);
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 2);
|
||||
// shapeB...
|
||||
cache.releaseMesh(shapeB);
|
||||
meshB.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 2);
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
// shapeC...
|
||||
cache.releaseMesh(shapeC);
|
||||
meshC.reset();
|
||||
QVERIFY(cache.getNumMeshes() == 1);
|
||||
cache.collectGarbage();
|
||||
QVERIFY(cache.getNumMeshes() == 0);
|
||||
|
||||
// delete unmanaged memory
|
||||
for (int i = 0; i < shapeA->getNumChildShapes(); ++i) {
|
||||
delete shapeA->getChildShape(i);
|
||||
}
|
||||
delete shapeA;
|
||||
for (int i = 0; i < shapeB->getNumChildShapes(); ++i) {
|
||||
delete shapeB->getChildShape(i);
|
||||
}
|
||||
delete shapeB;
|
||||
delete shapeC;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// CollisionRenderMeshCacheTests.h
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.10.30
|
||||
// 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_CollisionRenderMeshCacheTests_h
|
||||
#define hifi_CollisionRenderMeshCacheTests_h
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class CollisionRenderMeshCacheTests : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testShapeHullManifold();
|
||||
void testCompoundShape();
|
||||
void testMultipleShapes();
|
||||
};
|
||||
|
||||
#endif // hifi_CollisionRenderMeshCacheTests_h
|
Loading…
Reference in a new issue