Merge branch 'master' of https://github.com/worklist/hifi into 20423

This commit is contained in:
Thijs Wenker 2015-04-01 19:14:14 +02:00
commit f3ff48ab60
37 changed files with 348 additions and 115 deletions

View file

@ -26,6 +26,7 @@ set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets")
project(hifi)
add_definitions(-DGLM_FORCE_RADIANS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
if (WIN32)
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)

View file

@ -180,7 +180,7 @@ void AssignmentClientMonitor::readPendingDatagrams() {
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
if (!packetUUID.isNull()) {
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false);
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
matchingNode->setLinkedData(childData);
} else {

View file

@ -20,6 +20,7 @@
#include <AccountManager.h>
#include <HTTPConnection.h>
#include <LogHandler.h>
#include <NetworkingConstants.h>
#include <UUID.h>
#include "../AssignmentClient.h"
@ -252,7 +253,7 @@ OctreeServer::OctreeServer(const QByteArray& packet) :
// make sure the AccountManager has an Auth URL for payment redemptions
AccountManager::getInstance().setAuthURL(DEFAULT_NODE_AUTH_URL);
AccountManager::getInstance().setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
}
OctreeServer::~OctreeServer() {

View file

@ -95,6 +95,13 @@
"can_set": true
}
]
},
{
"name": "editors_are_rezzers",
"type": "checkbox",
"label": "Only editors can create new entities",
"help": "When checked, only those who can edit the domain can create new entites.",
"default": false
}
]
},

View file

@ -27,6 +27,7 @@
#include <HifiConfigVariantMap.h>
#include <HTTPConnection.h>
#include <LogUtils.h>
#include <NetworkingConstants.h>
#include <PacketHeaders.h>
#include <SettingHandle.h>
#include <SharedUtil.h>
@ -46,6 +47,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io";
const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users";
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors";
const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers";
DomainServer::DomainServer(int argc, char* argv[]) :
@ -181,7 +183,7 @@ bool DomainServer::optionallySetupOAuth() {
// if we don't have an oauth provider URL then we default to the default node auth url
if (_oauthProviderURL.isEmpty()) {
_oauthProviderURL = DEFAULT_NODE_AUTH_URL;
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL;
}
AccountManager& accountManager = AccountManager::getInstance();
@ -645,9 +647,23 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
bool canAdjustLocks = allowedEditors.isEmpty() || allowedEditors.contains(username);
const QVariant* editorsAreRezzersVariant =
valueForKeyPath(_settingsManager.getSettingsMap(), EDITORS_ARE_REZZERS_KEYPATH);
bool onlyEditorsAreRezzers = false;
if (editorsAreRezzersVariant) {
onlyEditorsAreRezzers = editorsAreRezzersVariant->toBool();
}
bool canRez = true;
if (onlyEditorsAreRezzers) {
canRez = canAdjustLocks;
}
SharedNodePointer newNode =
DependencyManager::get<LimitedNodeList>()->addOrUpdateNode(nodeUUID, nodeType,
publicSockAddr, localSockAddr, canAdjustLocks);
publicSockAddr, localSockAddr,
canAdjustLocks, canRez);
// when the newNode is created the linked data is also created
// if this was a static assignment set the UUID, set the sendingSockAddr
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(newNode->getLinkedData());
@ -902,6 +918,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append);
broadcastDataStream << node->getUUID();
broadcastDataStream << node->getCanAdjustLocks();
broadcastDataStream << node->getCanRez();
int numBroadcastPacketLeadBytes = broadcastDataStream.device()->pos();

View file

@ -23,6 +23,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var rollSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/dice/diceRoll.wav");
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to create new objects."
var screenSize = Controller.getViewportDimensions();
var BUTTON_SIZE = 32;
@ -54,20 +56,26 @@ var MAX_ANGULAR_SPEED = Math.PI;
function shootDice(position, velocity) {
for (var i = 0; i < NUMBER_OF_DICE; i++) {
dice.push(Entities.addEntity(
{ type: "Model",
modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx",
position: position,
velocity: velocity,
rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360),
angularVelocity: { x: Math.random() * MAX_ANGULAR_SPEED, y: Math.random() * MAX_ANGULAR_SPEED, z: Math.random() * MAX_ANGULAR_SPEED },
lifetime: LIFETIME,
gravity: { x: 0, y: GRAVITY, z: 0 },
shapeType: "box",
collisionsWillMove: true
}));
position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation()))));
if (!Entities.canRez()) {
Window.alert(INSUFFICIENT_PERMISSIONS_ERROR_MSG);
} else {
for (var i = 0; i < NUMBER_OF_DICE; i++) {
dice.push(Entities.addEntity(
{ type: "Model",
modelURL: HIFI_PUBLIC_BUCKET + "models/props/Dice/goldDie.fbx",
position: position,
velocity: velocity,
rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360),
angularVelocity: { x: Math.random() * MAX_ANGULAR_SPEED,
y: Math.random() * MAX_ANGULAR_SPEED,
z: Math.random() * MAX_ANGULAR_SPEED },
lifetime: LIFETIME,
gravity: { x: 0, y: GRAVITY, z: 0 },
shapeType: "box",
collisionsWillMove: true
}));
position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation()))));
}
}
}

