Merge remote-tracking branch 'upstream/master' into feature/qml_whitelist_tablet

This commit is contained in:
Brad Davis 2017-11-15 11:59:06 -08:00
commit 26a745be6f
76 changed files with 1022 additions and 225 deletions

3
.gitignore vendored
View file

@ -66,6 +66,9 @@ TAGS
*.sw[po]
*.qmlc
# ignore QML compilation output
*.qmlc
# ignore node files for the console
node_modules
npm-debug.log

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -5,10 +5,16 @@ Item {
id: keyItem
width: 45
height: 50
property int contentPadding: 4
property string glyph: "a"
property bool toggle: false // does this button have the toggle behaivor?
property bool toggled: false // is this button currently toggled?
property alias mouseArea: mouseArea1
property alias fontFamily: letter.font.family;
property alias fontPixelSize: letter.font.pixelSize
property alias verticalAlignment: letter.verticalAlignment
property alias letterAnchors: letter.anchors
function resetToggledMode(mode) {
toggled = mode;
@ -105,14 +111,8 @@ Item {
color: "#121212"
radius: 2
border.color: "#00000000"
anchors.right: parent.right
anchors.rightMargin: 4
anchors.left: parent.left
anchors.leftMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
anchors.top: parent.top
anchors.topMargin: 4
anchors.fill: parent
anchors.margins: contentPadding
}
Text {

View file

@ -8,7 +8,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.0
import QtQuick 2.7
import QtGraphicalEffects 1.0
import "."
Rectangle {
@ -55,6 +56,8 @@ Rectangle {
return ">";
} else if (str === "/") {
return "?";
} else if (str === "-") {
return "_";
} else {
return str.toUpperCase(str);
}
@ -67,6 +70,8 @@ Rectangle {
return ".";
} else if (str === "?") {
return "/";
} else if (str === "_") {
return "-";
} else {
return str.toLowerCase(str);
}
@ -85,7 +90,7 @@ Rectangle {
onShiftModeChanged: {
forEachKey(function (key) {
if (/[a-z]/i.test(key.glyph)) {
if (/[a-z-_]/i.test(key.glyph)) {
if (shiftMode) {
key.glyph = keyboardBase.toUpper(key.glyph);
} else {
@ -112,8 +117,6 @@ Rectangle {
}
Rectangle {
y: 0
x: 0
height: showMirrorText ? mirrorTextHeight : 0
width: keyboardWidth
color: "#252525"
@ -122,13 +125,18 @@ Rectangle {
TextInput {
id: mirrorText
visible: showMirrorText
FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; }
font.family: ralewaySemiBold.name
font.pointSize: 13.5
FontLoader { id: font; source: "../../fonts/FiraSans-Regular.ttf"; }
font.family: font.name
font.pixelSize: 20
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: "#FFFFFF";
anchors.fill: parent
color: "#00B4EF";
anchors.left: parent.left
anchors.leftMargin: 10
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
wrapMode: Text.WordWrap
readOnly: false // we need this to allow control to accept QKeyEvent
selectByMouse: false
@ -140,16 +148,15 @@ Rectangle {
event.accepted = true;
}
}
}
MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus
anchors.fill: parent
MouseArea { // ... and we need this mouse area to prevent mirrorText from getting mouse events to ensure it will never get focus
anchors.fill: parent
}
}
}
Rectangle {
id: keyboardRect
x: 0
y: showMirrorText ? mirrorTextHeight : 0
width: keyboardWidth
height: raisedHeight
@ -158,6 +165,8 @@ Rectangle {
anchors.bottom: parent.bottom
anchors.bottomMargin: 0
FontLoader { id: hiFiGlyphs; source: pathToFonts + "fonts/hifi-glyphs.ttf"; }
Column {
id: columnAlpha
width: keyboardWidth
@ -221,7 +230,7 @@ Rectangle {
Key { width: 43; glyph: "b"; }
Key { width: 43; glyph: "n"; }
Key { width: 43; glyph: "m"; }
Key { width: 43; glyph: "_"; }
Key { width: 43; glyph: "-"; }
Key { width: 43; glyph: "/"; }
Key { width: 43; glyph: "?"; }
}
@ -240,8 +249,13 @@ Rectangle {
Key { width: 231; glyph: " "; }
Key { width: 43; glyph: ","; }
Key { width: 43; glyph: "."; }
Key { width: 43; glyph: "\u276C"; }
Key { width: 43; glyph: "\u276D"; }
Key {
fontFamily: hiFiGlyphs.name;
fontPixelSize: 48;
letterAnchors.topMargin: -4;
verticalAlignment: Text.AlignVCenter;
width: 86; glyph: "\ue02b";
}
}
}
@ -328,8 +342,13 @@ Rectangle {
Key { width: 231; glyph: " "; }
Key { width: 43; glyph: ","; }
Key { width: 43; glyph: "."; }
Key { width: 43; glyph: "\u276C"; }
Key { width: 43; glyph: "\u276D"; }
Key {
fontFamily: hiFiGlyphs.name;
fontPixelSize: 48;
letterAnchors.topMargin: -4;
verticalAlignment: Text.AlignVCenter;
width: 86; glyph: "\ue02b";
}
}
}
}

View file

@ -27,6 +27,12 @@ Item {
id: hifi
}
function unfocus() {
webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) {
console.log('unfocus completed: ', result);
});
}
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {

View file

@ -10,6 +10,11 @@ Item {
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
onKeyboardRaisedChanged: {
if(!keyboardRaised) {
webroot.unfocus();
}
}
property bool punctuationMode: false
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface

View file

@ -15,6 +15,11 @@ Item {
property string scriptURL
property bool keyboardEnabled: false
property bool keyboardRaised: false
onKeyboardRaisedChanged: {
if(!keyboardRaised) {
webroot.unfocus();
}
}
property bool punctuationMode: false
property bool passwordField: false
property bool isDesktop: false

View file

@ -12,6 +12,11 @@ Item {
property alias urlTag: webroot.urlTag
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
onKeyboardRaisedChanged: {
if(!keyboardRaised) {
webroot.unfocus();
}
}
property bool punctuationMode: false
property bool passwordField: false
property alias flickable: webroot.interactive

View file

@ -476,9 +476,7 @@ Rectangle {
Commerce.buy(itemId, itemPrice, true);
}
} else {
if (urlHandler.canHandleUrl(itemHref)) {
urlHandler.handleUrl(itemHref);
}
sendToScript({method: 'checkout_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
}
}
}

View file

@ -346,9 +346,7 @@ Item {
enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated";
onClicked: {
if (urlHandler.canHandleUrl(root.itemHref)) {
urlHandler.handleUrl(root.itemHref);
}
sendToPurchases({method: 'purchases_rezClicked', itemHref: root.itemHref, isWearable: root.isWearable});
rezzedNotifContainer.visible = true;
rezzedNotifContainerTimer.start();
}

View file

@ -442,6 +442,8 @@ Rectangle {
onSendToPurchases: {
if (msg.method === 'purchases_itemInfoClicked') {
sendToScript({method: 'purchases_itemInfoClicked', itemId: itemId});
} else if (msg.method === "purchases_rezClicked") {
sendToScript({method: 'purchases_rezClicked', itemHref: itemHref, isWearable: isWearable});
} else if (msg.method === 'purchases_itemCertificateClicked') {
inspectionCertificate.visible = true;
inspectionCertificate.isLightbox = true;

View file

@ -32,6 +32,8 @@ Rectangle {
color: hifi.colors.baseGray
property bool keyboardEnabled: HMD.active
property bool keyboardRaised: false
LetterboxMessage {
id: letterBoxMessage
@ -380,7 +382,7 @@ Rectangle {
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
onActiveFocusChanged: {
// raise the keyboard
keyboard.raised = activeFocus;
root.keyboardRaised = activeFocus;
// scroll to the bottom of the content area.
if (activeFocus) {
@ -481,7 +483,7 @@ Rectangle {
HifiControls.Keyboard {
id: keyboard
raised: false
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: false
anchors {
bottom: parent.bottom

View file

@ -366,7 +366,7 @@ StackView {
HifiControls.Keyboard {
id: keyboard
raised: parent.keyboardEnabled
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom

View file

@ -15,7 +15,7 @@
#include "RayPickScriptingInterface.h"
LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) :
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) :
_renderingEnabled(enabled),
_renderStates(renderStates),
_defaultRenderStates(defaultRenderStates),
@ -23,6 +23,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende
_centerEndY(centerEndY),
_lockEnd(lockEnd),
_distanceScaleEnd(distanceScaleEnd),
_scaleWithAvatar(scaleWithAvatar),
_rayPickUID(DependencyManager::get<RayPickScriptingInterface>()->createRayPick(rayProps))
{
@ -94,6 +95,10 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta
if (endDim.isValid()) {
_renderStates[state].setEndDim(vec3FromVariant(endDim));
}
QVariant lineWidth = pathProps.toMap()["lineWidth"];
if (lineWidth.isValid()) {
_renderStates[state].setLineWidth(lineWidth.toFloat());
}
});
}
@ -152,6 +157,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
}
}
}
QVariant end = vec3toVariant(endVec);
if (!renderState.getPathID().isNull()) {
QVariantMap pathProps;
@ -159,6 +165,9 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
pathProps.insert("end", end);
pathProps.insert("visible", true);
pathProps.insert("ignoreRayIntersection", renderState.doesPathIgnoreRays());
if (_scaleWithAvatar) {
pathProps.insert("lineWidth", renderState.getLineWidth() * DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale());
}
qApp->getOverlays().editOverlay(renderState.getPathID(), pathProps);
}
if (!renderState.getEndID().isNull()) {
@ -166,7 +175,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
glm::quat faceAvatarRotation = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)));
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
if (_distanceScaleEnd) {
dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get<AvatarManager>()->getMyAvatar()->getSensorToWorldScale();
dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec);
endProps.insert("dimensions", vec3toVariant(dim));
}
if (_centerEndY) {
@ -258,6 +267,7 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons
}
if (!_pathID.isNull()) {
_pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool();
_lineWidth = qApp->getOverlays().getProperty(_pathID, "lineWidth").value.toFloat();
}
if (!_endID.isNull()) {
_endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value);

View file

@ -43,6 +43,9 @@ public:
void setEndDim(const glm::vec3& endDim) { _endDim = endDim; }
const glm::vec3& getEndDim() const { return _endDim; }
void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; }
const float& getLineWidth() const { return _lineWidth; }
void deleteOverlays();
private:
@ -54,6 +57,7 @@ private:
bool _endIgnoreRays;
glm::vec3 _endDim;
float _lineWidth;
};
@ -66,7 +70,7 @@ public:
typedef std::unordered_map<std::string, std::pair<float, RenderState>> DefaultRenderStateMap;
LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled);
~LaserPointer();
QUuid getRayUID() { return _rayPickUID; }
@ -97,6 +101,7 @@ private:
bool _centerEndY;
bool _lockEnd;
bool _distanceScaleEnd;
bool _scaleWithAvatar;
LockEndObject _lockEndObject;
const QUuid _rayPickUID;

View file

@ -11,9 +11,9 @@
#include "LaserPointerManager.h"
QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) {
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled) {
QUuid result;
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
std::shared_ptr<LaserPointer> laserPointer = std::make_shared<LaserPointer>(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled);
if (!laserPointer->getRayUID().isNull()) {
result = QUuid::createUuid();
withWriteLock([&] { _laserPointers[result] = laserPointer; });

View file

@ -25,7 +25,7 @@ class LaserPointerManager : protected ReadWriteLockable {
public:
QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates,
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled);
const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool scaleWithAvatar, const bool enabled);
void removeLaserPointer(const QUuid& uid);
void enableLaserPointer(const QUuid& uid) const;

View file

@ -51,6 +51,11 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
enabled = propertyMap["enabled"].toBool();
}
bool scaleWithAvatar = false;
if (propertyMap["scaleWithAvatar"].isValid()) {
scaleWithAvatar = propertyMap["scaleWithAvatar"].toBool();
}
LaserPointer::RenderStateMap renderStates;
if (propertyMap["renderStates"].isValid()) {
QList<QVariant> renderStateVariants = propertyMap["renderStates"].toList();
@ -80,7 +85,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert
}
}
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled);
return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, scaleWithAvatar, enabled);
}
void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const {

View file

@ -16,13 +16,11 @@
#include "Application.h"
const float DEFAULT_LINE_WIDTH = 1.0f;
const bool DEFAULT_IS_SOLID = false;
const bool DEFAULT_IS_DASHED_LINE = false;
Base3DOverlay::Base3DOverlay() :
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
_lineWidth(DEFAULT_LINE_WIDTH),
_isSolid(DEFAULT_IS_SOLID),
_isDashedLine(DEFAULT_IS_DASHED_LINE),
_ignoreRayIntersection(false),
@ -34,7 +32,6 @@ Base3DOverlay::Base3DOverlay() :
Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
Overlay(base3DOverlay),
SpatiallyNestable(NestableType::Overlay, QUuid::createUuid()),
_lineWidth(base3DOverlay->_lineWidth),
_isSolid(base3DOverlay->_isSolid),
_isDashedLine(base3DOverlay->_isDashedLine),
_ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection),
@ -153,12 +150,6 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) {
setLocalOrientation(quatFromVariant(properties["orientation"]));
needRenderItemUpdate = true;
}
if (properties["lineWidth"].isValid()) {
setLineWidth(properties["lineWidth"].toFloat());
needRenderItemUpdate = true;
}
if (properties["isSolid"].isValid()) {
setIsSolid(properties["isSolid"].toBool());
}
@ -225,9 +216,6 @@ QVariant Base3DOverlay::getProperty(const QString& property) {
if (property == "localRotation" || property == "localOrientation") {
return quatToVariant(getLocalOrientation());
}
if (property == "lineWidth") {
return _lineWidth;
}
if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") {
return _isSolid;
}

View file

@ -38,7 +38,6 @@ public:
// TODO: consider implementing registration points in this class
glm::vec3 getCenter() const { return getPosition(); }
float getLineWidth() const { return _lineWidth; }
bool getIsSolid() const { return _isSolid; }
bool getIsDashedLine() const { return _isDashedLine; }
bool getIsSolidLine() const { return !_isDashedLine; }
@ -47,7 +46,6 @@ public:
bool getDrawHUDLayer() const { return _drawHUDLayer; }
bool getIsGrabbable() const { return _isGrabbable; }
void setLineWidth(float lineWidth) { _lineWidth = lineWidth; }
void setIsSolid(bool isSolid) { _isSolid = isSolid; }
void setIsDashedLine(bool isDashedLine) { _isDashedLine = isDashedLine; }
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
@ -85,7 +83,6 @@ protected:
void setRenderVisible(bool visible);
const Transform& getRenderTransform() const { return _renderTransform; }
float _lineWidth;
bool _isSolid;
bool _isDashedLine;
bool _ignoreRayIntersection;

View file

@ -33,8 +33,8 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
_length = line3DOverlay->getLength();
_endParentID = line3DOverlay->getEndParentID();
_endParentJointIndex = line3DOverlay->getEndJointIndex();
_lineWidth = line3DOverlay->getLineWidth();
_glow = line3DOverlay->getGlow();
_glowWidth = line3DOverlay->getGlowWidth();
}
Line3DOverlay::~Line3DOverlay() {
@ -145,7 +145,7 @@ void Line3DOverlay::render(RenderArgs* args) {
geometryCache->renderDashedLine(*batch, start, end, colorv4, _geometryCacheID);
} else {
// renderGlowLine handles both glow = 0 and glow > 0 cases
geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _glowWidth, _geometryCacheID);
geometryCache->renderGlowLine(*batch, start, end, colorv4, _glow, _lineWidth, _geometryCacheID);
}
}
}
@ -239,11 +239,10 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
}
}
auto glowWidth = properties["glowWidth"];
if (glowWidth.isValid()) {
setGlowWidth(glowWidth.toFloat());
auto lineWidth = properties["lineWidth"];
if (lineWidth.isValid()) {
setLineWidth(lineWidth.toFloat());
}
}
QVariant Line3DOverlay::getProperty(const QString& property) {
@ -262,6 +261,9 @@ QVariant Line3DOverlay::getProperty(const QString& property) {
if (property == "length") {
return QVariant(getLength());
}
if (property == "lineWidth") {
return _lineWidth;
}
return Base3DOverlay::getProperty(property);
}

View file

@ -31,8 +31,8 @@ public:
// getters
glm::vec3 getStart() const;
glm::vec3 getEnd() const;
const float& getLineWidth() const { return _lineWidth; }
const float& getGlow() const { return _glow; }
const float& getGlowWidth() const { return _glowWidth; }
// setters
void setStart(const glm::vec3& start);
@ -41,8 +41,8 @@ public:
void setLocalStart(const glm::vec3& localStart) { setLocalPosition(localStart); }
void setLocalEnd(const glm::vec3& localEnd);
void setLineWidth(const float& lineWidth) { _lineWidth = lineWidth; }
void setGlow(const float& glow) { _glow = glow; }
void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; }
void setProperties(const QVariantMap& properties) override;
QVariant getProperty(const QString& property) override;
@ -70,8 +70,9 @@ private:
glm::vec3 _direction; // in parent frame
float _length { 1.0 }; // in parent frame
const float DEFAULT_LINE_WIDTH = 0.02f;
float _lineWidth { DEFAULT_LINE_WIDTH };
float _glow { 0.0 };
float _glowWidth { 0.0 };
int _geometryCacheID;
};

