Merge branch 'master' of github.com:highfidelity/hifi into fix/ambient-skybox

This commit is contained in:
Zach Pomerantz 2016-08-31 14:33:57 -07:00
commit c8ff6ee4cc
10 changed files with 335 additions and 153 deletions

View file

@ -52,7 +52,8 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
_viewState(viewState),
_scriptingServices(scriptingServices),
_displayModelBounds(false),
_dontDoPrecisionPicking(false)
_dontDoPrecisionPicking(false),
_layeredZones(this)
{
REGISTER_ENTITY_TYPE_WITH_FACTORY(Model, RenderableModelEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
@ -135,8 +136,8 @@ void EntityTreeRenderer::clear() {
_entitiesInScene.clear();
// reset the zone to the default (while we load the next scene)
_bestZone = nullptr;
applyZonePropertiesToScene(_bestZone);
_layeredZones.clear();
applyZoneAndHasSkybox(nullptr);
OctreeRenderer::clear();
}
@ -192,10 +193,10 @@ void EntityTreeRenderer::update() {
// If we haven't already updated and previously attempted to load a texture,
// check if the texture loaded and apply it
if (!updated && (
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())) ||
(_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())))) {
applyZonePropertiesToScene(_bestZone);
if (!updated &&
((_pendingAmbientTexture && (!_ambientTexture || _ambientTexture->isLoaded())) ||
(_pendingSkyboxTexture && (!_skyboxTexture || _skyboxTexture->isLoaded())))) {
applySkyboxAndHasAmbient();
}
// Even if we're not moving the mouse, if we started clicking on an entity and we have
@ -210,7 +211,7 @@ void EntityTreeRenderer::update() {
deleteReleasedModels();
}
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar) {
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
bool didUpdate = false;
float radius = 0.01f; // for now, assume 0.01 meter radius, because we actually check the point inside later
QVector<EntityItemPointer> foundEntities;
@ -220,12 +221,10 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
_tree->withReadLock([&] {
// FIXME - if EntityTree had a findEntitiesContainingPoint() this could theoretically be a little faster
std::static_pointer_cast<EntityTree>(_tree)->findEntities(avatarPosition, radius, foundEntities);
std::static_pointer_cast<EntityTree>(_tree)->findEntities(_avatarPosition, radius, foundEntities);
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
auto oldBestZone = _bestZone;
_bestZone = nullptr; // NOTE: Is this what we want?
_bestZoneVolume = std::numeric_limits<float>::max();
LayeredZones oldLayeredZones(std::move(_layeredZones));
_layeredZones.clear();
// create a list of entities that actually contain the avatar's position
for (auto& entity : foundEntities) {
@ -239,38 +238,34 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(const glm::vec3&
if (isZone || hasScript) {
// now check to see if the point contains our entity, this can be expensive if
// the entity has a collision hull
if (entity->contains(avatarPosition)) {
if (entity->contains(_avatarPosition)) {
if (entitiesContainingAvatar) {
*entitiesContainingAvatar << entity->getEntityItemID();
}
// if this entity is a zone and visible, determine if it is the bestZone
if (isZone && entity->getVisible()) {
float entityVolumeEstimate = entity->getVolumeEstimate();
if (entityVolumeEstimate < _bestZoneVolume) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
} else if (entityVolumeEstimate == _bestZoneVolume) {
// in the case of the volume being equal, we will use the
// EntityItemID to deterministically pick one entity over the other
if (!_bestZone) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
} else if (entity->getEntityItemID() < _bestZone->getEntityItemID()) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
}
}
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(entity);
_layeredZones.insert(zone);
}
}
}
}
if (_bestZone != oldBestZone) {
applyZonePropertiesToScene(_bestZone);
didUpdate = true;
// check if our layered zones have changed
if (_layeredZones.empty()) {
if (oldLayeredZones.empty()) {
return;
}
} else if (!oldLayeredZones.empty()) {
if (_layeredZones.contains(oldLayeredZones)) {
return;
}
}
_layeredZones.apply();
didUpdate = true;
});
return didUpdate;
}
@ -286,13 +281,14 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
// if some amount of time has elapsed since we last checked. We check the time
// elapsed because zones or entities might have been created "around us" while we've
// been stationary
auto movedEnough = glm::distance(avatarPosition, _lastAvatarPosition) > ZONE_CHECK_DISTANCE;
auto movedEnough = glm::distance(avatarPosition, _avatarPosition) > ZONE_CHECK_DISTANCE;
auto enoughTimeElapsed = (now - _lastZoneCheck) > ZONE_CHECK_INTERVAL;
if (movedEnough || enoughTimeElapsed) {
_avatarPosition = avatarPosition;
_lastZoneCheck = now;
QVector<EntityItemID> entitiesContainingAvatar;
didUpdate = findBestZoneAndMaybeContainingEntities(avatarPosition, &entitiesContainingAvatar);
didUpdate = findBestZoneAndMaybeContainingEntities(&entitiesContainingAvatar);
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
// EntityItemIDs from here. The callEntityScriptMethod() method is robust against attempting to call scripts
@ -318,7 +314,6 @@ bool EntityTreeRenderer::checkEnterLeaveEntities() {
}
}
_currentEntitiesInside = entitiesContainingAvatar;
_lastAvatarPosition = avatarPosition;
}
}
return didUpdate;
@ -342,24 +337,20 @@ void EntityTreeRenderer::leaveAllEntities() {
void EntityTreeRenderer::forceRecheckEntities() {
// make sure our "last avatar position" is something other than our current position,
// so that on our next chance, we'll check for enter/leave entity events.
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
_avatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
}
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
auto textureCache = DependencyManager::get<TextureCache>();
auto scene = DependencyManager::get<SceneScriptingInterface>();
auto sceneStage = scene->getStage();
auto skyStage = scene->getSkyStage();
auto sceneKeyLight = sceneStage->getKeyLight();
// Skybox and procedural skybox data
auto skybox = std::dynamic_pointer_cast<ProceduralSkybox>(skyStage->getSkybox());
// If there is no zone, use the default background
if (!zone) {
_zoneUserData = QString();
skybox->clear();
skyStage->getSkybox()->clear();
_pendingSkyboxTexture = false;
_skyboxTexture.clear();
@ -371,7 +362,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
sceneKeyLight->setAmbientMap(nullptr);
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
return;
return false;
}
// Set the keylight
@ -394,90 +385,127 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
}
// Set the ambient texture
bool isAmbientTextureSet = false;
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
_ambientTextureURL = zone->getKeyLightProperties().getAmbientURL();
if (_ambientTextureURL.isEmpty()) {
_pendingAmbientTexture = false;
_ambientTexture.clear();
} else {
_ambientTexture = textureCache->getTexture(zone->getKeyLightProperties().getAmbientURL(), NetworkTexture::CUBE_TEXTURE);
_pendingAmbientTexture = true;
if (_ambientTexture && _ambientTexture->isLoaded()) {
_pendingAmbientTexture = false;
auto texture = _ambientTexture->getGPUTexture();
if (texture) {
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
sceneKeyLight->setAmbientMap(texture);
isAmbientTextureSet = true;
} else {
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << zone->getKeyLightProperties().getAmbientURL();
}
}
}
// Set the skybox texture
return layerZoneAndHasSkybox(zone);
}
bool EntityTreeRenderer::layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone) {
assert(zone);
auto textureCache = DependencyManager::get<TextureCache>();
auto scene = DependencyManager::get<SceneScriptingInterface>();
auto skyStage = scene->getSkyStage();
auto skybox = skyStage->getSkybox();
bool hasSkybox = false;
switch (zone->getBackgroundMode()) {
case BACKGROUND_MODE_SKYBOX: {
case BACKGROUND_MODE_SKYBOX:
hasSkybox = true;
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
if (_zoneUserData != zone->getUserData()) {
_zoneUserData = zone->getUserData();
skybox->parse(_zoneUserData);
std::dynamic_pointer_cast<ProceduralSkybox>(skybox)->parse(_zoneUserData);
}
if (zone->getSkyboxProperties().getURL().isEmpty()) {
skybox->setCubemap(nullptr);
_skyboxTextureURL = zone->getSkyboxProperties().getURL();
if (_skyboxTextureURL.isEmpty()) {
_pendingSkyboxTexture = false;
_skyboxTexture.clear();
} else {
// Update the Texture of the Skybox with the one pointed by this zone
_skyboxTexture = textureCache->getTexture(zone->getSkyboxProperties().getURL(), NetworkTexture::CUBE_TEXTURE);
_pendingSkyboxTexture = true;
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
_pendingSkyboxTexture = false;
auto texture = _skyboxTexture->getGPUTexture();
if (texture) {
skybox->setCubemap(texture);
if (!isAmbientTextureSet) {
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
sceneKeyLight->setAmbientMap(texture);
isAmbientTextureSet = true;
}
} else {
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << zone->getSkyboxProperties().getURL();
skybox->setCubemap(nullptr);
}
} else {
skybox->setCubemap(nullptr);
}
}
applySkyboxAndHasAmbient();
skyStage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
break;
}
case BACKGROUND_MODE_INHERIT:
default:
// Clear the skybox to release its textures
_zoneUserData = QString();
skybox->clear();
_zoneUserData = QString();
_skyboxTexture.clear();
_pendingSkyboxTexture = false;
_skyboxTexture.clear();
// Let the application background through
if (isAmbientTextureSet) {
if (applySkyboxAndHasAmbient()) {
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
} else {
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
}
break;
}
if (!isAmbientTextureSet) {
return hasSkybox;
}
bool EntityTreeRenderer::applySkyboxAndHasAmbient() {
auto textureCache = DependencyManager::get<TextureCache>();
auto scene = DependencyManager::get<SceneScriptingInterface>();
auto sceneStage = scene->getStage();
auto skyStage = scene->getSkyStage();
auto sceneKeyLight = sceneStage->getKeyLight();
auto skybox = skyStage->getSkybox();
bool isAmbientSet = false;
if (_pendingAmbientTexture && !_ambientTexture) {
_ambientTexture = textureCache->getTexture(_ambientTextureURL, NetworkTexture::CUBE_TEXTURE);
}
if (_ambientTexture && _ambientTexture->isLoaded()) {
_pendingAmbientTexture = false;
auto texture = _ambientTexture->getGPUTexture();
if (texture) {
isAmbientSet = true;
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
sceneKeyLight->setAmbientMap(texture);
} else {
qCDebug(entitiesrenderer) << "Failed to load ambient texture:" << _ambientTexture->getURL();
}
}
if (_pendingSkyboxTexture && !_skyboxTexture) {
_skyboxTexture = textureCache->getTexture(_skyboxTextureURL, NetworkTexture::CUBE_TEXTURE);
}
if (_skyboxTexture && _skyboxTexture->isLoaded()) {
_pendingSkyboxTexture = false;
auto texture = _skyboxTexture->getGPUTexture();
if (texture) {
skybox->setCubemap(texture);
if (!isAmbientSet) {
sceneKeyLight->setAmbientSphere(texture->getIrradiance());
sceneKeyLight->setAmbientMap(texture);
isAmbientSet = true;
}
} else {
qCDebug(entitiesrenderer) << "Failed to load skybox texture:" << _skyboxTexture->getURL();
skybox->setCubemap(nullptr);
}
} else {
skybox->setCubemap(nullptr);
}
if (!isAmbientSet) {
sceneKeyLight->resetAmbientSphere();
sceneKeyLight->setAmbientMap(nullptr);
}
return isAmbientSet;
}
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
@ -1046,21 +1074,128 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
}
void EntityTreeRenderer::updateZone(const EntityItemID& id) {
if (!_bestZone) {
// Get in the zone!
auto zone = getTree()->findEntityByEntityItemID(id);
if (zone && zone->contains(_lastAvatarPosition)) {
_currentEntitiesInside << id;
emit enterEntity(id);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(id, "enterEntity");
}
if (zone->getVisible()) {
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(zone);
}
}
}
if (_bestZone && _bestZone->getID() == id) {
applyZonePropertiesToScene(_bestZone);
// Get in the zone!
auto zone = std::dynamic_pointer_cast<ZoneEntityItem>(getTree()->findEntityByEntityItemID(id));
if (zone && zone->contains(_avatarPosition)) {
_layeredZones.update(zone);
}
}
EntityTreeRenderer::LayeredZones::LayeredZones(LayeredZones&& other) {
// In a swap:
// > All iterators and references remain valid. The past-the-end iterator is invalidated.
bool isSkyboxLayerValid = (other._skyboxLayer != other.end());
swap(other);
_map.swap(other._map);
_skyboxLayer = other._skyboxLayer;
if (!isSkyboxLayerValid) {
_skyboxLayer = end();
}
}
void EntityTreeRenderer::LayeredZones::clear() {
std::set<LayeredZone>::clear();
_map.clear();
_skyboxLayer = end();
}
std::pair<EntityTreeRenderer::LayeredZones::iterator, bool> EntityTreeRenderer::LayeredZones::insert(const LayeredZone& layer) {
iterator it;
bool success;
std::tie(it, success) = std::set<LayeredZone>::insert(layer);
if (success) {
_map.emplace(it->id, it);
}
return { it, success };
}
void EntityTreeRenderer::LayeredZones::apply() {
assert(_entityTreeRenderer);
applyPartial(begin());
}
void EntityTreeRenderer::LayeredZones::update(std::shared_ptr<ZoneEntityItem> zone) {
assert(_entityTreeRenderer);
bool isVisible = zone->isVisible();
if (empty() && isVisible) {
// there are no zones: set this one
insert(zone);
apply();
return;
} else {
LayeredZone zoneLayer(zone);
// should we update? only if this zone is tighter than the current skybox zone
bool shouldUpdate = false;
if (_skyboxLayer == end() || zoneLayer <= *_skyboxLayer) {
shouldUpdate = true;
}
// find this zone's layer, if it exists
iterator layer = end();
auto it = _map.find(zoneLayer.id);
if (it != _map.end()) {
layer = it->second;
// if the volume changed, we need to resort the layer (reinsertion)
// if the visibility changed, we need to erase the layer
if (zoneLayer.volume != layer->volume || !isVisible) {
erase(layer);
_map.erase(it);
layer = end();
}
}
// (re)insert this zone's layer if necessary
if (layer == end() && isVisible) {
std::tie(layer, std::ignore) = insert(zoneLayer);
_map.emplace(layer->id, layer);
}
if (shouldUpdate) {
applyPartial(layer);
}
}
}
void EntityTreeRenderer::LayeredZones::applyPartial(iterator layer) {
bool hasSkybox = false;
_skyboxLayer = end();
if (layer == end()) {
if (empty()) {
_entityTreeRenderer->applyZoneAndHasSkybox(nullptr);
return;
} else { // a layer was removed - reapply from beginning
layer = begin();
}
}
if (layer == begin()) {
hasSkybox = _entityTreeRenderer->applyZoneAndHasSkybox(layer->zone);
} else {
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
}
if (layer != end()) {
while (!hasSkybox && ++layer != end()) {
hasSkybox = _entityTreeRenderer->layerZoneAndHasSkybox(layer->zone);
}
}
_skyboxLayer = layer;
}
bool EntityTreeRenderer::LayeredZones::contains(const LayeredZones& other) {
bool result = std::equal(other.begin(), other._skyboxLayer, begin());
if (result) {
// if valid, set the _skyboxLayer from the other LayeredZones
_skyboxLayer = std::next(begin(), std::distance(other.begin(), other._skyboxLayer));
}
return result;
}

View file

@ -95,7 +95,7 @@ public:
// For Scene.shouldRenderEntities
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _bestZone; }
std::shared_ptr<ZoneEntityItem> myAvatarZone() { return _layeredZones.getZone(); }
signals:
void mousePressOnEntity(const EntityItemID& entityItemID, const PointerEvent& event);
@ -138,9 +138,12 @@ private:
void resetEntitiesScriptEngine();
void addEntityToScene(EntityItemPointer entity);
bool findBestZoneAndMaybeContainingEntities(const glm::vec3& avatarPosition, QVector<EntityItemID>* entitiesContainingAvatar);
bool findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar = nullptr);
bool applyZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
bool layerZoneAndHasSkybox(const std::shared_ptr<ZoneEntityItem>& zone);
bool applySkyboxAndHasAmbient();
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false);
QList<ModelPointer> _releasedModels;
@ -156,15 +159,9 @@ private:
void leaveAllEntities();
void forceRecheckEntities();
glm::vec3 _lastAvatarPosition { 0.0f };
glm::vec3 _avatarPosition { 0.0f };
QVector<EntityItemID> _currentEntitiesInside;
bool _pendingSkyboxTexture { false };
NetworkTexturePointer _skyboxTexture;
bool _pendingAmbientTexture { false };
NetworkTexturePointer _ambientTexture;
bool _wantScripts;
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
@ -185,26 +182,62 @@ private:
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
std::shared_ptr<ZoneEntityItem> _bestZone;
float _bestZoneVolume;
class LayeredZone {
public:
LayeredZone(std::shared_ptr<ZoneEntityItem> zone, QUuid id, float volume) : zone(zone), id(id), volume(volume) {}
LayeredZone(std::shared_ptr<ZoneEntityItem> zone) : LayeredZone(zone, zone->getID(), zone->getVolumeEstimate()) {}
bool operator<(const LayeredZone& r) const { return std::tie(volume, id) < std::tie(r.volume, r.id); }
bool operator==(const LayeredZone& r) const { return id == r.id; }
bool operator<=(const LayeredZone& r) const { return (*this < r) || (*this == r); }
std::shared_ptr<ZoneEntityItem> zone;
QUuid id;
float volume;
};
class LayeredZones : public std::set<LayeredZone> {
public:
LayeredZones(EntityTreeRenderer* parent) : _entityTreeRenderer(parent) {}
LayeredZones(LayeredZones&& other);
// avoid accidental misconstruction
LayeredZones() = delete;
LayeredZones(const LayeredZones&) = delete;
LayeredZones& operator=(const LayeredZones&) = delete;
LayeredZones& operator=(LayeredZones&&) = delete;
void clear();
std::pair<iterator, bool> insert(const LayeredZone& layer);
void apply();
void update(std::shared_ptr<ZoneEntityItem> zone);
bool contains(const LayeredZones& other);
std::shared_ptr<ZoneEntityItem> getZone() { return empty() ? nullptr : begin()->zone; }
private:
void applyPartial(iterator layer);
std::map<QUuid, iterator> _map;
iterator _skyboxLayer{ end() };
EntityTreeRenderer* _entityTreeRenderer;
};
LayeredZones _layeredZones;
QString _zoneUserData;
NetworkTexturePointer _ambientTexture;
NetworkTexturePointer _skyboxTexture;
QString _ambientTextureURL;
QString _skyboxTextureURL;
bool _pendingAmbientTexture { false };
bool _pendingSkyboxTexture { false };
quint64 _lastZoneCheck { 0 };
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
const float ZONE_CHECK_DISTANCE = 0.001f;
glm::vec3 _previousKeyLightColor;
float _previousKeyLightIntensity;
float _previousKeyLightAmbientIntensity;
glm::vec3 _previousKeyLightDirection;
bool _previousStageSunModelEnabled;
float _previousStageLongitude;
float _previousStageLatitude;
float _previousStageAltitude;
float _previousStageHour;
int _previousStageDay;
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
// For Scene.shouldRenderEntities
QList<EntityItemID> _entityIDsLastInScene;