View file

@ -132,7 +132,7 @@
this.updateLightIDInUserData();
} else {
var that = this;
Script.setTimeout(function() { that.maybeUpdateLightIDInUserData() }, 500);
Script.setTimeout(function() { that.maybeUpdateLightIDInUserData() }, 500);
}
}
@ -213,6 +213,10 @@
this.preload = function(entityID) {
this.preOperation(entityID);
};
this.unload = function(){
Entities.deleteEntity(this.lightID);
}
this.clickReleaseOnEntity = function(entityID, mouseEvent) {
this.preOperation(entityID);

View file

@ -68,6 +68,7 @@
#include <MainWindow.h>
#include <ModelEntityItem.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
#include <OctalCode.h>
#include <OctreeSceneStats.h>
#include <PacketHeaders.h>
@ -138,8 +139,8 @@
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
#if defined(Q_OS_WIN)
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
#endif
@ -425,7 +426,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
UserActivityLogger::getInstance().launch(applicationVersion());
// once the event loop has started, check and signal for an access token
@ -3736,22 +3737,27 @@ bool Application::askToSetAvatarUrl(const QString& url) {
_myAvatar->setFaceModelURL(url);
UserActivityLogger::getInstance().changedModel("head", url);
_myAvatar->sendIdentityPacket();
emit faceURLChanged(url);
} else if (msgBox.clickedButton() == bodyButton) {
qDebug() << "Chose to use for body: " << url;
_myAvatar->setSkeletonModelURL(url);
// if the head is empty, reset it to the default head.
if (_myAvatar->getFaceModelURLString().isEmpty()) {
_myAvatar->setFaceModelURL(DEFAULT_HEAD_MODEL_URL);
emit faceURLChanged(DEFAULT_HEAD_MODEL_URL.toString());
UserActivityLogger::getInstance().changedModel("head", DEFAULT_HEAD_MODEL_URL.toString());
}
UserActivityLogger::getInstance().changedModel("skeleton", url);
_myAvatar->sendIdentityPacket();
emit skeletonURLChanged(url);
} else if (msgBox.clickedButton() == bodyAndHeadButton) {
qDebug() << "Chose to use for body + head: " << url;
_myAvatar->setFaceModelURL(QString());
_myAvatar->setSkeletonModelURL(url);
UserActivityLogger::getInstance().changedModel("skeleton", url);
_myAvatar->sendIdentityPacket();
emit faceURLChanged(QString());
emit skeletonURLChanged(url);
} else {
qDebug() << "Declined to use the avatar: " << url;
}

View file

@ -336,6 +336,9 @@ signals:
void checkBackgroundDownloads();
void domainConnectionRefused(const QString& reason);
void faceURLChanged(const QString& newValue);
void skeletonURLChanged(const QString& newValue);
public slots:
void domainChanged(const QString& domainHostname);
void updateWindowTitle();

View file

@ -685,6 +685,10 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
* joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
}
// Each joint contributes its point to the bounding box
glm::vec3 jointPosition = extractTranslation(transforms[i]);
totalExtents.addPoint(jointPosition);
Shape* shape = _shapes[i];
if (!shape) {
continue;
@ -694,8 +698,6 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
// that contains the sphere centered at the end of the joint with radius of the bone.
// TODO: skip hand and arm shapes for bounding box calculation
glm::vec3 jointPosition = extractTranslation(transforms[i]);
int type = shape->getType();
if (type == CAPSULE_SHAPE) {
// add the two furthest surface points of the capsule

View file

@ -54,6 +54,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid
_windowWidget = dockWidget;
} else {
_windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window);
_windowWidget->setWindowTitle(title);
_windowWidget->setMinimumSize(width, height);
@ -89,24 +90,24 @@ void WebWindowClass::setVisible(bool visible) {
if (visible) {
if (_isToolWindow) {
QMetaObject::invokeMethod(
Application::getInstance()->getToolWindow(), "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
Application::getInstance()->getToolWindow(), "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
} else {
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection);
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
}
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible));
QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::AutoConnection, Q_ARG(bool, visible));
}
void WebWindowClass::setURL(const QString& url) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setURL", Qt::BlockingQueuedConnection, Q_ARG(QString, url));
QMetaObject::invokeMethod(this, "setURL", Qt::AutoConnection, Q_ARG(QString, url));
return;
}
_webView->setUrl(url);
}
void WebWindowClass::raise() {
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection);
QMetaObject::invokeMethod(_windowWidget, "raise", Qt::AutoConnection);
}
QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {

View file

@ -13,7 +13,7 @@
#include <qwebview.h>
#include <AccountManager.h>
#include <LimitedNodeList.h>
#include <NetworkingConstants.h>
#include "Application.h"
#include "DataWebPage.h"
@ -39,7 +39,7 @@ DataWebDialog* DataWebDialog::dialogForPath(const QString& path,
connect(dialogWebView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared,
dialogWebView, &DataWebDialog::addJavascriptObjectsToWindow);
QUrl dataWebUrl(DEFAULT_NODE_AUTH_URL);
QUrl dataWebUrl(NetworkingConstants::METAVERSE_SERVER_URL);
dataWebUrl.setPath(path);
qDebug() << "Opening a data web dialog for" << dataWebUrl.toString();

View file

@ -14,6 +14,7 @@
#include <QPushButton>
#include <QPixmap>
#include <NetworkingConstants.h>
#include <PathUtils.h>
#include "Application.h"
@ -23,7 +24,8 @@
#include "LoginDialog.h"
#include "UIUtil.h"
const QString FORGOT_PASSWORD_URL = "https://metaverse.highfidelity.com/users/password/new";
const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/create";
const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new";
LoginDialog::LoginDialog(QWidget* parent) :
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP),
@ -44,6 +46,7 @@ LoginDialog::LoginDialog(QWidget* parent) :
this, &LoginDialog::close);
UIUtil::scaleWidgetFontSizes(this);
_ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL));
// Initialize toggle connection
toggleQAction();