View file

@ -40,22 +40,26 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
if (_stage) {
if (!LightStage::isIndexInvalid(_sunIndex)) {
_stage->removeLight(_sunIndex);
_sunIndex = INVALID_INDEX;
_shadowIndex = INVALID_INDEX;
}
if (!LightStage::isIndexInvalid(_ambientIndex)) {
_stage->removeLight(_ambientIndex);
_ambientIndex = INVALID_INDEX;
}
}
if (_backgroundStage) {
if (!BackgroundStage::isIndexInvalid(_backgroundIndex)) {
_backgroundStage->removeBackground(_backgroundIndex);
_backgroundIndex = INVALID_INDEX;
}
}
if (_hazeStage) {
if (!HazeStage::isIndexInvalid(_hazeIndex)) {
_hazeStage->removeHaze(_hazeIndex);
_hazeIndex = INVALID_INDEX;
}
}
}

View file

@ -0,0 +1,19 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Draw with color uniform
//
// Created by Olivier Prat on 25/10/2017
// Copyright 2017 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
//
uniform vec4 color;
out vec4 outFragColor;
void main(void) {
outFragColor = color;
}

View file

@ -22,6 +22,7 @@
const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple...
#include "DrawWhite_frag.h"
#include "DrawColor_frag.h"
#include "DrawTexture_frag.h"
#include "DrawTextureMirroredX_frag.h"
#include "DrawTextureOpaque_frag.h"
@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawVertexPositionVS;
ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
ShaderPointer StandardShaderLib::_drawNadaPS;
ShaderPointer StandardShaderLib::_drawWhitePS;
ShaderPointer StandardShaderLib::_drawColorPS;
ShaderPointer StandardShaderLib::_drawTexturePS;
ShaderPointer StandardShaderLib::_drawTextureMirroredXPS;
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
@ -125,6 +127,13 @@ ShaderPointer StandardShaderLib::getDrawWhitePS() {
return _drawWhitePS;
}
ShaderPointer StandardShaderLib::getDrawColorPS() {
if (!_drawColorPS) {
_drawColorPS = gpu::Shader::createPixel(std::string(DrawColor_frag));
}
return _drawColorPS;
}
ShaderPointer StandardShaderLib::getDrawTexturePS() {
if (!_drawTexturePS) {
_drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag));

