From 3e109ee770c19fa4151f55aa6093adcd804360b0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 6 Nov 2014 14:57:04 -0800 Subject: [PATCH 01/13] Add WebWindow widget for scripts --- interface/src/Application.cpp | 3 ++ interface/src/scripting/WebWindow.cpp | 68 +++++++++++++++++++++++++++ interface/src/scripting/WebWindow.h | 53 +++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 interface/src/scripting/WebWindow.cpp create mode 100644 interface/src/scripting/WebWindow.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b773231b0f..98be839e25 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -91,6 +91,7 @@ #include "scripting/MenuScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" +#include "scripting/WebWindow.h" #include "ui/DataWebDialog.h" #include "ui/InfoView.h" @@ -3871,6 +3872,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri // register `location` on the global object. scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); + + scriptEngine->registerFunction("WebWindow", WebWindow::constructor, 1); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); diff --git a/interface/src/scripting/WebWindow.cpp b/interface/src/scripting/WebWindow.cpp new file mode 100644 index 0000000000..dfd3104f4b --- /dev/null +++ b/interface/src/scripting/WebWindow.cpp @@ -0,0 +1,68 @@ +// +// WebWindow.cpp +// interface/src/scripting +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include + +#include "WindowScriptingInterface.h" +#include "WebWindow.h" + +ScriptEventBridge::ScriptEventBridge(QObject* parent) : QObject(parent) { +} + +void ScriptEventBridge::emitWebEvent(const QString& data) { + emit webEventReceived(data); +} + +void ScriptEventBridge::emitScriptEvent(const QString& data) { + emit scriptEventReceived(data); +} + +WebWindow::WebWindow(const QString& url, int width, int height) + : QObject(NULL), + _window(new QWidget(NULL, Qt::Tool)), + _eventBridge(new ScriptEventBridge(this)) { + + QWebView* webView = new QWebView(_window); + webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); + webView->setUrl(url); + QVBoxLayout* layout = new QVBoxLayout(_window); + _window->setLayout(layout); + layout->addWidget(webView); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + _window->setGeometry(0, 0, width, height); + + connect(this, &WebWindow::destroyed, _window, &QWidget::deleteLater); +} + +WebWindow::~WebWindow() { +} + +void WebWindow::setVisible(bool visible) { + QMetaObject::invokeMethod(_window, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); +} + +QScriptValue WebWindow::constructor(QScriptContext* context, QScriptEngine* engine) { + WebWindow* retVal; + QString file = context->argument(0).toString(); + QMetaObject::invokeMethod(WindowScriptingInterface::getInstance(), "doCreateWebWindow", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(WebWindow*, retVal), + Q_ARG(const QString&, file), + Q_ARG(int, context->argument(1).toInteger()), + Q_ARG(int, context->argument(2).toInteger())); + + connect(engine, &QScriptEngine::destroyed, retVal, &WebWindow::deleteLater); + + return engine->newQObject(retVal);//, QScriptEngine::ScriptOwnership); +} diff --git a/interface/src/scripting/WebWindow.h b/interface/src/scripting/WebWindow.h new file mode 100644 index 0000000000..698e43fd6c --- /dev/null +++ b/interface/src/scripting/WebWindow.h @@ -0,0 +1,53 @@ +// +// WebWindow.h +// interface/src/scripting +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_WebWindow_h +#define hifi_WebWindow_h + +#include +#include + +// #include "ScriptWebView.h" + +class ScriptEventBridge : public QObject { + Q_OBJECT +public: + ScriptEventBridge(QObject* parent = NULL); + +public slots: + void emitWebEvent(const QString& data); + void emitScriptEvent(const QString& data); + +signals: + void webEventReceived(const QString& data); + void scriptEventReceived(const QString& data); + +}; + +class WebWindow : public QObject { + Q_OBJECT + Q_PROPERTY(QObject* eventBridge READ getEventBridge) +public: + WebWindow(const QString& url, int width, int height); + ~WebWindow(); + + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + +public slots: + void setVisible(bool visible); + ScriptEventBridge* getEventBridge() const { return _eventBridge; } + +private: + QWidget* _window; + ScriptEventBridge* _eventBridge; +}; + +#endif From feaf5678bbaeb499ed4ae21bf9889c4df2fbd1f4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 6 Nov 2014 15:00:39 -0800 Subject: [PATCH 02/13] Add grid tools to entity edit tools --- examples/libraries/entitySelectionTool.js | 73 +++-- examples/libraries/gridTool.js | 266 +++++++++++++++++++ examples/newEditEntities.js | 27 +- gridControls.html | 206 ++++++++++++++ libraries/script-engine/src/ScriptEngine.cpp | 5 + libraries/script-engine/src/ScriptEngine.h | 1 + 6 files changed, 543 insertions(+), 35 deletions(-) create mode 100644 examples/libraries/gridTool.js create mode 100644 gridControls.html diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 29bf1bdd79..980689d625 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -394,8 +394,7 @@ SelectionDisplay = (function () { var baseOverlayAngles = { x: 0, y: 0, z: 0 }; var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles); var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, + position: { x: 1, y: 0, z: 0}, color: { red: 51, green: 152, blue: 203 }, alpha: 0.5, solid: true, @@ -570,6 +569,7 @@ SelectionDisplay = (function () { xRailOverlay, yRailOverlay, zRailOverlay, + baseOfEntityProjectionOverlay, ].concat(stretchHandles); overlayNames[highlightBox] = "highlightBox"; @@ -878,20 +878,24 @@ SelectionDisplay = (function () { translateHandlesVisible = false; } - var rotation = SelectionManager.worldRotation; - var dimensions = SelectionManager.worldDimensions; - var position = SelectionManager.worldPosition; + var rotation = selectionManager.worldRotation; + var dimensions = selectionManager.worldDimensions; + var position = selectionManager.worldPosition; Overlays.editOverlay(baseOfEntityProjectionOverlay, { - visible: true, - solid:true, - lineWidth: 2.0, - position: { x: position.x, - y: 0, - z: position.z }, - - dimensions: { x: dimensions.x, y: 0, z: dimensions.z }, + visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL", + solid: true, + // lineWidth: 2.0, + position: { + x: position.x, + y: grid.getOrigin().y, + z: position.z + }, + dimensions: { + x: dimensions.x, + y: dimensions.z + }, rotation: rotation, }); @@ -1098,6 +1102,7 @@ SelectionDisplay = (function () { var initialXZPick = null; var isConstrained = false; + var constrainMajorOnly = false; var startPosition = null; var duplicatedEntityIDs = null; var translateXZTool = { @@ -1143,34 +1148,46 @@ SelectionDisplay = (function () { // If shifted, constrain to one axis if (event.isShifted) { - if (Math.abs(vector.x) > Math.abs(vector.z)) { - vector.z = 0; - } else { - vector.x = 0; - } + // if (Math.abs(vector.x) > Math.abs(vector.z)) { + // vector.z = 0; + // } else { + // vector.x = 0; + // } if (!isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: true }); - var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); - var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); - var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); - var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); - Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); - Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); + // Overlays.editOverlay(xRailOverlay, { visible: true }); + // var xStart = Vec3.sum(startPosition, { x: -10000, y: 0, z: 0 }); + // var xEnd = Vec3.sum(startPosition, { x: 10000, y: 0, z: 0 }); + // var zStart = Vec3.sum(startPosition, { x: 0, y: 0, z: -10000 }); + // var zEnd = Vec3.sum(startPosition, { x: 0, y: 0, z: 10000 }); + // Overlays.editOverlay(xRailOverlay, { start: xStart, end: xEnd, visible: true }); + // Overlays.editOverlay(zRailOverlay, { start: zStart, end: zEnd, visible: true }); isConstrained = true; } + // constrainMajorOnly = event.isControl; + // vector = Vec3.subtract( + // grid.snapToGrid(Vec3.sum(startPosition, vector), constrainMajorOnly), + // startPosition); } else { if (isConstrained) { - Overlays.editOverlay(xRailOverlay, { visible: false }); - Overlays.editOverlay(zRailOverlay, { visible: false }); + // Overlays.editOverlay(xRailOverlay, { visible: false }); + // Overlays.editOverlay(zRailOverlay, { visible: false }); + isConstrained = false; } } + constrainMajorOnly = event.isControl; + var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, selectionManager.worldDimensions)); + vector = Vec3.subtract( + grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), + cornerPosition); + var wantDebug = false; for (var i = 0; i < SelectionManager.selections.length; i++) { var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id]; + var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z }); Entities.editEntity(SelectionManager.selections[i], { - position: Vec3.sum(properties.position, vector), + position: newPosition, }); if (wantDebug) { diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js new file mode 100644 index 0000000000..76c0581b2c --- /dev/null +++ b/examples/libraries/gridTool.js @@ -0,0 +1,266 @@ +Grid = function(opts) { + var that = {}; + + var color = { red: 100, green: 152, blue: 203 }; + var gridColor = { red: 100, green: 152, blue: 203 }; + var gridAlpha = 0.9; + var origin = { x: 0, y: 0, z: 0 }; + var majorGridEvery = 5; + var minorGridSpacing = 0.2; + var halfSize = 40; + var yOffset = 0.001; + + var worldSize = 16384; + + var minorGridWidth = 0.5; + var majorGridWidth = 1.5; + + var gridOverlays = []; + + var snapToGrid = true; + + var gridPlane = Overlays.addOverlay("rectangle3d", { + position: origin, + color: color, + size: halfSize * 2 * minorGridSpacing * 1.05, + alpha: 0.2, + solid: true, + visible: false, + ignoreRayIntersection: true, + }); + + that.getMinorIncrement = function() { return minorGridSpacing; }; + that.getMajorIncrement = function() { return minorGridSpacing * majorGridEvery; }; + + that.visible = false; + + that.getOrigin = function() { + return origin; + } + + that.getSnapToGrid = function() { return snapToGrid; }; + + that.setVisible = function(visible, noUpdate) { + that.visible = visible; + updateGrid(); + // for (var i = 0; i < gridOverlays.length; i++) { + // Overlays.editOverlay(gridOverlays[i], { visible: visible }); + // } + // Overlays.editOverlay(gridPlane, { visible: visible }); + + if (!noUpdate) { + that.emitUpdate(); + } + } + + that.snapToGrid = function(position, majorOnly) { + if (!snapToGrid) { + return position; + } + + var spacing = majorOnly ? (minorGridSpacing * majorGridEvery) : minorGridSpacing; + + position = Vec3.subtract(position, origin); + + position.x = Math.round(position.x / spacing) * spacing; + position.y = Math.round(position.y / spacing) * spacing; + position.z = Math.round(position.z / spacing) * spacing; + + return Vec3.sum(position, origin); + } + + that.setPosition = function(newPosition, noUpdate) { + origin = Vec3.subtract(newPosition, { x: 0, y: yOffset, z: 0 }); + updateGrid(); + + print("updated grid"); + if (!noUpdate) { + that.emitUpdate(); + } + }; + + that.emitUpdate = function() { + if (that.onUpdate) { + that.onUpdate({ + origin: origin, + minorGridSpacing: minorGridSpacing, + majorGridEvery: majorGridEvery, + gridSize: halfSize, + visible: that.visible, + snapToGrid: snapToGrid, + gridColor: gridColor, + }); + } + }; + + that.update = function(data) { + print("Got update"); + if (data.snapToGrid !== undefined) { + snapToGrid = data.snapToGrid; + } + + if (data.origin) { + var pos = data.origin; + pos.x = pos.x === undefined ? origin.x : pos.x; + pos.y = pos.y === undefined ? origin.y : pos.y; + pos.z = pos.z === undefined ? origin.z : pos.z; + that.setPosition(pos, true); + } + + if (data.minorGridSpacing) { + minorGridSpacing = data.minorGridSpacing; + } + + if (data.majorGridEvery) { + majorGridEvery = data.majorGridEvery; + } + + if (data.gridColor) { + gridColor = data.gridColor; + } + + if (data.gridSize) { + halfSize = data.gridSize; + } + + if (data.visible !== undefined) { + that.setVisible(data.visible, true); + } + + updateGrid(); + } + + function updateGrid() { + // Delete overlays + var gridLinesRequired = (halfSize * 2 + 1) * 2; + if (gridLinesRequired > gridOverlays.length) { + for (var i = gridOverlays.length; i < gridLinesRequired; i++) { + gridOverlays.push(Overlays.addOverlay("line3d", {})); + } + } else if (gridLinesRequired < gridOverlays.length) { + var numberToRemove = gridOverlays.length - gridLinesRequired; + var removed = gridOverlays.splice(gridOverlays.length - numberToRemove, numberToRemove); + for (var i = 0; i < removed.length; i++) { + Overlays.deleteOverlay(removed[i]); + } + } + + Overlays.editOverlay(gridPlane, { + position: origin, + size: halfSize * 2 * minorGridSpacing * 1.05, + }); + + var startX = { + x: origin.x - (halfSize * minorGridSpacing), + y: origin.y, + z: origin.z, + }; + var endX = { + x: origin.x + (halfSize * minorGridSpacing), + y: origin.y, + z: origin.z, + }; + var startZ = { + x: origin.x, + y: origin.y, + z: origin.z - (halfSize * minorGridSpacing) + }; + var endZ = { + x: origin.x, + y: origin.y, + z: origin.z + (halfSize * minorGridSpacing) + }; + + var overlayIdx = 0; + for (var i = -halfSize; i <= halfSize; i++) { + // Offset for X-axis aligned grid line + var offsetX = { x: 0, y: 0, z: i * minorGridSpacing }; + + // Offset for Z-axis aligned grid line + var offsetZ = { x: i * minorGridSpacing, y: 0, z: 0 }; + + var position = Vec3.sum(origin, offsetX); + var size = i % majorGridEvery == 0 ? majorGridWidth : minorGridWidth; + + var gridLineX = gridOverlays[overlayIdx++]; + var gridLineZ = gridOverlays[overlayIdx++]; + + Overlays.editOverlay(gridLineX, { + start: Vec3.sum(startX, offsetX), + end: Vec3.sum(endX, offsetX), + lineWidth: size, + color: gridColor, + alpha: gridAlpha, + solid: true, + visible: that.visible, + ignoreRayIntersection: true, + }); + Overlays.editOverlay(gridLineZ, { + start: Vec3.sum(startZ, offsetZ), + end: Vec3.sum(endZ, offsetZ), + lineWidth: size, + color: gridColor, + alpha: gridAlpha, + solid: true, + visible: that.visible, + ignoreRayIntersection: true, + }); + } + } + + function cleanup() { + Overlays.deleteOverlay(gridPlane); + for (var i = 0; i < gridOverlays.length; i++) { + Overlays.deleteOverlay(gridOverlays[i]); + } + } + + that.addListener = function(callback) { + that.onUpdate = callback; + } + + Script.scriptEnding.connect(cleanup); + updateGrid(); + + that.onUpdate = null; + + return that; +}; + +GridTool = function(opts) { + var that = {}; + + var horizontalGrid = opts.horizontalGrid; + var verticalGrid = opts.verticalGrid; + var listeners = []; + + // var webView = Window.createWebView('http://localhost:8000/gridControls.html', 200, 280); + var webView = new WebWindow('http://localhost:8000/gridControls.html', 200, 280); + + horizontalGrid.addListener(function(data) { + webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + }); + + webView.eventBridge.webEventReceived.connect(function(data) { + print('got event: ' + data); + data = JSON.parse(data); + if (data.type == "init") { + horizontalGrid.emitUpdate(); + } else if (data.type == "update") { + horizontalGrid.update(data); + for (var i = 0; i < listeners.length; i++) { + listeners[i](data); + } + } + }); + + that.addListener = function(callback) { + listeners.push(callback); + } + + that.setVisible = function(visible) { + webView.setVisible(visible); + } + + return that; +}; diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ea1f69e15f..b8e7a6174e 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -35,6 +35,12 @@ var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); var cameraManager = new CameraManager(); +Script.include("libraries/gridTool.js"); +var grid = Grid(); +gridTool = GridTool({ horizontalGrid: grid }); +gridTool.addListener(function(data) { +}); + selectionManager.setEventListener(selectionDisplay.updateHandles); var windowDimensions = Controller.getViewportDimensions(); @@ -258,6 +264,7 @@ var toolBar = (function () { if (activeButton === toolBar.clicked(clickedOverlay)) { isActive = !isActive; + gridTool.setVisible(isActive); if (!isActive) { selectionManager.clearSelections(); cameraManager.disable(); @@ -747,25 +754,32 @@ Controller.keyReleaseEvent.connect(function (event) { if (isActive) { cameraManager.enable(); } + } else if (event.text == 'g') { + if (isActive && selectionManager.hasSelection()) { + var newPosition = selectionManager.worldPosition; + newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 }); + grid.setPosition(newPosition); + } } else if (isActive) { var delta = null; + var increment = event.isShifted ? grid.getMajorIncrement() : grid.getMinorIncrement(); if (event.text == 'UP') { if (event.isControl || event.isAlt) { - delta = { x: 0, y: 1, z: 0 }; + delta = { x: 0, y: increment, z: 0 }; } else { - delta = { x: 0, y: 0, z: -1 }; + delta = { x: 0, y: 0, z: -increment }; } } else if (event.text == 'DOWN') { if (event.isControl || event.isAlt) { - delta = { x: 0, y: -1, z: 0 }; + delta = { x: 0, y: -increment, z: 0 }; } else { - delta = { x: 0, y: 0, z: 1 }; + delta = { x: 0, y: 0, z: increment }; } } else if (event.text == 'LEFT') { - delta = { x: -1, y: 0, z: 0 }; + delta = { x: -increment, y: 0, z: 0 }; } else if (event.text == 'RIGHT') { - delta = { x: 1, y: 0, z: 0 }; + delta = { x: increment, y: 0, z: 0 }; } if (delta != null) { @@ -820,7 +834,6 @@ function applyEntityProperties(data) { var properties = data.createEntities[i].properties; var newEntityID = Entities.addEntity(properties); DELETED_ENTITY_MAP[entityID.id] = newEntityID; - print(newEntityID.isKnownID); if (data.selectCreated) { selectedEntityIDs.push(newEntityID); } diff --git a/gridControls.html b/gridControls.html new file mode 100644 index 0000000000..84d437a60d --- /dev/null +++ b/gridControls.html @@ -0,0 +1,206 @@ + + + + + + +
+ + +
+
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+ + diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fb98124fc9..8f176de04f 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -322,6 +322,11 @@ QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* ob return QScriptValue::NullValue; } +void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments) { + QScriptValue scriptFun = newFunction(fun, numArguments); + globalObject().setProperty(name, scriptFun); +} + void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, QScriptValue object) { QScriptValue setterFunction = newFunction(setter, 1); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index d556475859..22617512a9 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -65,6 +65,7 @@ public: QScriptValue registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, QScriptValue object = QScriptValue::NullValue); + void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); Q_INVOKABLE void setIsAvatar(bool isAvatar); bool isAvatar() const { return _isAvatar; } From 2ebca0a659c6ceb2ed6a3046cec8defb14d2b0eb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 11 Nov 2014 09:50:25 -0800 Subject: [PATCH 03/13] Add Grid3DOverlay --- interface/src/ui/overlays/Grid3DOverlay.cpp | 118 ++++++++++++++++++++ interface/src/ui/overlays/Grid3DOverlay.h | 44 ++++++++ 2 files changed, 162 insertions(+) create mode 100644 interface/src/ui/overlays/Grid3DOverlay.cpp create mode 100644 interface/src/ui/overlays/Grid3DOverlay.h diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp new file mode 100644 index 0000000000..c628199fe3 --- /dev/null +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -0,0 +1,118 @@ +// +// Grid3DOverlay.cpp +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Grid3DOverlay.h" + +#include "Application.h" + +ProgramObject Grid3DOverlay::_gridProgram; + +Grid3DOverlay::Grid3DOverlay() : Base3DOverlay(), + _minorGridWidth(1.0), + _majorGridEvery(5) { +} + +Grid3DOverlay::~Grid3DOverlay() { +} + +void Grid3DOverlay::render(RenderArgs* args) { + if (!_visible) { + return; // do nothing if we're not visible + } + + if (!_gridProgram.isLinked()) { + if (!_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/grid.frag")) { + qDebug() << "Failed to compile: " + _gridProgram.log(); + return; + } + if (!_gridProgram.link()) { + qDebug() << "Failed to link: " + _gridProgram.log(); + return; + } + } + + // Render code largely taken from MetavoxelEditor::render() + glDisable(GL_LIGHTING); + + glDepthMask(GL_FALSE); + + glPushMatrix(); + + glm::quat rotation = getRotation(); + + glm::vec3 axis = glm::axis(rotation); + + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + glLineWidth(1.5f); + + // center the grid around the camera position on the plane + glm::vec3 rotated = glm::inverse(rotation) * Application::getInstance()->getCamera()->getPosition(); + float spacing = _minorGridWidth; + + float alpha = getAlpha(); + xColor color = getColor(); + glm::vec3 position = getPosition(); + + const int GRID_DIVISIONS = 300; + const float MAX_COLOR = 255.0f; + float scale = GRID_DIVISIONS * spacing; + + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + _gridProgram.bind(); + + // Minor grid + glPushMatrix(); + { + glTranslatef(_minorGridWidth * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2), + spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position.z); + + glScalef(scale, scale, scale); + + Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS); + } + glPopMatrix(); + + // Major grid + glPushMatrix(); + { + glLineWidth(4.0f); + spacing *= _majorGridEvery; + glTranslatef(spacing * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2), + spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position.z); + + scale *= _majorGridEvery; + glScalef(scale, scale, scale); + + Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS); + } + glPopMatrix(); + + _gridProgram.release(); + + glPopMatrix(); + + glEnable(GL_LIGHTING); + glDepthMask(GL_TRUE); +} + +void Grid3DOverlay::setProperties(const QScriptValue& properties) { + Base3DOverlay::setProperties(properties); + + if (properties.property("minorGridWidth").isValid()) { + _minorGridWidth = properties.property("minorGridWidth").toVariant().toFloat(); + } + + if (properties.property("majorGridEvery").isValid()) { + _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); + } +} diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h new file mode 100644 index 0000000000..b1675f15d7 --- /dev/null +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -0,0 +1,44 @@ +// +// Grid3DOverlay.h +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Grid3DOverlay_h +#define hifi_Grid3DOverlay_h + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include + +#include +#include + +#include "Base3DOverlay.h" + +#include "renderer/ProgramObject.h" + +class Grid3DOverlay : public Base3DOverlay { + Q_OBJECT + +public: + Grid3DOverlay(); + ~Grid3DOverlay(); + + virtual void render(RenderArgs* args); + virtual void setProperties(const QScriptValue& properties); + +private: + float _minorGridWidth; + int _majorGridEvery; + + static ProgramObject _gridProgram; +}; + +#endif // hifi_Grid3DOverlay_h From b04fd89e4f6c7f3241a6570966c16b65aa89d780 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 11 Nov 2014 09:55:30 -0800 Subject: [PATCH 04/13] Update grid tool html location --- .../html/gridControls.html | 19 +-- examples/libraries/gridTool.js | 121 ++++-------------- libraries/script-engine/src/ScriptEngine.cpp | 6 +- libraries/script-engine/src/ScriptEngine.h | 2 +- 4 files changed, 29 insertions(+), 119 deletions(-) rename gridControls.html => examples/html/gridControls.html (89%) diff --git a/gridControls.html b/examples/html/gridControls.html similarity index 89% rename from gridControls.html rename to examples/html/gridControls.html index 84d437a60d..e7bf1cdf8c 100644 --- a/gridControls.html +++ b/examples/html/gridControls.html @@ -2,20 +2,13 @@