View file

@ -16,17 +16,18 @@
#include <avatar/AvatarManager.h>
#include <devices/Faceshift.h>
#include <devices/SixenseManager.h>
#include <NetworkingConstants.h>
#include "Application.h"
#include "MainWindow.h"
#include "LODManager.h"
#include "Menu.h"
#include "ModelsBrowser.h"
#include "PreferencesDialog.h"
#include "Snapshot.h"
#include "UserActivityLogger.h"
#include "UIUtil.h"
const int PREFERENCES_HEIGHT_PADDING = 20;
PreferencesDialog::PreferencesDialog(QWidget* parent) :
@ -46,6 +47,11 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
connect(ui.buttonBrowseScriptsLocation, &QPushButton::clicked, this, &PreferencesDialog::openScriptsLocationBrowser);
connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked,
Application::getInstance(), &Application::loadDefaultScripts);
connect(Application::getInstance(), &Application::faceURLChanged, this, &PreferencesDialog::faceURLChanged);
connect(Application::getInstance(), &Application::skeletonURLChanged, this, &PreferencesDialog::skeletonURLChanged);
// move dialog to left side
move(parentWidget()->geometry().topLeft());
setFixedHeight(parentWidget()->size().height() - PREFERENCES_HEIGHT_PADDING);
@ -53,9 +59,19 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) :
UIUtil::scaleWidgetFontSizes(this);
}
void PreferencesDialog::faceURLChanged(const QString& newValue) {
ui.faceURLEdit->setText(newValue);
}
void PreferencesDialog::skeletonURLChanged(const QString& newValue) {
ui.skeletonURLEdit->setText(newValue);
}
void PreferencesDialog::accept() {
savePreferences();
close();
delete _marketplaceWindow;
_marketplaceWindow = NULL;
}
void PreferencesDialog::setHeadUrl(QString modelUrl) {
@ -67,15 +83,23 @@ void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
}
void PreferencesDialog::openHeadModelBrowser() {
ModelsBrowser modelBrowser(FSTReader::HEAD_MODEL);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
modelBrowser.browse();
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
auto WIDTH = 900;
auto HEIGHT = 700;
if (!_marketplaceWindow) {
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
}
_marketplaceWindow->setVisible(true);
}
void PreferencesDialog::openBodyModelBrowser() {
ModelsBrowser modelBrowser(FSTReader::HEAD_AND_BODY_MODEL);
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
modelBrowser.browse();
auto MARKETPLACE_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/marketplace?category=avatars";
auto WIDTH = 900;
auto HEIGHT = 700;
if (!_marketplaceWindow) {
_marketplaceWindow = new WebWindowClass("Marketplace", MARKETPLACE_URL, WIDTH, HEIGHT, false);
}
_marketplaceWindow->setVisible(true);
}
void PreferencesDialog::openSnapshotLocationBrowser() {
@ -192,11 +216,13 @@ void PreferencesDialog::savePreferences() {
UserActivityLogger::getInstance().changedDisplayName(displayNameStr);
shouldDispatchIdentityPacket = true;
}
auto AVATAR_FILE_EXTENSION = ".fst";
QUrl faceModelURL(ui.faceURLEdit->text());
QString faceModelURLString = faceModelURL.toString();
if (faceModelURLString != _faceURLString) {
if (faceModelURLString.isEmpty() || faceModelURLString.toLower().endsWith(".fst")) {
if (faceModelURLString.isEmpty() || faceModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
// change the faceModelURL in the profile, it will also update this user's BlendFace
myAvatar->setFaceModelURL(faceModelURL);
UserActivityLogger::getInstance().changedModel("head", faceModelURLString);
@ -209,7 +235,7 @@ void PreferencesDialog::savePreferences() {
QUrl skeletonModelURL(ui.skeletonURLEdit->text());
QString skeletonModelURLString = skeletonModelURL.toString();
if (skeletonModelURLString != _skeletonURLString) {
if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().endsWith(".fst")) {
if (skeletonModelURLString.isEmpty() || skeletonModelURLString.toLower().contains(AVATAR_FILE_EXTENSION)) {
// change the skeletonModelURL in the profile, it will also update this user's Body
myAvatar->setSkeletonModelURL(skeletonModelURL);
UserActivityLogger::getInstance().changedModel("skeleton", skeletonModelURLString);

View file

@ -17,6 +17,8 @@
#include <QDialog>
#include <QString>
#include "scripting/WebWindowClass.h"
class PreferencesDialog : public QDialog {
Q_OBJECT
@ -36,6 +38,8 @@ private:
QString _faceURLString;
QString _skeletonURLString;
QString _displayNameString;
WebWindowClass* _marketplaceWindow = NULL;
private slots:
void accept();
@ -43,6 +47,8 @@ private slots:
void setSkeletonUrl(QString modelUrl);
void openSnapshotLocationBrowser();
void openScriptsLocationBrowser();
void faceURLChanged(const QString& newValue);
void skeletonURLChanged(const QString& newValue);
};

View file

@ -447,7 +447,7 @@ border-radius: 4px; padding-top: 1px;</string>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="accountLabel">
<property name="font">
<font>
<family>Helvetica,Arial,sans-serif</family>
@ -456,9 +456,12 @@ border-radius: 4px; padding-top: 1px;</string>
</property>
<property name="text">
<string>&lt;style type=&quot;text/css&quot;&gt;
a { text-decoration: none; color: #267077;}
a { text-decoration: none; color: #267077; margin:0;padding:0;}
#create {font-weight:bold;}
p {margin:5px 0;}
&lt;/style&gt;
&lt;a href=&quot;https://metaverse.highfidelity.com/password/new&quot;&gt;Recover password?&lt;/a&gt;</string>
&lt;p&gt;&lt;a id=&quot;create&quot; href=&quot;%1&quot;&gt;Create account&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;%2&quot;&gt;Recover password&lt;/a&gt;&lt;/p&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>

View file

@ -23,6 +23,7 @@ EntityScriptingInterface::EntityScriptingInterface() :
{
auto nodeList = DependencyManager::get<NodeList>();
connect(nodeList.data(), &NodeList::canAdjustLocksChanged, this, &EntityScriptingInterface::canAdjustLocksChanged);
connect(nodeList.data(), &NodeList::canRezChanged, this, &EntityScriptingInterface::canRezChanged);
}
void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
@ -30,12 +31,15 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
getEntityPacketSender()->queueEditEntityMessage(packetType, entityID, properties);
}
bool EntityScriptingInterface::canAdjustLocks() {
auto nodeList = DependencyManager::get<NodeList>();
return nodeList->getThisNodeCanAdjustLocks();
}
bool EntityScriptingInterface::canRez() {
auto nodeList = DependencyManager::get<NodeList>();
return nodeList->getThisNodeCanRez();
}
void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) {
if (_entityTree) {

View file

@ -66,6 +66,9 @@ public slots:
// returns true if the DomainServer will allow this Node/Avatar to make changes
Q_INVOKABLE bool canAdjustLocks();
// returns true if the DomainServer will allow this Node/Avatar to rez new entities
Q_INVOKABLE bool canRez();
/// adds a model with the specific properties
Q_INVOKABLE EntityItemID addEntity(const EntityItemProperties& properties);
@ -117,6 +120,7 @@ signals:
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void canAdjustLocksChanged(bool canAdjustLocks);
void canRezChanged(bool canRez);
void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
void mouseMoveOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);

View file

@ -659,12 +659,14 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
qDebug() << "User attempted to edit an unknown entity. ID:" << entityItemID;
}
} else {
// this is a new entity... assign a new entityID
entityItemID = assignEntityID(entityItemID);
EntityItem* newEntity = addEntity(entityItemID, properties);
if (newEntity) {
newEntity->markAsChangedOnServer();
notifyNewlyCreatedEntity(*newEntity, senderNode);
if (senderNode->getCanRez()) {
// this is a new entity... assign a new entityID
entityItemID = assignEntityID(entityItemID);
EntityItem* newEntity = addEntity(entityItemID, properties);
if (newEntity) {
newEntity->markAsChangedOnServer();
notifyNewlyCreatedEntity(*newEntity, senderNode);
}
}
}
}

View file

@ -21,9 +21,12 @@
#include "Shape.h"
QHash<QString, float> COMMENT_SCALE_HINTS;
class OBJTokenizer {
public:
OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
OBJTokenizer(QIODevice* device);
enum SpecialToken {
NO_TOKEN = -1,
NO_PUSHBACKED_TOKEN = -1,
@ -46,6 +49,15 @@ private:
};
OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
// This is a list of comments that exports use to hint at scaling
if (COMMENT_SCALE_HINTS.isEmpty()) {
COMMENT_SCALE_HINTS["This file uses centimeters as units"] = 1.0f / 100.0f;
COMMENT_SCALE_HINTS["This file uses millimeters as units"] = 1.0f / 1000.0f;
}
}
int OBJTokenizer::nextToken() {
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
int token = _pushedBackToken;
@ -60,7 +72,7 @@ int OBJTokenizer::nextToken() {
}
switch (ch) {
case '#': {
_comment = _device->readLine(); // skip the comment
_comment = _device->readLine(); // stash comment for a future call to getComment
qDebug() << "COMMENT:" << _comment;
return COMMENT_TOKEN;
}
@ -136,11 +148,15 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
while (true) {
int tokenType = tokenizer.nextToken();
if (tokenType == OBJTokenizer::COMMENT_TOKEN) {
if (tokenizer.getComment().contains("This file uses centimeters as units")) {
scaleGuess = 1.0f / 100.0f;
}
if (tokenizer.getComment().contains("This file uses millimeters as units")) {
scaleGuess = 1.0f / 1000.0f;
// loop through the list of known comments which suggest a scaling factor.
// if we find one, save the scaling hint into scaleGuess
QString comment = tokenizer.getComment();
QHashIterator<QString, float> i(COMMENT_SCALE_HINTS);
while (i.hasNext()) {
i.next();
if (comment.contains(i.key())) {
scaleGuess = i.value();
}
}
continue;
}

View file

@ -33,8 +33,7 @@ AddressManager::AddressManager() :
_rootPlaceName(),
_rootPlaceID(),
_positionGetter(NULL),
_orientationGetter(NULL),
_localDSPortSharedMem(NULL)
_orientationGetter(NULL)
{
connect(qApp, &QCoreApplication::aboutToQuit, this, &AddressManager::storeCurrentAddress);
}
@ -331,13 +330,6 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) {
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
if (domainHostname == "localhost") {
auto nodeList = DependencyManager::get<NodeList>();
nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY,
_localDSPortSharedMem,
domainPort);
}
if (!hostnameRegex.cap(2).isEmpty()) {
domainPort = (qint16) hostnameRegex.cap(2).toInt();
}

View file

@ -95,8 +95,6 @@ private:
QUuid _rootPlaceID;
PositionGetter _positionGetter;
OrientationGetter _orientationGetter;
QSharedMemory* _localDSPortSharedMem; // memory shared with domain server
};
#endif // hifi_AddressManager_h

View file

@ -47,6 +47,7 @@ public:
void setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname);
unsigned short getPort() const { return _sockAddr.getPort(); }
void setPort(quint16 port) { _sockAddr.setPort(port); }
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }

View file

@ -36,8 +36,6 @@ const char SOLO_NODE_TYPES[2] = {
NodeType::AudioMixer
};
const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://metaverse.highfidelity.com");
LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) :
linkedDataCreateCallback(NULL),
_sessionUUID(),
@ -49,7 +47,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
_publicSockAddr(),
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
_packetStatTimer(),
_thisNodeCanAdjustLocks(false)
_thisNodeCanAdjustLocks(false),
_thisNodeCanRez(true)
{
static bool firstCall = true;
if (firstCall) {
@ -108,6 +107,13 @@ void LimitedNodeList::setThisNodeCanAdjustLocks(bool canAdjustLocks) {
}
}
void LimitedNodeList::setThisNodeCanRez(bool canRez) {
if (_thisNodeCanRez != canRez) {
_thisNodeCanRez = canRez;
emit canRezChanged(canRez);
}
}
QUdpSocket& LimitedNodeList::getDTLSSocket() {
if (!_dtlsSocket) {
// DTLS socket getter called but no DTLS socket exists, create it now
@ -392,8 +398,9 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
_nodeMutex.unlock();
QWriteLocker writeLocker(&_nodeMutex);
_nodeMutex.lockForWrite();
_nodeHash.unsafe_erase(it);
_nodeMutex.unlock();
handleNodeKill(matchingNode);
} else {
@ -416,7 +423,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) {
SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
bool canAdjustLocks) {
bool canAdjustLocks, bool canRez) {
NodeHash::const_iterator it = _nodeHash.find(uuid);
if (it != _nodeHash.end()) {
@ -425,11 +432,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
matchingNode->setPublicSocket(publicSocket);
matchingNode->setLocalSocket(localSocket);
matchingNode->setCanAdjustLocks(canAdjustLocks);
matchingNode->setCanRez(canRez);
return matchingNode;
} else {
// we didn't have this node, so add them
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks);
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez);
SharedNodePointer newNodePointer(newNode);
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));

View file

@ -42,8 +42,6 @@ const quint64 NODE_SILENCE_THRESHOLD_MSECS = 2 * 1000;
extern const char SOLO_NODE_TYPES[2];
extern const QUrl DEFAULT_NODE_AUTH_URL;
const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
@ -86,6 +84,9 @@ public:
bool getThisNodeCanAdjustLocks() const { return _thisNodeCanAdjustLocks; }
void setThisNodeCanAdjustLocks(bool canAdjustLocks);
bool getThisNodeCanRez() const { return _thisNodeCanRez; }
void setThisNodeCanRez(bool canRez);
void rebindNodeSocket();
QUdpSocket& getNodeSocket() { return _nodeSocket; }
@ -116,7 +117,8 @@ public:
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks);
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
bool canAdjustLocks, bool canRez);
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
@ -208,6 +210,7 @@ signals:
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
void canAdjustLocksChanged(bool canAdjustLocks);
void canRezChanged(bool canRez);
void dataSent(const quint8 channel_type, const int bytes);
void dataReceived(const quint8 channel_type, const int bytes);
@ -243,6 +246,7 @@ protected:
QElapsedTimer _packetStatTimer;
bool _thisNodeCanAdjustLocks;
bool _thisNodeCanRez;
template<typename IteratorLambda>
void eachNodeHashIterator(IteratorLambda functor) {

View file

@ -0,0 +1,21 @@
//
// NetworkingConstants.h
// libraries/networking/src
//
// Created by Stephen Birarda on 2015-03-31.
// Copyright 2015 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_NetworkingConstants_h
#define hifi_NetworkingConstants_h
#include <QtCore/QUrl>
namespace NetworkingConstants {
const QUrl METAVERSE_SERVER_URL = QUrl("https://metaverse.highfidelity.com");
}
#endif // hifi_NetworkingConstants_h

View file

@ -41,7 +41,7 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) {
}
Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
const HifiSockAddr& localSocket, bool canAdjustLocks) :
const HifiSockAddr& localSocket, bool canAdjustLocks, bool canRez) :
NetworkPeer(uuid, publicSocket, localSocket),
_type(type),
_activeSocket(NULL),
@ -53,7 +53,8 @@ Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket,
_clockSkewUsec(0),
_mutex(),
_clockSkewMovingPercentile(30, 0.8f), // moving 80th percentile of 30 samples
_canAdjustLocks(canAdjustLocks)
_canAdjustLocks(canAdjustLocks),
_canRez(canRez)
{
}
@ -133,6 +134,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) {
out << node._publicSocket;
out << node._localSocket;
out << node._canAdjustLocks;
out << node._canRez;
return out;
}
@ -143,6 +145,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) {
in >> node._publicSocket;
in >> node._localSocket;
in >> node._canAdjustLocks;
in >> node._canRez;
return in;
}