View file

@ -46,6 +46,7 @@ public:
static ShaderPointer getDrawNadaPS();
static ShaderPointer getDrawWhitePS();
static ShaderPointer getDrawColorPS();
static ShaderPointer getDrawTexturePS();
static ShaderPointer getDrawTextureMirroredXPS();
static ShaderPointer getDrawTextureOpaquePS();
@ -67,6 +68,7 @@ protected:
static ShaderPointer _drawNadaPS;
static ShaderPointer _drawWhitePS;
static ShaderPointer _drawColorPS;
static ShaderPointer _drawTexturePS;
static ShaderPointer _drawTextureMirroredXPS;
static ShaderPointer _drawTextureOpaquePS;

View file

@ -105,13 +105,13 @@ void DeferredLightingEffect::setupKeyLightBatch(const RenderArgs* args, gpu::Bat
PerformanceTimer perfTimer("DLE->setupBatch()");
model::LightPointer keySunLight;
auto lightStage = args->_scene->getStage<LightStage>();
if (lightStage && lightStage->_currentFrame._sunLights.size()) {
keySunLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front());
if (lightStage) {
keySunLight = lightStage->getCurrentKeyLight();
}
model::LightPointer keyAmbiLight;
if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
keyAmbiLight = lightStage->getLight(lightStage->_currentFrame._ambientLights.front());
if (lightStage) {
keyAmbiLight = lightStage->getCurrentAmbientLight();
}
if (keySunLight) {
@ -620,7 +620,7 @@ void RenderDeferredLocals::run(const render::RenderContextPointer& renderContext
auto& lightIndices = lightClusters->_visibleLightIndices;
if (!lightIndices.empty() && lightIndices[0] > 0) {
// Bind the global list of lights and the visible lights this frame
batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->_lightArrayBuffer);
batch.setUniformBuffer(deferredLightingEffect->_localLightLocations->lightBufferUnit, lightClusters->_lightStage->getLightArrayBuffer());
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);

View file

@ -175,9 +175,9 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu
batch.setUniformBuffer(HazeEffect_TransformBufferSlot, transformBuffer->getFrameTransformBuffer());
auto lightStage = args->_scene->getStage<LightStage>();
if (lightStage && lightStage->_currentFrame._sunLights.size() > 0) {
model::LightPointer keyLight;
keyLight = lightStage->getLight(lightStage->_currentFrame._sunLights.front());
if (lightStage) {
model::LightPointer keyLight;
keyLight = lightStage->getCurrentKeyLight();
if (keyLight != nullptr) {
batch.setUniformBuffer(HazeEffect_LightingMapSlot, keyLight->getLightSchemaBuffer());
}

View file

@ -1931,9 +1931,10 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
vec4 p1;
vec4 p2;
vec4 color;
float width;
};
LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color };
LineData lineData { vec4(p1, 1.0f), vec4(p2, 1.0f), color, glowWidth };
details.uniformBuffer->resize(sizeof(LineData));
details.uniformBuffer->setSubData(0, lineData);
}

View file

@ -727,7 +727,7 @@ void DebugLightClusters::run(const render::RenderContextPointer& renderContext,
batch.setModelTransform(Transform());
// Bind the Light CLuster data strucutre
batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->_lightArrayBuffer);
batch.setUniformBuffer(LIGHT_GPU_SLOT, lightClusters->_lightStage->getLightArrayBuffer());
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_GRID_SLOT, lightClusters->_clusterGridBuffer);
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_CLUSTER_CONTENT_SLOT, lightClusters->_clusterContentBuffer);

View file