View file

@ -26,13 +26,15 @@ Skybox::Skybox() {
}
void Skybox::setColor(const Color& color) {
_empty = false;
_schemaBuffer.edit<Schema>().color = color;
_empty = false;
}
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
_empty = false;
_cubemap = cubemap;
if (cubemap) {
_empty = false;
}
}
void Skybox::updateSchemaBuffer() const {
@ -52,9 +54,9 @@ void Skybox::updateSchemaBuffer() const {
}
void Skybox::clear() {
_empty = true;
_schemaBuffer.edit<Schema>().color = vec3(0);
setCubemap(nullptr);
_cubemap = nullptr;
_empty = true;
}
void Skybox::prepare(gpu::Batch& batch, int textureSlot, int bufferSlot) const {

View file

@ -100,7 +100,9 @@ bool Procedural::parseVersion(const QJsonValue& version) {
return (_version == 1 || _version == 2);
}
bool Procedural::parseUrl(const QUrl& shaderUrl) {
bool Procedural::parseShader(const QUrl& shaderPath) {
auto shaderUrl = ResourceManager::normalizeURL(shaderPath);
if (!shaderUrl.isValid()) {
if (!shaderUrl.isEmpty()) {
qWarning() << "Invalid shader URL: " << shaderUrl;
@ -168,7 +170,6 @@ void Procedural::parse(const QJsonObject& proceduralData) {
auto version = proceduralData[VERSION_KEY];
auto shaderUrl = proceduralData[URL_KEY].toString();
shaderUrl = ResourceManager::normalizeURL(shaderUrl);
auto uniforms = proceduralData[UNIFORMS_KEY].toObject();
auto channels = proceduralData[CHANNELS_KEY].toArray();
@ -176,7 +177,7 @@ void Procedural::parse(const QJsonObject& proceduralData) {
// Run through parsing regardless of validity to clear old cached resources
isValid = parseVersion(version) && isValid;
isValid = parseUrl(shaderUrl) && isValid;
isValid = parseShader(shaderUrl) && isValid;
isValid = parseUniforms(uniforms) && isValid;
isValid = parseTextures(channels) && isValid;
@ -221,6 +222,7 @@ bool Procedural::ready() {
_hasStartedFade = true;
_isFading = true;
}
return true;
}

View file

@ -107,7 +107,7 @@ private:
// This should only be called from the render thread, as it shares data with Procedural::prepare
void parse(const QJsonObject&);
bool parseVersion(const QJsonValue& version);
bool parseUrl(const QUrl& url);
bool parseShader(const QUrl& shaderPath);
bool parseUniforms(const QJsonObject& uniforms);
bool parseTextures(const QJsonArray& channels);

View file

@ -164,9 +164,10 @@ function toggleMarketplace() {
}
}
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
var toolBar = (function () {
var EDIT_SETTING = "io.highfidelity.isEditting"; // for communication with other scripts
var TOOL_ICON_URL = Script.resolvePath("assets/images/tools/");
var that = {},
toolBar,
systemToolbar,
@ -199,7 +200,7 @@ var toolBar = (function () {
}
function addButton(name, image, handler) {
var imageUrl = TOOL_ICON_URL + image;
var imageUrl = TOOLS_PATH + image;
var button = toolBar.addButton({
objectName: name,
imageURL: imageUrl,
@ -232,7 +233,7 @@ var toolBar = (function () {
systemToolbar = Toolbars.getToolbar(SYSTEM_TOOLBAR);
activeButton = systemToolbar.addButton({
objectName: EDIT_TOGGLE_BUTTON,
imageURL: TOOL_ICON_URL + "edit.svg",
imageURL: TOOLS_PATH + "edit.svg",
visible: true,
alpha: 0.9,
buttonState: 1,
@ -1326,13 +1327,14 @@ function pushCommandForSelections(createdEntityData, deletedEntityData) {
UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData);
}
var ENTITY_PROPERTIES_URL = Script.resolvePath('html/entityProperties.html');
var PropertiesTool = function (opts) {
var that = {};
var url = Script.resolvePath('html/entityProperties.html');
var webView = new OverlayWebWindow({
title: 'Entity Properties',
source: url,
source: ENTITY_PROPERTIES_URL,
toolWindow: true
});

View file

@ -16,8 +16,11 @@
// grab the toolbar
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
var ASSETS_PATH = Script.resolvePath("assets");
var TOOLS_PATH = Script.resolvePath("assets/images/tools/");
function buttonImageURL() {
return Script.resolvePath("assets/images/tools/" + (Users.canKick ? 'kick.svg' : 'ignore.svg'));
return TOOLS_PATH + (Users.canKick ? 'kick.svg' : 'ignore.svg');
}
// setup the mod button and add it to the toolbar
@ -68,7 +71,7 @@ function buttonClicked(){
button.clicked.connect(buttonClicked);
function overlayURL() {
return Script.resolvePath("assets") + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");
return ASSETS_PATH + "/images/" + (Users.canKick ? "kick-target.svg" : "ignore-target.svg");
}
function updateOverlays() {

View file

@ -124,7 +124,6 @@ var NotificationType = {
var randomSounds = new SoundArray({ localOnly: true }, true);
var numberOfSounds = 2;
for (var i = 1; i <= numberOfSounds; i++) {
randomSounds.addSound(Script.resolvePath("assets/sounds/notification-general"+ i + ".raw"));
}
@ -317,6 +316,8 @@ function notify(notice, button, height, imageProperties, image) {
return notificationText;
}
var CLOSE_NOTIFICATION_ICON = Script.resolvePath("assets/images/close-small-light.svg");
// This function creates and sizes the overlays
function createNotification(text, notificationType, imageProperties) {
var count = (text.match(/\n/g) || []).length,
@ -363,7 +364,7 @@ function createNotification(text, notificationType, imageProperties) {
width: 10.0,
height: 10.0,
subImage: { x: 0, y: 0, width: 10, height: 10 },
imageURL: Script.resolvePath("assets/images/close-small-light.svg"),
imageURL: CLOSE_NOTIFICATION_ICON,
color: { red: 255, green: 255, blue: 255},
visible: true,
alpha: backgroundAlpha
@ -534,7 +535,7 @@ function onDomainConnectionRefused(reason) {
function onSnapshotTaken(path, notify) {
if (notify) {
var imageProperties = {
path: Script.resolvePath("file:///" + path),
path: "file:///" + path,
aspectRatio: Window.innerWidth / Window.innerHeight
}
createNotification(wordWrap("Snapshot saved to " + path), NotificationType.SNAPSHOT, imageProperties);

View file

@ -32,9 +32,11 @@ function showFeedWindow() {
DialogsManager.showFeed();
}
var SNAPSHOT_REVIEW_URL = Script.resolvePath("html/SnapshotReview.html");
var outstanding;
function confirmShare(data) {
var dialog = new OverlayWebWindow('Snapshot Review', Script.resolvePath("html/SnapshotReview.html"), 800, 320);
var dialog = new OverlayWebWindow('Snapshot Review', SNAPSHOT_REVIEW_URL, 800, 320);
function onMessage(message) {
// Receives message from the html dialog via the qwebchannel EventBridge. This is complicated by the following:
// 1. Although we can send POJOs, we cannot receive a toplevel object. (Arrays of POJOs are fine, though.)

View file

@ -13,6 +13,10 @@
(function() { // BEGIN LOCAL_SCOPE
// resolve these paths immediately
var MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
var BASE_URL = Script.resolvePath("assets/images/tools/");
var PopUpMenu = function (properties) {
var value = properties.value,
promptOverlay,
@ -25,8 +29,7 @@ var PopUpMenu = function (properties) {
MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
MIN_MAX_BUTTON_WIDTH = 14,
MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH,
MIN_MAX_BUTTON_SVG = Script.resolvePath("assets/images/tools/min-max-toggle.svg");
MIN_MAX_BUTTON_HEIGHT = MIN_MAX_BUTTON_WIDTH;
function positionDisplayOptions() {
var y,
@ -223,8 +226,7 @@ var PopUpMenu = function (properties) {
var usersWindow = (function () {
var baseURL = Script.resolvePath("assets/images/tools/"),
WINDOW_WIDTH = 260,
var WINDOW_WIDTH = 260,
WINDOW_MARGIN = 12,
WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct
WINDOW_FONT = {
@ -261,7 +263,7 @@ var usersWindow = (function () {
WINDOW_BORDER_ALPHA = 0.5,
windowBorder,
MIN_MAX_BUTTON_SVG = baseURL + "min-max-toggle.svg",
MIN_MAX_BUTTON_SVG = BASE_URL + "min-max-toggle.svg",
MIN_MAX_BUTTON_SVG_WIDTH = 17.1,
MIN_MAX_BUTTON_SVG_HEIGHT = 32.5,
MIN_MAX_BUTTON_WIDTH = 14,
@ -293,7 +295,7 @@ var usersWindow = (function () {
scrollbarBackgroundHeight,
scrollbarBarHeight,
FRIENDS_BUTTON_SPACER = 6, // Space before add/remove friends button
FRIENDS_BUTTON_SVG = baseURL + "add-remove-friends.svg",
FRIENDS_BUTTON_SVG = BASE_URL + "add-remove-friends.svg",
FRIENDS_BUTTON_SVG_WIDTH = 107,
FRIENDS_BUTTON_SVG_HEIGHT = 27,
FRIENDS_BUTTON_WIDTH = FRIENDS_BUTTON_SVG_WIDTH,