View file

@ -45,7 +45,7 @@ class Node : public NetworkPeer {
Q_OBJECT
public:
Node(const QUuid& uuid, NodeType_t type,
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks);
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, bool canAdjustLocks, bool canRez);
~Node();
bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; }
@ -79,6 +79,9 @@ public:
void setCanAdjustLocks(bool canAdjustLocks) { _canAdjustLocks = canAdjustLocks; }
bool getCanAdjustLocks() { return _canAdjustLocks; }
void setCanRez(bool canRez) { _canRez = canRez; }
bool getCanRez() { return _canRez; }
void activatePublicSocket();
void activateLocalSocket();
@ -105,6 +108,7 @@ private:
QMutex _mutex;
MovingPercentile _clockSkewMovingPercentile;
bool _canAdjustLocks;
bool _canRez;
};
QDebug operator<<(QDebug debug, const Node &message);

View file

@ -277,6 +277,23 @@ void NodeList::sendDomainServerCheckIn() {
if (!_domainHandler.isConnected()) {
qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname();
// is this our localhost domain-server?
// if so we need to make sure we have an up-to-date local port in case it restarted
if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost
|| _domainHandler.getHostname() == "localhost") {
static QSharedMemory* localDSPortSharedMem = NULL;
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY,
localDSPortSharedMem,
domainPort);
qDebug() << "Local domain-server port read from shared memory (or default) is" << domainPort;
_domainHandler.setPort(domainPort);
}
}
// construct the DS check in packet
@ -386,6 +403,10 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
bool thisNodeCanAdjustLocks;
packetStream >> thisNodeCanAdjustLocks;
setThisNodeCanAdjustLocks(thisNodeCanAdjustLocks);
bool thisNodeCanRez;
packetStream >> thisNodeCanRez;
setThisNodeCanRez(thisNodeCanRez);
// pull each node in the packet
while(packetStream.device()->pos() < packet.size()) {
@ -394,8 +415,9 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
QUuid nodeUUID, connectionUUID;
HifiSockAddr nodePublicSocket, nodeLocalSocket;
bool canAdjustLocks;
bool canRez;
packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> canAdjustLocks;
packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> canAdjustLocks >> canRez;
// if the public socket address is 0 then it's reachable at the same IP
// as the domain server
@ -403,7 +425,8 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
nodePublicSocket.setAddress(_domainHandler.getIP());
}
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket, canAdjustLocks);
SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket,
nodeLocalSocket, canAdjustLocks, canRez);
packetStream >> connectionUUID;
node->setConnectionSecret(connectionUUID);