@ -19,14 +19,29 @@ const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::I
LightStage::LightStage() {
}
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
map = framebuffer->getDepthStencilBuffer();
Schema schema;
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
LightStage::Shadow::Schema::Schema() :
bias{ 0.005f },
scale{ 1.0f / MAP_SIZE } {
}
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth) {
gpu::FramebufferPointer LightStage::Shadow::framebuffer;
gpu::TexturePointer LightStage::Shadow::map;
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
Schema schema;
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
if (!framebuffer) {
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
map = framebuffer->getDepthStencilBuffer();
}
}
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum,
float viewMinShadowDistance, float viewMaxShadowDistance,
float nearDepth, float farDepth) {
assert(viewMinShadowDistance < viewMaxShadowDistance);
assert(nearDepth < farDepth);
// Orient the keylight frustum
@ -49,8 +64,8 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
const Transform view{ _frustum->getView()};
const Transform viewInverse{ view.getInverseMatrix() };
auto nearCorners = viewFrustum.getCorners(nearDepth);
auto farCorners = viewFrustum.getCorners(farDepth);
auto nearCorners = viewFrustum.getCorners(viewMinShadowDistance);
auto farCorners = viewFrustum.getCorners(viewMaxShadowDistance);
vec3 min{ viewInverse.transform(nearCorners.bottomLeft) };
vec3 max{ min };
@ -74,7 +89,10 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
fitFrustum(farCorners.topLeft);
fitFrustum(farCorners.topRight);
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, -max.z, -min.z);
// Re-adjust near shadow distance
auto near = glm::max(max.z, -nearDepth);
auto far = -min.z;
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, near, far);
_frustum->setProjection(ortho);
// Calculate the frustum's internal state
@ -85,6 +103,16 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, floa
_schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix();
}
void LightStage::Shadow::setFrustum(const ViewFrustum& shadowFrustum) {
const Transform view{ shadowFrustum.getView() };
const Transform viewInverse{ view.getInverseMatrix() };
*_frustum = shadowFrustum;
// Update the buffer
_schemaBuffer.edit<Schema>().projection = shadowFrustum.getProjection();
_schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix();
}
const glm::mat4& LightStage::Shadow::getView() const {
return _frustum->getView();
}
@ -100,11 +128,9 @@ LightStage::Index LightStage::findLight(const LightPointer& light) const {
} else {
return (*found).second;
}
}
LightStage::Index LightStage::addLight(const LightPointer& light) {
auto found = _lightMap.find(light);
if (found == _lightMap.end()) {
auto lightId = _lights.newElement(light);
@ -115,6 +141,7 @@ LightStage::Index LightStage::addLight(const LightPointer& light) {
if (lightId >= (Index) _descs.size()) {
_descs.emplace_back(Desc());
} else {
assert(_descs[lightId].shadowId == INVALID_INDEX);
_descs.emplace(_descs.begin() + lightId, Desc());
}
@ -133,6 +160,7 @@ LightStage::Index LightStage::addShadow(Index lightIndex) {
auto light = getLight(lightIndex);
Index shadowId = INVALID_INDEX;
if (light) {
assert(_descs[lightIndex].shadowId == INVALID_INDEX);
shadowId = _shadows.newElement(std::make_shared<Shadow>(light));
_descs[lightIndex].shadowId = shadowId;
}
@ -140,18 +168,65 @@ LightStage::Index LightStage::addShadow(Index lightIndex) {
}
LightStage::LightPointer LightStage::removeLight(Index index) {
LightPointer removed = _lights.freeElement(index);
if (removed) {
LightPointer removedLight = _lights.freeElement(index);
if (removedLight) {
auto shadowId = _descs[index].shadowId;
// Remove shadow if one exists for this light
if (shadowId != INVALID_INDEX) {
_shadows.freeElement(shadowId);
auto removedShadow = _shadows.freeElement(shadowId);
assert(removedShadow);
assert(removedShadow->getLight() == removedLight);
}
_lightMap.erase(removed);
_lightMap.erase(removedLight);
_descs[index] = Desc();
}
return removed;
assert(_descs.size() <= index || _descs[index].shadowId == INVALID_INDEX);
return removedLight;
}
LightStage::LightPointer LightStage::getCurrentKeyLight() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
return _lights.get(keyLightId);
}
LightStage::LightPointer LightStage::getCurrentAmbientLight() const {
Index keyLightId{ 0 };
if (!_currentFrame._ambientLights.empty()) {
keyLightId = _currentFrame._ambientLights.front();
}
return _lights.get(keyLightId);
}
LightStage::ShadowPointer LightStage::getCurrentKeyShadow() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
auto shadow = getShadow(keyLightId);
assert(shadow == nullptr || shadow->getLight() == getLight(keyLightId));
return shadow;
}
LightStage::LightAndShadow LightStage::getCurrentKeyLightAndShadow() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
auto shadow = getShadow(keyLightId);
auto light = getLight(keyLightId);
assert(shadow == nullptr || shadow->getLight() == light);
return LightAndShadow(light, shadow);
}
LightStage::Index LightStage::getShadowId(Index lightId) const {
if (checkLightId(lightId)) {
return _descs[lightId].shadowId;
} else {
return INVALID_INDEX;
}
}
void LightStage::updateLightArrayBuffer(Index lightId) {

View file

@ -48,8 +48,9 @@ public:
Shadow(model::LightPointer light);
void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth);
void setKeylightFrustum(const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f);
void setFrustum(const ViewFrustum& shadowFrustum);
const std::shared_ptr<ViewFrustum> getFrustum() const { return _frustum; }
const glm::mat4& getView() const;
@ -57,32 +58,36 @@ public:
const UniformBufferView& getBuffer() const { return _schemaBuffer; }
gpu::FramebufferPointer framebuffer;
gpu::TexturePointer map;
// Shadow maps are shared among all lights for the moment as only one key light
// is used.
static gpu::FramebufferPointer framebuffer;
static gpu::TexturePointer map;
const model::LightPointer& getLight() const { return _light; }
protected:
model::LightPointer _light;
std::shared_ptr<ViewFrustum> _frustum;
class Schema {
public:
Schema();
glm::mat4 projection;
glm::mat4 viewInverse;
glm::float32 bias = 0.005f;
glm::float32 scale = 1 / MAP_SIZE;
glm::float32 bias;
glm::float32 scale;
};
UniformBufferView _schemaBuffer = nullptr;
friend class Light;
};
using ShadowPointer = std::shared_ptr<Shadow>;
using Shadows = render::indexed_container::IndexedPointerVector<Shadow>;
struct Desc {
Index shadowId { INVALID_INDEX };
};
using Descs = std::vector<Desc>;
Index findLight(const LightPointer& light) const;
Index addLight(const LightPointer& light);
@ -100,50 +105,29 @@ public:
return _lights.get(lightId);
}
Index getShadowId(Index lightId) const {
if (checkLightId(lightId)) {
return _descs[lightId].shadowId;
} else {
return INVALID_INDEX;
}
}
Index getShadowId(Index lightId) const;
ShadowPointer getShadow(Index lightId) const {
return _shadows.get(getShadowId(lightId));
}
using LightAndShadow = std::pair<LightPointer, ShadowPointer>;
LightAndShadow getLightAndShadow(Index lightId) const {
return LightAndShadow(getLight(lightId), getShadow(lightId));
auto light = getLight(lightId);
auto shadow = getShadow(lightId);
assert(shadow == nullptr || shadow->getLight() == light);
return LightAndShadow(light, shadow);
}
LightPointer getCurrentKeyLight() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
return _lights.get(keyLightId);
}
ShadowPointer getCurrentKeyShadow() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
return getShadow(keyLightId);
}
LightAndShadow getCurrentKeyLightAndShadow() const {
Index keyLightId{ 0 };
if (!_currentFrame._sunLights.empty()) {
keyLightId = _currentFrame._sunLights.front();
}
return LightAndShadow(getLight(keyLightId), getShadow(keyLightId));
}
LightPointer getCurrentKeyLight() const;
LightPointer getCurrentAmbientLight() const;
ShadowPointer getCurrentKeyShadow() const;
LightAndShadow getCurrentKeyLightAndShadow() const;
LightStage();
Lights _lights;
LightMap _lightMap;
Descs _descs;
gpu::BufferPointer getLightArrayBuffer() const { return _lightArrayBuffer; }
void updateLightArrayBuffer(Index lightId);
class Frame {
public:
@ -172,15 +156,24 @@ public:
Frame _currentFrame;
gpu::BufferPointer _lightArrayBuffer;
void updateLightArrayBuffer(Index lightId);
protected:
struct Desc {
Index shadowId{ INVALID_INDEX };
};
using Descs = std::vector<Desc>;
gpu::BufferPointer _lightArrayBuffer;
Lights _lights;
Shadows _shadows;
Descs _descs;
LightMap _lightMap;
};
using LightStagePointer = std::shared_ptr<LightStage>;
class LightStageSetup {
public:
using JobModel = render::Job::Model<LightStageSetup>;

View file

@ -44,8 +44,6 @@
#include "DrawHaze.h"
#include "HighlightEffect.h"
#include <gpu/StandardShaderLib.h>
#include <sstream>
using namespace render;
@ -193,13 +191,18 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
{ // DEbug the bounds of the rendered items, still look at the zbuffer
{ // Debug the bounds of the rendered items, still look at the zbuffer
task.addJob<DrawBounds>("DrawMetaBounds", metas);
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
task.addJob<DrawBounds>("DrawLightBounds", lights);
task.addJob<DrawBounds>("DrawZones", zones);
const auto frustums = task.addJob<ExtractFrustums>("ExtractFrustums");
const auto viewFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::VIEW_FRUSTUM);
const auto shadowFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::SHADOW_FRUSTUM);
task.addJob<DrawFrustum>("DrawViewFrustum", viewFrustum, glm::vec3(1.0f, 1.0f, 0.0f));
task.addJob<DrawFrustum>("DrawShadowFrustum", shadowFrustum, glm::vec3(0.0f, 0.0f, 1.0f));
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true
task.addJob<DrawBounds>("DrawSelectionBounds", selectedItems);
@ -448,6 +451,11 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) {
assert(renderContext->args);
assert(renderContext->args->_context);
// We do not want to render HUD elements in secondary camera
if (renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) {
return;
}
// Grab the HUD texture
gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) {
if (renderContext->args->_hudOperator) {
@ -527,3 +535,32 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
});
}
void ExtractFrustums::run(const render::RenderContextPointer& renderContext, Output& output) {
assert(renderContext->args);
assert(renderContext->args->_context);
RenderArgs* args = renderContext->args;
// Return view frustum
auto& viewFrustum = output[VIEW_FRUSTUM].edit<ViewFrustumPointer>();
if (!viewFrustum) {
viewFrustum = std::make_shared<ViewFrustum>(args->getViewFrustum());
} else {
*viewFrustum = args->getViewFrustum();
}
// Return shadow frustum
auto& shadowFrustum = output[SHADOW_FRUSTUM].edit<ViewFrustumPointer>();
auto lightStage = args->_scene->getStage<LightStage>(LightStage::getName());
if (lightStage) {
auto globalShadow = lightStage->getCurrentKeyShadow();
if (globalShadow) {
shadowFrustum = globalShadow->getFrustum();
} else {
shadowFrustum.reset();
}
} else {
shadowFrustum.reset();
}
}

View file

