mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge remote-tracking branch 'upstream/master' into android
This commit is contained in:
commit
bdfa1273ba
63 changed files with 919 additions and 820 deletions
|
@ -343,7 +343,6 @@ void Agent::scriptRequestFinished() {
|
|||
|
||||
void Agent::executeScript() {
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine);
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ Column {
|
|||
'include_actions=' + actions,
|
||||
'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
|
||||
'require_online=true',
|
||||
'protocol=' + encodeURIComponent(AddressManager.protocolVersion()),
|
||||
'protocol=' + encodeURIComponent(Window.protocolSignature()),
|
||||
'page=' + pageNumber
|
||||
];
|
||||
var url = metaverseBase + 'user_stories?' + options.join('&');
|
||||
|
|
|
@ -392,7 +392,6 @@ Item {
|
|||
width: 118;
|
||||
height: paintedHeight;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.bold: true;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import "."
|
|||
Overlay {
|
||||
id: root
|
||||
|
||||
Image {
|
||||
AnimatedImage {
|
||||
id: image
|
||||
property bool scaleFix: true
|
||||
property real xStart: 0
|
||||
|
|
|
@ -610,8 +610,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
}
|
||||
};
|
||||
reportAndQuit("--protocolVersion", [&](FILE* fp) {
|
||||
DependencyManager::set<AddressManager>();
|
||||
auto version = DependencyManager::get<AddressManager>()->protocolVersion();
|
||||
auto version = protocolVersionsSignatureBase64();
|
||||
fputs(version.toLatin1().data(), fp);
|
||||
});
|
||||
reportAndQuit("--version", [&](FILE* fp) {
|
||||
|
@ -2148,6 +2147,11 @@ void Application::cleanupBeforeQuit() {
|
|||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
|
||||
// The PointerManager must be destroyed before the PickManager because when a Pointer is deleted,
|
||||
// it accesses the PickManager to delete its associated Pick
|
||||
DependencyManager::destroy<PointerManager>();
|
||||
DependencyManager::destroy<PickManager>();
|
||||
|
||||
qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete";
|
||||
}
|
||||
|
||||
|
@ -4420,8 +4424,9 @@ void Application::updateLOD(float deltaTime) const {
|
|||
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
|
||||
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
|
||||
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
|
||||
float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime));
|
||||
DependencyManager::get<LODManager>()->autoAdjustLOD(maxRenderTime, deltaTime);
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
lodManager->setRenderTimes(presentTime, engineRunTime, gpuTime);
|
||||
lodManager->autoAdjustLOD(deltaTime);
|
||||
} else {
|
||||
DependencyManager::get<LODManager>()->resetLODAdjust();
|
||||
}
|
||||
|
|
|
@ -26,43 +26,50 @@ Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DO
|
|||
LODManager::LODManager() {
|
||||
}
|
||||
|
||||
float LODManager::getLODDecreaseFPS() {
|
||||
float LODManager::getLODDecreaseFPS() const {
|
||||
if (qApp->isHMDMode()) {
|
||||
return getHMDLODDecreaseFPS();
|
||||
}
|
||||
return getDesktopLODDecreaseFPS();
|
||||
}
|
||||
|
||||
float LODManager::getLODIncreaseFPS() {
|
||||
float LODManager::getLODIncreaseFPS() const {
|
||||
if (qApp->isHMDMode()) {
|
||||
return getHMDLODIncreaseFPS();
|
||||
}
|
||||
return getDesktopLODIncreaseFPS();
|
||||
}
|
||||
|
||||
// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds
|
||||
// We use a "time-weighted running average" of the maxRenderTime and compare it against min/max thresholds
|
||||
// to determine if we should adjust the level of detail (LOD).
|
||||
//
|
||||
// A time-weighted running average has a timescale which determines how fast the average tracks the measured
|
||||
// value in real-time. Given a step-function in the mesured value, and assuming measurements happen
|
||||
// faster than the runningAverage is computed, the error between the value and its runningAverage will be
|
||||
// reduced by 1/e every timescale of real-time that passes.
|
||||
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec
|
||||
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.08f; // sec
|
||||
//
|
||||
// Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its
|
||||
// thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage to settle
|
||||
// to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few
|
||||
// multiples of the running average timescale:
|
||||
const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
|
||||
const uint64_t LOD_AUTO_ADJUST_PERIOD = 4 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
|
||||
|
||||
const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f;
|
||||
const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f;
|
||||
|
||||
void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
||||
// compute time-weighted running average renderTime
|
||||
void LODManager::setRenderTimes(float presentTime, float engineRunTime, float gpuTime) {
|
||||
_presentTime = presentTime;
|
||||
_engineRunTime = engineRunTime;
|
||||
_gpuTime = gpuTime;
|
||||
}
|
||||
|
||||
void LODManager::autoAdjustLOD(float realTimeDelta) {
|
||||
float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime);
|
||||
// compute time-weighted running average maxRenderTime
|
||||
// Note: we MUST clamp the blend to 1.0 for stability
|
||||
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec
|
||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec
|
||||
if (!_automaticLODAdjust) {
|
||||
// early exit
|
||||
return;
|
||||
|
@ -84,6 +91,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
<< "targetFPS =" << getLODDecreaseFPS()
|
||||
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||
emit LODDecreased();
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to provide an FPS just above the decrease threshold. It will drift close to its
|
||||
// true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
_avgRenderTime = (float)MSECS_PER_SECOND / (getLODDecreaseFPS() + 1.0f);
|
||||
}
|
||||
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
@ -105,6 +116,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
<< "targetFPS =" << getLODDecreaseFPS()
|
||||
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||
emit LODIncreased();
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to provide an FPS just below the increase threshold. It will drift close to its
|
||||
// true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
_avgRenderTime = (float)MSECS_PER_SECOND / (getLODIncreaseFPS() - 1.0f);
|
||||
}
|
||||
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
@ -119,11 +134,6 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
|||
if (lodToolsDialog) {
|
||||
lodToolsDialog->reloadSliders();
|
||||
}
|
||||
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||
// to be at middle of target zone. It will drift close to its true value within
|
||||
// about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||
float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS());
|
||||
_avgRenderTime = MSECS_PER_SECOND / expectedFPS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,6 +141,18 @@ void LODManager::resetLODAdjust() {
|
|||
_decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD;
|
||||
}
|
||||
|
||||
float LODManager::getLODLevel() const {
|
||||
// simpleLOD is a linearized and normalized number that represents how much LOD is being applied.
|
||||
// It ranges from:
|
||||
// 1.0 = normal (max) level of detail
|
||||
// 0.0 = min level of detail
|
||||
// In other words: as LOD "drops" the value of simpleLOD will also "drop", and it cannot go lower than 0.0.
|
||||
const float LOG_MIN_LOD_RATIO = logf(ADJUST_LOD_MIN_SIZE_SCALE / ADJUST_LOD_MAX_SIZE_SCALE);
|
||||
float power = logf(_octreeSizeScale / ADJUST_LOD_MAX_SIZE_SCALE);
|
||||
float simpleLOD = (LOG_MIN_LOD_RATIO - power) / LOG_MIN_LOD_RATIO;
|
||||
return simpleLOD;
|
||||
}
|
||||
|
||||
const float MIN_DECREASE_FPS = 0.5f;
|
||||
|
||||
void LODManager::setDesktopLODDecreaseFPS(float fps) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class AABox;
|
|||
class LODManager : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
|
||||
public:
|
||||
Q_INVOKABLE void setAutomaticLODAdjust(bool value) { _automaticLODAdjust = value; }
|
||||
Q_INVOKABLE bool getAutomaticLODAdjust() const { return _automaticLODAdjust; }
|
||||
|
@ -49,34 +49,56 @@ public:
|
|||
Q_INVOKABLE void setHMDLODDecreaseFPS(float value);
|
||||
Q_INVOKABLE float getHMDLODDecreaseFPS() const;
|
||||
Q_INVOKABLE float getHMDLODIncreaseFPS() const;
|
||||
|
||||
|
||||
// User Tweakable LOD Items
|
||||
Q_INVOKABLE QString getLODFeedbackText();
|
||||
Q_INVOKABLE void setOctreeSizeScale(float sizeScale);
|
||||
Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; }
|
||||
|
||||
|
||||
Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust);
|
||||
Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
|
||||
|
||||
Q_INVOKABLE float getLODDecreaseFPS();
|
||||
Q_INVOKABLE float getLODIncreaseFPS();
|
||||
|
||||
|
||||
Q_INVOKABLE float getLODDecreaseFPS() const;
|
||||
Q_INVOKABLE float getLODIncreaseFPS() const;
|
||||
|
||||
Q_PROPERTY(float presentTime READ getPresentTime)
|
||||
Q_PROPERTY(float engineRunTime READ getEngineRunTime)
|
||||
Q_PROPERTY(float gpuTime READ getGPUTime)
|
||||
Q_PROPERTY(float avgRenderTime READ getAverageRenderTime)
|
||||
Q_PROPERTY(float fps READ getMaxTheoreticalFPS)
|
||||
Q_PROPERTY(float lodLevel READ getLODLevel)
|
||||
|
||||
Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS)
|
||||
Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS)
|
||||
|
||||
float getPresentTime() const { return _presentTime; }
|
||||
float getEngineRunTime() const { return _engineRunTime; }
|
||||
float getGPUTime() const { return _gpuTime; }
|
||||
|
||||
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
||||
void autoAdjustLOD(float renderTime, float realTimeDelta);
|
||||
|
||||
void setRenderTimes(float presentTime, float engineRunTime, float gpuTime);
|
||||
void autoAdjustLOD(float realTimeDelta);
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void resetLODAdjust();
|
||||
|
||||
|
||||
float getAverageRenderTime() const { return _avgRenderTime; };
|
||||
float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; };
|
||||
float getLODLevel() const;
|
||||
|
||||
signals:
|
||||
void LODIncreased();
|
||||
void LODDecreased();
|
||||
|
||||
|
||||
private:
|
||||
LODManager();
|
||||
|
||||
|
||||
bool _automaticLODAdjust = true;
|
||||
float _avgRenderTime { 0.0f };
|
||||
float _presentTime { 0.0f }; // msec
|
||||
float _engineRunTime { 0.0f }; // msec
|
||||
float _gpuTime { 0.0f }; // msec
|
||||
float _avgRenderTime { 0.0f }; // msec
|
||||
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
|
||||
float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME };
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Ledger.h"
|
||||
#include "CommerceLogging.h"
|
||||
#include <NetworkingConstants.h>
|
||||
#include <AddressManager.h>
|
||||
|
||||
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
|
||||
// balance answers {status: 'success', data: {balance: integer}}
|
||||
|
@ -122,24 +123,33 @@ QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue)
|
|||
int sent = sentValue.toInt();
|
||||
int received = receivedValue.toInt();
|
||||
if (sent <= 0 && received <= 0) {
|
||||
return QString("-");
|
||||
return QString("0 HFC");
|
||||
}
|
||||
QString result;
|
||||
if (sent > 0) {
|
||||
result += QString("<font color='#B70A37'>-%1 HFC</font>").arg(sent);
|
||||
result += QString("<font color='#B70A37'><b>-%1 HFC</b></font>").arg(sent);
|
||||
if (received > 0) {
|
||||
result += QString("<br>");
|
||||
}
|
||||
}
|
||||
if (received > 0) {
|
||||
result += QString("<font color='#3AA38F'>%1 HFC</font>").arg(received);
|
||||
result += QString("<font color='#3AA38F'><b>%1 HFC</b></font>").arg(received);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static const QString USER_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/users/";
|
||||
QString userLink(const QString& username) {
|
||||
static const QString PLACE_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/places/";
|
||||
static const QStringList KNOWN_USERS(QStringList() << "highfidelity" << "marketplace");
|
||||
QString userLink(const QString& username, const QString& placename) {
|
||||
if (username.isEmpty()) {
|
||||
return QString("someone");
|
||||
if (placename.isEmpty()) {
|
||||
return QString("someone");
|
||||
} else {
|
||||
return QString("someone <a href=\"%1%2\">nearby</a>").arg(PLACE_PAGE_BASE_URL, placename);
|
||||
}
|
||||
}
|
||||
if (KNOWN_USERS.contains(username)) {
|
||||
return username;
|
||||
}
|
||||
return QString("<a href=\"%1%2\">%2</a>").arg(USER_PAGE_BASE_URL, username);
|
||||
}
|
||||
|
@ -153,13 +163,13 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC));
|
||||
QString result;
|
||||
|
||||
if (sentCerts <= 0 && receivedCerts <= 0) {
|
||||
if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
|
||||
// this is an hfc transfer.
|
||||
if (sent > 0) {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString());
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money sent to %1").arg(recipient);
|
||||
} else {
|
||||
QString sender = userLink(valueObject["sender_name"].toString());
|
||||
QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString());
|
||||
result += QString("Money from %1").arg(sender);
|
||||
}
|
||||
if (!message.isEmpty()) {
|
||||
|
@ -168,8 +178,8 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
} else {
|
||||
result += valueObject["message"].toString();
|
||||
}
|
||||
|
||||
// no matter what we append a smaller date to the bottom of this...
|
||||
|
||||
result += QString("<br><font size='-2' color='#1080B8'>%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate));
|
||||
return result;
|
||||
}
|
||||
|
@ -310,6 +320,7 @@ void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, co
|
|||
transaction["node_id"] = nodeID;
|
||||
transaction["quantity"] = amount;
|
||||
transaction["message"] = optionalMessage;
|
||||
transaction["place_name"] = DependencyManager::get<AddressManager>()->getPlaceName();
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferHfcToNodeSuccess", "transferHfcToNodeFailure");
|
||||
|
|
|
@ -390,6 +390,10 @@ QString WindowScriptingInterface::checkVersion() {
|
|||
return QCoreApplication::applicationVersion();
|
||||
}
|
||||
|
||||
QString WindowScriptingInterface::protocolSignature() {
|
||||
return protocolVersionsSignatureBase64();
|
||||
}
|
||||
|
||||
int WindowScriptingInterface::getInnerWidth() {
|
||||
return qApp->getDeviceSize().x;
|
||||
}
|
||||
|
|
|
@ -305,6 +305,13 @@ public slots:
|
|||
*/
|
||||
QString checkVersion();
|
||||
|
||||
/**jsdoc
|
||||
* Get the signature for Interface's protocol version.
|
||||
* @function Window.protocolSignature
|
||||
* @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using.
|
||||
*/
|
||||
QString protocolSignature();
|
||||
|
||||
/**jsdoc
|
||||
* Copies text to the operating system's clipboard.
|
||||
* @function Window.copyToClipboard
|
||||
|
|
|
@ -386,8 +386,6 @@ void Circle3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -154,8 +154,6 @@ void Cube3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -132,8 +132,6 @@ void Grid3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -208,8 +208,6 @@ void Image3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -275,8 +275,6 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -306,8 +306,6 @@ vectorType ModelOverlay::mapJoints(mapFunction<itemType> function) const {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -31,8 +31,7 @@ Overlay::Overlay() :
|
|||
_alphaPulse(0.0f),
|
||||
_colorPulse(0.0f),
|
||||
_color(DEFAULT_OVERLAY_COLOR),
|
||||
_visible(true),
|
||||
_anchor(NO_ANCHOR)
|
||||
_visible(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -49,8 +48,7 @@ Overlay::Overlay(const Overlay* overlay) :
|
|||
_alphaPulse(overlay->_alphaPulse),
|
||||
_colorPulse(overlay->_colorPulse),
|
||||
_color(overlay->_color),
|
||||
_visible(overlay->_visible),
|
||||
_anchor(overlay->_anchor)
|
||||
_visible(overlay->_visible)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -92,13 +90,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
|
|||
bool visible = properties["visible"].toBool();
|
||||
setVisible(visible);
|
||||
}
|
||||
|
||||
if (properties["anchor"].isValid()) {
|
||||
QString property = properties["anchor"].toString();
|
||||
if (property == "MyAvatar") {
|
||||
setAnchor(MY_AVATAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JSDoc for copying to @typedefs of overlay types that inherit Overlay.
|
||||
|
@ -119,8 +110,6 @@ void Overlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*/
|
||||
QVariant Overlay::getProperty(const QString& property) {
|
||||
if (property == "type") {
|
||||
|
@ -150,9 +139,6 @@ QVariant Overlay::getProperty(const QString& property) {
|
|||
if (property == "visible") {
|
||||
return _visible;
|
||||
}
|
||||
if (property == "anchor") {
|
||||
return _anchor == MY_AVATAR ? "MyAvatar" : "";
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
|
|
@ -26,11 +26,6 @@ class Overlay : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Anchor {
|
||||
NO_ANCHOR,
|
||||
MY_AVATAR
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Overlay> Pointer;
|
||||
typedef render::Payload<Overlay> Payload;
|
||||
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
|
||||
|
@ -63,7 +58,6 @@ public:
|
|||
virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; };
|
||||
xColor getColor();
|
||||
float getAlpha();
|
||||
Anchor getAnchor() const { return _anchor; }
|
||||
|
||||
float getPulseMax() const { return _pulseMax; }
|
||||
float getPulseMin() const { return _pulseMin; }
|
||||
|
@ -78,7 +72,6 @@ public:
|
|||
void setDrawHUDLayer(bool drawHUDLayer);
|
||||
void setColor(const xColor& color) { _color = color; }
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
void setAnchor(Anchor anchor) { _anchor = anchor; }
|
||||
|
||||
void setPulseMax(float value) { _pulseMax = value; }
|
||||
void setPulseMin(float value) { _pulseMin = value; }
|
||||
|
@ -118,7 +111,6 @@ protected:
|
|||
|
||||
xColor _color;
|
||||
bool _visible; // should the overlay be drawn at all
|
||||
Anchor _anchor;
|
||||
|
||||
unsigned int _stackOrder { 0 };
|
||||
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
//
|
||||
// OverlayPanel.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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 "OverlayPanel.h"
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
|
||||
#include <QVariant>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
#include "Base3DOverlay.h"
|
||||
|
||||
PropertyBinding::PropertyBinding(QString avatar, QUuid entity) :
|
||||
avatar(avatar),
|
||||
entity(entity)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant propertyBindingToVariant(const PropertyBinding& value) {
|
||||
QVariantMap obj;
|
||||
|
||||
if (value.avatar == "MyAvatar") {
|
||||
obj["avatar"] = "MyAvatar";
|
||||
} else if (!value.entity.isNull()) {
|
||||
obj["entity"] = value.entity;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void propertyBindingFromVariant(const QVariant& objectVar, PropertyBinding& value) {
|
||||
auto object = objectVar.toMap();
|
||||
auto avatar = object["avatar"];
|
||||
auto entity = object["entity"];
|
||||
|
||||
if (avatar.isValid() && !avatar.isNull()) {
|
||||
value.avatar = avatar.toString();
|
||||
} else if (entity.isValid() && !entity.isNull()) {
|
||||
value.entity = entity.toUuid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OverlayPanel::addChild(OverlayID childId) {
|
||||
if (!_children.contains(childId)) {
|
||||
_children.append(childId);
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayPanel::removeChild(OverlayID childId) {
|
||||
if (_children.contains(childId)) {
|
||||
_children.removeOne(childId);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant OverlayPanel::getProperty(const QString &property) {
|
||||
if (property == "anchorPosition") {
|
||||
return vec3toVariant(getAnchorPosition());
|
||||
}
|
||||
if (property == "anchorPositionBinding") {
|
||||
return propertyBindingToVariant(PropertyBinding(_anchorPositionBindMyAvatar ?
|
||||
"MyAvatar" : "",
|
||||
_anchorPositionBindEntity));
|
||||
}
|
||||
if (property == "anchorRotation") {
|
||||
return quatToVariant(getAnchorRotation());
|
||||
}
|
||||
if (property == "anchorRotationBinding") {
|
||||
return propertyBindingToVariant(PropertyBinding(_anchorRotationBindMyAvatar ?
|
||||
"MyAvatar" : "",
|
||||
_anchorRotationBindEntity));
|
||||
}
|
||||
if (property == "anchorScale") {
|
||||
return vec3toVariant(getAnchorScale());
|
||||
}
|
||||
if (property == "visible") {
|
||||
return getVisible();
|
||||
}
|
||||
if (property == "children") {
|
||||
QVariantList array;
|
||||
for (int i = 0; i < _children.length(); i++) {
|
||||
array.append(OverlayIDtoScriptValue(nullptr, _children[i]).toVariant());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
auto value = Billboardable::getProperty(property);
|
||||
if (value.isValid()) {
|
||||
return value;
|
||||
}
|
||||
return PanelAttachable::getProperty(property);
|
||||
}
|
||||
|
||||
void OverlayPanel::setProperties(const QVariantMap& properties) {
|
||||
PanelAttachable::setProperties(properties);
|
||||
Billboardable::setProperties(properties);
|
||||
|
||||
auto anchorPosition = properties["anchorPosition"];
|
||||
if (anchorPosition.isValid()) {
|
||||
setAnchorPosition(vec3FromVariant(anchorPosition));
|
||||
}
|
||||
|
||||
auto anchorPositionBinding = properties["anchorPositionBinding"];
|
||||
if (anchorPositionBinding.isValid()) {
|
||||
PropertyBinding binding = {};
|
||||
propertyBindingFromVariant(anchorPositionBinding, binding);
|
||||
_anchorPositionBindMyAvatar = binding.avatar == "MyAvatar";
|
||||
_anchorPositionBindEntity = binding.entity;
|
||||
}
|
||||
|
||||
auto anchorRotation = properties["anchorRotation"];
|
||||
if (anchorRotation.isValid()) {
|
||||
setAnchorRotation(quatFromVariant(anchorRotation));
|
||||
}
|
||||
|
||||
auto anchorRotationBinding = properties["anchorRotationBinding"];
|
||||
if (anchorRotationBinding.isValid()) {
|
||||
PropertyBinding binding = {};
|
||||
propertyBindingFromVariant(anchorPositionBinding, binding);
|
||||
_anchorRotationBindMyAvatar = binding.avatar == "MyAvatar";
|
||||
_anchorRotationBindEntity = binding.entity;
|
||||
}
|
||||
|
||||
auto anchorScale = properties["anchorScale"];
|
||||
if (anchorScale.isValid()) {
|
||||
setAnchorScale(vec3FromVariant(anchorScale));
|
||||
}
|
||||
|
||||
auto visible = properties["visible"];
|
||||
if (visible.isValid()) {
|
||||
setVisible(visible.toBool());
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayPanel::applyTransformTo(Transform& transform, bool force) {
|
||||
if (force || usecTimestampNow() > _transformExpiry) {
|
||||
PanelAttachable::applyTransformTo(transform, true);
|
||||
if (!getParentPanel()) {
|
||||
if (_anchorPositionBindMyAvatar) {
|
||||
transform.setTranslation(DependencyManager::get<AvatarManager>()->getMyAvatar()
|
||||
->getPosition());
|
||||
} else if (!_anchorPositionBindEntity.isNull()) {
|
||||
EntityTreePointer entityTree = DependencyManager::get<EntityScriptingInterface>()->getEntityTree();
|
||||
entityTree->withReadLock([&] {
|
||||
EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorPositionBindEntity);
|
||||
if (foundEntity) {
|
||||
transform.setTranslation(foundEntity->getPosition());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
transform.setTranslation(getAnchorPosition());
|
||||
}
|
||||
|
||||
if (_anchorRotationBindMyAvatar) {
|
||||
transform.setRotation(DependencyManager::get<AvatarManager>()->getMyAvatar()
|
||||
->getOrientation());
|
||||
} else if (!_anchorRotationBindEntity.isNull()) {
|
||||
EntityTreePointer entityTree = DependencyManager::get<EntityScriptingInterface>()->getEntityTree();
|
||||
entityTree->withReadLock([&] {
|
||||
EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorRotationBindEntity);
|
||||
if (foundEntity) {
|
||||
transform.setRotation(foundEntity->getRotation());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
transform.setRotation(getAnchorRotation());
|
||||
}
|
||||
|
||||
transform.setScale(getAnchorScale());
|
||||
|
||||
transform.postTranslate(getOffsetPosition());
|
||||
transform.postRotate(getOffsetRotation());
|
||||
transform.postScale(getOffsetScale());
|
||||
}
|
||||
pointTransformAtCamera(transform, getOffsetRotation());
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,86 +0,0 @@
|
|||
//
|
||||
// OverlayPanel.h
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Created by Zander Otavka on 7/2/15.
|
||||
// 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_OverlayPanel_h
|
||||
#define hifi_OverlayPanel_h
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QUuid>
|
||||
|
||||
#include "PanelAttachable.h"
|
||||
#include "Billboardable.h"
|
||||
#include "Overlay.h"
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
class PropertyBinding {
|
||||
public:
|
||||
PropertyBinding() {}
|
||||
PropertyBinding(QString avatar, QUuid entity);
|
||||
QString avatar;
|
||||
QUuid entity;
|
||||
};
|
||||
|
||||
QVariant propertyBindingToVariant(const PropertyBinding& value);
|
||||
void propertyBindingFromVariant(const QVariant& object, PropertyBinding& value);
|
||||
|
||||
|
||||
class OverlayPanel : public QObject, public PanelAttachable, public Billboardable {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef std::shared_ptr<OverlayPanel> Pointer;
|
||||
|
||||
void init(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
// getters
|
||||
glm::vec3 getAnchorPosition() const { return _anchorTransform.getTranslation(); }
|
||||
glm::quat getAnchorRotation() const { return _anchorTransform.getRotation(); }
|
||||
glm::vec3 getAnchorScale() const { return _anchorTransform.getScale(); }
|
||||
bool getVisible() const { return _visible; }
|
||||
|
||||
// setters
|
||||
void setAnchorPosition(const glm::vec3& position) { _anchorTransform.setTranslation(position); }
|
||||
void setAnchorRotation(const glm::quat& rotation) { _anchorTransform.setRotation(rotation); }
|
||||
void setAnchorScale(float scale) { _anchorTransform.setScale(scale); }
|
||||
void setAnchorScale(const glm::vec3& scale) { _anchorTransform.setScale(scale); }
|
||||
void setVisible(bool visible) { _visible = visible; }
|
||||
|
||||
const QList<OverlayID>& getChildren() { return _children; }
|
||||
void addChild(OverlayID childId);
|
||||
void removeChild(OverlayID childId);
|
||||
OverlayID popLastChild() { return _children.takeLast(); }
|
||||
|
||||
void setProperties(const QVariantMap& properties);
|
||||
QVariant getProperty(const QString& property);
|
||||
|
||||
virtual void applyTransformTo(Transform& transform, bool force = false) override;
|
||||
|
||||
private:
|
||||
Transform _anchorTransform;
|
||||
|
||||
bool _anchorPositionBindMyAvatar = false;
|
||||
QUuid _anchorPositionBindEntity;
|
||||
|
||||
bool _anchorRotationBindMyAvatar = false;
|
||||
QUuid _anchorRotationBindEntity;
|
||||
|
||||
bool _visible = true;
|
||||
QList<OverlayID> _children;
|
||||
|
||||
QScriptEngine* _scriptEngine;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // hifi_OverlayPanel_h
|
|
@ -68,16 +68,10 @@ void Overlays::cleanupAllOverlays() {
|
|||
foreach(Overlay::Pointer overlay, overlaysWorld) {
|
||||
_overlaysToDelete.push_back(overlay);
|
||||
}
|
||||
#if OVERLAY_PANELS
|
||||
_panels.clear();
|
||||
#endif
|
||||
cleanupOverlaysToDelete();
|
||||
}
|
||||
|
||||
void Overlays::init() {
|
||||
#if OVERLAY_PANELS
|
||||
_scriptEngine = new QScriptEngine();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Overlays::update(float deltatime) {
|
||||
|
@ -300,12 +294,6 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
|
|||
|
||||
if (thisOverlay) {
|
||||
OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone(), [](Overlay* ptr) { ptr->deleteLater(); }));
|
||||
#if OVERLAY_PANELS
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay);
|
||||
if (attachable && attachable->getParentPanel()) {
|
||||
attachable->getParentPanel()->addChild(cloneId);
|
||||
}
|
||||
#endif
|
||||
return cloneId;
|
||||
}
|
||||
|
||||
|
@ -381,15 +369,6 @@ void Overlays::deleteOverlay(OverlayID id) {
|
|||
}
|
||||
}
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete);
|
||||
if (attachable && attachable->getParentPanel()) {
|
||||
attachable->getParentPanel()->removeChild(id);
|
||||
attachable->setParentPanel(nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
_overlaysToDelete.push_back(overlayToDelete);
|
||||
emit overlayDeleted(id);
|
||||
}
|
||||
|
@ -424,49 +403,6 @@ QObject* Overlays::getOverlayObject(OverlayID id) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
OverlayID Overlays::getParentPanel(OverlayID childId) const {
|
||||
Overlay::Pointer overlay = getOverlay(childId);
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
|
||||
if (attachable) {
|
||||
return _panels.key(attachable->getParentPanel());
|
||||
} else if (_panels.contains(childId)) {
|
||||
return _panels.key(getPanel(childId)->getParentPanel());
|
||||
}
|
||||
return UNKNOWN_OVERLAY_ID;
|
||||
}
|
||||
|
||||
void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) {
|
||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(getOverlay(childId));
|
||||
if (attachable) {
|
||||
if (_panels.contains(panelId)) {
|
||||
auto panel = getPanel(panelId);
|
||||
panel->addChild(childId);
|
||||
attachable->setParentPanel(panel);
|
||||
} else {
|
||||
auto panel = attachable->getParentPanel();
|
||||
if (panel) {
|
||||
panel->removeChild(childId);
|
||||
attachable->setParentPanel(nullptr);
|
||||
}
|
||||
}
|
||||
} else if (_panels.contains(childId)) {
|
||||
OverlayPanel::Pointer child = getPanel(childId);
|
||||
if (_panels.contains(panelId)) {
|
||||
auto panel = getPanel(panelId);
|
||||
panel->addChild(childId);
|
||||
child->setParentPanel(panel);
|
||||
} else {
|
||||
auto panel = child->getParentPanel();
|
||||
if (panel) {
|
||||
panel->removeChild(childId);
|
||||
child->setParentPanel(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||
if (!_enabled) {
|
||||
return UNKNOWN_OVERLAY_ID;
|
||||
|
@ -717,62 +653,6 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) {
|
|||
return QSizeF(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) {
|
||||
QWriteLocker lock(&_lock);
|
||||
|
||||
OverlayID thisID = QUuid::createUuid();
|
||||
_panels[thisID] = panel;
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
OverlayID Overlays::addPanel(const QVariant& properties) {
|
||||
OverlayPanel::Pointer panel = std::make_shared<OverlayPanel>();
|
||||
panel->init(_scriptEngine);
|
||||
panel->setProperties(properties.toMap());
|
||||
return addPanel(panel);
|
||||
}
|
||||
|
||||
void Overlays::editPanel(OverlayID panelId, const QVariant& properties) {
|
||||
if (_panels.contains(panelId)) {
|
||||
_panels[panelId]->setProperties(properties.toMap());
|
||||
}
|
||||
}
|
||||
|
||||
OverlayPropertyResult Overlays::getPanelProperty(OverlayID panelId, const QString& property) {
|
||||
OverlayPropertyResult result;
|
||||
if (_panels.contains(panelId)) {
|
||||
OverlayPanel::Pointer thisPanel = getPanel(panelId);
|
||||
QReadLocker lock(&_lock);
|
||||
result.value = thisPanel->getProperty(property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Overlays::deletePanel(OverlayID panelId) {
|
||||
OverlayPanel::Pointer panelToDelete;
|
||||
|
||||
{
|
||||
QWriteLocker lock(&_lock);
|
||||
if (_panels.contains(panelId)) {
|
||||
panelToDelete = _panels.take(panelId);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (!panelToDelete->getChildren().isEmpty()) {
|
||||
OverlayID childId = panelToDelete->popLastChild();
|
||||
deleteOverlay(childId);
|
||||
deletePanel(childId);
|
||||
}
|
||||
|
||||
emit panelDeleted(panelId);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Overlays::isAddedOverlay(OverlayID id) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
bool result;
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "Overlay.h"
|
||||
|
||||
#include "PanelAttachable.h"
|
||||
#include "OverlayPanel.h"
|
||||
|
||||
class PickRay;
|
||||
|
||||
|
@ -93,9 +92,6 @@ public:
|
|||
void enable();
|
||||
|
||||
Overlay::Pointer getOverlay(OverlayID id) const;
|
||||
#if OVERLAY_PANELS
|
||||
OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; }
|
||||
#endif
|
||||
|
||||
/// adds an overlay that's already been created
|
||||
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
||||
|
@ -468,30 +464,6 @@ public slots:
|
|||
*/
|
||||
bool isAddedOverlay(OverlayID id);
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
OverlayID getParentPanel(OverlayID childId) const;
|
||||
void setParentPanel(OverlayID childId, OverlayID panelId);
|
||||
|
||||
/// adds a panel that has already been created
|
||||
OverlayID addPanel(OverlayPanel::Pointer panel);
|
||||
|
||||
/// creates and adds a panel based on a set of properties
|
||||
OverlayID addPanel(const QVariant& properties);
|
||||
|
||||
/// edit the properties of a panel
|
||||
void editPanel(OverlayID panelId, const QVariant& properties);
|
||||
|
||||
/// get a property of a panel
|
||||
OverlayPropertyResult getPanelProperty(OverlayID panelId, const QString& property);
|
||||
|
||||
/// deletes a panel and all child overlays
|
||||
void deletePanel(OverlayID panelId);
|
||||
|
||||
/// return true if there is a panel with that id else false
|
||||
bool isAddedPanel(OverlayID id) { return _panels.contains(id); }
|
||||
|
||||
#endif
|
||||
|
||||
/**jsdoc
|
||||
* Generate a mouse press event on an overlay.
|
||||
* @function Overlays.sendMousePressOnOverlay
|
||||
|
@ -612,10 +584,6 @@ signals:
|
|||
*/
|
||||
void overlayDeleted(OverlayID id);
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
void panelDeleted(OverlayID id);
|
||||
#endif
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when a mouse press event occurs on an overlay. Only occurs for 3D overlays (unless you use
|
||||
* {@link Overlays.sendMousePressOnOverlay|sendMousePressOnOverlay} for a 2D overlay).
|
||||
|
@ -732,15 +700,9 @@ private:
|
|||
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
QMap<OverlayID, OverlayPanel::Pointer> _panels;
|
||||
#endif
|
||||
QList<Overlay::Pointer> _overlaysToDelete;
|
||||
unsigned int _stackOrder { 1 };
|
||||
|
||||
#if OVERLAY_PANELS
|
||||
QScriptEngine* _scriptEngine;
|
||||
#endif
|
||||
bool _enabled = true;
|
||||
|
||||
PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
|
||||
|
|
|
@ -65,23 +65,7 @@ namespace render {
|
|||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
||||
auto batch = args->_batch;
|
||||
auto avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::quat myAvatarRotation = avatar->getWorldOrientation();
|
||||
glm::vec3 myAvatarPosition = avatar->getWorldPosition();
|
||||
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||
glm::vec3 axis = glm::axis(myAvatarRotation);
|
||||
float myAvatarScale = avatar->getModelScale();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(myAvatarPosition);
|
||||
transform.setRotation(glm::angleAxis(angle, axis));
|
||||
transform.setScale(myAvatarScale);
|
||||
batch->setModelTransform(transform);
|
||||
overlay->render(args);
|
||||
} else {
|
||||
overlay->render(args);
|
||||
}
|
||||
overlay->render(args);
|
||||
}
|
||||
}
|
||||
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay) {
|
||||
|
|
|
@ -13,18 +13,8 @@
|
|||
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "OverlayPanel.h"
|
||||
|
||||
bool PanelAttachable::getParentVisible() const {
|
||||
#if OVERLAY_PANELS
|
||||
if (getParentPanel()) {
|
||||
return getParentPanel()->getVisible() && getParentPanel()->getParentVisible();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// JSDoc for copying to @typedefs of overlay types that inherit PanelAttachable.
|
||||
|
@ -67,15 +57,6 @@ bool PanelAttachable::applyTransformTo(Transform& transform, bool force) {
|
|||
if (force || usecTimestampNow() > _transformExpiry) {
|
||||
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
|
||||
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
|
||||
#if OVERLAY_PANELS
|
||||
if (getParentPanel()) {
|
||||
getParentPanel()->applyTransformTo(transform, true);
|
||||
transform.postTranslate(getOffsetPosition());
|
||||
transform.postRotate(getOffsetRotation());
|
||||
transform.postScale(getOffsetScale());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#ifndef hifi_PanelAttachable_h
|
||||
#define hifi_PanelAttachable_h
|
||||
|
||||
#define OVERLAY_PANELS 0
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -44,18 +42,12 @@ class OverlayPanel;
|
|||
class PanelAttachable {
|
||||
public:
|
||||
// getters
|
||||
#if OVERLAY_PANELS
|
||||
std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; }
|
||||
#endif
|
||||
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
|
||||
glm::quat getOffsetRotation() const { return _offset.getRotation(); }
|
||||
glm::vec3 getOffsetScale() const { return _offset.getScale(); }
|
||||
bool getParentVisible() const;
|
||||
|
||||
// setters
|
||||
#if OVERLAY_PANELS
|
||||
void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; }
|
||||
#endif
|
||||
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
|
||||
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
|
||||
void setOffsetScale(float scale) { _offset.setScale(scale); }
|
||||
|
@ -71,9 +63,6 @@ protected:
|
|||
quint64 _transformExpiry = 0;
|
||||
|
||||
private:
|
||||
#if OVERLAY_PANELS
|
||||
std::shared_ptr<OverlayPanel> _parentPanel = nullptr;
|
||||
#endif
|
||||
Transform _offset;
|
||||
};
|
||||
|
||||
|
|
|
@ -127,8 +127,6 @@ const render::ShapeKey Rectangle3DOverlay::getShapeKey() {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -128,8 +128,6 @@ void Shape3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -47,8 +47,6 @@ Sphere3DOverlay::Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay) :
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -224,8 +224,6 @@ void Text3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -484,8 +484,6 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) {
|
|||
* the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise
|
||||
* used.)
|
||||
* @property {boolean} visible=true - If <code>true</code>, the overlay is rendered, otherwise it is not rendered.
|
||||
* @property {string} anchor="" - If set to <code>"MyAvatar"</code> then the overlay is attached to your avatar, moving and
|
||||
* rotating as you move your avatar.
|
||||
*
|
||||
* @property {string} name="" - A friendly name for the overlay.
|
||||
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
|
||||
|
|
|
@ -328,13 +328,15 @@ void Avatar::updateAvatarEntities() {
|
|||
AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs();
|
||||
if (!recentlyDettachedAvatarEntities.empty()) {
|
||||
// only lock this thread when absolutely necessary
|
||||
AvatarEntityMap avatarEntityData;
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
foreach (auto entityID, recentlyDettachedAvatarEntities) {
|
||||
if (!_avatarEntityData.contains(entityID)) {
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
}
|
||||
}
|
||||
avatarEntityData = _avatarEntityData;
|
||||
});
|
||||
foreach (auto entityID, recentlyDettachedAvatarEntities) {
|
||||
if (!avatarEntityData.contains(entityID)) {
|
||||
entityTree->deleteEntity(entityID, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// remove stale data hashes
|
||||
foreach (auto entityID, recentlyDettachedAvatarEntities) {
|
||||
|
|
|
@ -2086,6 +2086,10 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
|||
|
||||
EntityDynamicPointer action = _objectActions[actionID];
|
||||
auto removedActionType = action->getType();
|
||||
action->setOwnerEntity(nullptr);
|
||||
action->setIsMine(false);
|
||||
_objectActions.remove(actionID);
|
||||
|
||||
if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) {
|
||||
_dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING;
|
||||
_dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar
|
||||
|
@ -2101,9 +2105,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi
|
|||
// because they should have been set correctly when the action was added
|
||||
// and/or when children were linked
|
||||
}
|
||||
action->setOwnerEntity(nullptr);
|
||||
action->setIsMine(false);
|
||||
_objectActions.remove(actionID);
|
||||
|
||||
if (simulation) {
|
||||
action->removeFromSimulation(simulation);
|
||||
|
|
|
@ -722,7 +722,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask);
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collidesWith, CollisionMask);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(collidesWith, CollisionMask);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight);
|
||||
|
@ -737,7 +737,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, xColor, setBackgroundColor);
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(shapeType, ShapeType);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isEmitting, bool, setIsEmitting);
|
||||
|
@ -775,10 +775,10 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(hazeMode, HazeMode);
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(keyLightMode, KeyLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(ambientLightMode, AmbientLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(skyboxMode, SkyboxMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(hazeMode, HazeMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
|
||||
|
|
|
@ -367,7 +367,7 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid
|
|||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(P, S) \
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QString newValue = P.toVariant().toString(); \
|
||||
|
|
|
@ -19,15 +19,6 @@
|
|||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#define CPU_MIPMAPS 1
|
||||
#else
|
||||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <Finally.h>
|
||||
#include <Profile.h>
|
||||
#include <StatTracker.h>
|
||||
|
@ -37,6 +28,12 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#define CPU_MIPMAPS 1
|
||||
#else
|
||||
#define CPU_MIPMAPS 1
|
||||
#include <nvtt/nvtt.h>
|
||||
#endif
|
||||
|
||||
static const glm::uvec2 SPARSE_PAGE_SIZE(128);
|
||||
static const glm::uvec2 MAX_TEXTURE_SIZE(4096);
|
||||
|
@ -51,25 +48,21 @@ static std::atomic<bool> compressNormalTextures { false };
|
|||
static std::atomic<bool> compressGrayscaleTextures { false };
|
||||
static std::atomic<bool> compressCubeTextures { false };
|
||||
|
||||
bool needsSparseRectification(const glm::uvec2& size) {
|
||||
// Don't attempt to rectify small textures (textures less than the sparse page size in any dimension)
|
||||
if (glm::any(glm::lessThan(size, SPARSE_PAGE_SIZE))) {
|
||||
return false;
|
||||
uint rectifyDimension(const uint& dimension) {
|
||||
if (dimension < SPARSE_PAGE_SIZE.x) {
|
||||
uint newSize = SPARSE_PAGE_SIZE.x;
|
||||
while (dimension <= newSize / 2) {
|
||||
newSize /= 2;
|
||||
}
|
||||
return newSize;
|
||||
} else {
|
||||
uint pages = (dimension / SPARSE_PAGE_SIZE.x) + (dimension % SPARSE_PAGE_SIZE.x == 0 ? 0 : 1);
|
||||
return pages * SPARSE_PAGE_SIZE.x;
|
||||
}
|
||||
|
||||
// Don't rectify textures that are already an exact multiple of sparse page size
|
||||
if (glm::uvec2(0) == (size % SPARSE_PAGE_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Texture is not sparse compatible, but is bigger than the sparse page size in both dimensions, rectify!
|
||||
return true;
|
||||
}
|
||||
|
||||
glm::uvec2 rectifyToSparseSize(const glm::uvec2& size) {
|
||||
glm::uvec2 pages = ((size / SPARSE_PAGE_SIZE) + glm::clamp(size % SPARSE_PAGE_SIZE, glm::uvec2(0), glm::uvec2(1)));
|
||||
glm::uvec2 result = pages * SPARSE_PAGE_SIZE;
|
||||
return result;
|
||||
glm::uvec2 rectifySize(const glm::uvec2& size) {
|
||||
return { rectifyDimension(size.x), rectifyDimension(size.y) };
|
||||
}
|
||||
|
||||
|
||||
|
@ -329,9 +322,12 @@ QImage processSourceImage(QImage&& srcImage, bool cubemap) {
|
|||
++DECIMATED_TEXTURE_COUNT;
|
||||
}
|
||||
|
||||
if (!cubemap && needsSparseRectification(targetSize)) {
|
||||
++RECTIFIED_TEXTURE_COUNT;
|
||||
targetSize = rectifyToSparseSize(targetSize);
|
||||
if (!cubemap) {
|
||||
auto rectifiedSize = rectifySize(targetSize);
|
||||
if (rectifiedSize != targetSize) {
|
||||
++RECTIFIED_TEXTURE_COUNT;
|
||||
targetSize = rectifiedSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEV_DECIMATE_TEXTURES && glm::all(glm::greaterThanEqual(targetSize / SPARSE_PAGE_SIZE, glm::uvec2(2)))) {
|
||||
|
|
|
@ -73,6 +73,7 @@ public:
|
|||
* Get Interface's protocol version.
|
||||
* @function location.protocolVersion
|
||||
* @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using.
|
||||
* @deprecated This function is deprecated and will be removed. Use {@link Window.protocolSignature} instead.
|
||||
*/
|
||||
Q_INVOKABLE QString protocolVersion();
|
||||
|
||||
|
|
|
@ -63,13 +63,6 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) :
|
|||
_packetStatTimer(),
|
||||
_permissions(NodePermissions())
|
||||
{
|
||||
static bool firstCall = true;
|
||||
if (firstCall) {
|
||||
NodeType::init();
|
||||
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
qRegisterMetaType<ConnectionStep>("ConnectionStep");
|
||||
auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get();
|
||||
_nodeSocket.bind(QHostAddress::AnyIPv4, port);
|
||||
|
|
|
@ -29,28 +29,25 @@ int NodePtrMetaTypeId = qRegisterMetaType<Node*>("Node*");
|
|||
int sharedPtrNodeMetaTypeId = qRegisterMetaType<QSharedPointer<Node>>("QSharedPointer<Node>");
|
||||
int sharedNodePtrMetaTypeId = qRegisterMetaType<SharedNodePointer>("SharedNodePointer");
|
||||
|
||||
void NodeType::init() {
|
||||
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||
|
||||
TypeNameHash.insert(NodeType::DomainServer, "Domain Server");
|
||||
TypeNameHash.insert(NodeType::EntityServer, "Entity Server");
|
||||
TypeNameHash.insert(NodeType::Agent, "Agent");
|
||||
TypeNameHash.insert(NodeType::AudioMixer, "Audio Mixer");
|
||||
TypeNameHash.insert(NodeType::AvatarMixer, "Avatar Mixer");
|
||||
TypeNameHash.insert(NodeType::MessagesMixer, "Messages Mixer");
|
||||
TypeNameHash.insert(NodeType::AssetServer, "Asset Server");
|
||||
TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server");
|
||||
TypeNameHash.insert(NodeType::UpstreamAudioMixer, "Upstream Audio Mixer");
|
||||
TypeNameHash.insert(NodeType::UpstreamAvatarMixer, "Upstream Avatar Mixer");
|
||||
TypeNameHash.insert(NodeType::DownstreamAudioMixer, "Downstream Audio Mixer");
|
||||
TypeNameHash.insert(NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer");
|
||||
TypeNameHash.insert(NodeType::Unassigned, "Unassigned");
|
||||
}
|
||||
static const QHash<NodeType_t, QString> TYPE_NAME_HASH {
|
||||
{ NodeType::DomainServer, "Domain Server" },
|
||||
{ NodeType::EntityServer, "Entity Server" },
|
||||
{ NodeType::Agent, "Agent" },
|
||||
{ NodeType::AudioMixer, "Audio Mixer" },
|
||||
{ NodeType::AvatarMixer, "Avatar Mixer" },
|
||||
{ NodeType::MessagesMixer, "Messages Mixer" },
|
||||
{ NodeType::AssetServer, "Asset Server" },
|
||||
{ NodeType::EntityScriptServer, "Entity Script Server" },
|
||||
{ NodeType::UpstreamAudioMixer, "Upstream Audio Mixer" },
|
||||
{ NodeType::UpstreamAvatarMixer, "Upstream Avatar Mixer" },
|
||||
{ NodeType::DownstreamAudioMixer, "Downstream Audio Mixer" },
|
||||
{ NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer" },
|
||||
{ NodeType::Unassigned, "Unassigned" }
|
||||
};
|
||||
|
||||
const QString& NodeType::getNodeTypeName(NodeType_t nodeType) {
|
||||
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||
QHash<NodeType_t, QString>::iterator matchedTypeName = TypeNameHash.find(nodeType);
|
||||
return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME;
|
||||
const auto matchedTypeName = TYPE_NAME_HASH.find(nodeType);
|
||||
return matchedTypeName != TYPE_NAME_HASH.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME;
|
||||
}
|
||||
|
||||
bool NodeType::isUpstream(NodeType_t nodeType) {
|
||||
|
@ -84,8 +81,7 @@ NodeType_t NodeType::downstreamType(NodeType_t primaryType) {
|
|||
}
|
||||
|
||||
NodeType_t NodeType::fromString(QString type) {
|
||||
QHash<NodeType_t, QString>& TypeNameHash = Node::getTypeNameHash();
|
||||
return TypeNameHash.key(type, NodeType::Unassigned);
|
||||
return TYPE_NAME_HASH.key(type, NodeType::Unassigned);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -89,11 +89,6 @@ public:
|
|||
|
||||
bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; }
|
||||
|
||||
static QHash<NodeType_t, QString>& getTypeNameHash() {
|
||||
static QHash<NodeType_t, QString> TypeNameHash;
|
||||
return TypeNameHash;
|
||||
}
|
||||
|
||||
private:
|
||||
// privatize copy and assignment operator to disallow Node copying
|
||||
Node(const Node &otherNode);
|
||||
|
|
|
@ -31,8 +31,6 @@ namespace NodeType {
|
|||
const NodeType_t DownstreamAvatarMixer = 'w';
|
||||
const NodeType_t Unassigned = 1;
|
||||
|
||||
void init();
|
||||
|
||||
const QString& getNodeTypeName(NodeType_t nodeType);
|
||||
bool isUpstream(NodeType_t nodeType);
|
||||
bool isDownstream(NodeType_t nodeType);
|
||||
|
|
|
@ -319,11 +319,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs&
|
|||
// Setup lighting model for all items;
|
||||
batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer());
|
||||
|
||||
// Setup haze iff curretn zone has haze
|
||||
// Setup haze iff current zone has haze
|
||||
auto hazeStage = args->_scene->getStage<HazeStage>();
|
||||
if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) {
|
||||
graphics::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front());
|
||||
batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer());
|
||||
if (hazePointer) {
|
||||
batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
// From the lighting model define a global shapKey ORED with individiual keys
|
||||
|
|
|
@ -87,7 +87,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
|||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("hazeParametersBuffer"), Slot::BUFFER::HAZE_MODEL));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
|
|
77
scripts/developer/utilities/render/lod.js
Normal file
77
scripts/developer/utilities/render/lod.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
"use strict";
|
||||
|
||||
//
|
||||
// lodi.js
|
||||
// tablet-engine app
|
||||
//
|
||||
// Copyright 2018 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
|
||||
//
|
||||
|
||||
(function() {
|
||||
var TABLET_BUTTON_NAME = "LOD";
|
||||
var QMLAPP_URL = Script.resolvePath("./lod.qml");
|
||||
var ICON_URL = Script.resolvePath("../../../system/assets/images/lod-i.svg");
|
||||
var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/lod-a.svg");
|
||||
|
||||
var onScreen = false;
|
||||
|
||||
function onClicked() {
|
||||
if (onScreen) {
|
||||
tablet.gotoHomeScreen();
|
||||
} else {
|
||||
tablet.loadQMLSource(QMLAPP_URL);
|
||||
}
|
||||
}
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var button = tablet.addButton({
|
||||
text: TABLET_BUTTON_NAME,
|
||||
icon: ICON_URL,
|
||||
activeIcon: ACTIVE_ICON_URL,
|
||||
sortOrder: 1
|
||||
});
|
||||
|
||||
var hasEventBridge = false;
|
||||
|
||||
function wireEventBridge(on) {
|
||||
if (!tablet) {
|
||||
print("Warning in wireEventBridge(): 'tablet' undefined!");
|
||||
return;
|
||||
}
|
||||
if (on) {
|
||||
if (!hasEventBridge) {
|
||||
tablet.fromQml.connect(fromQml);
|
||||
hasEventBridge = true;
|
||||
}
|
||||
} else {
|
||||
if (hasEventBridge) {
|
||||
tablet.fromQml.disconnect(fromQml);
|
||||
hasEventBridge = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onScreenChanged(type, url) {
|
||||
onScreen = (url === QMLAPP_URL);
|
||||
button.editProperties({isActive: onScreen});
|
||||
wireEventBridge(onScreen);
|
||||
}
|
||||
|
||||
function fromQml(message) {
|
||||
}
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
tablet.screenChanged.connect(onScreenChanged);
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
if (onScreen) {
|
||||
tablet.gotoHomeScreen();
|
||||
}
|
||||
button.clicked.disconnect(onClicked);
|
||||
tablet.screenChanged.disconnect(onScreenChanged);
|
||||
tablet.removeButton(button);
|
||||
});
|
||||
}());
|
92
scripts/developer/utilities/render/lod.qml
Normal file
92
scripts/developer/utilities/render/lod.qml
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// lod.qml
|
||||
// scripts/developer/utilities/render
|
||||
//
|
||||
// Created by Andrew Meadows on 2018.01.10
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "../lib/plotperf"
|
||||
|
||||
Item {
|
||||
id: lodIU
|
||||
anchors.fill:parent
|
||||
|
||||
Column {
|
||||
id: stats
|
||||
spacing: 8
|
||||
anchors.fill:parent
|
||||
|
||||
function evalEvenHeight() {
|
||||
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
|
||||
return (height - spacing * (children.length - 1)) / children.length
|
||||
}
|
||||
|
||||
PlotPerf {
|
||||
title: "Load Indicators"
|
||||
height: parent.evalEvenHeight()
|
||||
object: LODManager
|
||||
valueScale: 1
|
||||
valueUnit: "ms"
|
||||
plots: [
|
||||
{
|
||||
prop: "presentTime",
|
||||
label: "present",
|
||||
color: "#FFFF00"
|
||||
},
|
||||
{
|
||||
prop: "engineRunTime",
|
||||
label: "engineRun",
|
||||
color: "#FF00FF"
|
||||
},
|
||||
{
|
||||
prop: "gpuTime",
|
||||
label: "gpu",
|
||||
color: "#00FFFF"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "FPS"
|
||||
height: parent.evalEvenHeight()
|
||||
object: LODManager
|
||||
valueScale: 1
|
||||
valueUnit: "Hz"
|
||||
plots: [
|
||||
{
|
||||
prop: "lodIncreaseFPS",
|
||||
label: "LOD++",
|
||||
color: "#66FF66"
|
||||
},
|
||||
{
|
||||
prop: "fps",
|
||||
label: "FPS",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
{
|
||||
prop: "lodDecreaseFPS",
|
||||
label: "LOD--",
|
||||
color: "#FF6666"
|
||||
}
|
||||
]
|
||||
}
|
||||
PlotPerf {
|
||||
title: "LOD"
|
||||
height: parent.evalEvenHeight()
|
||||
object: LODManager
|
||||
valueScale: 0.1
|
||||
valueUnit: ""
|
||||
plots: [
|
||||
{
|
||||
prop: "lodLevel",
|
||||
label: "LOD",
|
||||
color: "#9999FF"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
46
scripts/system/assets/images/lod-a.svg
Normal file
46
scripts/system/assets/images/lod-a.svg
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lod-a.svg"><metadata
|
||||
id="metadata4241"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs4239" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2880"
|
||||
inkscape:window-height="1724"
|
||||
id="namedview4237"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.66"
|
||||
inkscape:cx="22.9339"
|
||||
inkscape:cy="22.463149"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="33"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:44.7959404px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 0.17382812 0.10351562 L 0.17382812 26.466797 L 12.335938 26.466797 C 12.295785 25.916449 12.273438 25.352399 12.273438 24.773438 C 12.273438 24.325519 12.298233 23.895635 12.322266 23.464844 L 5.6464844 23.464844 L 5.6464844 0.10351562 L 0.17382812 0.10351562 z M 12.322266 23.464844 L 16.9375 23.464844 C 17.131223 20.269693 18.048402 17.696004 19.695312 15.748047 C 21.57624 13.54041 24.107908 12.4375 27.291016 12.4375 C 30.474123 12.4375 32.99176 13.54041 34.84375 15.748047 C 36.522116 17.733209 37.438284 20.371891 37.607422 23.652344 C 39.352093 23.851854 40.904899 24.187106 42.263672 24.662109 C 42.242096 19.950324 40.88586 16.190967 38.1875 13.386719 C 35.46739 10.546406 31.834178 9.125 27.291016 9.125 C 22.733385 9.125 19.088094 10.546406 16.353516 13.386719 C 13.889087 15.947857 12.553913 19.312575 12.322266 23.464844 z M 42.263672 24.662109 C 42.263846 24.700089 42.267578 24.735334 42.267578 24.773438 C 42.267578 25.968111 42.179749 27.101932 42.007812 28.175781 C 42.345297 28.39193 42.664811 28.621521 42.951172 28.876953 C 44.826172 30.525965 45.763672 33.130435 45.763672 36.689453 C 45.763672 40.272198 44.826172 42.893812 42.951172 44.554688 C 41.089193 46.215563 38.146485 47.046875 34.123047 47.046875 L 29.357422 47.046875 L 29.357422 40.285156 C 28.688843 40.354889 28.004565 40.402344 27.291016 40.402344 C 26.644531 40.402344 26.021914 40.365471 25.412109 40.308594 L 25.412109 50 L 33.517578 50 C 39.142578 50 43.283203 48.926571 45.939453 46.779297 C 48.595703 44.632023 49.923828 41.268723 49.923828 36.689453 C 49.923828 32.13391 48.602214 28.787755 45.958984 26.652344 C 44.948178 25.831197 43.714341 25.169238 42.263672 24.662109 z M 25.412109 40.308594 L 25.412109 36.939453 C 23.099 36.57794 21.188155 35.53144 19.695312 33.779297 C 18.116681 31.9121 17.214144 29.470287 16.970703 26.466797 L 12.335938 26.466797 C 12.626268 30.446204 13.963889 33.678709 16.353516 36.162109 C 18.700203 38.587982 21.722877 39.964492 25.412109 40.308594 z M 16.970703 26.466797 L 25.34375 26.466797 L 25.34375 23.464844 L 16.9375 23.464844 C 16.911675 23.890786 16.896484 24.325331 16.896484 24.773438 C 16.896484 25.358829 16.926317 25.91918 16.970703 26.466797 z M 25.412109 36.939453 C 26.013434 37.033433 26.634257 37.091797 27.291016 37.091797 C 28.01543 37.091797 28.701951 37.02645 29.357422 36.912109 L 29.357422 26.386719 L 34.123047 26.386719 C 35.374898 26.386719 36.510129 26.475933 37.552734 26.636719 C 37.606917 26.036054 37.644531 25.420213 37.644531 24.773438 C 37.644531 24.389533 37.626377 24.01998 37.607422 23.652344 C 36.34394 23.507859 34.983448 23.431641 33.517578 23.431641 L 25.412109 23.431641 L 25.412109 36.939453 z M 37.552734 26.636719 C 37.288908 29.561476 36.3922 31.947799 34.84375 33.779297 C 33.413238 35.484518 31.582121 36.524034 29.357422 36.912109 L 29.357422 40.285156 C 32.945677 39.910903 35.894611 38.544976 38.1875 36.162109 C 40.223734 34.035893 41.495873 31.373159 42.007812 28.175781 C 40.833664 27.423776 39.345701 26.913222 37.552734 26.636719 z "
|
||||
id="text4243" /></svg>
|
After Width: | Height: | Size: 4.9 KiB |
46
scripts/system/assets/images/lod-i.svg
Normal file
46
scripts/system/assets/images/lod-i.svg
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="lod-i.svg"><metadata
|
||||
id="metadata4241"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs4239" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2880"
|
||||
inkscape:window-height="1724"
|
||||
id="namedview4237"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.66"
|
||||
inkscape:cx="22.9339"
|
||||
inkscape:cy="22.463149"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="33"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:44.7959404px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 0.17382812 0.10351562 L 0.17382812 26.466797 L 12.335938 26.466797 C 12.295785 25.916449 12.273438 25.352399 12.273438 24.773438 C 12.273438 24.325519 12.298233 23.895635 12.322266 23.464844 L 5.6464844 23.464844 L 5.6464844 0.10351562 L 0.17382812 0.10351562 z M 12.322266 23.464844 L 16.9375 23.464844 C 17.131223 20.269693 18.048402 17.696004 19.695312 15.748047 C 21.57624 13.54041 24.107908 12.4375 27.291016 12.4375 C 30.474123 12.4375 32.99176 13.54041 34.84375 15.748047 C 36.522116 17.733209 37.438284 20.371891 37.607422 23.652344 C 39.352093 23.851854 40.904899 24.187106 42.263672 24.662109 C 42.242096 19.950324 40.88586 16.190967 38.1875 13.386719 C 35.46739 10.546406 31.834178 9.125 27.291016 9.125 C 22.733385 9.125 19.088094 10.546406 16.353516 13.386719 C 13.889087 15.947857 12.553913 19.312575 12.322266 23.464844 z M 42.263672 24.662109 C 42.263846 24.700089 42.267578 24.735334 42.267578 24.773438 C 42.267578 25.968111 42.179749 27.101932 42.007812 28.175781 C 42.345297 28.39193 42.664811 28.621521 42.951172 28.876953 C 44.826172 30.525965 45.763672 33.130435 45.763672 36.689453 C 45.763672 40.272198 44.826172 42.893812 42.951172 44.554688 C 41.089193 46.215563 38.146485 47.046875 34.123047 47.046875 L 29.357422 47.046875 L 29.357422 40.285156 C 28.688843 40.354889 28.004565 40.402344 27.291016 40.402344 C 26.644531 40.402344 26.021914 40.365471 25.412109 40.308594 L 25.412109 50 L 33.517578 50 C 39.142578 50 43.283203 48.926571 45.939453 46.779297 C 48.595703 44.632023 49.923828 41.268723 49.923828 36.689453 C 49.923828 32.13391 48.602214 28.787755 45.958984 26.652344 C 44.948178 25.831197 43.714341 25.169238 42.263672 24.662109 z M 25.412109 40.308594 L 25.412109 36.939453 C 23.099 36.57794 21.188155 35.53144 19.695312 33.779297 C 18.116681 31.9121 17.214144 29.470287 16.970703 26.466797 L 12.335938 26.466797 C 12.626268 30.446204 13.963889 33.678709 16.353516 36.162109 C 18.700203 38.587982 21.722877 39.964492 25.412109 40.308594 z M 16.970703 26.466797 L 25.34375 26.466797 L 25.34375 23.464844 L 16.9375 23.464844 C 16.911675 23.890786 16.896484 24.325331 16.896484 24.773438 C 16.896484 25.358829 16.926317 25.91918 16.970703 26.466797 z M 25.412109 36.939453 C 26.013434 37.033433 26.634257 37.091797 27.291016 37.091797 C 28.01543 37.091797 28.701951 37.02645 29.357422 36.912109 L 29.357422 26.386719 L 34.123047 26.386719 C 35.374898 26.386719 36.510129 26.475933 37.552734 26.636719 C 37.606917 26.036054 37.644531 25.420213 37.644531 24.773438 C 37.644531 24.389533 37.626377 24.01998 37.607422 23.652344 C 36.34394 23.507859 34.983448 23.431641 33.517578 23.431641 L 25.412109 23.431641 L 25.412109 36.939453 z M 37.552734 26.636719 C 37.288908 29.561476 36.3922 31.947799 34.84375 33.779297 C 33.413238 35.484518 31.582121 36.524034 29.357422 36.912109 L 29.357422 40.285156 C 32.945677 39.910903 35.894611 38.544976 38.1875 36.162109 C 40.223734 34.035893 41.495873 31.373159 42.007812 28.175781 C 40.833664 27.423776 39.345701 26.913222 37.552734 26.636719 z "
|
||||
id="text4243" /></svg>
|
After Width: | Height: | Size: 4.9 KiB |
|
@ -136,7 +136,7 @@
|
|||
'include_actions=' + actions,
|
||||
'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'),
|
||||
'require_online=true',
|
||||
'protocol=' + encodeURIComponent(location.protocolVersion()),
|
||||
'protocol=' + encodeURIComponent(Window.protocolSignature()),
|
||||
'per_page=' + count
|
||||
];
|
||||
var url = Account.metaverseServerURL + '/api/v1/user_stories?' + options.join('&');
|
||||
|
|
|
@ -163,46 +163,31 @@ class MyTestWindow : public TestWindow {
|
|||
}
|
||||
};
|
||||
|
||||
extern bool needsSparseRectification(const uvec2& size);
|
||||
extern uvec2 rectifyToSparseSize(const uvec2& size);
|
||||
extern uvec2 rectifySize(const uvec2& size);
|
||||
|
||||
void testSparseRectify() {
|
||||
std::vector<std::pair<uvec2, bool>> NEEDS_SPARSE_TESTS {{
|
||||
std::vector<std::pair<uvec2, uvec2>> SPARSE_SIZE_TESTS {
|
||||
// Already sparse
|
||||
{ {1024, 1024 }, false },
|
||||
{ { 128, 128 }, false },
|
||||
{ {1024, 1024 }, { 1024, 1024 } },
|
||||
{ { 128, 128 }, { 128, 128 } },
|
||||
// Too small in one dimension
|
||||
{ { 127, 127 }, false },
|
||||
{ { 1, 1 }, false },
|
||||
{ { 1000, 1 }, false },
|
||||
{ { 1024, 1 }, false },
|
||||
{ { 100, 100 }, false },
|
||||
// needs rectification
|
||||
{ { 1000, 1000 }, true },
|
||||
{ { 1024, 1000 }, true },
|
||||
} };
|
||||
|
||||
for (const auto& test : NEEDS_SPARSE_TESTS) {
|
||||
const auto& size = test.first;
|
||||
const auto& expected = test.second;
|
||||
auto result = needsSparseRectification(size);
|
||||
Q_ASSERT(expected == result);
|
||||
result = needsSparseRectification(uvec2(size.y, size.x));
|
||||
Q_ASSERT(expected == result);
|
||||
}
|
||||
|
||||
std::vector<std::pair<uvec2, uvec2>> SPARSE_SIZE_TESTS { {
|
||||
{ { 127, 127 }, { 128, 128 } },
|
||||
{ { 1, 1 }, { 1, 1 } },
|
||||
{ { 1000, 1 }, { 1024, 1 } },
|
||||
{ { 1024, 1 }, { 1024, 1 } },
|
||||
{ { 100, 100 }, { 128, 128 } },
|
||||
{ { 57, 510 }, { 64, 512 } },
|
||||
// needs rectification
|
||||
{ { 1000, 1000 }, { 1024, 1024 } },
|
||||
{ { 1024, 1000 }, { 1024, 1024 } },
|
||||
} };
|
||||
};
|
||||
|
||||
for (const auto& test : SPARSE_SIZE_TESTS) {
|
||||
const auto& size = test.first;
|
||||
const auto& expected = test.second;
|
||||
auto result = rectifyToSparseSize(size);
|
||||
auto result = rectifySize(size);
|
||||
Q_ASSERT(expected == result);
|
||||
result = rectifyToSparseSize(uvec2(size.y, size.x));
|
||||
result = rectifySize(uvec2(size.y, size.x));
|
||||
Q_ASSERT(expected == uvec2(result.y, result.x));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +1,41 @@
|
|||
set(TARGET_NAME auto-tester)
|
||||
set (TARGET_NAME auto-tester)
|
||||
project(${TARGET_NAME})
|
||||
|
||||
# Automatically run UIC and MOC. This replaces the older WRAP macros
|
||||
SET(CMAKE_AUTOUIC ON)
|
||||
SET(CMAKE_AUTOMOC ON)
|
||||
SET (CMAKE_AUTOUIC ON)
|
||||
SET (CMAKE_AUTOMOC ON)
|
||||
|
||||
setup_hifi_project(Core Widgets)
|
||||
link_hifi_libraries()
|
||||
setup_hifi_project (Core Widgets)
|
||||
link_hifi_libraries ()
|
||||
|
||||
# FIX: Qt was built with -reduce-relocations
|
||||
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
SET (CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
# Qt includes
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${Qt5Core_INCLUDE_DIRS})
|
||||
include_directories(${Qt5Widgets_INCLUDE_DIRS})
|
||||
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories (${Qt5Core_INCLUDE_DIRS})
|
||||
include_directories (${Qt5Widgets_INCLUDE_DIRS})
|
||||
|
||||
set(QT_LIBRARIES Qt5::Core Qt5::Widgets)
|
||||
|
||||
# Find all sources files
|
||||
file (GLOB_RECURSE SOURCES src/*.cpp)
|
||||
file (GLOB_RECURSE HEADERS src/*.h)
|
||||
file (GLOB_RECURSE UIS src/ui/*.ui)
|
||||
set (QT_LIBRARIES Qt5::Core Qt5::Widgets)
|
||||
|
||||
if (WIN32)
|
||||
# Do not show Console
|
||||
set_property(TARGET auto-tester PROPERTY WIN32_EXECUTABLE true)
|
||||
set_property (TARGET auto-tester PROPERTY WIN32_EXECUTABLE true)
|
||||
endif()
|
||||
|
||||
add_executable(PROJECT_NAME ${SOURCES} ${HEADERS} ${UIS})
|
||||
target_zlib()
|
||||
add_dependency_external_projects (quazip)
|
||||
find_package (QuaZip REQUIRED)
|
||||
target_include_directories( ${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES})
|
||||
|
||||
target_link_libraries(PROJECT_NAME ${QT_LIBRARIES})
|
||||
|
||||
# Copy required dll's.
|
||||
add_custom_command(TARGET auto-tester POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:auto-tester>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:auto-tester>
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:auto-tester>
|
||||
)
|
||||
package_libraries_for_deployment()
|
||||
|
||||
if (WIN32)
|
||||
add_paths_to_fixup_libs (${QUAZIP_DLL_PATH})
|
||||
|
||||
find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT WINDEPLOYQT_COMMAND)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "ImageComparer.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
@ -26,11 +27,6 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
|
|||
const double c1 = pow((K1 * L), 2);
|
||||
const double c2 = pow((K2 * L), 2);
|
||||
|
||||
// Coefficients for luminosity calculation
|
||||
const double R_Y = 0.212655f;
|
||||
const double G_Y = 0.715158f;
|
||||
const double B_Y = 0.072187f;
|
||||
|
||||
// First go over all full 8x8 blocks
|
||||
// This is done in 3 loops
|
||||
// 1) Read the pixels into a linear array (an optimization)
|
||||
|
@ -116,4 +112,4 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
|
|||
}
|
||||
|
||||
return ssim / windowCounter;
|
||||
};
|
||||
};
|
|
@ -13,18 +13,62 @@
|
|||
#include <QtCore/QTextStream>
|
||||
#include <QDirIterator>
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
#include <quazip5/JlCompress.h>
|
||||
|
||||
Test::Test() {
|
||||
snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.+-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg");
|
||||
snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.*-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg");
|
||||
|
||||
expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg");
|
||||
|
||||
mismatchWindow.setModal(true);
|
||||
}
|
||||
|
||||
bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages) {
|
||||
bool Test::createTestResultsFolderPathIfNeeded(QString directory) {
|
||||
// The test results folder is located in the root of the tests (i.e. for recursive test evaluation)
|
||||
if (testResultsFolderPath == "") {
|
||||
testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER;
|
||||
QDir testResultsFolder(testResultsFolderPath);
|
||||
|
||||
if (testResultsFolder.exists()) {
|
||||
testResultsFolder.removeRecursively();
|
||||
}
|
||||
|
||||
// Create a new test results folder
|
||||
return QDir().mkdir(testResultsFolderPath);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Test::zipAndDeleteTestResultsFolder() {
|
||||
QString zippedResultsFileName { testResultsFolderPath + ".zip" };
|
||||
QFileInfo fileInfo(zippedResultsFileName);
|
||||
if (!fileInfo.exists()) {
|
||||
QFile::remove(zippedResultsFileName);
|
||||
}
|
||||
|
||||
QDir testResultsFolder(testResultsFolderPath);
|
||||
if (!testResultsFolder.isEmpty()) {
|
||||
JlCompress::compressDir(testResultsFolderPath + ".zip", testResultsFolderPath);
|
||||
}
|
||||
|
||||
testResultsFolder.removeRecursively();
|
||||
|
||||
//In all cases, for the next evaluation
|
||||
testResultsFolderPath = "";
|
||||
index = 1;
|
||||
}
|
||||
|
||||
bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar) {
|
||||
progressBar->setMinimum(0);
|
||||
progressBar->setMaximum(expectedImages.length() - 1);
|
||||
progressBar->setValue(0);
|
||||
progressBar->setVisible(true);
|
||||
|
||||
// Loop over both lists and compare each pair of images
|
||||
// Quit loop if user has aborted due to a failed test.
|
||||
const double THRESHOLD{ 0.999 };
|
||||
const double THRESHOLD { 0.999 };
|
||||
bool success{ true };
|
||||
bool keepOn{ true };
|
||||
for (int i = 0; keepOn && i < expectedImages.length(); ++i) {
|
||||
|
@ -45,42 +89,107 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage
|
|||
}
|
||||
|
||||
if (similarityIndex < THRESHOLD) {
|
||||
mismatchWindow.setTestFailure(TestFailure{
|
||||
TestFailure testFailure = TestFailure{
|
||||
(float)similarityIndex,
|
||||
expectedImages[i].left(expectedImages[i].lastIndexOf("/") + 1), // path to the test (including trailing /)
|
||||
QFileInfo(expectedImages[i].toStdString().c_str()).fileName(), // filename of expected image
|
||||
QFileInfo(resultImages[i].toStdString().c_str()).fileName() // filename of result image
|
||||
});
|
||||
};
|
||||
|
||||
mismatchWindow.exec();
|
||||
mismatchWindow.setTestFailure(testFailure);
|
||||
|
||||
switch (mismatchWindow.getUserResponse()) {
|
||||
case USER_RESPONSE_PASS:
|
||||
break;
|
||||
case USE_RESPONSE_FAIL:
|
||||
success = false;
|
||||
break;
|
||||
case USER_RESPONSE_ABORT:
|
||||
keepOn = false;
|
||||
success = false;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
if (!interactiveMode) {
|
||||
appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage());
|
||||
success = false;
|
||||
} else {
|
||||
mismatchWindow.exec();
|
||||
|
||||
switch (mismatchWindow.getUserResponse()) {
|
||||
case USER_RESPONSE_PASS:
|
||||
break;
|
||||
case USE_RESPONSE_FAIL:
|
||||
appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage());
|
||||
success = false;
|
||||
break;
|
||||
case USER_RESPONSE_ABORT:
|
||||
keepOn = false;
|
||||
success = false;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progressBar->setValue(i);
|
||||
}
|
||||
|
||||
progressBar->setVisible(false);
|
||||
return success;
|
||||
}
|
||||
|
||||
void Test::evaluateTests() {
|
||||
void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) {
|
||||
if (!QDir().exists(testResultsFolderPath)) {
|
||||
messageBox.critical(0, "Internal error", "Folder " + testResultsFolderPath + " not found");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) };
|
||||
if (!QDir().mkdir(failureFolderPath)) {
|
||||
messageBox.critical(0, "Internal error", "Failed to create folder " + failureFolderPath);
|
||||
exit(-1);
|
||||
}
|
||||
++index;
|
||||
|
||||
QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME);
|
||||
if (!descriptionFile.open(QIODevice::ReadWrite)) {
|
||||
messageBox.critical(0, "Internal error", "Failed to create file " + TEST_RESULTS_FILENAME);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Create text file describing the failure
|
||||
QTextStream stream(&descriptionFile);
|
||||
stream << "Test failed in folder " << testFailure._pathname.left(testFailure._pathname.length() - 1) << endl; // remove trailing '/'
|
||||
stream << "Expected image was " << testFailure._expectedImageFilename << endl;
|
||||
stream << "Actual image was " << testFailure._actualImageFilename << endl;
|
||||
stream << "Similarity index was " << testFailure._error << endl;
|
||||
|
||||
descriptionFile.close();
|
||||
|
||||
// Copy expected and actual images, and save the difference image
|
||||
QString sourceFile;
|
||||
QString destinationFile;
|
||||
|
||||
sourceFile = testFailure._pathname + testFailure._expectedImageFilename;
|
||||
destinationFile = failureFolderPath + "/" + "Expected Image.jpg";
|
||||
if (!QFile::copy(sourceFile, destinationFile)) {
|
||||
messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sourceFile = testFailure._pathname + testFailure._actualImageFilename;
|
||||
destinationFile = failureFolderPath + "/" + "Actual Image.jpg";
|
||||
if (!QFile::copy(sourceFile, destinationFile)) {
|
||||
messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
comparisonImage.save(failureFolderPath + "/" + "Difference Image.jpg");
|
||||
}
|
||||
|
||||
void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) {
|
||||
// Get list of JPEG images in folder, sorted by name
|
||||
QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly);
|
||||
if (pathToImageDirectory == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave if test results folder could not be created
|
||||
if (!createTestResultsFolderPathIfNeeded(pathToImageDirectory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory);
|
||||
|
||||
// Separate images into two lists. The first is the expected images, the second is the test results
|
||||
|
@ -107,36 +216,57 @@ void Test::evaluateTests() {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
bool success = compareImageLists(expectedImages, resultImages);
|
||||
bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar);
|
||||
|
||||
if (success) {
|
||||
messageBox.information(0, "Success", "All images are as expected");
|
||||
} else {
|
||||
messageBox.information(0, "Failure", "One or more images are not as expected");
|
||||
}
|
||||
|
||||
zipAndDeleteTestResultsFolder();
|
||||
}
|
||||
|
||||
bool Test::isAValidDirectory(QString pathname) {
|
||||
// Only process directories
|
||||
QDir dir(pathname);
|
||||
if (!dir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore '.', '..' directories
|
||||
if (pathname[pathname.length() - 1] == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Two criteria are used to decide if a folder contains valid test results.
|
||||
// 1) a 'test'js' file exists in the folder
|
||||
// 2) the folder has the same number of actual and expected images
|
||||
void Test::evaluateTestsRecursively() {
|
||||
void Test::evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar) {
|
||||
// Select folder to start recursing from
|
||||
QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", ".", QFileDialog::ShowDirsOnly);
|
||||
if (topLevelDirectory == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave if test results folder could not be created
|
||||
if (!createTestResultsFolderPathIfNeeded(topLevelDirectory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool success{ true };
|
||||
QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString directory = it.next();
|
||||
if (directory[directory.length() - 1] == '.') {
|
||||
// ignore '.', '..' directories
|
||||
|
||||
if (!isAValidDirectory(directory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
const QString testPathname{ directory + "/" + testFilename };
|
||||
const QString testPathname{ directory + "/" + TEST_FILENAME };
|
||||
QFileInfo fileInfo(testPathname);
|
||||
if (!fileInfo.exists()) {
|
||||
// Folder does not contain 'test.js'
|
||||
|
@ -164,7 +294,7 @@ void Test::evaluateTestsRecursively() {
|
|||
}
|
||||
|
||||
// Set success to false if any test has failed
|
||||
success &= compareImageLists(expectedImages, resultImages);
|
||||
success &= compareImageLists(expectedImages, resultImages, directory, interactiveMode, progressBar);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
|
@ -172,6 +302,8 @@ void Test::evaluateTestsRecursively() {
|
|||
} else {
|
||||
messageBox.information(0, "Failure", "One or more images are not as expected");
|
||||
}
|
||||
|
||||
zipAndDeleteTestResultsFolder();
|
||||
}
|
||||
|
||||
void Test::importTest(QTextStream& textStream, const QString& testPathname, int testNumber) {
|
||||
|
@ -191,7 +323,8 @@ void Test::createRecursiveScript() {
|
|||
if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
messageBox.critical(0,
|
||||
"Internal Error",
|
||||
"Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\"");
|
||||
"Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\""
|
||||
);
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -206,7 +339,7 @@ void Test::createRecursiveScript() {
|
|||
QVector<QString> testPathnames;
|
||||
|
||||
// First test if top-level folder has a test.js file
|
||||
const QString testPathname{ topLevelDirectory + "/" + testFilename };
|
||||
const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME };
|
||||
QFileInfo fileInfo(testPathname);
|
||||
if (fileInfo.exists()) {
|
||||
// Current folder contains a test
|
||||
|
@ -219,12 +352,14 @@ void Test::createRecursiveScript() {
|
|||
QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString directory = it.next();
|
||||
if (directory[directory.length() - 1] == '.') {
|
||||
// ignore '.', '..' directories
|
||||
|
||||
// Only process directories
|
||||
QDir dir(directory);
|
||||
if (!isAValidDirectory(directory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString testPathname{ directory + "/" + testFilename };
|
||||
const QString testPathname{ directory + "/" + TEST_FILENAME };
|
||||
QFileInfo fileInfo(testPathname);
|
||||
if (fileInfo.exists()) {
|
||||
// Current folder contains a test
|
||||
|
@ -264,7 +399,7 @@ void Test::createRecursiveScript() {
|
|||
// The script produced will look as follows:
|
||||
// if (test1HasNotStarted) {
|
||||
// test1HasNotStarted = false;
|
||||
// test1.test();
|
||||
// test1.test("auto");
|
||||
// print("******started test 1******");
|
||||
// }
|
||||
// |
|
||||
|
@ -287,7 +422,7 @@ void Test::createRecursiveScript() {
|
|||
textStream << tab << tab << "if (test" << i - 1 << ".complete && test" << i << "HasNotStarted) {" << endl;
|
||||
}
|
||||
textStream << tab << tab << tab << "test" << i << "HasNotStarted = false;" << endl;
|
||||
textStream << tab << tab << tab << "test" << i << "." << testFunction << "();" << endl;
|
||||
textStream << tab << tab << tab << "test" << i << "." << testFunction << "(\"auto\");" << endl;
|
||||
textStream << tab << tab << tab << "print(\"******started test " << i << "******\");" << endl;
|
||||
|
||||
textStream << tab << tab << "}" << endl << endl;
|
||||
|
@ -366,6 +501,41 @@ void Test::createTest() {
|
|||
messageBox.information(0, "Success", "Test images have been created");
|
||||
}
|
||||
|
||||
void Test::deleteOldSnapshots() {
|
||||
// Select folder to start recursing from
|
||||
QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select root folder for snapshot deletion", ".", QFileDialog::ShowDirsOnly);
|
||||
if (topLevelDirectory == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Recurse over folders
|
||||
QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QString directory = it.next();
|
||||
|
||||
// Only process directories
|
||||
QDir dir(directory);
|
||||
if (!isAValidDirectory(directory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory);
|
||||
|
||||
// Delete any file that is a snapshot (NOT the Expected Images)
|
||||
QStringList expectedImages;
|
||||
QStringList resultImages;
|
||||
foreach(QString currentFilename, sortedImageFilenames) {
|
||||
QString fullCurrentFilename = directory + "/" + currentFilename;
|
||||
if (isInSnapshotFilenameFormat(currentFilename)) {
|
||||
if (!QFile::remove(fullCurrentFilename)) {
|
||||
messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nSnapshot deletion aborted");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory) {
|
||||
imageDirectory = QDir(pathToImageDirectory);
|
||||
QStringList nameFilters;
|
||||
|
@ -374,6 +544,7 @@ QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirect
|
|||
return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name);
|
||||
}
|
||||
|
||||
// Use regular expressions to check if files are in specific format
|
||||
bool Test::isInSnapshotFilenameFormat(QString filename) {
|
||||
return (snapshotFilenameFormat.match(filename).hasMatch());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//
|
||||
// Test.h
|
||||
// zone/ambientLightInheritence
|
||||
//
|
||||
// Created by Nissim Hadar on 2 Nov 2017.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -15,6 +14,7 @@
|
|||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QProgressBar>
|
||||
|
||||
#include "ImageComparer.h"
|
||||
#include "ui/MismatchWindow.h"
|
||||
|
@ -23,10 +23,13 @@ class Test {
|
|||
public:
|
||||
Test();
|
||||
|
||||
void evaluateTests();
|
||||
void evaluateTestsRecursively();
|
||||
void evaluateTests(bool interactiveMode, QProgressBar* progressBar);
|
||||
void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar);
|
||||
void createRecursiveScript();
|
||||
void createTest();
|
||||
void deleteOldSnapshots();
|
||||
|
||||
bool compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar);
|
||||
|
||||
QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory);
|
||||
|
||||
|
@ -35,8 +38,17 @@ public:
|
|||
|
||||
void importTest(QTextStream& textStream, const QString& testPathname, int testNumber);
|
||||
|
||||
void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage);
|
||||
|
||||
bool createTestResultsFolderPathIfNeeded(QString directory);
|
||||
void zipAndDeleteTestResultsFolder();
|
||||
|
||||
bool isAValidDirectory(QString pathname);
|
||||
|
||||
private:
|
||||
const QString testFilename{ "test.js" };
|
||||
const QString TEST_FILENAME { "test.js" };
|
||||
const QString TEST_RESULTS_FOLDER { "TestResults" };
|
||||
const QString TEST_RESULTS_FILENAME { "TestResults.txt" };
|
||||
|
||||
QMessageBox messageBox;
|
||||
|
||||
|
@ -49,7 +61,9 @@ private:
|
|||
|
||||
ImageComparer imageComparer;
|
||||
|
||||
bool compareImageLists(QStringList expectedImages, QStringList resultImages);
|
||||
|
||||
QString testResultsFolderPath { "" };
|
||||
int index { 1 };
|
||||
};
|
||||
|
||||
#endif // hifi_test_h
|
||||
#endif // hifi_test_h
|
|
@ -34,4 +34,9 @@ enum UserResponse {
|
|||
USER_RESPONSE_ABORT
|
||||
};
|
||||
|
||||
#endif // hifi_common_h
|
||||
// Coefficients for luminosity calculation
|
||||
const double R_Y = 0.212655f;
|
||||
const double G_Y = 0.715158f;
|
||||
const double B_Y = 0.072187f;
|
||||
|
||||
#endif // hifi_common_h
|
|
@ -17,4 +17,4 @@ int main(int argc, char *argv[]) {
|
|||
autoTester.show();
|
||||
|
||||
return application.exec();
|
||||
}
|
||||
}
|
|
@ -12,14 +12,18 @@
|
|||
|
||||
AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) {
|
||||
ui.setupUi(this);
|
||||
|
||||
ui.checkBoxInteractiveMode->setChecked(true);
|
||||
|
||||
ui.progressBar->setVisible(false);
|
||||
}
|
||||
|
||||
void AutoTester::on_evaluateTestsButton_clicked() {
|
||||
test.evaluateTests();
|
||||
test.evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar);
|
||||
}
|
||||
|
||||
void AutoTester::on_evaluateTestsRecursivelyButton_clicked() {
|
||||
test.evaluateTestsRecursively();
|
||||
test.evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar);
|
||||
}
|
||||
|
||||
void AutoTester::on_createRecursiveScriptButton_clicked() {
|
||||
|
@ -30,6 +34,10 @@ void AutoTester::on_createTestButton_clicked() {
|
|||
test.createTest();
|
||||
}
|
||||
|
||||
void AutoTester::on_deleteOldSnapshotsButton_clicked() {
|
||||
test.deleteOldSnapshots();
|
||||
}
|
||||
|
||||
void AutoTester::on_closeButton_clicked() {
|
||||
exit(0);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
//
|
||||
// AutoTester.h
|
||||
// zone/ambientLightInheritence
|
||||
//
|
||||
// Created by Nissim Hadar on 2 Nov 2017.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -22,10 +21,11 @@ public:
|
|||
AutoTester(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
private slots:
|
||||
void on_evaluateTestsButton_clicked();
|
||||
void on_evaluateTestsRecursivelyButton_clicked();
|
||||
void on_createRecursiveScriptButton_clicked();
|
||||
void on_evaluateTestsButton_clicked();
|
||||
void on_evaluateTestsRecursivelyButton_clicked();
|
||||
void on_createRecursiveScriptButton_clicked();
|
||||
void on_createTestButton_clicked();
|
||||
void on_deleteOldSnapshotsButton_clicked();
|
||||
void on_closeButton_clicked();
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>286</width>
|
||||
<height>470</height>
|
||||
<width>607</width>
|
||||
<height>395</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -17,9 +17,9 @@
|
|||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>360</y>
|
||||
<width>160</width>
|
||||
<x>190</x>
|
||||
<y>300</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -30,9 +30,9 @@
|
|||
<widget class="QPushButton" name="createTestButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>270</y>
|
||||
<width>160</width>
|
||||
<x>360</x>
|
||||
<y>130</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -43,9 +43,9 @@
|
|||
<widget class="QPushButton" name="evaluateTestsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>20</y>
|
||||
<width>160</width>
|
||||
<x>20</x>
|
||||
<y>75</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -56,9 +56,9 @@
|
|||
<widget class="QPushButton" name="createRecursiveScriptButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>210</y>
|
||||
<width>160</width>
|
||||
<x>360</x>
|
||||
<y>75</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -69,9 +69,9 @@
|
|||
<widget class="QPushButton" name="evaluateTestsRecursivelyButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>75</y>
|
||||
<width>160</width>
|
||||
<x>20</x>
|
||||
<y>130</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -79,13 +79,55 @@
|
|||
<string>Evaluate Tests Recursively</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="checkBoxInteractiveMode">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>23</x>
|
||||
<y>40</y>
|
||||
<width>131</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If unchecked, will not show results during evaluation</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Interactive Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>190</y>
|
||||
<width>255</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="deleteOldSnapshotsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>360</x>
|
||||
<y>240</y>
|
||||
<width>220</width>
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete Old Snapshots</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>286</width>
|
||||
<width>607</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -103,4 +145,4 @@
|
|||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
</ui>
|
|
@ -11,11 +11,48 @@
|
|||
|
||||
#include <QtCore/QFileInfo>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
MismatchWindow::MismatchWindow(QWidget *parent) : QDialog(parent) {
|
||||
setupUi(this);
|
||||
|
||||
expectedImage->setScaledContents(true);
|
||||
resultImage->setScaledContents(true);
|
||||
diffImage->setScaledContents(true);
|
||||
}
|
||||
|
||||
QPixmap MismatchWindow::computeDiffPixmap(QImage expectedImage, QImage resultImage) {
|
||||
// This is an optimization, as QImage.setPixel() is embarrassingly slow
|
||||
unsigned char* buffer = new unsigned char[expectedImage.height() * expectedImage.width() * 3];
|
||||
|
||||
// loop over each pixel
|
||||
for (int y = 0; y < expectedImage.height(); ++y) {
|
||||
for (int x = 0; x < expectedImage.width(); ++x) {
|
||||
QRgb pixelP = expectedImage.pixel(QPoint(x, y));
|
||||
QRgb pixelQ = resultImage.pixel(QPoint(x, y));
|
||||
|
||||
// Convert to luminance
|
||||
double p = R_Y * qRed(pixelP) + G_Y * qGreen(pixelP) + B_Y * qBlue(pixelP);
|
||||
double q = R_Y * qRed(pixelQ) + G_Y * qGreen(pixelQ) + B_Y * qBlue(pixelQ);
|
||||
|
||||
// The intensity value is modified to increase the brightness of the displayed image
|
||||
double absoluteDifference = fabs(p - q) / 255.0;
|
||||
double modifiedDifference = sqrt(absoluteDifference);
|
||||
|
||||
int difference = (int)(modifiedDifference * 255.0);
|
||||
|
||||
buffer[3 * (x + y * expectedImage.width()) + 0] = difference;
|
||||
buffer[3 * (x + y * expectedImage.width()) + 1] = difference;
|
||||
buffer[3 * (x + y * expectedImage.width()) + 2] = difference;
|
||||
}
|
||||
}
|
||||
|
||||
QImage diffImage(buffer, expectedImage.width(), expectedImage.height(), QImage::Format_RGB888);
|
||||
QPixmap resultPixmap = QPixmap::fromImage(diffImage);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
return resultPixmap;
|
||||
}
|
||||
|
||||
void MismatchWindow::setTestFailure(TestFailure testFailure) {
|
||||
|
@ -24,10 +61,19 @@ void MismatchWindow::setTestFailure(TestFailure testFailure) {
|
|||
imagePath->setText("Path to test: " + testFailure._pathname);
|
||||
|
||||
expectedFilename->setText(testFailure._expectedImageFilename);
|
||||
expectedImage->setPixmap(QPixmap(testFailure._pathname + testFailure._expectedImageFilename));
|
||||
|
||||
resultFilename->setText(testFailure._actualImageFilename);
|
||||
resultImage->setPixmap(QPixmap(testFailure._pathname + testFailure._actualImageFilename));
|
||||
|
||||
QPixmap expectedPixmap = QPixmap(testFailure._pathname + testFailure._expectedImageFilename);
|
||||
QPixmap actualPixmap = QPixmap(testFailure._pathname + testFailure._actualImageFilename);
|
||||
|
||||
diffPixmap = computeDiffPixmap(
|
||||
QImage(testFailure._pathname + testFailure._expectedImageFilename),
|
||||
QImage(testFailure._pathname + testFailure._actualImageFilename)
|
||||
);
|
||||
|
||||
expectedImage->setPixmap(expectedPixmap);
|
||||
resultImage->setPixmap(actualPixmap);
|
||||
diffImage->setPixmap(diffPixmap);
|
||||
}
|
||||
|
||||
void MismatchWindow::on_passTestButton_clicked() {
|
||||
|
@ -44,3 +90,7 @@ void MismatchWindow::on_abortTestsButton_clicked() {
|
|||
_userResponse = USER_RESPONSE_ABORT;
|
||||
close();
|
||||
}
|
||||
|
||||
QPixmap MismatchWindow::getComparisonImage() {
|
||||
return diffPixmap;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ public:
|
|||
|
||||
UserResponse getUserResponse() { return _userResponse; }
|
||||
|
||||
QPixmap computeDiffPixmap(QImage expectedImage, QImage resultImage);
|
||||
QPixmap getComparisonImage();
|
||||
|
||||
private slots:
|
||||
void on_passTestButton_clicked();
|
||||
void on_failTestButton_clicked();
|
||||
|
@ -32,7 +35,9 @@ private slots:
|
|||
|
||||
private:
|
||||
UserResponse _userResponse{ USER_RESPONSE_INVALID };
|
||||
|
||||
QPixmap diffPixmap;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_MismatchWindow_h
|
||||
#endif // hifi_MismatchWindow_h
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1585</width>
|
||||
<height>694</height>
|
||||
<width>1782</width>
|
||||
<height>942</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -16,10 +16,10 @@
|
|||
<widget class="QLabel" name="expectedImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>170</y>
|
||||
<width>720</width>
|
||||
<height>362</height>
|
||||
<x>10</x>
|
||||
<y>25</y>
|
||||
<width>800</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -29,28 +29,41 @@
|
|||
<widget class="QLabel" name="resultImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>760</x>
|
||||
<y>170</y>
|
||||
<width>720</width>
|
||||
<height>362</height>
|
||||
<x>900</x>
|
||||
<y>25</y>
|
||||
<width>800</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>result image</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="diffImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>540</x>
|
||||
<y>480</y>
|
||||
<width>800</width>
|
||||
<height>450</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>diff image</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="resultFilename">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>760</x>
|
||||
<y>90</y>
|
||||
<width>800</width>
|
||||
<x>60</x>
|
||||
<y>660</y>
|
||||
<width>480</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -60,15 +73,15 @@
|
|||
<widget class="QLabel" name="expectedFilename">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>90</y>
|
||||
<width>700</width>
|
||||
<x>60</x>
|
||||
<y>630</y>
|
||||
<width>480</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -78,15 +91,15 @@
|
|||
<widget class="QLabel" name="imagePath">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>40</x>
|
||||
<y>30</y>
|
||||
<x>20</x>
|
||||
<y>600</y>
|
||||
<width>1200</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -97,7 +110,7 @@
|
|||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>600</y>
|
||||
<y>790</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
|
@ -109,8 +122,8 @@
|
|||
<widget class="QPushButton" name="failTestButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>330</x>
|
||||
<y>600</y>
|
||||
<x>120</x>
|
||||
<y>790</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
|
@ -122,36 +135,62 @@
|
|||
<widget class="QPushButton" name="abortTestsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>630</x>
|
||||
<y>600</y>
|
||||
<width>75</width>
|
||||
<x>210</x>
|
||||
<y>790</y>
|
||||
<width>121</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Abort Tests</string>
|
||||
<string>Abort current test</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="errorLabel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>810</x>
|
||||
<y>600</y>
|
||||
<width>720</width>
|
||||
<x>30</x>
|
||||
<y>850</y>
|
||||
<width>500</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>16</pointsize>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>similarity</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>5</y>
|
||||
<width>151</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Expected Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>930</x>
|
||||
<y>5</y>
|
||||
<width>151</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Actual Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
</ui>
|
|
@ -195,9 +195,9 @@ void DomainBaker::enumerateEntities() {
|
|||
auto filename = modelURL.fileName();
|
||||
auto baseName = filename.left(filename.lastIndexOf('.'));
|
||||
auto subDirName = "/" + baseName;
|
||||
int i = 0;
|
||||
int i = 1;
|
||||
while (QDir(_contentOutputPath + subDirName).exists()) {
|
||||
subDirName = "/" + baseName + "-" + i++;
|
||||
subDirName = "/" + baseName + "-" + QString::number(i++);
|
||||
}
|
||||
QSharedPointer<FBXBaker> baker {
|
||||
new FBXBaker(modelURL, []() -> QThread* {
|
||||
|
|
|
@ -133,7 +133,7 @@ var DEBUG_INFO = {
|
|||
Reticle: {
|
||||
supportsScale: 'scale' in Reticle,
|
||||
},
|
||||
protocolVersion: location.protocolVersion,
|
||||
protocolVersion: Window.protocolSignature(),
|
||||
};
|
||||
|
||||
var globalState = {
|
||||
|
|
|
@ -52,7 +52,7 @@ function CustomSettingsApp(options) {
|
|||
|
||||
this.extraParams = Object.assign(options.extraParams || {}, {
|
||||
customSettingsVersion: CustomSettingsApp.version+'',
|
||||
protocolVersion: location.protocolVersion && location.protocolVersion()
|
||||
protocolVersion: Window.protocolSignature && Window.protocolSignature()
|
||||
});
|
||||
|
||||
var params = {
|
||||
|
|
Loading…
Reference in a new issue