View file

@ -15,6 +15,7 @@
#include "AccountManager.h"
#include "LimitedNodeList.h"
#include "NetworkingConstants.h"
#include "SharedUtil.h"
#include "OAuthNetworkAccessManager.h"
@ -33,7 +34,8 @@ QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::O
QIODevice* outgoingData) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.hasValidAccessToken() && req.url().host() == DEFAULT_NODE_AUTH_URL.host()) {
if (accountManager.hasValidAccessToken()
&& req.url().host() == NetworkingConstants::METAVERSE_SERVER_URL.host()) {
QNetworkRequest authenticatedRequest(req);
authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
authenticatedRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER,

View file

@ -64,7 +64,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 2;
case PacketTypeDomainList:
case PacketTypeDomainListRequest:
return 4;
return 5;
case PacketTypeCreateAssignment:
case PacketTypeRequestAssignment:
return 2;

View file

@ -35,7 +35,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
// Very small or large objects are not supported.
float diagonal = 4.0f * glm::length2(info.getHalfExtents());
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
// qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal;
return NULL;

View file

@ -17,12 +17,13 @@
#include <qurlquery.h>
#include <NetworkAccessManager.h>
#include <NetworkingConstants.h>
#include <AccountManager.h>
#include "XMLHttpRequestClass.h"
#include "ScriptEngine.h"
const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/";
const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/api/";
Q_DECLARE_METATYPE(QByteArray*)

View file

@ -66,7 +66,9 @@ QDataStream& operator>>(QDataStream& in, glm::quat& quaternion) {
}
// less common utils can be enabled with DEBUG
#ifdef DEBUG
// FIXME, remove the second defined clause once these compile, or remove the
// functions.
#if defined(DEBUG) && defined(FIXED_STREAMS)
std::ostream& operator<<(std::ostream& s, const CollisionInfo& c) {
s << "{penetration=" << c._penetration

View file

@ -38,6 +38,15 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
}
std::cout << "-------------------\n";
foreach (const FBXMesh& mesh, geometry.meshes) {
foreach (const FBXMeshPart &meshPart, mesh.parts) {
std::cout << meshPart.triangleIndices.size() << " ";
}
}
std::cout << "\n";
//results->meshCount = geometry.meshes.count();
// qDebug() << "read in" << geometry.meshes.count() << "meshes";
@ -52,14 +61,29 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
vertices.append(glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f)));
}
//get the triangle indices for each mesh
// get the triangle indices for each mesh
QVector<int> triangles;
foreach(FBXMeshPart part, mesh.parts){
QVector<int> indices = part.triangleIndices;
foreach(FBXMeshPart meshPart, mesh.parts){
QVector<int> indices = meshPart.triangleIndices;
triangles += indices;
unsigned int quadCount = meshPart.quadIndices.size() / 4;
for (unsigned int i = 0; i < quadCount; i++) {
unsigned int p0Index = meshPart.quadIndices[i * 4];
unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
// split each quad into two triangles
triangles.append(p0Index);
triangles.append(p1Index);
triangles.append(p2Index);
triangles.append(p0Index);
triangles.append(p2Index);
triangles.append(p3Index);
}
}
//only read meshes with triangles
// only read meshes with triangles
if (triangles.count() <= 0){
continue;
}
@ -131,15 +155,16 @@ void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFB
auto d1 = p2 - p0;
auto cp = glm::cross(d0, d1);
cp = 5.0f * glm::normalize(cp);
cp = -2.0f * glm::normalize(cp);
auto p3 = p0 + cp;
auto p4 = p1 + cp;
auto p5 = p2 + cp;
auto n = results->perMeshVertices.size();
results->perMeshVertices[i] << p3 << p4 << p5;
results->perMeshTriangleIndices[i] << n << n+1 << n+2;
results->perMeshVertices[i] << p3;
results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
}
results->meshCount++;
@ -148,21 +173,26 @@ void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFB
bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params,
bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *inMeshes, VHACD::IVHACD::Parameters params,
vhacd::ComputeResults *results,
int startMeshIndex, int endMeshIndex, float minimumMeshSize) const {
int startMeshIndex, int endMeshIndex, float minimumMeshSize,
bool fattenFaces) const {
// vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
// combineMeshes(inMeshes, meshes);
// vhacd::LoadFBXResults *meshes = new vhacd::LoadFBXResults;
// fattenMeshes(inMeshes, meshes);
if (fattenFaces) {
fattenMeshes(inMeshes, meshes);
} else {
meshes = inMeshes;
}
VHACD::IVHACD * interfaceVHACD = VHACD::CreateVHACD();
int meshCount = meshes->meshCount;
int count = 0;
std::cout << "Performing V-HACD computation on " << meshCount << " meshes ..... " << std::endl;
if (startMeshIndex < 0) {
startMeshIndex = 0;
@ -171,6 +201,14 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD
endMeshIndex = meshCount;
}
for (int i = 0; i < meshCount; i++) {
std::cout << meshes->perMeshTriangleIndices.at(i).size() << " ";
}
std::cout << "\n";
std::cout << "Performing V-HACD computation on " << endMeshIndex - startMeshIndex << " meshes ..... " << std::endl;
for (int i = startMeshIndex; i < endMeshIndex; i++){
qDebug() << "--------------------";
std::vector<glm::vec3> vertices = meshes->perMeshVertices.at(i).toStdVector();
@ -211,7 +249,6 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD
}
hull.m_points = m_points_copy;
int *m_triangles_copy = new int[hull.m_nTriangles * 3];
// std::copy(std::begin(hull.m_triangles), std::end(hull.m_triangles), std::begin(m_triangles_copy));
for (unsigned int i=0; i<hull.m_nTriangles * 3; i++) {

View file

@ -43,7 +43,8 @@ namespace vhacd {
void combineMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
void fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params,
vhacd::ComputeResults *results, int startMeshIndex, int endMeshIndex, float minimumMeshSize) const;
vhacd::ComputeResults *results, int startMeshIndex, int endMeshIndex, float minimumMeshSize,
bool fattenFaces) const;
~VHACDUtil();
};