@ -170,6 +170,22 @@ public:
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
};
class ExtractFrustums {
public:
enum Frustum {
VIEW_FRUSTUM,
SHADOW_FRUSTUM,
FRUSTUM_COUNT
};
using Output = render::VaryingArray<ViewFrustumPointer, FRUSTUM_COUNT>;
using JobModel = render::Job::ModelO<ExtractFrustums, Output>;
void run(const render::RenderContextPointer& renderContext, Output& output);
};
class RenderDeferredTaskConfig : public render::Task::Config {
Q_OBJECT
Q_PROPERTY(float fadeScale MEMBER fadeScale NOTIFY dirty)

View file

@ -22,25 +22,136 @@
#include "DeferredLightingEffect.h"
#include "FramebufferCache.h"
// These values are used for culling the objects rendered in the shadow map
// but are readjusted afterwards
#define SHADOW_FRUSTUM_NEAR 1.0f
#define SHADOW_FRUSTUM_FAR 500.0f
using namespace render;
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state);
void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
const render::ShapeBounds& inShapes) {
static void computeNearFar(const Triangle& triangle, const Plane shadowClipPlanes[4], float& near, float& far) {
static const int MAX_TRIANGLE_COUNT = 16;
Triangle clippedTriangles[MAX_TRIANGLE_COUNT];
auto clippedTriangleCount = clipTriangleWithPlanes(triangle, shadowClipPlanes, 4, clippedTriangles, MAX_TRIANGLE_COUNT);
for (auto i = 0; i < clippedTriangleCount; i++) {
const auto& clippedTriangle = clippedTriangles[i];
near = glm::min(near, -clippedTriangle.v0.z);
near = glm::min(near, -clippedTriangle.v1.z);
near = glm::min(near, -clippedTriangle.v2.z);
far = glm::max(far, -clippedTriangle.v0.z);
far = glm::max(far, -clippedTriangle.v1.z);
far = glm::max(far, -clippedTriangle.v2.z);
}
}
static void computeNearFar(const glm::vec3 sceneBoundVertices[8], const Plane shadowClipPlanes[4], float& near, float& far) {
// This code is inspired from Microsoft's CascadedShadowMaps11 sample which is under MIT licence.
// See https://code.msdn.microsoft.com/windowsdesktop/Direct3D-Shadow-Win32-2d72a4f2/sourcecode?fileId=121915&pathId=1645833187
// Basically it decomposes the object bounding box in triangles and clips each triangle with the shadow
// frustum planes. Finally it computes the minimum and maximum depth of the clipped triangle vertices
// in shadow space to extract the near and far distances of the shadow frustum.
static const std::array<int[4], 6> boxQuadVertexIndices = { {
{ TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR },
{ TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR },
{ TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR },
{ TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR },
{ BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_RIGHT_NEAR, BOTTOM_LEFT_NEAR },
{ TOP_LEFT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR }
} };
Triangle triangle;
for (auto quadVertexIndices : boxQuadVertexIndices) {
triangle.v0 = sceneBoundVertices[quadVertexIndices[0]];
triangle.v1 = sceneBoundVertices[quadVertexIndices[1]];
triangle.v2 = sceneBoundVertices[quadVertexIndices[2]];
computeNearFar(triangle, shadowClipPlanes, near, far);
triangle.v1 = sceneBoundVertices[quadVertexIndices[3]];
computeNearFar(triangle, shadowClipPlanes, near, far);
}
}
static void adjustNearFar(const AABox& inShapeBounds, ViewFrustum& shadowFrustum) {
const Transform shadowView{ shadowFrustum.getView() };
const Transform shadowViewInverse{ shadowView.getInverseMatrix() };
glm::vec3 sceneBoundVertices[8];
// Keep only the left, right, top and bottom shadow frustum planes as we wish to determine
// the near and far
Plane shadowClipPlanes[4];
int i;
// The vertices of the scene bounding box are expressed in the shadow frustum's local space
for (i = 0; i < 8; i++) {
sceneBoundVertices[i] = shadowViewInverse.transform(inShapeBounds.getVertex(static_cast<BoxVertex>(i)));
}
// This indirection array is just a protection in case the ViewFrustum::PlaneIndex enum
// changes order especially as we don't need to test the NEAR and FAR planes.
static const ViewFrustum::PlaneIndex planeIndices[4] = {
ViewFrustum::TOP_PLANE,
ViewFrustum::BOTTOM_PLANE,
ViewFrustum::LEFT_PLANE,
ViewFrustum::RIGHT_PLANE
};
// Same goes for the shadow frustum planes.
for (i = 0; i < 4; i++) {
const auto& worldPlane = shadowFrustum.getPlanes()[planeIndices[i]];
// We assume the transform doesn't have a non uniform scale component to apply the
// transform to the normal without using the correct transpose of inverse, which should be the
// case for a view matrix.
auto planeNormal = shadowViewInverse.transformDirection(worldPlane.getNormal());
auto planePoint = shadowViewInverse.transform(worldPlane.getPoint());
shadowClipPlanes[i].setNormalAndPoint(planeNormal, planePoint);
}
float near = std::numeric_limits<float>::max();
float far = 0.0f;
computeNearFar(sceneBoundVertices, shadowClipPlanes, near, far);
// Limit the far range to the one used originally. There's no point in rendering objects
// that are not in the view frustum.
far = glm::min(far, shadowFrustum.getFarClip());
const auto depthEpsilon = 0.1f;
auto projMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, near - depthEpsilon, far + depthEpsilon);
auto shadowProjection = shadowFrustum.getProjection();
shadowProjection[2][2] = projMatrix[2][2];
shadowProjection[3][2] = projMatrix[3][2];
shadowFrustum.setProjection(shadowProjection);
shadowFrustum.calculate();
}
void RenderShadowMap::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
const auto& inShapes = inputs.get0();
const auto& inShapeBounds = inputs.get1();
auto lightStage = renderContext->_scene->getStage<LightStage>();
assert(lightStage);
const auto shadow = lightStage->getCurrentKeyShadow();
auto shadow = lightStage->getCurrentKeyShadow();
if (!shadow) return;
const auto& fbo = shadow->framebuffer;
RenderArgs* args = renderContext->args;
ShapeKey::Builder defaultKeyBuilder;
auto adjustedShadowFrustum = args->getViewFrustum();
// Adjust the frustum near and far depths based on the rendered items bounding box to have
// the minimal Z range.
adjustNearFar(inShapeBounds, adjustedShadowFrustum);
// Reapply the frustum as it has been adjusted
shadow->setFrustum(adjustedShadowFrustum);
args->popViewFrustum();
args->pushViewFrustum(adjustedShadowFrustum);
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
@ -55,8 +166,13 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
vec4(vec3(1.0, 1.0, 1.0), 0.0), 1.0, 0, true);
batch.setProjectionTransform(shadow->getProjection());
batch.setViewTransform(shadow->getView(), false);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, false);
auto shadowPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder);
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
@ -87,7 +203,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
}
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; };
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; };
// Prepare the ShapePipeline
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
@ -109,10 +225,10 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
// Sort
const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadowMap", sortedPipelines);
const auto sortedShapesAndBounds = task.addJob<DepthSortShapesAndComputeBounds>("DepthSortShadowMap", sortedPipelines, true);
// GPU jobs: Render to shadow map
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapesAndBounds, shapePlumber);
task.addJob<RenderShadowTeardown>("ShadowTeardown", cachedMode);
}
@ -135,8 +251,8 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
auto nearClip = args->getViewFrustum().getNearClip();
float nearDepth = -args->_boomOffset.z;
const int SHADOW_FAR_DEPTH = 20;
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH);
const float SHADOW_MAX_DISTANCE = 20.0f;
globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
// Set the keylight render args
args->pushViewFrustum(*(globalShadow->getFrustum()));

View file

@ -21,11 +21,11 @@ class ViewFrustum;
class RenderShadowMap {
public:
using JobModel = render::Job::ModelI<RenderShadowMap, render::ShapeBounds>;
using Inputs = render::VaryingSet2<render::ShapeBounds, AABox>;
using JobModel = render::Job::ModelI<RenderShadowMap, Inputs>;
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
void run(const render::RenderContextPointer& renderContext,
const render::ShapeBounds& inShapes);
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
protected:
render::ShapePlumberPointer _shapePlumber;

View file

@ -19,7 +19,10 @@
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
// auto items = input.get<Input>();
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
// Shadows use an orthographic projection because they are linked to sunlights
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
// TODO : create a special cull functor for this.
task.addJob<RenderShadowTask>("RenderShadowTask", nullptr);
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
assert(items.canCast<RenderFetchCullSortTask::Output>());

View file

@ -68,6 +68,8 @@ vec2 PCFkernel[4] = vec2[4](
);
float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) {
// PCF is buggy so disable it for the time being
#if 0
float pcfRadius = 3.0;
float shadowScale = getShadowScale();
@ -80,6 +82,9 @@ float evalShadowAttenuationPCF(vec4 position, vec4 shadowTexcoord) {
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[2], 0.0)) +
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(offset + PCFkernel[3], 0.0))
));
#else
float shadowAttenuation = fetchShadow(shadowTexcoord.xyz);
#endif
return shadowAttenuation;
}

View file

@ -10,8 +10,8 @@
//
in vec4 _color;
in float distanceFromCenter;
in float distanceFromCenter;
out vec4 _fragColor;
void main(void) {

View file

@ -16,6 +16,7 @@ layout(std140) uniform lineData {
vec4 p1;
vec4 p2;
vec4 color;
float width;
};
out vec4 _color;
@ -39,7 +40,7 @@ void main(void) {
// Find the vector from the eye to one of the points
vec3 v2 = normalize(p1eye.xyz);
// The orthogonal vector is the cross product of these two
vec3 orthogonal = cross(v1, v2) * 0.02;
vec3 orthogonal = cross(v1, v2) * width;
// Deteremine which end to emit based on the vertex id (even / odd)
vec4 eye = (0 == gl_VertexID % 2) ? p1eye : p2eye;

View file

@ -20,7 +20,7 @@
#include <PerfStat.h>
#include <ViewFrustum.h>
#include <gpu/Context.h>
#include <gpu/StandardShaderLib.h>
#include <drawItemBounds_vert.h>
#include <drawItemBounds_frag.h>
@ -215,3 +215,85 @@ void DrawBounds::run(const RenderContextPointer& renderContext,
});
}
gpu::PipelinePointer DrawFrustum::_pipeline;
gpu::BufferView DrawFrustum::_frustumMeshIndices;
DrawFrustum::DrawFrustum(const glm::vec3& color) :
_color{ color } {
_frustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
_frustumMeshStream.addBuffer(_frustumMeshVertices._buffer, _frustumMeshVertices._offset, _frustumMeshVertices._stride);
}
void DrawFrustum::configure(const Config& configuration) {
_updateFrustum = !configuration.isFrozen;
}
void DrawFrustum::run(const render::RenderContextPointer& renderContext, const Input& input) {
assert(renderContext->args);
assert(renderContext->args->_context);
RenderArgs* args = renderContext->args;
if (input) {
const auto& frustum = *input;
static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 };
if (!_frustumMeshIndices._buffer) {
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
_frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
}
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
auto ps = gpu::StandardShaderLib::getDrawColorPS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("color", 0));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(true, false));
_pipeline = gpu::Pipeline::create(program, state);
}
if (_updateFrustum) {
updateFrustum(frustum);
}
// Render the frustums in wireframe
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setPipeline(_pipeline);
batch.setIndexBuffer(_frustumMeshIndices);
batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f);
batch.setInputStream(0, _frustumMeshStream);
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
args->_batch = nullptr;
});
}
}
void DrawFrustum::updateFrustum(const ViewFrustum& frustum) {
auto& vertices = _frustumMeshVertices.edit<std::array<glm::vec3, 8U> >();
vertices[0] = frustum.getNearTopLeft();
vertices[1] = frustum.getNearTopRight();
vertices[2] = frustum.getNearBottomRight();
vertices[3] = frustum.getNearBottomLeft();
vertices[4] = frustum.getFarTopLeft();
vertices[5] = frustum.getFarTopRight();
vertices[6] = frustum.getFarBottomRight();
vertices[7] = frustum.getFarBottomLeft();
}

View file

