diff --git a/examples/libraries/overlayManager.js b/examples/libraries/overlayManager.js index ce79214537..49398c5009 100644 --- a/examples/libraries/overlayManager.js +++ b/examples/libraries/overlayManager.js @@ -236,18 +236,10 @@ "dimensions" ]); - ImageOverlay = generateOverlayClass(Overlay2D, "image", [ - "subImage", "imageURL" - ]); - Image3DOverlay = generateOverlayClass(Billboard3DOverlay, "image3d", [ "url", "subImage" ]); - TextOverlay = generateOverlayClass(Overlay2D, "text", [ - "font", "text", "backgroundColor", "backgroundAlpha", "leftMargin", "topMargin" - ]); - Text3DOverlay = generateOverlayClass(Billboard3DOverlay, "text3d", [ "text", "backgroundColor", "backgroundAlpha", "lineHeight", "leftMargin", "topMargin", "rightMargin", "bottomMargin" diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index 7ab68cab1c..6c01580ea6 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -132,14 +132,15 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit this.y = y; this.width = 0; this.height = ToolBar.TITLE_BAR_HEIGHT; - this.back = this.back = Overlays.addOverlay("text", { - backgroundColor: { red: 255, green: 255, blue: 255 }, + this.backAlpha = 1.0; + this.back = Overlays.addOverlay("rectangle", { + color: { red: 255, green: 255, blue: 255 }, x: this.x, y: this.y, + radius: 4, width: this.width, height: this.height, - alpha: 1.0, - backgroundAlpha: 1.0, + alpha: this.backAlpha, visible: false }); this.spacing = []; @@ -246,10 +247,8 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit this.tools[tool].setAlpha(alpha); } if (this.back != null) { - Overlays.editOverlay(this.back, { - alpha: alpha, - backgroundAlpha: alpha - }); + this.backAlpha = alpha; + Overlays.editOverlay(this.back, { alpha: alpha }); } } else { this.tools[tool].setAlpha(alpha); @@ -258,9 +257,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit this.setBack = function(color, alpha) { if (color == null) { - Overlays.editOverlay(this.back, { - visible: false - }); + Overlays.editOverlay(this.back, { visible: false }); } else { Overlays.editOverlay(this.back, { width: this.width + @@ -268,8 +265,8 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit height: this.height + ((direction == ToolBar.VERTICAL) ? 1 : 2) * ToolBar.SPACING, visible: true, - backgroundColor: color, - backgroundAlpha: alpha + color: color, + alpha: alpha }); } } @@ -339,12 +336,9 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit that.hover = function (enable) { // Can be overriden or extended by clients. that.isHovering = enable; if (that.back) { - if (enable) { - that.oldAlpha = Overlays.getProperty(that.back, 'backgroundAlpha'); - } Overlays.editOverlay(this.back, { visible: enable, - backgroundAlpha: enable ? 0.5 : that.oldAlpha + alpha: enable ? 0.5 : that.backAlpha }); } }; diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index d510e7b966..42ff64abc6 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -145,7 +145,7 @@ "id": "rightHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_right.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -157,7 +157,7 @@ "id": "rightHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_right.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_right.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -205,7 +205,7 @@ "id": "leftHandGraspOpen", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_open_left.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_left.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -217,7 +217,7 @@ "id": "leftHandGraspClosed", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/hydra_pose_closed_left.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_left.fbx", "startFrame": 10.0, "endFrame": 10.0, "timeScale": 1.0, @@ -420,7 +420,7 @@ "id": "idleStand", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "startFrame": 0.0, "endFrame": 90.0, "timeScale": 1.0, @@ -432,7 +432,7 @@ "id": "idleTalk", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/talk/talk.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/talk.fbx", "startFrame": 0.0, "endFrame": 801.0, "timeScale": 1.0, @@ -457,7 +457,7 @@ "id": "walkFwdShort", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_fwd.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_fwd.fbx", "startFrame": 0.0, "endFrame": 39.0, "timeScale": 1.0, @@ -469,7 +469,7 @@ "id": "walkFwdNormal", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_fwd.fbx", "startFrame": 0.0, "endFrame": 35.0, "timeScale": 1.0, @@ -481,7 +481,7 @@ "id": "walkFwdRun", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/run_fwd.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/run_fwd.fbx", "startFrame": 0.0, "endFrame": 21.0, "timeScale": 1.0, @@ -495,7 +495,7 @@ "id": "idleToWalkFwd", "type": "clip", "data": { - "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/idle_to_walk.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle_to_walk.fbx", "startFrame": 1.0, "endFrame": 19.0, "timeScale": 1.0, @@ -518,7 +518,7 @@ "id": "walkBwdShort", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_short_bwd.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_bwd.fbx", "startFrame": 0.0, "endFrame": 38.0, "timeScale": 1.0, @@ -530,7 +530,7 @@ "id": "walkBwdNormal", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_bwd.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_bwd.fbx", "startFrame": 0.0, "endFrame": 36.0, "timeScale": 1.0, @@ -544,7 +544,7 @@ "id": "turnLeft", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_left.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_left.fbx", "startFrame": 0.0, "endFrame": 28.0, "timeScale": 1.0, @@ -556,7 +556,7 @@ "id": "turnRight", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/turn_right.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_right.fbx", "startFrame": 0.0, "endFrame": 30.0, "timeScale": 1.0, @@ -579,7 +579,7 @@ "id": "strafeLeftShort", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_left.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_left.fbx", "startFrame": 0.0, "endFrame": 28.0, "timeScale": 1.0, @@ -591,7 +591,7 @@ "id": "strafeLeftNormal", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_left.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_left.fbx", "startFrame": 0.0, "endFrame": 30.0, "timeScale": 1.0, @@ -616,7 +616,7 @@ "id": "strafeRightShort", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_short_right.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_right.fbx", "startFrame": 0.0, "endFrame": 28.0, "timeScale": 1.0, @@ -628,7 +628,7 @@ "id": "strafeRightNormal", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/side_step_right.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_right.fbx", "startFrame": 0.0, "endFrame": 30.0, "timeScale": 1.0, @@ -642,7 +642,7 @@ "id": "awayIntro", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx", "startFrame": 0.0, "endFrame": 83.0, "timeScale": 1.0, @@ -654,7 +654,7 @@ "id": "away", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx", "startFrame": 83.0, "endFrame": 84.0, "timeScale": 1.0, @@ -666,7 +666,7 @@ "id": "awayOutro", "type": "clip", "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/kneel/kneel.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx", "startFrame": 84.0, "endFrame": 167.0, "timeScale": 1.0, @@ -678,7 +678,7 @@ "id": "fly", "type": "clip", "data": { - "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims/fly.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx", "startFrame": 1.0, "endFrame": 80.0, "timeScale": 1.0, @@ -700,7 +700,7 @@ "id": "userAnimA", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "startFrame": 0.0, "endFrame": 90.0, "timeScale": 1.0, @@ -712,7 +712,7 @@ "id": "userAnimB", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/idle.fbx", + "url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx", "startFrame": 0.0, "endFrame": 90.0, "timeScale": 1.0, diff --git a/interface/resources/qml/TextOverlayElement.qml b/interface/resources/qml/TextOverlayElement.qml deleted file mode 100644 index 0d9dd1eacc..0000000000 --- a/interface/resources/qml/TextOverlayElement.qml +++ /dev/null @@ -1,23 +0,0 @@ -import Hifi 1.0 -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -TextOverlayElement { - id: root - Rectangle { - color: root.backgroundColor - anchors.fill: parent - Text { - x: root.leftMargin - y: root.topMargin - id: text - objectName: "textElement" - text: root.text - color: root.textColor - font.family: root.fontFamily - font.pixelSize: root.fontSize - lineHeightMode: Text.FixedHeight - lineHeight: root.lineHeight - } - } -} diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 8c4f73c200..9afae4a3c1 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -25,7 +25,7 @@ FocusScope { readonly property alias zLevels: zLevels QtObject { id: zLevels; - readonly property real normal: 0 + readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls. readonly property real top: 2000 readonly property real modal: 4000 readonly property real menu: 8000 diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml new file mode 100644 index 0000000000..b10b66f07c --- /dev/null +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -0,0 +1,78 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +import "." + +Overlay { + id: root + + Image { + id: image + property bool scaleFix: true; + property real xOffset: 0 + property real yOffset: 0 + property real imageScale: 1.0 + property var resizer: Timer { + interval: 50 + repeat: false + running: false + onTriggered: { + var targetAspect = root.width / root.height; + var sourceAspect = image.sourceSize.width / image.sourceSize.height; + if (sourceAspect <= targetAspect) { + if (root.width === image.sourceSize.width) { + return; + } + image.imageScale = root.width / image.sourceSize.width; + } else if (sourceAspect > targetAspect){ + if (root.height === image.sourceSize.height) { + return; + } + image.imageScale = root.height / image.sourceSize.height; + } + image.sourceSize = Qt.size(image.sourceSize.width * image.imageScale, image.sourceSize.height * image.imageScale); + } + } + x: -1 * xOffset * imageScale + y: -1 * yOffset * imageScale + + onSourceSizeChanged: { + if (sourceSize.width !== 0 && sourceSize.height !== 0 && progress === 1.0 && scaleFix) { + scaleFix = false; + resizer.start(); + } + } + } + + function updateSubImage(subImage) { + var keys = Object.keys(subImage); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var value = subImage[key]; + switch (key) { + case "x": image.xOffset = value; break; + case "y": image.yOffset = value; break; + } + } + } + + function updatePropertiesFromScript(properties) { + var keys = Object.keys(properties); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var value = properties[key]; + switch (key) { + case "height": root.height = value; break; + case "width": root.width = value; break; + case "x": root.x = value; break; + case "y": root.y = value; break; + case "visible": root.visible = value; break; + case "alpha": root.opacity = value; break; + case "imageURL": image.source = value; break; + case "subImage": updateSubImage(value); break; + default: console.log("OVERLAY Unhandled image property " + key); + } + } + } +} + diff --git a/interface/resources/qml/hifi/overlays/Overlay.qml b/interface/resources/qml/hifi/overlays/Overlay.qml new file mode 100644 index 0000000000..80f3233b69 --- /dev/null +++ b/interface/resources/qml/hifi/overlays/Overlay.qml @@ -0,0 +1,30 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +Item { + id: root + clip: true + + property int dumpDepth: 0; + + + function dumpObject(object) { + var keys = Object.keys(object); + var tabsString = ""; + for (var j = 0; j < dumpDepth; ++j) { + tabsString = tabsString + "\t"; + } + + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var value = object[key]; + console.log(tabsString + "OVERLAY Key " + key + " (" + typeof(value) + "): " + value); + if (typeof(value) === "object") { + ++dumpDepth; + dumpObject(value) + --dumpDepth; + } + } + } +} diff --git a/interface/resources/qml/hifi/overlays/RectangleOverlay.qml b/interface/resources/qml/hifi/overlays/RectangleOverlay.qml new file mode 100644 index 0000000000..fc4169103a --- /dev/null +++ b/interface/resources/qml/hifi/overlays/RectangleOverlay.qml @@ -0,0 +1,38 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +import "." + +Overlay { + id: root + + Rectangle { + id: rectangle + anchors.fill: parent + color: "black" + } + + function updatePropertiesFromScript(properties) { + var keys = Object.keys(properties); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var value = properties[key]; + console.log("OVERLAY rectangle property " + key + " set to value " + value); + switch (key) { + case "height": root.height = value; break; + case "width": root.width = value; break; + case "x": root.x = value; break; + case "y": root.y = value; break; + case "visible": root.visible = value; break; + case "alpha": rectangle.color.a = value; break; + case "color": rectangle.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.color.a); break; + case "borderAlpha": rectangle.border.color.a = value; break; + case "borderColor": rectangle.border.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, rectangle.border.color.a); break; + case "borderWidth": rectangle.border.width = value; break; + case "radius": rectangle.radius = value; break; + default: console.log("OVERLAY Unhandled rectangle property " + key); + } + } + } +} + diff --git a/interface/resources/qml/hifi/overlays/TextOverlay.qml b/interface/resources/qml/hifi/overlays/TextOverlay.qml new file mode 100644 index 0000000000..ba5cafdf64 --- /dev/null +++ b/interface/resources/qml/hifi/overlays/TextOverlay.qml @@ -0,0 +1,54 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +import "." + +Overlay { + id: root + clip: true + Rectangle { + id: background; + anchors.fill: parent + color: "#B2000000" + + Text { + id: textField; + anchors { fill: parent; bottomMargin: textField.anchors.topMargin; rightMargin: textField.anchors.leftMargin; } + objectName: "textElement" + color: "white" + lineHeightMode: Text.FixedHeight + font.family: "Helvetica" + font.pixelSize: 18 + lineHeight: 18 + } + } + + + function updatePropertiesFromScript(properties) { + var keys = Object.keys(properties); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var value = properties[key]; + switch (key) { + case "height": root.height = value; break; + case "width": root.width = value; break; + case "x": root.x = value; break; + case "y": root.y = value; break; + case "visible": root.visible = value; break; + case "alpha": textField.color.a = value; break; + case "margin": textField.anchors.margins = value; break; + case "leftMargin": textField.anchors.leftMargin = value; break; + case "topMargin": textField.anchors.topMargin = value; break; + case "color": // fall through + case "textColor": textField.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, textField.color.a); break; + case "text": textField.text = value; break; + case "backgroundAlpha": background.color = Qt.rgba(background.color.r, background.color.g, background.color.b, value); break; + case "backgroundColor": background.color = Qt.rgba(value.red / 255, value.green / 255, value.blue / 255, background.color.a); break; + case "font": textField.font.pixelSize = value.size; break; + case "lineHeight": textField.lineHeight = value; break; + default: + console.log("OVERLAY text unhandled property " + key); + } + } + } +} diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 15da88023b..a57e53b384 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include "AddressManager.h" @@ -83,6 +84,17 @@ int main(int argc, const char* argv[]) { #endif } + // Check OpenGL version. + // This is done separately from the main Application so that start-up and shut-down logic within the main Application is + // not made more complicated than it already is. + { + OpenGLVersionChecker openGLVersionChecker(argc, const_cast(argv)); + if (!openGLVersionChecker.isValidVersion()) { + qCDebug(interfaceapp, "Early exit due to OpenGL version."); + return 0; + } + } + QElapsedTimer startupTime; startupTime.start(); @@ -96,6 +108,7 @@ int main(int argc, const char* argv[]) { usecTimestampNowForceClockSkew(clockSkew); qCDebug(interfaceapp, "clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew); } + // Oculus initialization MUST PRECEDE OpenGL context creation. // The nature of the Application constructor means this has to be either here, // or in the main window ctor, before GL startup. diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 8df62b9675..4077fb0ab5 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -17,159 +17,15 @@ QString const ImageOverlay::TYPE = "image"; +QUrl const ImageOverlay::URL(QString("hifi/overlays/ImageOverlay.qml")); -ImageOverlay::ImageOverlay() : - _imageURL(), - _renderImage(false), - _wantClipFromImage(false) -{ -} +ImageOverlay::ImageOverlay() + : QmlOverlay(URL) { } ImageOverlay::ImageOverlay(const ImageOverlay* imageOverlay) : - Overlay2D(imageOverlay), - _imageURL(imageOverlay->_imageURL), - _textureImage(imageOverlay->_textureImage), - _texture(imageOverlay->_texture), - _fromImage(imageOverlay->_fromImage), - _renderImage(imageOverlay->_renderImage), - _wantClipFromImage(imageOverlay->_wantClipFromImage) -{ -} + QmlOverlay(URL, imageOverlay) { } -// TODO: handle setting image multiple times, how do we manage releasing the bound texture? -void ImageOverlay::setImageURL(const QUrl& url) { - _imageURL = url; - if (url.isEmpty()) { - _isLoaded = true; - _renderImage = false; - _texture.clear(); - } else { - _isLoaded = false; - _renderImage = true; - } -} - -void ImageOverlay::render(RenderArgs* args) { - if (!_isLoaded && _renderImage) { - _isLoaded = true; - _texture = DependencyManager::get()->getTexture(_imageURL); - } - // If we are not visible or loaded, return. If we are trying to render an - // image but the texture hasn't loaded, return. - if (!_visible || !_isLoaded || (_renderImage && !_texture->isLoaded())) { - return; - } - - auto geometryCache = DependencyManager::get(); - gpu::Batch& batch = *args->_batch; - geometryCache->useSimpleDrawPipeline(batch); - if (_renderImage) { - batch.setResourceTexture(0, _texture->getGPUTexture()); - } else { - batch.setResourceTexture(0, args->_whiteTexture); - } - - const float MAX_COLOR = 255.0f; - xColor color = getColor(); - float alpha = getAlpha(); - glm::vec4 quadColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); - - int left = _bounds.left(); - int right = _bounds.right() + 1; - int top = _bounds.top(); - int bottom = _bounds.bottom() + 1; - - glm::vec2 topLeft(left, top); - glm::vec2 bottomRight(right, bottom); - - batch.setModelTransform(Transform()); - - // if for some reason our image is not over 0 width or height, don't attempt to render the image - if (_renderImage) { - float imageWidth = _texture->getWidth(); - float imageHeight = _texture->getHeight(); - if (imageWidth > 0 && imageHeight > 0) { - QRect fromImage; - if (_wantClipFromImage) { - float scaleX = imageWidth / _texture->getOriginalWidth(); - float scaleY = imageHeight / _texture->getOriginalHeight(); - - fromImage.setX(scaleX * _fromImage.x()); - fromImage.setY(scaleY * _fromImage.y()); - fromImage.setWidth(scaleX * _fromImage.width()); - fromImage.setHeight(scaleY * _fromImage.height()); - } - else { - fromImage.setX(0); - fromImage.setY(0); - fromImage.setWidth(imageWidth); - fromImage.setHeight(imageHeight); - } - - float x = fromImage.x() / imageWidth; - float y = fromImage.y() / imageHeight; - float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure - float h = fromImage.height() / imageHeight; - - glm::vec2 texCoordTopLeft(x, y); - glm::vec2 texCoordBottomRight(x + w, y + h); - glm::vec4 texcoordRect(texCoordTopLeft, w, h); - - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); - } else { - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); - } - } else { - DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); - } -} - -void ImageOverlay::setProperties(const QScriptValue& properties) { - Overlay2D::setProperties(properties); - - QScriptValue subImageBounds = properties.property("subImage"); - if (subImageBounds.isValid()) { - QRect oldSubImageRect = _fromImage; - QRect subImageRect = _fromImage; - if (subImageBounds.property("x").isValid()) { - subImageRect.setX(subImageBounds.property("x").toVariant().toInt()); - } else { - subImageRect.setX(oldSubImageRect.x()); - } - if (subImageBounds.property("y").isValid()) { - subImageRect.setY(subImageBounds.property("y").toVariant().toInt()); - } else { - subImageRect.setY(oldSubImageRect.y()); - } - if (subImageBounds.property("width").isValid()) { - subImageRect.setWidth(subImageBounds.property("width").toVariant().toInt()); - } else { - subImageRect.setWidth(oldSubImageRect.width()); - } - if (subImageBounds.property("height").isValid()) { - subImageRect.setHeight(subImageBounds.property("height").toVariant().toInt()); - } else { - subImageRect.setHeight(oldSubImageRect.height()); - } - setClipFromSource(subImageRect); - } - - QScriptValue imageURL = properties.property("imageURL"); - if (imageURL.isValid()) { - setImageURL(imageURL.toVariant().toString()); - } -} - -QScriptValue ImageOverlay::getProperty(const QString& property) { - if (property == "subImage") { - return qRectToScriptValue(_scriptEngine, _fromImage); - } - if (property == "imageURL") { - return _imageURL.toString(); - } - - return Overlay2D::getProperty(property); -} ImageOverlay* ImageOverlay::createClone() const { return new ImageOverlay(this); } + diff --git a/interface/src/ui/overlays/ImageOverlay.h b/interface/src/ui/overlays/ImageOverlay.h index 5698a73732..224cb42045 100644 --- a/interface/src/ui/overlays/ImageOverlay.h +++ b/interface/src/ui/overlays/ImageOverlay.h @@ -11,48 +11,22 @@ #ifndef hifi_ImageOverlay_h #define hifi_ImageOverlay_h -// include this before QGLWidget, which includes an earlier version of OpenGL -#include -#include #include -#include +#include "QmlOverlay.h" -#include "Overlay2D.h" - -class ImageOverlay : public Overlay2D { +class ImageOverlay : public QmlOverlay { Q_OBJECT public: static QString const TYPE; virtual QString getType() const { return TYPE; } + static QUrl const URL; ImageOverlay(); ImageOverlay(const ImageOverlay* imageOverlay); - virtual void render(RenderArgs* args); - - // getters - const QRect& getClipFromSource() const { return _fromImage; } - const QUrl& getImageURL() const { return _imageURL; } - - // setters - void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; } - void setImageURL(const QUrl& url); - virtual void setProperties(const QScriptValue& properties); - virtual QScriptValue getProperty(const QString& property); - - virtual ImageOverlay* createClone() const; - -private: - - QUrl _imageURL; - QImage _textureImage; - - NetworkTexturePointer _texture; - QRect _fromImage; // where from in the image to sample - bool _renderImage; // is there an image associated with this overlay, or is it just a colored rectangle - bool _wantClipFromImage; + virtual ImageOverlay* createClone() const override; }; diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 9a19c71db6..4d3b5ae36f 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -39,6 +39,7 @@ public: virtual void render(RenderArgs* args) = 0; virtual AABox getBounds() const = 0; + virtual bool supportsGetProperty() const { return true; } virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index f6e6851c38..10298b8f15 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -30,6 +30,7 @@ #include "Sphere3DOverlay.h" #include "Grid3DOverlay.h" #include "TextOverlay.h" +#include "RectangleOverlay.h" #include "Text3DOverlay.h" #include "Web3DOverlay.h" #include @@ -175,6 +176,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope thisOverlay = std::make_shared(); } else if (type == Web3DOverlay::TYPE) { thisOverlay = std::make_shared(); + } else if (type == RectangleOverlay::TYPE) { + thisOverlay = std::make_shared(); } if (thisOverlay) { @@ -373,7 +376,7 @@ OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& prop OverlayPropertyResult result; Overlay::Pointer thisOverlay = getOverlay(id); QReadLocker lock(&_lock); - if (thisOverlay) { + if (thisOverlay && thisOverlay->supportsGetProperty()) { result.value = thisOverlay->getProperty(property); } return result; diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp new file mode 100644 index 0000000000..e141d38f2b --- /dev/null +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -0,0 +1,74 @@ +// +// Created by Bradley Austin Davis on 2016/01/27 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QmlOverlay.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.h" +#include "text/FontFamilies.h" + +QmlOverlay::QmlOverlay(const QUrl& url) { + buildQmlElement(url); +} + +QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay) + : Overlay2D(textOverlay) { + buildQmlElement(url); +} + +void QmlOverlay::buildQmlElement(const QUrl& url) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->returnFromUiThread([=] { + offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { + _qmlElement = dynamic_cast(object); + }); + while (!_qmlElement) { + qApp->processEvents(); + } + return QVariant(); + }); +} + +QmlOverlay::~QmlOverlay() { + if (_qmlElement) { + _qmlElement->deleteLater(); + _qmlElement = nullptr; + } +} + +void QmlOverlay::setProperties(const QScriptValue& properties) { + Overlay2D::setProperties(properties); + auto bounds = _bounds; + DependencyManager::get()->executeOnUiThread([=] { + _qmlElement->setX(bounds.left()); + _qmlElement->setY(bounds.top()); + _qmlElement->setWidth(bounds.width()); + _qmlElement->setHeight(bounds.height()); + }); + QMetaObject::invokeMethod(_qmlElement, "updatePropertiesFromScript", Q_ARG(QVariant, properties.toVariant())); +} + +void QmlOverlay::render(RenderArgs* args) { + if (!_qmlElement) { + return; + } + + if (_visible != _qmlElement->isVisible()) { + _qmlElement->setVisible(_visible); + } +} diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h new file mode 100644 index 0000000000..75f1a391a3 --- /dev/null +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -0,0 +1,41 @@ +// +// Created by Bradley Austin Davis on 2016/01/27 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_QmlOverlay_h +#define hifi_QmlOverlay_h + +#include + +#include +#include "Overlay2D.h" + +class QQuickItem; + +class QmlOverlay : public Overlay2D { + Q_OBJECT + +public: + QmlOverlay(const QUrl& url); + QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay); + ~QmlOverlay(); + + // Cannot fetch properties from QML based overlays due to race conditions + bool supportsGetProperty() const override { return false; } + + void setProperties(const QScriptValue& properties) override; + void render(RenderArgs* args) override; + +private: + void buildQmlElement(const QUrl& url); + +protected: + QQuickItem* _qmlElement{ nullptr }; +}; + + +#endif // hifi_QmlOverlay_h diff --git a/interface/src/ui/overlays/RectangleOverlay.cpp b/interface/src/ui/overlays/RectangleOverlay.cpp new file mode 100644 index 0000000000..1487a4cb63 --- /dev/null +++ b/interface/src/ui/overlays/RectangleOverlay.cpp @@ -0,0 +1,21 @@ +// +// Created by Bradley Austin Davis on 2016/01/27 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RectangleOverlay.h" + +QString const RectangleOverlay::TYPE = "rectangle"; +QUrl const RectangleOverlay::URL(QString("hifi/overlays/RectangleOverlay.qml")); + +RectangleOverlay::RectangleOverlay() : QmlOverlay(URL) {} + +RectangleOverlay::RectangleOverlay(const RectangleOverlay* rectangleOverlay) + : QmlOverlay(URL, rectangleOverlay) { } + +RectangleOverlay* RectangleOverlay::createClone() const { + return new RectangleOverlay(this); +} diff --git a/interface/src/ui/overlays/RectangleOverlay.h b/interface/src/ui/overlays/RectangleOverlay.h new file mode 100644 index 0000000000..06e2fb228c --- /dev/null +++ b/interface/src/ui/overlays/RectangleOverlay.h @@ -0,0 +1,27 @@ +// +// Created by Bradley Austin Davis on 2016/01/27 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_RectangleOverlay_h +#define hifi_RectangleOverlay_h + +#include "QmlOverlay.h" + +class RectangleOverlay : public QmlOverlay { +public: + static QString const TYPE; + virtual QString getType() const { return TYPE; } + static QUrl const URL; + + RectangleOverlay(); + RectangleOverlay(const RectangleOverlay* RectangleOverlay); + + virtual RectangleOverlay* createClone() const; +}; + + +#endif // hifi_RectangleOverlay_h diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 6926e9b241..762d855a11 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -24,216 +24,21 @@ #include "Application.h" #include "text/FontFamilies.h" -#define TEXT_OVERLAY_PROPERTY(type, name, initialValue) \ - Q_PROPERTY(type name READ name WRITE set##name NOTIFY name##Changed) \ -public: \ - type name() { return _##name; }; \ - void set##name(const type& name) { \ - if (name != _##name) { \ - _##name = name; \ - emit name##Changed(); \ - } \ - } \ -private: \ - type _##name{ initialValue }; - - -class TextOverlayElement : public QQuickItem { - Q_OBJECT - HIFI_QML_DECL -private: - TEXT_OVERLAY_PROPERTY(QString, text, "") - TEXT_OVERLAY_PROPERTY(QString, fontFamily, SANS_FONT_FAMILY) - TEXT_OVERLAY_PROPERTY(QString, textColor, "#ffffffff") - TEXT_OVERLAY_PROPERTY(QString, backgroundColor, "#B2000000") - TEXT_OVERLAY_PROPERTY(qreal, fontSize, 18) - TEXT_OVERLAY_PROPERTY(qreal, lineHeight, 18) - TEXT_OVERLAY_PROPERTY(qreal, leftMargin, 0) - TEXT_OVERLAY_PROPERTY(qreal, topMargin, 0) - -public: - TextOverlayElement(QQuickItem* parent = nullptr) : QQuickItem(parent) { - } - -signals: - void textChanged(); - void fontFamilyChanged(); - void fontSizeChanged(); - void lineHeightChanged(); - void leftMarginChanged(); - void topMarginChanged(); - void textColorChanged(); - void backgroundColorChanged(); -}; - -HIFI_QML_DEF(TextOverlayElement) - -QString toQmlColor(const glm::vec4& v) { - QString templat("#%1%2%3%4"); - return templat. - arg((int)(v.a * 255), 2, 16, QChar('0')). - arg((int)(v.r * 255), 2, 16, QChar('0')). - arg((int)(v.g * 255), 2, 16, QChar('0')). - arg((int)(v.b * 255), 2, 16, QChar('0')); -} - QString const TextOverlay::TYPE = "text"; +QUrl const TextOverlay::URL(QString("hifi/overlays/TextOverlay.qml")); -TextOverlay::TextOverlay() : - _backgroundColor(DEFAULT_BACKGROUND_COLOR), - _backgroundAlpha(DEFAULT_BACKGROUND_ALPHA), - _leftMargin(DEFAULT_MARGIN), - _topMargin(DEFAULT_MARGIN), - _fontSize(DEFAULT_FONTSIZE) -{ - qApp->postLambdaEvent([=] { - static std::once_flag once; - std::call_once(once, [] { - TextOverlayElement::registerType(); - }); - auto offscreenUi = DependencyManager::get(); - TextOverlayElement::show([=](QQmlContext* context, QObject* object) { - _qmlElement = static_cast(object); - }); - }); - while (!_qmlElement) { - QThread::msleep(1); - } +TextOverlay::TextOverlay() : QmlOverlay(URL) { } + +TextOverlay::TextOverlay(const TextOverlay* textOverlay) + : QmlOverlay(URL, textOverlay) { } -TextOverlay::TextOverlay(const TextOverlay* textOverlay) : - Overlay2D(textOverlay), - _text(textOverlay->_text), - _backgroundColor(textOverlay->_backgroundColor), - _backgroundAlpha(textOverlay->_backgroundAlpha), - _leftMargin(textOverlay->_leftMargin), - _topMargin(textOverlay->_topMargin), - _fontSize(textOverlay->_fontSize) -{ - qApp->postLambdaEvent([=] { - auto offscreenUi = DependencyManager::get(); - TextOverlayElement::show([this](QQmlContext* context, QObject* object) { - _qmlElement = static_cast(object); - }); - }); - while (!_qmlElement) { - QThread::msleep(1); - } -} - -TextOverlay::~TextOverlay() { - if (_qmlElement) { - _qmlElement->deleteLater(); - } -} - -xColor TextOverlay::getBackgroundColor() { - if (_colorPulse == 0.0f) { - return _backgroundColor; - } - - float pulseLevel = updatePulse(); - xColor result = _backgroundColor; - if (_colorPulse < 0.0f) { - result.red *= (1.0f - pulseLevel); - result.green *= (1.0f - pulseLevel); - result.blue *= (1.0f - pulseLevel); - } else { - result.red *= pulseLevel; - result.green *= pulseLevel; - result.blue *= pulseLevel; - } - return result; -} - -void TextOverlay::render(RenderArgs* args) { - if (!_qmlElement) { - return; - } - if (_visible != _qmlElement->isVisible()) { - _qmlElement->setVisible(_visible); - } -} - - -void TextOverlay::setProperties(const QScriptValue& properties) { - Overlay2D::setProperties(properties); - _qmlElement->setX(_bounds.left()); - _qmlElement->setY(_bounds.top()); - _qmlElement->setWidth(_bounds.width()); - _qmlElement->setHeight(_bounds.height()); - _qmlElement->settextColor(toQmlColor(vec4(toGlm(_color), _alpha))); - QScriptValue font = properties.property("font"); - if (font.isObject()) { - if (font.property("size").isValid()) { - setFontSize(font.property("size").toInt32()); - } - QFont font(_qmlElement->fontFamily()); - font.setPixelSize(_qmlElement->fontSize()); - QFontMetrics fm(font); - _qmlElement->setlineHeight(fm.lineSpacing() * 1.2); - } - - QScriptValue text = properties.property("text"); - if (text.isValid()) { - setText(text.toVariant().toString()); - } - - QScriptValue backgroundColor = properties.property("backgroundColor"); - if (backgroundColor.isValid()) { - QScriptValue red = backgroundColor.property("red"); - QScriptValue green = backgroundColor.property("green"); - QScriptValue blue = backgroundColor.property("blue"); - if (red.isValid() && green.isValid() && blue.isValid()) { - _backgroundColor.red = red.toVariant().toInt(); - _backgroundColor.green = green.toVariant().toInt(); - _backgroundColor.blue = blue.toVariant().toInt(); - } - } - - if (properties.property("backgroundAlpha").isValid()) { - _backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat(); - } - _qmlElement->setbackgroundColor(toQmlColor(vec4(toGlm(_backgroundColor), _backgroundAlpha))); - - if (properties.property("leftMargin").isValid()) { - setLeftMargin(properties.property("leftMargin").toVariant().toInt()); - } - - if (properties.property("topMargin").isValid()) { - setTopMargin(properties.property("topMargin").toVariant().toInt()); - } -} +TextOverlay::~TextOverlay() { } TextOverlay* TextOverlay::createClone() const { return new TextOverlay(this); } -QScriptValue TextOverlay::getProperty(const QString& property) { - if (property == "font") { - QScriptValue font = _scriptEngine->newObject(); - font.setProperty("size", _fontSize); - return font; - } - if (property == "text") { - return _text; - } - if (property == "backgroundColor") { - return xColorToScriptValue(_scriptEngine, _backgroundColor); - } - if (property == "backgroundAlpha") { - return _backgroundAlpha; - } - if (property == "leftMargin") { - return _leftMargin; - } - if (property == "topMargin") { - return _topMargin; - } - - return Overlay2D::getProperty(property); -} - QSizeF TextOverlay::textSize(const QString& text) const { int lines = 1; foreach(QChar c, text) { @@ -241,31 +46,15 @@ QSizeF TextOverlay::textSize(const QString& text) const { ++lines; } } - QFont font(_qmlElement->fontFamily()); - font.setPixelSize(_qmlElement->fontSize()); + QFont font(SANS_FONT_FAMILY); + font.setPixelSize(18); QFontMetrics fm(font); - QSizeF result = QSizeF(fm.width(text), _qmlElement->lineHeight() * lines); + QSizeF result = QSizeF(fm.width(text), 18 * lines); return result; } -void TextOverlay::setFontSize(int fontSize) { - _fontSize = fontSize; - _qmlElement->setfontSize(fontSize); -} -void TextOverlay::setText(const QString& text) { - _text = text; - _qmlElement->settext(text); -} - -void TextOverlay::setLeftMargin(int margin) { - _leftMargin = margin; - _qmlElement->setleftMargin(margin); -} - -void TextOverlay::setTopMargin(int margin) { - _topMargin = margin; - _qmlElement->settopMargin(margin); -} - -#include "TextOverlay.moc" +void TextOverlay::setTopMargin(float margin) {} +void TextOverlay::setLeftMargin(float margin) {} +void TextOverlay::setFontSize(float size) {} +void TextOverlay::setText(const QString& text) {} diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index a8e6967871..7c6e133ebd 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -11,59 +11,27 @@ #ifndef hifi_TextOverlay_h #define hifi_TextOverlay_h -#include +#include "QmlOverlay.h" -#include - -#include "Overlay2D.h" - -const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; -const float DEFAULT_BACKGROUND_ALPHA = 0.7f; -const int DEFAULT_MARGIN = 10; -const int DEFAULT_FONTSIZE = 12; -const int DEFAULT_FONT_WEIGHT = 50; - -class TextOverlayElement; - -class TextOverlay : public Overlay2D { - Q_OBJECT - +class TextOverlay : public QmlOverlay { public: static QString const TYPE; - virtual QString getType() const { return TYPE; } + QString getType() const override { return TYPE; } + static QUrl const URL; + TextOverlay(); TextOverlay(const TextOverlay* textOverlay); ~TextOverlay(); - virtual void render(RenderArgs* args); - // getters - const QString& getText() const { return _text; } - int getLeftMargin() const { return _leftMargin; } - int getTopMargin() const { return _topMargin; } - xColor getBackgroundColor(); - float getBackgroundAlpha() const { return _backgroundAlpha; } - - // setters + void setTopMargin(float margin); + void setLeftMargin(float margin); + void setFontSize(float size); void setText(const QString& text); - void setLeftMargin(int margin); - void setTopMargin(int margin); - void setFontSize(int fontSize); - virtual void setProperties(const QScriptValue& properties); - virtual TextOverlay* createClone() const; - virtual QScriptValue getProperty(const QString& property); + TextOverlay* createClone() const; QSizeF textSize(const QString& text) const; // Pixels - -private: - TextOverlayElement* _qmlElement{ nullptr }; - QString _text; - xColor _backgroundColor; - float _backgroundAlpha; - int _leftMargin; - int _topMargin; - int _fontSize; }; diff --git a/libraries/gl/src/gl/Config.h b/libraries/gl/src/gl/Config.h index fe693d8c65..2e42e85122 100644 --- a/libraries/gl/src/gl/Config.h +++ b/libraries/gl/src/gl/Config.h @@ -19,6 +19,7 @@ #define GPU_LEGACY 0 #define GPU_CORE_41 410 #define GPU_CORE_43 430 +#define GPU_CORE_MINIMUM GPU_CORE_41 #if defined(__APPLE__) diff --git a/libraries/gl/src/gl/OpenGLVersionChecker.cpp b/libraries/gl/src/gl/OpenGLVersionChecker.cpp new file mode 100644 index 0000000000..761c27a302 --- /dev/null +++ b/libraries/gl/src/gl/OpenGLVersionChecker.cpp @@ -0,0 +1,61 @@ +// +// OpenGLVersionChecker.cpp +// libraries/gl/src/gl +// +// Created by David Rowe on 28 Jan 2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "OpenGLVersionChecker.h" + +#include +#include + +#include "Config.h" +#include "GLWidget.h" + +OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) : + QApplication(argc, argv) +{ +} + +bool OpenGLVersionChecker::isValidVersion() { + bool valid = true; + + // Retrieve OpenGL version + GLWidget* glWidget = new GLWidget(); + glWidget->initializeGL(); + QString glVersion = QString((const char*)glGetString(GL_VERSION)); + delete glWidget; + + // Compare against minimum + // The GL_VERSION string begins with a version number in one of these forms: + // - major_number.minor_number + // - major_number.minor_number.release_number + // Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml + QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); + int majorNumber = versionParts[0].toInt(); + int minorNumber = versionParts[1].toInt(); + int minimumMajorNumber = GPU_CORE_MINIMUM / 100; + int minimumMinorNumber = (GPU_CORE_MINIMUM - minimumMajorNumber * 100) / 10; + valid = (majorNumber > minimumMajorNumber + || (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber)); + + // Prompt user if below minimum + if (!valid) { + QMessageBox messageBox; + messageBox.setWindowTitle("OpenGL Version Too Low"); + messageBox.setIcon(QMessageBox::Warning); + messageBox.setText(QString().sprintf("Your OpenGL version of %i.%i is lower than the minimum of %i.%i.", + majorNumber, minorNumber, minimumMajorNumber, minimumMinorNumber)); + messageBox.setInformativeText("Press OK to exit; Ignore to continue."); + messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Ignore); + messageBox.setDefaultButton(QMessageBox::Ok); + valid = messageBox.exec() == QMessageBox::Ignore; + } + + return valid; +} diff --git a/libraries/gl/src/gl/OpenGLVersionChecker.h b/libraries/gl/src/gl/OpenGLVersionChecker.h new file mode 100644 index 0000000000..3e16c3a32d --- /dev/null +++ b/libraries/gl/src/gl/OpenGLVersionChecker.h @@ -0,0 +1,25 @@ +// +// OpenGLVersionChecker.h +// libraries/gl/src/gl +// +// Created by David Rowe on 28 Jan 2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_OpenGLVersionChecker_h +#define hifi_OpenGLVersionChecker_h + +#include + +class OpenGLVersionChecker : public QApplication { + +public: + OpenGLVersionChecker(int& argc, char** argv); + + static bool isValidVersion(); +}; + +#endif // hifi_OpenGLVersionChecker_h diff --git a/tests/ui/qmlscratch.pro b/tests/ui/qmlscratch.pro index a4e4b33957..d063e673fd 100644 --- a/tests/ui/qmlscratch.pro +++ b/tests/ui/qmlscratch.pro @@ -27,5 +27,6 @@ DISTFILES += \ ../../interface/resources/qml/windows/*.qml \ ../../interface/resources/qml/hifi/*.qml \ ../../interface/resources/qml/hifi/dialogs/*.qml \ - ../../interface/resources/qml/hifi/dialogs/preferences/*.qml + ../../interface/resources/qml/hifi/dialogs/preferences/*.qml \ + ../../interface/resources/qml/hifi/overlays/*.qml