View file

@ -92,6 +92,9 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
const QCommandLineOption outputOneMeshOption("1", "output hulls as single mesh");
parser.addOption(outputOneMeshOption);
const QCommandLineOption fattenFacesOption("f", "fatten faces");
parser.addOption(fattenFacesOption);
const QCommandLineOption inputFilenameOption("i", "input file", "filename.fbx");
parser.addOption(inputFilenameOption);
@ -107,6 +110,15 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
const QCommandLineOption minimumMeshSizeOption("m", "minimum mesh size to consider", "0");
parser.addOption(minimumMeshSizeOption);
const QCommandLineOption vHacdResolutionOption("resolution", "v-hacd resolution", "100000");
parser.addOption(vHacdResolutionOption);
const QCommandLineOption vHacdDepthOption("depth", "v-hacd depth", "20");
parser.addOption(vHacdDepthOption);
const QCommandLineOption vHacdDeltaOption("delta", "v-hacd delta", "0.05");
parser.addOption(vHacdDeltaOption);
if (!parser.parse(QCoreApplication::arguments())) {
qCritical() << parser.errorText() << endl;
@ -119,17 +131,15 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
Q_UNREACHABLE();
}
bool fattenFaces = parser.isSet(fattenFacesOption);
bool outputOneMesh = parser.isSet(outputOneMeshOption);
QString inputFilename;
// check for an assignment pool passed on the command line or in the config
if (parser.isSet(inputFilenameOption)) {
inputFilename = parser.value(inputFilenameOption);
}
QString outputFilename;
// check for an assignment pool passed on the command line or in the config
if (parser.isSet(outputFilenameOption)) {
outputFilename = parser.value(outputFilenameOption);
}
@ -148,30 +158,43 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
}
int startMeshIndex = -1;
// check for an assignment pool passed on the command line or in the config
if (parser.isSet(startMeshIndexOption)) {
startMeshIndex = parser.value(startMeshIndexOption).toInt();
}
int endMeshIndex = -1;
// check for an assignment pool passed on the command line or in the config
if (parser.isSet(endMeshIndexOption)) {
endMeshIndex = parser.value(endMeshIndexOption).toInt();
}
float minimumMeshSize = 0.0f;
// check for an assignment pool passed on the command line or in the config
if (parser.isSet(minimumMeshSizeOption)) {
minimumMeshSize = parser.value(minimumMeshSizeOption).toFloat();
}
int vHacdResolution = 100000;
if (parser.isSet(vHacdResolutionOption)) {
vHacdResolution = parser.value(vHacdResolutionOption).toInt();
}
int vHacdDepth = 20;
if (parser.isSet(vHacdDepthOption)) {
vHacdDepth = parser.value(vHacdDepthOption).toInt();
}
float vHacdDelta = 0.05;
if (parser.isSet(vHacdDeltaOption)) {
vHacdDelta = parser.value(vHacdDeltaOption).toFloat();
}
//set parameters for V-HACD
params.m_callback = &pCallBack; //progress callback
params.m_resolution = 100000; // 100000
params.m_depth = 20; // 20
params.m_resolution = vHacdResolution; // 100000
params.m_depth = vHacdDepth; // 20
params.m_concavity = 0.001; // 0.001
params.m_delta = 0.05; // 0.05
params.m_delta = vHacdDelta; // 0.05
params.m_planeDownsampling = 4; // 4
params.m_convexhullDownsampling = 4; // 4
params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes
@ -198,8 +221,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
//perform vhacd computation
begin = std::chrono::high_resolution_clock::now();
if (!vUtil.computeVHACD(&fbx, params, &results, startMeshIndex, endMeshIndex, minimumMeshSize)) {
if (!vUtil.computeVHACD(&fbx, params, &results, startMeshIndex, endMeshIndex, minimumMeshSize, fattenFaces)) {
cout << "Compute Failed...";
}
end = std::chrono::high_resolution_clock::now();