@ -70,6 +70,43 @@ private:
int _colorLocation { -1 };
};
class DrawFrustumConfig : public render::JobConfig {
Q_OBJECT
Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty)
public:
DrawFrustumConfig(bool enabled = false) : JobConfig(enabled) {}
bool isFrozen{ false };
signals:
void dirty();
};
class DrawFrustum {
public:
using Config = DrawFrustumConfig;
using Input = ViewFrustumPointer;
using JobModel = render::Job::ModelI<DrawFrustum, Input, Config>;
DrawFrustum(const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f));
void configure(const Config& configuration);
void run(const render::RenderContextPointer& renderContext, const Input& input);
private:
static gpu::PipelinePointer _pipeline;
static gpu::BufferView _frustumMeshIndices;
bool _updateFrustum{ true };
gpu::BufferView _frustumMeshVertices;
gpu::BufferStream _frustumMeshStream;
glm::vec3 _color;
void updateFrustum(const ViewFrustum& frustum);
};
}
#endif // hifi_render_DrawTask_h

View file

@ -40,7 +40,8 @@ struct BackToFrontSort {
}
};
void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems) {
void render::depthSortItems(const RenderContextPointer& renderContext, bool frontToBack,
const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds) {
assert(renderContext->args);
assert(renderContext->args->hasViewFrustum());
@ -74,12 +75,26 @@ void render::depthSortItems(const RenderContextPointer& renderContext, bool fron
std::sort(itemBoundSorts.begin(), itemBoundSorts.end(), backToFrontSort);
}
// Finally once sorted result to a list of itemID
// Finally once sorted result to a list of itemID and keep uniques
render::ItemID previousID = Item::INVALID_ITEM_ID;
for (auto& item : itemBoundSorts) {
if (item._id != previousID) {
outItems.emplace_back(ItemBound(item._id, item._bounds));
previousID = item._id;
if (!bounds) {
for (auto& item : itemBoundSorts) {
if (item._id != previousID) {
outItems.emplace_back(ItemBound(item._id, item._bounds));
previousID = item._id;
}
}
} else if (!itemBoundSorts.empty()) {
if (bounds->isNull()) {
*bounds = itemBoundSorts.front()._bounds;
}
for (auto& item : itemBoundSorts) {
if (item._id != previousID) {
outItems.emplace_back(ItemBound(item._id, item._bounds));
previousID = item._id;
*bounds += item._bounds;
}
}
}
}
@ -119,6 +134,27 @@ void DepthSortShapes::run(const RenderContextPointer& renderContext, const Shape
}
}
void DepthSortShapesAndComputeBounds::run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs) {
auto& outShapes = outputs.edit0();
auto& outBounds = outputs.edit1();
outShapes.clear();
outShapes.reserve(inShapes.size());
outBounds = AABox();
for (auto& pipeline : inShapes) {
auto& inItems = pipeline.second;
auto outItems = outShapes.find(pipeline.first);
if (outItems == outShapes.end()) {
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemBounds{})).first;
}
AABox bounds;
depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &bounds);
outBounds += bounds;
}
}
void DepthSortItems::run(const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) {
depthSortItems(renderContext, _frontToBack, inItems, outItems);
}

View file

@ -15,7 +15,7 @@
#include "Engine.h"
namespace render {
void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems);
void depthSortItems(const RenderContextPointer& renderContext, bool frontToBack, const ItemBounds& inItems, ItemBounds& outItems, AABox* bounds = nullptr);
class PipelineSortShapes {
public:
@ -33,6 +33,17 @@ namespace render {
void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, ShapeBounds& outShapes);
};
class DepthSortShapesAndComputeBounds {
public:
using Outputs = VaryingSet2<ShapeBounds, AABox>;
using JobModel = Job::ModelIO<DepthSortShapesAndComputeBounds, ShapeBounds, Outputs>;
bool _frontToBack;
DepthSortShapesAndComputeBounds(bool frontToBack = true) : _frontToBack(frontToBack) {}
void run(const RenderContextPointer& renderContext, const ShapeBounds& inShapes, Outputs& outputs);
};
class DepthSortItems {
public:
using JobModel = Job::ModelIO<DepthSortItems, ItemBounds, ItemBounds>;

View file

@ -127,10 +127,11 @@ public:
AABox getOctreeChild(OctreeChild child) const; // returns the AABox of the would be octree child of this AABox
glm::vec4 getPlane(BoxFace face) const;
private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
glm::vec4 getPlane(BoxFace face) const;
static BoxFace getOppositeFace(BoxFace face);

View file

@ -14,10 +14,12 @@
#include <assert.h>
#include <cstring>
#include <cmath>
#include <bitset>
#include <glm/gtx/quaternion.hpp>
#include "NumericalConstants.h"
#include "GLMHelpers.h"
#include "Plane.h"
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
// compute the projection of the point vector onto the segment vector
@ -314,6 +316,134 @@ bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direc
return false;
}
static void getTrianglePlaneIntersectionPoints(const glm::vec3 trianglePoints[3], const float pointPlaneDistances[3],
const int clippedPointIndex, const int keptPointIndices[2],
glm::vec3 points[2]) {
assert(clippedPointIndex >= 0 && clippedPointIndex < 3);
const auto& clippedPoint = trianglePoints[clippedPointIndex];
const float clippedPointPlaneDistance = pointPlaneDistances[clippedPointIndex];
for (auto i = 0; i < 2; i++) {
assert(keptPointIndices[i] >= 0 && keptPointIndices[i] < 3);
const auto& keptPoint = trianglePoints[keptPointIndices[i]];
const float keptPointPlaneDistance = pointPlaneDistances[keptPointIndices[i]];
auto intersectionEdgeRatio = clippedPointPlaneDistance / (clippedPointPlaneDistance - keptPointPlaneDistance);
points[i] = clippedPoint + (keptPoint - clippedPoint) * intersectionEdgeRatio;
}
}
int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount) {
float pointDistanceToPlane[3];
std::bitset<3> arePointsClipped;
glm::vec3 triangleVertices[3] = { triangle.v0, triangle.v1, triangle.v2 };
int clippedTriangleCount = 0;
int i;
assert(clippedTriangleCount > 0);
for (i = 0; i < 3; i++) {
pointDistanceToPlane[i] = plane.distance(triangleVertices[i]);
arePointsClipped.set(i, pointDistanceToPlane[i] < 0.0f);
}
switch (arePointsClipped.count()) {
case 0:
// Easy, the entire triangle is kept as is.
*clippedTriangles = triangle;
clippedTriangleCount = 1;
break;
case 1:
{
int clippedPointIndex = 2;
int keptPointIndices[2] = { 0, 1 };
glm::vec3 newVertices[2];
// Determine which point was clipped.
if (arePointsClipped.test(0)) {
clippedPointIndex = 0;
keptPointIndices[0] = 2;
} else if (arePointsClipped.test(1)) {
clippedPointIndex = 1;
keptPointIndices[1] = 2;
}
// We have a quad now, so we need to create two triangles.
getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, clippedPointIndex, keptPointIndices, newVertices);
clippedTriangles->v0 = triangleVertices[keptPointIndices[0]];
clippedTriangles->v1 = triangleVertices[keptPointIndices[1]];
clippedTriangles->v2 = newVertices[1];
clippedTriangles++;
clippedTriangleCount++;
if (clippedTriangleCount < maxClippedTriangleCount) {
clippedTriangles->v0 = triangleVertices[keptPointIndices[0]];
clippedTriangles->v1 = newVertices[0];
clippedTriangles->v2 = newVertices[1];
clippedTriangles++;
clippedTriangleCount++;
}
}
break;
case 2:
{
int keptPointIndex = 2;
int clippedPointIndices[2] = { 0, 1 };
glm::vec3 newVertices[2];
// Determine which point was NOT clipped.
if (!arePointsClipped.test(0)) {
keptPointIndex = 0;
clippedPointIndices[0] = 2;
} else if (!arePointsClipped.test(1)) {
keptPointIndex = 1;
clippedPointIndices[1] = 2;
}
// We have a single triangle
getTrianglePlaneIntersectionPoints(triangleVertices, pointDistanceToPlane, keptPointIndex, clippedPointIndices, newVertices);
clippedTriangles->v0 = triangleVertices[keptPointIndex];
clippedTriangles->v1 = newVertices[0];
clippedTriangles->v2 = newVertices[1];
clippedTriangleCount = 1;
}
break;
default:
// Entire triangle is clipped.
break;
}
return clippedTriangleCount;
}
int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount) {
auto planesEnd = planes + planeCount;
int triangleCount = 1;
std::vector<Triangle> trianglesToTest;
assert(maxClippedTriangleCount > 0);
*clippedTriangles = triangle;
while (planes < planesEnd) {
int clippedSubTriangleCount;
trianglesToTest.clear();
trianglesToTest.insert(trianglesToTest.begin(), clippedTriangles, clippedTriangles + triangleCount);
triangleCount = 0;
for (const auto& triangleToTest : trianglesToTest) {
clippedSubTriangleCount = clipTriangleWithPlane(triangleToTest, *planes,
clippedTriangles + triangleCount, maxClippedTriangleCount - triangleCount);
triangleCount += clippedSubTriangleCount;
if (triangleCount >= maxClippedTriangleCount) {
return triangleCount;
}
}
++planes;
}
return triangleCount;
}
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {

View file

@ -15,6 +15,8 @@
#include <glm/glm.hpp>
#include <vector>
class Plane;
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end);
/// Computes the penetration between a point and a sphere (centered at the origin)
@ -109,6 +111,8 @@ inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3
return findRayTriangleIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance, allowBackface);
}
int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount);
int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount);
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);

View file

@ -19,7 +19,9 @@
class Plane {
public:
Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1,v2,v3); }
Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1, v2, v3); }
Plane(const glm::vec3 &normal, const glm::vec3 &point) { setNormalAndPoint(normal, point); }
Plane(float a, float b, float c, float d) { setCoefficients(a, b, c, d); }
Plane() : _normal(0.0f), _point(0.0f), _dCoefficient(0.0f) {};
~Plane() {} ;

View file

@ -149,6 +149,7 @@ public:
Vec4 transform(const Vec4& pos) const;
Vec3 transform(const Vec3& pos) const;
Vec3 transformDirection(const Vec3& dir) const;
bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); }
@ -541,6 +542,13 @@ inline Transform::Vec3 Transform::transform(const Vec3& pos) const {
return Vec3(result.x / result.w, result.y / result.w, result.z / result.w);
}
inline Transform::Vec3 Transform::transformDirection(const Vec3& dir) const {
Mat4 m;
getMatrix(m);
Vec4 result = m * Vec4(dir, 0.0f);
return Vec3(result.x, result.y, result.z);
}
inline Transform::Mat4& Transform::getCachedMatrix(Transform::Mat4& result) const {
updateCache();
result = (*_matrix);

View file

@ -1080,6 +1080,7 @@ static const uint8_t BACKSPACE_SYMBOL[] = { 0xE2, 0x86, 0x90, 0x00 };
static const uint8_t LEFT_ARROW[] = { 0xE2, 0x9D, 0xAC, 0x00 };
static const uint8_t RIGHT_ARROW[] = { 0xE2, 0x9D, 0xAD, 0x00 };
static const uint8_t RETURN_SYMBOL[] = { 0xE2, 0x8F, 0x8E, 0x00 };
static const uint8_t COLLAPSE_KEYBOARD[] = { 0xEE, 0x80, 0xAB, 0x00 };
static const char PUNCTUATION_STRING[] = "123";
static const char ALPHABET_STRING[] = "abc";
@ -1103,6 +1104,9 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
if (equals(utf8Key, SHIFT_ARROW) || equals(utf8Key, NUMERIC_SHIFT_ARROW) ||
equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) {
return; // ignore
} else if (equals(utf8Key, COLLAPSE_KEYBOARD)) {
lowerKeyboard();
return;
} else if (equals(utf8Key, BACKSPACE_SYMBOL)) {
scanCode = Qt::Key_Backspace;
keyString = "\x08";
@ -1124,7 +1128,19 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
}
}
void OffscreenQmlSurface::lowerKeyboard() {
QSignalBlocker blocker(_quickWindow);
if (_currentFocusItem) {
_currentFocusItem->setFocus(false);
setKeyboardRaised(_currentFocusItem, false);
}
}
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) {
qCDebug(uiLogging) << "setKeyboardRaised: " << object << ", raised: " << raised << ", numeric: " << numeric << ", password: " << passwordField;
#if Q_OS_ANDROID
return;
#endif
@ -1159,6 +1175,10 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
item->setProperty("passwordField", QVariant(passwordField));
}
if (raised) {
item->setProperty("keyboardRaised", QVariant(!raised));
}
item->setProperty("keyboardRaised", QVariant(raised));
return;
}

View file

@ -90,6 +90,7 @@ public:
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false);
Q_INVOKABLE void synthesizeKeyPress(QString key, QObject* targetOverride = nullptr);
Q_INVOKABLE void lowerKeyboard();
using TextureAndFence = std::pair<uint32_t, void*>;
// Checks to see if a new texture is available. If one is, the function returns true and

View file

@ -96,7 +96,6 @@ function rayCastTest() {
color: color,
alpha: 1,
visible: visible,
lineWidth: 2,
start: origin,
end: Vec3.sum(origin,Vec3.multiply(5,direction))
});

View file

@ -0,0 +1,20 @@
//
// debugShadow.js
// developer/utilities/render
//
// Olivier Prat, created on 10/25/2017.
// Copyright 2017 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
//
// Set up the qml ui
var qml = Script.resolvePath('shadow.qml');
var window = new OverlayWindow({
title: 'Shadow Debug',
source: qml,
width: 200,
height: 90
});
window.closed.connect(function() { Script.stop(); });

View file

@ -0,0 +1,50 @@
//
// shadow.qml
// developer/utilities/render
//
// Olivier Prat, created on 10/25/2017.
// Copyright 2017 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
Column {
id: root
spacing: 8
property var viewConfig: Render.getConfig("RenderMainView.DrawViewFrustum");
property var shadowConfig: Render.getConfig("RenderMainView.DrawShadowFrustum");
Component.onCompleted: {
viewConfig.enabled = true;
shadowConfig.enabled = true;
}
Component.onDestruction: {
viewConfig.enabled = false;
shadowConfig.enabled = false;
}
CheckBox {
text: "Freeze Frustums"
checked: false
onCheckedChanged: {
viewConfig.isFrozen = checked;
shadowConfig.isFrozen = checked;
}
}
Row {
spacing: 8
Label {
text: "View"
color: "yellow"
font.italic: true
}
Label {
text: "Shadow"
color: "blue"
font.italic: true
}
}
}

View file

@ -284,8 +284,7 @@
endParentJointIndex: yourJointIndex,
end: yourJointPosition,
color: identifyAvatarLineColor,
alpha: 1,
lineWidth: 1
alpha: 1
};
avatarIdentifiers[yourAvatarID] = identifierParams;

View file

@ -33,7 +33,6 @@ Script.include("/~/system/libraries/Xform.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -55,7 +54,6 @@ Script.include("/~/system/libraries/Xform.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -77,7 +75,6 @@ Script.include("/~/system/libraries/Xform.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -649,6 +646,7 @@ Script.include("/~/system/libraries/Xform.js");
renderStates: renderStates,
faceAvatar: true,
distanceScaleEnd: true,
scaleWithAvatar: true,
defaultRenderStates: defaultRenderStates
});
}

View file

@ -25,7 +25,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -47,7 +46,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -69,7 +67,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -190,6 +187,7 @@ Script.include("/~/system/libraries/controllers.js");
renderStates: renderStates,
faceAvatar: true,
distanceScaleEnd: true,
scaleWithAvatar: true,
defaultRenderStates: defaultRenderStates
});

View file

@ -31,7 +31,6 @@
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawHUDLayer: true,
parentID: MyAvatar.SELF_ID
@ -53,7 +52,6 @@
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawHUDLayer: true,
parentID: MyAvatar.SELF_ID
@ -75,7 +73,6 @@
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawHUDLayer: true,
parentID: MyAvatar.SELF_ID

View file

@ -27,7 +27,6 @@ Script.include("/~/system/libraries/utils.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -49,7 +48,6 @@ Script.include("/~/system/libraries/utils.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -71,7 +69,6 @@ Script.include("/~/system/libraries/utils.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -237,6 +234,7 @@ Script.include("/~/system/libraries/utils.js");
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,
faceAvatar: true,
scaleWithAvatar: true,
defaultRenderStates: defaultRenderStates
});

View file

@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -371,6 +368,7 @@ Script.include("/~/system/libraries/controllers.js");
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,
faceAvatar: true,
scaleWithAvatar: true,
defaultRenderStates: defaultRenderStates
});

View file

@ -153,6 +153,7 @@ Script.include("/~/system/libraries/controllers.js");
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
filter: RayPick.PICK_ENTITIES,
faceAvatar: true,
scaleWithAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
@ -161,6 +162,7 @@ Script.include("/~/system/libraries/controllers.js");
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
scaleWithAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates
});
@ -168,6 +170,7 @@ Script.include("/~/system/libraries/controllers.js");
joint: "Avatar",
filter: RayPick.PICK_ENTITIES,
faceAvatar: true,
scaleWithAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
@ -176,6 +179,7 @@ Script.include("/~/system/libraries/controllers.js");
joint: "Avatar",
filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
scaleWithAvatar: true,
centerEndY: false,
renderStates: teleportRenderStates
});

View file

@ -26,7 +26,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -48,7 +47,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -70,7 +68,6 @@ Script.include("/~/system/libraries/controllers.js");
alpha: 1,
solid: true,
glow: 1.0,
lineWidth: 5,
ignoreRayIntersection: true, // always ignore this
drawInFront: true, // Even when burried inside of something, show it.
parentID: MyAvatar.SELF_ID
@ -88,7 +85,6 @@ Script.include("/~/system/libraries/controllers.js");
{name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath}
];
// triggered when stylus presses a web overlay/entity
var HAPTIC_STYLUS_STRENGTH = 1.0;
var HAPTIC_STYLUS_DURATION = 20.0;
@ -452,6 +448,7 @@ Script.include("/~/system/libraries/controllers.js");
posOffset: getGrabPointSphereOffset(this.handToController(), true),
renderStates: renderStates,
faceAvatar: true,
scaleWithAvatar: true,
defaultRenderStates: defaultRenderStates
});
}

View file

@ -339,7 +339,6 @@ SelectionDisplay = (function() {
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4
};
@ -352,7 +351,6 @@ SelectionDisplay = (function() {
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4
};
@ -365,7 +363,6 @@ SelectionDisplay = (function() {
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4
};
@ -378,14 +375,12 @@ SelectionDisplay = (function() {
solid: grabberSolid,
visible: false,
dashed: false,
lineWidth: grabberLineWidth,
drawInFront: true,
borderSize: 1.4
};
var spotLightLineProperties = {
color: lightOverlayColor,
lineWidth: 1.5
color: lightOverlayColor
};
var highlightBox = Overlays.addOverlay("cube", {
@ -400,7 +395,6 @@ SelectionDisplay = (function() {
solid: false,
visible: false,
dashed: true,
lineWidth: 2.0,
ignoreRayIntersection: true, // this never ray intersects
drawInFront: true
});
@ -416,8 +410,7 @@ SelectionDisplay = (function() {
alpha: 1,
solid: false,
visible: false,
dashed: false,
lineWidth: 1.0
dashed: false
});
var selectionBoxes = [];
@ -466,7 +459,6 @@ SelectionDisplay = (function() {
// var normalLine = Overlays.addOverlay("line3d", {
// visible: true,
// lineWidth: 2.0,
// start: { x: 0, y: 0, z: 0 },
// end: { x: 0, y: 0, z: 0 },
// color: { red: 255, green: 255, blue: 0 },
@ -656,7 +648,6 @@ SelectionDisplay = (function() {
var xRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: Vec3.ZERO,
end: Vec3.ZERO,
color: {
@ -668,7 +659,6 @@ SelectionDisplay = (function() {
});
var yRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: Vec3.ZERO,
end: Vec3.ZERO,
color: {
@ -680,7 +670,6 @@ SelectionDisplay = (function() {
});
var zRailOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 1.0,
start: Vec3.ZERO,
end: Vec3.ZERO,
color: {
@ -693,7 +682,6 @@ SelectionDisplay = (function() {
var rotateZeroOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 2.0,
start: Vec3.ZERO,
end: Vec3.ZERO,
color: {
@ -706,7 +694,6 @@ SelectionDisplay = (function() {
var rotateCurrentOverlay = Overlays.addOverlay("line3d", {
visible: false,
lineWidth: 2.0,
start: Vec3.ZERO,
end: Vec3.ZERO,
color: {
@ -1788,7 +1775,6 @@ SelectionDisplay = (function() {
y: distance,
z: 1
},
lineWidth: 1.5,
rotation: rotation,
visible: true
});
@ -1994,7 +1980,6 @@ SelectionDisplay = (function() {
solid: false,
visible: false,
dashed: false,
lineWidth: 1.0,
ignoreRayIntersection: true
}));
}

View file

@ -168,6 +168,106 @@
}));
}
var HALF_TREE_SCALE = 16384;
function getPositionToCreateEntity(extra) {
var CREATE_DISTANCE = 2;
var position;
var delta = extra !== undefined ? extra : 0;
if (Camera.mode === "entity" || Camera.mode === "independent") {
position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta));
} else {
position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta));
position.y += 0.5;
}
if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
return null;
}
return position;
}
function rezEntity(itemHref, isWearable) {
var success = Clipboard.importEntities(itemHref);
if (success) {
var VERY_LARGE = 10000;
var isLargeImport = Clipboard.getClipboardContentsLargestDimension() >= VERY_LARGE;
var position = Vec3.ZERO;
if (!isLargeImport) {
position = getPositionToCreateEntity(Clipboard.getClipboardContentsLargestDimension() / 2);
}
if (position !== null && position !== undefined) {
var pastedEntityIDs = Clipboard.pasteEntities(position);
if (!isLargeImport) {
// The first entity in Clipboard gets the specified position with the rest being relative to it. Therefore, move
// entities after they're imported so that they're all the correct distance in front of and with geometric mean
// centered on the avatar/camera direction.
var deltaPosition = Vec3.ZERO;
var entityPositions = [];
var entityParentIDs = [];
var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type;
var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"];
if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) {
var targetDirection;
if (Camera.mode === "entity" || Camera.mode === "independent") {
targetDirection = Camera.orientation;
} else {
targetDirection = MyAvatar.orientation;
}
targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z);
var targetPosition = getPositionToCreateEntity();
var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
"registrationPoint", "rotation", "parentID"]);
var adjustedPosition = adjustPositionPerBoundingBox(targetPosition, targetDirection,
curLoopEntityProps.registrationPoint, curLoopEntityProps.dimensions, curLoopEntityProps.rotation);
var delta = Vec3.subtract(adjustedPosition, curLoopEntityProps.position);
var distance = Vec3.dot(delta, targetDirection);
deltaParallel = Math.min(distance, deltaParallel);
deltaPerpendicular = Vec3.sum(Vec3.subtract(delta, Vec3.multiply(distance, targetDirection)),
deltaPerpendicular);
entityPositions[i] = curLoopEntityProps.position;
entityParentIDs[i] = curLoopEntityProps.parentID;
}
deltaPerpendicular = Vec3.multiply(1 / pastedEntityIDs.length, deltaPerpendicular);
deltaPosition = Vec3.sum(Vec3.multiply(deltaParallel, targetDirection), deltaPerpendicular);
}
if (grid.getSnapToGrid()) {
var firstEntityProps = Entities.getEntityProperties(pastedEntityIDs[0], ["position", "dimensions",
"registrationPoint"]);
var positionPreSnap = Vec3.sum(deltaPosition, firstEntityProps.position);
position = grid.snapToSurface(grid.snapToGrid(positionPreSnap, false, firstEntityProps.dimensions,
firstEntityProps.registrationPoint), firstEntityProps.dimensions, firstEntityProps.registrationPoint);
deltaPosition = Vec3.subtract(position, firstEntityProps.position);
}
if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) {
if (Uuid.isNull(entityParentIDs[editEntityIndex])) {
Entities.editEntity(pastedEntityIDs[editEntityIndex], {
position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex])
});
}
}
}
}
if (isActive) {
selectionManager.setSelections(pastedEntityIDs);
}
} else {
Window.notifyEditError("Can't import entities: entities would be out of bounds.");
}
} else {
Window.notifyEditError("There was an error importing the entity file.");
}
}
marketplaceButton.clicked.connect(onClick);
tablet.screenChanged.connect(onScreenChanged);
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
@ -330,6 +430,10 @@
tablet.gotoWebScreen(MARKETPLACE_URL + '/items/' + itemId, MARKETPLACES_INJECT_SCRIPT_URL);
}
break;
case 'checkout_rezClicked':
case 'purchases_rezClicked':
rezEntity(message.itemHref, message.isWearable);
break;
case 'header_marketplaceImageClicked':
case 'purchases_backClicked':
tablet.gotoWebScreen(message.referrerURL, MARKETPLACES_INJECT_SCRIPT_URL);

View file

@ -189,7 +189,6 @@ function HighlightedEntity(id, entityProperties) {
green: 0x91,
blue: 0x29
},
lineWidth: 1.0,
ignoreRayIntersection: true,
drawInFront: false // Arguable. For now, let's not distract with mysterious wires around the scene.
});

View file

@ -350,8 +350,7 @@
end: ZERO_VECTOR,
color: { red: 255, green: 0, blue: 0},
alpha: 1,
visible: true,
lineWidth: 2
visible: true
});
},
};

View file

@ -329,7 +329,6 @@
y: 0,
z: 0
}, lineVectors[0]],
lineWidth: 5,
color: this.stringData.currentColor
});
@ -339,7 +338,6 @@
y: 0,
z: 0
}, lineVectors[1]],
lineWidth: 5,
color: this.stringData.currentColor
});

View file

@ -125,7 +125,6 @@ function createPreNotchString() {
y: 0,
z: 0
}, downOffset)],
lineWidth: 5,
color: {
red: 255,
green: 255,

View file

@ -450,7 +450,6 @@
y: 0,
z: 0
}, downOffset)],
lineWidth: 5,
color: {
red: 255,
green: 255,

View file

@ -427,7 +427,6 @@ MasterReset = function() {
y: 0,
z: 0
}, downOffset)],
lineWidth: 5,
color: {
red: 255,
green: 255,

View file

@ -346,8 +346,7 @@
end: { x: 0, y: 0, z: 0 },
color: COLORS.RED,
alpha: 1,
visible: true,
lineWidth: 2
visible: true
});
},
};

View file

@ -266,7 +266,6 @@
dimensions: { "x": 5, "y": 5, "z": 5 },
ignoreForCollisions: 1,
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
lineWidth: 5,
name: STRING_NAME,
parentID: this.entityID,
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
@ -287,7 +286,6 @@
resetStringToIdlePosition: function() {
Entities.editEntity(this.stringID, {
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
lineWidth: 5,
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
});

View file

@ -99,7 +99,6 @@
lifetime: 360,
type: 'Line',
glow: 1.0,
lineWidth: 5,
alpha: 0.5,
ignoreRayIntersection: true,
drawInFront: true,

View file

@ -72,7 +72,6 @@ Laser = function (side) {
}
laserLine = Overlays.addOverlay("line3d", {
lineWidth: 5,
alpha: 1.0,
glow: 1.0,
ignoreRayIntersection: true,

View file

@ -408,7 +408,6 @@ function getControllerLocation(controllerHand) {
dimensions: { "x": 5, "y": 5, "z": 5 },
ignoreForCollisions: 1,
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
lineWidth: 5,
color: { red: 153, green: 102, blue: 51 },
name: STRING_NAME,
parentID: this.entityID,
@ -430,7 +429,6 @@ function getControllerLocation(controllerHand) {
resetStringToIdlePosition: function() {
Entities.editEntity(this.stringID, {
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
lineWidth: 5,
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
});