From 0119797454535fb58cce7b71354d33abe0d7f78e Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 18 Nov 2014 02:26:11 +0100 Subject: [PATCH 001/100] virtual keyboard rendered --- examples/virtualKeyboard.js | 235 ++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 examples/virtualKeyboard.js diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js new file mode 100644 index 0000000000..109196008d --- /dev/null +++ b/examples/virtualKeyboard.js @@ -0,0 +1,235 @@ +const KBD_UPPERCASE_DEFAULT = 0; +const KBD_LOWERCASE_DEFAULT = 1; +const KBD_UPPERCASE_HOVER = 2; +const KBD_LOWERCASE_HOVER = 3; +const KBD_BACKGROUND = 4; + +const KEYBOARD_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/keyboard.svg"; + +const KEYBOARD_HEIGHT = 434.1; +const KEYBOARD_WIDTH = 1174.7; + +const BOUND_X = 0; +const BOUND_Y = 1; +const BOUND_W = 2; +const BOUND_H = 3; + +const KEY_STATE_LOWER = 0; +const KEY_STATE_UPPER = 1; + +function KeyboardKey(keyboard, key_properties) { + this.event = key_properties.event != undefined ? + key_properties.event : 'keypress'; + this.bounds = key_properties.bounds; + this.states = key_properties.states; + this.keyboard = keyboard; + this.key_state = key_properties.key_state != undefined ? key_properties.key_state : KBD_LOWERCASE_HOVER; + // one overlay per bound vector [this.bounds] + this.overlays = []; + this.updatePosition = function() { + }; + this.containsCoord = function(x, y) { + for (var i = 0; i < this.bounds.length; i++) { + if (x >= this.bounds[i][BOUND_X] && + x <= (this.bounds[i][BOUND_X] + this.bounds[i][BOUND_W]) && + y >= this.bounds[i][BOUND_Y] && + y <= (this.bounds[i][BOUND_Y] + this.bounds[i][BOUND_H])) + { + return true; + } + } + return false; + }; + this.remove = function() { + for (var i = 0; i < this.overlays.length; i++) { + Overlays.deleteOverlay(this.overlays[i]); + } + }; + this.isLoaded = function() { + for (var i = 0; i < this.overlays.length; i++) { + if (!Overlays.isLoaded(this.overlays[i])) { + return false; + } + } + return true; + }; + for (var i = 0; i < this.bounds.length; i++) { + var newOverlay = Overlays.cloneOverlay(this.keyboard.background); + Overlays.editOverlay(newOverlay, { + x: 50 + this.bounds[i][BOUND_X], + y: 50 + this.bounds[i][BOUND_Y], + width: this.bounds[i][BOUND_W], + height: this.bounds[i][BOUND_H], + subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.key_state) + this.bounds[i][BOUND_Y]}, + alpha: 1 + }); + this.overlays.push(newOverlay); + } +} + +function Keyboard() { + this.background = Overlays.addOverlay("image", { + x: 50, + y: 50, + width: KEYBOARD_WIDTH, + height: KEYBOARD_HEIGHT, + subImage: {width: KEYBOARD_WIDTH, height: KEYBOARD_HEIGHT, y: KEYBOARD_HEIGHT * KBD_BACKGROUND}, + imageURL: KEYBOARD_URL, + alpha: 1 + }); + this.updatePosition = function() { + + }; + this.getFocussedKey = function() { + + }; + this.remove = function() { + Overlays.deleteOverlay(this.background); + for (var i = 0; i < this.keys.length; i++) { + this.keys[i].remove(); + } + }; + + this.onKeyPress = null; + this.onKeyDown = null; + this.onKeyUp = null; + this.onSubmit = null; + + this.keys = []; + // + // keyProperties contains the key data + // + // coords [[x,y,w,h],[x,y,w,h]] + // states array of 1 or 2 objects [lowercase, uppercase] each object contains a charCode and a char + var keyProperties = [ + {bounds: [[12, 12, 65, 52]], states: [{charCode: 192, char: '~'}]}, + {bounds: [[84, 12, 65, 52]], states: [{charCode: 192, char: '!'}]}, + {bounds: [[156, 12, 65, 52]], states: [{charCode: 192, char: '@'}]}, + {bounds: [[228, 12, 65, 52]], states: [{charCode: 192, char: '#'}]}, + {bounds: [[300, 12, 65, 52]], states: [{charCode: 192, char: '$'}]}, + {bounds: [[372, 12, 65, 52]], states: [{charCode: 192, char: '%'}]}, + {bounds: [[445, 12, 65, 52]], states: [{charCode: 192, char: '^'}]}, + {bounds: [[517, 12, 65, 52]], states: [{charCode: 192, char: '&'}]}, + {bounds: [[589, 12, 65, 52]], states: [{charCode: 192, char: '*'}]}, + {bounds: [[662, 12, 65, 52]], states: [{charCode: 192, char: '('}]}, + {bounds: [[734, 12, 65, 52]], states: [{charCode: 192, char: ')'}]}, + {bounds: [[806, 12, 65, 52]], states: [{charCode: 192, char: '_'}]}, + {bounds: [[881, 12, 65, 52]], states: [{charCode: 192, char: '{'}]}, + {bounds: [[953, 12, 65, 52]], states: [{charCode: 192, char: '}'}]}, + {bounds: [[1025, 12, 65, 52]], states: [{charCode: 192, char: '<'}]}, + {bounds: [[1097, 12, 65, 52]], states: [{charCode: 192, char: '>'}]}, + + {bounds: [[12, 71, 65, 63]], states: [{charCode: 192, char: '`'}]}, + {bounds: [[84, 71, 65, 63]], states: [{charCode: 192, char: '1'}]}, + {bounds: [[156, 71, 65, 63]], states: [{charCode: 192, char: '2'}]}, + {bounds: [[228, 71, 65, 63]], states: [{charCode: 192, char: '3'}]}, + {bounds: [[300, 71, 65, 63]], states: [{charCode: 192, char: '4'}]}, + {bounds: [[372, 71, 65, 63]], states: [{charCode: 192, char: '5'}]}, + {bounds: [[445, 71, 65, 63]], states: [{charCode: 192, char: '6'}]}, + {bounds: [[517, 71, 65, 63]], states: [{charCode: 192, char: '7'}], key_state: KBD_UPPERCASE_DEFAULT}, + {bounds: [[589, 71, 65, 63]], states: [{charCode: 192, char: '8'}]}, + {bounds: [[661, 71, 65, 63]], states: [{charCode: 192, char: '9'}]}, + {bounds: [[733, 71, 65, 63]], states: [{charCode: 192, char: '0'}]}, + {bounds: [[806, 71, 65, 63]], states: [{charCode: 192, char: '-'}]}, + {bounds: [[880, 71, 65, 63]], states: [{charCode: 192, char: '='}]}, + {bounds: [[953, 71, 65, 63]], states: [{charCode: 192, char: '+'}]}, + {bounds: [[1024, 71, 139, 63]], event: 'delete'}, + + // enter key has 2 bounds and one state + {bounds: [[11, 143, 98, 71], [11, 213, 121, 62]], event: 'enter'}, + + {bounds: [[118, 142, 64, 63]], states: [{charCode: 192, char: 'q'}, {charCode: 192, char: 'Q'}]}, + {bounds: [[190, 142, 64, 63]], states: [{charCode: 192, char: 'w'}, {charCode: 192, char: 'W'}]}, + {bounds: [[262, 142, 64, 63]], states: [{charCode: 192, char: 'e'}, {charCode: 192, char: 'E'}]}, + {bounds: [[334, 142, 64, 63]], states: [{charCode: 192, char: 'r'}, {charCode: 192, char: 'R'}]}, + {bounds: [[407, 142, 64, 63]], states: [{charCode: 192, char: 't'}, {charCode: 192, char: 'T'}]}, + {bounds: [[479, 142, 64, 63]], states: [{charCode: 192, char: 'y'}, {charCode: 192, char: 'Y'}]}, + {bounds: [[551, 142, 65, 63]], states: [{charCode: 192, char: 'u'}, {charCode: 192, char: 'U'}]}, + {bounds: [[623, 142, 65, 63]], states: [{charCode: 192, char: 'i'}, {charCode: 192, char: 'I'}]}, + {bounds: [[695, 142, 65, 63]], states: [{charCode: 192, char: 'o'}, {charCode: 192, char: 'O'}]}, + {bounds: [[768, 142, 64, 63]], states: [{charCode: 192, char: 'p'}, {charCode: 192, char: 'P'}]}, + {bounds: [[840, 142, 64, 63]], states: [{charCode: 192, char: '['}]}, + {bounds: [[912, 142, 65, 63]], states: [{charCode: 192, char: ']'}]}, + {bounds: [[984, 142, 65, 63]], states: [{charCode: 192, char: '\\'}]}, + {bounds: [[1055, 142, 65, 63]], states: [{charCode: 192, char: '|'}]}, + + {bounds: [[1126, 143, 35, 72], [1008, 214, 153, 62]], event: 'enter'}, + + {bounds: [[140, 213, 65, 63]], states: [{charCode: 192, char: 'a'}, {charCode: 192, char: 'A'}]}, + {bounds: [[211, 213, 64, 63]], states: [{charCode: 192, char: 's'}, {charCode: 192, char: 'S'}]}, + {bounds: [[283, 213, 65, 63]], states: [{charCode: 192, char: 'd'}, {charCode: 192, char: 'D'}]}, + {bounds: [[355, 213, 65, 63]], states: [{charCode: 192, char: 'f'}, {charCode: 192, char: 'F'}]}, + {bounds: [[428, 213, 64, 63]], states: [{charCode: 192, char: 'g'}, {charCode: 192, char: 'G'}]}, + {bounds: [[500, 213, 64, 63]], states: [{charCode: 192, char: 'h'}, {charCode: 192, char: 'H'}]}, + {bounds: [[572, 213, 65, 63]], states: [{charCode: 192, char: 'j'}, {charCode: 192, char: 'J'}]}, + {bounds: [[644, 213, 65, 63]], states: [{charCode: 192, char: 'k'}, {charCode: 192, char: 'K'}]}, + {bounds: [[716, 213, 65, 63]], states: [{charCode: 192, char: 'l'}, {charCode: 192, char: 'L'}]}, + {bounds: [[789, 213, 64, 63]], states: [{charCode: 192, char: ';'}]}, + {bounds: [[861, 213, 64, 63]], states: [{charCode: 192, char: '\''}]}, + {bounds: [[934, 213, 65, 63]], states: [{charCode: 192, char: ':'}]}, + + {bounds: [[12, 283, 157, 63]], event: 'shift'}, + + {bounds: [[176, 283, 65, 63]], states: [{charCode: 192, char: 'z'}, {charCode: 192, char: 'Z'}]}, + {bounds: [[249, 283, 64, 63]], states: [{charCode: 192, char: 'x'}, {charCode: 192, char: 'X'}]}, + {bounds: [[321, 283, 64, 63]], states: [{charCode: 192, char: 'c'}, {charCode: 192, char: 'C'}]}, + {bounds: [[393, 283, 64, 63]], states: [{charCode: 192, char: 'v'}, {charCode: 192, char: 'V'}]}, + {bounds: [[465, 283, 65, 63]], states: [{charCode: 192, char: 'b'}, {charCode: 192, char: 'B'}]}, + {bounds: [[537, 283, 65, 63]], states: [{charCode: 192, char: 'n'}, {charCode: 192, char: 'N'}]}, + {bounds: [[610, 283, 64, 63]], states: [{charCode: 192, char: 'm'}, {charCode: 192, char: 'M'}]}, + {bounds: [[682, 283, 64, 63]], states: [{charCode: 192, char: ','}]}, + {bounds: [[754, 283, 65, 63]], states: [{charCode: 192, char: '.'}]}, + {bounds: [[826, 283, 65, 63]], states: [{charCode: 192, char: '/'}]}, + {bounds: [[899, 283, 64, 63]], states: [{charCode: 192, char: '?'}], key_state: KBD_UPPERCASE_DEFAULT}, + + {bounds: [[972, 283, 190, 63]], event: 'shift'}, + + {bounds: [[249, 355, 573, 67]], states: [{charCode: 192, char: ' '}]}, + + {bounds: [[899, 355, 263, 67]], event: 'submit'} + + + + ]; + + this.keys_in_waitingline = []; + this.keys_being_downloaded = []; + + for (var i = 0; i < keyProperties.length; i++) { + //this.keys_in_waitingline.push(keyProperties[i]); + //this.keys.push(new KeyboardKey(this, keyProperties[i])); + } + var tthis = this; + this.keyboardtextureloaded = function() { + if (Overlays.isLoaded(tthis.background)) { + Script.clearInterval(tthis.keyboardtextureloaded_timer); + for (var i = 0; i < keyProperties.length; i++) { + tthis.keys.push(new KeyboardKey(tthis, keyProperties[i])); + } + } + }; + this.keyboardtextureloaded_timer = Script.setInterval(this.keyboardtextureloaded, 250); +} + +var keyboard = new Keyboard(); +keyboard.onKeyPress = function() { + print("Key press event test"); +}; + +function scriptEnding() { + keyboard.remove(); +} +function mousePressEvent(event) { + //var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + //if (clickedOverlay != 0) { + // Overlays.deleteOverlay(clickedOverlay); + //} +} + +function onUpdate() { + MyAvatar.getHeadFinalYaw(); + MyAvatar.getHeadFinalPitch(); +} + +Script.update.connect(onUpdate); +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From d52f410c03d309542f2ffc33655e38676a360de0 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 18 Nov 2014 03:11:47 +0100 Subject: [PATCH 002/100] virtualKeyboard: added cursor which responds to HMD --- examples/virtualKeyboard.js | 67 ++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 109196008d..4e871a79ab 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -1,3 +1,16 @@ +// +// virtualKeyboard.js +// examples +// +// Created by Thijs Wenker on 11/18/14. +// Copyright 2014 High Fidelity, Inc. +// +// Control a virtual keyboard using your favorite HMD. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + const KBD_UPPERCASE_DEFAULT = 0; const KBD_LOWERCASE_DEFAULT = 1; const KBD_UPPERCASE_HOVER = 2; @@ -5,9 +18,15 @@ const KBD_LOWERCASE_HOVER = 3; const KBD_BACKGROUND = 4; const KEYBOARD_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/keyboard.svg"; +const CURSOR_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/cursor.svg"; -const KEYBOARD_HEIGHT = 434.1; const KEYBOARD_WIDTH = 1174.7; +const KEYBOARD_HEIGHT = 434.1; + +const CURSOR_WIDTH = 33.9; +const CURSOR_HEIGHT = 33.9; + +const VIEW_ANGLE = 60.0; const BOUND_X = 0; const BOUND_Y = 1; @@ -216,20 +235,42 @@ keyboard.onKeyPress = function() { print("Key press event test"); }; +function Cursor() { + var tthis = this; + var dimensions = Controller.getViewportDimensions(); + this.overlay = Overlays.addOverlay("image", { + x: dimensions.x / 2, + y: dimensions.y / 2, + width: CURSOR_WIDTH, + height: CURSOR_HEIGHT, + imageURL: CURSOR_URL, + alpha: 1 + }); + this.remove = function() { + Overlays.deleteOverlay(this.overlay); + }; + this.update = function() { + var screen_angle = 60; + var dimensions = Controller.getViewportDimensions(); + var editobject = {};//{x: dimensions.x / 2, y: dimensions.y / 2}; + if (MyAvatar.getHeadFinalYaw() <= (VIEW_ANGLE / 2) && MyAvatar.getHeadFinalYaw() >= -1 * (VIEW_ANGLE / 2)) { + angle = ((-1 * MyAvatar.getHeadFinalYaw()) + (VIEW_ANGLE / 2)) / VIEW_ANGLE; + editobject.x = angle * dimensions.x; + } + if (MyAvatar.getHeadFinalPitch() <= (VIEW_ANGLE / 2) && MyAvatar.getHeadFinalPitch() >= -1 * (VIEW_ANGLE / 2)) { + angle = ((-1 * MyAvatar.getHeadFinalPitch()) + (VIEW_ANGLE / 2)) / VIEW_ANGLE; + // print(angle * dimensions.y); + editobject.y = angle * dimensions.y; + } + Overlays.editOverlay(tthis.overlay, editobject); + }; + Script.update.connect(this.update); +} +var cursor = new Cursor(); function scriptEnding() { keyboard.remove(); -} -function mousePressEvent(event) { - //var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - //if (clickedOverlay != 0) { - // Overlays.deleteOverlay(clickedOverlay); - //} + cursor.remove(); + Overlays.deleteOverlay(cursor); } -function onUpdate() { - MyAvatar.getHeadFinalYaw(); - MyAvatar.getHeadFinalPitch(); -} - -Script.update.connect(onUpdate); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From 7dc35bb3490cbf3e2465d188bc9cbbd41fae796b Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 19 Nov 2014 03:12:22 +0100 Subject: [PATCH 003/100] virtual-keyboard: - positioned in bottom - keyboard hover-able --- examples/virtualKeyboard.js | 185 ++++++++++++++++++++++++++++-------- 1 file changed, 147 insertions(+), 38 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 4e871a79ab..41ddfa75ae 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -27,6 +27,7 @@ const CURSOR_WIDTH = 33.9; const CURSOR_HEIGHT = 33.9; const VIEW_ANGLE = 60.0; +const VIEW_ANGLE_BY_TWO = VIEW_ANGLE / 2; const BOUND_X = 0; const BOUND_Y = 1; @@ -36,13 +37,31 @@ const BOUND_H = 3; const KEY_STATE_LOWER = 0; const KEY_STATE_UPPER = 1; +var cursor = null; +var keyboard = new Keyboard(); + +keyboard.onKeyPress = function() { + print("Key press event test"); +}; + +keyboard.onFullyLoaded = function() { + print("Virtual-keyboard fully loaded."); + // the cursor is being loaded after the keyboard, else it will be on the background of the keyboard + cursor = new Cursor(); + cursor.onUpdate = function(position) { + keyboard.setFocusPosition(position.x, position.y); + }; +}; + function KeyboardKey(keyboard, key_properties) { + var tthis = this; + this._focus = false; this.event = key_properties.event != undefined ? key_properties.event : 'keypress'; this.bounds = key_properties.bounds; this.states = key_properties.states; this.keyboard = keyboard; - this.key_state = key_properties.key_state != undefined ? key_properties.key_state : KBD_LOWERCASE_HOVER; + this.key_state = key_properties.key_state != undefined ? key_properties.key_state : KBD_LOWERCASE_DEFAULT; // one overlay per bound vector [this.bounds] this.overlays = []; this.updatePosition = function() { @@ -59,6 +78,33 @@ function KeyboardKey(keyboard, key_properties) { } return false; }; + this.updateState = function() { + tthis.setState(eval('KBD_' + (tthis.keyboard.shift ? 'UPPERCASE' : 'LOWERCASE') + '_' + (tthis._focus ? 'HOVER' : 'DEFAULT'))); + }; + this.blur = function() { + tthis._focus = false; + tthis.updateState(); + }; + this.focus = function() { + tthis._focus = true; + tthis.updateState(); + }; + this.setState = function(state) { + tthis.key_state = state; + for (var i = 0; i < tthis.bounds.length; i++) { + Overlays.editOverlay(tthis.overlays[i], { + subImage: {width: tthis.bounds[i][BOUND_W], height: tthis.bounds[i][BOUND_H], x: tthis.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * tthis.key_state) + tthis.bounds[i][BOUND_Y]} + }); + } + }; + this.updatePosition = function() { + for (var i = 0; i < tthis.bounds.length; i++) { + Overlays.editOverlay(tthis.overlays[i], { + x: tthis.keyboard.x + tthis.bounds[i][BOUND_X], + y: tthis.keyboard.y + tthis.bounds[i][BOUND_Y], + }); + } + }; this.remove = function() { for (var i = 0; i < this.overlays.length; i++) { Overlays.deleteOverlay(this.overlays[i]); @@ -67,7 +113,7 @@ function KeyboardKey(keyboard, key_properties) { this.isLoaded = function() { for (var i = 0; i < this.overlays.length; i++) { if (!Overlays.isLoaded(this.overlays[i])) { - return false; + return false; } } return true; @@ -75,8 +121,8 @@ function KeyboardKey(keyboard, key_properties) { for (var i = 0; i < this.bounds.length; i++) { var newOverlay = Overlays.cloneOverlay(this.keyboard.background); Overlays.editOverlay(newOverlay, { - x: 50 + this.bounds[i][BOUND_X], - y: 50 + this.bounds[i][BOUND_Y], + x: this.keyboard.x + this.bounds[i][BOUND_X], + y: this.keyboard.y + this.bounds[i][BOUND_Y], width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.key_state) + this.bounds[i][BOUND_Y]}, @@ -87,21 +133,66 @@ function KeyboardKey(keyboard, key_properties) { } function Keyboard() { + var tthis = this; + var dimensions = Controller.getViewportDimensions(); + this.focussed_key = -1; + this.shift = false; + this.x = (dimensions.x / 2) - (KEYBOARD_WIDTH / 2); + this.y = dimensions.y - KEYBOARD_HEIGHT; this.background = Overlays.addOverlay("image", { - x: 50, - y: 50, + x: this.x, + y: this.y, width: KEYBOARD_WIDTH, height: KEYBOARD_HEIGHT, subImage: {width: KEYBOARD_WIDTH, height: KEYBOARD_HEIGHT, y: KEYBOARD_HEIGHT * KBD_BACKGROUND}, imageURL: KEYBOARD_URL, alpha: 1 }); + + this.setFocusPosition = function(x, y) { + var localx = x - tthis.x; + var localy = y - tthis.y; + var new_focus_key = -1; + if (localx >= 0 && localy >= 0 && localx <= KEYBOARD_WIDTH && localy <= KEYBOARD_HEIGHT) { + for (var i = 0; i < tthis.keys.length; i++) { + if (tthis.keys[i].containsCoord(localx, localy)) { + //print(tthis.keys[i].states[0].char); + new_focus_key = i; + break; + } + } + } + if (new_focus_key != tthis.focussed_key) { + print(new_focus_key); + if (tthis.focussed_key != -1) { + tthis.keys[tthis.focussed_key].blur(); + } + tthis.focussed_key = new_focus_key; + if (tthis.focussed_key != -1) { + tthis.keys[tthis.focussed_key].focus(); + } + } + return tthis; + }; + + this.pressFocussedKey = function() { + if (tthis.focussed_key != -1) { + this.onKeyPress(tthis.keys[tthis.focussed_key]); + } + return tthis; + }; + this.updatePosition = function() { }; + this.getFocussedKey = function() { - + if (tthis.focussed_key == -1) { + return null; + } + return tthis.keys[tthis.focussed_key]; }; + this.remove = function() { Overlays.deleteOverlay(this.background); for (var i = 0; i < this.keys.length; i++) { @@ -113,6 +204,7 @@ function Keyboard() { this.onKeyDown = null; this.onKeyUp = null; this.onSubmit = null; + this.onFullyLoaded = null; this.keys = []; // @@ -145,7 +237,7 @@ function Keyboard() { {bounds: [[300, 71, 65, 63]], states: [{charCode: 192, char: '4'}]}, {bounds: [[372, 71, 65, 63]], states: [{charCode: 192, char: '5'}]}, {bounds: [[445, 71, 65, 63]], states: [{charCode: 192, char: '6'}]}, - {bounds: [[517, 71, 65, 63]], states: [{charCode: 192, char: '7'}], key_state: KBD_UPPERCASE_DEFAULT}, + {bounds: [[517, 71, 65, 63]], states: [{charCode: 192, char: '7'}]}, {bounds: [[589, 71, 65, 63]], states: [{charCode: 192, char: '8'}]}, {bounds: [[661, 71, 65, 63]], states: [{charCode: 192, char: '9'}]}, {bounds: [[733, 71, 65, 63]], states: [{charCode: 192, char: '0'}]}, @@ -199,48 +291,37 @@ function Keyboard() { {bounds: [[682, 283, 64, 63]], states: [{charCode: 192, char: ','}]}, {bounds: [[754, 283, 65, 63]], states: [{charCode: 192, char: '.'}]}, {bounds: [[826, 283, 65, 63]], states: [{charCode: 192, char: '/'}]}, - {bounds: [[899, 283, 64, 63]], states: [{charCode: 192, char: '?'}], key_state: KBD_UPPERCASE_DEFAULT}, + {bounds: [[899, 283, 64, 63]], states: [{charCode: 192, char: '?'}]}, {bounds: [[972, 283, 190, 63]], event: 'shift'}, {bounds: [[249, 355, 573, 67]], states: [{charCode: 192, char: ' '}]}, {bounds: [[899, 355, 263, 67]], event: 'submit'} - - - ]; - this.keys_in_waitingline = []; - this.keys_being_downloaded = []; - - for (var i = 0; i < keyProperties.length; i++) { - //this.keys_in_waitingline.push(keyProperties[i]); - //this.keys.push(new KeyboardKey(this, keyProperties[i])); - } - var tthis = this; this.keyboardtextureloaded = function() { if (Overlays.isLoaded(tthis.background)) { Script.clearInterval(tthis.keyboardtextureloaded_timer); for (var i = 0; i < keyProperties.length; i++) { tthis.keys.push(new KeyboardKey(tthis, keyProperties[i])); } + if (keyboard.onFullyLoaded != null) { + tthis.onFullyLoaded(); + } } }; this.keyboardtextureloaded_timer = Script.setInterval(this.keyboardtextureloaded, 250); } -var keyboard = new Keyboard(); -keyboard.onKeyPress = function() { - print("Key press event test"); -}; - function Cursor() { var tthis = this; var dimensions = Controller.getViewportDimensions(); + this.x = dimensions.x / 2; + this.y = dimensions.y / 2; this.overlay = Overlays.addOverlay("image", { - x: dimensions.x / 2, - y: dimensions.y / 2, + x: this.x, + y: this.y, width: CURSOR_WIDTH, height: CURSOR_HEIGHT, imageURL: CURSOR_URL, @@ -249,28 +330,56 @@ function Cursor() { this.remove = function() { Overlays.deleteOverlay(this.overlay); }; + this.getPosition = function() { + return {x: tthis.getX(), y: tthis.getY()}; + }; + this.getX = function() { + return tthis.x; + }; + this.getY = function() { + return tthis.y; + }; + this.onUpdate = null; this.update = function() { - var screen_angle = 60; var dimensions = Controller.getViewportDimensions(); - var editobject = {};//{x: dimensions.x / 2, y: dimensions.y / 2}; - if (MyAvatar.getHeadFinalYaw() <= (VIEW_ANGLE / 2) && MyAvatar.getHeadFinalYaw() >= -1 * (VIEW_ANGLE / 2)) { - angle = ((-1 * MyAvatar.getHeadFinalYaw()) + (VIEW_ANGLE / 2)) / VIEW_ANGLE; - editobject.x = angle * dimensions.x; + var editobject = {}; + if (MyAvatar.getHeadFinalYaw() <= VIEW_ANGLE_BY_TWO && MyAvatar.getHeadFinalYaw() >= -1 * VIEW_ANGLE_BY_TWO) { + angle = ((-1 * MyAvatar.getHeadFinalYaw()) + VIEW_ANGLE_BY_TWO) / VIEW_ANGLE; + tthis.x = angle * dimensions.x; + editobject.x = tthis.x - (CURSOR_WIDTH / 2); } - if (MyAvatar.getHeadFinalPitch() <= (VIEW_ANGLE / 2) && MyAvatar.getHeadFinalPitch() >= -1 * (VIEW_ANGLE / 2)) { - angle = ((-1 * MyAvatar.getHeadFinalPitch()) + (VIEW_ANGLE / 2)) / VIEW_ANGLE; - // print(angle * dimensions.y); - editobject.y = angle * dimensions.y; + if (MyAvatar.getHeadFinalPitch() <= VIEW_ANGLE_BY_TWO && MyAvatar.getHeadFinalPitch() >= -1 * VIEW_ANGLE_BY_TWO) { + angle = ((-1 * MyAvatar.getHeadFinalPitch()) + VIEW_ANGLE_BY_TWO) / VIEW_ANGLE; + tthis.y = angle * dimensions.y; + editobject.y = tthis.y - (CURSOR_HEIGHT / 2); + } + if (Object.keys(editobject).length > 0) { + Overlays.editOverlay(tthis.overlay, editobject); + if (tthis.onUpdate != null) { + tthis.onUpdate(tthis.getPosition()); + } } - Overlays.editOverlay(tthis.overlay, editobject); }; Script.update.connect(this.update); } -var cursor = new Cursor(); + +function keyPressEvent(key) { + if (key.text === "SPACE") { + print("pressed space"); + + for (var i = 0; i < keyboard.keys.length; i++) { + print(i + " = " + keyboard.keys[i].key_state); + } + } +} + function scriptEnding() { keyboard.remove(); cursor.remove(); Overlays.deleteOverlay(cursor); + Controller.releaseKeyEvents({text: "SPACE"}); } +Controller.captureKeyEvents({text: "SPACE"}); +Controller.keyPressEvent.connect(keyPressEvent); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From 4eb4330e84560cf40e18b7b0f890904e03df71b7 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 19 Nov 2014 23:08:50 +0100 Subject: [PATCH 004/100] virtualkeyboard now scales to the viewportdimensions --- examples/virtualKeyboard.js | 79 ++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 41ddfa75ae..e99a70faed 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -39,6 +39,7 @@ const KEY_STATE_UPPER = 1; var cursor = null; var keyboard = new Keyboard(); +var text = null; keyboard.onKeyPress = function() { print("Key press event test"); @@ -46,6 +47,20 @@ keyboard.onKeyPress = function() { keyboard.onFullyLoaded = function() { print("Virtual-keyboard fully loaded."); + var dimensions = Controller.getViewportDimensions(); + text = Overlays.addOverlay("text", { + x: 0,//(dimensions.x / 2) - (KEYBOARD_WIDTH / 2), + y: dimensions.y - keyboard.height() - 60, + width: dimensions.x, + height: 50, + backgroundColor: { red: 255, green: 255, blue: 255}, + color: { red: 0, green: 0, blue: 0}, + topMargin: 10, + leftMargin: 8, + font: {size: 28}, + text: "", + alpha: 0.8 + }); // the cursor is being loaded after the keyboard, else it will be on the background of the keyboard cursor = new Cursor(); cursor.onUpdate = function(position) { @@ -56,6 +71,7 @@ keyboard.onFullyLoaded = function() { function KeyboardKey(keyboard, key_properties) { var tthis = this; this._focus = false; + this._beingpressed = false; this.event = key_properties.event != undefined ? key_properties.event : 'keypress'; this.bounds = key_properties.bounds; @@ -81,6 +97,22 @@ function KeyboardKey(keyboard, key_properties) { this.updateState = function() { tthis.setState(eval('KBD_' + (tthis.keyboard.shift ? 'UPPERCASE' : 'LOWERCASE') + '_' + (tthis._focus ? 'HOVER' : 'DEFAULT'))); }; + this.updateColor = function() { + var colorIntensity = _beingpressed ? 128 : 255; + for (var i = 0; i < tthis.bounds.length; i++) { + Overlays.editOverlay(tthis.overlays[i], + {color: {red: colorIntensity, green: colorIntensity, blue: colorIntensity}} + ); + } + }; + this.press = function() { + tthis._beingpressed = true; + tthis.updateColor(); + }; + this.release = function() { + tthis._beingpressed = false; + tthis.updateColor(); + }; this.blur = function() { tthis._focus = false; tthis.updateState(); @@ -121,10 +153,10 @@ function KeyboardKey(keyboard, key_properties) { for (var i = 0; i < this.bounds.length; i++) { var newOverlay = Overlays.cloneOverlay(this.keyboard.background); Overlays.editOverlay(newOverlay, { - x: this.keyboard.x + this.bounds[i][BOUND_X], - y: this.keyboard.y + this.bounds[i][BOUND_Y], - width: this.bounds[i][BOUND_W], - height: this.bounds[i][BOUND_H], + x: this.keyboard.x + this.bounds[i][BOUND_X] * keyboard.scale, + y: this.keyboard.y + this.bounds[i][BOUND_Y] * keyboard.scale, + width: this.bounds[i][BOUND_W] * keyboard.scale, + height: this.bounds[i][BOUND_H] * keyboard.scale, subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.key_state) + this.bounds[i][BOUND_Y]}, alpha: 1 }); @@ -136,22 +168,30 @@ function Keyboard() { var tthis = this; var dimensions = Controller.getViewportDimensions(); this.focussed_key = -1; + this.scale = dimensions.x / KEYBOARD_WIDTH; this.shift = false; - this.x = (dimensions.x / 2) - (KEYBOARD_WIDTH / 2); - this.y = dimensions.y - KEYBOARD_HEIGHT; + this.width = function() { + return KEYBOARD_WIDTH * tthis.scale; + }; + this.height = function() { + return KEYBOARD_HEIGHT * tthis.scale; + }; + this.x = (dimensions.x / 2) - (this.width() / 2); + this.y = dimensions.y - this.height(); this.background = Overlays.addOverlay("image", { x: this.x, y: this.y, - width: KEYBOARD_WIDTH, - height: KEYBOARD_HEIGHT, + width: this.width(), + height: this.height(), subImage: {width: KEYBOARD_WIDTH, height: KEYBOARD_HEIGHT, y: KEYBOARD_HEIGHT * KBD_BACKGROUND}, imageURL: KEYBOARD_URL, alpha: 1 }); this.setFocusPosition = function(x, y) { - var localx = x - tthis.x; - var localy = y - tthis.y; + // set to local unscaled position + var localx = (x - tthis.x) / tthis.scale; + var localy = (y - tthis.y) / tthis.scale; var new_focus_key = -1; if (localx >= 0 && localy >= 0 && localx <= KEYBOARD_WIDTH && localy <= KEYBOARD_HEIGHT) { for (var i = 0; i < tthis.keys.length; i++) { @@ -163,7 +203,7 @@ function Keyboard() { } } if (new_focus_key != tthis.focussed_key) { - print(new_focus_key); + //print(new_focus_key); if (tthis.focussed_key != -1) { tthis.keys[tthis.focussed_key].blur(); } @@ -179,6 +219,7 @@ function Keyboard() { if (tthis.focussed_key != -1) { this.onKeyPress(tthis.keys[tthis.focussed_key]); } + return tthis; }; @@ -366,20 +407,22 @@ function Cursor() { function keyPressEvent(key) { if (key.text === "SPACE") { print("pressed space"); + } +} - for (var i = 0; i < keyboard.keys.length; i++) { - print(i + " = " + keyboard.keys[i].key_state); - } +function keyReleaseEvent(key) { + if (key.text === "SPACE") { + print("released space"); } } function scriptEnding() { keyboard.remove(); cursor.remove(); - Overlays.deleteOverlay(cursor); - Controller.releaseKeyEvents({text: "SPACE"}); + Overlays.deleteOverlay(text); + Controller.releaseKeyEvents({key: 32}); } - -Controller.captureKeyEvents({text: "SPACE"}); +Controller.captureKeyEvents({key: 32}); Controller.keyPressEvent.connect(keyPressEvent); +Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From fefe9bdb8768a75a86724d977f22443bd1b42475 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 20 Nov 2014 22:40:49 +0100 Subject: [PATCH 005/100] virtual-keyboard: rescale-able --- examples/virtualKeyboard.js | 60 ++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index e99a70faed..d7065e8c76 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -37,6 +37,7 @@ const BOUND_H = 3; const KEY_STATE_LOWER = 0; const KEY_STATE_UPPER = 1; +var windowDimensions = Controller.getViewportDimensions(); var cursor = null; var keyboard = new Keyboard(); var text = null; @@ -49,7 +50,7 @@ keyboard.onFullyLoaded = function() { print("Virtual-keyboard fully loaded."); var dimensions = Controller.getViewportDimensions(); text = Overlays.addOverlay("text", { - x: 0,//(dimensions.x / 2) - (KEYBOARD_WIDTH / 2), + x: 0, y: dimensions.y - keyboard.height() - 60, width: dimensions.x, height: 50, @@ -129,11 +130,13 @@ function KeyboardKey(keyboard, key_properties) { }); } }; - this.updatePosition = function() { + this.rescale = function() { for (var i = 0; i < tthis.bounds.length; i++) { Overlays.editOverlay(tthis.overlays[i], { - x: tthis.keyboard.x + tthis.bounds[i][BOUND_X], - y: tthis.keyboard.y + tthis.bounds[i][BOUND_Y], + x: tthis.keyboard.getX() + tthis.bounds[i][BOUND_X] * keyboard.scale, + y: tthis.keyboard.getY() + tthis.bounds[i][BOUND_Y] * keyboard.scale, + width: this.bounds[i][BOUND_W] * keyboard.scale, + height: this.bounds[i][BOUND_H] * keyboard.scale }); } }; @@ -153,8 +156,8 @@ function KeyboardKey(keyboard, key_properties) { for (var i = 0; i < this.bounds.length; i++) { var newOverlay = Overlays.cloneOverlay(this.keyboard.background); Overlays.editOverlay(newOverlay, { - x: this.keyboard.x + this.bounds[i][BOUND_X] * keyboard.scale, - y: this.keyboard.y + this.bounds[i][BOUND_Y] * keyboard.scale, + x: this.keyboard.getX() + this.bounds[i][BOUND_X] * keyboard.scale, + y: this.keyboard.getY() + this.bounds[i][BOUND_Y] * keyboard.scale, width: this.bounds[i][BOUND_W] * keyboard.scale, height: this.bounds[i][BOUND_H] * keyboard.scale, subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.key_state) + this.bounds[i][BOUND_Y]}, @@ -166,9 +169,8 @@ function KeyboardKey(keyboard, key_properties) { function Keyboard() { var tthis = this; - var dimensions = Controller.getViewportDimensions(); this.focussed_key = -1; - this.scale = dimensions.x / KEYBOARD_WIDTH; + this.scale = windowDimensions.x / KEYBOARD_WIDTH; this.shift = false; this.width = function() { return KEYBOARD_WIDTH * tthis.scale; @@ -176,22 +178,38 @@ function Keyboard() { this.height = function() { return KEYBOARD_HEIGHT * tthis.scale; }; - this.x = (dimensions.x / 2) - (this.width() / 2); - this.y = dimensions.y - this.height(); + this.getX = function() { + return (windowDimensions.x / 2) - (this.width() / 2); + }; + this.getY = function() { + return windowDimensions.y - this.height(); + }; this.background = Overlays.addOverlay("image", { - x: this.x, - y: this.y, + x: this.getX(), + y: this.getY(), width: this.width(), height: this.height(), subImage: {width: KEYBOARD_WIDTH, height: KEYBOARD_HEIGHT, y: KEYBOARD_HEIGHT * KBD_BACKGROUND}, imageURL: KEYBOARD_URL, alpha: 1 }); + this.rescale = function() { + this.scale = windowDimensions.x / KEYBOARD_WIDTH; + Overlays.editOverlay(tthis.background, { + x: this.getX(), + y: this.getY(), + width: this.width(), + height: this.height() + }); + for (var i = 0; i < tthis.keys.length; i++) { + tthis.keys[i].rescale(); + } + }; this.setFocusPosition = function(x, y) { // set to local unscaled position - var localx = (x - tthis.x) / tthis.scale; - var localy = (y - tthis.y) / tthis.scale; + var localx = (x - tthis.getX()) / tthis.scale; + var localy = (y - tthis.getY()) / tthis.scale; var new_focus_key = -1; if (localx >= 0 && localy >= 0 && localx <= KEYBOARD_WIDTH && localy <= KEYBOARD_HEIGHT) { for (var i = 0; i < tthis.keys.length; i++) { @@ -382,16 +400,24 @@ function Cursor() { }; this.onUpdate = null; this.update = function() { - var dimensions = Controller.getViewportDimensions(); + var newWindowDimensions = Controller.getViewportDimensions(); + if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) { + windowDimensions = newWindowDimensions; + keyboard.rescale(); + Overlays.editOverlay(text, { + y: windowDimensions.y - keyboard.height() - 60, + width: windowDimensions.x + }); + } var editobject = {}; if (MyAvatar.getHeadFinalYaw() <= VIEW_ANGLE_BY_TWO && MyAvatar.getHeadFinalYaw() >= -1 * VIEW_ANGLE_BY_TWO) { angle = ((-1 * MyAvatar.getHeadFinalYaw()) + VIEW_ANGLE_BY_TWO) / VIEW_ANGLE; - tthis.x = angle * dimensions.x; + tthis.x = angle * windowDimensions.x; editobject.x = tthis.x - (CURSOR_WIDTH / 2); } if (MyAvatar.getHeadFinalPitch() <= VIEW_ANGLE_BY_TWO && MyAvatar.getHeadFinalPitch() >= -1 * VIEW_ANGLE_BY_TWO) { angle = ((-1 * MyAvatar.getHeadFinalPitch()) + VIEW_ANGLE_BY_TWO) / VIEW_ANGLE; - tthis.y = angle * dimensions.y; + tthis.y = angle * windowDimensions.y; editobject.y = tthis.y - (CURSOR_HEIGHT / 2); } if (Object.keys(editobject).length > 0) { From 2b57f68857530b5b630558aa60c9abd5e1532656 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 21 Nov 2014 02:07:11 +0100 Subject: [PATCH 006/100] virtual-keyboard: - shift key functions - keys show pressed while pressing them - keyboard.onKeyPress and onKeyRelease are functional --- examples/virtualKeyboard.js | 64 +++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index d7065e8c76..ce3677bec3 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -26,7 +26,9 @@ const KEYBOARD_HEIGHT = 434.1; const CURSOR_WIDTH = 33.9; const CURSOR_HEIGHT = 33.9; -const VIEW_ANGLE = 60.0; +// VIEW_ANGLE can be adjusted to your likings, the smaller the faster movement. +// Try setting it to 60 if it goes too fast for you. +const VIEW_ANGLE = 30.0; const VIEW_ANGLE_BY_TWO = VIEW_ANGLE / 2; const BOUND_X = 0; @@ -81,7 +83,12 @@ function KeyboardKey(keyboard, key_properties) { this.key_state = key_properties.key_state != undefined ? key_properties.key_state : KBD_LOWERCASE_DEFAULT; // one overlay per bound vector [this.bounds] this.overlays = []; - this.updatePosition = function() { + this.getKeyEvent = function() { + if (tthis.event == 'keypress') { + var state = tthis.states[(tthis.keyboard.shift ? 1 : 2) % tthis.states.length]; + return {key: state.charCode, char: state.char, event: tthis.event}; + } + return {event: tthis.event}; }; this.containsCoord = function(x, y) { for (var i = 0; i < this.bounds.length; i++) { @@ -99,7 +106,7 @@ function KeyboardKey(keyboard, key_properties) { tthis.setState(eval('KBD_' + (tthis.keyboard.shift ? 'UPPERCASE' : 'LOWERCASE') + '_' + (tthis._focus ? 'HOVER' : 'DEFAULT'))); }; this.updateColor = function() { - var colorIntensity = _beingpressed ? 128 : 255; + var colorIntensity = this._beingpressed ? 128 : 255; for (var i = 0; i < tthis.bounds.length; i++) { Overlays.editOverlay(tthis.overlays[i], {color: {red: colorIntensity, green: colorIntensity, blue: colorIntensity}} @@ -221,7 +228,6 @@ function Keyboard() { } } if (new_focus_key != tthis.focussed_key) { - //print(new_focus_key); if (tthis.focussed_key != -1) { tthis.keys[tthis.focussed_key].blur(); } @@ -235,14 +241,44 @@ function Keyboard() { this.pressFocussedKey = function() { if (tthis.focussed_key != -1) { - this.onKeyPress(tthis.keys[tthis.focussed_key]); + if (tthis.keys[tthis.focussed_key].event == 'shift') { + tthis.toggleShift(); + } else { + tthis.keys[tthis.focussed_key].press(); + } + if (this.onKeyPress != null) { + this.onKeyPress(tthis.keys[tthis.focussed_key].getKeyEvent()); + } } return tthis; }; - - this.updatePosition = function() { - + + this.releaseKeys = function() { + for (var i = 0; i < tthis.keys.length; i++) { + if (tthis.keys[i]._beingpressed) { + if (tthis.keys[i].event != 'shift') { + tthis.keys[i].release(); + } + if (this.onKeyRelease != null) { + this.onKeyRelease(tthis.keys[i].getKeyEvent()); + } + } + } + }; + + this.toggleShift = function() { + tthis.shift = !tthis.shift; + for (var i = 0; i < tthis.keys.length; i++) { + tthis.keys[i].updateState(); + if (tthis.keys[i].event == 'shift') { + if (tthis.shift) { + tthis.keys[i].press(); + continue; + } + tthis.keys[i].release(); + } + } }; this.getFocussedKey = function() { @@ -260,8 +296,7 @@ function Keyboard() { }; this.onKeyPress = null; - this.onKeyDown = null; - this.onKeyUp = null; + this.onKeyRelease = null; this.onSubmit = null; this.onFullyLoaded = null; @@ -354,7 +389,7 @@ function Keyboard() { {bounds: [[972, 283, 190, 63]], event: 'shift'}, - {bounds: [[249, 355, 573, 67]], states: [{charCode: 192, char: ' '}]}, + {bounds: [[249, 355, 573, 67]], states: [{charCode: 32, char: ' '}]}, {bounds: [[899, 355, 263, 67]], event: 'submit'} ]; @@ -375,9 +410,8 @@ function Keyboard() { function Cursor() { var tthis = this; - var dimensions = Controller.getViewportDimensions(); - this.x = dimensions.x / 2; - this.y = dimensions.y / 2; + this.x = windowDimensions.x / 2; + this.y = windowDimensions.y / 2; this.overlay = Overlays.addOverlay("image", { x: this.x, y: this.y, @@ -433,12 +467,14 @@ function Cursor() { function keyPressEvent(key) { if (key.text === "SPACE") { print("pressed space"); + keyboard.pressFocussedKey(); } } function keyReleaseEvent(key) { if (key.text === "SPACE") { print("released space"); + keyboard.releaseKeys(); } } From a60374e4c11de48cb8ed713d684226d5f518d33a Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 21 Nov 2014 02:59:05 +0100 Subject: [PATCH 007/100] virtual-keyboard: added text-entity example --- examples/virtualKeyboard.js | 86 ++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index ce3677bec3..5829a4fd2b 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -6,6 +6,10 @@ // Copyright 2014 High Fidelity, Inc. // // Control a virtual keyboard using your favorite HMD. +// Usage: Enable VR-mode and go to First person mode, +// look at the key that you would like to press, and press the spacebar on your "REAL" keyboard. +// +// leased some code from newEditEntities.js for Text Entity example // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -20,6 +24,8 @@ const KBD_BACKGROUND = 4; const KEYBOARD_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/keyboard.svg"; const CURSOR_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/cursor.svg"; +const SPACEBAR_CHARCODE = 32; + const KEYBOARD_WIDTH = 1174.7; const KEYBOARD_HEIGHT = 434.1; @@ -31,6 +37,11 @@ const CURSOR_HEIGHT = 33.9; const VIEW_ANGLE = 30.0; const VIEW_ANGLE_BY_TWO = VIEW_ANGLE / 2; +const SPAWN_DISTANCE = 1; +const DEFAULT_TEXT_DIMENSION_X = 1; +const DEFAULT_TEXT_DIMENSION_Y = 1; +const DEFAULT_TEXT_DIMENSION_Z = 0.02; + const BOUND_X = 0; const BOUND_Y = 1; const BOUND_W = 2; @@ -43,9 +54,55 @@ var windowDimensions = Controller.getViewportDimensions(); var cursor = null; var keyboard = new Keyboard(); var text = null; +var textText = ""; +function appendChar(char) { + textText += char; + updateTextOverlay(); + Overlays.editOverlay(text, {text: textText}); +} +function deleteChar() { + if (textText.length > 0) { + textText = textText.substring(0, textText.length - 1); + updateTextOverlay(); + } +} +function updateTextOverlay() { + Overlays.editOverlay(text, {text: textText}); +} +keyboard.onKeyPress = function(event) { + if (event.event == 'keypress') { + appendChar(event.char); + } else if (event.event == 'enter') { + appendChar("\n"); + } +}; -keyboard.onKeyPress = function() { - print("Key press event test"); +keyboard.onKeyRelease = function(event) { + print("Key release event test"); + // you can cancel a key by releasing its focusing before releasing it + if (event.focus) { + if (event.event == 'delete') { + deleteChar(); + } else if (event.event == 'submit') { + print(textText); + + var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); + + if (position.x > 0 && position.y > 0 && position.z > 0) { + Entities.addEntity({ + type: "Text", + position: position, + dimensions: { x: DEFAULT_TEXT_DIMENSION_X, y: DEFAULT_TEXT_DIMENSION_Y, z: DEFAULT_TEXT_DIMENSION_Z }, + backgroundColor: { red: 0, green: 0, blue: 0 }, + textColor: { red: 255, green: 255, blue: 255 }, + text: textText, + lineHight: "0.1" + }); + } + textText = ""; + updateTextOverlay(); + } + } }; keyboard.onFullyLoaded = function() { @@ -53,9 +110,9 @@ keyboard.onFullyLoaded = function() { var dimensions = Controller.getViewportDimensions(); text = Overlays.addOverlay("text", { x: 0, - y: dimensions.y - keyboard.height() - 60, + y: dimensions.y - keyboard.height() - 260, width: dimensions.x, - height: 50, + height: 250, backgroundColor: { red: 255, green: 255, blue: 255}, color: { red: 0, green: 0, blue: 0}, topMargin: 10, @@ -86,9 +143,9 @@ function KeyboardKey(keyboard, key_properties) { this.getKeyEvent = function() { if (tthis.event == 'keypress') { var state = tthis.states[(tthis.keyboard.shift ? 1 : 2) % tthis.states.length]; - return {key: state.charCode, char: state.char, event: tthis.event}; + return {key: state.charCode, char: state.char, event: tthis.event, focus: tthis._focus}; } - return {event: tthis.event}; + return {event: tthis.event, focus: tthis._focus}; }; this.containsCoord = function(x, y) { for (var i = 0; i < this.bounds.length; i++) { @@ -221,7 +278,6 @@ function Keyboard() { if (localx >= 0 && localy >= 0 && localx <= KEYBOARD_WIDTH && localy <= KEYBOARD_HEIGHT) { for (var i = 0; i < tthis.keys.length; i++) { if (tthis.keys[i].containsCoord(localx, localy)) { - //print(tthis.keys[i].states[0].char); new_focus_key = i; break; } @@ -439,7 +495,7 @@ function Cursor() { windowDimensions = newWindowDimensions; keyboard.rescale(); Overlays.editOverlay(text, { - y: windowDimensions.y - keyboard.height() - 60, + y: windowDimensions.y - keyboard.height() - 260, width: windowDimensions.x }); } @@ -464,16 +520,14 @@ function Cursor() { Script.update.connect(this.update); } -function keyPressEvent(key) { - if (key.text === "SPACE") { - print("pressed space"); +function keyPressEvent(event) { + if (event.key === SPACEBAR_CHARCODE) { keyboard.pressFocussedKey(); } } -function keyReleaseEvent(key) { - if (key.text === "SPACE") { - print("released space"); +function keyReleaseEvent(event) { + if (event.key === SPACEBAR_CHARCODE) { keyboard.releaseKeys(); } } @@ -482,9 +536,9 @@ function scriptEnding() { keyboard.remove(); cursor.remove(); Overlays.deleteOverlay(text); - Controller.releaseKeyEvents({key: 32}); + Controller.releaseKeyEvents({key: SPACEBAR_CHARCODE}); } -Controller.captureKeyEvents({key: 32}); +Controller.captureKeyEvents({key: SPACEBAR_CHARCODE}); Controller.keyPressEvent.connect(keyPressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From e12f64bae41fe6d037fa4d2e4589048c56b7182d Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sun, 23 Nov 2014 17:15:14 +0100 Subject: [PATCH 008/100] virtual-keyboard: - added keycodes - resizes the example text entity based on text size - adds the author of the text entity in the bottom right corner --- examples/virtualKeyboard.js | 171 +++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 72 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 5829a4fd2b..cd2ce9f7ba 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -38,8 +38,6 @@ const VIEW_ANGLE = 30.0; const VIEW_ANGLE_BY_TWO = VIEW_ANGLE / 2; const SPAWN_DISTANCE = 1; -const DEFAULT_TEXT_DIMENSION_X = 1; -const DEFAULT_TEXT_DIMENSION_Y = 1; const DEFAULT_TEXT_DIMENSION_Z = 0.02; const BOUND_X = 0; @@ -50,11 +48,18 @@ const BOUND_H = 3; const KEY_STATE_LOWER = 0; const KEY_STATE_UPPER = 1; +const TEXT_MARGIN_TOP = 0.15; +const TEXT_MARGIN_LEFT = 0.15; +const TEXT_MARGIN_RIGHT = 0.17; +const TEXT_MARGIN_BOTTOM = 0.17; + var windowDimensions = Controller.getViewportDimensions(); var cursor = null; var keyboard = new Keyboard(); var text = null; var textText = ""; +var textSizeMeasureOverlay = Overlays.addOverlay("text3d", {visible: false}); + function appendChar(char) { textText += char; updateTextOverlay(); @@ -88,15 +93,36 @@ keyboard.onKeyRelease = function(event) { var position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); + var textLines = textText.split("\n"); + var maxLineWidth = 0; + for (textLine in textLines) { + var lineWidth = Overlays.textWidth(textSizeMeasureOverlay, textLines[textLine]); + if (lineWidth > maxLineWidth) { + maxLineWidth = lineWidth; + } + } + var usernameLine = "--" + GlobalServices.myUsername; + var usernameWidth = Overlays.textWidth(textSizeMeasureOverlay, usernameLine); + if (maxLineWidth < usernameWidth) { + maxLineWidth = usernameWidth; + } else { + var spaceableWidth = maxLineWidth - usernameWidth; + var spaceWidth = Overlays.textWidth(textSizeMeasureOverlay, " "); + var numberOfSpaces = Math.floor(spaceableWidth / spaceWidth); + for (var i = 0; i < numberOfSpaces; i++) { + usernameLine = " " + usernameLine; + } + } + var dimension_x = maxLineWidth + TEXT_MARGIN_RIGHT + TEXT_MARGIN_LEFT; if (position.x > 0 && position.y > 0 && position.z > 0) { Entities.addEntity({ type: "Text", + rotation: MyAvatar.orientation, position: position, - dimensions: { x: DEFAULT_TEXT_DIMENSION_X, y: DEFAULT_TEXT_DIMENSION_Y, z: DEFAULT_TEXT_DIMENSION_Z }, + dimensions: { x: dimension_x, y: (textLines.length + 1) * 0.14 + TEXT_MARGIN_TOP + TEXT_MARGIN_BOTTOM, z: DEFAULT_TEXT_DIMENSION_Z }, backgroundColor: { red: 0, green: 0, blue: 0 }, textColor: { red: 255, green: 255, blue: 255 }, - text: textText, - lineHight: "0.1" + text: textText + "\n" + usernameLine }); } textText = ""; @@ -363,85 +389,85 @@ function Keyboard() { // coords [[x,y,w,h],[x,y,w,h]] // states array of 1 or 2 objects [lowercase, uppercase] each object contains a charCode and a char var keyProperties = [ - {bounds: [[12, 12, 65, 52]], states: [{charCode: 192, char: '~'}]}, - {bounds: [[84, 12, 65, 52]], states: [{charCode: 192, char: '!'}]}, - {bounds: [[156, 12, 65, 52]], states: [{charCode: 192, char: '@'}]}, - {bounds: [[228, 12, 65, 52]], states: [{charCode: 192, char: '#'}]}, - {bounds: [[300, 12, 65, 52]], states: [{charCode: 192, char: '$'}]}, - {bounds: [[372, 12, 65, 52]], states: [{charCode: 192, char: '%'}]}, - {bounds: [[445, 12, 65, 52]], states: [{charCode: 192, char: '^'}]}, - {bounds: [[517, 12, 65, 52]], states: [{charCode: 192, char: '&'}]}, - {bounds: [[589, 12, 65, 52]], states: [{charCode: 192, char: '*'}]}, - {bounds: [[662, 12, 65, 52]], states: [{charCode: 192, char: '('}]}, - {bounds: [[734, 12, 65, 52]], states: [{charCode: 192, char: ')'}]}, - {bounds: [[806, 12, 65, 52]], states: [{charCode: 192, char: '_'}]}, - {bounds: [[881, 12, 65, 52]], states: [{charCode: 192, char: '{'}]}, - {bounds: [[953, 12, 65, 52]], states: [{charCode: 192, char: '}'}]}, - {bounds: [[1025, 12, 65, 52]], states: [{charCode: 192, char: '<'}]}, - {bounds: [[1097, 12, 65, 52]], states: [{charCode: 192, char: '>'}]}, + {bounds: [[12, 12, 65, 52]], states: [{charCode: 126, char: '~'}]}, + {bounds: [[84, 12, 65, 52]], states: [{charCode: 33, char: '!'}]}, + {bounds: [[156, 12, 65, 52]], states: [{charCode: 64, char: '@'}]}, + {bounds: [[228, 12, 65, 52]], states: [{charCode: 35, char: '#'}]}, + {bounds: [[300, 12, 65, 52]], states: [{charCode: 36, char: '$'}]}, + {bounds: [[372, 12, 65, 52]], states: [{charCode: 37, char: '%'}]}, + {bounds: [[445, 12, 65, 52]], states: [{charCode: 94, char: '^'}]}, + {bounds: [[517, 12, 65, 52]], states: [{charCode: 38, char: '&'}]}, + {bounds: [[589, 12, 65, 52]], states: [{charCode: 42, char: '*'}]}, + {bounds: [[662, 12, 65, 52]], states: [{charCode: 40, char: '('}]}, + {bounds: [[734, 12, 65, 52]], states: [{charCode: 41, char: ')'}]}, + {bounds: [[806, 12, 65, 52]], states: [{charCode: 95, char: '_'}]}, + {bounds: [[881, 12, 65, 52]], states: [{charCode: 123, char: '{'}]}, + {bounds: [[953, 12, 65, 52]], states: [{charCode: 125, char: '}'}]}, + {bounds: [[1025, 12, 65, 52]], states: [{charCode: 60, char: '<'}]}, + {bounds: [[1097, 12, 65, 52]], states: [{charCode: 62, char: '>'}]}, - {bounds: [[12, 71, 65, 63]], states: [{charCode: 192, char: '`'}]}, - {bounds: [[84, 71, 65, 63]], states: [{charCode: 192, char: '1'}]}, - {bounds: [[156, 71, 65, 63]], states: [{charCode: 192, char: '2'}]}, - {bounds: [[228, 71, 65, 63]], states: [{charCode: 192, char: '3'}]}, - {bounds: [[300, 71, 65, 63]], states: [{charCode: 192, char: '4'}]}, - {bounds: [[372, 71, 65, 63]], states: [{charCode: 192, char: '5'}]}, - {bounds: [[445, 71, 65, 63]], states: [{charCode: 192, char: '6'}]}, - {bounds: [[517, 71, 65, 63]], states: [{charCode: 192, char: '7'}]}, - {bounds: [[589, 71, 65, 63]], states: [{charCode: 192, char: '8'}]}, - {bounds: [[661, 71, 65, 63]], states: [{charCode: 192, char: '9'}]}, - {bounds: [[733, 71, 65, 63]], states: [{charCode: 192, char: '0'}]}, - {bounds: [[806, 71, 65, 63]], states: [{charCode: 192, char: '-'}]}, - {bounds: [[880, 71, 65, 63]], states: [{charCode: 192, char: '='}]}, - {bounds: [[953, 71, 65, 63]], states: [{charCode: 192, char: '+'}]}, + {bounds: [[12, 71, 65, 63]], states: [{charCode: 96, char: '`'}]}, + {bounds: [[84, 71, 65, 63]], states: [{charCode: 49, char: '1'}]}, + {bounds: [[156, 71, 65, 63]], states: [{charCode: 50, char: '2'}]}, + {bounds: [[228, 71, 65, 63]], states: [{charCode: 51, char: '3'}]}, + {bounds: [[300, 71, 65, 63]], states: [{charCode: 52, char: '4'}]}, + {bounds: [[372, 71, 65, 63]], states: [{charCode: 53, char: '5'}]}, + {bounds: [[445, 71, 65, 63]], states: [{charCode: 54, char: '6'}]}, + {bounds: [[517, 71, 65, 63]], states: [{charCode: 55, char: '7'}]}, + {bounds: [[589, 71, 65, 63]], states: [{charCode: 56, char: '8'}]}, + {bounds: [[661, 71, 65, 63]], states: [{charCode: 57, char: '9'}]}, + {bounds: [[733, 71, 65, 63]], states: [{charCode: 48, char: '0'}]}, + {bounds: [[806, 71, 65, 63]], states: [{charCode: 45, char: '-'}]}, + {bounds: [[880, 71, 65, 63]], states: [{charCode: 61, char: '='}]}, + {bounds: [[953, 71, 65, 63]], states: [{charCode: 43, char: '+'}]}, {bounds: [[1024, 71, 139, 63]], event: 'delete'}, // enter key has 2 bounds and one state {bounds: [[11, 143, 98, 71], [11, 213, 121, 62]], event: 'enter'}, - {bounds: [[118, 142, 64, 63]], states: [{charCode: 192, char: 'q'}, {charCode: 192, char: 'Q'}]}, - {bounds: [[190, 142, 64, 63]], states: [{charCode: 192, char: 'w'}, {charCode: 192, char: 'W'}]}, - {bounds: [[262, 142, 64, 63]], states: [{charCode: 192, char: 'e'}, {charCode: 192, char: 'E'}]}, - {bounds: [[334, 142, 64, 63]], states: [{charCode: 192, char: 'r'}, {charCode: 192, char: 'R'}]}, - {bounds: [[407, 142, 64, 63]], states: [{charCode: 192, char: 't'}, {charCode: 192, char: 'T'}]}, - {bounds: [[479, 142, 64, 63]], states: [{charCode: 192, char: 'y'}, {charCode: 192, char: 'Y'}]}, - {bounds: [[551, 142, 65, 63]], states: [{charCode: 192, char: 'u'}, {charCode: 192, char: 'U'}]}, - {bounds: [[623, 142, 65, 63]], states: [{charCode: 192, char: 'i'}, {charCode: 192, char: 'I'}]}, - {bounds: [[695, 142, 65, 63]], states: [{charCode: 192, char: 'o'}, {charCode: 192, char: 'O'}]}, - {bounds: [[768, 142, 64, 63]], states: [{charCode: 192, char: 'p'}, {charCode: 192, char: 'P'}]}, - {bounds: [[840, 142, 64, 63]], states: [{charCode: 192, char: '['}]}, - {bounds: [[912, 142, 65, 63]], states: [{charCode: 192, char: ']'}]}, - {bounds: [[984, 142, 65, 63]], states: [{charCode: 192, char: '\\'}]}, - {bounds: [[1055, 142, 65, 63]], states: [{charCode: 192, char: '|'}]}, + {bounds: [[118, 142, 64, 63]], states: [{charCode: 113, char: 'q'}, {charCode: 81, char: 'Q'}]}, + {bounds: [[190, 142, 64, 63]], states: [{charCode: 119, char: 'w'}, {charCode: 87, char: 'W'}]}, + {bounds: [[262, 142, 64, 63]], states: [{charCode: 101, char: 'e'}, {charCode: 69, char: 'E'}]}, + {bounds: [[334, 142, 64, 63]], states: [{charCode: 114, char: 'r'}, {charCode: 82, char: 'R'}]}, + {bounds: [[407, 142, 64, 63]], states: [{charCode: 116, char: 't'}, {charCode: 84, char: 'T'}]}, + {bounds: [[479, 142, 64, 63]], states: [{charCode: 121, char: 'y'}, {charCode: 89, char: 'Y'}]}, + {bounds: [[551, 142, 65, 63]], states: [{charCode: 117, char: 'u'}, {charCode: 85, char: 'U'}]}, + {bounds: [[623, 142, 65, 63]], states: [{charCode: 105, char: 'i'}, {charCode: 73, char: 'I'}]}, + {bounds: [[695, 142, 65, 63]], states: [{charCode: 111, char: 'o'}, {charCode: 79, char: 'O'}]}, + {bounds: [[768, 142, 64, 63]], states: [{charCode: 112, char: 'p'}, {charCode: 80, char: 'P'}]}, + {bounds: [[840, 142, 64, 63]], states: [{charCode: 91, char: '['}]}, + {bounds: [[912, 142, 65, 63]], states: [{charCode: 93, char: ']'}]}, + {bounds: [[984, 142, 65, 63]], states: [{charCode: 92, char: '\\'}]}, + {bounds: [[1055, 142, 65, 63]], states: [{charCode: 124, char: '|'}]}, {bounds: [[1126, 143, 35, 72], [1008, 214, 153, 62]], event: 'enter'}, - {bounds: [[140, 213, 65, 63]], states: [{charCode: 192, char: 'a'}, {charCode: 192, char: 'A'}]}, - {bounds: [[211, 213, 64, 63]], states: [{charCode: 192, char: 's'}, {charCode: 192, char: 'S'}]}, - {bounds: [[283, 213, 65, 63]], states: [{charCode: 192, char: 'd'}, {charCode: 192, char: 'D'}]}, - {bounds: [[355, 213, 65, 63]], states: [{charCode: 192, char: 'f'}, {charCode: 192, char: 'F'}]}, - {bounds: [[428, 213, 64, 63]], states: [{charCode: 192, char: 'g'}, {charCode: 192, char: 'G'}]}, - {bounds: [[500, 213, 64, 63]], states: [{charCode: 192, char: 'h'}, {charCode: 192, char: 'H'}]}, - {bounds: [[572, 213, 65, 63]], states: [{charCode: 192, char: 'j'}, {charCode: 192, char: 'J'}]}, - {bounds: [[644, 213, 65, 63]], states: [{charCode: 192, char: 'k'}, {charCode: 192, char: 'K'}]}, - {bounds: [[716, 213, 65, 63]], states: [{charCode: 192, char: 'l'}, {charCode: 192, char: 'L'}]}, - {bounds: [[789, 213, 64, 63]], states: [{charCode: 192, char: ';'}]}, - {bounds: [[861, 213, 64, 63]], states: [{charCode: 192, char: '\''}]}, - {bounds: [[934, 213, 65, 63]], states: [{charCode: 192, char: ':'}]}, + {bounds: [[140, 213, 65, 63]], states: [{charCode: 97, char: 'a'}, {charCode: 65, char: 'A'}]}, + {bounds: [[211, 213, 64, 63]], states: [{charCode: 115, char: 's'}, {charCode: 83, char: 'S'}]}, + {bounds: [[283, 213, 65, 63]], states: [{charCode: 100, char: 'd'}, {charCode: 68, char: 'D'}]}, + {bounds: [[355, 213, 65, 63]], states: [{charCode: 102, char: 'f'}, {charCode: 70, char: 'F'}]}, + {bounds: [[428, 213, 64, 63]], states: [{charCode: 103, char: 'g'}, {charCode: 71, char: 'G'}]}, + {bounds: [[500, 213, 64, 63]], states: [{charCode: 104, char: 'h'}, {charCode: 72, char: 'H'}]}, + {bounds: [[572, 213, 65, 63]], states: [{charCode: 106, char: 'j'}, {charCode: 74, char: 'J'}]}, + {bounds: [[644, 213, 65, 63]], states: [{charCode: 107, char: 'k'}, {charCode: 75, char: 'K'}]}, + {bounds: [[716, 213, 65, 63]], states: [{charCode: 108, char: 'l'}, {charCode: 76, char: 'L'}]}, + {bounds: [[789, 213, 64, 63]], states: [{charCode: 59, char: ';'}]}, + {bounds: [[861, 213, 64, 63]], states: [{charCode: 39, char: '\''}]}, + {bounds: [[934, 213, 65, 63]], states: [{charCode: 58, char: ':'}]}, {bounds: [[12, 283, 157, 63]], event: 'shift'}, - {bounds: [[176, 283, 65, 63]], states: [{charCode: 192, char: 'z'}, {charCode: 192, char: 'Z'}]}, - {bounds: [[249, 283, 64, 63]], states: [{charCode: 192, char: 'x'}, {charCode: 192, char: 'X'}]}, - {bounds: [[321, 283, 64, 63]], states: [{charCode: 192, char: 'c'}, {charCode: 192, char: 'C'}]}, - {bounds: [[393, 283, 64, 63]], states: [{charCode: 192, char: 'v'}, {charCode: 192, char: 'V'}]}, - {bounds: [[465, 283, 65, 63]], states: [{charCode: 192, char: 'b'}, {charCode: 192, char: 'B'}]}, - {bounds: [[537, 283, 65, 63]], states: [{charCode: 192, char: 'n'}, {charCode: 192, char: 'N'}]}, - {bounds: [[610, 283, 64, 63]], states: [{charCode: 192, char: 'm'}, {charCode: 192, char: 'M'}]}, - {bounds: [[682, 283, 64, 63]], states: [{charCode: 192, char: ','}]}, - {bounds: [[754, 283, 65, 63]], states: [{charCode: 192, char: '.'}]}, - {bounds: [[826, 283, 65, 63]], states: [{charCode: 192, char: '/'}]}, - {bounds: [[899, 283, 64, 63]], states: [{charCode: 192, char: '?'}]}, + {bounds: [[176, 283, 65, 63]], states: [{charCode: 122, char: 'z'}, {charCode: 90, char: 'Z'}]}, + {bounds: [[249, 283, 64, 63]], states: [{charCode: 120, char: 'x'}, {charCode: 88, char: 'X'}]}, + {bounds: [[321, 283, 64, 63]], states: [{charCode: 99, char: 'c'}, {charCode: 67, char: 'C'}]}, + {bounds: [[393, 283, 64, 63]], states: [{charCode: 118, char: 'v'}, {charCode: 86, char: 'V'}]}, + {bounds: [[465, 283, 65, 63]], states: [{charCode: 98, char: 'b'}, {charCode: 66, char: 'B'}]}, + {bounds: [[537, 283, 65, 63]], states: [{charCode: 110, char: 'n'}, {charCode: 78, char: 'N'}]}, + {bounds: [[610, 283, 64, 63]], states: [{charCode: 109, char: 'm'}, {charCode: 77, char: 'M'}]}, + {bounds: [[682, 283, 64, 63]], states: [{charCode: 44, char: ','}]}, + {bounds: [[754, 283, 65, 63]], states: [{charCode: 46, char: '.'}]}, + {bounds: [[826, 283, 65, 63]], states: [{charCode: 47, char: '/'}]}, + {bounds: [[899, 283, 64, 63]], states: [{charCode: 63, char: '?'}]}, {bounds: [[972, 283, 190, 63]], event: 'shift'}, @@ -536,6 +562,7 @@ function scriptEnding() { keyboard.remove(); cursor.remove(); Overlays.deleteOverlay(text); + Overlays.deleteOverlay(textSizeMeasureOverlay); Controller.releaseKeyEvents({key: SPACEBAR_CHARCODE}); } Controller.captureKeyEvents({key: SPACEBAR_CHARCODE}); From 3c5f33f0ac06ae0bc86ad49b82146ae36e89be9b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 2 Dec 2014 12:28:04 -0800 Subject: [PATCH 009/100] Hemisphere vbo refactoring --- interface/src/ui/ApplicationOverlay.cpp | 194 ++++++++++++------------ interface/src/ui/ApplicationOverlay.h | 4 +- 2 files changed, 100 insertions(+), 98 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 1307672ad1..e479452fec 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -1129,118 +1129,118 @@ void ApplicationOverlay::renderStatsAndLogs() { nodeBoundsDisplay.drawOverlay(); } -//Renders a hemisphere with texture coordinates. -void ApplicationOverlay::renderTexturedHemisphere() { - const int slices = 80; - const int stacks = 80; - - //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm - static VerticesIndices vbo(0, 0); - int vertices = slices * (stacks - 1) + 1; - int indices = slices * 2 * 3 * (stacks - 2) + slices * 3; - - static float oldTextureFOV = _textureFov; - //We only generate the VBO when the _textureFov changes - if (vbo.first == 0 || oldTextureFOV != _textureFov) { - oldTextureFOV = _textureFov; - TextureVertex* vertexData = new TextureVertex[vertices]; - TextureVertex* vertex = vertexData; - for (int i = 0; i < stacks - 1; i++) { - float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1); - float z = -sinf(phi), radius = cosf(phi); - - for (int j = 0; j < slices; j++) { - float theta = TWO_PI * (float)j / (float)slices; - - vertex->position.x = sinf(theta) * radius; - vertex->position.y = cosf(theta) * radius; - vertex->position.z = z; - vertex->uv.x = asin(vertex->position.x) / (_textureFov) + 0.5f; - vertex->uv.y = asin(vertex->position.y) / (_textureFov) + 0.5f; - vertex++; - } - } - vertex->position.x = 0.0f; - vertex->position.y = 0.0f; - vertex->position.z = -1.0f; - vertex->uv.x = 0.5f; - vertex->uv.y = 0.5f; - vertex++; - - if (vbo.first == 0){ - glGenBuffers(1, &vbo.first); - } - glBindBuffer(GL_ARRAY_BUFFER, vbo.first); - const int BYTES_PER_VERTEX = sizeof(TextureVertex); - glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); - delete[] vertexData; - - GLushort* indexData = new GLushort[indices]; - GLushort* index = indexData; - for (int i = 0; i < stacks - 2; i++) { - GLushort bottom = i * slices; - GLushort top = bottom + slices; - for (int j = 0; j < slices; j++) { - int next = (j + 1) % slices; - - *(index++) = bottom + j; - *(index++) = top + next; - *(index++) = top + j; - - *(index++) = bottom + j; - *(index++) = bottom + next; - *(index++) = top + next; - } - } - GLushort bottom = (stacks - 2) * slices; - GLushort top = bottom + slices; - for (int i = 0; i < slices; i++) { - *(index++) = bottom + i; - *(index++) = bottom + (i + 1) % slices; - *(index++) = top; - } - - glGenBuffers(1, &vbo.second); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); - const int BYTES_PER_INDEX = sizeof(GLushort); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); - delete[] indexData; - - } else { - glBindBuffer(GL_ARRAY_BUFFER, vbo.first); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); +ApplicationOverlay::VerticesIndices* ApplicationOverlay::makeTexturedHemiphereVBO(float fov, + float aspectRatio, + int slices, + int stacks) { + if (fov >= PI) { + qDebug() << "ApplicationOverlay::makeHemiphereVBO(): FOV greater or equal than Pi will create issues"; } + + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm + VerticesIndices* vbo = new VerticesIndices(0, 0); + + // Compute number of vertices needed + int vertices = slices * stacks; + + // Compute vertices positions and texture UV coordinate + TextureVertex* vertexData = new TextureVertex[vertices]; + TextureVertex* vertexPtr = &vertexData[0]; + for (int i = 0; i < stacks; i++) { + float stacksRatio = (float)i / (float)stacks; // First stack is 0.0f, last stack is 1.0f + // abs(phi) <= fov / 2.0f + float phi = fov * (stacksRatio - 0.5f); + + for (int j = 0; j < slices; j++) { + float slicesRatio = (float)j / (float)slices; // First slice is 0.0f, last slice is 1.0f + // abs(theta) <= fov * aspectRatio / 2.0f + float theta = fov * aspectRatio * (slicesRatio - 0.5f); + + vertexPtr->position.x = -sinf(theta); + vertexPtr->position.y = sinf(phi); + vertexPtr->position.z = cosf(theta); + vertexPtr->uv.x = slicesRatio; + vertexPtr->uv.y = 1.0f - stacksRatio; + vertexPtr++; + } + } + // Create and write to buffer + glGenBuffers(1, &vbo->first); + glBindBuffer(GL_ARRAY_BUFFER, vbo->first); + static const int BYTES_PER_VERTEX = sizeof(TextureVertex); + glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + delete[] vertexData; + + + // Compute number of indices needed + static const int VERTEX_PER_TRANGLE = 3; + static const int TRIANGLE_PER_RECTANGLE = 2; + int numberOfRectangles = (slices - 1) * (stacks - 1); + int indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; + + // Compute indices order + GLushort* indexData = new GLushort[indices]; + GLushort* indexPtr = indexData; + for (int i = 0; i < stacks - 1; i++) { + for (int j = 0; j < slices - 1; j++) { + GLushort bottomLeftIndex = i * slices + j; + GLushort bottomRightIndex = bottomLeftIndex + 1; + GLushort topLeftIndex = bottomLeftIndex + slices; + GLushort topRightIndex = topLeftIndex + 1; + + *(indexPtr++) = topLeftIndex; + *(indexPtr++) = bottomLeftIndex; + *(indexPtr++) = topRightIndex; + + *(indexPtr++) = topRightIndex; + *(indexPtr++) = bottomLeftIndex; + *(indexPtr++) = bottomRightIndex; + } + } + // Create and write to buffer + glGenBuffers(1, &vbo->second); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo->second); + static const int BYTES_PER_INDEX = sizeof(GLushort); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + delete[] indexData; + + return vbo; +} + +//Renders a hemisphere with texture coordinates. +void ApplicationOverlay::renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices) { + glBindBuffer(GL_ARRAY_BUFFER, vbo->first); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo->second); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(TextureVertex), (void*)0); - glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex), (void*)12); + static const int STRIDE = sizeof(TextureVertex); + static const void* VERTEX_POINTER = 0; + static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); + glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); + glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); - glPushMatrix(); - Application* application = Application::getInstance(); - MyAvatar* myAvatar = application->getAvatar(); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); const glm::quat& orientation = myAvatar->getOrientation(); const glm::vec3& position = myAvatar->getDefaultEyePosition(); - - glm::mat4 rotation = glm::toMat4(orientation); - - glTranslatef(position.x, position.y, position.z); - glMultMatrixf(&rotation[0][0]); - const float scale = _oculusuiRadius * myAvatar->getScale(); - glScalef(scale, scale, scale); - - glDrawRangeElements(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0); - - glPopMatrix(); + + glPushMatrix(); { + glTranslatef(position.x, position.y, position.z); + glm::mat4 rotation = glm::toMat4(orientation); + glMultMatrixf(&rotation[0][0]); + glScalef(scale, scale, scale); + + glDrawRangeElements(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0); + } glPopMatrix(); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } void ApplicationOverlay::renderDomainConnectionStatusBorder() { diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index a493f6cd1b..94100d094c 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -55,8 +55,10 @@ private: void renderMagnifier(int mouseX, int mouseY, float sizeMult, bool showBorder) const; void renderAudioMeter(); void renderStatsAndLogs(); - void renderTexturedHemisphere(); void renderDomainConnectionStatusBorder(); + + VerticesIndices* makeTexturedHemiphereVBO(float fov, float aspectRatio, int slices, int stacks); + void renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices); QOpenGLFramebufferObject* _framebufferObject; float _trailingAudioLoudness; From bf21376c90f66d557f34dda723b7fb7894355ccd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 2 Dec 2014 13:34:11 -0800 Subject: [PATCH 010/100] TexturedHemisphere class --- interface/src/ui/ApplicationOverlay.cpp | 608 ++++++++++++------------ interface/src/ui/ApplicationOverlay.h | 38 +- 2 files changed, 342 insertions(+), 304 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e479452fec..f5396c72f0 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -27,20 +27,16 @@ const float MAG_SPEED = 0.08f; const quint64 MSECS_TO_USECS = 1000ULL; -// Fast helper functions -inline float max(float a, float b) { - return (a > b) ? a : b; -} +const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; +const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; -inline float min(float a, float b) { - return (a < b) ? a : b; -} +const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; +const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; -ApplicationOverlay::ApplicationOverlay() : - _framebufferObject(NULL), - _textureFov(DEFAULT_OCULUS_UI_ANGULAR_SIZE * RADIANS_PER_DEGREE), +ApplicationOverlay::ApplicationOverlay() : + _textureFov(glm::radians(DEFAULT_OCULUS_UI_ANGULAR_SIZE)), _alpha(1.0f), - _oculusuiRadius(1.0f), + _oculusUIRadius(1.0f), _crosshairTexture(0) { memset(_reticleActive, 0, sizeof(_reticleActive)); @@ -49,23 +45,14 @@ ApplicationOverlay::ApplicationOverlay() : } ApplicationOverlay::~ApplicationOverlay() { - if (_framebufferObject != NULL) { - delete _framebufferObject; - } } -const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; -const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; - -const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; -const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); - _textureFov = Menu::getInstance()->getOculusUIAngularSize() * RADIANS_PER_DEGREE; + _textureFov = glm::radians(Menu::getInstance()->getOculusUIAngularSize()); Application* application = Application::getInstance(); @@ -86,42 +73,39 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { } } - if (renderToTexture) { - getFramebufferObject()->bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - // Render 2D overlay glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - glLoadIdentity(); - gluOrtho2D(0, glWidget->width(), glWidget->height(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); - - renderAudioMeter(); - - if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { - myAvatar->renderHeadMouse(glWidget->width(), glWidget->height()); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (renderToTexture) { + _overlays.bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - - renderStatsAndLogs(); - - // give external parties a change to hook in - emit application->renderingOverlay(); - - overlays.render2D(); - - renderPointers(); - - renderDomainConnectionStatusBorder(); - - glPopMatrix(); - + + glPushMatrix(); { + glLoadIdentity(); + gluOrtho2D(0, glWidget->width(), glWidget->height(), 0); + + renderAudioMeter(); + + if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { + myAvatar->renderHeadMouse(glWidget->width(), glWidget->height()); + } + + renderStatsAndLogs(); + + // give external parties a change to hook in + emit application->renderingOverlay(); + + overlays.render2D(); + + renderPointers(); + + renderDomainConnectionStatusBorder(); + } glPopMatrix(); glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); @@ -129,7 +113,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); if (renderToTexture) { - getFramebufferObject()->release(); + _overlays.release(); } } @@ -559,7 +543,6 @@ void ApplicationOverlay::renderPointers() { } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); - } void ApplicationOverlay::renderControllerPointers() { @@ -844,118 +827,6 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { glEnable(GL_DEPTH_TEST); } -//Renders a small magnification of the currently bound texture at the coordinates -void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult, bool showBorder) const -{ - Application* application = Application::getInstance(); - GLCanvas* glWidget = application->getGLWidget(); - - const int widgetWidth = glWidget->width(); - const int widgetHeight = glWidget->height(); - - const float magnifyWidth = MAGNIFY_WIDTH * sizeMult; - const float magnifyHeight = MAGNIFY_HEIGHT * sizeMult; - - mouseX -= magnifyWidth / 2; - mouseY -= magnifyHeight / 2; - - float newWidth = magnifyWidth * MAGNIFY_MULT; - float newHeight = magnifyHeight * MAGNIFY_MULT; - - // Magnification Texture Coordinates - float magnifyULeft = mouseX / (float)widgetWidth; - float magnifyURight = (mouseX + magnifyWidth) / (float)widgetWidth; - float magnifyVBottom = 1.0f - mouseY / (float)widgetHeight; - float magnifyVTop = 1.0f - (mouseY + magnifyHeight) / (float)widgetHeight; - - // Coordinates of magnification overlay - float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; - float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; - - // Get position on hemisphere using angle - - //Get new UV coordinates from our magnification window - float newULeft = newMouseX / widgetWidth; - float newURight = (newMouseX + newWidth) / widgetWidth; - float newVBottom = 1.0 - newMouseY / widgetHeight; - float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; - - // Project our position onto the hemisphere using the UV coordinates - float radius = _oculusuiRadius * application->getAvatar()->getScale(); - float radius2 = radius * radius; - - float lX = radius * sin((newULeft - 0.5f) * _textureFov); - float rX = radius * sin((newURight - 0.5f) * _textureFov); - float bY = radius * sin((newVBottom - 0.5f) * _textureFov); - float tY = radius * sin((newVTop - 0.5f) * _textureFov); - - float blZ, tlZ, brZ, trZ; - - float dist; - float discriminant; - - //Bottom Left - dist = sqrt(lX * lX + bY * bY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - blZ = sqrt(discriminant); - } else { - blZ = 0; - } - //Top Left - dist = sqrt(lX * lX + tY * tY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - tlZ = sqrt(discriminant); - } else { - tlZ = 0; - } - //Bottom Right - dist = sqrt(rX * rX + bY * bY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - brZ = sqrt(discriminant); - } else { - brZ = 0; - } - //Top Right - dist = sqrt(rX * rX + tY * tY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - trZ = sqrt(discriminant); - } else { - trZ = 0; - } - - if (showBorder) { - glDisable(GL_TEXTURE_2D); - glLineWidth(1.0f); - //Outer Line - glBegin(GL_LINE_STRIP); - glColor4f(1.0f, 0.0f, 0.0f, _alpha); - - glVertex3f(lX, tY, -tlZ); - glVertex3f(rX, tY, -trZ); - glVertex3f(rX, bY, -brZ); - glVertex3f(lX, bY, -blZ); - glVertex3f(lX, tY, -tlZ); - - glEnd(); - glEnable(GL_TEXTURE_2D); - } - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - glBegin(GL_QUADS); - - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); - - glEnd(); - -} - void ApplicationOverlay::renderAudioMeter() { Application* application = Application::getInstance(); @@ -1129,120 +1000,6 @@ void ApplicationOverlay::renderStatsAndLogs() { nodeBoundsDisplay.drawOverlay(); } -ApplicationOverlay::VerticesIndices* ApplicationOverlay::makeTexturedHemiphereVBO(float fov, - float aspectRatio, - int slices, - int stacks) { - if (fov >= PI) { - qDebug() << "ApplicationOverlay::makeHemiphereVBO(): FOV greater or equal than Pi will create issues"; - } - - //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm - VerticesIndices* vbo = new VerticesIndices(0, 0); - - // Compute number of vertices needed - int vertices = slices * stacks; - - // Compute vertices positions and texture UV coordinate - TextureVertex* vertexData = new TextureVertex[vertices]; - TextureVertex* vertexPtr = &vertexData[0]; - for (int i = 0; i < stacks; i++) { - float stacksRatio = (float)i / (float)stacks; // First stack is 0.0f, last stack is 1.0f - // abs(phi) <= fov / 2.0f - float phi = fov * (stacksRatio - 0.5f); - - for (int j = 0; j < slices; j++) { - float slicesRatio = (float)j / (float)slices; // First slice is 0.0f, last slice is 1.0f - // abs(theta) <= fov * aspectRatio / 2.0f - float theta = fov * aspectRatio * (slicesRatio - 0.5f); - - vertexPtr->position.x = -sinf(theta); - vertexPtr->position.y = sinf(phi); - vertexPtr->position.z = cosf(theta); - vertexPtr->uv.x = slicesRatio; - vertexPtr->uv.y = 1.0f - stacksRatio; - vertexPtr++; - } - } - // Create and write to buffer - glGenBuffers(1, &vbo->first); - glBindBuffer(GL_ARRAY_BUFFER, vbo->first); - static const int BYTES_PER_VERTEX = sizeof(TextureVertex); - glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); - delete[] vertexData; - - - // Compute number of indices needed - static const int VERTEX_PER_TRANGLE = 3; - static const int TRIANGLE_PER_RECTANGLE = 2; - int numberOfRectangles = (slices - 1) * (stacks - 1); - int indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; - - // Compute indices order - GLushort* indexData = new GLushort[indices]; - GLushort* indexPtr = indexData; - for (int i = 0; i < stacks - 1; i++) { - for (int j = 0; j < slices - 1; j++) { - GLushort bottomLeftIndex = i * slices + j; - GLushort bottomRightIndex = bottomLeftIndex + 1; - GLushort topLeftIndex = bottomLeftIndex + slices; - GLushort topRightIndex = topLeftIndex + 1; - - *(indexPtr++) = topLeftIndex; - *(indexPtr++) = bottomLeftIndex; - *(indexPtr++) = topRightIndex; - - *(indexPtr++) = topRightIndex; - *(indexPtr++) = bottomLeftIndex; - *(indexPtr++) = bottomRightIndex; - } - } - // Create and write to buffer - glGenBuffers(1, &vbo->second); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo->second); - static const int BYTES_PER_INDEX = sizeof(GLushort); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); - delete[] indexData; - - return vbo; -} - -//Renders a hemisphere with texture coordinates. -void ApplicationOverlay::renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices) { - glBindBuffer(GL_ARRAY_BUFFER, vbo->first); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo->second); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - static const int STRIDE = sizeof(TextureVertex); - static const void* VERTEX_POINTER = 0; - static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); - glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); - glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); - - - MyAvatar* myAvatar = Application::getInstance()->getAvatar(); - const glm::quat& orientation = myAvatar->getOrientation(); - const glm::vec3& position = myAvatar->getDefaultEyePosition(); - const float scale = _oculusuiRadius * myAvatar->getScale(); - - glPushMatrix(); { - glTranslatef(position.x, position.y, position.z); - glm::mat4 rotation = glm::toMat4(orientation); - glMultMatrixf(&rotation[0][0]); - glScalef(scale, scale, scale); - - glDrawRangeElements(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0); - } glPopMatrix(); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - void ApplicationOverlay::renderDomainConnectionStatusBorder() { NodeList* nodeList = NodeList::getInstance(); @@ -1267,22 +1024,281 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { } } -QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { - QSize size = Application::getInstance()->getGLWidget()->getDeviceSize(); - if (!_framebufferObject || _framebufferObject->size() != size) { - - delete _framebufferObject; - - _framebufferObject = new QOpenGLFramebufferObject(size); - glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_2D, 0); +//Renders a small magnification of the currently bound texture at the coordinates +void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult, bool showBorder) const { + Application* application = Application::getInstance(); + GLCanvas* glWidget = application->getGLWidget(); + + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); + + const float magnifyWidth = MAGNIFY_WIDTH * sizeMult; + const float magnifyHeight = MAGNIFY_HEIGHT * sizeMult; + + mouseX -= magnifyWidth / 2; + mouseY -= magnifyHeight / 2; + + float newWidth = magnifyWidth * MAGNIFY_MULT; + float newHeight = magnifyHeight * MAGNIFY_MULT; + + // Magnification Texture Coordinates + float magnifyULeft = mouseX / (float)widgetWidth; + float magnifyURight = (mouseX + magnifyWidth) / (float)widgetWidth; + float magnifyVBottom = 1.0f - mouseY / (float)widgetHeight; + float magnifyVTop = 1.0f - (mouseY + magnifyHeight) / (float)widgetHeight; + + // Coordinates of magnification overlay + float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; + float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; + + // Get position on hemisphere using angle + + //Get new UV coordinates from our magnification window + float newULeft = newMouseX / widgetWidth; + float newURight = (newMouseX + newWidth) / widgetWidth; + float newVBottom = 1.0 - newMouseY / widgetHeight; + float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; + + // Project our position onto the hemisphere using the UV coordinates + float radius = _oculusuiRadius * application->getAvatar()->getScale(); + float radius2 = radius * radius; + + float lX = radius * sin((newULeft - 0.5f) * _textureFov); + float rX = radius * sin((newURight - 0.5f) * _textureFov); + float bY = radius * sin((newVBottom - 0.5f) * _textureFov); + float tY = radius * sin((newVTop - 0.5f) * _textureFov); + + float blZ, tlZ, brZ, trZ; + + float dist; + float discriminant; + + //Bottom Left + dist = sqrt(lX * lX + bY * bY); + discriminant = radius2 - dist * dist; + if (discriminant > 0) { + blZ = sqrt(discriminant); + } else { + blZ = 0; } - return _framebufferObject; + //Top Left + dist = sqrt(lX * lX + tY * tY); + discriminant = radius2 - dist * dist; + if (discriminant > 0) { + tlZ = sqrt(discriminant); + } else { + tlZ = 0; + } + //Bottom Right + dist = sqrt(rX * rX + bY * bY); + discriminant = radius2 - dist * dist; + if (discriminant > 0) { + brZ = sqrt(discriminant); + } else { + brZ = 0; + } + //Top Right + dist = sqrt(rX * rX + tY * tY); + discriminant = radius2 - dist * dist; + if (discriminant > 0) { + trZ = sqrt(discriminant); + } else { + trZ = 0; + } + + if (showBorder) { + glDisable(GL_TEXTURE_2D); + glLineWidth(1.0f); + //Outer Line + glBegin(GL_LINE_STRIP); + glColor4f(1.0f, 0.0f, 0.0f, _alpha); + + glVertex3f(lX, tY, -tlZ); + glVertex3f(rX, tY, -trZ); + glVertex3f(rX, bY, -brZ); + glVertex3f(lX, bY, -blZ); + glVertex3f(lX, tY, -tlZ); + + glEnd(); + glEnable(GL_TEXTURE_2D); + } + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + glBegin(GL_QUADS); + + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); + + glEnd(); + +} + +ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : + _vertices(0), + _indices(0), + _framebufferObject(NULL), + _vbo(0, 0) { +} + +ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() { + cleanupVBO(); + if (_framebufferObject != NULL) { + delete _framebufferObject; + } +} + +void ApplicationOverlay::TexturedHemisphere::bind() { + if (_framebufferObject != NULL) { + _framebufferObject->bind(); + } +} + +void ApplicationOverlay::TexturedHemisphere::release() { + if (_framebufferObject != NULL) { + _framebufferObject->release(); + } +} + +void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, + const float aspectRatio, + const int slices, + const int stacks) { + if (fov >= PI) { + qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; + } + // Cleanup old VBO if necessary + cleanupVBO(); + + //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm + + // Compute number of vertices needed + _vertices = slices * stacks; + + // Compute vertices positions and texture UV coordinate + TextureVertex* vertexData = new TextureVertex[_vertices]; + TextureVertex* vertexPtr = &vertexData[0]; + for (int i = 0; i < stacks; i++) { + float stacksRatio = (float)i / (float)stacks; // First stack is 0.0f, last stack is 1.0f + // abs(phi) <= fov / 2.0f + float phi = fov * (stacksRatio - 0.5f); + + for (int j = 0; j < slices; j++) { + float slicesRatio = (float)j / (float)slices; // First slice is 0.0f, last slice is 1.0f + // abs(theta) <= fov * aspectRatio / 2.0f + float theta = fov * aspectRatio * (slicesRatio - 0.5f); + + vertexPtr->position.x = -sinf(theta); + vertexPtr->position.y = sinf(phi); + vertexPtr->position.z = cosf(theta); + vertexPtr->uv.x = slicesRatio; + vertexPtr->uv.y = 1.0f - stacksRatio; + vertexPtr++; + } + } + // Create and write to buffer + glGenBuffers(1, &_vbo.first); + glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); + static const int BYTES_PER_VERTEX = sizeof(TextureVertex); + glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + delete[] vertexData; + + + // Compute number of indices needed + static const int VERTEX_PER_TRANGLE = 3; + static const int TRIANGLE_PER_RECTANGLE = 2; + int numberOfRectangles = (slices - 1) * (stacks - 1); + _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; + + // Compute indices order + GLushort* indexData = new GLushort[_indices]; + GLushort* indexPtr = indexData; + for (int i = 0; i < stacks - 1; i++) { + for (int j = 0; j < slices - 1; j++) { + GLushort bottomLeftIndex = i * slices + j; + GLushort bottomRightIndex = bottomLeftIndex + 1; + GLushort topLeftIndex = bottomLeftIndex + slices; + GLushort topRightIndex = topLeftIndex + 1; + + *(indexPtr++) = topLeftIndex; + *(indexPtr++) = bottomLeftIndex; + *(indexPtr++) = topRightIndex; + + *(indexPtr++) = topRightIndex; + *(indexPtr++) = bottomLeftIndex; + *(indexPtr++) = bottomRightIndex; + } + } + // Create and write to buffer + glGenBuffers(1, &_vbo.second); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); + static const int BYTES_PER_INDEX = sizeof(GLushort); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + delete[] indexData; +} + +void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { + if (_vbo.first != 0) { + glDeleteBuffers(1, &_vbo.first); + _vbo.first = 0; + } + if (_vbo.second != 0) { + glDeleteBuffers(1, &_vbo.second); + _vbo.second = 0; + } +} + +void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject(const QSize& size) { + if (_framebufferObject != NULL) { + delete _framebufferObject; + } + + _framebufferObject = new QOpenGLFramebufferObject(size); + glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + glBindTexture(GL_TEXTURE_2D, 0); +} + +//Renders a hemisphere with texture coordinates. +void ApplicationOverlay::TexturedHemisphere::render(const glm::quat& orientation, const glm::vec3& position, const float scale) { + if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) { + qDebug() << "TexturedHemisphere::render(): Incorrect initialisation"; + return; + } + + _framebufferObject->bind(); + glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + static const int STRIDE = sizeof(TextureVertex); + static const void* VERTEX_POINTER = 0; + static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); + glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); + glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); + + glPushMatrix(); { + glTranslatef(position.x, position.y, position.z); + glm::mat4 rotation = glm::toMat4(orientation); + glMultMatrixf(&rotation[0][0]); + glScalef(scale, scale, scale); + + glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); + } glPopMatrix(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + _framebufferObject->release(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 94100d094c..94fc4e4958 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -37,7 +37,6 @@ public: // Getters - QOpenGLFramebufferObject* getFramebufferObject(); float getAlpha() const { return _alpha; } private: @@ -48,7 +47,31 @@ private: }; typedef QPair VerticesIndices; - + class TexturedHemisphere { + public: + TexturedHemisphere(); + ~TexturedHemisphere(); + + void bind(); + void release(); + + void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); + void buildFramebufferObject(const QSize& size); + void render(const glm::quat& orientation, const glm::vec3& position, const float scale); + + private: + void cleanupVBO(); + + GLuint _vertices; + GLuint _indices; + QOpenGLFramebufferObject* _framebufferObject; + VerticesIndices _vbo; + }; + + VerticesIndices* makeTexturedHemiphereVBO(float fov, float aspectRatio, int slices, int stacks); + void renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices); + QOpenGLFramebufferObject* newFramebufferObject(QSize& size); + void renderPointers(); void renderControllerPointers(); void renderPointersOculus(const glm::vec3& eyePos); @@ -56,15 +79,14 @@ private: void renderAudioMeter(); void renderStatsAndLogs(); void renderDomainConnectionStatusBorder(); - - VerticesIndices* makeTexturedHemiphereVBO(float fov, float aspectRatio, int slices, int stacks); - void renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices); - QOpenGLFramebufferObject* _framebufferObject; + TexturedHemisphere _overlays; + TexturedHemisphere _reticule; + float _trailingAudioLoudness; float _textureFov; - enum MagnifyDevices { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_MAGNIFIERS = RIGHT_CONTROLLER + 1 }; + enum MagnifyDevices { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_MAGNIFIERS }; bool _reticleActive[NUMBER_OF_MAGNIFIERS]; int _mouseX[NUMBER_OF_MAGNIFIERS]; int _mouseY[NUMBER_OF_MAGNIFIERS]; @@ -74,7 +96,7 @@ private: float _magSizeMult[NUMBER_OF_MAGNIFIERS]; float _alpha; - float _oculusuiRadius; + float _oculusUIRadius; GLuint _crosshairTexture; }; From 73004d1beee351a742cd4ccb30b7b8d06356cd09 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 3 Dec 2014 14:40:47 -0800 Subject: [PATCH 011/100] Decoupled reticules from Overlays view --- interface/src/ui/ApplicationOverlay.cpp | 525 +++++++++++------------- interface/src/ui/ApplicationOverlay.h | 12 +- 2 files changed, 237 insertions(+), 300 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f5396c72f0..1050eb5a65 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -33,8 +33,16 @@ const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; +// Return a point's coordinates on a sphere from it's polar (theta) and azimutal (phi) angles. +glm::vec3 getPoint(float radius, float theta, float phi) { + return glm::vec3(radius * glm::sin(theta) * glm::sin(phi), + radius * glm::cos(theta), + radius * glm::sin(theta) * (-glm::cos(phi))); +} + ApplicationOverlay::ApplicationOverlay() : _textureFov(glm::radians(DEFAULT_OCULUS_UI_ANGULAR_SIZE)), + _textureAspectRatio(1.0f), _alpha(1.0f), _oculusUIRadius(1.0f), _crosshairTexture(0) { @@ -47,18 +55,16 @@ ApplicationOverlay::ApplicationOverlay() : ApplicationOverlay::~ApplicationOverlay() { } - // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(bool renderToTexture) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); - - _textureFov = glm::radians(Menu::getInstance()->getOculusUIAngularSize()); - Application* application = Application::getInstance(); - Overlays& overlays = application->getOverlays(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); + + _textureFov = glm::radians(Menu::getInstance()->getOculusUIAngularSize()); + _textureAspectRatio = application->getGLWidget()->getDeviceWidth() / application->getGLWidget()->getDeviceHeight(); //Handle fading and deactivation/activation of UI if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { @@ -79,8 +85,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (renderToTexture) { + _overlays.buildFramebufferObject(); _overlays.bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @@ -130,7 +136,7 @@ void ApplicationOverlay::displayOverlayTexture() { glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); + _overlays.bindTexture(); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -276,7 +282,7 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { //We back the ray up by dir to ensure that it will not start inside the UI. glm::vec3 adjustedPos = tipPos - dir; //Find intersection of crosshair ray. - if (raySphereIntersect(dir, adjustedPos, _oculusuiRadius * myAvatar->getScale(), &t)){ + if (raySphereIntersect(dir, adjustedPos, _oculusUIRadius * myAvatar->getScale(), &t)){ glm::vec3 collisionPos = adjustedPos + dir * t; //Normalize it in case its not a radius of 1 collisionPos = glm::normalize(collisionPos); @@ -324,7 +330,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, glm::vec3 relativeDirection = orientation * direction; float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusuiRadius * myAvatar->getScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ result = position + direction * t; return true; } @@ -351,7 +357,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); + _overlays.bindTexture(); glMatrixMode(GL_MODELVIEW); @@ -362,58 +368,59 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { //Update and draw the magnifiers - glPushMatrix(); const glm::quat& orientation = myAvatar->getOrientation(); const glm::vec3& position = myAvatar->getDefaultEyePosition(); - - glm::mat4 rotation = glm::toMat4(orientation); - - glTranslatef(position.x, position.y, position.z); - glMultMatrixf(&rotation[0][0]); - for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { - - if (_magActive[i]) { - _magSizeMult[i] += MAG_SPEED; - if (_magSizeMult[i] > 1.0f) { - _magSizeMult[i] = 1.0f; + const float scale = myAvatar->getScale() * _oculusUIRadius; + + + glPushMatrix(); { + glTranslatef(position.x, position.y, position.z); + glm::mat4 rotation = glm::toMat4(orientation); + glMultMatrixf(&rotation[0][0]); + glScalef(scale, scale, scale); + for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { + + if (_magActive[i]) { + _magSizeMult[i] += MAG_SPEED; + if (_magSizeMult[i] > 1.0f) { + _magSizeMult[i] = 1.0f; + } + } else { + _magSizeMult[i] -= MAG_SPEED; + if (_magSizeMult[i] < 0.0f) { + _magSizeMult[i] = 0.0f; + } } - } else { - _magSizeMult[i] -= MAG_SPEED; - if (_magSizeMult[i] < 0.0f) { - _magSizeMult[i] = 0.0f; + + if (_magSizeMult[i] > 0.0f) { + //Render magnifier, but dont show border for mouse magnifier + renderMagnifier(_magX[i], _magY[i], _magSizeMult[i], i != MOUSE); } } - - if (_magSizeMult[i] > 0.0f) { - //Render magnifier, but dont show border for mouse magnifier - renderMagnifier(_magX[i], _magY[i], _magSizeMult[i], i != MOUSE); - } - } - glPopMatrix(); - - glDepthMask(GL_FALSE); - glDisable(GL_ALPHA_TEST); - - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - renderTexturedHemisphere(); - - renderPointersOculus(myAvatar->getDefaultEyePosition()); - - glDepthMask(GL_TRUE); - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glEnable(GL_LIGHTING); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - + + glDepthMask(GL_FALSE); + glDisable(GL_ALPHA_TEST); + + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); + _overlays.render(); + + renderPointersOculus(myAvatar->getDefaultEyePosition()); + + glDepthMask(GL_TRUE); + _overlays.releaseTexture(); + glDisable(GL_TEXTURE_2D); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_LIGHTING); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } glPopMatrix(); } // Draws the FBO texture for 3DTV. void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { - if (_alpha == 0.0f) { return; } @@ -427,7 +434,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture()); + _overlays.bindTexture(); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); @@ -686,143 +693,122 @@ void ApplicationOverlay::renderControllerPointers() { } } + +void renderReticule(glm::quat orientation, float alpha) { + const float reticleSize = TWO_PI / 80.0f; + + glm::vec3 topLeft = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, - reticleSize / 2.0f); + glm::vec3 topRight = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, + reticleSize / 2.0f); + glm::vec3 bottomLeft = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, - reticleSize / 2.0f); + glm::vec3 bottomRight = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, + reticleSize / 2.0f); + + glPushMatrix(); { + glm::vec3 axis = glm::axis(orientation); + glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); + + glBegin(GL_QUADS); { + glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(topLeft.x, topLeft.y, topLeft.z); + glTexCoord2f(1.0f, 0.0f); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glTexCoord2f(1.0f, 1.0f); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glTexCoord2f(0.0f, 1.0f); glVertex3f(topRight.x, topRight.y, topRight.z); + } glEnd(); + } glPopMatrix(); +} + void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { - - Application* application = Application::getInstance(); - GLCanvas* glWidget = application->getGLWidget(); - glm::vec3 cursorVerts[4]; - + GLCanvas* glWidget = Application::getInstance()->getGLWidget(); const int widgetWidth = glWidget->width(); const int widgetHeight = glWidget->height(); - - const float reticleSize = 50.0f; - + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); - MyAvatar* myAvatar = application->getAvatar(); - + //Controller Pointers + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { - PalmData& palm = myAvatar->getHand()->getPalms()[i]; - if (palm.isActive()) { - glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); - glm::vec3 tipPos = (tip - eyePos); - - float length = glm::length(eyePos - tip); - float size = 0.03f * length; - - glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * size; - glm::vec3 right = glm::vec3(1.0, 0.0, 0.0) * size; - - cursorVerts[0] = -right + up; - cursorVerts[1] = right + up; - cursorVerts[2] = right - up; - cursorVerts[3] = -right - up; - - glPushMatrix(); - - // objToCamProj is the vector in world coordinates from the - // local origin to the camera projected in the XZ plane - glm::vec3 cursorToCameraXZ(-tipPos.x, 0, -tipPos.z); - cursorToCameraXZ = glm::normalize(cursorToCameraXZ); - - //Translate the cursor to the tip of the oculus ray - glTranslatef(tip.x, tip.y, tip.z); - - glm::vec3 direction(0, 0, 1); - // easy fix to determine wether the angle is negative or positive - // for positive angles upAux will be a vector pointing in the - // positive y direction, otherwise upAux will point downwards - // effectively reversing the rotation. - glm::vec3 upAux = glm::cross(direction, cursorToCameraXZ); - - // compute the angle - float angleCosine = glm::dot(direction, cursorToCameraXZ); - - //Rotate in XZ direction - glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, upAux[0], upAux[1], upAux[2]); - - glm::vec3 cursorToCamera = glm::normalize(-tipPos); - - // Compute the angle between cursorToCameraXZ and cursorToCamera, - angleCosine = glm::dot(cursorToCameraXZ, cursorToCamera); - - //Rotate in Y direction - if (cursorToCamera.y < 0) { - glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, 1, 0, 0); - } else { - glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, -1, 0, 0); - } - - glBegin(GL_QUADS); - - glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z); - glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z); - glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z); - glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z); - - glEnd(); - - glPopMatrix(); - } +// PalmData& palm = myAvatar->getHand()->getPalms()[i]; +// if (palm.isActive()) { +// glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); +// glm::vec3 tipPos = (tip - eyePos); +// +// float length = glm::length(eyePos - tip); +// float size = 0.03f * length; +// +// glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * size; +// glm::vec3 right = glm::vec3(1.0, 0.0, 0.0) * size; +// +// cursorVerts[0] = -right + up; +// cursorVerts[1] = right + up; +// cursorVerts[2] = right - up; +// cursorVerts[3] = -right - up; +// +// glPushMatrix(); +// +// // objToCamProj is the vector in world coordinates from the +// // local origin to the camera projected in the XZ plane +// glm::vec3 cursorToCameraXZ(-tipPos.x, 0, -tipPos.z); +// cursorToCameraXZ = glm::normalize(cursorToCameraXZ); +// +// //Translate the cursor to the tip of the oculus ray +// glTranslatef(tip.x, tip.y, tip.z); +// +// glm::vec3 direction(0, 0, 1); +// // easy fix to determine wether the angle is negative or positive +// // for positive angles upAux will be a vector pointing in the +// // positive y direction, otherwise upAux will point downwards +// // effectively reversing the rotation. +// glm::vec3 upAux = glm::cross(direction, cursorToCameraXZ); +// +// // compute the angle +// float angleCosine = glm::dot(direction, cursorToCameraXZ); +// +// //Rotate in XZ direction +// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, upAux[0], upAux[1], upAux[2]); +// +// glm::vec3 cursorToCamera = glm::normalize(-tipPos); +// +// // Compute the angle between cursorToCameraXZ and cursorToCamera, +// angleCosine = glm::dot(cursorToCameraXZ, cursorToCamera); +// +// //Rotate in Y direction +// if (cursorToCamera.y < 0) { +// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, 1, 0, 0); +// } else { +// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, -1, 0, 0); +// } +// +// glBegin(GL_QUADS); +// +// glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha); +// +// glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z); +// glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z); +// glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z); +// glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z); +// +// glEnd(); +// +// glPopMatrix(); +// } } //Mouse Pointer if (_reticleActive[MOUSE]) { - float mouseX = (float)_mouseX[MOUSE]; float mouseY = (float)_mouseY[MOUSE]; - mouseX -= reticleSize / 2; - mouseY += reticleSize / 2; - - //Get new UV coordinates from our magnification window - float newULeft = mouseX / widgetWidth; - float newURight = (mouseX + reticleSize) / widgetWidth; - float newVBottom = 1.0 - mouseY / widgetHeight; - float newVTop = 1.0 - (mouseY - reticleSize) / widgetHeight; - - // Project our position onto the hemisphere using the UV coordinates - float lX = sin((newULeft - 0.5f) * _textureFov); - float rX = sin((newURight - 0.5f) * _textureFov); - float bY = sin((newVBottom - 0.5f) * _textureFov); - float tY = sin((newVTop - 0.5f) * _textureFov); - - float dist; - //Bottom Left - dist = sqrt(lX * lX + bY * bY); - float blZ = sqrt(1.0f - dist * dist); - //Top Left - dist = sqrt(lX * lX + tY * tY); - float tlZ = sqrt(1.0f - dist * dist); - //Bottom Right - dist = sqrt(rX * rX + bY * bY); - float brZ = sqrt(1.0f - dist * dist); - //Top Right - dist = sqrt(rX * rX + tY * tY); - float trZ = sqrt(1.0f - dist * dist); - - glBegin(GL_QUADS); - - glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha); - - const glm::quat& orientation = myAvatar->getOrientation(); - cursorVerts[0] = orientation * glm::vec3(lX, tY, -tlZ) + eyePos; - cursorVerts[1] = orientation * glm::vec3(rX, tY, -trZ) + eyePos; - cursorVerts[2] = orientation * glm::vec3(rX, bY, -brZ) + eyePos; - cursorVerts[3] = orientation * glm::vec3(lX, bY, -blZ) + eyePos; - - glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z); - glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z); - glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z); - glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z); - - glEnd(); - } + static const float MOUSE_PITCH_RANGE = 1.0f * PI; + static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; + float pitch = -(mouseY / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; + float yaw = -(mouseX / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; + + glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); + renderReticule(orientation, _alpha); + } glEnable(GL_DEPTH_TEST); } @@ -1032,107 +1018,61 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult, const int widgetWidth = glWidget->width(); const int widgetHeight = glWidget->height(); - const float magnifyWidth = MAGNIFY_WIDTH * sizeMult; - const float magnifyHeight = MAGNIFY_HEIGHT * sizeMult; - - mouseX -= magnifyWidth / 2; - mouseY -= magnifyHeight / 2; - - float newWidth = magnifyWidth * MAGNIFY_MULT; - float newHeight = magnifyHeight * MAGNIFY_MULT; - + const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; + const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; // Magnification Texture Coordinates - float magnifyULeft = mouseX / (float)widgetWidth; - float magnifyURight = (mouseX + magnifyWidth) / (float)widgetWidth; - float magnifyVBottom = 1.0f - mouseY / (float)widgetHeight; - float magnifyVTop = 1.0f - (mouseY + magnifyHeight) / (float)widgetHeight; + float magnifyULeft = (mouseX - halfWidth) / (float)widgetWidth; + float magnifyURight = (mouseX + halfWidth) / (float)widgetWidth; + float magnifyVBottom = 1.0f - (mouseY - halfHeight) / (float)widgetHeight; + float magnifyVTop = 1.0f - (mouseY + halfHeight) / (float)widgetHeight; - // Coordinates of magnification overlay - float newMouseX = (mouseX + magnifyWidth / 2) - newWidth / 2.0f; - float newMouseY = (mouseY + magnifyHeight / 2) + newHeight / 2.0f; - - // Get position on hemisphere using angle + const float newHalfWidth = halfWidth * MAGNIFY_MULT; + const float newHalfHeight = halfHeight * MAGNIFY_MULT; //Get new UV coordinates from our magnification window - float newULeft = newMouseX / widgetWidth; - float newURight = (newMouseX + newWidth) / widgetWidth; - float newVBottom = 1.0 - newMouseY / widgetHeight; - float newVTop = 1.0 - (newMouseY - newHeight) / widgetHeight; + float newULeft = (mouseX - newHalfWidth) / (float)widgetWidth; + float newURight = (mouseX + newHalfWidth) / (float)widgetWidth; + float newVBottom = 1.0f - (mouseY - newHalfHeight) / (float)widgetHeight; + float newVTop = 1.0f - (mouseY + newHalfHeight) / (float)widgetHeight; - // Project our position onto the hemisphere using the UV coordinates - float radius = _oculusuiRadius * application->getAvatar()->getScale(); - float radius2 = radius * radius; + // Find spherical coordinates from newUV, fov and aspect ratio + float radius = _oculusUIRadius * application->getAvatar()->getScale(); + const float leftPhi = (newULeft - 0.5f) * _textureFov * _textureAspectRatio; + const float rightPhi = (newURight - 0.5f) * _textureFov * _textureAspectRatio; + const float bottomTheta = PI_OVER_TWO - (newVBottom - 0.5f) * _textureFov; + const float topTheta = PI_OVER_TWO - (newVTop - 0.5f) * _textureFov; - float lX = radius * sin((newULeft - 0.5f) * _textureFov); - float rX = radius * sin((newURight - 0.5f) * _textureFov); - float bY = radius * sin((newVBottom - 0.5f) * _textureFov); - float tY = radius * sin((newVTop - 0.5f) * _textureFov); + glm::vec3 bottomLeft = getPoint(radius, bottomTheta, leftPhi); + glm::vec3 bottomRight = getPoint(radius, bottomTheta, rightPhi); + glm::vec3 topLeft = getPoint(radius, topTheta, leftPhi); + glm::vec3 topRight = getPoint(radius, topTheta, rightPhi); - float blZ, tlZ, brZ, trZ; - - float dist; - float discriminant; - - //Bottom Left - dist = sqrt(lX * lX + bY * bY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - blZ = sqrt(discriminant); - } else { - blZ = 0; - } - //Top Left - dist = sqrt(lX * lX + tY * tY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - tlZ = sqrt(discriminant); - } else { - tlZ = 0; - } - //Bottom Right - dist = sqrt(rX * rX + bY * bY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - brZ = sqrt(discriminant); - } else { - brZ = 0; - } - //Top Right - dist = sqrt(rX * rX + tY * tY); - discriminant = radius2 - dist * dist; - if (discriminant > 0) { - trZ = sqrt(discriminant); - } else { - trZ = 0; - } - - if (showBorder) { - glDisable(GL_TEXTURE_2D); - glLineWidth(1.0f); - //Outer Line - glBegin(GL_LINE_STRIP); - glColor4f(1.0f, 0.0f, 0.0f, _alpha); + glPushMatrix(); { + if (showBorder) { + glDisable(GL_TEXTURE_2D); + glLineWidth(1.0f); + //Outer Line + glBegin(GL_LINE_STRIP); { + glColor4f(1.0f, 0.0f, 0.0f, _alpha); - glVertex3f(lX, tY, -tlZ); - glVertex3f(rX, tY, -trZ); - glVertex3f(rX, bY, -brZ); - glVertex3f(lX, bY, -blZ); - glVertex3f(lX, tY, -tlZ); + glVertex3f(topLeft.x, topLeft.y, topLeft.z); + glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glVertex3f(topRight.x, topRight.y, topRight.z); + glVertex3f(topLeft.x, topLeft.y, topLeft.z); + } glEnd(); + + glEnable(GL_TEXTURE_2D); + } + glColor4f(1.0f, 1.0f, 1.0f, _alpha); - glEnd(); - glEnable(GL_TEXTURE_2D); - } - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - glBegin(GL_QUADS); - - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(lX, tY, -tlZ); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(rX, tY, -trZ); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(rX, bY, -brZ); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(lX, bY, -blZ); - - glEnd(); - + glBegin(GL_QUADS); { + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(topRight.x, topRight.y, topRight.z); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(topLeft.x, topLeft.y, topLeft.z); + } glEnd(); + } glPopMatrix(); } ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : @@ -1150,15 +1090,19 @@ ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() { } void ApplicationOverlay::TexturedHemisphere::bind() { - if (_framebufferObject != NULL) { - _framebufferObject->bind(); - } + _framebufferObject->bind(); } void ApplicationOverlay::TexturedHemisphere::release() { - if (_framebufferObject != NULL) { - _framebufferObject->release(); - } + _framebufferObject->release(); +} + +void ApplicationOverlay::TexturedHemisphere::bindTexture() { + glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); +} + +void ApplicationOverlay::TexturedHemisphere::releaseTexture() { + glBindTexture(GL_TEXTURE_2D, 0); } void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, @@ -1182,18 +1126,16 @@ void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, for (int i = 0; i < stacks; i++) { float stacksRatio = (float)i / (float)stacks; // First stack is 0.0f, last stack is 1.0f // abs(phi) <= fov / 2.0f - float phi = fov * (stacksRatio - 0.5f); + float theta = PI_OVER_TWO - fov * (stacksRatio - 0.5f); for (int j = 0; j < slices; j++) { float slicesRatio = (float)j / (float)slices; // First slice is 0.0f, last slice is 1.0f // abs(theta) <= fov * aspectRatio / 2.0f - float theta = fov * aspectRatio * (slicesRatio - 0.5f); + float phi = fov * aspectRatio * (slicesRatio - 0.5f); - vertexPtr->position.x = -sinf(theta); - vertexPtr->position.y = sinf(phi); - vertexPtr->position.z = cosf(theta); + vertexPtr->position = getPoint(1.0f, theta, phi); vertexPtr->uv.x = slicesRatio; - vertexPtr->uv.y = 1.0f - stacksRatio; + vertexPtr->uv.y = stacksRatio; vertexPtr++; } } @@ -1249,30 +1191,35 @@ void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { } } -void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject(const QSize& size) { +void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { + QSize size = Application::getInstance()->getGLWidget()->getDeviceSize(); + if (_framebufferObject != NULL && size == _framebufferObject->size()) { + // Already build + return; + } + if (_framebufferObject != NULL) { delete _framebufferObject; } _framebufferObject = new QOpenGLFramebufferObject(size); - glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); + bindTexture(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_2D, 0); + releaseTexture(); } //Renders a hemisphere with texture coordinates. -void ApplicationOverlay::TexturedHemisphere::render(const glm::quat& orientation, const glm::vec3& position, const float scale) { +void ApplicationOverlay::TexturedHemisphere::render() { if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) { qDebug() << "TexturedHemisphere::render(): Incorrect initialisation"; return; } - _framebufferObject->bind(); glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); @@ -1285,19 +1232,11 @@ void ApplicationOverlay::TexturedHemisphere::render(const glm::quat& orientation glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); - glPushMatrix(); { - glTranslatef(position.x, position.y, position.z); - glm::mat4 rotation = glm::toMat4(orientation); - glMultMatrixf(&rotation[0][0]); - glScalef(scale, scale, scale); - - glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); - } glPopMatrix(); + glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); - _framebufferObject->release(); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 94fc4e4958..f3be8a30c8 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -54,10 +54,12 @@ private: void bind(); void release(); + void bindTexture(); + void releaseTexture(); + void buildFramebufferObject(); void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks); - void buildFramebufferObject(const QSize& size); - void render(const glm::quat& orientation, const glm::vec3& position, const float scale); + void render(); private: void cleanupVBO(); @@ -68,10 +70,6 @@ private: VerticesIndices _vbo; }; - VerticesIndices* makeTexturedHemiphereVBO(float fov, float aspectRatio, int slices, int stacks); - void renderTexturedHemisphere(ApplicationOverlay::VerticesIndices* vbo, int vertices, int indices); - QOpenGLFramebufferObject* newFramebufferObject(QSize& size); - void renderPointers(); void renderControllerPointers(); void renderPointersOculus(const glm::vec3& eyePos); @@ -81,10 +79,10 @@ private: void renderDomainConnectionStatusBorder(); TexturedHemisphere _overlays; - TexturedHemisphere _reticule; float _trailingAudioLoudness; float _textureFov; + float _textureAspectRatio; enum MagnifyDevices { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_MAGNIFIERS }; bool _reticleActive[NUMBER_OF_MAGNIFIERS]; From 0624ab7c720b090a971f9539e6e80c1be3095443 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 3 Dec 2014 16:04:23 -0800 Subject: [PATCH 012/100] Fixed aspect ratio and cropped overlay texture --- interface/src/ui/ApplicationOverlay.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 1050eb5a65..922ad43164 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -64,7 +64,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { MyAvatar* myAvatar = application->getAvatar(); _textureFov = glm::radians(Menu::getInstance()->getOculusUIAngularSize()); - _textureAspectRatio = application->getGLWidget()->getDeviceWidth() / application->getGLWidget()->getDeviceHeight(); + _textureAspectRatio = (float)application->getGLWidget()->getDeviceWidth() / (float)application->getGLWidget()->getDeviceHeight(); //Handle fading and deactivation/activation of UI if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { @@ -403,7 +403,18 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glColor4f(1.0f, 1.0f, 1.0f, _alpha); - _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); + + static float textureFOV = 0.0f, textureAspectRatio = 1.0f; + static QSize size; + if (textureFOV != _textureFov || + textureAspectRatio != _textureAspectRatio || + size != application->getGLWidget()->getDeviceSize()) { + textureFOV = _textureFov; + textureAspectRatio = _textureAspectRatio; + size = application->getGLWidget()->getDeviceSize(); + + _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); + } _overlays.render(); renderPointersOculus(myAvatar->getDefaultEyePosition()); @@ -805,8 +816,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; float pitch = -(mouseY / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; float yaw = -(mouseX / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; - glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); + renderReticule(orientation, _alpha); } @@ -1124,13 +1135,13 @@ void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, TextureVertex* vertexData = new TextureVertex[_vertices]; TextureVertex* vertexPtr = &vertexData[0]; for (int i = 0; i < stacks; i++) { - float stacksRatio = (float)i / (float)stacks; // First stack is 0.0f, last stack is 1.0f - // abs(phi) <= fov / 2.0f + float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f + // abs(theta) <= fov / 2.0f float theta = PI_OVER_TWO - fov * (stacksRatio - 0.5f); for (int j = 0; j < slices; j++) { - float slicesRatio = (float)j / (float)slices; // First slice is 0.0f, last slice is 1.0f - // abs(theta) <= fov * aspectRatio / 2.0f + float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f + // abs(phi) <= fov * aspectRatio / 2.0f float phi = fov * aspectRatio * (slicesRatio - 0.5f); vertexPtr->position = getPoint(1.0f, theta, phi); From bd39688c624244f70ab3768aa157bc20deef60c1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 3 Dec 2014 17:04:26 -0800 Subject: [PATCH 013/100] Magnifiy window tweaks --- interface/src/ui/ApplicationOverlay.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index f3be8a30c8..5fa93f6521 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -15,9 +15,9 @@ class Overlays; class QOpenGLFramebufferObject; -const float MAGNIFY_WIDTH = 160.0f; -const float MAGNIFY_HEIGHT = 80.0f; -const float MAGNIFY_MULT = 4.0f; +const float MAGNIFY_WIDTH = 220.0f; +const float MAGNIFY_HEIGHT = 100.0f; +const float MAGNIFY_MULT = 2.0f; // Handles the drawing of the overlays to the screen class ApplicationOverlay { From 8d814ab07b11a9ad72051a22c7c38ed749fb6562 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 3 Dec 2014 17:05:42 -0800 Subject: [PATCH 014/100] Updated Oculus pickray --- interface/src/ui/ApplicationOverlay.cpp | 26 ++++++++++++------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 922ad43164..af03147ff9 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -161,23 +161,21 @@ void ApplicationOverlay::displayOverlayTexture() { } void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { - MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + static const float MOUSE_PITCH_RANGE = 1.0f * PI; + static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; - //invert y direction - y = 1.0 - y; - - //Get position on hemisphere UI - x = sin((x - 0.5f) * _textureFov); - y = sin((y - 0.5f) * _textureFov); - - float dist = sqrt(x * x + y * y); - float z = -sqrt(1.0f - dist * dist); - - glm::vec3 relativePosition = myAvatar->getDefaultEyePosition() + - glm::normalize(myAvatar->getOrientation() * glm::vec3(x, y, z)); + const MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + const GLCanvas* glWidget = Application::getInstance()->getGLWidget(); + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); + + const float pitch = -(y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; + const float yaw = -(x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; + const glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); + const glm::vec3 localDirection = orientation * IDENTITY_FRONT; //Rotate the UI pick ray by the avatar orientation - direction = glm::normalize(relativePosition - Application::getInstance()->getCamera()->getPosition()); + direction = myAvatar->getOrientation() * localDirection; } // Calculates the click location on the screen by taking into account any From dd8deeea59c74c6b9b495e15cb1b348838670e9c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 3 Dec 2014 22:39:11 -0800 Subject: [PATCH 015/100] simpler butterflies script that doesn't put as much traffic on entity server --- examples/butterflies.js | 192 +++++++++------------------------------- 1 file changed, 44 insertions(+), 148 deletions(-) diff --git a/examples/butterflies.js b/examples/butterflies.js index 8055e5b7d9..9bd568d011 100644 --- a/examples/butterflies.js +++ b/examples/butterflies.js @@ -13,18 +13,13 @@ // -var numButterflies = 20; +var numButterflies = 25; function getRandomFloat(min, max) { return Math.random() * (max - min) + min; } -// Multiply vector by scalar -function vScalarMult(v, s) { - var rval = { x: v.x * s, y: v.y * s, z: v.z * s }; - return rval; -} // Create a random vector with individual lengths between a,b function randVector(a, b) { @@ -32,50 +27,36 @@ function randVector(a, b) { return rval; } -// Returns a vector which is fraction of the way between a and b -function vInterpolate(a, b, fraction) { - var rval = { x: a.x + (b.x - a.x) * fraction, y: a.y + (b.y - a.y) * fraction, z: a.z + (b.z - a.z) * fraction }; - return rval; -} - var startTimeInSeconds = new Date().getTime() / 1000; -var NATURAL_SIZE_OF_BUTTERFLY = { x: 1.76, y: 0.825, z: 0.20 }; -var lifeTime = 600; // lifetime of the butterflies in seconds -var range = 3.0; // Over what distance in meters do you want the flock to fly around +var NATURAL_SIZE_OF_BUTTERFLY = { x: 1.0, y: 0.4, z: 0.2 }; + +var lifeTime = 3600; // One hour lifespan +var range = 5.0; // Over what distance in meters do you want the flock to fly around var frame = 0; -var CHANCE_OF_MOVING = 0.9; -var BUTTERFLY_GRAVITY = 0; -var BUTTERFLY_FLAP_SPEED = 0.5; -var BUTTERFLY_VELOCITY = 0.55; var DISTANCE_IN_FRONT_OF_ME = 1.5; var DISTANCE_ABOVE_ME = 1.5; -var flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum( +var FIXED_LOCATION = false; + +if (!FIXED_LOCATION) { + var flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum( Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_ABOVE_ME), Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_IN_FRONT_OF_ME))); - +} else { + var flockPosition = { x: 4999.6, y: 4986.5, z: 5003.5 }; +} -// set these pitch, yaw, roll to the needed values to orient the model as you want it -var pitchInDegrees = 270.0; -var yawInDegrees = 0.0; -var rollInDegrees = 0.0; -var pitchInRadians = pitchInDegrees / 180.0 * Math.PI; -var yawInRadians = yawInDegrees / 180.0 * Math.PI; -var rollInRadians = rollInDegrees / 180.0 * Math.PI; - -var rotation = Quat.fromPitchYawRollDegrees(pitchInDegrees, yawInDegrees, rollInDegrees);//experimental // This is our butterfly object function defineButterfly(entityID, targetPosition) { this.entityID = entityID; - this.previousFlapOffset = 0; this.targetPosition = targetPosition; - this.moving = false; } // Array of butterflies var butterflies = []; + function addButterfly() { // Decide the size of butterfly var color = { red: 100, green: 100, blue: 100 }; @@ -88,26 +69,24 @@ function addButterfly() { size = MINSIZE + Math.random() * RANGESIZE; var dimensions = Vec3.multiply(NATURAL_SIZE_OF_BUTTERFLY, (size / maxSize)); - - flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum( - Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_ABOVE_ME), - Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_IN_FRONT_OF_ME))); - + + var GRAVITY = -0.2; + var newFrameRate = 20 + Math.random() * 30; var properties = { type: "Model", lifetime: lifeTime, position: Vec3.sum(randVector(-range, range), flockPosition), - velocity: { x: 0, y: 0.0, z: 0 }, - gravity: { x: 0, y: 1.0, z: 0 }, - damping: 0.1, + rotation: Quat.fromPitchYawRollDegrees(-80 + Math.random() * 20, Math.random() * 360.0, 0.0), + velocity: { x: 0, y: 0, z: 0 }, + gravity: { x: 0, y: GRAVITY, z: 0 }, + damping: 0.9999, dimensions: dimensions, color: color, - rotation: rotation, animationURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/content/butterfly/butterfly.fbx", - animationIsPlaying: true, + animationSettings: "{\"firstFrame\":0,\"fps\":" + newFrameRate + ",\"frameIndex\":0,\"hold\":false,\"lastFrame\":10000,\"loop\":true,\"running\":true,\"startAutomatically\":false}", modelURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/content/butterfly/butterfly.fbx" }; - butterflies.push(new defineButterfly(Entities.addEntity(properties), properties.position)); + butterflies.push(Entities.addEntity(properties)); } // Generate the butterflies @@ -116,117 +95,34 @@ for (var i = 0; i < numButterflies; i++) { } // Main update function -function updateButterflies(deltaTime) { - // Check to see if we've been running long enough that our butterflies are dead - var nowTimeInSeconds = new Date().getTime() / 1000; - if ((nowTimeInSeconds - startTimeInSeconds) >= lifeTime) { - Script.stop(); - return; - } - +function updateButterflies(deltaTime) { frame++; // Only update every third frame because we don't need to do it too quickly if ((frame % 3) == 0) { - flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum(Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_ABOVE_ME), - Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_IN_FRONT_OF_ME))); - // Update all the butterflies + var CHANCE_OF_IMPULSE = 0.04; for (var i = 0; i < numButterflies; i++) { - entityID = Entities.identifyEntity(butterflies[i].entityID); - butterflies[i].entityID = entityID; - var properties = Entities.getEntityProperties(entityID); - - if (properties.position.y > flockPosition.y + getRandomFloat(0.0,0.3)){ //0.3 //ceiling - properties.gravity.y = - 3.0; - properties.damping.y = 1.0; - properties.velocity.y = 0; - properties.velocity.x = properties.velocity.x; - properties.velocity.z = properties.velocity.z; - if (properties.velocity.x < 0.5){ - butterflies[i].moving = false; - } - if (properties.velocity.z < 0.5){ - butterflies[i].moving = false; - } - } - - if (properties.velocity.y <= -0.2) { - properties.velocity.y = 0.22; - properties.velocity.x = properties.velocity.x; - properties.velocity.z = properties.velocity.z; - } - - if (properties.position.y < flockPosition.y - getRandomFloat(0.0,0.3)) { //-0.3 // floor - properties.velocity.y = 0.9; - properties.gravity.y = - 4.0; - properties.velocity.x = properties.velocity.x; - properties.velocity.z = properties.velocity.z; - if (properties.velocity.x < 0.5){ - butterflies[i].moving = false; - } - if (properties.velocity.z < 0.5){ - butterflies[i].moving = false; - } - } - - - // Begin movement by getting a target - if (butterflies[i].moving == false) { - if (Math.random() < CHANCE_OF_MOVING) { - var targetPosition = Vec3.sum(randVector(-range, range), flockPosition); - if (targetPosition.x < 0) { - targetPosition.x = 0; - } - if (targetPosition.y < 0) { - targetPosition.y = 0; - } - if (targetPosition.z < 0) { - targetPosition.z = 0; - } - if (targetPosition.x > TREE_SCALE) { - targetPosition.x = TREE_SCALE; - } - if (targetPosition.y > TREE_SCALE) { - targetPosition.y = TREE_SCALE; - } - if (targetPosition.z > TREE_SCALE) { - targetPosition.z = TREE_SCALE; - } - butterflies[i].targetPosition = targetPosition; - butterflies[i].moving = true; + if (Math.random() < CHANCE_OF_IMPULSE) { + var properties = Entities.getEntityProperties(butterflies[i]); + if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) { + Entities.editEntity(butterflies[i], { position: flockPosition } ); + } else if (properties.velocity.y < 0.0) { + // If falling, Create a new direction and impulse + var HORIZ_SCALE = 0.50; + var VERT_SCALE = 0.50; + var newHeading = Math.random() * 360.0; + var newVelocity = Vec3.multiply(HORIZ_SCALE, Quat.getFront(Quat.fromPitchYawRollDegrees(0.0, newHeading, 0.0))); + newVelocity.y = (Math.random() + 0.5) * VERT_SCALE; + Entities.editEntity(butterflies[i], { rotation: Quat.fromPitchYawRollDegrees(-80 + Math.random() * 20, newHeading, (Math.random() - 0.5) * 10), + velocity: newVelocity } ); } } - - // If we are moving, move towards the target - if (butterflies[i].moving) { - - var holding = properties.velocity.y; - - var desiredVelocity = Vec3.subtract(butterflies[i].targetPosition, properties.position); - desiredVelocity = vScalarMult(Vec3.normalize(desiredVelocity), BUTTERFLY_VELOCITY); - - properties.velocity = vInterpolate(properties.velocity, desiredVelocity, 0.5); - properties.velocity.y = holding ; - - - // If we are near the target, we should get a new target - var halfLargestDimension = Vec3.length(properties.dimensions) / 2.0; - if (Vec3.length(Vec3.subtract(properties.position, butterflies[i].targetPosition)) < (halfLargestDimension)) { - butterflies[i].moving = false; - } - - var yawRads = Math.atan2(properties.velocity.z, properties.velocity.x); - yawRads = yawRads + Math.PI / 2.0; - var newOrientation = Quat.fromPitchYawRollRadians(pitchInRadians, yawRads, rollInRadians); - properties.rotation = newOrientation; - } - - // Use a cosine wave offset to make it look like its flapping. - var offset = Math.cos(nowTimeInSeconds * BUTTERFLY_FLAP_SPEED) * (halfLargestDimension); - properties.position.y = properties.position.y + (offset - butterflies[i].previousFlapOffset); - // Change position relative to previous offset. - butterflies[i].previousFlapOffset = offset; - Entities.editEntity(entityID, properties); + } + // Check to see if we've been running long enough that our butterflies are dead + var nowTimeInSeconds = new Date().getTime() / 1000; + if ((nowTimeInSeconds - startTimeInSeconds) >= lifeTime) { + Script.stop(); + return; } } } @@ -237,6 +133,6 @@ Script.update.connect(updateButterflies); // Delete our little friends if script is stopped Script.scriptEnding.connect(function() { for (var i = 0; i < numButterflies; i++) { - Entities.deleteEntity(butterflies[i].entityID); + Entities.deleteEntity(butterflies[i]); } }); \ No newline at end of file From 3b6936b47d842035ca0cb5a403618775ce2d0f06 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 11:16:01 -0800 Subject: [PATCH 016/100] Changed Mag and reticules data representation --- interface/src/devices/SixenseManager.cpp | 2 - interface/src/ui/ApplicationOverlay.cpp | 782 +++++++++++------------ interface/src/ui/ApplicationOverlay.h | 28 +- 3 files changed, 380 insertions(+), 432 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 6d227027ed..7a555eb902 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -540,8 +540,6 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { //a magnification window was clicked on int clickX = pos.x(); int clickY = pos.y(); - //Checks for magnification window click - application->getApplicationOverlay().getClickLocation(clickX, clickY); //Set pos to the new click location, which may be the same if no magnification window is open pos.setX(clickX); pos.setY(clickY); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 8a55408bd1..5a644718c7 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -30,9 +30,13 @@ const quint64 MSECS_TO_USECS = 1000ULL; const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; +static const float MOUSE_PITCH_RANGE = 1.0f * PI; +static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; + const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; + // Return a point's coordinates on a sphere from it's polar (theta) and azimutal (phi) angles. glm::vec3 getPoint(float radius, float theta, float phi) { return glm::vec3(radius * glm::sin(theta) * glm::sin(phi), @@ -40,6 +44,86 @@ glm::vec3 getPoint(float radius, float theta, float phi) { radius * glm::sin(theta) * (-glm::cos(phi))); } +//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should +//be multiplied by dir and added to origin to get the location of the collision +bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) +{ + //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection + + //Compute A, B and C coefficients + float a = glm::dot(dir, dir); + float b = 2 * glm::dot(dir, origin); + float c = glm::dot(origin, origin) - (r * r); + + //Find discriminant + float disc = b * b - 4 * a * c; + + // if discriminant is negative there are no real roots, so return + // false as ray misses sphere + if (disc < 0) { + return false; + } + + // compute q as described above + float distSqrt = sqrtf(disc); + float q; + if (b < 0) { + q = (-b - distSqrt) / 2.0; + } else { + q = (-b + distSqrt) / 2.0; + } + + // compute t0 and t1 + float t0 = q / a; + float t1 = c / q; + + // make sure t0 is smaller than t1 + if (t0 > t1) { + // if t0 is bigger than t1 swap them around + float temp = t0; + t0 = t1; + t1 = temp; + } + + // if t1 is less than zero, the object is in the ray's negative direction + // and consequently the ray misses the sphere + if (t1 < 0) { + return false; + } + + // if t0 is less than zero, the intersection point is at t1 + if (t0 < 0) { + *result = t1; + return true; + } else { // else the intersection point is at t0 + *result = t0; + return true; + } +} + +void renderReticule(glm::quat orientation, float alpha) { + const float reticleSize = TWO_PI / 80.0f; + + glm::vec3 topLeft = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, - reticleSize / 2.0f); + glm::vec3 topRight = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, + reticleSize / 2.0f); + glm::vec3 bottomLeft = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, - reticleSize / 2.0f); + glm::vec3 bottomRight = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, + reticleSize / 2.0f); + + glPushMatrix(); { + glm::vec3 axis = glm::axis(orientation); + glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); + + glBegin(GL_QUADS); { + glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(topLeft.x, topLeft.y, topLeft.z); + glTexCoord2f(1.0f, 0.0f); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glTexCoord2f(1.0f, 1.0f); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glTexCoord2f(0.0f, 1.0f); glVertex3f(topRight.x, topRight.y, topRight.z); + } glEnd(); + } glPopMatrix(); +} + ApplicationOverlay::ApplicationOverlay() : _textureFov(glm::radians(DEFAULT_OCULUS_UI_ANGULAR_SIZE)), _textureAspectRatio(1.0f), @@ -125,152 +209,241 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { // Draws the FBO texture for the screen void ApplicationOverlay::displayOverlayTexture() { - if (_alpha == 0.0f) { return; } - - Application* application = Application::getInstance(); - GLCanvas* glWidget = application->getGLWidget(); - + GLCanvas* glWidget = Application::getInstance()->getGLWidget(); glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); _overlays.bindTexture(); glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - glLoadIdentity(); - gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - - glBegin(GL_QUADS); - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - glTexCoord2f(0, 0); glVertex2i(0, glWidget->getDeviceHeight()); - glTexCoord2f(1, 0); glVertex2i(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); - glTexCoord2f(1, 1); glVertex2i(glWidget->getDeviceWidth(), 0); - glTexCoord2f(0, 1); glVertex2i(0, 0); - glEnd(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - glPopMatrix(); + glPushMatrix(); { + glLoadIdentity(); + gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + + glBegin(GL_QUADS); { + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + glTexCoord2f(0, 0); glVertex2i(0, glWidget->getDeviceHeight()); + glTexCoord2f(1, 0); glVertex2i(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); + glTexCoord2f(1, 1); glVertex2i(glWidget->getDeviceWidth(), 0); + glTexCoord2f(0, 1); glVertex2i(0, 0); + } glEnd(); + } glPopMatrix(); + glDisable(GL_TEXTURE_2D); } -void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { - static const float MOUSE_PITCH_RANGE = 1.0f * PI; - static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; - - const MyAvatar* myAvatar = Application::getInstance()->getAvatar(); - const GLCanvas* glWidget = Application::getInstance()->getGLWidget(); - const int widgetWidth = glWidget->width(); - const int widgetHeight = glWidget->height(); +// Draws the FBO texture for Oculus rift. +void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { + if (_alpha == 0.0f) { + return; + } + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + _overlays.bindTexture(); - const float pitch = -(y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; - const float yaw = -(x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDisable(GL_LIGHTING); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.01f); + + + //Update and draw the magnifiers + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + const glm::quat& orientation = myAvatar->getOrientation(); + const glm::vec3& position = myAvatar->getDefaultEyePosition(); + const float scale = myAvatar->getScale() * _oculusUIRadius; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); { + glTranslatef(position.x, position.y, position.z); + glm::mat4 rotation = glm::toMat4(orientation); + glMultMatrixf(&rotation[0][0]); + glScalef(scale, scale, scale); + for (int i = 0; i < NUMBER_OF_RETICULES; i++) { + + if (_magActive[i]) { + _magSizeMult[i] += MAG_SPEED; + if (_magSizeMult[i] > 1.0f) { + _magSizeMult[i] = 1.0f; + } + } else { + _magSizeMult[i] -= MAG_SPEED; + if (_magSizeMult[i] < 0.0f) { + _magSizeMult[i] = 0.0f; + } + } + + if (_magSizeMult[i] > 0.0f) { + //Render magnifier, but dont show border for mouse magnifier + float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; + float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; + float projection = + + renderMagnifier(_reticulePosition[i], _magSizeMult[i], i != MOUSE); + } + } + + glDepthMask(GL_FALSE); + glDisable(GL_ALPHA_TEST); + + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + + static float textureFOV = 0.0f, textureAspectRatio = 1.0f; + if (textureFOV != _textureFov || + textureAspectRatio != _textureAspectRatio) { + textureFOV = _textureFov; + textureAspectRatio = _textureAspectRatio; + + _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); + } + _overlays.render(); + renderPointersOculus(myAvatar->getDefaultEyePosition()); + + glDepthMask(GL_TRUE); + _overlays.releaseTexture(); + glDisable(GL_TEXTURE_2D); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_LIGHTING); + } glPopMatrix(); +} + +// Draws the FBO texture for 3DTV. +void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { + if (_alpha == 0.0f) { + return; + } + + Application* application = Application::getInstance(); + + MyAvatar* myAvatar = application->getAvatar(); + const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); + + glActiveTexture(GL_TEXTURE0); + + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + _overlays.bindTexture(); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glLoadIdentity(); + // Transform to world space + glm::quat rotation = whichCamera.getRotation(); + glm::vec3 axis2 = glm::axis(rotation); + glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); + glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); + + // Translate to the front of the camera + glm::vec3 pos = whichCamera.getPosition(); + glm::quat rot = myAvatar->getOrientation(); + glm::vec3 axis = glm::axis(rot); + + glTranslatef(pos.x, pos.y, pos.z); + glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); + + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + //Render + const GLfloat distance = 1.0f; + + const GLfloat halfQuadHeight = distance * tan(fov); + const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; + const GLfloat quadWidth = halfQuadWidth * 2.0f; + const GLfloat quadHeight = halfQuadHeight * 2.0f; + + GLfloat x = -halfQuadWidth; + GLfloat y = -halfQuadHeight; + glDisable(GL_DEPTH_TEST); + + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); + glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); + glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); + glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); + + glEnd(); + + if (_crosshairTexture == 0) { + _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); + } + + //draw the mouse pointer + glBindTexture(GL_TEXTURE_2D, _crosshairTexture); + + const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; + x -= reticleSize / 2.0f; + y += reticleSize / 2.0f; + const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth; + const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight; + + glBegin(GL_QUADS); + + glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); + + glTexCoord2d(0.0f, 0.0f); glVertex3f(x + mouseX, y + mouseY, -distance); + glTexCoord2d(1.0f, 0.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY, -distance); + glTexCoord2d(1.0f, 1.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance); + glTexCoord2d(0.0f, 1.0f); glVertex3f(x + mouseX, y + mouseY - reticleSize, -distance); + + glEnd(); + + glEnable(GL_DEPTH_TEST); + + glPopMatrix(); + + glDepthMask(GL_TRUE); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_LIGHTING); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); +} + + + + + +void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { + const float pitch = (0.5f - y) * MOUSE_PITCH_RANGE; + const float yaw = (0.5f - x) * MOUSE_YAW_RANGE; const glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); const glm::vec3 localDirection = orientation * IDENTITY_FRONT; //Rotate the UI pick ray by the avatar orientation + const MyAvatar* myAvatar = Application::getInstance()->getAvatar(); direction = myAvatar->getOrientation() * localDirection; } -// Calculates the click location on the screen by taking into account any -// opened magnification windows. -void ApplicationOverlay::getClickLocation(int &x, int &y) const { - int dx; - int dy; - const float xRange = MAGNIFY_WIDTH * MAGNIFY_MULT / 2.0f; - const float yRange = MAGNIFY_HEIGHT * MAGNIFY_MULT / 2.0f; - - //Loop through all magnification windows - for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { - if (_magActive[i]) { - dx = x - _magX[i]; - dy = y - _magY[i]; - //Check to see if they clicked inside a mag window - if (abs(dx) <= xRange && abs(dy) <= yRange) { - //Move the click to the actual UI location by inverting the magnification - x = dx / MAGNIFY_MULT + _magX[i]; - y = dy / MAGNIFY_MULT + _magY[i]; - return; - } - } - } -} - -//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should -//be multiplied by dir and added to origin to get the location of the collision -bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result) -{ - //Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection - - //Compute A, B and C coefficients - float a = glm::dot(dir, dir); - float b = 2 * glm::dot(dir, origin); - float c = glm::dot(origin, origin) - (r * r); - - //Find discriminant - float disc = b * b - 4 * a * c; - - // if discriminant is negative there are no real roots, so return - // false as ray misses sphere - if (disc < 0) { - return false; - } - - // compute q as described above - float distSqrt = sqrtf(disc); - float q; - if (b < 0) { - q = (-b - distSqrt) / 2.0; - } else { - q = (-b + distSqrt) / 2.0; - } - - // compute t0 and t1 - float t0 = q / a; - float t1 = c / q; - - // make sure t0 is smaller than t1 - if (t0 > t1) { - // if t0 is bigger than t1 swap them around - float temp = t0; - t0 = t1; - t1 = temp; - } - - // if t1 is less than zero, the object is in the ray's negative direction - // and consequently the ray misses the sphere - if (t1 < 0) { - return false; - } - - // if t0 is less than zero, the intersection point is at t1 - if (t0 < 0) { - *result = t1; - return true; - } else { // else the intersection point is at t0 - *result = t0; - return true; - } -} - //Caculate the click location using one of the sixense controllers. Scale is not applied QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { - Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); MyAvatar* myAvatar = application->getAvatar(); glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); glm::vec3 eyePos = myAvatar->getHead()->getEyePosition(); - glm::quat orientation = glm::inverse(myAvatar->getOrientation()); - glm::vec3 dir = orientation * glm::normalize(application->getCamera()->getPosition() - tip); //direction of ray goes towards camera - glm::vec3 tipPos = orientation * (tip - eyePos); + glm::quat invOrientation = glm::inverse(myAvatar->getOrientation()); + //direction of ray goes towards camera + glm::vec3 dir = invOrientation * glm::normalize(application->getCamera()->getPosition() - tip); + glm::vec3 tipPos = invOrientation * (tip - eyePos); QPoint rv; @@ -336,196 +509,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, return false; } -// Draws the FBO texture for Oculus rift. -void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { - if (_alpha == 0.0f) { - return; - } - - Application* application = Application::getInstance(); - - MyAvatar* myAvatar = application->getAvatar(); - - glActiveTexture(GL_TEXTURE0); - - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); - - _overlays.bindTexture(); - - glMatrixMode(GL_MODELVIEW); - - glDepthMask(GL_TRUE); - - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.01f); - - //Update and draw the magnifiers - - const glm::quat& orientation = myAvatar->getOrientation(); - const glm::vec3& position = myAvatar->getDefaultEyePosition(); - const float scale = myAvatar->getScale() * _oculusUIRadius; - - - glPushMatrix(); { - glTranslatef(position.x, position.y, position.z); - glm::mat4 rotation = glm::toMat4(orientation); - glMultMatrixf(&rotation[0][0]); - glScalef(scale, scale, scale); - for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) { - - if (_magActive[i]) { - _magSizeMult[i] += MAG_SPEED; - if (_magSizeMult[i] > 1.0f) { - _magSizeMult[i] = 1.0f; - } - } else { - _magSizeMult[i] -= MAG_SPEED; - if (_magSizeMult[i] < 0.0f) { - _magSizeMult[i] = 0.0f; - } - } - - if (_magSizeMult[i] > 0.0f) { - //Render magnifier, but dont show border for mouse magnifier - renderMagnifier(_magX[i], _magY[i], _magSizeMult[i], i != MOUSE); - } - } - - glDepthMask(GL_FALSE); - glDisable(GL_ALPHA_TEST); - - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - - static float textureFOV = 0.0f, textureAspectRatio = 1.0f; - static QSize size; - if (textureFOV != _textureFov || - textureAspectRatio != _textureAspectRatio || - size != application->getGLWidget()->getDeviceSize()) { - textureFOV = _textureFov; - textureAspectRatio = _textureAspectRatio; - size = application->getGLWidget()->getDeviceSize(); - - _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); - } - _overlays.render(); - - renderPointersOculus(myAvatar->getDefaultEyePosition()); - - glDepthMask(GL_TRUE); - _overlays.releaseTexture(); - glDisable(GL_TEXTURE_2D); - - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glEnable(GL_LIGHTING); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - } glPopMatrix(); -} - -// Draws the FBO texture for 3DTV. -void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov) { - if (_alpha == 0.0f) { - return; - } - - Application* application = Application::getInstance(); - - MyAvatar* myAvatar = application->getAvatar(); - const glm::vec3& viewMatrixTranslation = application->getViewMatrixTranslation(); - - glActiveTexture(GL_TEXTURE0); - - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - _overlays.bindTexture(); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glEnable(GL_TEXTURE_2D); - - glMatrixMode(GL_MODELVIEW); - - glPushMatrix(); - glLoadIdentity(); - // Transform to world space - glm::quat rotation = whichCamera.getRotation(); - glm::vec3 axis2 = glm::axis(rotation); - glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); - glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); - - // Translate to the front of the camera - glm::vec3 pos = whichCamera.getPosition(); - glm::quat rot = myAvatar->getOrientation(); - glm::vec3 axis = glm::axis(rot); - - glTranslatef(pos.x, pos.y, pos.z); - glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); - - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - //Render - const GLfloat distance = 1.0f; - - const GLfloat halfQuadHeight = distance * tan(fov); - const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; - const GLfloat quadWidth = halfQuadWidth * 2.0f; - const GLfloat quadHeight = halfQuadHeight * 2.0f; - - GLfloat x = -halfQuadWidth; - GLfloat y = -halfQuadHeight; - glDisable(GL_DEPTH_TEST); - - glBegin(GL_QUADS); - - glTexCoord2f(0.0f, 1.0f); glVertex3f(x, y + quadHeight, -distance); - glTexCoord2f(1.0f, 1.0f); glVertex3f(x + quadWidth, y + quadHeight, -distance); - glTexCoord2f(1.0f, 0.0f); glVertex3f(x + quadWidth, y, -distance); - glTexCoord2f(0.0f, 0.0f); glVertex3f(x, y, -distance); - - glEnd(); - - if (_crosshairTexture == 0) { - _crosshairTexture = Application::getInstance()->getGLWidget()->bindTexture(QImage(Application::resourcesPath() + "images/sixense-reticle.png")); - } - - //draw the mouse pointer - glBindTexture(GL_TEXTURE_2D, _crosshairTexture); - - const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; - x -= reticleSize / 2.0f; - y += reticleSize / 2.0f; - const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth; - const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight; - - glBegin(GL_QUADS); - - glColor3f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2]); - - glTexCoord2d(0.0f, 0.0f); glVertex3f(x + mouseX, y + mouseY, -distance); - glTexCoord2d(1.0f, 0.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY, -distance); - glTexCoord2d(1.0f, 1.0f); glVertex3f(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance); - glTexCoord2d(0.0f, 1.0f); glVertex3f(x + mouseX, y + mouseY - reticleSize, -distance); - - glEnd(); - - glEnable(GL_DEPTH_TEST); - - glPopMatrix(); - - glDepthMask(GL_TRUE); - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); - glEnable(GL_LIGHTING); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); -} //Renders optional pointers void ApplicationOverlay::renderPointers() { @@ -544,10 +528,7 @@ void ApplicationOverlay::renderPointers() { //If we are in oculus, render reticle later _reticleActive[MOUSE] = true; _magActive[MOUSE] = true; - _mouseX[MOUSE] = application->getMouseX(); - _mouseY[MOUSE] = application->getMouseY(); - _magX[MOUSE] = _mouseX[MOUSE]; - _magY[MOUSE] = _mouseY[MOUSE]; + _reticulePosition[MOUSE] = glm::vec2(application->getMouseX(), application->getMouseY()); _reticleActive[LEFT_CONTROLLER] = false; _reticleActive[RIGHT_CONTROLLER] = false; @@ -567,9 +548,9 @@ void ApplicationOverlay::renderControllerPointers() { MyAvatar* myAvatar = application->getAvatar(); //Static variables used for storing controller state - static quint64 pressedTime[NUMBER_OF_MAGNIFIERS] = { 0ULL, 0ULL, 0ULL }; - static bool isPressed[NUMBER_OF_MAGNIFIERS] = { false, false, false }; - static bool stateWhenPressed[NUMBER_OF_MAGNIFIERS] = { false, false, false }; + static quint64 pressedTime[NUMBER_OF_RETICULES] = { 0ULL, 0ULL, 0ULL }; + static bool isPressed[NUMBER_OF_RETICULES] = { false, false, false }; + static bool stateWhenPressed[NUMBER_OF_RETICULES] = { false, false, false }; const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); @@ -616,14 +597,11 @@ void ApplicationOverlay::renderControllerPointers() { QPoint point = getPalmClickLocation(palmData); - _mouseX[index] = point.x(); - _mouseY[index] = point.y(); + _reticulePosition[index] = glm::vec2(point.x(), point.y()); //When button 2 is pressed we drag the mag window if (isPressed[index]) { _magActive[index] = true; - _magX[index] = point.x(); - _magY[index] = point.y(); } // If oculus is enabled, we draw the crosshairs later @@ -676,30 +654,6 @@ void ApplicationOverlay::renderControllerPointers() { } } - -void renderReticule(glm::quat orientation, float alpha) { - const float reticleSize = TWO_PI / 80.0f; - - glm::vec3 topLeft = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, - reticleSize / 2.0f); - glm::vec3 topRight = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, + reticleSize / 2.0f); - glm::vec3 bottomLeft = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, - reticleSize / 2.0f); - glm::vec3 bottomRight = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, + reticleSize / 2.0f); - - glPushMatrix(); { - glm::vec3 axis = glm::axis(orientation); - glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); - - glBegin(GL_QUADS); { - glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha); - - glTexCoord2f(0.0f, 0.0f); glVertex3f(topLeft.x, topLeft.y, topLeft.z); - glTexCoord2f(1.0f, 0.0f); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); - glTexCoord2f(1.0f, 1.0f); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); - glTexCoord2f(0.0f, 1.0f); glVertex3f(topRight.x, topRight.y, topRight.z); - } glEnd(); - } glPopMatrix(); -} - void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { GLCanvas* glWidget = Application::getInstance()->getGLWidget(); const int widgetWidth = glWidget->width(); @@ -781,13 +735,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { //Mouse Pointer if (_reticleActive[MOUSE]) { - float mouseX = (float)_mouseX[MOUSE]; - float mouseY = (float)_mouseY[MOUSE]; - - static const float MOUSE_PITCH_RANGE = 1.0f * PI; - static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; - float pitch = -(mouseY / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; - float yaw = -(mouseX / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; + float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; + float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); renderReticule(orientation, _alpha); @@ -796,6 +745,76 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { glEnable(GL_DEPTH_TEST); } +//Renders a small magnification of the currently bound texture at the coordinates +void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) const { + Application* application = Application::getInstance(); + GLCanvas* glWidget = application->getGLWidget(); + + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); + + if (magPos.x < 0 || magPos.x > widgetWidth || magPos.y < 0 || magPos.y > widgetHeight) { + return; + } + + const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; + const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; + // Magnification Texture Coordinates + float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; + float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; + float magnifyVBottom = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; + float magnifyVTop = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; + + const float newHalfWidth = halfWidth * MAGNIFY_MULT; + const float newHalfHeight = halfHeight * MAGNIFY_MULT; + //Get new UV coordinates from our magnification window + float newULeft = (magPos.x - newHalfWidth) / (float)widgetWidth; + float newURight = (magPos.x + newHalfWidth) / (float)widgetWidth; + float newVBottom = 1.0f - (magPos.y - newHalfHeight) / (float)widgetHeight; + float newVTop = 1.0f - (magPos.y + newHalfHeight) / (float)widgetHeight; + + // Find spherical coordinates from newUV, fov and aspect ratio + float radius = _oculusUIRadius * application->getAvatar()->getScale(); + const float leftPhi = (newULeft - 0.5f) * _textureFov * _textureAspectRatio; + const float rightPhi = (newURight - 0.5f) * _textureFov * _textureAspectRatio; + const float bottomTheta = PI_OVER_TWO - (newVBottom - 0.5f) * _textureFov; + const float topTheta = PI_OVER_TWO - (newVTop - 0.5f) * _textureFov; + + glm::vec3 bottomLeft = getPoint(radius, bottomTheta, leftPhi); + glm::vec3 bottomRight = getPoint(radius, bottomTheta, rightPhi); + glm::vec3 topLeft = getPoint(radius, topTheta, leftPhi); + glm::vec3 topRight = getPoint(radius, topTheta, rightPhi); + + glPushMatrix(); { + if (showBorder) { + glDisable(GL_TEXTURE_2D); + glLineWidth(1.0f); + //Outer Line + glBegin(GL_LINE_STRIP); { + glColor4f(1.0f, 0.0f, 0.0f, _alpha); + + glVertex3f(topLeft.x, topLeft.y, topLeft.z); + glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glVertex3f(topRight.x, topRight.y, topRight.z); + glVertex3f(topLeft.x, topLeft.y, topLeft.z); + } glEnd(); + + glEnable(GL_TEXTURE_2D); + } + glColor4f(1.0f, 1.0f, 1.0f, _alpha); + + glBegin(GL_QUADS); { + glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); + glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); + glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(topRight.x, topRight.y, topRight.z); + glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(topLeft.x, topLeft.y, topLeft.z); + } glEnd(); + } glPopMatrix(); +} + + + void ApplicationOverlay::renderAudioMeter() { Application* application = Application::getInstance(); @@ -993,70 +1012,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { } } -//Renders a small magnification of the currently bound texture at the coordinates -void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult, bool showBorder) const { - Application* application = Application::getInstance(); - GLCanvas* glWidget = application->getGLWidget(); - - const int widgetWidth = glWidget->width(); - const int widgetHeight = glWidget->height(); - - const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; - const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; - // Magnification Texture Coordinates - float magnifyULeft = (mouseX - halfWidth) / (float)widgetWidth; - float magnifyURight = (mouseX + halfWidth) / (float)widgetWidth; - float magnifyVBottom = 1.0f - (mouseY - halfHeight) / (float)widgetHeight; - float magnifyVTop = 1.0f - (mouseY + halfHeight) / (float)widgetHeight; - - - const float newHalfWidth = halfWidth * MAGNIFY_MULT; - const float newHalfHeight = halfHeight * MAGNIFY_MULT; - //Get new UV coordinates from our magnification window - float newULeft = (mouseX - newHalfWidth) / (float)widgetWidth; - float newURight = (mouseX + newHalfWidth) / (float)widgetWidth; - float newVBottom = 1.0f - (mouseY - newHalfHeight) / (float)widgetHeight; - float newVTop = 1.0f - (mouseY + newHalfHeight) / (float)widgetHeight; - - // Find spherical coordinates from newUV, fov and aspect ratio - float radius = _oculusUIRadius * application->getAvatar()->getScale(); - const float leftPhi = (newULeft - 0.5f) * _textureFov * _textureAspectRatio; - const float rightPhi = (newURight - 0.5f) * _textureFov * _textureAspectRatio; - const float bottomTheta = PI_OVER_TWO - (newVBottom - 0.5f) * _textureFov; - const float topTheta = PI_OVER_TWO - (newVTop - 0.5f) * _textureFov; - - glm::vec3 bottomLeft = getPoint(radius, bottomTheta, leftPhi); - glm::vec3 bottomRight = getPoint(radius, bottomTheta, rightPhi); - glm::vec3 topLeft = getPoint(radius, topTheta, leftPhi); - glm::vec3 topRight = getPoint(radius, topTheta, rightPhi); - - glPushMatrix(); { - if (showBorder) { - glDisable(GL_TEXTURE_2D); - glLineWidth(1.0f); - //Outer Line - glBegin(GL_LINE_STRIP); { - glColor4f(1.0f, 0.0f, 0.0f, _alpha); - - glVertex3f(topLeft.x, topLeft.y, topLeft.z); - glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); - glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); - glVertex3f(topRight.x, topRight.y, topRight.z); - glVertex3f(topLeft.x, topLeft.y, topLeft.z); - } glEnd(); - - glEnable(GL_TEXTURE_2D); - } - glColor4f(1.0f, 1.0f, 1.0f, _alpha); - - glBegin(GL_QUADS); { - glTexCoord2f(magnifyULeft, magnifyVBottom); glVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z); - glTexCoord2f(magnifyURight, magnifyVBottom); glVertex3f(bottomRight.x, bottomRight.y, bottomRight.z); - glTexCoord2f(magnifyURight, magnifyVTop); glVertex3f(topRight.x, topRight.y, topRight.z); - glTexCoord2f(magnifyULeft, magnifyVTop); glVertex3f(topLeft.x, topLeft.y, topLeft.z); - } glEnd(); - } glPopMatrix(); -} + ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : _vertices(0), diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 5fa93f6521..7c423b3a06 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -22,7 +22,6 @@ const float MAGNIFY_MULT = 2.0f; // Handles the drawing of the overlays to the screen class ApplicationOverlay { public: - ApplicationOverlay(); ~ApplicationOverlay(); @@ -30,14 +29,10 @@ public: void displayOverlayTexture(); void displayOverlayTextureOculus(Camera& whichCamera); void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); + void computeOculusPickRay(float x, float y, glm::vec3& direction) const; - void getClickLocation(int &x, int &y) const; QPoint getPalmClickLocation(const PalmData *palm) const; bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; - - - // Getters - float getAlpha() const { return _alpha; } private: // Interleaved vertex data @@ -70,31 +65,30 @@ private: VerticesIndices _vbo; }; - void renderPointers(); + void renderPointers();; + void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) const; + void renderControllerPointers(); void renderPointersOculus(const glm::vec3& eyePos); - void renderMagnifier(int mouseX, int mouseY, float sizeMult, bool showBorder) const; + void renderAudioMeter(); void renderStatsAndLogs(); void renderDomainConnectionStatusBorder(); TexturedHemisphere _overlays; - float _trailingAudioLoudness; float _textureFov; float _textureAspectRatio; - enum MagnifyDevices { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_MAGNIFIERS }; - bool _reticleActive[NUMBER_OF_MAGNIFIERS]; - int _mouseX[NUMBER_OF_MAGNIFIERS]; - int _mouseY[NUMBER_OF_MAGNIFIERS]; - bool _magActive[NUMBER_OF_MAGNIFIERS]; - int _magX[NUMBER_OF_MAGNIFIERS]; - int _magY[NUMBER_OF_MAGNIFIERS]; - float _magSizeMult[NUMBER_OF_MAGNIFIERS]; + enum Reticules { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICULES }; + bool _reticleActive[NUMBER_OF_RETICULES]; + glm::vec2 _reticulePosition[NUMBER_OF_RETICULES]; + bool _magActive[NUMBER_OF_RETICULES]; + float _magSizeMult[NUMBER_OF_RETICULES]; float _alpha; float _oculusUIRadius; + float _trailingAudioLoudness; GLuint _crosshairTexture; }; From b6fd3628c8524799c60bfa8a9c2f1405c7ad3bc1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 12:00:38 -0800 Subject: [PATCH 017/100] first round of hacking on implementing rendering of models for detailed ray picking --- interface/resources/shaders/select.frag | 25 ++ interface/resources/shaders/select.vert | 26 ++ .../entities/RenderableModelEntityItem.cpp | 382 ++++++++++++++++++ .../src/entities/RenderableModelEntityItem.h | 11 + interface/src/renderer/Model.cpp | 20 +- interface/src/renderer/Model.h | 6 +- 6 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 interface/resources/shaders/select.frag create mode 100644 interface/resources/shaders/select.vert diff --git a/interface/resources/shaders/select.frag b/interface/resources/shaders/select.frag new file mode 100644 index 0000000000..a7c5067fbc --- /dev/null +++ b/interface/resources/shaders/select.frag @@ -0,0 +1,25 @@ +#version 120 + +// +// simple.frag +// fragment shader +// +// Created by Andrzej Kapolka on 9/15/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 +// + +// the interpolated normal +varying vec4 normal; + +// the glow intensity +uniform float glowIntensity; + +void main(void) { + // set the diffuse, normal, specular data + gl_FragData[0] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_Color.rgb, glowIntensity); + gl_FragData[1] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); + gl_FragData[2] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0); +} diff --git a/interface/resources/shaders/select.vert b/interface/resources/shaders/select.vert new file mode 100644 index 0000000000..9f76597fd6 --- /dev/null +++ b/interface/resources/shaders/select.vert @@ -0,0 +1,26 @@ +#version 120 + +// +// simple.vert +// vertex shader +// +// Created by Andrzej Kapolka on 9/15/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 +// + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // transform and store the normal for interpolation + normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + + // pass along the diffuse color + gl_FrontColor = vec4(1.0f, 0.0f, 0.0f, 0.0f); //gl_Color; + + // use standard pipeline transform + gl_Position = ftransform(); +} diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 10b18ad9c5..11d16c39f8 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -133,6 +133,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) { getModel(renderer); } + + + if (_model) { // handle animations.. if (hasAnimation()) { @@ -257,7 +260,386 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const { return properties; } +bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { + + // extents is the entity relative, scaled, centered extents of the entity + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); + + float depth = depthOfRayIntersection(entityFrameOrigin, entityFrameDirection); + + return true; // we only got here if we intersected our non-aabox +} +/* +void RenderableModelEntityItem::renderEntityAsBillboard() { + TextureCache* textureCache = Application->getInstance()->getTextureCache(); + textureCache->getPrimaryFramebufferObject()->bind(); + + const int BILLBOARD_SIZE = 64; + renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true); + + //QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); + //glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); + + textureCache->getPrimaryFramebufferObject()->release(); + + return image; +} +*/ + +float RenderableModelEntityItem::depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const { + qDebug() << "RenderableModelEntityItem::depthOfRayIntersection()...."; + + Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); + + glEnable(GL_SCISSOR_TEST); + glEnable(GL_LIGHTING); // enable? + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); // we don't need blending + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + + // * we know the direction that the ray is coming into our bounding box. + // * we know the location on our bounding box that the ray intersected + // * because this API is theoretically called for things that aren't on the screen, + // or could be off in the distance, but with an original ray pick origin ALSO off + // in the distance, we don't really know the "pixel" size of the model at that + // place in space. In fact that concept really doesn't make sense at all... so + // we need to pick our own "scale" based on whatever level of precision makes + // sense... what makes sense? + // * we could say that we allow ray intersections down to some N meters (say 1cm + // or 0.01 meters) in real space. The model's bounds in meters are known. + // + // + float renderGranularity = 0.01f; // 1cm of render granularity - this could be ridiculous for large models + + qDebug() << " renderGranularity:" << renderGranularity; + + // note: these are in tree units, not meters + glm::vec3 dimensions = getDimensions(); + glm::vec3 registrationPoint = getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); + + AABox entityFrameBox(corner, dimensions); + entityFrameBox.scale((float)TREE_SCALE); + + // rotationBetween(v1, v2) -- Helper function return the rotation from the first vector onto the second + //glm::quat viewRotation = rotationBetween(entityFrameDirection, IDENTITY_FRONT); + //glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, entityFrameDirection); + glm::quat viewRotation = rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT); + //glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, IDENTITY_FRONT); + + // I'd like to calculate the tightest bounding box around the entity for + // the direction of the + glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); + glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); + const int VERTEX_COUNT = 8; + for (int j = 0; j < VERTEX_COUNT; j++) { + glm::vec3 vertex = entityFrameBox.getVertex((BoxVertex)j); + qDebug() << " vertex[" << j <<"]:" << vertex; + + glm::vec3 rotated = viewRotation * vertex; + qDebug() << " rotated[" << j <<"]:" << rotated; + + minima = glm::min(minima, rotated); + maxima = glm::max(maxima, rotated); + } + + qDebug() << " minima:" << minima; + qDebug() << " maxima:" << maxima; + + int width = glm::round((maxima.x - minima.x) / renderGranularity); + int height = glm::round((maxima.y - minima.y) / renderGranularity); + + qDebug() << " width:" << width; + qDebug() << " height:" << height; + + glViewport(0, 0, width, height); + glScissor(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glLoadIdentity(); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glm::vec3 axis = glm::axis(viewRotation); + glRotatef(glm::degrees(glm::angle(viewRotation)), axis.x, axis.y, axis.z); + + glm::vec3 entityFrameOriginInMeters = entityFrameOrigin * (float)TREE_SCALE; + glm::vec3 entityFrameDirectionInMeters = entityFrameDirection * (float)TREE_SCALE; + //glTranslatef(entityFrameOriginInMerters.x, entityFrameOriginInMerters.y, entityFrameOriginInMerters.z); + + Application::getInstance()->setupWorldLight(); + Application::getInstance()->updateUntranslatedViewMatrix(); + + + bool renderAsModel = true; + + if (renderAsModel) { + const float alpha = 1.0f; + + glm::vec3 position = getPositionInMeters(); + glm::vec3 center = getCenterInMeters(); + dimensions = getDimensions() * (float)TREE_SCALE; + glm::quat rotation = getRotation(); + + const float MAX_COLOR = 255.0f; + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + glPushMatrix(); + { + //glTranslatef(position.x, position.y, position.z); + //glm::vec3 axis = glm::axis(rotation); + //glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + //glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + + //glScalef(dimensions.x, dimensions.y, dimensions.z); + //Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(0.5f, 15, 15); + + //_model->setRotation(rotation); + //_model->setScaleToFit(true, glm::vec3(1.0f,1.0f,1.0f)); + + //glm::vec3(0.0f,2.0f,0.0f) + _model->setSnapModelToRegistrationPoint(true, glm::vec3(0.5f,0.5f,0.5f)); + _model->setTranslation(glm::vec3(0.0f,0.0f,0.0f)); + _model->simulate(0.0f); + _model->render(alpha, Model::DEFAULT_RENDER_MODE); + + //_model->render(1.0f, Model::DEFAULT_RENDER_MODE); + + //_model->setScaleToFit(true, dimensions); + _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); + _model->setTranslation(position); + _model->simulate(0.0f); + + glPushMatrix(); + glScalef(dimensions.x, dimensions.y, dimensions.z); + Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15); + glPopMatrix(); + + /* + glBegin(GL_LINES); + + // low-z side - blue + glColor4f(0.0f, 0.0f, 1.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, -0.5f); + + // high-z side - cyan + glColor4f(0.0f, 1.0f, 1.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, 0.5f); + glVertex3f( 0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f(-0.5f, -0.5f, 0.5f); + + // low-x side - yellow + glColor4f(1.0f, 1.0f, 0.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, 0.5f); + + glVertex3f(-0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, -0.5f); + + // high-x side - red + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, 0.5f); + glVertex3f(0.5f, -0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + // origin and direction - green + float distanceToHit; + BoxFace ignoreFace; + + entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace); + glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit); + +qDebug() << "distanceToHit: " << distanceToHit; +qDebug() << "pointOfIntersection: " << pointOfIntersection; + + glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f); + glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f); +qDebug() << "pointA: " << pointA; +qDebug() << "pointB: " << pointB; + + glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + glVertex3f(pointA.x, pointA.y, pointA.z); + glVertex3f(pointB.x, pointB.y, pointB.z); + + glEnd(); + */ + + + glPopMatrix(); + } + glPopMatrix(); + + + } else { + glm::vec3 position = getPositionInMeters(); + glm::vec3 center = getCenterInMeters(); + dimensions = getDimensions() * (float)TREE_SCALE; + glm::quat rotation = getRotation(); + + glColor4f(1.0f, 0.0f, 1.0f, 1.0f); + glLineWidth(2.0f); + + glPushMatrix(); + { + //glTranslatef(position.x, position.y, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + + glScalef(dimensions.x, dimensions.y, dimensions.z); + //Application::getInstance()->getDeferredLightingEffect()->renderWireCube(1.0f); + Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15); + + glBegin(GL_LINES); + + // low-z side - blue + glColor4f(0.0f, 0.0f, 1.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, -0.5f); + + // high-z side - cyan + glColor4f(0.0f, 1.0f, 1.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, 0.5f); + glVertex3f( 0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, 0.5f, 0.5f); + glVertex3f( 0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f(-0.5f, -0.5f, 0.5f); + + // low-x side - yellow + glColor4f(1.0f, 1.0f, 0.0f, 1.0f); + glVertex3f(-0.5f, -0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, 0.5f); + + glVertex3f(-0.5f, -0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, 0.5f); + + glVertex3f(-0.5f, 0.5f, 0.5f); + glVertex3f(-0.5f, 0.5f, -0.5f); + + glVertex3f(-0.5f, 0.5f, -0.5f); + glVertex3f(-0.5f, -0.5f, -0.5f); + + // high-x side - red + glColor4f(1.0f, 0.0f, 0.0f, 1.0f); + glVertex3f(0.5f, -0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, 0.5f); + glVertex3f(0.5f, -0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, 0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, 0.5f, -0.5f); + glVertex3f(0.5f, -0.5f, -0.5f); + + + // origin and direction - green + float distanceToHit; + BoxFace ignoreFace; + + entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace); + glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit); + +qDebug() << "distanceToHit: " << distanceToHit; +qDebug() << "pointOfIntersection: " << pointOfIntersection; + + glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f); + glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f); +qDebug() << "pointA: " << pointA; +qDebug() << "pointB: " << pointB; + + glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + glVertex3f(pointA.x, pointA.y, pointA.z); + glVertex3f(pointB.x, pointB.y, pointB.z); + + glEnd(); + + glPopMatrix(); + } + glPopMatrix(); + } + + QImage colorData(width, height, QImage::Format_ARGB32); + QVector depthData(width * height); + + glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, colorData.bits()); + glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData.data()); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glEnable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + + Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->release(); + + glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); + + QImage imageData = colorData.mirrored(false,true); + + bool saved = imageData.save("/Users/zappoman/Development/foo.bmp"); + + qDebug() << " saved:" << saved; + + + return 0.0f; +} + diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 48c9a26051..09db54d64f 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -28,6 +28,9 @@ #include #include +#include +#include + class RenderableModelEntityItem : public ModelEntityItem { public: static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -51,6 +54,11 @@ public: virtual void somethingChangedNotification() { _needsInitialSimulation = true; } virtual void render(RenderArgs* args); + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const; + Model* getModel(EntityTreeRenderer* renderer); private: void remapTextures(); @@ -63,6 +71,9 @@ private: QString _currentTextures; QStringList _originalTextures; bool _originalTexturesRead; + + float depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const; + }; #endif // hifi_RenderableModelEntityItem_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b2570b7c28..74aa190a26 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -103,6 +103,9 @@ Model::SkinLocations Model::_skinNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; Model::SkinLocations Model::_skinTranslucentLocations; +ProgramObject Model::_selectProgram; +Model::Locations Model::_selectLocations; + void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); // if anyone sets scale manually, then we are no longer scaled to fit @@ -269,7 +272,7 @@ void Model::init() { _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _program.link(); - + initProgram(_program, _locations); _normalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, @@ -387,6 +390,14 @@ void Model::init() { _skinTranslucentProgram.link(); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + + + // select/ray picking program + _selectProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/select.vert"); + _selectProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/select.frag"); + _selectProgram.link(); + initProgram(_selectProgram, _selectLocations); + } } @@ -2148,6 +2159,13 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f ProgramObject* activeProgram = program; Locations* activeLocations = locations; + // XXXBHG - hack to render yellow + if (mode == SELECT_RENDER_MODE) { + //activeProgram = &_selectProgram; + //activeLocations = &_selectLocations; + // need skin version + } + if (isSkinned) { activeProgram = skinProgram; activeLocations = skinLocations; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index d24e4d9f2e..9fdec3f25b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -86,7 +86,7 @@ public: void reset(); virtual void simulate(float deltaTime, bool fullUpdate = true); - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, SELECT_RENDER_MODE }; bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); @@ -318,6 +318,8 @@ private: static ProgramObject _skinTranslucentProgram; static ProgramObject _skinShadowProgram; + + static ProgramObject _selectProgram; static int _normalMapTangentLocation; static int _normalSpecularMapTangentLocation; @@ -343,6 +345,8 @@ private: static Locations _lightmapSpecularMapLocations; static Locations _lightmapNormalSpecularMapLocations; + static Locations _selectLocations; + static void initProgram(ProgramObject& program, Locations& locations, int specularTextureUnit = 1); class SkinLocations : public Locations { From 5e2d1c33644a39d9aa65374c48ea5f3324e915af Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 4 Dec 2014 21:15:10 +0100 Subject: [PATCH 018/100] more comfortable movement setting --- examples/virtualKeyboard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index cd2ce9f7ba..58b44e8585 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -34,7 +34,7 @@ const CURSOR_HEIGHT = 33.9; // VIEW_ANGLE can be adjusted to your likings, the smaller the faster movement. // Try setting it to 60 if it goes too fast for you. -const VIEW_ANGLE = 30.0; +const VIEW_ANGLE = 40.0; const VIEW_ANGLE_BY_TWO = VIEW_ANGLE / 2; const SPAWN_DISTANCE = 1; From 5ec9a9b6eda41117da2002c2f56da4d89693cfcf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 13:08:16 -0800 Subject: [PATCH 019/100] make text entities correctly ray pick --- libraries/entities/src/TextEntityItem.cpp | 49 ++++++++++++++++++++++- libraries/entities/src/TextEntityItem.h | 5 +++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 491240c178..17ef33ee1c 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -10,9 +10,12 @@ // +#include + #include #include +#include #include "EntityTree.h" #include "EntityTreeElement.h" @@ -110,4 +113,48 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, appendValue, getLineHeight()); APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, appendColor, getTextColor()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, appendColor, getBackgroundColor()); -} \ No newline at end of file +} + + +bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const { + + RayIntersectionInfo rayInfo; + rayInfo._rayStart = origin; + rayInfo._rayDirection = direction; + rayInfo._rayLength = std::numeric_limits::max(); + + PlaneShape plane; + + const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f); + glm::vec3 normal = _rotation * UNROTATED_NORMAL; + plane.setNormal(normal); + plane.setPoint(_position); // the position is definitely a point on our plane + + bool intersects = plane.findRayIntersection(rayInfo); + + if (intersects) { + glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance); + // now we know the point the ray hit our plane + + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 dimensions = getDimensions(); + glm::vec3 registrationPoint = getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); + AABox entityFrameBox(corner, dimensions); + + glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f)); + + intersects = entityFrameBox.contains(entityFrameHitAt); + } + + if (intersects) { + distance = rayInfo._hitDistance; + } + return intersects; +} diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 019d230c36..a3d323aefd 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -41,6 +41,11 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject) const; + static const QString DEFAULT_TEXT; void setText(const QString& value) { _text = value; } const QString& getText() const { return _text; } From a7185738e9e961be7afe5e66c151024efb0fc097 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 5 Dec 2014 00:52:36 +0100 Subject: [PATCH 020/100] virtualkeyboard: scaling text in input box --- examples/virtualKeyboard.js | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 58b44e8585..3d00f934e2 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -56,6 +56,7 @@ const TEXT_MARGIN_BOTTOM = 0.17; var windowDimensions = Controller.getViewportDimensions(); var cursor = null; var keyboard = new Keyboard(); +var textFontSize = 9; var text = null; var textText = ""; var textSizeMeasureOverlay = Overlays.addOverlay("text3d", {visible: false}); @@ -65,15 +66,39 @@ function appendChar(char) { updateTextOverlay(); Overlays.editOverlay(text, {text: textText}); } + function deleteChar() { if (textText.length > 0) { textText = textText.substring(0, textText.length - 1); updateTextOverlay(); } } + function updateTextOverlay() { - Overlays.editOverlay(text, {text: textText}); + var textwidth = Overlays.textWidth(text, textText); + var textLines = textText.split("\n"); + var maxLineWidth = 0; + for (textLine in textLines) { + var lineWidth = Overlays.textWidth(text, textLines[textLine]); + if (lineWidth > maxLineWidth) { + maxLineWidth = lineWidth; + } + } + var suggestedFontSize = (windowDimensions.x / maxLineWidth) * textFontSize * 0.90; + var maxFontSize = 240 / textLines.length; + textFontSize = (suggestedFontSize > maxFontSize) ? maxFontSize : suggestedFontSize; + var topMargin = (250 - (textFontSize * textLines.length)) / 2; + Overlays.editOverlay(text, {text: textText, font: {size: textFontSize}, topMargin: topMargin}); + var maxLineWidth = 0; + for (textLine in textLines) { + var lineWidth = Overlays.textWidth(text, textLines[textLine]); + if (lineWidth > maxLineWidth) { + maxLineWidth = lineWidth; + } + } + Overlays.editOverlay(text, {leftMargin: (windowDimensions.x - maxLineWidth) / 2}); } + keyboard.onKeyPress = function(event) { if (event.event == 'keypress') { appendChar(event.char); @@ -141,12 +166,13 @@ keyboard.onFullyLoaded = function() { height: 250, backgroundColor: { red: 255, green: 255, blue: 255}, color: { red: 0, green: 0, blue: 0}, - topMargin: 10, - leftMargin: 8, - font: {size: 28}, + topMargin: 5, + leftMargin: 0, + font: {size: textFontSize}, text: "", alpha: 0.8 }); + updateTextOverlay(); // the cursor is being loaded after the keyboard, else it will be on the background of the keyboard cursor = new Cursor(); cursor.onUpdate = function(position) { From c0ba9e73c28725a6662e70d5f7a53879a318d7ea Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Fri, 5 Dec 2014 01:07:49 +0100 Subject: [PATCH 021/100] fixed font height bq --- examples/virtualKeyboard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 3d00f934e2..2340bcab6e 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -85,9 +85,9 @@ function updateTextOverlay() { } } var suggestedFontSize = (windowDimensions.x / maxLineWidth) * textFontSize * 0.90; - var maxFontSize = 240 / textLines.length; + var maxFontSize = 190 / textLines.length; textFontSize = (suggestedFontSize > maxFontSize) ? maxFontSize : suggestedFontSize; - var topMargin = (250 - (textFontSize * textLines.length)) / 2; + var topMargin = (250 - (textFontSize * textLines.length)) / 4; Overlays.editOverlay(text, {text: textText, font: {size: textFontSize}, topMargin: topMargin}); var maxLineWidth = 0; for (textLine in textLines) { From 1102b4d633841e54cc780caccd49698af8357eba Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 4 Dec 2014 16:40:55 -0800 Subject: [PATCH 022/100] Moving GPU into it's own library --- interface/CMakeLists.txt | 2 +- libraries/gpu/CMakeLists.txt | 52 +++++++++++++++++++ .../gpu}/src/gpu/Batch.cpp | 0 {interface => libraries/gpu}/src/gpu/Batch.h | 4 +- .../gpu}/src/gpu/Context.cpp | 0 .../gpu}/src/gpu/Context.h | 4 +- {interface => libraries/gpu}/src/gpu/Format.h | 2 +- .../gpu}/src/gpu/GLBackend.cpp | 2 +- .../gpu}/src/gpu/GLBackend.h | 6 +-- libraries/gpu/src/gpu/GPUConfig.h | 30 +++++++++++ .../gpu}/src/gpu/Resource.cpp | 0 .../gpu}/src/gpu/Resource.h | 4 +- .../gpu}/src/gpu/Stream.cpp | 0 {interface => libraries/gpu}/src/gpu/Stream.h | 6 +-- 14 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 libraries/gpu/CMakeLists.txt rename {interface => libraries/gpu}/src/gpu/Batch.cpp (100%) rename {interface => libraries/gpu}/src/gpu/Batch.h (98%) rename {interface => libraries/gpu}/src/gpu/Context.cpp (100%) rename {interface => libraries/gpu}/src/gpu/Context.h (94%) rename {interface => libraries/gpu}/src/gpu/Format.h (98%) rename {interface => libraries/gpu}/src/gpu/GLBackend.cpp (99%) rename {interface => libraries/gpu}/src/gpu/GLBackend.h (98%) create mode 100644 libraries/gpu/src/gpu/GPUConfig.h rename {interface => libraries/gpu}/src/gpu/Resource.cpp (100%) rename {interface => libraries/gpu}/src/gpu/Resource.h (98%) rename {interface => libraries/gpu}/src/gpu/Stream.cpp (100%) rename {interface => libraries/gpu}/src/gpu/Stream.h (97%) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index eb788ac49a..38dd02c655 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -107,7 +107,7 @@ endif() add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) # link required hifi libraries -link_hifi_libraries(shared octree voxels fbx metavoxels networking entities avatars audio animation script-engine physics) +link_hifi_libraries(shared octree voxels gpu fbx metavoxels networking entities avatars audio animation script-engine physics) # find any optional and required libraries find_package(ZLIB REQUIRED) diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt new file mode 100644 index 0000000000..712e4320b5 --- /dev/null +++ b/libraries/gpu/CMakeLists.txt @@ -0,0 +1,52 @@ +set(TARGET_NAME gpu) + +# use setup_hifi_library macro to setup our project and link appropriate Qt modules +setup_hifi_library() + +include_glm() + +link_hifi_libraries(shared) +if (APPLE) + # link in required OS X frameworks and include the right GL headers + find_library(CoreFoundation CoreFoundation) + find_library(OpenGL OpenGL) + + target_link_libraries(${TARGET_NAME} ${CoreFoundation} ${OpenGL}) + + # install command for OS X bundle + INSTALL(TARGETS ${TARGET_NAME} + BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime + RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime + ) +else (APPLE) + find_package(OpenGL REQUIRED) + + if (${OPENGL_INCLUDE_DIR}) + include_directories(SYSTEM "${OPENGL_INCLUDE_DIR}") + endif () + + target_link_libraries(${TARGET_NAME} "${OPENGL_LIBRARY}") + + # link target to external libraries + if (WIN32) + find_package(GLEW REQUIRED) + include_directories(${GLEW_INCLUDE_DIRS}) + + # we're using static GLEW, so define GLEW_STATIC + add_definitions(-DGLEW_STATIC) + + target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" "${NSIGHT_LIBRARIES}" opengl32.lib) + + # try to find the Nsight package and add it to the build if we find it + find_package(NSIGHT) + if (NSIGHT_FOUND) + include_directories(${NSIGHT_INCLUDE_DIRS}) + add_definitions(-DNSIGHT_FOUND) + target_link_libraries(${TARGET_NAME} "${NSIGHT_LIBRARIES}") + endif () + + endif() +endif (APPLE) + +# call macro to link our dependencies and bubble them up via a property on our target +link_shared_dependencies() diff --git a/interface/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp similarity index 100% rename from interface/src/gpu/Batch.cpp rename to libraries/gpu/src/gpu/Batch.cpp diff --git a/interface/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h similarity index 98% rename from interface/src/gpu/Batch.h rename to libraries/gpu/src/gpu/Batch.h index 5304740dd3..601ae63a77 100644 --- a/interface/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -12,13 +12,13 @@ #define hifi_gpu_Batch_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" #include "Transform.h" #include -#include "gpu/Stream.h" +#include "Stream.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" diff --git a/interface/src/gpu/Context.cpp b/libraries/gpu/src/gpu/Context.cpp similarity index 100% rename from interface/src/gpu/Context.cpp rename to libraries/gpu/src/gpu/Context.cpp diff --git a/interface/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h similarity index 94% rename from interface/src/gpu/Context.h rename to libraries/gpu/src/gpu/Context.h index 8398288cb9..3a0fffb4ef 100644 --- a/interface/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -12,9 +12,9 @@ #define hifi_gpu_Context_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" -#include "gpu/Resource.h" +#include "Resource.h" namespace gpu { diff --git a/interface/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h similarity index 98% rename from interface/src/gpu/Format.h rename to libraries/gpu/src/gpu/Format.h index 8faa995924..d216495b4c 100644 --- a/interface/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -12,7 +12,7 @@ #define hifi_gpu_Format_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" namespace gpu { diff --git a/interface/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp similarity index 99% rename from interface/src/gpu/GLBackend.cpp rename to libraries/gpu/src/gpu/GLBackend.cpp index 1f8e7bf99f..85f0dde858 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -12,7 +12,7 @@ #include -#include "gpu/Batch.h" +#include "Batch.h" using namespace gpu; diff --git a/interface/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h similarity index 98% rename from interface/src/gpu/GLBackend.h rename to libraries/gpu/src/gpu/GLBackend.h index 0e4b38d89e..5a40e9ca36 100644 --- a/interface/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -12,10 +12,10 @@ #define hifi_gpu_GLBackend_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" -#include "gpu/Context.h" -#include "gpu/Batch.h" +#include "Context.h" +#include "Batch.h" #include diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h new file mode 100644 index 0000000000..024cf73112 --- /dev/null +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -0,0 +1,30 @@ +// +// GPUConfig.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 12/4/14. +// Copyright 2013 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 gpu__GPUConfig__ +#define gpu__GPUConfig__ + +#define GL_GLEXT_PROTOTYPES 1 + +#if defined(APPLE) +#include + +#elif defined(UNIX) +#include +#include + +#elif defined(WIN32) +#include +#include + +#endif + +#endif diff --git a/interface/src/gpu/Resource.cpp b/libraries/gpu/src/gpu/Resource.cpp similarity index 100% rename from interface/src/gpu/Resource.cpp rename to libraries/gpu/src/gpu/Resource.cpp diff --git a/interface/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h similarity index 98% rename from interface/src/gpu/Resource.h rename to libraries/gpu/src/gpu/Resource.h index 52108c215a..6247efe675 100644 --- a/interface/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -12,9 +12,9 @@ #define hifi_gpu_Resource_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" -#include "gpu/Format.h" +#include "Format.h" #include diff --git a/interface/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp similarity index 100% rename from interface/src/gpu/Stream.cpp rename to libraries/gpu/src/gpu/Stream.cpp diff --git a/interface/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h similarity index 97% rename from interface/src/gpu/Stream.h rename to libraries/gpu/src/gpu/Stream.h index d024182531..93abfeeca3 100644 --- a/interface/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -12,10 +12,10 @@ #define hifi_gpu_Stream_h #include -#include "InterfaceConfig.h" +#include "GPUConfig.h" -#include "gpu/Resource.h" -#include "gpu/Format.h" +#include "Resource.h" +#include "Format.h" #include #include From 37ffa48fa3ef45e6f1840f8327ead23e45846c05 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 16:43:12 -0800 Subject: [PATCH 023/100] more work on improved model picking --- .../entities/RenderableModelEntityItem.cpp | 385 +----------------- .../src/entities/RenderableModelEntityItem.h | 3 - interface/src/renderer/Model.cpp | 7 + 3 files changed, 18 insertions(+), 377 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 11d16c39f8..ccd6622856 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -263,383 +263,20 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const { bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) const { - - // extents is the entity relative, scaled, centered extents of the entity - glm::mat4 rotation = glm::mat4_cast(getRotation()); - glm::mat4 translation = glm::translate(getPosition()); - glm::mat4 entityToWorldMatrix = translation * rotation; - glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); - glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); - glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); - - float depth = depthOfRayIntersection(entityFrameOrigin, entityFrameDirection); - - return true; // we only got here if we intersected our non-aabox -} - - -/* -void RenderableModelEntityItem::renderEntityAsBillboard() { - TextureCache* textureCache = Application->getInstance()->getTextureCache(); - textureCache->getPrimaryFramebufferObject()->bind(); - - const int BILLBOARD_SIZE = 64; - renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true); - - //QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32); - //glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits()); - - textureCache->getPrimaryFramebufferObject()->release(); - - return image; -} -*/ - -float RenderableModelEntityItem::depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const { - qDebug() << "RenderableModelEntityItem::depthOfRayIntersection()...."; + qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection()...."; + qDebug() << " origin:" << origin; + glm::vec3 originInMeters = origin * (float)TREE_SCALE; + qDebug() << " originInMeters:" << originInMeters; + QString extraInfo; + float localDistance; + bool intersectsModel = _model->findRayIntersectionAgainstSubMeshes(originInMeters, direction, localDistance, face, extraInfo); - Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); - - glEnable(GL_SCISSOR_TEST); - glEnable(GL_LIGHTING); // enable? - glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); // we don't need blending - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - - // * we know the direction that the ray is coming into our bounding box. - // * we know the location on our bounding box that the ray intersected - // * because this API is theoretically called for things that aren't on the screen, - // or could be off in the distance, but with an original ray pick origin ALSO off - // in the distance, we don't really know the "pixel" size of the model at that - // place in space. In fact that concept really doesn't make sense at all... so - // we need to pick our own "scale" based on whatever level of precision makes - // sense... what makes sense? - // * we could say that we allow ray intersections down to some N meters (say 1cm - // or 0.01 meters) in real space. The model's bounds in meters are known. - // - // - float renderGranularity = 0.01f; // 1cm of render granularity - this could be ridiculous for large models - - qDebug() << " renderGranularity:" << renderGranularity; - - // note: these are in tree units, not meters - glm::vec3 dimensions = getDimensions(); - glm::vec3 registrationPoint = getRegistrationPoint(); - glm::vec3 corner = -(dimensions * registrationPoint); - - AABox entityFrameBox(corner, dimensions); - entityFrameBox.scale((float)TREE_SCALE); - - // rotationBetween(v1, v2) -- Helper function return the rotation from the first vector onto the second - //glm::quat viewRotation = rotationBetween(entityFrameDirection, IDENTITY_FRONT); - //glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, entityFrameDirection); - glm::quat viewRotation = rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT); - //glm::quat viewRotation = rotationBetween(IDENTITY_FRONT, IDENTITY_FRONT); - - // I'd like to calculate the tightest bounding box around the entity for - // the direction of the - glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); - glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); - const int VERTEX_COUNT = 8; - for (int j = 0; j < VERTEX_COUNT; j++) { - glm::vec3 vertex = entityFrameBox.getVertex((BoxVertex)j); - qDebug() << " vertex[" << j <<"]:" << vertex; - - glm::vec3 rotated = viewRotation * vertex; - qDebug() << " rotated[" << j <<"]:" << rotated; - - minima = glm::min(minima, rotated); - maxima = glm::max(maxima, rotated); + if (intersectsModel) { + distance = localDistance / (float)TREE_SCALE; } - qDebug() << " minima:" << minima; - qDebug() << " maxima:" << maxima; - - int width = glm::round((maxima.x - minima.x) / renderGranularity); - int height = glm::round((maxima.y - minima.y) / renderGranularity); - - qDebug() << " width:" << width; - qDebug() << " height:" << height; - - glViewport(0, 0, width, height); - glScissor(0, 0, width, height); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glLoadIdentity(); - glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glm::vec3 axis = glm::axis(viewRotation); - glRotatef(glm::degrees(glm::angle(viewRotation)), axis.x, axis.y, axis.z); - - glm::vec3 entityFrameOriginInMeters = entityFrameOrigin * (float)TREE_SCALE; - glm::vec3 entityFrameDirectionInMeters = entityFrameDirection * (float)TREE_SCALE; - //glTranslatef(entityFrameOriginInMerters.x, entityFrameOriginInMerters.y, entityFrameOriginInMerters.z); - - Application::getInstance()->setupWorldLight(); - Application::getInstance()->updateUntranslatedViewMatrix(); - - - bool renderAsModel = true; - - if (renderAsModel) { - const float alpha = 1.0f; - - glm::vec3 position = getPositionInMeters(); - glm::vec3 center = getCenterInMeters(); - dimensions = getDimensions() * (float)TREE_SCALE; - glm::quat rotation = getRotation(); - - const float MAX_COLOR = 255.0f; - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - - glPushMatrix(); - { - //glTranslatef(position.x, position.y, position.z); - //glm::vec3 axis = glm::axis(rotation); - //glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - - glPushMatrix(); - glm::vec3 positionToCenter = center - position; - //glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - - //glScalef(dimensions.x, dimensions.y, dimensions.z); - //Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(0.5f, 15, 15); - - //_model->setRotation(rotation); - //_model->setScaleToFit(true, glm::vec3(1.0f,1.0f,1.0f)); - - //glm::vec3(0.0f,2.0f,0.0f) - _model->setSnapModelToRegistrationPoint(true, glm::vec3(0.5f,0.5f,0.5f)); - _model->setTranslation(glm::vec3(0.0f,0.0f,0.0f)); - _model->simulate(0.0f); - _model->render(alpha, Model::DEFAULT_RENDER_MODE); - - //_model->render(1.0f, Model::DEFAULT_RENDER_MODE); - - //_model->setScaleToFit(true, dimensions); - _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); - _model->setTranslation(position); - _model->simulate(0.0f); - - glPushMatrix(); - glScalef(dimensions.x, dimensions.y, dimensions.z); - Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15); - glPopMatrix(); - - /* - glBegin(GL_LINES); - - // low-z side - blue - glColor4f(0.0f, 0.0f, 1.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, -0.5f); - - // high-z side - cyan - glColor4f(0.0f, 1.0f, 1.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, 0.5f); - glVertex3f( 0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f(-0.5f, -0.5f, 0.5f); - - // low-x side - yellow - glColor4f(1.0f, 1.0f, 0.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, 0.5f); - - glVertex3f(-0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, -0.5f); - - // high-x side - red - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, 0.5f); - glVertex3f(0.5f, -0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - - - // origin and direction - green - float distanceToHit; - BoxFace ignoreFace; - - entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace); - glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit); - -qDebug() << "distanceToHit: " << distanceToHit; -qDebug() << "pointOfIntersection: " << pointOfIntersection; - - glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f); - glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f); -qDebug() << "pointA: " << pointA; -qDebug() << "pointB: " << pointB; - - glColor4f(0.0f, 1.0f, 0.0f, 1.0f); - glVertex3f(pointA.x, pointA.y, pointA.z); - glVertex3f(pointB.x, pointB.y, pointB.z); - - glEnd(); - */ - - - glPopMatrix(); - } - glPopMatrix(); - - - } else { - glm::vec3 position = getPositionInMeters(); - glm::vec3 center = getCenterInMeters(); - dimensions = getDimensions() * (float)TREE_SCALE; - glm::quat rotation = getRotation(); - - glColor4f(1.0f, 0.0f, 1.0f, 1.0f); - glLineWidth(2.0f); - - glPushMatrix(); - { - //glTranslatef(position.x, position.y, position.z); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - - glPushMatrix(); - glm::vec3 positionToCenter = center - position; - glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); - - glScalef(dimensions.x, dimensions.y, dimensions.z); - //Application::getInstance()->getDeferredLightingEffect()->renderWireCube(1.0f); - Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(0.5f, 15, 15); - - glBegin(GL_LINES); - - // low-z side - blue - glColor4f(0.0f, 0.0f, 1.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, -0.5f); - - // high-z side - cyan - glColor4f(0.0f, 1.0f, 1.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, 0.5f); - glVertex3f( 0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, 0.5f, 0.5f); - glVertex3f( 0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f(-0.5f, -0.5f, 0.5f); - - // low-x side - yellow - glColor4f(1.0f, 1.0f, 0.0f, 1.0f); - glVertex3f(-0.5f, -0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, 0.5f); - - glVertex3f(-0.5f, -0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, 0.5f); - - glVertex3f(-0.5f, 0.5f, 0.5f); - glVertex3f(-0.5f, 0.5f, -0.5f); - - glVertex3f(-0.5f, 0.5f, -0.5f); - glVertex3f(-0.5f, -0.5f, -0.5f); - - // high-x side - red - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - glVertex3f(0.5f, -0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, 0.5f); - glVertex3f(0.5f, -0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, 0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, 0.5f, -0.5f); - glVertex3f(0.5f, -0.5f, -0.5f); - - - // origin and direction - green - float distanceToHit; - BoxFace ignoreFace; - - entityFrameBox.findRayIntersection(entityFrameOriginInMeters, entityFrameDirectionInMeters, distanceToHit, ignoreFace); - glm::vec3 pointOfIntersection = entityFrameOriginInMeters + (entityFrameDirectionInMeters * distanceToHit); - -qDebug() << "distanceToHit: " << distanceToHit; -qDebug() << "pointOfIntersection: " << pointOfIntersection; - - glm::vec3 pointA = pointOfIntersection + (entityFrameDirectionInMeters * -1.0f); - glm::vec3 pointB = pointOfIntersection + (entityFrameDirectionInMeters * 1.0f); -qDebug() << "pointA: " << pointA; -qDebug() << "pointB: " << pointB; - - glColor4f(0.0f, 1.0f, 0.0f, 1.0f); - glVertex3f(pointA.x, pointA.y, pointA.z); - glVertex3f(pointB.x, pointB.y, pointB.z); - - glEnd(); - - glPopMatrix(); - } - glPopMatrix(); - } - - QImage colorData(width, height, QImage::Format_ARGB32); - QVector depthData(width * height); - - glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, colorData.bits()); - glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData.data()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glEnable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - - Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->release(); - - glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); - - QImage imageData = colorData.mirrored(false,true); - - bool saved = imageData.save("/Users/zappoman/Development/foo.bmp"); - - qDebug() << " saved:" << saved; - - - return 0.0f; + return intersectsModel; // we only got here if we intersected our non-aabox } + diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 09db54d64f..4c6bb5a046 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -71,9 +71,6 @@ private: QString _currentTextures; QStringList _originalTextures; bool _originalTexturesRead; - - float depthOfRayIntersection(const glm::vec3& entityFrameOrigin, const glm::vec3& entityFrameDirection) const; - }; #endif // hifi_RenderableModelEntityItem_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 74aa190a26..9941be566a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -536,6 +536,8 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } + qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; + // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; glm::mat4 rotation = glm::mat4_cast(_rotation); @@ -544,11 +546,14 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); Extents modelExtents = getMeshExtents(); // NOTE: unrotated + qDebug() << " modelExtents:" << modelExtents; glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; glm::vec3 corner = dimensions * -0.5f; // since we're going to do the ray picking in the model frame of reference AABox overlayFrameBox(corner, dimensions); + qDebug() << " overlayFrameBox:" << overlayFrameBox; + glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); @@ -560,11 +565,13 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g float distanceToSubMesh; BoxFace subMeshFace; int subMeshIndex = 0; + // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); + qDebug() << "subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { if (distanceToSubMesh < bestDistance) { bestDistance = distanceToSubMesh; From f13bf65554c3c8629f5d6cb45e5f72154a48c91b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 16:43:34 -0800 Subject: [PATCH 024/100] more work on improved model picking --- interface/resources/shaders/select.frag | 25 ------------------------ interface/resources/shaders/select.vert | 26 ------------------------- 2 files changed, 51 deletions(-) delete mode 100644 interface/resources/shaders/select.frag delete mode 100644 interface/resources/shaders/select.vert diff --git a/interface/resources/shaders/select.frag b/interface/resources/shaders/select.frag deleted file mode 100644 index a7c5067fbc..0000000000 --- a/interface/resources/shaders/select.frag +++ /dev/null @@ -1,25 +0,0 @@ -#version 120 - -// -// simple.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/15/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 -// - -// the interpolated normal -varying vec4 normal; - -// the glow intensity -uniform float glowIntensity; - -void main(void) { - // set the diffuse, normal, specular data - gl_FragData[0] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_Color.rgb, glowIntensity); - gl_FragData[1] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); - gl_FragData[2] = vec4(1.0f, 1.0f, 0.0f, 0.0f); //vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0); -} diff --git a/interface/resources/shaders/select.vert b/interface/resources/shaders/select.vert deleted file mode 100644 index 9f76597fd6..0000000000 --- a/interface/resources/shaders/select.vert +++ /dev/null @@ -1,26 +0,0 @@ -#version 120 - -// -// simple.vert -// vertex shader -// -// Created by Andrzej Kapolka on 9/15/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 -// - -// the interpolated normal -varying vec4 normal; - -void main(void) { - // transform and store the normal for interpolation - normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); - - // pass along the diffuse color - gl_FrontColor = vec4(1.0f, 0.0f, 0.0f, 0.0f); //gl_Color; - - // use standard pipeline transform - gl_Position = ftransform(); -} From 6b5fdceb6e2c8dd656123d16dff49752d000e503 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 4 Dec 2014 16:48:04 -0800 Subject: [PATCH 025/100] more work on improved model picking --- .../src/entities/RenderableModelEntityItem.h | 3 --- interface/src/renderer/Model.cpp | 18 ------------------ interface/src/renderer/Model.h | 6 +----- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 4c6bb5a046..9ed85beeaa 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -28,9 +28,6 @@ #include #include -#include -#include - class RenderableModelEntityItem : public ModelEntityItem { public: static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties); diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9941be566a..19176c4833 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -103,9 +103,6 @@ Model::SkinLocations Model::_skinNormalSpecularMapLocations; Model::SkinLocations Model::_skinShadowLocations; Model::SkinLocations Model::_skinTranslucentLocations; -ProgramObject Model::_selectProgram; -Model::Locations Model::_selectLocations; - void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); // if anyone sets scale manually, then we are no longer scaled to fit @@ -390,14 +387,6 @@ void Model::init() { _skinTranslucentProgram.link(); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); - - - // select/ray picking program - _selectProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/select.vert"); - _selectProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/select.frag"); - _selectProgram.link(); - initProgram(_selectProgram, _selectLocations); - } } @@ -2166,13 +2155,6 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f ProgramObject* activeProgram = program; Locations* activeLocations = locations; - // XXXBHG - hack to render yellow - if (mode == SELECT_RENDER_MODE) { - //activeProgram = &_selectProgram; - //activeLocations = &_selectLocations; - // need skin version - } - if (isSkinned) { activeProgram = skinProgram; activeLocations = skinLocations; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 9fdec3f25b..b16cf11b09 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -86,7 +86,7 @@ public: void reset(); virtual void simulate(float deltaTime, bool fullUpdate = true); - enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, SELECT_RENDER_MODE }; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); @@ -319,8 +319,6 @@ private: static ProgramObject _skinShadowProgram; - static ProgramObject _selectProgram; - static int _normalMapTangentLocation; static int _normalSpecularMapTangentLocation; @@ -345,8 +343,6 @@ private: static Locations _lightmapSpecularMapLocations; static Locations _lightmapNormalSpecularMapLocations; - static Locations _selectLocations; - static void initProgram(ProgramObject& program, Locations& locations, int specularTextureUnit = 1); class SkinLocations : public Locations { From da1bb83eb0b34c8ea9c7b50c105c0dad4436f43f Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 4 Dec 2014 17:14:41 -0800 Subject: [PATCH 026/100] compiling the gpu library on mac --- libraries/gpu/CMakeLists.txt | 8 +------- libraries/gpu/src/gpu/GPUConfig.h | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/libraries/gpu/CMakeLists.txt b/libraries/gpu/CMakeLists.txt index 712e4320b5..577f9f7a58 100644 --- a/libraries/gpu/CMakeLists.txt +++ b/libraries/gpu/CMakeLists.txt @@ -8,16 +8,10 @@ include_glm() link_hifi_libraries(shared) if (APPLE) # link in required OS X frameworks and include the right GL headers - find_library(CoreFoundation CoreFoundation) find_library(OpenGL OpenGL) - target_link_libraries(${TARGET_NAME} ${CoreFoundation} ${OpenGL}) + target_link_libraries(${TARGET_NAME} ${OpenGL}) - # install command for OS X bundle - INSTALL(TARGETS ${TARGET_NAME} - BUNDLE DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime - RUNTIME DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/install" COMPONENT Runtime - ) else (APPLE) find_package(OpenGL REQUIRED) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 024cf73112..0d0a140e62 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -14,7 +14,8 @@ #define GL_GLEXT_PROTOTYPES 1 -#if defined(APPLE) +#ifdef __APPLE__ +#include #include #elif defined(UNIX) From 16da10bf19f401ed86f3c172275a27f53eb9e3a8 Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 4 Dec 2014 17:15:59 -0800 Subject: [PATCH 027/100] compiling the gpu library on mac --- libraries/gpu/src/gpu/GPUConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 0d0a140e62..faecfd4889 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -14,7 +14,7 @@ #define GL_GLEXT_PROTOTYPES 1 -#ifdef __APPLE__ +#if defined(__APPLE__) #include #include From 7026af7b9ab68789f83851b513a8d23b4d75c13f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 17:26:14 -0800 Subject: [PATCH 028/100] Centrilized Oculus interference in pickRay --- interface/src/Application.cpp | 11 +- interface/src/Camera.cpp | 17 +-- interface/src/entities/EntityTreeRenderer.cpp | 13 +- .../scripting/JoystickScriptingInterface.cpp | 2 +- interface/src/ui/ApplicationOverlay.cpp | 132 ++++++++++-------- interface/src/ui/ApplicationOverlay.h | 11 +- interface/src/ui/NodeBounds.cpp | 11 +- 7 files changed, 102 insertions(+), 95 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9ab87fdc30..06965df947 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1131,7 +1131,7 @@ void Application::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { // this starts an HFActionEvent HFActionEvent startActionEvent(HFActionEvent::startType(), - _viewFrustum.computePickRay(0.5f, 0.5f)); + _myCamera.computeViewPickRay(0.5f, 0.5f)); sendEvent(this, &startActionEvent); } @@ -1222,7 +1222,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) { case Qt::Key_Space: { if (!event->isAutoRepeat()) { // this ends the HFActionEvent - HFActionEvent endActionEvent(HFActionEvent::endType(), _viewFrustum.computePickRay(0.5f, 0.5f)); + HFActionEvent endActionEvent(HFActionEvent::endType(), _myCamera.computeViewPickRay(0.5f, 0.5f)); sendEvent(this, &endActionEvent); } @@ -1253,7 +1253,6 @@ void Application::focusOutEvent(QFocusEvent* event) { } void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { - bool showMouse = true; // Used by application overlay to determine how to draw cursor(s) @@ -2079,8 +2078,10 @@ void Application::updateMouseRay() { x = _mouseX / (float)_glWidget->width(); y = _mouseY / (float)_glWidget->height(); } - _viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection); - + PickRay pickRay = _myCamera.computeViewPickRay(x, y); + _mouseRayOrigin = pickRay.origin; + _mouseRayDirection = pickRay.direction; + // adjust for mirroring if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { glm::vec3 mouseRayOffset = _mouseRayOrigin - _viewFrustum.getPosition(); diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 6e5a83790e..d069afb96a 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -97,20 +97,17 @@ void Camera::setFarClip(float f) { PickRay Camera::computePickRay(float x, float y) { float screenWidth = Application::getInstance()->getGLWidget()->width(); float screenHeight = Application::getInstance()->getGLWidget()->height(); - PickRay result; - if (OculusManager::isConnected()) { - result.origin = getPosition(); - Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction); - } else { - Application::getInstance()->getViewFrustum()->computePickRay(x / screenWidth, y / screenHeight, - result.origin, result.direction); - } - return result; + + return computeViewPickRay(x / screenWidth, y / screenHeight); } PickRay Camera::computeViewPickRay(float xRatio, float yRatio) { PickRay result; - Application::getInstance()->getViewFrustum()->computePickRay(xRatio, yRatio, result.origin, result.direction); + if (OculusManager::isConnected()) { + Application::getInstance()->getApplicationOverlay().computeOculusPickRay(xRatio, yRatio, result.origin, result.direction); + } else { + Application::getInstance()->getViewFrustum()->computePickRay(xRatio, yRatio, result.origin, result.direction); + } return result; } diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 5aacd36a12..67f19159cd 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -635,18 +635,7 @@ void EntityTreeRenderer::deleteReleasedModels() { } PickRay EntityTreeRenderer::computePickRay(float x, float y) { - float screenWidth = Application::getInstance()->getGLWidget()->width(); - float screenHeight = Application::getInstance()->getGLWidget()->height(); - PickRay result; - if (OculusManager::isConnected()) { - Camera* camera = Application::getInstance()->getCamera(); - result.origin = camera->getPosition(); - Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction); - } else { - ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); - viewFrustum->computePickRay(x / screenWidth, y / screenHeight, result.origin, result.direction); - } - return result; + return Application::getInstance()->getCamera()->computePickRay(x, y); } diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp index 40109703d6..039dc40961 100644 --- a/interface/src/scripting/JoystickScriptingInterface.cpp +++ b/interface/src/scripting/JoystickScriptingInterface.cpp @@ -133,7 +133,7 @@ void JoystickScriptingInterface::update() { // global action events fire in the center of the screen HFActionEvent actionEvent(actionType, - Application::getInstance()->getViewFrustum()->computePickRay(0.5f, 0.5f)); + Application::getInstance()->getCamera()->computeViewPickRay(0.5f, 0.5f)); qApp->sendEvent(qApp, &actionEvent); } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5a644718c7..36babb64e0 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -30,18 +30,19 @@ const quint64 MSECS_TO_USECS = 1000ULL; const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; -static const float MOUSE_PITCH_RANGE = 1.0f * PI; -static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; +static const float MOUSE_PITCH_RANGE = 1.0f * PI; +static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; -// Return a point's coordinates on a sphere from it's polar (theta) and azimutal (phi) angles. -glm::vec3 getPoint(float radius, float theta, float phi) { - return glm::vec3(radius * glm::sin(theta) * glm::sin(phi), - radius * glm::cos(theta), - radius * glm::sin(theta) * (-glm::cos(phi))); + +// Return a point's coordinates on a sphere from pitch and yaw +glm::vec3 getPoint(float yaw, float pitch) { + return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), + glm::sin(-pitch), + glm::cos(-pitch) * (-glm::cos(yaw))); } //Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should @@ -104,10 +105,10 @@ bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, void renderReticule(glm::quat orientation, float alpha) { const float reticleSize = TWO_PI / 80.0f; - glm::vec3 topLeft = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, - reticleSize / 2.0f); - glm::vec3 topRight = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, + reticleSize / 2.0f); - glm::vec3 bottomLeft = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, - reticleSize / 2.0f); - glm::vec3 bottomRight = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, + reticleSize / 2.0f); + glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); + glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); + glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); + glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f); glPushMatrix(); { glm::vec3 axis = glm::axis(orientation); @@ -284,11 +285,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_magSizeMult[i] > 0.0f) { //Render magnifier, but dont show border for mouse magnifier - float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; - float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; - float projection = + glm::vec2 projection = screenToOverlay(_reticulePosition[i]); - renderMagnifier(_reticulePosition[i], _magSizeMult[i], i != MOUSE); + renderMagnifier(projection, _magSizeMult[i], i != MOUSE); } } @@ -296,7 +295,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glDisable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, _alpha); - static float textureFOV = 0.0f, textureAspectRatio = 1.0f; if (textureFOV != _textureFov || @@ -417,11 +415,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as glColor4f(1.0f, 1.0f, 1.0f, 1.0f); } - - - - -void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const { +void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const { const float pitch = (0.5f - y) * MOUSE_PITCH_RANGE; const float yaw = (0.5f - x) * MOUSE_YAW_RANGE; const glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); @@ -429,6 +423,7 @@ void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direc //Rotate the UI pick ray by the avatar orientation const MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + origin = myAvatar->getDefaultEyePosition(); direction = myAvatar->getOrientation() * localDirection; } @@ -497,7 +492,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, glm::quat orientation = myAvatar->getOrientation(); - glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition()); + glm::vec3 relativePosition = orientation * (position - myAvatar->getDefaultEyePosition()); glm::vec3 relativeDirection = orientation * direction; float t; @@ -655,10 +650,6 @@ void ApplicationOverlay::renderControllerPointers() { } void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { - GLCanvas* glWidget = Application::getInstance()->getGLWidget(); - const int widgetWidth = glWidget->width(); - const int widgetHeight = glWidget->height(); - glBindTexture(GL_TEXTURE_2D, _crosshairTexture); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); @@ -735,10 +726,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { //Mouse Pointer if (_reticleActive[MOUSE]) { - float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE; - float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE; - glm::quat orientation(glm::vec3(pitch, yaw, 0.0f)); - + glm::vec2 projection = screenToSpherical(_reticulePosition[MOUSE]); + glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); renderReticule(orientation, _alpha); } @@ -753,37 +742,26 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool const int widgetWidth = glWidget->width(); const int widgetHeight = glWidget->height(); - if (magPos.x < 0 || magPos.x > widgetWidth || magPos.y < 0 || magPos.y > widgetHeight) { - return; - } - const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f; const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f; // Magnification Texture Coordinates - float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; - float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; - float magnifyVBottom = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; - float magnifyVTop = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; + const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth; + const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth; + const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight; + const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight; const float newHalfWidth = halfWidth * MAGNIFY_MULT; const float newHalfHeight = halfHeight * MAGNIFY_MULT; - //Get new UV coordinates from our magnification window - float newULeft = (magPos.x - newHalfWidth) / (float)widgetWidth; - float newURight = (magPos.x + newHalfWidth) / (float)widgetWidth; - float newVBottom = 1.0f - (magPos.y - newHalfHeight) / (float)widgetHeight; - float newVTop = 1.0f - (magPos.y + newHalfHeight) / (float)widgetHeight; + //Get yaw / pitch value for the corners + const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth, + magPos.y - newHalfHeight)); + const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth, + magPos.y + newHalfHeight)); - // Find spherical coordinates from newUV, fov and aspect ratio - float radius = _oculusUIRadius * application->getAvatar()->getScale(); - const float leftPhi = (newULeft - 0.5f) * _textureFov * _textureAspectRatio; - const float rightPhi = (newURight - 0.5f) * _textureFov * _textureAspectRatio; - const float bottomTheta = PI_OVER_TWO - (newVBottom - 0.5f) * _textureFov; - const float topTheta = PI_OVER_TWO - (newVTop - 0.5f) * _textureFov; - - glm::vec3 bottomLeft = getPoint(radius, bottomTheta, leftPhi); - glm::vec3 bottomRight = getPoint(radius, bottomTheta, rightPhi); - glm::vec3 topLeft = getPoint(radius, topTheta, leftPhi); - glm::vec3 topRight = getPoint(radius, topTheta, rightPhi); + const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y); + const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y); + const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y); + const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y); glPushMatrix(); { if (showBorder) { @@ -1065,14 +1043,14 @@ void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, for (int i = 0; i < stacks; i++) { float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f // abs(theta) <= fov / 2.0f - float theta = PI_OVER_TWO - fov * (stacksRatio - 0.5f); + float pitch = -fov * (stacksRatio - 0.5f); for (int j = 0; j < slices; j++) { float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f // abs(phi) <= fov * aspectRatio / 2.0f - float phi = fov * aspectRatio * (slicesRatio - 0.5f); + float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); - vertexPtr->position = getPoint(1.0f, theta, phi); + vertexPtr->position = getPoint(yaw, pitch); vertexPtr->uv.x = slicesRatio; vertexPtr->uv.y = stacksRatio; vertexPtr++; @@ -1180,3 +1158,43 @@ void ApplicationOverlay::TexturedHemisphere::render() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } + +glm::vec2 ApplicationOverlay::screenToSpherical(glm::vec2 screenPos) const { + QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize(); + float yaw = -(screenPos.x / screenSize.width() - 0.5f) * MOUSE_YAW_RANGE; + float pitch = (screenPos.y / screenSize.height() - 0.5f) * MOUSE_PITCH_RANGE; + + return glm::vec2(yaw, pitch); +} + +glm::vec2 ApplicationOverlay::sphericalToScreen(glm::vec2 sphericalPos) const { + QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize(); + float x = (-sphericalPos.x / MOUSE_YAW_RANGE + 0.5f) * screenSize.width(); + float y = (sphericalPos.y / MOUSE_PITCH_RANGE + 0.5f) * screenSize.height(); + + return glm::vec2(x, y); +} + +glm::vec2 ApplicationOverlay::sphericalToOverlay(glm::vec2 sphericalPos) const { + QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize(); + float x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f) * screenSize.width(); + float y = (sphericalPos.y / _textureFov + 0.5f) * screenSize.height(); + + return glm::vec2(x, y); +} + +glm::vec2 ApplicationOverlay::overlayToSpherical(glm::vec2 overlayPos) const { + QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize(); + float yaw = -(overlayPos.x / screenSize.width() - 0.5f) * _textureFov * _textureAspectRatio; + float pitch = (overlayPos.y / screenSize.height() - 0.5f) * _textureFov; + + return glm::vec2(yaw, pitch); +} + +glm::vec2 ApplicationOverlay::screenToOverlay(glm::vec2 screenPos) const { + return sphericalToOverlay(screenToSpherical(screenPos)); +} + +glm::vec2 ApplicationOverlay::overlayToScreen(glm::vec2 overlayPos) const { + return sphericalToScreen(overlayToSpherical(overlayPos)); +} diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 7c423b3a06..399cd504b8 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -30,10 +30,17 @@ public: void displayOverlayTextureOculus(Camera& whichCamera); void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov); - void computeOculusPickRay(float x, float y, glm::vec3& direction) const; + void computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const; QPoint getPalmClickLocation(const PalmData *palm) const; bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; - + + glm::vec2 screenToSpherical(glm::vec2 screenPos) const; + glm::vec2 sphericalToScreen(glm::vec2 sphericalPos) const; + glm::vec2 sphericalToOverlay(glm::vec2 sphericalPos) const; + glm::vec2 overlayToSpherical(glm::vec2 overlayPos) const; + glm::vec2 screenToOverlay(glm::vec2 screenPos) const; + glm::vec2 overlayToScreen(glm::vec2 overlayPos) const; + private: // Interleaved vertex data struct TextureVertex { diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index 49509cc9cf..631129321c 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -38,12 +38,7 @@ void NodeBounds::draw() { // Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers // itself after the cursor disappears. Application* application = Application::getInstance(); - GLCanvas* glWidget = application->getGLWidget(); - float mouseX = application->getMouseX() / (float)glWidget->width(); - float mouseY = application->getMouseY() / (float)glWidget->height(); - glm::vec3 mouseRayOrigin; - glm::vec3 mouseRayDirection; - application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection); + PickRay pickRay = application->getCamera()->computeViewPickRay(application->getMouseX(), application->getMouseY()); // Variables to keep track of the selected node and properties to draw the cube later if needed Node* selectedNode = NULL; @@ -106,8 +101,8 @@ void NodeBounds::draw() { float distance; BoxFace face; - bool inside = serverBounds.contains(mouseRayOrigin); - bool colliding = serverBounds.findRayIntersection(mouseRayOrigin, mouseRayDirection, distance, face); + bool inside = serverBounds.contains(pickRay.origin); + bool colliding = serverBounds.findRayIntersection(pickRay.origin, pickRay.direction, distance, face); // If the camera is inside a node it will be "selected" if you don't have your cursor over another node // that you aren't inside. From 84da070901e65c0a3cb1a709e1813a061da47817 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 18:27:03 -0800 Subject: [PATCH 029/100] Correct mouse position in occulus --- interface/src/Application.cpp | 86 +++++++++++++++++++------ interface/src/Application.h | 11 +++- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/NodeBounds.cpp | 6 +- 4 files changed, 78 insertions(+), 27 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe6e81bd79..ca3fcfdd1b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1305,18 +1305,20 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (event->button() == Qt::LeftButton) { _mouseX = event->x(); _mouseY = event->y(); - _mouseDragStartedX = _mouseX; - _mouseDragStartedY = _mouseY; + _mouseDragStartedX = getTrueMouseX(); + _mouseDragStartedY = getTrueMouseY(); _mousePressed = true; - - if (_audio.mousePressEvent(_mouseX, _mouseY)) { - // stop propagation - return; - } - - if (_rearMirrorTools->mousePressEvent(_mouseX, _mouseY)) { - // stop propagation - return; + + if (mouseOnScreen()) { + if (_audio.mousePressEvent(getMouseX(), getMouseY())) { + // stop propagation + return; + } + + if (_rearMirrorTools->mousePressEvent(getMouseX(), getMouseY())) { + // stop propagation + return; + } } // nobody handled this - make it an action event on the _window object @@ -1349,11 +1351,12 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { _mouseY = event->y(); _mousePressed = false; - checkBandwidthMeterClick(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) { // let's set horizontal offset to give stats some margin to mirror int horizontalOffset = MIRROR_VIEW_WIDTH; - Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset); + Stats::getInstance()->checkClick(getMouseX(), getMouseY(), + getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset); + checkBandwidthMeterClick(); } // fire an action end event @@ -1546,13 +1549,13 @@ void Application::idle() { void Application::checkBandwidthMeterClick() { // ... to be called upon button release - if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) && Menu::getInstance()->isOptionChecked(MenuOption::Stats) && Menu::getInstance()->isOptionChecked(MenuOption::UserInterface) && - glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) - <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH - && _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { + glm::compMax(glm::abs(glm::ivec2(getMouseX() - getMouseDragStartedX(), + getMouseY() - getMouseDragStartedY()))) + <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH + && _bandwidthMeter.isWithinArea(getMouseX(), getMouseY(), _glWidget->width(), _glWidget->height())) { // The bandwidth meter is visible, the click didn't get dragged too far and // we actually hit the bandwidth meter @@ -1666,6 +1669,48 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox (mouseVoxel.z + mouseVoxel.s / 2.0f) * TREE_SCALE); } +bool Application::mouseOnScreen() const { + if (OculusManager::isConnected()) { + return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() && + getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight(); + } + return true; +} + +int Application::getMouseX() const { + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); + return pos.x; + } + return getTrueMouseX(); +} + +int Application::getMouseY() const { + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY())); + return pos.y; + } + return getTrueMouseY(); +} + +int Application::getMouseDragStartedX() const { + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), + getTrueMouseDragStartedY())); + return pos.x; + } + return getTrueMouseDragStartedX(); +} + +int Application::getMouseDragStartedY() const { + if (OculusManager::isConnected()) { + glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseDragStartedX(), + getTrueMouseDragStartedY())); + return pos.y; + } + return getTrueMouseDragStartedY(); +} + FaceTracker* Application::getActiveFaceTracker() { return (_dde.isActive() ? static_cast(&_dde) : (_faceshift.isActive() ? static_cast(&_faceshift) : @@ -1898,7 +1943,6 @@ void Application::init() { _mouseX = _glWidget->width() / 2; _mouseY = _glWidget->height() / 2; - QCursor::setPos(_mouseX, _mouseY); // TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager _avatarManager.init(); @@ -2076,8 +2120,8 @@ void Application::updateMouseRay() { // if the mouse pointer isn't visible, act like it's at the center of the screen float x = 0.5f, y = 0.5f; if (!_mouseHidden) { - x = _mouseX / (float)_glWidget->width(); - y = _mouseY / (float)_glWidget->height(); + x = getTrueMouseX() / (float)_glWidget->width(); + y = getTrueMouseY() / (float)_glWidget->height(); } PickRay pickRay = _myCamera.computeViewPickRay(x, y); _mouseRayOrigin = pickRay.origin; diff --git a/interface/src/Application.h b/interface/src/Application.h index b737141b40..7c24eaec8e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -213,8 +213,15 @@ public: bool isMouseHidden() const { return _mouseHidden; } const glm::vec3& getMouseRayOrigin() const { return _mouseRayOrigin; } const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } - int getMouseX() const { return _mouseX; } - int getMouseY() const { return _mouseY; } + bool mouseOnScreen() const; + int getMouseX() const; + int getMouseY() const; + int getTrueMouseX() const { return _mouseX; } + int getTrueMouseY() const { return _mouseY; } + int getMouseDragStartedX() const; + int getMouseDragStartedY() const; + int getTrueMouseDragStartedX() const { return _mouseDragStartedX; } + int getTrueMouseDragStartedY() const { return _mouseDragStartedY; } bool getLastMouseMoveWasSimulated() const { return _lastMouseMoveWasSimulated;; } Faceshift* getFaceshift() { return &_faceshift; } Visage* getVisage() { return &_visage; } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 36babb64e0..287cd60a84 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -523,7 +523,7 @@ void ApplicationOverlay::renderPointers() { //If we are in oculus, render reticle later _reticleActive[MOUSE] = true; _magActive[MOUSE] = true; - _reticulePosition[MOUSE] = glm::vec2(application->getMouseX(), application->getMouseY()); + _reticulePosition[MOUSE] = glm::vec2(application->getTrueMouseX(), application->getTrueMouseY()); _reticleActive[LEFT_CONTROLLER] = false; _reticleActive[RIGHT_CONTROLLER] = false; diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index 631129321c..3c6b4c625a 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -38,7 +38,7 @@ void NodeBounds::draw() { // Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers // itself after the cursor disappears. Application* application = Application::getInstance(); - PickRay pickRay = application->getCamera()->computeViewPickRay(application->getMouseX(), application->getMouseY()); + PickRay pickRay = application->getCamera()->computeViewPickRay(application->getTrueMouseX(), application->getTrueMouseY()); // Variables to keep track of the selected node and properties to draw the cube later if needed Node* selectedNode = NULL; @@ -220,8 +220,8 @@ void NodeBounds::drawOverlay() { const int MOUSE_OFFSET = 10; const int BACKGROUND_BEVEL = 3; - int mouseX = application->getMouseX(), - mouseY = application->getMouseY(), + int mouseX = application->getTrueMouseX(), + mouseY = application->getTrueMouseY(), textWidth = widthText(TEXT_SCALE, 0, _overlayText); glColor4f(0.4f, 0.4f, 0.4f, 0.6f); renderBevelCornersRect(mouseX + MOUSE_OFFSET, mouseY - TEXT_HEIGHT - PADDING, From 9f444581e9175d0c440255dd8f0b8d0e10728030 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 18:53:30 -0800 Subject: [PATCH 030/100] Fixed JS picking in oculus --- interface/src/Application.cpp | 1 - interface/src/ui/overlays/Overlays.cpp | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ca3fcfdd1b..32517bc896 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1288,7 +1288,6 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { } void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { - if (!_aboutToQuit) { _entities.mousePressEvent(event, deviceID); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 455b73fb80..d991cb762c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -244,6 +245,11 @@ void Overlays::deleteOverlay(unsigned int id) { } unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { + glm::vec2 pointCpy = point; + if (OculusManager::isConnected()) { + pointCpy = Application::getInstance()->getApplicationOverlay().screenToOverlay(point); + } + QReadLocker lock(&_lock); QMapIterator i(_overlays2D); i.toBack(); @@ -251,7 +257,8 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { i.previous(); unsigned int thisID = i.key(); Overlay2D* thisOverlay = static_cast(i.value()); - if (thisOverlay->getVisible() && thisOverlay->isLoaded() && thisOverlay->getBounds().contains(point.x, point.y, false)) { + if (thisOverlay->getVisible() && thisOverlay->isLoaded() && + thisOverlay->getBounds().contains(pointCpy.x, pointCpy.y, false)) { return thisID; } } From d2b0cdbac31c08ca6dc96dfdce0596fa73d07180 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 19:31:59 -0800 Subject: [PATCH 031/100] Hydra reticule rendering for Oculus --- interface/src/ui/ApplicationOverlay.cpp | 84 ++++--------------------- 1 file changed, 13 insertions(+), 71 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 287cd60a84..71d1a728df 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -29,6 +29,7 @@ const quint64 MSECS_TO_USECS = 1000ULL; const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; +const float reticleSize = TWO_PI / 100.0f; const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; @@ -103,8 +104,6 @@ bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, } void renderReticule(glm::quat orientation, float alpha) { - const float reticleSize = TWO_PI / 80.0f; - glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); @@ -523,7 +522,7 @@ void ApplicationOverlay::renderPointers() { //If we are in oculus, render reticle later _reticleActive[MOUSE] = true; _magActive[MOUSE] = true; - _reticulePosition[MOUSE] = glm::vec2(application->getTrueMouseX(), application->getTrueMouseY()); + _reticulePosition[MOUSE] = glm::vec2(application->getMouseX(), application->getMouseY()); _reticleActive[LEFT_CONTROLLER] = false; _reticleActive[RIGHT_CONTROLLER] = false; @@ -658,70 +657,17 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { MyAvatar* myAvatar = Application::getInstance()->getAvatar(); for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { -// PalmData& palm = myAvatar->getHand()->getPalms()[i]; -// if (palm.isActive()) { -// glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); -// glm::vec3 tipPos = (tip - eyePos); -// -// float length = glm::length(eyePos - tip); -// float size = 0.03f * length; -// -// glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * size; -// glm::vec3 right = glm::vec3(1.0, 0.0, 0.0) * size; -// -// cursorVerts[0] = -right + up; -// cursorVerts[1] = right + up; -// cursorVerts[2] = right - up; -// cursorVerts[3] = -right - up; -// -// glPushMatrix(); -// -// // objToCamProj is the vector in world coordinates from the -// // local origin to the camera projected in the XZ plane -// glm::vec3 cursorToCameraXZ(-tipPos.x, 0, -tipPos.z); -// cursorToCameraXZ = glm::normalize(cursorToCameraXZ); -// -// //Translate the cursor to the tip of the oculus ray -// glTranslatef(tip.x, tip.y, tip.z); -// -// glm::vec3 direction(0, 0, 1); -// // easy fix to determine wether the angle is negative or positive -// // for positive angles upAux will be a vector pointing in the -// // positive y direction, otherwise upAux will point downwards -// // effectively reversing the rotation. -// glm::vec3 upAux = glm::cross(direction, cursorToCameraXZ); -// -// // compute the angle -// float angleCosine = glm::dot(direction, cursorToCameraXZ); -// -// //Rotate in XZ direction -// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, upAux[0], upAux[1], upAux[2]); -// -// glm::vec3 cursorToCamera = glm::normalize(-tipPos); -// -// // Compute the angle between cursorToCameraXZ and cursorToCamera, -// angleCosine = glm::dot(cursorToCameraXZ, cursorToCamera); -// -// //Rotate in Y direction -// if (cursorToCamera.y < 0) { -// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, 1, 0, 0); -// } else { -// glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, -1, 0, 0); -// } -// -// glBegin(GL_QUADS); -// -// glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha); -// -// glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z); -// glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z); -// glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z); -// glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z); -// -// glEnd(); -// -// glPopMatrix(); -// } + PalmData& palm = myAvatar->getHand()->getPalms()[i]; + if (palm.isActive()) { + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); + glm::vec3 tipDirection = glm::normalize(glm::inverse(myAvatar->getOrientation()) * (tip - eyePos)); + float pitch = -glm::asin(tipDirection.y); + float yawSign = glm::sign(-tipDirection.x); + float yaw = glm::acos(-tipDirection.z) * + ((yawSign == 0.0f) ? 1.0f : yawSign); + glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0.0f)); + renderReticule(orientation, _alpha); + } } //Mouse Pointer @@ -791,8 +737,6 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool } glPopMatrix(); } - - void ApplicationOverlay::renderAudioMeter() { Application* application = Application::getInstance(); @@ -990,8 +934,6 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { } } - - ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : _vertices(0), _indices(0), From 90d4e7bae92e9357741a4a9990c926d405c06e78 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 19:38:39 -0800 Subject: [PATCH 032/100] Comments --- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/ApplicationOverlay.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 71d1a728df..c029a2e00f 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -39,7 +39,7 @@ static const float MOUSE_PITCH_RANGE = 1.0f * PI; static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI; -// Return a point's coordinates on a sphere from pitch and yaw +// Return a point's cartesian coordinates on a sphere from pitch and yaw glm::vec3 getPoint(float yaw, float pitch) { return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)), glm::sin(-pitch), diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 399cd504b8..2ca430aae6 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -34,6 +34,13 @@ public: QPoint getPalmClickLocation(const PalmData *palm) const; bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const; + // Converter from one frame of reference to another. + // Frame of reference: + // Screen: Position on the screen (x,y) + // Spherical: Pitch and yaw that gives the position on the sphere we project on (yaw,pitch) + // Overlay: Position on the overlay (x,y) + // (x,y) in Overlay are similar than (x,y) in Screen except they can be outside of the bound of te screen. + // This allows for picking outside of the screen projection in 3D. glm::vec2 screenToSpherical(glm::vec2 screenPos) const; glm::vec2 sphericalToScreen(glm::vec2 sphericalPos) const; glm::vec2 sphericalToOverlay(glm::vec2 sphericalPos) const; From 7322cd3ecee1e80613ab0362ab68cb62a4e7fd44 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 4 Dec 2014 20:16:50 -0800 Subject: [PATCH 033/100] Coding Standard --- interface/src/ui/overlays/Overlays.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index d991cb762c..25e667e56c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -245,9 +245,9 @@ void Overlays::deleteOverlay(unsigned int id) { } unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { - glm::vec2 pointCpy = point; + glm::vec2 pointCopy = point; if (OculusManager::isConnected()) { - pointCpy = Application::getInstance()->getApplicationOverlay().screenToOverlay(point); + pointCopy = Application::getInstance()->getApplicationOverlay().screenToOverlay(point); } QReadLocker lock(&_lock); @@ -258,7 +258,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { unsigned int thisID = i.key(); Overlay2D* thisOverlay = static_cast(i.value()); if (thisOverlay->getVisible() && thisOverlay->isLoaded() && - thisOverlay->getBounds().contains(pointCpy.x, pointCpy.y, false)) { + thisOverlay->getBounds().contains(pointCopy.x, pointCopy.y, false)) { return thisID; } } From c5247ca65b0cfde24b83fd7e8969dc9c9111ae96 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 5 Dec 2014 08:45:00 -0800 Subject: [PATCH 034/100] Add ability to set injector properties during playing, and orbitingSound.js --- examples/orbitingSound.js | 49 +++++++++++++++++++ .../audio/src/AudioScriptingInterface.cpp | 7 +++ libraries/audio/src/AudioScriptingInterface.h | 2 + 3 files changed, 58 insertions(+) create mode 100644 examples/orbitingSound.js diff --git a/examples/orbitingSound.js b/examples/orbitingSound.js new file mode 100644 index 0000000000..903d73cebc --- /dev/null +++ b/examples/orbitingSound.js @@ -0,0 +1,49 @@ +// +// orbitingSound.js +// examples +// +// Created by Philip Rosedale on December 4, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// An object playing a sound appears and circles you, changing brightness with the audio playing. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var RADIUS = 2.0; +var orbitCenter = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.getOrientation()), RADIUS)); +var time = 0; +var SPEED = 1.0; +var currentPosition = { x: 0, y: 0, z: 0 }; +var trailingLoudness = 0.0; + +var soundClip = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Tabla+Loops/Tabla1.wav"); + +var properties = { + type: "Box", + position: orbitCenter, + dimensions: { x: 0.25, y: 0.25, z: 0.25 }, + color: { red: 100, green: 0, blue : 0 } + }; + +var objectId = Entities.addEntity(properties); +var sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 }); + +function update(deltaTime) { + time += deltaTime; + currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS }; + trailingLoudness = 0.9 * trailingLoudness + 0.1 * Audio.getLoudness(sound); + Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } ); + //if (Audio.isInjectorPlaying(sound)) { + Audio.setInjectorOptions(sound, { position: currentPosition }); + //} else { + // sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 }); + //} +} + +Script.scriptEnding.connect(function() { + Entities.deleteEntity(objectId); + Audio.stopInjector(sound); +}); + +Script.update.connect(update); \ No newline at end of file diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index b604e2825b..8cd133ad40 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -85,6 +85,13 @@ bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) { return (injector != NULL); } +void AudioScriptingInterface::setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions) { + AudioInjectorOptions optionsCopy = injectorOptions; + if (injector) { + injector->setOptions(optionsCopy); + } +} + float AudioScriptingInterface::getLoudness(AudioInjector* injector) { if (injector) { return injector->getLoudness(); diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/audio/src/AudioScriptingInterface.h index 5b67666a97..b437286ecf 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/audio/src/AudioScriptingInterface.h @@ -35,6 +35,8 @@ public slots: void stopInjector(AudioInjector* injector); bool isInjectorPlaying(AudioInjector* injector); + void setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions); + void injectorStopped(); signals: From bc609016a91ca8a2fb14406f213b0bf07603cea4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 5 Dec 2014 08:59:41 -0800 Subject: [PATCH 035/100] remove debug --- examples/orbitingSound.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/orbitingSound.js b/examples/orbitingSound.js index 903d73cebc..54e319faaa 100644 --- a/examples/orbitingSound.js +++ b/examples/orbitingSound.js @@ -34,11 +34,7 @@ function update(deltaTime) { currentPosition = { x: orbitCenter.x + Math.cos(time * SPEED) * RADIUS, y: orbitCenter.y, z: orbitCenter.z + Math.sin(time * SPEED) * RADIUS }; trailingLoudness = 0.9 * trailingLoudness + 0.1 * Audio.getLoudness(sound); Entities.editEntity( objectId, { position: currentPosition, color: { red: Math.min(trailingLoudness * 2000, 255), green: 0, blue: 0 } } ); - //if (Audio.isInjectorPlaying(sound)) { - Audio.setInjectorOptions(sound, { position: currentPosition }); - //} else { - // sound = Audio.playSound(soundClip, { position: orbitCenter, loop: true, volume: 0.5 }); - //} + Audio.setInjectorOptions(sound, { position: currentPosition }); } Script.scriptEnding.connect(function() { From feab9423758b639fccbd3a958ce52d27faea1c91 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 10:01:16 -0800 Subject: [PATCH 036/100] Revert "get rid of redundant _displayViewFrustum and use _viewFrustum" This reverts commit 6d385d9a75de786e0d1f583ad8448c30a9df2492. --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 ++ interface/src/MetavoxelSystem.cpp | 6 +++--- interface/src/renderer/DeferredLightingEffect.cpp | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 85b21b073f..44f83102e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2910,7 +2910,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr // transform by eye offset // load the view frustum - loadViewFrustum(whichCamera, _viewFrustum); + loadViewFrustum(whichCamera, _displayViewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -3184,7 +3184,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { // allow 3DTV/Oculus to override parameters from camera - _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + _displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); if (OculusManager::isConnected()) { OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); diff --git a/interface/src/Application.h b/interface/src/Application.h index b737141b40..e432f7fdf0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -196,6 +196,7 @@ public: const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } + ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } @@ -517,6 +518,7 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) + ViewFrustum _displayViewFrustum; ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 996b92e22d..b98fea8eca 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -192,7 +192,7 @@ static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; void MetavoxelSystem::render() { // update the frustum - ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); + ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); @@ -1896,7 +1896,7 @@ private: SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), lod, - encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -1932,7 +1932,7 @@ private: BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : MetavoxelVisitor(QVector() << attribute), - _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index 63d874cda7..be4e457131 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -232,8 +232,8 @@ void DeferredLightingEffect::render() { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - const glm::vec3& eyePoint = Application::getInstance()->getViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, Application::getInstance()->getViewFrustum()->getNearTopLeft()); + const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); + float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft()); if (!_pointLights.isEmpty()) { _pointLight.bind(); From 9753c82a3bc5b5bdb2cea5f596c71e66d0823b67 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 2 Dec 2014 11:45:33 -0800 Subject: [PATCH 037/100] get rid of redundant _displayViewFrustum and use _viewFrustum --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 -- interface/src/MetavoxelSystem.cpp | 6 +++--- interface/src/renderer/DeferredLightingEffect.cpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44f83102e2..85b21b073f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2910,7 +2910,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr // transform by eye offset // load the view frustum - loadViewFrustum(whichCamera, _displayViewFrustum); + loadViewFrustum(whichCamera, _viewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -3184,7 +3184,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { // allow 3DTV/Oculus to override parameters from camera - _displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); if (OculusManager::isConnected()) { OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); diff --git a/interface/src/Application.h b/interface/src/Application.h index e432f7fdf0..b737141b40 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -196,7 +196,6 @@ public: const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } - ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } @@ -518,7 +517,6 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) - ViewFrustum _displayViewFrustum; ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b98fea8eca..996b92e22d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -192,7 +192,7 @@ static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; void MetavoxelSystem::render() { // update the frustum - ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); + ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); @@ -1896,7 +1896,7 @@ private: SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), lod, - encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), + encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -1932,7 +1932,7 @@ private: BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : MetavoxelVisitor(QVector() << attribute), - _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), + _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index be4e457131..63d874cda7 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -232,8 +232,8 @@ void DeferredLightingEffect::render() { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft()); + const glm::vec3& eyePoint = Application::getInstance()->getViewFrustum()->getPosition(); + float nearRadius = glm::distance(eyePoint, Application::getInstance()->getViewFrustum()->getNearTopLeft()); if (!_pointLights.isEmpty()) { _pointLight.bind(); From e68e3fe774df3dd9d9942735718823cb06fca6bf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 10:06:17 -0800 Subject: [PATCH 038/100] Revert "get rid of redundant _displayViewFrustum and use _viewFrustum" This reverts commit 6d385d9a75de786e0d1f583ad8448c30a9df2492. --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 2 ++ interface/src/MetavoxelSystem.cpp | 6 +++--- interface/src/renderer/DeferredLightingEffect.cpp | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 85b21b073f..44f83102e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2910,7 +2910,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr // transform by eye offset // load the view frustum - loadViewFrustum(whichCamera, _viewFrustum); + loadViewFrustum(whichCamera, _displayViewFrustum); // flip x if in mirror mode (also requires reversing winding order for backface culling) if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -3184,7 +3184,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { // allow 3DTV/Oculus to override parameters from camera - _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + _displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); if (OculusManager::isConnected()) { OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); diff --git a/interface/src/Application.h b/interface/src/Application.h index b737141b40..e432f7fdf0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -196,6 +196,7 @@ public: const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } + ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } VoxelImporter* getVoxelImporter() { return &_voxelImporter; } VoxelSystem* getVoxels() { return &_voxels; } @@ -517,6 +518,7 @@ private: ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) + ViewFrustum _displayViewFrustum; ViewFrustum _shadowViewFrustum; quint64 _lastQueriedTime; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 996b92e22d..b98fea8eca 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -192,7 +192,7 @@ static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; void MetavoxelSystem::render() { // update the frustum - ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum(); + ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); _frustum.set(viewFrustum->getFarTopLeft(), viewFrustum->getFarTopRight(), viewFrustum->getFarBottomLeft(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); @@ -1896,7 +1896,7 @@ private: SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector(), QVector(), lod, - encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } @@ -1932,7 +1932,7 @@ private: BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : MetavoxelVisitor(QVector() << attribute), - _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), + _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())), _containmentDepth(INT_MAX) { } diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index 63d874cda7..be4e457131 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -232,8 +232,8 @@ void DeferredLightingEffect::render() { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - const glm::vec3& eyePoint = Application::getInstance()->getViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, Application::getInstance()->getViewFrustum()->getNearTopLeft()); + const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); + float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft()); if (!_pointLights.isEmpty()) { _pointLight.bind(); From 0ece6c0968dc2764c0cdfbc16f5198b2f3fd12fd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 5 Dec 2014 10:43:15 -0800 Subject: [PATCH 039/100] Update properties window to show properties for locked entities --- examples/html/entityProperties.html | 150 ++++++++++++++-------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index a79edfb181..87ab066c5c 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -163,99 +163,99 @@ disableChildren(document.getElementById("properties"), 'input'); elLocked.removeAttribute('disabled'); } else { - enableChildren(document.getElementById("properties"), 'input'); + enableChildren(document.getElementById("properties-table"), 'input'); + } - elVisible.checked = properties.visible; + elVisible.checked = properties.visible; - elPositionX.value = properties.position.x.toFixed(2); - elPositionY.value = properties.position.y.toFixed(2); - elPositionZ.value = properties.position.z.toFixed(2); + elPositionX.value = properties.position.x.toFixed(2); + elPositionY.value = properties.position.y.toFixed(2); + elPositionZ.value = properties.position.z.toFixed(2); - elDimensionsX.value = properties.dimensions.x.toFixed(2); - elDimensionsY.value = properties.dimensions.y.toFixed(2); - elDimensionsZ.value = properties.dimensions.z.toFixed(2); + elDimensionsX.value = properties.dimensions.x.toFixed(2); + elDimensionsY.value = properties.dimensions.y.toFixed(2); + elDimensionsZ.value = properties.dimensions.z.toFixed(2); - elRegistrationX.value = properties.registrationPoint.x.toFixed(2); - elRegistrationY.value = properties.registrationPoint.y.toFixed(2); - elRegistrationZ.value = properties.registrationPoint.z.toFixed(2); + elRegistrationX.value = properties.registrationPoint.x.toFixed(2); + elRegistrationY.value = properties.registrationPoint.y.toFixed(2); + elRegistrationZ.value = properties.registrationPoint.z.toFixed(2); - elLinearVelocityX.value = properties.velocity.x.toFixed(2); - elLinearVelocityY.value = properties.velocity.y.toFixed(2); - elLinearVelocityZ.value = properties.velocity.z.toFixed(2); - elLinearDamping.value = properties.damping.toFixed(2); + elLinearVelocityX.value = properties.velocity.x.toFixed(2); + elLinearVelocityY.value = properties.velocity.y.toFixed(2); + elLinearVelocityZ.value = properties.velocity.z.toFixed(2); + elLinearDamping.value = properties.damping.toFixed(2); - elAngularVelocityX.value = properties.angularVelocity.x.toFixed(2); - elAngularVelocityY.value = properties.angularVelocity.y.toFixed(2); - elAngularVelocityZ.value = properties.angularVelocity.z.toFixed(2); - elAngularDamping.value = properties.angularDamping.toFixed(2); + elAngularVelocityX.value = properties.angularVelocity.x.toFixed(2); + elAngularVelocityY.value = properties.angularVelocity.y.toFixed(2); + elAngularVelocityZ.value = properties.angularVelocity.z.toFixed(2); + elAngularDamping.value = properties.angularDamping.toFixed(2); - elGravityX.value = properties.gravity.x.toFixed(2); - elGravityY.value = properties.gravity.y.toFixed(2); - elGravityZ.value = properties.gravity.z.toFixed(2); + elGravityX.value = properties.gravity.x.toFixed(2); + elGravityY.value = properties.gravity.y.toFixed(2); + elGravityZ.value = properties.gravity.z.toFixed(2); - elMass.value = properties.mass.toFixed(2); - elIgnoreForCollisions.checked = properties.ignoreForCollisions; - elCollisionsWillMove.checked = properties.collisionsWillMove; - elLifetime.value = properties.lifetime; + elMass.value = properties.mass.toFixed(2); + elIgnoreForCollisions.checked = properties.ignoreForCollisions; + elCollisionsWillMove.checked = properties.collisionsWillMove; + elLifetime.value = properties.lifetime; - if (properties.type != "Box") { - elBoxSection.style.display = 'none'; - } else { - elBoxSection.style.display = 'block'; + if (properties.type != "Box") { + elBoxSection.style.display = 'none'; + } else { + elBoxSection.style.display = 'block'; - elBoxColorRed.value = properties.color.red; - elBoxColorGreen.value = properties.color.green; - elBoxColorBlue.value = properties.color.blue; - } + elBoxColorRed.value = properties.color.red; + elBoxColorGreen.value = properties.color.green; + elBoxColorBlue.value = properties.color.blue; + } - if (properties.type != "Model") { - elModelSection.style.display = 'none'; - } else { - elModelSection.style.display = 'block'; - elModelURL.value = properties.modelURL; - elModelAnimationURL.value = properties.animationURL; - elModelAnimationPlaying.checked = properties.animationIsPlaying; - elModelAnimationFPS.value = properties.animationFPS; - } + if (properties.type != "Model") { + elModelSection.style.display = 'none'; + } else { + elModelSection.style.display = 'block'; + elModelURL.value = properties.modelURL; + elModelAnimationURL.value = properties.animationURL; + elModelAnimationPlaying.checked = properties.animationIsPlaying; + elModelAnimationFPS.value = properties.animationFPS; + } - if (properties.type != "Text") { - elTextSection.style.display = 'none'; - } else { - elTextSection.style.display = 'block'; + if (properties.type != "Text") { + elTextSection.style.display = 'none'; + } else { + elTextSection.style.display = 'block'; - elTextText.value = properties.text; - elTextLineHeight.value = properties.lineHeight; - elTextTextColorRed.value = properties.textColor.red; - elTextTextColorGreen.value = properties.textColor.green; - elTextTextColorBlue.value = properties.textColor.blue; - elTextBackgroundColorRed.value = properties.backgroundColor.red; - elTextBackgroundColorGreen.value = properties.backgroundColor.green; - elTextBackgroundColorBlue.value = properties.backgroundColor.blue; - } + elTextText.value = properties.text; + elTextLineHeight.value = properties.lineHeight; + elTextTextColorRed.value = properties.textColor.red; + elTextTextColorGreen.value = properties.textColor.green; + elTextTextColorBlue.value = properties.textColor.blue; + elTextBackgroundColorRed.value = properties.backgroundColor.red; + elTextBackgroundColorGreen.value = properties.backgroundColor.green; + elTextBackgroundColorBlue.value = properties.backgroundColor.blue; + } - if (properties.type != "Light") { - elLightSection.style.display = 'none'; - } else { - elLightSection.style.display = 'block'; + if (properties.type != "Light") { + elLightSection.style.display = 'none'; + } else { + elLightSection.style.display = 'block'; - elLightDiffuseRed.value = properties.diffuseColor.red; - elLightDiffuseGreen.value = properties.diffuseColor.green; - elLightDiffuseBlue.value = properties.diffuseColor.blue; + elLightDiffuseRed.value = properties.diffuseColor.red; + elLightDiffuseGreen.value = properties.diffuseColor.green; + elLightDiffuseBlue.value = properties.diffuseColor.blue; - elLightAmbientRed.value = properties.ambientColor.red; - elLightAmbientGreen.value = properties.ambientColor.green; - elLightAmbientBlue.value = properties.ambientColor.blue; + elLightAmbientRed.value = properties.ambientColor.red; + elLightAmbientGreen.value = properties.ambientColor.green; + elLightAmbientBlue.value = properties.ambientColor.blue; - elLightSpecularRed.value = properties.specularColor.red; - elLightSpecularGreen.value = properties.specularColor.green; - elLightSpecularBlue.value = properties.specularColor.blue; + elLightSpecularRed.value = properties.specularColor.red; + elLightSpecularGreen.value = properties.specularColor.green; + elLightSpecularBlue.value = properties.specularColor.blue; - elLightConstantAttenuation.value = properties.constantAttenuation; - elLightLinearAttenuation.value = properties.linearAttenuation; - elLightQuadraticAttenuation.value = properties.quadraticAttenuation; - elLightExponent.value = properties.exponent; - elLightCutoff.value = properties.cutoff; - } + elLightConstantAttenuation.value = properties.constantAttenuation; + elLightLinearAttenuation.value = properties.linearAttenuation; + elLightQuadraticAttenuation.value = properties.quadraticAttenuation; + elLightExponent.value = properties.exponent; + elLightCutoff.value = properties.cutoff; } } } From 849397288e07f8257653261ff585f816459edca6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 5 Dec 2014 10:46:35 -0800 Subject: [PATCH 040/100] Update properties tool to be a resizable table --- examples/html/entityProperties.html | 521 +++++++++++++++------------- examples/html/style.css | 64 +++- 2 files changed, 331 insertions(+), 254 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 87ab066c5c..97e16fcf11 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -160,7 +160,7 @@ elLocked.checked = properties.locked; if (properties.locked) { - disableChildren(document.getElementById("properties"), 'input'); + disableChildren(document.getElementById("properties-table"), 'input'); elLocked.removeAttribute('disabled'); } else { enableChildren(document.getElementById("properties-table"), 'input'); @@ -345,7 +345,7 @@ elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying')); elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS')); elModelAnimationFrame.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFrameIndex')); - + elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text')); elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight')); @@ -361,6 +361,50 @@ elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction); elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction); + + var resizing = false; + var startX = 0; + var originalWidth = 0; + var resizeHandleWidth = 10; + + var col1 = document.querySelector("#col-label"); + + document.body.addEventListener('mousemove', function(event) { + if (resizing) { + var dX = event.x - startX; + col1.style.width = (originalWidth + dX) + "px"; + } + }); + document.body.addEventListener('mouseup', function(event) { + resizing = false; + }); + document.body.addEventListener('mouseleave', function(event) { + resizing = false; + }); + var els = document.querySelectorAll("#properties-table td"); + for (var i = 0; i < els.length; i++) { + var el = els[i]; + el.addEventListener('mousemove', function(event) { + if (!resizing) { + var distance = this.offsetWidth - event.offsetX; + if (distance < resizeHandleWidth) { + document.body.style.cursor = "ew-resize"; + } else { + document.body.style.cursor = "initial"; + } + } + }); + el.addEventListener('mousedown', function(event) { + var distance = this.offsetWidth - event.offsetX; + if (distance < resizeHandleWidth) { + startX = event.x; + originalWidth = this.offsetWidth; + resizing = true; + target = this; + } + }); + } + } @@ -368,272 +412,269 @@
-
-
- - - -
- -
- - + + + + + + + + + + + + + -
- - +
+ + + -
- - - X - Y - Z - -
+ + + + -
- - - X - Y - Z - -
+ + + + -
- - +
+ + + + + + + + + + + -
- - - X - Y - Z - -
-
- - +
+ + + + + + + + + + + + + + + -
- - - X - Y - Z - -
+ + + + -
- - +
+ + + -
- - +
+ + + -
- - +
+ + + -
- - +
+ + + -
-
- - - Red - Green - Blue - -
-
+ + + + -
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
-
-
- - - - -
-
- - - - -
-
- - - Red - Green - Blue - -
-
- - - Red - Green - Blue - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
-
- - - - -
-
- - - Red - Green - Blue - -
-
- - - Red - Green - Blue - -
-
- - - Red - Green - Blue - -
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
- - - - -
-
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Type + + +
Locked - - +
Visible - - +
Position +
X
+
Y
+
Z
+
Registration +
X
+
Y
+
Z
+
Width - - -
- - +
Height - - -
- - +
Depth - - +
Linear +
X
+
Y
+
Z
+
Linear Damping - - -
- - - Pitch - Roll - Yaw - -
-
- - +
Angular +
Pitch
+
Yaw
+
Roll
+
Angular Damping - - +
Gravity +
X
+
Y
+
Z
+
Mass - - +
Ignore For Collisions - - +
Collisions Will Move - - +
Lifetime - - +
Color +
Red
+
Green
+
Blue
+
Model URL + +
Animation URL + +
Animation Playing + +
Animation FPS + +
Animation Frame + +
Text + +
Line Height + +
Text Color +
Red
+
Green
+
Blue
+
Background Color +
Red
+
Green
+
Blue
+
Spot Light + +
Diffuse +
Red
+
Green
+
Blue
+
Ambient +
Red
+
Green
+
Blue
+
Specular +
Red
+
Green
+
Blue
+
Constant Attenuation + +
Linear Attenuation + +
Quadratic Attenuation + +
Exponent + +
Cutoff (degrees) + +
diff --git a/examples/html/style.css b/examples/html/style.css index b721c31b88..424933e14e 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -17,15 +17,6 @@ body { user-select: none; } -input { - line-height: 2; -} - -.input-left { - display: inline-block; - width: 20px; -} - .color-box { display: inline-block; width: 20px; @@ -63,7 +54,6 @@ input { .property-section label { font-weight: bold; - vertical-align: middle; } .property-section span { @@ -89,9 +79,10 @@ input[type=button] { font-size: .9em; } -input.coord { - width: 6em; - height: 2em; +input { + padding: 2px; + border: 1px solid #999; + background-color: #eee; } table#entity-table { @@ -105,7 +96,7 @@ table#entity-table { cursor: pointer; } -tr.selected { +#entity-table tr.selected { background-color: #AAA; } @@ -130,3 +121,48 @@ th#entity-type { th#entity-url { } + + +div.input-area { + display: inline-block; +} + +input { +} + + + +table#properties-table { + border: none; + border-collapse: collapse; + width: 100%; + background-color: #efefef; + font-family: Arial; + font-size: 12px; + table-layout: fixed; +} + +#properties-table tr { + border-bottom: 1px solid #e5e5e5; +} + +#properties-table td.label { + padding-right: 10px; + border-right: 1px solid #999; + text-align: right; + font-weight: bold; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + vertical-align: middle; + height: 1.2em; +} + +#properties-table td { + padding: 5px 0px 5px 10px; +} + +col#col-label { + width: 130px; +} From f5a1c264925962abd32480bf148a6ffd03124448 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 5 Dec 2014 11:08:00 -0800 Subject: [PATCH 041/100] Add backgroundAlpha property to 2D and 3D text overlays --- examples/overlaysExample.js | 4 +++- interface/src/ui/overlays/Text3DOverlay.cpp | 10 ++++++++++ interface/src/ui/overlays/Text3DOverlay.h | 2 ++ interface/src/ui/overlays/TextOverlay.cpp | 9 +++++++++ interface/src/ui/overlays/TextOverlay.h | 3 +++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index 0d47f7ca64..4aa5b1cd75 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -69,7 +69,8 @@ var text = Overlays.addOverlay("text", { topMargin: 4, leftMargin: 4, text: "Here is some text.\nAnd a second line.", - alpha: 0.7 + alpha: 0.7, + backgroundAlpha: 0.5 }); // This will create an image overlay, which starts out as invisible @@ -170,6 +171,7 @@ var clipboardPreview = Overlays.addOverlay("clipboard", { // Demonstrate retrieving overlay properties print("Text overlay text property value =\n" + Overlays.getProperty(text, "text")); print("Text overlay alpha =\n" + Overlays.getProperty(text, "alpha")); +print("Text overlay background alpha =\n" + Overlays.getProperty(text, "backgroundAlpha")); print("Text overlay visible =\n" + Overlays.getProperty(text, "visible")); print("Text overlay font size =\n" + Overlays.getProperty(text, "font").size); print("Text overlay anchor =\n" + Overlays.getProperty(text, "anchor")); diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index dbb423ad99..bd3ab47bce 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -16,12 +16,14 @@ #include "ui/TextRenderer.h" const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; +const float DEFAULT_BACKGROUND_ALPHA = 0.7f; const float DEFAULT_MARGIN = 0.1f; const int FIXED_FONT_POINT_SIZE = 40; const float LINE_SCALE_RATIO = 1.2f; Text3DOverlay::Text3DOverlay() : _backgroundColor(DEFAULT_BACKGROUND_COLOR), + _backgroundAlpha(DEFAULT_BACKGROUND_ALPHA), _lineHeight(0.1f), _leftMargin(DEFAULT_MARGIN), _topMargin(DEFAULT_MARGIN), @@ -35,6 +37,7 @@ Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) : Planar3DOverlay(text3DOverlay), _text(text3DOverlay->_text), _backgroundColor(text3DOverlay->_backgroundColor), + _backgroundAlpha(text3DOverlay->_backgroundAlpha), _lineHeight(text3DOverlay->_lineHeight), _leftMargin(text3DOverlay->_leftMargin), _topMargin(text3DOverlay->_topMargin), @@ -166,6 +169,10 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) { } } + if (properties.property("backgroundAlpha").isValid()) { + _backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat(); + } + if (properties.property("lineHeight").isValid()) { setLineHeight(properties.property("lineHeight").toVariant().toFloat()); } @@ -200,6 +207,9 @@ QScriptValue Text3DOverlay::getProperty(const QString& property) { if (property == "backgroundColor") { return xColorToScriptValue(_scriptEngine, _backgroundColor); } + if (property == "backgroundAlpha") { + return _backgroundAlpha; + } if (property == "lineHeight") { return _lineHeight; } diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index c624830ac8..d74131391a 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -37,6 +37,7 @@ public: float getBottomMargin() const { return _bottomMargin; } bool getIsFacingAvatar() const { return _isFacingAvatar; } xColor getBackgroundColor(); + float getBackgroundAlpha() const { return _backgroundAlpha; } // setters void setText(const QString& text) { _text = text; } @@ -59,6 +60,7 @@ private: QString _text; xColor _backgroundColor; + float _backgroundAlpha; float _lineHeight; float _leftMargin; float _topMargin; diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 1d72cf7f05..68823d813d 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -19,6 +19,7 @@ TextOverlay::TextOverlay() : _backgroundColor(DEFAULT_BACKGROUND_COLOR), + _backgroundAlpha(DEFAULT_BACKGROUND_ALPHA), _leftMargin(DEFAULT_MARGIN), _topMargin(DEFAULT_MARGIN), _fontSize(DEFAULT_FONTSIZE) @@ -29,6 +30,7 @@ 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) @@ -125,6 +127,10 @@ void TextOverlay::setProperties(const QScriptValue& properties) { } } + if (properties.property("backgroundAlpha").isValid()) { + _backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat(); + } + if (properties.property("leftMargin").isValid()) { setLeftMargin(properties.property("leftMargin").toVariant().toInt()); } @@ -150,6 +156,9 @@ QScriptValue TextOverlay::getProperty(const QString& property) { if (property == "backgroundColor") { return xColorToScriptValue(_scriptEngine, _backgroundColor); } + if (property == "backgroundAlpha") { + return _backgroundAlpha; + } if (property == "leftMargin") { return _leftMargin; } diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 703e15be10..754faea2bc 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -28,6 +28,7 @@ #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 = 11; const int DEFAULT_FONT_WEIGHT = 50; @@ -46,6 +47,7 @@ public: int getLeftMargin() const { return _leftMargin; } int getTopMargin() const { return _topMargin; } xColor getBackgroundColor(); + float getBackgroundAlpha() const { return _backgroundAlpha; } // setters void setText(const QString& text) { _text = text; } @@ -62,6 +64,7 @@ public: private: QString _text; xColor _backgroundColor; + float _backgroundAlpha; int _leftMargin; int _topMargin; int _fontSize; From bd6ea9b4e782930280933ce02f5cbd338ffc20e4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 5 Dec 2014 11:18:03 -0800 Subject: [PATCH 042/100] Render with backgroundAlpha property --- interface/src/ui/overlays/Text3DOverlay.cpp | 5 +++-- interface/src/ui/overlays/TextOverlay.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index bd3ab47bce..2e80fae8a0 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -91,8 +91,8 @@ void Text3DOverlay::render(RenderArgs* args) { const float MAX_COLOR = 255.0f; xColor backgroundColor = getBackgroundColor(); - float alpha = getAlpha(); - glColor4f(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, alpha); + glColor4f(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, + getBackgroundAlpha()); glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; @@ -127,6 +127,7 @@ void Text3DOverlay::render(RenderArgs* args) { enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y); glColor3f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR); + float alpha = getAlpha(); QStringList lines = _text.split("\n"); int lineOffset = maxHeight; foreach(QString thisLine, lines) { diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 68823d813d..272c9bc916 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -65,11 +65,10 @@ void TextOverlay::render(RenderArgs* args) { return; // do nothing if we're not visible } - const float MAX_COLOR = 255.0f; xColor backgroundColor = getBackgroundColor(); - float alpha = getAlpha(); - glColor4f(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, alpha); + glColor4f(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, + getBackgroundAlpha()); glBegin(GL_QUADS); glVertex2f(_bounds.left(), _bounds.top()); @@ -87,6 +86,7 @@ void TextOverlay::render(RenderArgs* args) { int y = _bounds.top() + _topMargin + topAdjust; glColor3f(_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR); + float alpha = getAlpha(); QStringList lines = _text.split("\n"); int lineOffset = 0; foreach(QString thisLine, lines) { From a6b86da47af2f75ec013d6e3eaa6d08793629f7c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 11:31:27 -0800 Subject: [PATCH 043/100] basics of triangle picking working for models --- examples/developerMenuItems.js | 1 + interface/src/Menu.h | 1 + .../entities/RenderableModelEntityItem.cpp | 9 +- interface/src/renderer/Model.cpp | 148 +++++++++++++++++- interface/src/renderer/Model.h | 12 +- interface/src/ui/overlays/Base3DOverlay.cpp | 2 +- interface/src/ui/overlays/Base3DOverlay.h | 4 +- .../src/ui/overlays/BillboardOverlay.cpp | 2 +- interface/src/ui/overlays/BillboardOverlay.h | 2 +- interface/src/ui/overlays/Circle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Circle3DOverlay.h | 2 +- interface/src/ui/overlays/ModelOverlay.cpp | 4 +- interface/src/ui/overlays/ModelOverlay.h | 4 +- interface/src/ui/overlays/Planar3DOverlay.cpp | 2 +- interface/src/ui/overlays/Planar3DOverlay.h | 2 +- interface/src/ui/overlays/Volume3DOverlay.cpp | 2 +- interface/src/ui/overlays/Volume3DOverlay.h | 2 +- libraries/entities/src/EntityTreeElement.cpp | 23 ++- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/fbx/src/FBXReader.cpp | 1 + libraries/fbx/src/FBXReader.h | 1 + libraries/octree/src/OctreeElement.cpp | 45 ++++-- libraries/octree/src/OctreeElement.h | 2 +- libraries/shared/src/GeometryUtil.cpp | 46 ++++++ libraries/shared/src/GeometryUtil.h | 16 ++ 25 files changed, 298 insertions(+), 39 deletions(-) diff --git a/examples/developerMenuItems.js b/examples/developerMenuItems.js index 221975c9c8..0d2c4895ea 100644 --- a/examples/developerMenuItems.js +++ b/examples/developerMenuItems.js @@ -24,6 +24,7 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt to Reduce Material Switches", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Pick Against Model Triangles", isCheckable: true, isChecked: false }); Menu.addMenu("Developer > Entities > Culling"); Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Out Of View Mesh Parts", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Too Small Mesh Parts", isCheckable: true, isChecked: false }); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 0d46c4020d..520c83177e 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -432,6 +432,7 @@ namespace MenuOption { const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString Pair = "Pair"; const QString PasteToVoxel = "Paste to Voxel..."; + const QString PickAgainstModelTriangles = "Pick Against Model Triangles"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString Quit = "Quit"; diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index ccd6622856..6bc6f52782 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -133,9 +133,6 @@ void RenderableModelEntityItem::render(RenderArgs* args) { getModel(renderer); } - - - if (_model) { // handle animations.. if (hasAnimation()) { @@ -175,7 +172,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); + bool dontRenderAsScene = true; // Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); if (dontRenderAsScene) { _model->render(alpha, modelRenderMode, args); } else { @@ -270,10 +267,14 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori qDebug() << " originInMeters:" << originInMeters; QString extraInfo; float localDistance; + bool intersectsModel = _model->findRayIntersectionAgainstSubMeshes(originInMeters, direction, localDistance, face, extraInfo); if (intersectsModel) { + // NOTE: findRayIntersectionAgainstSubMeshes() does work in meters, but we're expected to return + // results in tree scale. distance = localDistance / (float)TREE_SCALE; + qDebug() << " --hit this mode -- returning distance:" << distance; } return intersectsModel; // we only got here if we intersected our non-aabox diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 19176c4833..6b398284a3 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -54,6 +54,7 @@ Model::Model(QObject* parent) : _blendNumber(0), _appliedBlendNumber(0), _calculatedMeshBoxesValid(false), + _calculatedMeshTrianglesValid(false), _meshGroupsKnown(false) { // we may have been created in the network thread, but we live in the main thread @@ -516,7 +517,7 @@ void Model::setJointStates(QVector states) { } bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) const { + float& distance, BoxFace& face, QString& extraInfo) { bool intersectedSomething = false; @@ -524,8 +525,12 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (!isActive()) { return intersectedSomething; } + + bool pickAgainstTriangles = Menu::getInstance()->isOptionChecked(MenuOption::PickAgainstModelTriangles); qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; + qDebug() << " origin:" << origin; + qDebug() << " direction:" << direction; // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; @@ -538,31 +543,58 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g qDebug() << " modelExtents:" << modelExtents; glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; - glm::vec3 corner = dimensions * -0.5f; // since we're going to do the ray picking in the model frame of reference + glm::vec3 corner = dimensions * _registrationPoint; // since we're going to do the ray picking in the model frame of reference AABox overlayFrameBox(corner, dimensions); qDebug() << " overlayFrameBox:" << overlayFrameBox; glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); + qDebug() << " modelFrameOrigin:" << modelFrameOrigin; + qDebug() << " modelFrameDirection:" << modelFrameDirection; // we can use the AABox's ray intersection by mapping our origin and direction into the model frame // and testing intersection there. if (overlayFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { float bestDistance = std::numeric_limits::max(); + float bestTriangleDistance = std::numeric_limits::max(); + bool someTriangleHit = false; + float distanceToSubMesh; BoxFace subMeshFace; int subMeshIndex = 0; - + + const FBXGeometry& geometry = _geometry->getFBXGeometry(); // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { - const FBXGeometry& geometry = _geometry->getFBXGeometry(); qDebug() << "subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { if (distanceToSubMesh < bestDistance) { + + if (pickAgainstTriangles) { + if (!_calculatedMeshTrianglesValid) { + recalcuateMeshBoxes(); + } + // check our triangles here.... + const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; + int t = 0; + foreach (const Triangle& triangle, meshTriangles) { + //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; + t++; + + float thisTriangleDistance; + if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { + if (thisTriangleDistance < bestTriangleDistance) { + bestTriangleDistance = thisTriangleDistance; + someTriangleHit = true; + } + } + } + } + bestDistance = distanceToSubMesh; intersectedSomething = true; face = subMeshFace; @@ -571,6 +603,27 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g } subMeshIndex++; } + + // if we were asked to pick against triangles, and we didn't hit one, then we + // do not consider this model to be hit at all. + if (pickAgainstTriangles && !someTriangleHit) { + intersectedSomething = false; + } + qDebug() << "pickAgainstTriangles:" << pickAgainstTriangles; + qDebug() << "someTriangleHit:" << someTriangleHit; + qDebug() << "bestTriangleDistance:" << bestTriangleDistance; + qDebug() << "bestDistance:" << bestDistance; + + if (intersectedSomething) { + qDebug() << " --- we hit this model --- "; + + if (pickAgainstTriangles) { + distance = bestTriangleDistance; + } else { + distance = bestDistance; + } + qDebug() << "distance:" << distance; + } return intersectedSomething; } @@ -579,17 +632,92 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g } void Model::recalcuateMeshBoxes() { - if (!_calculatedMeshBoxesValid) { + bool pickAgainstTriangles = Menu::getInstance()->isOptionChecked(MenuOption::PickAgainstModelTriangles); + bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; + + if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded) { + qDebug() << "Model::recalcuateMeshBoxes()"; PerformanceTimer perfTimer("calculatedMeshBoxes"); const FBXGeometry& geometry = _geometry->getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); + _calculatedMeshTriangles.clear(); for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); + + qDebug() << "mesh.meshExtents["< thisMeshTriangles; + for (int j = 0; j < mesh.parts.size(); j++) { + const FBXMeshPart& part = mesh.parts.at(j); + + const int INDICES_PER_TRIANGLE = 3; + const int INDICES_PER_QUAD = 4; + + if (part.quadIndices.size() > 0) { + int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD; + qDebug() << "numberOfQuads:" << numberOfQuads; + int vIndex = 0; + for (int q = 0; q < numberOfQuads; q++) { + int i0 = part.quadIndices[vIndex++]; + int i1 = part.quadIndices[vIndex++]; + int i2 = part.quadIndices[vIndex++]; + int i3 = part.quadIndices[vIndex++]; + + glm::vec3 v0 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f))); + glm::vec3 v1 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f))); + glm::vec3 v2 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f))); + glm::vec3 v3 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f))); + + Triangle tri1 = { v0, v1, v3 }; + Triangle tri2 = { v1, v2, v3 }; + + //qDebug() << "quad["<< q <<"].t1 :" << v0 << ", "<< v1 << ", " << v3; + //qDebug() << "quad["<< q <<"].t2 :" << v1 << ", "<< v2 << ", " << v3; + + thisMeshTriangles.push_back(tri1); + thisMeshTriangles.push_back(tri2); + } + } + + if (part.triangleIndices.size() > 0) { + int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE; + qDebug() << "numberOfTris:" << numberOfTris; + int vIndex = 0; + for (int t = 0; t < numberOfTris; t++) { + int i0 = part.triangleIndices[vIndex++]; + int i1 = part.triangleIndices[vIndex++]; + int i2 = part.triangleIndices[vIndex++]; + + glm::vec3 v0 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f))); + glm::vec3 v1 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f))); + glm::vec3 v2 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f))); + + Triangle tri = { v0, v1, v2 }; + + //qDebug() << "triangle["<< t <<"] :" << v0 << ", " << v1 << ", " << v2; + + thisMeshTriangles.push_back(tri); + } + } + } + + _calculatedMeshTriangles.push_back(thisMeshTriangles); + qDebug() << "------------------------------------------------------------------------------"; + } + } _calculatedMeshBoxesValid = true; + _calculatedMeshTrianglesValid = pickAgainstTriangles; } } @@ -851,6 +979,15 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { return translatedExtents; } +glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { + // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix + glm::vec3 offsetPoint = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(point, 1.0f)); + glm::vec3 scaledPoint = ((offsetPoint + _offset) * _scale); + glm::vec3 rotatedPoint = _rotation * scaledPoint; + glm::vec3 translatedPoint = rotatedPoint + _translation; + return translatedPoint; +} + bool Model::getJointState(int index, glm::quat& rotation) const { if (index == -1 || index >= _jointStates.size()) { @@ -1149,6 +1286,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { if (isActive() && fullUpdate) { _calculatedMeshBoxesValid = false; // if we have to simulate, we need to assume our mesh boxes are all invalid + _calculatedMeshTrianglesValid = false; // check for scale to fit if (_scaleToFit && !_scaledToFit) { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b16cf11b09..406622e6a8 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -19,6 +19,7 @@ #include "Transform.h" #include #include +#include #include #include "AnimationHandle.h" @@ -34,7 +35,6 @@ class Shape; #include "RenderArgs.h" class ViewFrustum; - #include "gpu/Stream.h" #include "gpu/Batch.h" @@ -119,6 +119,9 @@ public: /// Returns the scaled equivalent of some extents in model space. Extents calculateScaledOffsetExtents(const Extents& extents) const; + /// Returns the scaled equivalent of a point in model space. + glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; + /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } @@ -194,7 +197,7 @@ public: { _geometry->setTextureWithNameToURL(name, url); } bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) const; + float& distance, BoxFace& face, QString& extraInfo); protected: QSharedPointer _geometry; @@ -361,8 +364,11 @@ private: static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1); - QVector _calculatedMeshBoxes; + QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; + + QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes + bool _calculatedMeshTrianglesValid; void recalcuateMeshBoxes(); diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 55b4c88812..a9588cd7a3 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -167,7 +167,7 @@ QScriptValue Base3DOverlay::getProperty(const QString& property) { } bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) const { + float& distance, BoxFace& face) { return false; } diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index d57f9731c4..b5314bd6d3 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -50,10 +50,10 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) const { + float& distance, BoxFace& face, QString& extraInfo) { return findRayIntersection(origin, direction, distance, face); } diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index 5fbad7839a..f9ad7fdb38 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -213,7 +213,7 @@ void BillboardOverlay::replyFinished() { } bool BillboardOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) const { + float& distance, BoxFace& face) { if (_billboardTexture) { float maxSize = glm::max(_fromImage.width(), _fromImage.height()); diff --git a/interface/src/ui/overlays/BillboardOverlay.h b/interface/src/ui/overlays/BillboardOverlay.h index be947acf98..03daef934d 100644 --- a/interface/src/ui/overlays/BillboardOverlay.h +++ b/interface/src/ui/overlays/BillboardOverlay.h @@ -35,7 +35,7 @@ public: void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); virtual BillboardOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index d19297b589..68d589d20b 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -355,7 +355,7 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, - const glm::vec3& direction, float& distance, BoxFace& face) const { + const glm::vec3& direction, float& distance, BoxFace& face) { bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); if (intersects) { diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index b428be7a43..92fdf54c82 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -48,7 +48,7 @@ public: void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; } void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; } - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); virtual Circle3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 60049e0b3b..ecce137f4d 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -170,14 +170,14 @@ QScriptValue ModelOverlay::getProperty(const QString& property) { } bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) const { + float& distance, BoxFace& face) { QString subMeshNameTemp; return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, subMeshNameTemp); } bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) const { + float& distance, BoxFace& face, QString& extraInfo) { return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo); } diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 80b52ea27e..567498feb5 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -26,9 +26,9 @@ public: virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) const; + float& distance, BoxFace& face, QString& extraInfo); virtual ModelOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index a8288b241c..628ff6a7dc 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -92,7 +92,7 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) { } bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) const { + float& distance, BoxFace& face) { RayIntersectionInfo rayInfo; rayInfo._rayStart = origin; diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h index d34fe44ebc..9355265f80 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.h +++ b/interface/src/ui/overlays/Planar3DOverlay.h @@ -39,7 +39,7 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); protected: glm::vec2 _dimensions; diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index c4192a15b2..40fea5c8c9 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -100,7 +100,7 @@ QScriptValue Volume3DOverlay::getProperty(const QString& property) { } bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) const { + float& distance, BoxFace& face) { // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = getPosition(); diff --git a/interface/src/ui/overlays/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h index 005646c036..7938641a8f 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.h +++ b/interface/src/ui/overlays/Volume3DOverlay.h @@ -41,7 +41,7 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); protected: glm::vec3 _dimensions; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e18f79276e..e0ebe47412 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -475,7 +475,7 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) { + void** intersectedObject, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... @@ -509,15 +509,32 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. + qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; + qDebug() << " origin:" << origin; + qDebug() << " checking entity:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + qDebug() << " distance:" << distance; + if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { + qDebug() << " localDistance:" << localDistance; + if (localDistance < distance) { + qDebug() << " localDistance < distance... continue..."; + // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { + + qDebug() << " entity->supportsDetailedRayIntersection()...."; if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, localFace, intersectedObject)) { + + qDebug() << " localDistance (detailed):" << localDistance; if (localDistance < distance) { + + qDebug() << " localDistance < distance..."; + qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + distance = localDistance; face = localFace; *intersectedObject = (void*)entity; @@ -527,6 +544,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con } else { // if the entity type doesn't support a detailed intersection, then just return the non-AABox results if (localDistance < distance) { + + qDebug() << " localDistance < distance..."; + qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + distance = localDistance; face = localFace; *intersectedObject = (void*)entity; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index ab3754749b..e59b35189f 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -137,7 +137,7 @@ public: virtual bool canRayIntersect() const { return hasEntities(); } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject); + void** intersectedObject, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 8126463d27..d52d342d78 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -2044,6 +2044,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, extracted.mesh.meshExtents.minimum = glm::min(extracted.mesh.meshExtents.minimum, transformedVertex); extracted.mesh.meshExtents.maximum = glm::max(extracted.mesh.meshExtents.maximum, transformedVertex); + extracted.mesh.modelTransform = modelTransform; } // look for textures, material properties diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index c34a9677a6..659893c128 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -149,6 +149,7 @@ public: QVector clusters; Extents meshExtents; + glm::mat4 modelTransform; bool isEye; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index e5db8b24f8..e085298c33 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1339,28 +1339,54 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 keepSearching = true; // assume that we will continue searching after this. AACube cube = getAACube(); - float localDistance; + float distanceToElementCube = std::numeric_limits::max(); + float distanceToElementDetails = distance; BoxFace localFace; + qDebug() << "OctreeElement::findRayIntersection()...."; + qDebug() << " origin:" << origin; + qDebug() << " checking element:" << cube; + qDebug() << " distance:" << distance; + // if the ray doesn't intersect with our cube, we can stop searching! - if (!cube.findRayIntersection(origin, direction, localDistance, localFace)) { + if (!cube.findRayIntersection(origin, direction, distanceToElementCube, localFace)) { + qDebug() << " didn't intersect cube... done searching..."; keepSearching = false; // no point in continuing to search return false; // we did not intersect } + qDebug() << " distanceToElementCube:" << distanceToElementCube; + // by default, we only allow intersections with leaves with content if (!canRayIntersect()) { return false; // we don't intersect with non-leaves, and we keep searching } // we did hit this element, so calculate appropriate distances - localDistance *= TREE_SCALE; - if (localDistance < distance) { + //localDistance *= TREE_SCALE; + + // if the distance to the element cube is not less than the current best distance, then it's not possible + // for any details inside the cube to be closer so we don't need to consider them. + if (distanceToElementCube < distance) { + + qDebug() << " distanceToElementCube < distance:" << (distanceToElementCube < distance); + qDebug() << " continue.... call... findDetailedRayIntersection()..."; + //qDebug() << " distanceToElementCube < distance -- continue.... call... findDetailedRayIntersection()..."; + if (findDetailedRayIntersection(origin, direction, keepSearching, - element, distance, face, intersectedObject)) { - distance = localDistance; - face = localFace; - return true; + element, distanceToElementDetails, face, intersectedObject, distanceToElementCube)) { + + qDebug() << " findDetailedRayIntersection() -- intersected something"; + if (distanceToElementDetails < distance) { + qDebug() << " distanceToElementDetails < distance -- THIS ONE IS GOOD -------"; + + distance = distanceToElementDetails; + face = localFace; + + qDebug() << " distance:" << distance << " -- THIS ONE IS GOOD -------"; + + return true; + } } } return false; @@ -1368,11 +1394,12 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) { + void** intersectedObject, float distanceToElementCube) { // we did hit this element, so calculate appropriate distances if (hasContent()) { element = this; + distance = distanceToElementCube; if (intersectedObject) { *intersectedObject = this; } diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 2bd5e3ae1e..9161a9b171 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -123,7 +123,7 @@ public: virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject); + void** intersectedObject, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 1b6472a18f..c064630f83 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -252,6 +252,52 @@ bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direct return true; } +bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { + + glm::vec3 e1, e2, h, s, q; + float a, f, u, v, t; + + e1 = v1 - v0; + e2 = v2 - v0; + + h = glm::cross(direction, e2); + a = glm::dot(e1, h); + + if (a > -0.00001 && a < 0.00001) { + return false; + } + + f = 1/a; + s = origin - v0; + u = f * glm::dot(s,h); + + if (u < 0.0 || u > 1.0) { + return false; + } + + q = glm::cross(s, e1); + v = f * glm::dot(direction, q); + + if (v < 0.0 || u + v > 1.0) { + return false; + } + + // at this stage we can compute t to find out where the intersection point is on the line + t = f * glm::dot(e2,q); + + // ray intersection + if (t > 0.00001) { + distance = t; + return true; + } else { + // this means that there is a line intersection but not a ray intersection + return false; + } + return false; +} + + // 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) { diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index b521a79771..f439352ca8 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -76,6 +76,22 @@ bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& directi bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance); +bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance); + +class Triangle { +public: + glm::vec3 v0; + glm::vec3 v1; + glm::vec3 v2; +}; + +inline bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, + const Triangle& triangle, float& distance) { + return findRayTrianlgeIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance); +} + + 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); int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk); From 69792178b95f5eb4a1223456fb3052aeff0fed8d Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 5 Dec 2014 13:43:04 -0800 Subject: [PATCH 044/100] trying to fix the linux compilation --- libraries/gpu/src/gpu/GPUConfig.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index faecfd4889..393a476182 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -18,14 +18,15 @@ #include #include -#elif defined(UNIX) -#include -#include - #elif defined(WIN32) #include #include +#else +#include +#include + + #endif #endif From 2c8b1721cc56c08503467819c7261e00cf70ee62 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 5 Dec 2014 14:06:41 -0800 Subject: [PATCH 045/100] Add warp from right ('O') button on gamepad --- examples/butterflies.js | 2 +- examples/headMove.js | 88 +++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/examples/butterflies.js b/examples/butterflies.js index 9bd568d011..069a0d6792 100644 --- a/examples/butterflies.js +++ b/examples/butterflies.js @@ -32,7 +32,7 @@ var startTimeInSeconds = new Date().getTime() / 1000; var NATURAL_SIZE_OF_BUTTERFLY = { x: 1.0, y: 0.4, z: 0.2 }; var lifeTime = 3600; // One hour lifespan -var range = 5.0; // Over what distance in meters do you want the flock to fly around +var range = 7.0; // Over what distance in meters do you want the flock to fly around var frame = 0; var DISTANCE_IN_FRONT_OF_ME = 1.5; diff --git a/examples/headMove.js b/examples/headMove.js index 4d2e4ded07..943664b70f 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -11,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var gamepads = {}; + var debug = false; var willMove = false; @@ -19,7 +21,6 @@ var warpPosition = { x: 0, y: 0, z: 0 }; var hipsToEyes; var restoreCountdownTimer; -var headTurningTimer = 0.0; // Overlays to show target location @@ -62,13 +63,6 @@ function restoreCameraState() { Camera.mode = oldMode; } -function activateWarp() { - if (warpActive) return; - warpActive = true; - - updateWarp(); -} - var WATCH_AVATAR_DISTANCE = 2.5; var sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); @@ -132,6 +126,22 @@ function updateWarp() { }); } +function activateWarp() { + if (warpActive) return; + warpActive = true; + movingWithHead = true; + hipsToEyes = MyAvatar.getEyePosition().y - MyAvatar.position.y; + headStartPosition = MyAvatar.getTrackedHeadPosition(); + headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); + headStartFinalPitch = MyAvatar.getHeadFinalPitch(); + headStartRoll = MyAvatar.getHeadFinalRoll(); + headStartYaw = MyAvatar.getHeadFinalYaw(); + deltaYaw = 0.0; + warpPosition = MyAvatar.position; + warpPosition.y += hipsToEyes; + updateWarp(); +} + function finishWarp() { if (!warpActive) return; warpActive = false; @@ -152,6 +162,9 @@ function finishWarp() { cameraPosition = Vec3.subtract(MyAvatar.position, Vec3.multiplyQbyV(Camera.getOrientation(), { x: 0, y: -hipsToEyes, z: -hipsToEyes * WATCH_AVATAR_DISTANCE })); Camera.setPosition(cameraPosition); playSound(); + if (watchAvatar) { + restoreCountdownTimer = RESTORE_TIME; + } } } @@ -169,35 +182,11 @@ function update(deltaTime) { restoreCountDownTimer = 0.0; } } - var HEAD_TURN_TIME = 0.10; - var HEAD_TURN_DEGREES = 4.0; - var HEAD_TURN_START_ANGLE = 45.0; - var currentYaw = MyAvatar.getHeadFinalYaw(); - if (Math.abs(currentYaw) > HEAD_TURN_START_ANGLE) { - headTurningTimer += deltaTime; - if (headTurningTimer > HEAD_TURN_TIME) { - headTurningTimer = 0.0; - MyAvatar.orientation = Quat.multiply(Quat.fromPitchYawRollDegrees(0, (currentYaw > 0) ? HEAD_TURN_DEGREES: -HEAD_TURN_DEGREES, 0), - MyAvatar.orientation); - } - } else { - headTurningTimer = 0.0; - } } Controller.keyPressEvent.connect(function(event) { if (event.text == "SPACE" && !event.isAutoRepeat && !movingWithHead) { keyDownTime = 0.0; - movingWithHead = true; - hipsToEyes = MyAvatar.getEyePosition().y - MyAvatar.position.y; - headStartPosition = MyAvatar.getTrackedHeadPosition(); - headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); - headStartFinalPitch = MyAvatar.getHeadFinalPitch(); - headStartRoll = MyAvatar.getHeadFinalRoll(); - headStartYaw = MyAvatar.getHeadFinalYaw(); - deltaYaw = 0.0; - warpPosition = MyAvatar.position; - warpPosition.y += hipsToEyes; activateWarp(); } }); @@ -223,11 +212,40 @@ Controller.keyReleaseEvent.connect(function(event) { } timeSinceLastUp = 0.0; finishWarp(); - if (watchAvatar) { - restoreCountdownTimer = RESTORE_TIME; - } } }); +function reportButtonValue(button, newValue, oldValue) { + if (button == Joysticks.BUTTON_FACE_RIGHT) { + if (newValue) { + activateWarp(); + } else { + finishWarp(); + } + } +} + Script.update.connect(update); +function addJoystick(gamepad) { + gamepad.buttonStateChanged.connect(reportButtonValue); + + gamepads[gamepad.instanceId] = gamepad; + + print("Added gamepad: " + gamepad.name + " (" + gamepad.instanceId + ")"); +} + +function removeJoystick(gamepad) { + delete gamepads[gamepad.instanceId] + + print("Removed gamepad: " + gamepad.name + " (" + gamepad.instanceId + ")"); +} + +var allJoysticks = Joysticks.getAllJoysticks(); +for (var i = 0; i < allJoysticks.length; i++) { + addJoystick(allJoysticks[i]); +} + +Joysticks.joystickAdded.connect(addJoystick); +Joysticks.joystickRemoved.connect(removeJoystick); + From 0ccbb98bdee1985567b24a39c38fc0cd05368890 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 15:03:35 -0800 Subject: [PATCH 046/100] more work on improved model picking --- libraries/entities/src/EntityTreeElement.cpp | 26 +++++++++++++++++--- libraries/octree/src/OctreeElement.cpp | 10 ++++++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e0ebe47412..c452dab5cb 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -478,10 +478,19 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con void** intersectedObject, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... + + qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; + qDebug() << " origin:" << origin; + qDebug() << " distance:" << distance; + qDebug() << " number of entities:" << _entityItems->size(); + int entityNumber = 0; QList::iterator entityItr = _entityItems->begin(); QList::const_iterator entityEnd = _entityItems->end(); bool somethingIntersected = false; + + //float bestEntityDistance = distance; + while(entityItr != entityEnd) { EntityItem* entity = (*entityItr); @@ -489,9 +498,16 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con float localDistance; BoxFace localFace; + qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; + qDebug() << " checking entity[" << entityNumber << "]:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + qDebug() << " checking the AABox:" << entityBox; + // if the ray doesn't intersect with our cube, we can stop searching! if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { + qDebug() << " AABox for entity intersects!"; + qDebug() << " localDistance:" << localDistance; + // extents is the entity relative, scaled, centered extents of the entity glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); glm::mat4 translation = glm::translate(entity->getPosition()); @@ -509,12 +525,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. - qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; - qDebug() << " origin:" << origin; - qDebug() << " checking entity:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); - qDebug() << " distance:" << distance; + qDebug() << " checking the entityFrameBox:" << entityFrameBox; if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { + qDebug() << " entityFrameBox intersects!"; qDebug() << " localDistance:" << localDistance; if (localDistance < distance) { @@ -559,7 +573,11 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con } ++entityItr; + entityNumber++; } + + qDebug() << " EntityTreeElement::findDetailedRayIntersection().... returning somethingIntersected:" << somethingIntersected << "keepSearching:" << keepSearching; + return somethingIntersected; } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index e085298c33..330624f4b9 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1343,9 +1343,12 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 float distanceToElementDetails = distance; BoxFace localFace; + AACube debugCube = cube; + debugCube.scale((float)TREE_SCALE); + qDebug() << "OctreeElement::findRayIntersection()...."; qDebug() << " origin:" << origin; - qDebug() << " checking element:" << cube; + qDebug() << " checking element:" << debugCube << "in meters"; qDebug() << " distance:" << distance; // if the ray doesn't intersect with our cube, we can stop searching! @@ -1359,6 +1362,7 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 // by default, we only allow intersections with leaves with content if (!canRayIntersect()) { + qDebug() << " NOT canRayIntersect() -- no point in calling detailed..."; return false; // we don't intersect with non-leaves, and we keep searching } @@ -1367,9 +1371,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 // if the distance to the element cube is not less than the current best distance, then it's not possible // for any details inside the cube to be closer so we don't need to consider them. - if (distanceToElementCube < distance) { + if (cube.contains(origin) || distanceToElementCube < distance) { qDebug() << " distanceToElementCube < distance:" << (distanceToElementCube < distance); + qDebug() << " cube.contains(origin):" << (cube.contains(origin)); qDebug() << " continue.... call... findDetailedRayIntersection()..."; //qDebug() << " distanceToElementCube < distance -- continue.... call... findDetailedRayIntersection()..."; @@ -1403,6 +1408,7 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g if (intersectedObject) { *intersectedObject = this; } + qDebug() << " OctreeElement::findDetailedRayIntersection().... hasContent() -- done searching..."; keepSearching = false; return true; // we did intersect } From 896a34212b455ca8ab3ba9bb1593e93a76a0eae5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 5 Dec 2014 15:27:24 -0800 Subject: [PATCH 047/100] Fix sections not properly updating in properties tool --- examples/html/entityProperties.html | 202 +++++++++++++++------------- 1 file changed, 106 insertions(+), 96 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 97e16fcf11..0308d7f5e7 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -104,12 +104,12 @@ var elCollisionsWillMove = document.getElementById("property-collisions-will-move"); var elLifetime = document.getElementById("property-lifetime"); - var elBoxSection = document.getElementById("box-section"); + var elBoxSections = document.querySelectorAll(".box-section"); var elBoxColorRed = document.getElementById("property-box-red"); var elBoxColorGreen = document.getElementById("property-box-green"); var elBoxColorBlue = document.getElementById("property-box-blue"); - var elLightSection = document.getElementById('light-section'); + var elLightSections = document.querySelectorAll(".light-section"); var elLightSpotLight = document.getElementById("property-light-spot-light"); var elLightDiffuseRed = document.getElementById("property-light-diffuse-red"); var elLightDiffuseGreen = document.getElementById("property-light-diffuse-green"); @@ -129,14 +129,14 @@ var elLightExponent = document.getElementById("property-light-exponent"); var elLightCutoff = document.getElementById("property-light-cutoff"); - var elModelSection = document.getElementById("model-section"); + var elModelSections = document.querySelectorAll(".model-section"); var elModelURL = document.getElementById("property-model-url"); var elModelAnimationURL = document.getElementById("property-model-animation-url"); var elModelAnimationPlaying = document.getElementById("property-model-animation-playing"); var elModelAnimationFPS = document.getElementById("property-model-animation-fps"); var elModelAnimationFrame = document.getElementById("property-model-animation-frame"); - var elTextSection = document.getElementById("text-section"); + var elTextSections = document.querySelectorAll(".text-section"); var elTextText = document.getElementById("property-text-text"); var elTextLineHeight = document.getElementById("property-text-line-height"); var elTextTextColorRed = document.getElementById("property-text-text-color-red"); @@ -200,9 +200,13 @@ elLifetime.value = properties.lifetime; if (properties.type != "Box") { - elBoxSection.style.display = 'none'; + for (var i = 0; i < elBoxSections.length; i++) { + elBoxSections[i].style.display = 'none'; + } } else { - elBoxSection.style.display = 'block'; + for (var i = 0; i < elBoxSections.length; i++) { + elBoxSections[i].style.display = 'table-row'; + } elBoxColorRed.value = properties.color.red; elBoxColorGreen.value = properties.color.green; @@ -210,9 +214,14 @@ } if (properties.type != "Model") { - elModelSection.style.display = 'none'; + for (var i = 0; i < elModelSections.length; i++) { + elModelSections[i].style.display = 'none'; + } } else { - elModelSection.style.display = 'block'; + for (var i = 0; i < elModelSections.length; i++) { + elModelSections[i].style.display = 'table-row'; + } + elModelURL.value = properties.modelURL; elModelAnimationURL.value = properties.animationURL; elModelAnimationPlaying.checked = properties.animationIsPlaying; @@ -220,9 +229,13 @@ } if (properties.type != "Text") { - elTextSection.style.display = 'none'; + for (var i = 0; i < elTextSections.length; i++) { + elTextSections[i].style.display = 'none'; + } } else { - elTextSection.style.display = 'block'; + for (var i = 0; i < elTextSections.length; i++) { + elTextSections[i].style.display = 'table-row'; + } elTextText.value = properties.text; elTextLineHeight.value = properties.lineHeight; @@ -235,9 +248,13 @@ } if (properties.type != "Light") { - elLightSection.style.display = 'none'; + for (var i = 0; i < elLightSections.length; i++) { + elLightSections[i].style.display = 'none'; + } } else { - elLightSection.style.display = 'block'; + for (var i = 0; i < elLightSections.length; i++) { + elLightSections[i].style.display = 'table-row'; + } elLightDiffuseRed.value = properties.diffuseColor.red; elLightDiffuseGreen.value = properties.diffuseColor.green; @@ -437,7 +454,7 @@ - + Position @@ -446,7 +463,7 @@
Y
Z
- + Registration @@ -455,55 +472,45 @@
Y
Z
- + - Width + Dimensions - +
X
+
Y
+
Z
- - - Height - - - - - - Depth - - - - + - Linear + Linear Velocity
X
Y
Z
- + Linear Damping + - - Angular + Angular Velocity
Pitch
Yaw
Roll
- + Angular Damping - + Gravity @@ -512,168 +519,171 @@
Y
Z
- + Mass - + Ignore For Collisions - + Collisions Will Move - + Lifetime + + - + Color -
Red
-
Green
-
Blue
+
R
+
G
+
B
- + - + Model URL - - + + Animation URL - - + + Animation Playing - - + + Animation FPS - - + + Animation Frame - + - + + Text - - + + Line Height - - + + Text Color -
Red
-
Green
-
Blue
+
R
+
G
+
B
- - + + Background Color -
Red
-
Green
-
Blue
+
R
+
G
+
B
- + - + Spot Light - - + + Diffuse -
Red
-
Green
-
Blue
+
R
+
G
+
B
- - + + Ambient -
Red
-
Green
-
Blue
+
R
+
G
+
B
- - + + Specular -
Red
-
Green
-
Blue
+
R
+
G
+
B
- - + + Constant Attenuation - - + + Linear Attenuation - - + + Quadratic Attenuation - - + + Exponent - - + + Cutoff (degrees) - + From a89411fd5eeb2f7e1a07e482b9f04441d7e9a910 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 5 Dec 2014 15:27:40 -0800 Subject: [PATCH 048/100] Add script URL to properties tool --- examples/html/entityProperties.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 0308d7f5e7..17eb0ad88f 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -103,6 +103,7 @@ var elIgnoreForCollisions = document.getElementById("property-ignore-for-collisions"); var elCollisionsWillMove = document.getElementById("property-collisions-will-move"); var elLifetime = document.getElementById("property-lifetime"); + var elScriptURL = document.getElementById("property-script-url"); var elBoxSections = document.querySelectorAll(".box-section"); var elBoxColorRed = document.getElementById("property-box-red"); @@ -198,6 +199,7 @@ elIgnoreForCollisions.checked = properties.ignoreForCollisions; elCollisionsWillMove.checked = properties.collisionsWillMove; elLifetime.value = properties.lifetime; + elScriptURL.value = properties.script; if (properties.type != "Box") { for (var i = 0; i < elBoxSections.length; i++) { @@ -324,6 +326,7 @@ elIgnoreForCollisions.addEventListener('change', createEmitCheckedPropertyUpdateFunction('ignoreForCollisions')); elCollisionsWillMove.addEventListener('change', createEmitCheckedPropertyUpdateFunction('collisionsWillMove')); elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime')); + elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script')); var boxColorChangeFunction = createEmitColorPropertyUpdateFunction( 'color', elBoxColorRed, elBoxColorGreen, elBoxColorBlue); @@ -550,6 +553,11 @@ + Script URL + + + + From ccdb13c951129351336296f578d7c7d3f2b937d7 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 6 Dec 2014 00:33:33 +0100 Subject: [PATCH 049/100] virtualkeyboard: moved files to hifi public bucket --- examples/virtualKeyboard.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index 2340bcab6e..e48da8a4d1 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -15,14 +15,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("libraries/globals.js"); + const KBD_UPPERCASE_DEFAULT = 0; const KBD_LOWERCASE_DEFAULT = 1; const KBD_UPPERCASE_HOVER = 2; const KBD_LOWERCASE_HOVER = 3; const KBD_BACKGROUND = 4; -const KEYBOARD_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/keyboard.svg"; -const CURSOR_URL = "http://test.thoys.nl/hifi/images/virtualKeyboard/cursor.svg"; +const KEYBOARD_URL = HIFI_PUBLIC_BUCKET + "images/keyboard.svg"; +const CURSOR_URL = HIFI_PUBLIC_BUCKET + "images/cursor.svg"; const SPACEBAR_CHARCODE = 32; From ae647d39d0f62c94de93ec1bb85d01cfd0fb0292 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 16:14:18 -0800 Subject: [PATCH 050/100] fix models with registrations other than 0,0,0 --- interface/src/renderer/Model.cpp | 24 ++++++++++++++++---- libraries/entities/src/EntityTreeElement.cpp | 4 ++++ libraries/octree/src/OctreeElement.cpp | 4 ++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 6b398284a3..a259e42117 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -543,10 +543,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g qDebug() << " modelExtents:" << modelExtents; glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; - glm::vec3 corner = dimensions * _registrationPoint; // since we're going to do the ray picking in the model frame of reference - AABox overlayFrameBox(corner, dimensions); + glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference + AABox modelFrameBox(corner, dimensions); - qDebug() << " overlayFrameBox:" << overlayFrameBox; + qDebug() << " modelFrameBox:" << modelFrameBox; glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); @@ -555,7 +555,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g // we can use the AABox's ray intersection by mapping our origin and direction into the model frame // and testing intersection there. - if (overlayFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { + if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { + + qDebug() << " modelFrameBox.findRayIntersection() HITS!!!"; float bestDistance = std::numeric_limits::max(); float bestTriangleDistance = std::numeric_limits::max(); @@ -566,14 +568,21 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g int subMeshIndex = 0; const FBXGeometry& geometry = _geometry->getFBXGeometry(); + + qDebug() << " Checking mesh boxes...."; // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { - qDebug() << "subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; + qDebug() << " subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { + qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() HITS!"; + qDebug() << " subMeshBox[" << subMeshIndex <<"].distanceToSubMesh:" << distanceToSubMesh; + qDebug() << " bestDistance:" << bestDistance; if (distanceToSubMesh < bestDistance) { + qDebug() << " distanceToSubMesh < bestDistance !! looks like a good match!"; + if (pickAgainstTriangles) { if (!_calculatedMeshTrianglesValid) { recalcuateMeshBoxes(); @@ -599,6 +608,8 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g intersectedSomething = true; face = subMeshFace; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + } else { + qDebug() << " distanceToSubMesh >= bestDistance !! TOO FAR AWAY!"; } } subMeshIndex++; @@ -607,6 +618,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g // if we were asked to pick against triangles, and we didn't hit one, then we // do not consider this model to be hit at all. if (pickAgainstTriangles && !someTriangleHit) { + qDebug() << "pickAgainstTriangles && !someTriangleHit --- call it a NON-HIT!"; intersectedSomething = false; } qDebug() << "pickAgainstTriangles:" << pickAgainstTriangles; @@ -626,6 +638,8 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g } return intersectedSomething; + } else { + qDebug() << "modelFrameBox.findRayIntersection()... DID NOT INTERSECT..."; } return intersectedSomething; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index c452dab5cb..aea278adf6 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -553,6 +553,8 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; + } else { + qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } else { @@ -566,6 +568,8 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; + } else { + qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 330624f4b9..9f6e0530a8 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1391,6 +1391,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 qDebug() << " distance:" << distance << " -- THIS ONE IS GOOD -------"; return true; + } else { + qDebug() << " distanceToElementDetails:" << distanceToElementDetails; + qDebug() << " distance:" << distance; + qDebug() << " distanceToElementDetails >= distance -- THIS ONE IS NOT SELECTED even though it INTERSECTED -------"; } } } From ee124f580df3beca04d0b2b44e03009bb0a43a48 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 5 Dec 2014 17:02:49 -0800 Subject: [PATCH 051/100] removed _mouse{X,Y} --- interface/src/Application.cpp | 17 +---------------- interface/src/Application.h | 6 ++---- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0ecb99fbcc..41e925fd9d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -165,8 +165,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _scaleMirror(1.0f), _rotateMirror(0.0f), _raiseMirror(0.0f), - _mouseX(0), - _mouseY(0), _lastMouseMove(usecTimestampNow()), _lastMouseMoveWasSimulated(false), _mouseHidden(false), @@ -1282,9 +1280,6 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { _mouseHidden = false; _seenMouseMove = true; } - - _mouseX = event->x(); - _mouseY = event->y(); } void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { @@ -1302,8 +1297,6 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { if (event->button() == Qt::LeftButton) { - _mouseX = event->x(); - _mouseY = event->y(); _mouseDragStartedX = getTrueMouseX(); _mouseDragStartedY = getTrueMouseY(); _mousePressed = true; @@ -1346,8 +1339,6 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { if (event->button() == Qt::LeftButton) { - _mouseX = event->x(); - _mouseY = event->y(); _mousePressed = false; if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) { @@ -1940,9 +1931,6 @@ void Application::init() { _voxelShader.init(); _pointShader.init(); - _mouseX = _glWidget->width() / 2; - _mouseY = _glWidget->height() / 2; - // TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager _avatarManager.init(); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); @@ -3557,9 +3545,6 @@ void Application::deleteVoxelAt(const VoxelDetail& voxel) { } void Application::resetSensors() { - _mouseX = _glWidget->width() / 2; - _mouseY = _glWidget->height() / 2; - _faceshift.reset(); _visage.reset(); _dde.reset(); @@ -3572,7 +3557,7 @@ void Application::resetSensors() { QScreen* currentScreen = _window->windowHandle()->screen(); QWindow* mainWindow = _window->windowHandle(); QPoint windowCenter = mainWindow->geometry().center(); - QCursor::setPos(currentScreen, windowCenter); + _glWidget->cursor().setPos(currentScreen, windowCenter); _myAvatar->reset(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 8fb0cb090d..58dec1da1f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -217,8 +217,8 @@ public: bool mouseOnScreen() const; int getMouseX() const; int getMouseY() const; - int getTrueMouseX() const { return _mouseX; } - int getTrueMouseY() const { return _mouseY; } + int getTrueMouseX() const { return _glWidget->mapFromGlobal(QCursor::pos()).x(); } + int getTrueMouseY() const { return _glWidget->mapFromGlobal(QCursor::pos()).y(); } int getMouseDragStartedX() const; int getMouseDragStartedY() const; int getTrueMouseDragStartedX() const { return _mouseDragStartedX; } @@ -563,8 +563,6 @@ private: Environment _environment; - int _mouseX; - int _mouseY; int _mouseDragStartedX; int _mouseDragStartedY; quint64 _lastMouseMove; From 1bb08ef30f0cfb4aa0a56e9b394cf69ceef2c7af Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 5 Dec 2014 17:10:58 -0800 Subject: [PATCH 052/100] Centered reticule --- interface/src/ui/ApplicationOverlay.cpp | 30 ++++++++++++++++++++----- interface/src/ui/ApplicationOverlay.h | 3 ++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index c029a2e00f..f4e9e627ad 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -127,6 +127,7 @@ void renderReticule(glm::quat orientation, float alpha) { ApplicationOverlay::ApplicationOverlay() : _textureFov(glm::radians(DEFAULT_OCULUS_UI_ANGULAR_SIZE)), _textureAspectRatio(1.0f), + _lastMouseMove(0), _alpha(1.0f), _oculusUIRadius(1.0f), _crosshairTexture(0) { @@ -284,7 +285,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_magSizeMult[i] > 0.0f) { //Render magnifier, but dont show border for mouse magnifier - glm::vec2 projection = screenToOverlay(_reticulePosition[i]); + glm::vec2 projection = screenToOverlay(glm::vec2(_reticulePosition[MOUSE].x(), + _reticulePosition[MOUSE].y())); renderMagnifier(projection, _magSizeMult[i], i != MOUSE); } @@ -520,13 +522,30 @@ void ApplicationOverlay::renderPointers() { if (OculusManager::isConnected() && !application->getLastMouseMoveWasSimulated()) { //If we are in oculus, render reticle later + if (_lastMouseMove == 0) { + _lastMouseMove = usecTimestampNow(); + } + QPoint position = QPoint(application->getTrueMouseX(), application->getTrueMouseY()); + + static const int MAX_IDLE_TIME = 3; + if (_reticulePosition[MOUSE] != position) { + _lastMouseMove = usecTimestampNow(); + } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) { + float pitch, yaw, roll; + OculusManager::getEulerAngles(yaw, pitch, roll); + glm::vec2 screenPos = sphericalToScreen(glm::vec2(yaw, -pitch)); + + position = QPoint(screenPos.x, screenPos.y); + QCursor::setPos(application->getGLWidget()->mapToGlobal(position)); + } + + _reticulePosition[MOUSE] = position; _reticleActive[MOUSE] = true; _magActive[MOUSE] = true; - _reticulePosition[MOUSE] = glm::vec2(application->getMouseX(), application->getMouseY()); _reticleActive[LEFT_CONTROLLER] = false; _reticleActive[RIGHT_CONTROLLER] = false; - } else if (application->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + _lastMouseMove = 0; //only render controller pointer if we aren't already rendering a mouse pointer _reticleActive[MOUSE] = false; _magActive[MOUSE] = false; @@ -591,7 +610,7 @@ void ApplicationOverlay::renderControllerPointers() { QPoint point = getPalmClickLocation(palmData); - _reticulePosition[index] = glm::vec2(point.x(), point.y()); + _reticulePosition[index] = point; //When button 2 is pressed we drag the mag window if (isPressed[index]) { @@ -672,7 +691,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { //Mouse Pointer if (_reticleActive[MOUSE]) { - glm::vec2 projection = screenToSpherical(_reticulePosition[MOUSE]); + glm::vec2 projection = screenToSpherical(glm::vec2(_reticulePosition[MOUSE].x(), + _reticulePosition[MOUSE].y())); glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); renderReticule(orientation, _alpha); } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 2ca430aae6..538a163d0e 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -96,9 +96,10 @@ private: enum Reticules { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICULES }; bool _reticleActive[NUMBER_OF_RETICULES]; - glm::vec2 _reticulePosition[NUMBER_OF_RETICULES]; + QPoint _reticulePosition[NUMBER_OF_RETICULES]; bool _magActive[NUMBER_OF_RETICULES]; float _magSizeMult[NUMBER_OF_RETICULES]; + quint64 _lastMouseMove; float _alpha; float _oculusUIRadius; From d89d10d26362d4b01d81ada9af392d354a03d554 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 5 Dec 2014 17:36:46 -0800 Subject: [PATCH 053/100] Hide cusor in VR mode --- interface/src/Application.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 41e925fd9d..2d92a99cab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2342,7 +2342,20 @@ void Application::update(float deltaTime) { _prioVR.update(deltaTime); } - + + static QCursor cursor; + if (OculusManager::isConnected() && + Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)){ + if (_window->cursor().shape() != Qt::BlankCursor) { + qDebug() << "Hiding cursor" << _window->cursor().shape(); + cursor = _window->cursor(); + _window->setCursor(QCursor(Qt::BlankCursor)); + } + } else if(_window->cursor().shape() == Qt::BlankCursor) { + qDebug() << "Showing cursor" << _window->cursor().shape(); + _window->setCursor(cursor); + } + // Dispatch input events _controllerScriptingInterface.updateInputControllers(); From 7d96ad5836bd6dcdc3feff80c22426ce5912c636 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 5 Dec 2014 18:08:53 -0800 Subject: [PATCH 054/100] cleanup of EntitySimulation API * remove EntityItem::_simulationState (only useful to EntitySimulation) * move code from SimpleEntitySimuation to EntitySimulation * EntitySimulation now maintans many QSets of entities * cleanup and clarify use of EnityTree::updateEntity() * reduced cost of polling for entity expiries * changed "UpdateFlags" to "DirtyFlags" and clarified what they're for --- .../entities/RenderableModelEntityItem.cpp | 6 +- .../src/entities/RenderableModelEntityItem.h | 4 +- .../entities/src/EntityCollisionSystem.cpp | 10 +- libraries/entities/src/EntityItem.cpp | 74 +++--- libraries/entities/src/EntityItem.h | 60 +++-- libraries/entities/src/EntitySimulation.cpp | 168 +++++++++++- libraries/entities/src/EntitySimulation.h | 39 ++- libraries/entities/src/EntityTree.cpp | 48 ++-- libraries/entities/src/EntityTree.h | 8 + libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/entities/src/ModelEntityItem.cpp | 13 +- libraries/entities/src/ModelEntityItem.h | 2 +- .../entities/src/MovingEntitiesOperator.cpp | 9 +- .../entities/src/MovingEntitiesOperator.h | 3 +- .../entities/src/SimpleEntitySimulation.cpp | 239 ++++-------------- .../entities/src/SimpleEntitySimulation.h | 28 +- 16 files changed, 384 insertions(+), 329 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 10b18ad9c5..6c8d85507d 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -150,7 +150,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } glm::quat rotation = getRotation(); - if (needsSimulation() && _model->isActive()) { + if (needsToCallUpdate() && _model->isActive()) { _model->setScaleToFit(true, dimensions); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(rotation); @@ -245,8 +245,8 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { return result; } -bool RenderableModelEntityItem::needsSimulation() const { - return _needsInitialSimulation || getSimulationState() == EntityItem::Moving; +bool RenderableModelEntityItem::needsToCallUpdate() const { + return _needsInitialSimulation || ModelEntityItem::needsToCallUpdate(); } EntityItemProperties RenderableModelEntityItem::getProperties() const { diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 48c9a26051..0aa2578a6c 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -52,9 +52,11 @@ public: virtual void render(RenderArgs* args); Model* getModel(EntityTreeRenderer* renderer); + + bool needsToCallUpdate() const; + private: void remapTextures(); - bool needsSimulation() const; Model* _model; bool _needsInitialSimulation; diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 2ac8ea596d..b74b9fac80 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -208,7 +208,9 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { propertiesA.setPosition(newPositionA * (float)TREE_SCALE); propertiesA.setLastEdited(now); - _entityTree->updateEntity(idA, propertiesA); + // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, + // thereby waking up static non-moving entities. + _entityTree->updateEntity(entityA, propertiesA); _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idA, propertiesA); } @@ -225,7 +227,9 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { propertiesB.setPosition(newPositionB * (float)TREE_SCALE); propertiesB.setLastEdited(now); - _entityTree->updateEntity(idB, propertiesB); + // NOTE: EntityTree::updateEntity() will cause the entity to get sorted correctly in the EntitySimulation, + // thereby waking up static non-moving entities. + _entityTree->updateEntity(entityB, propertiesB); _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, idB, propertiesB); } } @@ -331,6 +335,6 @@ void EntityCollisionSystem::applyHardCollision(EntityItem* entity, const Collisi properties.setVelocity(velocity * (float)TREE_SCALE); properties.setLastEdited(usecTimestampNow()); - _entityTree->updateEntity(entityItemID, properties); + _entityTree->updateEntity(entity, properties); _packetSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, entityItemID, properties); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 98dda6f33f..d0d07d1227 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -58,6 +58,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; + _lastSimulated = 0; _lastUpdated = 0; _created = 0; // TODO: when do we actually want to make this "now" _changedOnServer = 0; @@ -88,12 +89,12 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) { _lastEdited = 0; _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; + _lastSimulated = 0; _lastUpdated = 0; _created = 0; - _updateFlags = 0; + _dirtyFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); - _simulationState = EntityItem::Static; } EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { @@ -101,13 +102,13 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert _lastEdited = 0; _lastEditedFromRemote = 0; _lastEditedFromRemoteInRemoteTime = 0; + _lastSimulated = 0; _lastUpdated = 0; _created = properties.getCreated(); - _updateFlags = 0; + _dirtyFlags = 0; _changedOnServer = 0; initFromEntityItemID(entityItemID); setProperties(properties, true); // force copy - _simulationState = EntityItem::Static; } EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { @@ -154,7 +155,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet ByteCountCoded typeCoder = getType(); QByteArray encodedType = typeCoder; - quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited(); + quint64 updateDelta = getLastMoved() <= getLastEdited() ? 0 : getLastMoved() - getLastEdited(); ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); @@ -450,9 +451,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef ByteCountCoded updateDeltaCoder = encodedUpdateDelta; quint64 updateDelta = updateDeltaCoder; if (overwriteLocalData) { - _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited + _lastSimulated = _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that for _lastEdited if (wantDebug) { - qDebug() << "_lastUpdated=" << _lastUpdated; + qDebug() << "_lastUpdated =" << _lastUpdated; qDebug() << "_lastEdited=" << _lastEdited; qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted; } @@ -565,20 +566,20 @@ bool EntityItem::isRestingOnSurface() const { && _gravity.y < 0.0f; } -void EntityItem::update(const quint64& updateTime) { +void EntityItem::simulate(const quint64& now) { bool wantDebug = false; - if (_lastUpdated == 0) { - _lastUpdated = updateTime; + if (_lastSimulated == 0) { + _lastSimulated = now; } - float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); + float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); if (wantDebug) { qDebug() << "********** EntityItem::update()"; qDebug() << " entity ID=" << getEntityItemID(); - qDebug() << " updateTime=" << updateTime; - qDebug() << " _lastUpdated=" << _lastUpdated; + qDebug() << " now=" << now; + qDebug() << " _lastSimulated=" << _lastSimulated; qDebug() << " timeElapsed=" << timeElapsed; qDebug() << " hasVelocity=" << hasVelocity(); qDebug() << " hasGravity=" << hasGravity(); @@ -611,10 +612,10 @@ void EntityItem::update(const quint64& updateTime) { } } - _lastUpdated = updateTime; + _lastSimulated = now; if (wantDebug) { - qDebug() << " ********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; + qDebug() << " ********** EntityItem::update() .... SETTING _lastSimulated=" << _lastSimulated; } if (hasAngularVelocity()) { @@ -707,6 +708,7 @@ void EntityItem::update(const quint64& updateTime) { velocity = NO_VELOCITY; } + // NOTE: the simulation should NOT set any DirtyFlags on this entity setPosition(position); // this will automatically recalculate our collision shape setVelocity(velocity); @@ -719,20 +721,18 @@ void EntityItem::update(const quint64& updateTime) { } } -EntityItem::SimulationState EntityItem::computeSimulationState() const { - if (hasVelocity() || (hasGravity() && !isRestingOnSurface()) || hasAngularVelocity()) { - return EntityItem::Moving; - } - if (isMortal()) { - return EntityItem::Mortal; - } - return EntityItem::Static; +bool EntityItem::isMoving() const { + return hasVelocity() || (hasGravity() && !isRestingOnSurface()) || hasAngularVelocity(); } bool EntityItem::lifetimeHasExpired() const { return isMortal() && (getAge() > getLifetime()); } +quint64 EntityItem::getExpiry() const { + return _created + (quint64)(_lifetime * (float)USECS_PER_SECOND); +} + EntityItemProperties EntityItem::getProperties() const { EntityItemProperties properties; properties._id = getID(); @@ -948,7 +948,7 @@ void EntityItem::updatePosition(const glm::vec3& value) { if (_position != value) { _position = value; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_POSITION; + _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -957,7 +957,7 @@ void EntityItem::updatePositionInMeters(const glm::vec3& value) { if (_position != position) { _position = position; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_POSITION; + _dirtyFlags |= EntityItem::DIRTY_POSITION; } } @@ -965,7 +965,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { if (_dimensions != value) { _dimensions = value; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _dirtyFlags |= EntityItem::DIRTY_SHAPE; } } @@ -974,7 +974,7 @@ void EntityItem::updateDimensionsInMeters(const glm::vec3& value) { if (_dimensions != dimensions) { _dimensions = dimensions; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_SHAPE; + _dirtyFlags |= EntityItem::DIRTY_SHAPE; } } @@ -982,21 +982,21 @@ void EntityItem::updateRotation(const glm::quat& rotation) { if (_rotation != rotation) { _rotation = rotation; recalculateCollisionShape(); - _updateFlags |= EntityItem::UPDATE_POSITION; + _dirtyFlags |= EntityItem::DIRTY_POSITION; } } void EntityItem::updateMass(float value) { if (_mass != value) { _mass = value; - _updateFlags |= EntityItem::UPDATE_MASS; + _dirtyFlags |= EntityItem::DIRTY_MASS; } } void EntityItem::updateVelocity(const glm::vec3& value) { if (_velocity != value) { _velocity = value; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } @@ -1004,14 +1004,14 @@ void EntityItem::updateVelocityInMeters(const glm::vec3& value) { glm::vec3 velocity = value / (float) TREE_SCALE; if (_velocity != velocity) { _velocity = velocity; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateGravity(const glm::vec3& value) { if (_gravity != value) { _gravity = value; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } @@ -1019,35 +1019,35 @@ void EntityItem::updateGravityInMeters(const glm::vec3& value) { glm::vec3 gravity = value / (float) TREE_SCALE; if (_gravity != gravity) { _gravity = gravity; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateAngularVelocity(const glm::vec3& value) { if (_angularVelocity != value) { _angularVelocity = value; - _updateFlags |= EntityItem::UPDATE_VELOCITY; + _dirtyFlags |= EntityItem::DIRTY_VELOCITY; } } void EntityItem::updateIgnoreForCollisions(bool value) { if (_ignoreForCollisions != value) { _ignoreForCollisions = value; - _updateFlags |= EntityItem::UPDATE_COLLISION_GROUP; + _dirtyFlags |= EntityItem::DIRTY_COLLISION_GROUP; } } void EntityItem::updateCollisionsWillMove(bool value) { if (_collisionsWillMove != value) { _collisionsWillMove = value; - _updateFlags |= EntityItem::UPDATE_MOTION_TYPE; + _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } void EntityItem::updateLifetime(float value) { if (_lifetime != value) { _lifetime = value; - _updateFlags |= EntityItem::UPDATE_LIFETIME; + _dirtyFlags |= EntityItem::DIRTY_LIFETIME; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7dbcaed8fc..f0d3330087 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -41,15 +41,14 @@ class EntityTreeElementExtraEncodeData; class EntityItem { public: - enum EntityUpdateFlags { - UPDATE_POSITION = 0x0001, - UPDATE_VELOCITY = 0x0002, - UPDATE_MASS = 0x0004, - UPDATE_COLLISION_GROUP = 0x0008, - UPDATE_MOTION_TYPE = 0x0010, - UPDATE_SHAPE = 0x0020, - UPDATE_LIFETIME = 0x0040 - //UPDATE_APPEARANCE = 0x8000, + enum EntityDirtyFlags { + DIRTY_POSITION = 0x0001, + DIRTY_VELOCITY = 0x0002, + DIRTY_MASS = 0x0004, + DIRTY_COLLISION_GROUP = 0x0008, + DIRTY_MOTION_TYPE = 0x0010, + DIRTY_SHAPE = 0x0020, + DIRTY_LIFETIME = 0x0040 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -77,12 +76,12 @@ public: /// has changed. This will be called with properties change or when new data is loaded from a stream virtual void somethingChangedNotification() { } - quint64 getLastUpdated() const { return _lastUpdated; } /// Last simulated time of this entity universal usecs + quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + { _lastEdited = _lastSimulated = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } @@ -121,17 +120,14 @@ public: unsigned char* bufferOut, int sizeIn, int& sizeOut); static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); - virtual void update(const quint64& now); + + // perform update + virtual void update(const quint64& now) { _lastUpdated = now; } - typedef enum SimulationState_t { - Static, - Mortal, - Moving - } SimulationState; + // perform linear extrapolation for SimpleEntitySimulation + void simulate(const quint64& now); - // computes the SimulationState that the entity SHOULD be in. - // Use getSimulationState() to find the state under which it is currently categorized. - virtual SimulationState computeSimulationState() const; + bool needsToCallUpdate() const { return false; } virtual void debugDump() const; @@ -221,11 +217,14 @@ public: /// age of this entity in seconds float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } bool lifetimeHasExpired() const; + quint64 getExpiry() const; // position, size, and bounds related helpers float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0) AACube getMaximumAACube() const; AACube getMinimumAACube() const; + AACube getOldMaximumAACube() const { return _oldMaximumAACube; } + void setOldMaximumAACube(const AACube& cube) { _oldMaximumAACube = cube; } AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) static const QString DEFAULT_SCRIPT; @@ -278,7 +277,7 @@ public: virtual const Shape& getCollisionShapeInMeters() const { return _collisionShape; } virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); } - // updateFoo() methods to be used when changes need to be accumulated in the _updateFlags + // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); void updatePositionInMeters(const glm::vec3& value); void updateDimensions(const glm::vec3& value); @@ -294,12 +293,11 @@ public: void updateCollisionsWillMove(bool value); void updateLifetime(float value); - uint32_t getUpdateFlags() const { return _updateFlags; } - void clearUpdateFlags() { _updateFlags = 0; } - - SimulationState getSimulationState() const { return _simulationState; } + uint32_t getDirtyFlags() const { return _dirtyFlags; } + void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } - void setSimulationState(SimulationState state) { _simulationState = state; } + bool isMoving() const; + protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -309,7 +307,8 @@ protected: QUuid _id; uint32_t _creatorTokenID; bool _newlyCreated; - quint64 _lastUpdated; + quint64 _lastSimulated; // last time this entity called simulate() + quint64 _lastUpdated; // last time this entity called update() quint64 _lastEdited; // this is the last official local or remote edit time quint64 _lastEditedFromRemote; // this is the last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime; // time in server time space the last time we received and edit from the server @@ -343,11 +342,10 @@ protected: void setRadius(float value); AACubeShape _collisionShape; - SimulationState _simulationState; // only set by EntityTree + AACube _oldMaximumAACube; // remember this so we know where the entity used to live in the tree - // UpdateFlags are set whenever a property changes that requires the change to be communicated to other - // data structures. It is the responsibility of the EntityTree to relay changes entity and clear flags. - uint32_t _updateFlags; + // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. + uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation }; diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 8058c2f24e..223df588d5 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -9,12 +9,178 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "EntitySimulation.h" +#include "MovingEntitiesOperator.h" void EntitySimulation::setEntityTree(EntityTree* tree) { if (_entityTree && _entityTree != tree) { - clearEntities(); + _mortalEntities.clear(); + _nextExpiry = quint64(-1); + _updateableEntities.clear(); + _entitiesToBeSorted.clear(); } _entityTree = tree; } +void EntitySimulation::updateEntities(QSet& entitiesToDelete) { + quint64 now = usecTimestampNow(); + + // these methods may accumulate entries in _entitiesToBeDeleted + expireMortalEntities(now); + callUpdateOnEntitiesThatNeedIt(now); + updateEntitiesInternal(now); + sortEntitiesThatMoved(); + + // at this point we harvest _entitiesToBeDeleted + entitiesToDelete.unite(_entitiesToDelete); + _entitiesToDelete.clear(); +} + +void EntitySimulation::expireMortalEntities(const quint64& now) { + if (now > _nextExpiry) { + // only search for expired entities if we expect to find one + _nextExpiry = quint64(-1); + QSet::iterator itemItr = _mortalEntities.begin(); + while (itemItr != _mortalEntities.end()) { + EntityItem* entity = *itemItr; + quint64 expiry = entity->getExpiry(); + if (expiry < now) { + _entitiesToDelete.insert(entity); + itemItr = _mortalEntities.erase(itemItr); + _updateableEntities.remove(entity); + _entitiesToBeSorted.remove(entity); + removeEntityInternal(entity); + } else { + if (expiry < _nextExpiry) { + // remeber the smallest _nextExpiry so we know when to start the next search + _nextExpiry = expiry; + } + ++itemItr; + } + } + } +} + +void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) { + PerformanceTimer perfTimer("updatingEntities"); + QSet::iterator itemItr = _updateableEntities.begin(); + while (itemItr != _updateableEntities.end()) { + EntityItem* entity = *itemItr; + // TODO: catch transition from needing update to not as a "change" + // so we don't have to scan for it here. + if (!entity->needsToCallUpdate()) { + itemItr = _updateableEntities.erase(itemItr); + } else { + entity->update(now); + ++itemItr; + } + } +} + +void EntitySimulation::sortEntitiesThatMoved() { + // NOTE: this is only for entities that have been moved by THIS EntitySimulation. + // External changes to entity position/shape are expected to be sorted outside of the EntitySimulation. + PerformanceTimer perfTimer("sortingEntities"); + MovingEntitiesOperator moveOperator(_entityTree); + AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); + QSet::iterator itemItr = _entitiesToBeSorted.begin(); + while (itemItr != _entitiesToBeSorted.end()) { + EntityItem* entity = *itemItr; + // check to see if this movement has sent the entity outside of the domain. + AACube newCube = entity->getMaximumAACube(); + if (!domainBounds.touches(newCube)) { + qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + _entitiesToDelete.insert(entity); + _mortalEntities.remove(entity); + _updateableEntities.remove(entity); + removeEntityInternal(entity); + } else { + moveOperator.addEntityToMoveList(entity, newCube); + } + ++itemItr; + } + _entitiesToBeSorted.clear(); + + if (moveOperator.hasMovingEntities()) { + PerformanceTimer perfTimer("recurseTreeWithOperator"); + _entityTree->recurseTreeWithOperator(&moveOperator); + moveOperator.finish(); + } +} + +void EntitySimulation::addEntity(EntityItem* entity) { + assert(entity); + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; + } + } + if (entity->needsToCallUpdate()) { + _updateableEntities.insert(entity); + } + addEntityInternal(entity); +} + +void EntitySimulation::removeEntity(EntityItem* entity) { + assert(entity); + _updateableEntities.remove(entity); + _mortalEntities.remove(entity); + _entitiesToBeSorted.remove(entity); + _entitiesToDelete.remove(entity); + removeEntityInternal(entity); +} + +void EntitySimulation::entityChanged(EntityItem* entity) { + assert(entity); + + // Although it is not the responsibility of the EntitySimulation to sort the tree for EXTERNAL changes + // it IS responsibile for triggering deletes for entities that leave the bounds of the domain, hence + // we must check for that case here, however we rely on the change event to have set DIRTY_POSITION flag. + bool wasRemoved = false; + uint32_t dirtyFlags = entity->getDirtyFlags(); + if (dirtyFlags & EntityItem::DIRTY_POSITION) { + AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); + AACube newCube = entity->getMaximumAACube(); + if (!domainBounds.touches(newCube)) { + qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; + _entitiesToDelete.insert(entity); + _mortalEntities.remove(entity); + _updateableEntities.remove(entity); + removeEntityInternal(entity); + wasRemoved = true; + } + } + if (!wasRemoved) { + if (dirtyFlags & EntityItem::DIRTY_LIFETIME) { + if (entity->isMortal()) { + _mortalEntities.insert(entity); + quint64 expiry = entity->getExpiry(); + if (expiry < _nextExpiry) { + _nextExpiry = expiry; + } + } else { + _mortalEntities.remove(entity); + } + entity->clearDirtyFlags(EntityItem::DIRTY_LIFETIME); + } + if (entity->needsToCallUpdate()) { + _updateableEntities.insert(entity); + } else { + _updateableEntities.remove(entity); + } + entityChangedInternal(entity); + } + entity->clearDirtyFlags(); +} + +void EntitySimulation::clearEntities() { + _mortalEntities.clear(); + _nextExpiry = quint64(-1); + _updateableEntities.clear(); + _entitiesToBeSorted.clear(); + clearEntitiesInternal(); +} diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 770d6ebdb0..506e2ed9d0 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -14,36 +14,61 @@ #include +#include + #include "EntityTree.h" class EntitySimulation { public: EntitySimulation() : _entityTree(NULL) { } - virtual ~EntitySimulation() {} + virtual ~EntitySimulation() { setEntityTree(NULL); } /// \param tree pointer to EntityTree which is stored internally - virtual void setEntityTree(EntityTree* tree); + void setEntityTree(EntityTree* tree); /// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted. - virtual void update(QSet& entitiesToDelete) = 0; + void updateEntities(QSet& entitiesToDelete); /// \param entity pointer to EntityItem to add to the simulation /// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list - virtual void addEntity(EntityItem* entity) = 0; + void addEntity(EntityItem* entity); /// \param entity pointer to EntityItem to removed from the simulation /// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list - virtual void removeEntity(EntityItem* entity) = 0; + void removeEntity(EntityItem* entity); /// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation - virtual void entityChanged(EntityItem* entity) = 0; + /// call this whenever an entity was changed from some EXTERNAL event (NOT by the EntitySimulation itself) + void entityChanged(EntityItem* entity); - virtual void clearEntities() = 0; + void clearEntities(); EntityTree* getEntityTree() { return _entityTree; } protected: + + // These pure virtual methods are protected because they are not to be called will-nilly. The base class + // calls them in the right places. + virtual void updateEntitiesInternal(const quint64& now) = 0; + virtual void addEntityInternal(EntityItem* entity) = 0; + virtual void removeEntityInternal(EntityItem* entity) = 0; + virtual void entityChangedInternal(EntityItem* entity) = 0; + virtual void clearEntitiesInternal() = 0; + + void expireMortalEntities(const quint64& now); + void callUpdateOnEntitiesThatNeedIt(const quint64& now); + void sortEntitiesThatMoved(); + + // back pointer to EntityTree structure EntityTree* _entityTree; + + // We maintain multiple lists, each for its distinct purpose. + // An entity may be in more than one list. + QSet _mortalEntities; // entities that have an expiry + quint64 _nextExpiry; + QSet _updateableEntities; // entities that need update() called + QSet _entitiesToBeSorted; // entities that were moved by THIS simulation and might need to be resorted in the tree + QSet _entitiesToDelete; }; #endif // hifi_EntitySimulation_h diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index d3d9e2da53..8c18f965aa 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -79,6 +79,7 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons /// Adds a new entity item to the tree void EntityTree::postAddEntity(EntityItem* entity) { assert(entity); + entity->setOldMaximumAACube(entity->getMaximumAACube()); // check to see if we need to simulate this entity.. if (_simulation) { _simulation->addEntity(entity); @@ -99,51 +100,64 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp qDebug() << "UNEXPECTED!!!! don't call updateEntity() on entity items that don't exist. entityID=" << entityID; return false; } - + + return updateEntityWithElement(existingEntity, properties, containingElement); +} + +bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& properties) { + EntityTreeElement* containingElement = getContainingElement(entity->getEntityItemID()); + if (!containingElement) { + qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entity-->element lookup failed!!! entityID=" + << entity->getEntityItemID(); + return false; + } + return updateEntityWithElement(entity, properties, containingElement); +} + +bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties, + EntityTreeElement* containingElement) { // enforce support for locked entities. If an entity is currently locked, then the only // property we allow you to change is the locked property. - if (existingEntity->getLocked()) { + if (entity->getLocked()) { if (properties.lockedChanged()) { bool wantsLocked = properties.getLocked(); if (!wantsLocked) { EntityItemProperties tempProperties; tempProperties.setLocked(wantsLocked); - UpdateEntityOperator theOperator(this, containingElement, existingEntity, tempProperties); + UpdateEntityOperator theOperator(this, containingElement, entity, tempProperties); recurseTreeWithOperator(&theOperator); _isDirty = true; - if (_simulation && existingEntity->getUpdateFlags() != 0) { - _simulation->entityChanged(existingEntity); - } } } } else { - // check to see if we need to simulate this entity... - QString entityScriptBefore = existingEntity->getScript(); + QString entityScriptBefore = entity->getScript(); - UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); + UpdateEntityOperator theOperator(this, containingElement, entity, properties); recurseTreeWithOperator(&theOperator); + entity->setOldMaximumAACube(entity->getMaximumAACube()); _isDirty = true; - if (_simulation && existingEntity->getUpdateFlags() != 0) { - _simulation->entityChanged(existingEntity); + if (_simulation && entity->getDirtyFlags() != 0) { + _simulation->entityChanged(entity); } - QString entityScriptAfter = existingEntity->getScript(); + QString entityScriptAfter = entity->getScript(); if (entityScriptBefore != entityScriptAfter) { - emitEntityScriptChanging(entityID); // the entity script has changed + emit entityScriptChanging(entity->getEntityItemID()); // the entity script has changed } } - containingElement = getContainingElement(entityID); + // TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG). + containingElement = getContainingElement(entity->getEntityItemID()); if (!containingElement) { - qDebug() << "UNEXPECTED!!!! after updateEntity() we no longer have a containing element??? entityID=" << entityID; + qDebug() << "UNEXPECTED!!!! after updateEntity() we no longer have a containing element??? entityID=" + << entity->getEntityItemID(); return false; } return true; } - EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItem* result = NULL; @@ -572,7 +586,7 @@ void EntityTree::update() { if (_simulation) { lockForWrite(); QSet entitiesToDelete; - _simulation->update(entitiesToDelete); + _simulation->updateEntities(entitiesToDelete); if (entitiesToDelete.size() > 0) { // translate into list of ID's QSet idsToDelete; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index eeb0182042..9a0fb43ecb 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -82,7 +82,13 @@ public: void postAddEntity(EntityItem* entityItem); EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties); + + // use this method if you only know the entityID bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties); + + // use this method if you have a pointer to the entity (avoid an extra entity lookup) + bool updateEntity(EntityItem* entity, const EntityItemProperties& properties); + void deleteEntity(const EntityItemID& entityID); void deleteEntities(QSet entityIDs); void removeEntityFromSimulation(EntityItem* entity); @@ -156,6 +162,8 @@ signals: private: + bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties, + EntityTreeElement* containingElement); static bool findNearPointOperation(OctreeElement* element, void* extraData); static bool findInSphereOperation(OctreeElement* element, void* extraData); static bool findInCubeOperation(OctreeElement* element, void* extraData); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e18f79276e..d3e303009c 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -757,7 +757,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); - if (entityItem->getUpdateFlags()) { + if (entityItem->getDirtyFlags()) { _myTree->entityChanged(entityItem); } bool bestFitAfter = bestFitEntityBounds(entityItem); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 0de2035dec..565974d19e 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -373,17 +373,11 @@ bool ModelEntityItem::isAnimatingSomething() const { !getAnimationURL().isEmpty(); } -EntityItem::SimulationState ModelEntityItem::computeSimulationState() const { - // if we're animating then we need to have update() periodically called on this entity - // which means we need to categorized as Moving - return isAnimatingSomething() ? EntityItem::Moving : EntityItem::computeSimulationState(); +bool ModelEntityItem::needsToCallUpdate() const { + return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate(); } -void ModelEntityItem::update(const quint64& updateTime) { - EntityItem::update(updateTime); // let our base class handle it's updates... - - quint64 now = updateTime; - +void ModelEntityItem::update(const quint64& now) { // only advance the frame index if we're playing if (getAnimationIsPlaying()) { float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND; @@ -392,6 +386,7 @@ void ModelEntityItem::update(const quint64& updateTime) { } else { _lastAnimated = now; } + EntityItem::update(now); // let our base class handle it's updates... } void ModelEntityItem::debugDump() const { diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 0b2508ec80..502b21af12 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -46,7 +46,7 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData); virtual void update(const quint64& now); - virtual SimulationState computeSimulationState() const; + virtual bool needsToCallUpdate() const; virtual void debugDump() const; diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index 045e07a910..86b8de7b10 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -49,9 +49,10 @@ MovingEntitiesOperator::~MovingEntitiesOperator() { } -void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) { +void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& newCube) { EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID()); AABox newCubeClamped = newCube.clamp(0.0f, 1.0f); + AACube oldCube = entity->getOldMaximumAACube(); AABox oldCubeClamped = oldCube.clamp(0.0f, 1.0f); if (_wantDebug) { @@ -290,3 +291,9 @@ OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* elem } return NULL; } + +void MovingEntitiesOperator::finish() { + foreach(const EntityToMoveDetails& details, _entitiesToMove) { + details.entity->setOldMaximumAACube(details.newCube); + } +} diff --git a/libraries/entities/src/MovingEntitiesOperator.h b/libraries/entities/src/MovingEntitiesOperator.h index fbec898cec..bddf5da450 100644 --- a/libraries/entities/src/MovingEntitiesOperator.h +++ b/libraries/entities/src/MovingEntitiesOperator.h @@ -38,11 +38,12 @@ public: MovingEntitiesOperator(EntityTree* tree); ~MovingEntitiesOperator(); - void addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube); + void addEntityToMoveList(EntityItem* entity, const AACube& newCube); virtual bool preRecursion(OctreeElement* element); virtual bool postRecursion(OctreeElement* element); virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex); bool hasMovingEntities() const { return _entitiesToMove.size() > 0; } + void finish(); private: EntityTree* _tree; QSet _entitiesToMove; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index b3316978a9..b962f6980e 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -9,216 +9,63 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include +//#include #include "EntityItem.h" -#include "MovingEntitiesOperator.h" #include "SimpleEntitySimulation.h" -void SimpleEntitySimulation::update(QSet& entitiesToDelete) { - quint64 now = usecTimestampNow(); - updateChangedEntities(now, entitiesToDelete); - updateMovingEntities(now, entitiesToDelete); - updateMortalEntities(now, entitiesToDelete); -} -void SimpleEntitySimulation::addEntity(EntityItem* entity) { - assert(entity && entity->getSimulationState() == EntityItem::Static); - EntityItem::SimulationState state = entity->computeSimulationState(); - switch(state) { - case EntityItem::Moving: - _movingEntities.push_back(entity); - entity->setSimulationState(state); - break; - case EntityItem::Mortal: - _mortalEntities.push_back(entity); - entity->setSimulationState(state); - break; - case EntityItem::Static: - default: - break; +void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { + QSet::iterator itemItr = _movingEntities.begin(); + while (itemItr != _movingEntities.end()) { + EntityItem* entity = *itemItr; + if (!entity->isMoving()) { + itemItr = _movingEntities.erase(itemItr); + _movableButStoppedEntities.insert(entity); + } else { + entity->simulate(now); + _entitiesToBeSorted.insert(entity); + } } } -void SimpleEntitySimulation::removeEntity(EntityItem* entity) { - assert(entity); - // make sure to remove it from any of our simulation lists - EntityItem::SimulationState state = entity->getSimulationState(); - switch (state) { - case EntityItem::Moving: - _movingEntities.removeAll(entity); - break; - case EntityItem::Mortal: - _mortalEntities.removeAll(entity); - break; - - default: - break; +void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { + if (entity->getCollisionsWillMove()) { + if (entity->isMoving()) { + _movingEntities.insert(entity); + } else { + _movableButStoppedEntities.insert(entity); + } } - entity->setSimulationState(EntityItem::Static); - _changedEntities.remove(entity); } -void SimpleEntitySimulation::entityChanged(EntityItem* entity) { - assert(entity); - // we batch all changes and deal with them in updateChangedEntities() - _changedEntities.insert(entity); +void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { + _movingEntities.remove(entity); + _movableButStoppedEntities.remove(entity); } -void SimpleEntitySimulation::clearEntities() { - foreach (EntityItem* entity, _changedEntities) { - entity->clearUpdateFlags(); - entity->setSimulationState(EntityItem::Static); +const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_MOTION_TYPE; + +void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { + int dirtyFlags = entity->getDirtyFlags(); + if (dirtyFlags & SIMPLE_SIMULATION_DIRTY_FLAGS) { + if (entity->getCollisionsWillMove()) { + if (entity->isMoving()) { + _movingEntities.insert(entity); + _movableButStoppedEntities.remove(entity); + } else { + _movingEntities.remove(entity); + _movableButStoppedEntities.insert(entity); + } + } else { + _movingEntities.remove(entity); + _movableButStoppedEntities.remove(entity); + } } - _changedEntities.clear(); +} + +void SimpleEntitySimulation::clearEntitiesInternal() { _movingEntities.clear(); - _mortalEntities.clear(); -} - -void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet& entitiesToDelete) { - foreach (EntityItem* entity, _changedEntities) { - // check to see if the lifetime has expired, for immortal entities this is always false - if (entity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); - entitiesToDelete.insert(entity); - clearEntityState(entity); - } else { - updateEntityState(entity); - } - entity->clearUpdateFlags(); - } - _changedEntities.clear(); + _movableButStoppedEntities.clear(); } -void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet& entitiesToDelete) { - if (_entityTree && _movingEntities.size() > 0) { - PerformanceTimer perfTimer("_movingEntities"); - MovingEntitiesOperator moveOperator(_entityTree); - QList::iterator item_itr = _movingEntities.begin(); - while (item_itr != _movingEntities.end()) { - EntityItem* entity = *item_itr; - - // always check to see if the lifetime has expired, for immortal entities this is always false - if (entity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); - entitiesToDelete.insert(entity); - // remove entity from the list - item_itr = _movingEntities.erase(item_itr); - entity->setSimulationState(EntityItem::Static); - } else { - AACube oldCube = entity->getMaximumAACube(); - entity->update(now); - AACube newCube = entity->getMaximumAACube(); - - // check to see if this movement has sent the entity outside of the domain. - AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); - if (!domainBounds.touches(newCube)) { - qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds."; - entitiesToDelete.insert(entity); - // remove entity from the list - item_itr = _movingEntities.erase(item_itr); - entity->setSimulationState(EntityItem::Static); - } else { - moveOperator.addEntityToMoveList(entity, oldCube, newCube); - EntityItem::SimulationState newState = entity->computeSimulationState(); - if (newState != EntityItem::Moving) { - if (newState == EntityItem::Mortal) { - _mortalEntities.push_back(entity); - } - // remove entity from the list - item_itr = _movingEntities.erase(item_itr); - entity->setSimulationState(newState); - } else { - ++item_itr; - } - } - } - } - if (moveOperator.hasMovingEntities()) { - PerformanceTimer perfTimer("recurseTreeWithOperator"); - _entityTree->recurseTreeWithOperator(&moveOperator); - } - } -} - -void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { - QList::iterator item_itr = _mortalEntities.begin(); - while (item_itr != _mortalEntities.end()) { - EntityItem* entity = *item_itr; - // always check to see if the lifetime has expired, for immortal entities this is always false - if (entity->lifetimeHasExpired()) { - qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID(); - entitiesToDelete.insert(entity); - // remove entity from the list - item_itr = _mortalEntities.erase(item_itr); - entity->setSimulationState(EntityItem::Static); - } else { - // check to see if this entity is no longer moving - EntityItem::SimulationState newState = entity->computeSimulationState(); - if (newState != EntityItem::Mortal) { - if (newState == EntityItem::Moving) { - entity->update(now); - _movingEntities.push_back(entity); - } - // remove entity from the list - item_itr = _mortalEntities.erase(item_itr); - entity->setSimulationState(newState); - } else { - ++item_itr; - } - } - } -} - -void SimpleEntitySimulation::updateEntityState(EntityItem* entity) { - EntityItem::SimulationState oldState = entity->getSimulationState(); - EntityItem::SimulationState newState = entity->computeSimulationState(); - if (newState != oldState) { - switch (oldState) { - case EntityItem::Moving: - _movingEntities.removeAll(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.removeAll(entity); - break; - - default: - break; - } - - switch (newState) { - case EntityItem::Moving: - _movingEntities.push_back(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.push_back(entity); - break; - - default: - break; - } - entity->setSimulationState(newState); - } -} - -void SimpleEntitySimulation::clearEntityState(EntityItem* entity) { - EntityItem::SimulationState oldState = entity->getSimulationState(); - switch (oldState) { - case EntityItem::Moving: - _movingEntities.removeAll(entity); - break; - - case EntityItem::Mortal: - _mortalEntities.removeAll(entity); - break; - - default: - break; - } - entity->setSimulationState(EntityItem::Static); -} - - diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 7d0e8f0113..92b6a28215 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -19,29 +19,17 @@ class SimpleEntitySimulation : public EntitySimulation { public: SimpleEntitySimulation() : EntitySimulation() { } - virtual ~SimpleEntitySimulation() { setEntityTree(NULL); } - - virtual void update(QSet& entitiesToDelete); - - virtual void addEntity(EntityItem* entity); - virtual void removeEntity(EntityItem* entity); - virtual void entityChanged(EntityItem* entity); - - virtual void clearEntities(); + virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } protected: - void updateEntityState(EntityItem* entity); - void clearEntityState(EntityItem* entity); + virtual void updateEntitiesInternal(const quint64& now); + virtual void addEntityInternal(EntityItem* entity); + virtual void removeEntityInternal(EntityItem* entity); + virtual void entityChangedInternal(EntityItem* entity); + virtual void clearEntitiesInternal(); - QList& getMovingEntities() { return _movingEntities; } - - void updateChangedEntities(quint64 now, QSet& entitiesToDelete); - void updateMovingEntities(quint64 now, QSet& entitiesToDelete); - void updateMortalEntities(quint64 now, QSet& entitiesToDelete); - - QSet _changedEntities; // entities that have changed in the last frame - QList _movingEntities; // entities that need to be updated - QList _mortalEntities; // non-moving entities that need to be checked for expiry + QSet _movingEntities; + QSet _movableButStoppedEntities; }; #endif // hifi_SimpleEntitySimulation_h From f1c6e2d1a23db6b3c276565110c6c3c0fa8fca69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 19:52:48 -0800 Subject: [PATCH 055/100] more debugging --- interface/src/Application.cpp | 17 ++++++++ .../entities/RenderableModelEntityItem.cpp | 2 + interface/src/renderer/Model.cpp | 39 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44f83102e2..863bca8a85 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -434,6 +434,23 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #endif this->installEventFilter(this); + + + + + qDebug() << "------------------------------------------------------------"; + qDebug() << " test findRayTrianlgeIntersection()...."; + float distanceA; + bool testA = findRayTrianlgeIntersection(glm::vec3(0.5,0.5,1), glm::vec3(0,0,-1), glm::vec3(0,0,0), glm::vec3(1,0,0), glm::vec3(0,1,0), distanceA); + qDebug() << " testA:" << testA; + qDebug() << " distanceA:" << distanceA; + + float distanceB; + bool testB = findRayTrianlgeIntersection(glm::vec3(0.5,0.5,1), glm::vec3(0,0,-1), glm::vec3(0,0,0), glm::vec3(0,1,0), glm::vec3(1,0,0), distanceB); + qDebug() << " testB:" << testB; + qDebug() << " distanceB:" << distanceB; + qDebug() << "------------------------------------------------------------"; + } void Application::aboutToQuit() { diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 6bc6f52782..e2fd50ceee 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -262,6 +262,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori void** intersectedObject) const { qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection()...."; + qDebug() << " this.id:" << getEntityItemID(); + qDebug() << " this.modelURL:" << getModelURL(); qDebug() << " origin:" << origin; glm::vec3 originInMeters = origin * (float)TREE_SCALE; qDebug() << " originInMeters:" << originInMeters; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a259e42117..3606a17cf8 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -584,6 +584,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g qDebug() << " distanceToSubMesh < bestDistance !! looks like a good match!"; if (pickAgainstTriangles) { + qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; if (!_calculatedMeshTrianglesValid) { recalcuateMeshBoxes(); } @@ -596,9 +597,15 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g float thisTriangleDistance; if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; if (thisTriangleDistance < bestTriangleDistance) { bestTriangleDistance = thisTriangleDistance; someTriangleHit = true; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; + } else { + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; } } } @@ -611,6 +618,38 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g } else { qDebug() << " distanceToSubMesh >= bestDistance !! TOO FAR AWAY!"; } + } else { + // TODO: this needs to be deleted... there shouldn't be any reason to run this here... if the mesh's bounding box + // doesn't intersect, then how can any of it's triangles!!!! + + qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() MISSES???"; + if (pickAgainstTriangles) { + qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles anyway!!"; + if (!_calculatedMeshTrianglesValid) { + recalcuateMeshBoxes(); + } + // check our triangles here.... + const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; + int t = 0; + foreach (const Triangle& triangle, meshTriangles) { + //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; + t++; + + float thisTriangleDistance; + if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; + if (thisTriangleDistance < bestTriangleDistance) { + bestTriangleDistance = thisTriangleDistance; + someTriangleHit = true; + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; + } else { + qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; + } + } + } + } } subMeshIndex++; } From 1fec69698ec66db629413af7b1288737fb7715a6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 5 Dec 2014 23:23:21 -0800 Subject: [PATCH 056/100] get the triangle picking for submeshes working, remove some debug --- .../entities/RenderableModelEntityItem.cpp | 16 +- interface/src/renderer/Model.cpp | 200 ++++++++++-------- interface/src/renderer/Model.h | 1 + libraries/entities/src/EntityTreeElement.cpp | 44 ++-- libraries/octree/src/OctreeElement.cpp | 34 +-- libraries/shared/src/GeometryUtil.cpp | 8 +- 6 files changed, 169 insertions(+), 134 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index e2fd50ceee..37efeb98ee 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -174,7 +174,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("model->render"); bool dontRenderAsScene = true; // Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); if (dontRenderAsScene) { - _model->render(alpha, modelRenderMode, args); + if (!_model->renderTriangleProxies()) { + _model->render(alpha, modelRenderMode, args); + } } else { _model->renderInScene(alpha, args); } @@ -261,12 +263,12 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) const { - qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection()...."; - qDebug() << " this.id:" << getEntityItemID(); - qDebug() << " this.modelURL:" << getModelURL(); - qDebug() << " origin:" << origin; + //qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection()...."; + //qDebug() << " this.id:" << getEntityItemID(); + //qDebug() << " this.modelURL:" << getModelURL(); + //qDebug() << " origin:" << origin; glm::vec3 originInMeters = origin * (float)TREE_SCALE; - qDebug() << " originInMeters:" << originInMeters; + //qDebug() << " originInMeters:" << originInMeters; QString extraInfo; float localDistance; @@ -276,7 +278,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori // NOTE: findRayIntersectionAgainstSubMeshes() does work in meters, but we're expected to return // results in tree scale. distance = localDistance / (float)TREE_SCALE; - qDebug() << " --hit this mode -- returning distance:" << distance; + //qDebug() << " --hit this mode -- returning distance:" << distance; } return intersectsModel; // we only got here if we intersected our non-aabox diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 3606a17cf8..8f684440da 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -516,6 +516,61 @@ void Model::setJointStates(QVector states) { _boundingRadius = radius; } +bool Model::renderTriangleProxies() { + if (!isActive()) { + return false; + } + if (_calculatedMeshTrianglesValid) { + int color = 0; + foreach (const QVector& meshTriangles, _calculatedMeshTriangles) { + switch(color) { + case 0: glColor3ub( 0, 0, 255); break; + case 1: glColor3ub( 0, 255, 0); break; + case 2: glColor3ub( 0, 255, 255); break; + case 3: glColor3ub(255, 0, 0); break; + case 4: glColor3ub(255, 0, 255); break; + case 5: glColor3ub(255, 255, 0); break; + case 6: glColor3ub( 0, 0, 128); break; + case 7: glColor3ub( 0, 128, 0); break; + case 8: glColor3ub( 0, 128, 128); break; + case 9: glColor3ub(128, 0, 0); break; + case 10: glColor3ub(128, 0, 128); break; + case 11: glColor3ub(128, 128, 0); break; + case 12: glColor3ub(128, 128, 255); break; + case 13: glColor3ub(128, 255, 128); break; + case 14: glColor3ub(128, 255, 255); break; + case 15: glColor3ub(255, 128, 128); break; + case 16: glColor3ub(255, 128, 255); break; + case 17: glColor3ub(255, 255, 128); break; + default: glColor3ub(255,255, 255); break; + } + + if (_calculatedMeshBoxes.size() > color) { + const AABox& box = _calculatedMeshBoxes[color]; + glm::vec3 center = box.calcCenter(); + glm::vec3 dimensions = box.getDimensions(); + glPushMatrix(); + glTranslatef(center.x, center.y, center.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + Application::getInstance()->getDeferredLightingEffect()->renderWireCube(1.0f); + glPopMatrix(); + } + + + glBegin(GL_TRIANGLES); + foreach (const Triangle& triangle, meshTriangles) { + //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; + glVertex3f( triangle.v0.x, triangle.v0.y, triangle.v0.z); + glVertex3f( triangle.v1.x, triangle.v1.y, triangle.v1.z); + glVertex3f( triangle.v2.x, triangle.v2.y, triangle.v2.z); + } + glEnd(); + color++; + } + } + return _calculatedMeshTrianglesValid; +} + bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo) { @@ -528,9 +583,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g bool pickAgainstTriangles = Menu::getInstance()->isOptionChecked(MenuOption::PickAgainstModelTriangles); - qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; - qDebug() << " origin:" << origin; - qDebug() << " direction:" << direction; + //qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; + //qDebug() << " origin:" << origin; + //qDebug() << " direction:" << direction; // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; @@ -540,24 +595,24 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); Extents modelExtents = getMeshExtents(); // NOTE: unrotated - qDebug() << " modelExtents:" << modelExtents; + //qDebug() << " modelExtents:" << modelExtents; glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference AABox modelFrameBox(corner, dimensions); - qDebug() << " modelFrameBox:" << modelFrameBox; + //qDebug() << " modelFrameBox:" << modelFrameBox; glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); - qDebug() << " modelFrameOrigin:" << modelFrameOrigin; - qDebug() << " modelFrameDirection:" << modelFrameDirection; + //qDebug() << " modelFrameOrigin:" << modelFrameOrigin; + //qDebug() << " modelFrameDirection:" << modelFrameDirection; // we can use the AABox's ray intersection by mapping our origin and direction into the model frame // and testing intersection there. if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { - qDebug() << " modelFrameBox.findRayIntersection() HITS!!!"; + //qDebug() << " modelFrameBox.findRayIntersection() HITS!!!"; float bestDistance = std::numeric_limits::max(); float bestTriangleDistance = std::numeric_limits::max(); @@ -569,22 +624,23 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g const FBXGeometry& geometry = _geometry->getFBXGeometry(); - qDebug() << " Checking mesh boxes...."; - + //qDebug() << " Checking mesh boxes...."; + // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { - qDebug() << " subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; + //qDebug() << " subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { - qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() HITS!"; - qDebug() << " subMeshBox[" << subMeshIndex <<"].distanceToSubMesh:" << distanceToSubMesh; - qDebug() << " bestDistance:" << bestDistance; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() HITS!"; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].distanceToSubMesh:" << distanceToSubMesh; + //qDebug() << " bestDistance:" << bestDistance; if (distanceToSubMesh < bestDistance) { - qDebug() << " distanceToSubMesh < bestDistance !! looks like a good match!"; + //qDebug() << " distanceToSubMesh < bestDistance !! looks like a good match!"; if (pickAgainstTriangles) { - qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; + someTriangleHit = false; + //qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; if (!_calculatedMeshTrianglesValid) { recalcuateMeshBoxes(); } @@ -592,93 +648,59 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; int t = 0; foreach (const Triangle& triangle, meshTriangles) { - //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; + //qDebug() << "checking triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; t++; float thisTriangleDistance; if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; - if (thisTriangleDistance < bestTriangleDistance) { + //qDebug() << "---- HIT triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2 << " -----"; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; + if (thisTriangleDistance < bestDistance) { bestTriangleDistance = thisTriangleDistance; someTriangleHit = true; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; + + bestDistance = thisTriangleDistance; + intersectedSomething = true; + face = subMeshFace; + extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + + //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; } else { - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; + //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; } } } + } else { + // this is the non-triangle picking case... + bestDistance = distanceToSubMesh; + intersectedSomething = true; + face = subMeshFace; + extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } - - bestDistance = distanceToSubMesh; - intersectedSomething = true; - face = subMeshFace; - extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } else { - qDebug() << " distanceToSubMesh >= bestDistance !! TOO FAR AWAY!"; + //qDebug() << " distanceToSubMesh >= bestDistance !! TOO FAR AWAY!"; } - } else { - // TODO: this needs to be deleted... there shouldn't be any reason to run this here... if the mesh's bounding box - // doesn't intersect, then how can any of it's triangles!!!! - - qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() MISSES???"; - if (pickAgainstTriangles) { - qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles anyway!!"; - if (!_calculatedMeshTrianglesValid) { - recalcuateMeshBoxes(); - } - // check our triangles here.... - const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; - int t = 0; - foreach (const Triangle& triangle, meshTriangles) { - //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; - t++; - - float thisTriangleDistance; - if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; - if (thisTriangleDistance < bestTriangleDistance) { - bestTriangleDistance = thisTriangleDistance; - someTriangleHit = true; - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; - } else { - qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; - } - } - } - } - } + } subMeshIndex++; } - // if we were asked to pick against triangles, and we didn't hit one, then we - // do not consider this model to be hit at all. - if (pickAgainstTriangles && !someTriangleHit) { - qDebug() << "pickAgainstTriangles && !someTriangleHit --- call it a NON-HIT!"; - intersectedSomething = false; - } - qDebug() << "pickAgainstTriangles:" << pickAgainstTriangles; - qDebug() << "someTriangleHit:" << someTriangleHit; - qDebug() << "bestTriangleDistance:" << bestTriangleDistance; - qDebug() << "bestDistance:" << bestDistance; + //qDebug() << "pickAgainstTriangles:" << pickAgainstTriangles; + //qDebug() << "someTriangleHit:" << someTriangleHit; + //qDebug() << "bestTriangleDistance:" << bestTriangleDistance; + //qDebug() << "bestDistance:" << bestDistance; + //qDebug() << "intersectedSomething:" << intersectedSomething; if (intersectedSomething) { - qDebug() << " --- we hit this model --- "; - - if (pickAgainstTriangles) { - distance = bestTriangleDistance; - } else { - distance = bestDistance; - } - qDebug() << "distance:" << distance; + //qDebug() << " --- we hit this model --- "; + distance = bestDistance; + //qDebug() << "distance:" << distance; } return intersectedSomething; } else { - qDebug() << "modelFrameBox.findRayIntersection()... DID NOT INTERSECT..."; + //qDebug() << "modelFrameBox.findRayIntersection()... DID NOT INTERSECT..."; } return intersectedSomething; @@ -689,12 +711,14 @@ void Model::recalcuateMeshBoxes() { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded) { - qDebug() << "Model::recalcuateMeshBoxes()"; + qDebug() << "************************************************************************************************"; + qDebug() << "Model::recalcuateMeshBoxes() -------------------------------------------------------------------"; PerformanceTimer perfTimer("calculatedMeshBoxes"); const FBXGeometry& geometry = _geometry->getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); _calculatedMeshTriangles.clear(); + _calculatedMeshTriangles.resize(numberOfMeshes); for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); @@ -731,8 +755,14 @@ void Model::recalcuateMeshBoxes() { glm::vec3 v2 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f))); glm::vec3 v3 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f))); - Triangle tri1 = { v0, v1, v3 }; - Triangle tri2 = { v1, v2, v3 }; + // Sam's + //Triangle tri1 = { v0, v1, v3 }; + //Triangle tri2 = { v1, v2, v3 }; + + // triangle 0 1 2 + // triangle 2 3 0 + Triangle tri1 = { v0, v1, v2 }; + Triangle tri2 = { v2, v3, v0 }; //qDebug() << "quad["<< q <<"].t1 :" << v0 << ", "<< v1 << ", " << v3; //qDebug() << "quad["<< q <<"].t2 :" << v1 << ", "<< v2 << ", " << v3; @@ -764,7 +794,7 @@ void Model::recalcuateMeshBoxes() { } } - _calculatedMeshTriangles.push_back(thisMeshTriangles); + _calculatedMeshTriangles[i] = thisMeshTriangles; qDebug() << "------------------------------------------------------------------------------"; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 406622e6a8..4145b7b3d9 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -89,6 +89,7 @@ public: enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, RenderArgs* args = NULL); + bool renderTriangleProxies(); // Scene rendering support static void startScene(RenderArgs::RenderSide renderSide); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index aea278adf6..ac65245f4b 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -479,10 +479,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // only called if we do intersect our bounding cube, but find if we actually intersect with entities... - qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; - qDebug() << " origin:" << origin; - qDebug() << " distance:" << distance; - qDebug() << " number of entities:" << _entityItems->size(); + //qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; + //qDebug() << " origin:" << origin; + //qDebug() << " distance:" << distance; + //qDebug() << " number of entities:" << _entityItems->size(); int entityNumber = 0; QList::iterator entityItr = _entityItems->begin(); @@ -498,15 +498,15 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con float localDistance; BoxFace localFace; - qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; - qDebug() << " checking entity[" << entityNumber << "]:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); - qDebug() << " checking the AABox:" << entityBox; + //qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; + //qDebug() << " checking entity[" << entityNumber << "]:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + //qDebug() << " checking the AABox:" << entityBox; // if the ray doesn't intersect with our cube, we can stop searching! if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { - qDebug() << " AABox for entity intersects!"; - qDebug() << " localDistance:" << localDistance; + //qDebug() << " AABox for entity intersects!"; + //qDebug() << " localDistance:" << localDistance; // extents is the entity relative, scaled, centered extents of the entity glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); @@ -525,51 +525,51 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. - qDebug() << " checking the entityFrameBox:" << entityFrameBox; + //qDebug() << " checking the entityFrameBox:" << entityFrameBox; if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { - qDebug() << " entityFrameBox intersects!"; - qDebug() << " localDistance:" << localDistance; + //qDebug() << " entityFrameBox intersects!"; + //qDebug() << " localDistance:" << localDistance; if (localDistance < distance) { - qDebug() << " localDistance < distance... continue..."; + //qDebug() << " localDistance < distance... continue..."; // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { - qDebug() << " entity->supportsDetailedRayIntersection()...."; + //qDebug() << " entity->supportsDetailedRayIntersection()...."; if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, localFace, intersectedObject)) { - qDebug() << " localDistance (detailed):" << localDistance; + //qDebug() << " localDistance (detailed):" << localDistance; if (localDistance < distance) { - qDebug() << " localDistance < distance..."; - qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + //qDebug() << " localDistance < distance..."; + //qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); distance = localDistance; face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; } else { - qDebug() << " localDistance >= distance... TOO FAR AWAY"; + //qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } else { // if the entity type doesn't support a detailed intersection, then just return the non-AABox results if (localDistance < distance) { - qDebug() << " localDistance < distance..."; - qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); + //qDebug() << " localDistance < distance..."; + //qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); distance = localDistance; face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; } else { - qDebug() << " localDistance >= distance... TOO FAR AWAY"; + //qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } @@ -580,7 +580,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con entityNumber++; } - qDebug() << " EntityTreeElement::findDetailedRayIntersection().... returning somethingIntersected:" << somethingIntersected << "keepSearching:" << keepSearching; + //qDebug() << " EntityTreeElement::findDetailedRayIntersection().... returning somethingIntersected:" << somethingIntersected << "keepSearching:" << keepSearching; return somethingIntersected; } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 9f6e0530a8..e3ff06b2d3 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1346,23 +1346,23 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 AACube debugCube = cube; debugCube.scale((float)TREE_SCALE); - qDebug() << "OctreeElement::findRayIntersection()...."; - qDebug() << " origin:" << origin; - qDebug() << " checking element:" << debugCube << "in meters"; - qDebug() << " distance:" << distance; + //qDebug() << "OctreeElement::findRayIntersection()...."; + //qDebug() << " origin:" << origin; + //qDebug() << " checking element:" << debugCube << "in meters"; + //qDebug() << " distance:" << distance; // if the ray doesn't intersect with our cube, we can stop searching! if (!cube.findRayIntersection(origin, direction, distanceToElementCube, localFace)) { - qDebug() << " didn't intersect cube... done searching..."; + //qDebug() << " didn't intersect cube... done searching..."; keepSearching = false; // no point in continuing to search return false; // we did not intersect } - qDebug() << " distanceToElementCube:" << distanceToElementCube; + //qDebug() << " distanceToElementCube:" << distanceToElementCube; // by default, we only allow intersections with leaves with content if (!canRayIntersect()) { - qDebug() << " NOT canRayIntersect() -- no point in calling detailed..."; + //qDebug() << " NOT canRayIntersect() -- no point in calling detailed..."; return false; // we don't intersect with non-leaves, and we keep searching } @@ -1373,28 +1373,28 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 // for any details inside the cube to be closer so we don't need to consider them. if (cube.contains(origin) || distanceToElementCube < distance) { - qDebug() << " distanceToElementCube < distance:" << (distanceToElementCube < distance); - qDebug() << " cube.contains(origin):" << (cube.contains(origin)); - qDebug() << " continue.... call... findDetailedRayIntersection()..."; + //qDebug() << " distanceToElementCube < distance:" << (distanceToElementCube < distance); + //qDebug() << " cube.contains(origin):" << (cube.contains(origin)); + //qDebug() << " continue.... call... findDetailedRayIntersection()..."; //qDebug() << " distanceToElementCube < distance -- continue.... call... findDetailedRayIntersection()..."; if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, face, intersectedObject, distanceToElementCube)) { - qDebug() << " findDetailedRayIntersection() -- intersected something"; + //qDebug() << " findDetailedRayIntersection() -- intersected something"; if (distanceToElementDetails < distance) { - qDebug() << " distanceToElementDetails < distance -- THIS ONE IS GOOD -------"; + //qDebug() << " distanceToElementDetails < distance -- THIS ONE IS GOOD -------"; distance = distanceToElementDetails; face = localFace; - qDebug() << " distance:" << distance << " -- THIS ONE IS GOOD -------"; + //qDebug() << " distance:" << distance << " -- THIS ONE IS GOOD -------"; return true; } else { - qDebug() << " distanceToElementDetails:" << distanceToElementDetails; - qDebug() << " distance:" << distance; - qDebug() << " distanceToElementDetails >= distance -- THIS ONE IS NOT SELECTED even though it INTERSECTED -------"; + //qDebug() << " distanceToElementDetails:" << distanceToElementDetails; + //qDebug() << " distance:" << distance; + //qDebug() << " distanceToElementDetails >= distance -- THIS ONE IS NOT SELECTED even though it INTERSECTED -------"; } } } @@ -1412,7 +1412,7 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g if (intersectedObject) { *intersectedObject = this; } - qDebug() << " OctreeElement::findDetailedRayIntersection().... hasContent() -- done searching..."; + //qDebug() << " OctreeElement::findDetailedRayIntersection().... hasContent() -- done searching..."; keepSearching = false; return true; // we did intersect } diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index c064630f83..f44c954a3a 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -252,6 +252,7 @@ bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direct return true; } + bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { @@ -264,7 +265,8 @@ bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direc h = glm::cross(direction, e2); a = glm::dot(e1, h); - if (a > -0.00001 && a < 0.00001) { + if (a > EPSILON && a < EPSILON) { + qDebug() << "if (a > EPSILON && a < EPSILON)..."; return false; } @@ -287,17 +289,17 @@ bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direc t = f * glm::dot(e2,q); // ray intersection - if (t > 0.00001) { + if (t > EPSILON) { distance = t; return true; } else { // this means that there is a line intersection but not a ray intersection + qDebug() << "if (t <= EPSILON)..."; return false; } return false; } - // 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) { From fd00ad95caed61701a7eae47acc30a0923f393fa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 6 Dec 2014 09:24:30 -0800 Subject: [PATCH 057/100] Fix voxel size text display --- examples/editVoxels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 1dd825d3cf..ff096973a3 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -319,7 +319,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, topMargin: 13, text: this.scale.toString(), - alpha: 0.9, + backgroundAlpha: 0.0, visible: editToolsOn }); this.powerOverlay = Overlays.addOverlay("text", { @@ -327,7 +327,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, leftMargin: 28, text: this.power.toString(), - alpha: 0.0, + backgroundAlpha: 0.0, visible: false }); this.setScale = function(scale) { From ec907d1d1da54eb00fec1791e8dae64edd1dea1f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 09:44:30 -0800 Subject: [PATCH 058/100] removed debug --- libraries/shared/src/GeometryUtil.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index f44c954a3a..e2736f8502 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -266,7 +266,6 @@ bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direc a = glm::dot(e1, h); if (a > EPSILON && a < EPSILON) { - qDebug() << "if (a > EPSILON && a < EPSILON)..."; return false; } @@ -294,7 +293,6 @@ bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direc return true; } else { // this means that there is a line intersection but not a ray intersection - qDebug() << "if (t <= EPSILON)..."; return false; } return false; From 303274a554d8876da4330395d1c8b2d9813ad7cc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 10:59:48 -0800 Subject: [PATCH 059/100] tweaks and debug cleanup --- .../entities/RenderableModelEntityItem.cpp | 6 +-- interface/src/renderer/Model.cpp | 41 ++++--------------- interface/src/renderer/Model.h | 6 +-- 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 37efeb98ee..c5f5f0c98a 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -172,11 +172,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); - bool dontRenderAsScene = true; // Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); + bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); if (dontRenderAsScene) { - if (!_model->renderTriangleProxies()) { - _model->render(alpha, modelRenderMode, args); - } + _model->render(alpha, modelRenderMode, args); } else { _model->renderInScene(alpha, args); } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 8f684440da..a59a76709a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -571,8 +571,8 @@ bool Model::renderTriangleProxies() { return _calculatedMeshTrianglesValid; } -bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) { +bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) { bool intersectedSomething = false; @@ -581,8 +581,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } - bool pickAgainstTriangles = Menu::getInstance()->isOptionChecked(MenuOption::PickAgainstModelTriangles); - //qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; //qDebug() << " origin:" << origin; //qDebug() << " direction:" << direction; @@ -706,13 +704,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } -void Model::recalcuateMeshBoxes() { - bool pickAgainstTriangles = Menu::getInstance()->isOptionChecked(MenuOption::PickAgainstModelTriangles); +void Model::recalcuateMeshBoxes(bool pickAgainstTriangles) { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded) { - qDebug() << "************************************************************************************************"; - qDebug() << "Model::recalcuateMeshBoxes() -------------------------------------------------------------------"; PerformanceTimer perfTimer("calculatedMeshBoxes"); const FBXGeometry& geometry = _geometry->getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); @@ -723,16 +718,9 @@ void Model::recalcuateMeshBoxes() { const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); - qDebug() << "mesh.meshExtents["< thisMeshTriangles; for (int j = 0; j < mesh.parts.size(); j++) { const FBXMeshPart& part = mesh.parts.at(j); @@ -742,7 +730,6 @@ void Model::recalcuateMeshBoxes() { if (part.quadIndices.size() > 0) { int numberOfQuads = part.quadIndices.size() / INDICES_PER_QUAD; - qDebug() << "numberOfQuads:" << numberOfQuads; int vIndex = 0; for (int q = 0; q < numberOfQuads; q++) { int i0 = part.quadIndices[vIndex++]; @@ -755,18 +742,14 @@ void Model::recalcuateMeshBoxes() { glm::vec3 v2 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f))); glm::vec3 v3 = calculateScaledOffsetPoint(glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f))); - // Sam's - //Triangle tri1 = { v0, v1, v3 }; - //Triangle tri2 = { v1, v2, v3 }; + // Sam's recommended triangle slices + Triangle tri1 = { v0, v1, v3 }; + Triangle tri2 = { v1, v2, v3 }; - // triangle 0 1 2 - // triangle 2 3 0 - Triangle tri1 = { v0, v1, v2 }; - Triangle tri2 = { v2, v3, v0 }; + // NOTE: Random guy on the internet's recommended triangle slices + //Triangle tri1 = { v0, v1, v2 }; + //Triangle tri2 = { v2, v3, v0 }; - //qDebug() << "quad["<< q <<"].t1 :" << v0 << ", "<< v1 << ", " << v3; - //qDebug() << "quad["<< q <<"].t2 :" << v1 << ", "<< v2 << ", " << v3; - thisMeshTriangles.push_back(tri1); thisMeshTriangles.push_back(tri2); } @@ -774,7 +757,6 @@ void Model::recalcuateMeshBoxes() { if (part.triangleIndices.size() > 0) { int numberOfTris = part.triangleIndices.size() / INDICES_PER_TRIANGLE; - qDebug() << "numberOfTris:" << numberOfTris; int vIndex = 0; for (int t = 0; t < numberOfTris; t++) { int i0 = part.triangleIndices[vIndex++]; @@ -787,17 +769,12 @@ void Model::recalcuateMeshBoxes() { Triangle tri = { v0, v1, v2 }; - //qDebug() << "triangle["<< t <<"] :" << v0 << ", " << v1 << ", " << v2; - thisMeshTriangles.push_back(tri); } } } - _calculatedMeshTriangles[i] = thisMeshTriangles; - qDebug() << "------------------------------------------------------------------------------"; } - } _calculatedMeshBoxesValid = true; _calculatedMeshTrianglesValid = pickAgainstTriangles; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 4145b7b3d9..69dc6344ad 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -197,8 +197,8 @@ public: Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) { _geometry->setTextureWithNameToURL(name, url); } - bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo); + bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); protected: QSharedPointer _geometry; @@ -371,7 +371,7 @@ private: QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes bool _calculatedMeshTrianglesValid; - void recalcuateMeshBoxes(); + void recalcuateMeshBoxes(bool pickAgainstTriangles = false); void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes From 4ee99ef38a69298a819ccf14b51c779aa88272af Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 6 Dec 2014 11:03:28 -0800 Subject: [PATCH 060/100] Remove dead code that's causing problems --- examples/editModels.js | 4 ---- examples/newEditEntities.js | 4 ---- 2 files changed, 8 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 8e3503b9b2..ec9e67881b 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1169,8 +1169,6 @@ var toolBar = (function () { menuItemHeight = Tool.IMAGE_HEIGHT / 2 - 2; loadURLMenuItem = Overlays.addOverlay("text", { - x: newModelButton.x - menuItemWidth, - y: newModelButton.y + menuItemOffset, height: menuItemHeight, backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, @@ -1180,8 +1178,6 @@ var toolBar = (function () { }); loadFileMenuItem = Overlays.addOverlay("text", { - x: newModelButton.x - menuItemWidth, - y: newModelButton.y + menuItemOffset + menuItemHeight, height: menuItemHeight, backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ef1be8fef9..9bbb07651c 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -140,8 +140,6 @@ var toolBar = (function () { menuItemHeight = Tool.IMAGE_HEIGHT / 2 - 2; loadURLMenuItem = Overlays.addOverlay("text", { - x: newModelButton.x - menuItemWidth, - y: newModelButton.y + menuItemOffset, height: menuItemHeight, backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, @@ -151,8 +149,6 @@ var toolBar = (function () { }); loadFileMenuItem = Overlays.addOverlay("text", { - x: newModelButton.x - menuItemWidth, - y: newModelButton.y + menuItemOffset + menuItemHeight, height: menuItemHeight, backgroundColor: menuBackgroundColor, topMargin: menuItemMargin, From ca62e61579c4714a007051480b0148cc81725dac Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 6 Dec 2014 11:11:52 -0800 Subject: [PATCH 061/100] Update scripts with text overlays to use new backgroundAlpha property --- examples/ControlACs.js | 1 + examples/Recorder.js | 3 +++ examples/editModels.js | 7 +++++++ examples/fallingSand.js | 4 ++-- examples/growTrees.js | 4 ++-- examples/libraries/ExportMenu.js | 2 +- examples/libraries/ToolTip.js | 1 + examples/libraries/entityCameraTool.js | 8 ++++++++ examples/libraries/entitySelectionTool.js | 1 + examples/libraries/progressDialog.js | 2 ++ examples/libraries/toolBars.js | 8 ++++++-- examples/lobby.js | 1 + examples/newEditEntities.js | 2 ++ examples/notifications.js | 5 +++-- examples/testModelOverlaySubMeshes.js | 1 + examples/textInputOverlayExample.js | 1 + 16 files changed, 42 insertions(+), 9 deletions(-) diff --git a/examples/ControlACs.js b/examples/ControlACs.js index bbdb1cc4ef..73a4385c24 100644 --- a/examples/ControlACs.js +++ b/examples/ControlACs.js @@ -117,6 +117,7 @@ function setupToolBars() { leftMargin: TEXT_MARGIN, topMargin: TEXT_MARGIN, alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, visible: true })); } diff --git a/examples/Recorder.js b/examples/Recorder.js index 8c784bcea2..ff8c449012 100644 --- a/examples/Recorder.js +++ b/examples/Recorder.js @@ -115,6 +115,7 @@ function setupTimer() { width: 0, height: 0, alpha: 1.0, + backgroundAlpha: 1.0, visible: true }); @@ -129,6 +130,7 @@ function setupTimer() { width: slider.w, height: slider.h, alpha: 1.0, + backgroundAlpha: 1.0, visible: true }); slider.foreground = Overlays.addOverlay("text", { @@ -138,6 +140,7 @@ function setupTimer() { width: slider.pos * slider.w, height: slider.h, alpha: 1.0, + backgroundAlpha: 1.0, visible: true }); diff --git a/examples/editModels.js b/examples/editModels.js index ec9e67881b..c8ad2eb254 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -206,6 +206,7 @@ var progressDialog = (function () { height: backgroundHeight, imageURL: backgroundUrl, alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -216,6 +217,7 @@ var progressDialog = (function () { textColor: textColor, backgroundColor: textBackground, alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -226,6 +228,7 @@ var progressDialog = (function () { textColor: textColor, backgroundColor: textBackground, alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -1174,6 +1177,7 @@ var toolBar = (function () { topMargin: menuItemMargin, text: "Model URL", alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -1183,6 +1187,7 @@ var toolBar = (function () { topMargin: menuItemMargin, text: "Model File", alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -1489,6 +1494,7 @@ var ExportMenu = function (opts) { width: scaleViewWidth, height: height, alpha: 0.0, + backgroundAlpha: 0.0, color: { red: 255, green: 255, blue: 255 }, text: "1" }); @@ -2476,6 +2482,7 @@ function Tooltip() { text: "", color: { red: 228, green: 228, blue: 228 }, alpha: 0.8, + backgroundAlpha: 0.8, visible: false }); this.show = function (doShow) { diff --git a/examples/fallingSand.js b/examples/fallingSand.js index 5018aeb9ca..c85196f10e 100644 --- a/examples/fallingSand.js +++ b/examples/fallingSand.js @@ -117,7 +117,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, topMargin: 13, text: this.scale.toString(), - alpha: 0.0, + backgroundAlpha: 0.0, visible: editToolsOn, color: activeUIColor }); @@ -126,7 +126,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, leftMargin: 28, text: this.power.toString(), - alpha: 0.0, + backgroundAlpha: 0.0, visible: false, color: activeUIColor }); diff --git a/examples/growTrees.js b/examples/growTrees.js index 13d6cdc587..a5b55eecd6 100644 --- a/examples/growTrees.js +++ b/examples/growTrees.js @@ -116,7 +116,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, topMargin: 13, text: this.scale.toString(), - alpha: 0.0, + backgroundAlpha: 0.0, visible: editToolsOn, color: activeUIColor }); @@ -125,7 +125,7 @@ function ScaleSelector() { width: this.SECOND_PART, height: this.height, leftMargin: 28, text: this.power.toString(), - alpha: 0.0, + backgroundAlpha: 0.0, visible: false, color: activeUIColor }); diff --git a/examples/libraries/ExportMenu.js b/examples/libraries/ExportMenu.js index 0a47f2bd69..247391808f 100644 --- a/examples/libraries/ExportMenu.js +++ b/examples/libraries/ExportMenu.js @@ -81,7 +81,7 @@ ExportMenu = function (opts) { y: pos.y + margin, width: scaleViewWidth, height: height, - alpha: 0.0, + backgroundAlpha: 0.0, color: { red: 255, green: 255, blue: 255 }, text: "1" }); diff --git a/examples/libraries/ToolTip.js b/examples/libraries/ToolTip.js index 785a0e4d2f..590eba36d0 100644 --- a/examples/libraries/ToolTip.js +++ b/examples/libraries/ToolTip.js @@ -26,6 +26,7 @@ function Tooltip() { text: "", color: { red: 128, green: 128, blue: 128 }, alpha: 0.2, + backgroundAlpha: 0.2, visible: false }); this.show = function (doShow) { diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 3cd2b8a97e..803a58f48e 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -390,6 +390,7 @@ var ZoomTool = function(opts) { leftMargin: 4, text: "+", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var decreaseButton = Overlays.addOverlay("text", { @@ -403,6 +404,7 @@ var ZoomTool = function(opts) { leftMargin: 4, text: "-", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var zoomBar = Overlays.addOverlay("text", { @@ -416,6 +418,7 @@ var ZoomTool = function(opts) { leftMargin: 4, text: "", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var zoomHandle = Overlays.addOverlay("text", { @@ -428,6 +431,7 @@ var ZoomTool = function(opts) { leftMargin: 4, text: "", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); @@ -501,6 +505,7 @@ var ArrowTool = function(opts) { leftMargin: 4, text: "^", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var leftButton = Overlays.addOverlay("text", { @@ -514,6 +519,7 @@ var ArrowTool = function(opts) { leftMargin: 4, text: "<", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var rightButton = Overlays.addOverlay("text", { @@ -540,6 +546,7 @@ var ArrowTool = function(opts) { leftMargin: 4, text: "v", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); var centerButton = Overlays.addOverlay("text", { @@ -553,6 +560,7 @@ var ArrowTool = function(opts) { leftMargin: 4, text: "", alpha: 1.0, + backgroundAlpha: 1.0, visible: true, }); diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index fa97e9351f..c05ccbcef5 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -368,6 +368,7 @@ SelectionDisplay = (function () { color: { red: 0, green: 0, blue: 0}, backgroundColor: { red: 255, green: 255, blue: 255 }, alpha: 0.7, + backgroundAlpha: 0.7, visible: false, isFacingAvatar: true, drawInFront: true, diff --git a/examples/libraries/progressDialog.js b/examples/libraries/progressDialog.js index dff0904372..7d3b1f88e2 100644 --- a/examples/libraries/progressDialog.js +++ b/examples/libraries/progressDialog.js @@ -40,6 +40,7 @@ progressDialog = (function () { textColor: textColor, backgroundColor: textBackground, alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -50,6 +51,7 @@ progressDialog = (function () { textColor: textColor, backgroundColor: textBackground, alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index dc17f02869..5802625d7b 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -138,6 +138,7 @@ ToolBar = function(x, y, direction) { width: this.width, height: this.height, alpha: 1.0, + backgroundAlpha: 1.0, visible: false }); this.spacing = []; @@ -243,7 +244,10 @@ ToolBar = function(x, y, direction) { this.tools[tool].setAlpha(alpha); } if (this.back != null) { - Overlays.editOverlay(this.back, { alpha: alpha}); + Overlays.editOverlay(this.back, { + alpha: alpha, + backgroundAlpha: alpha + }); } } else { this.tools[tool].setAlpha(alpha); @@ -263,7 +267,7 @@ ToolBar = function(x, y, direction) { ((direction == ToolBar.VERTICAL) ? 1 : 2) * ToolBar.SPACING, visible: true, backgroundColor: color, - alpha: alpha + backgroundAlpha: alpha }); } } diff --git a/examples/lobby.js b/examples/lobby.js index 9e454eccc9..c5a9645e90 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -113,6 +113,7 @@ function drawLobby() { text: "", lineHeight: lineHeight, alpha: 0.9, + backgroundAlpha: 0.9, ignoreRayIntersection: true, visible: false, isFacingAvatar: true diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 9bbb07651c..4abf56c8fd 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -145,6 +145,7 @@ var toolBar = (function () { topMargin: menuItemMargin, text: "Model URL", alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); @@ -154,6 +155,7 @@ var toolBar = (function () { topMargin: menuItemMargin, text: "Model File", alpha: 0.9, + backgroundAlpha: 0.9, visible: false }); diff --git a/examples/notifications.js b/examples/notifications.js index 16e9dd70b2..2c2c4a5c0b 100644 --- a/examples/notifications.js +++ b/examples/notifications.js @@ -115,6 +115,7 @@ function createNotification(text) { color: textColor, backgroundColor: backColor, alpha: backgroundAlpha, + backgroundAlpha: backgroundAlpha, topMargin: topMargin, leftMargin: leftMargin, font: {size: fontSize}, @@ -160,7 +161,7 @@ function fadeIn(noticeIn, buttonIn) { pauseTimer = Script.setInterval(function() { q++; qFade = q / 10.0; - Overlays.editOverlay(noticeIn, {alpha: qFade}); + Overlays.editOverlay(noticeIn, {alpha: qFade, backgroundAlpha: qFade}); Overlays.editOverlay(buttonIn, {alpha: qFade}); if (q >= 9.0) { Script.clearInterval(pauseTimer); @@ -344,7 +345,7 @@ function fadeOut(noticeOut, buttonOut, arraysOut) { pauseTimer = Script.setInterval(function() { r--; rFade = r / 10.0; - Overlays.editOverlay(noticeOut, {alpha: rFade}); + Overlays.editOverlay(noticeOut, {alpha: rFade, backgroundAlpha: rFade}); Overlays.editOverlay(buttonOut, {alpha: rFade}); if (r < 0) { dismiss(noticeOut, buttonOut, arraysOut); diff --git a/examples/testModelOverlaySubMeshes.js b/examples/testModelOverlaySubMeshes.js index 5195b76e60..20ec10ef7c 100644 --- a/examples/testModelOverlaySubMeshes.js +++ b/examples/testModelOverlaySubMeshes.js @@ -57,6 +57,7 @@ var statusText = Overlays.addOverlay("text", { height: 20, backgroundColor: { red: 0, green: 0, blue: 0}, alpha: 1.0, + backgroundAlpha: 1.0, color: { red: 255, green: 255, blue: 255}, topMargin: 4, leftMargin: 4, diff --git a/examples/textInputOverlayExample.js b/examples/textInputOverlayExample.js index e837e81eb5..8a5fad81cd 100644 --- a/examples/textInputOverlayExample.js +++ b/examples/textInputOverlayExample.js @@ -44,6 +44,7 @@ var inputWindow = Overlays.addOverlay("text", { color: textColor, backgroundColor: backColor, alpha: backgroundAlpha, + backgroundAlpha: backgroundAlpha, topMargin: topMargin, leftMargin: leftMargin, font: {size: fontSize}, From 7ea85073f4397faba010fd4ff5f3afbaabc8e3fc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 11:45:49 -0800 Subject: [PATCH 062/100] introduce precision picking in API form --- examples/developerMenuItems.js | 6 ++-- examples/editModels.js | 2 +- interface/src/Menu.h | 2 ++ interface/src/entities/EntityTreeRenderer.cpp | 17 ++++++--- interface/src/entities/EntityTreeRenderer.h | 3 +- .../entities/RenderableLightEntityItem.cpp | 2 +- .../src/entities/RenderableLightEntityItem.h | 2 +- .../entities/RenderableModelEntityItem.cpp | 29 ++++++++------- .../src/entities/RenderableModelEntityItem.h | 2 +- interface/src/renderer/Model.cpp | 2 +- libraries/entities/src/EntityItem.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 11 +++--- .../entities/src/EntityScriptingInterface.h | 7 ++-- libraries/entities/src/EntityTreeElement.cpp | 4 +-- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/entities/src/SphereEntityItem.cpp | 2 +- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/octree/src/Octree.cpp | 8 +++-- libraries/octree/src/Octree.h | 4 ++- libraries/octree/src/OctreeElement.cpp | 35 +++---------------- libraries/octree/src/OctreeElement.h | 4 +-- 23 files changed, 74 insertions(+), 78 deletions(-) diff --git a/examples/developerMenuItems.js b/examples/developerMenuItems.js index 0d2c4895ea..34bd3b3a75 100644 --- a/examples/developerMenuItems.js +++ b/examples/developerMenuItems.js @@ -19,15 +19,17 @@ function setupMenus() { if (!Menu.menuExists("Developer > Entities")) { Menu.addMenu("Developer > Entities"); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Triangles", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Children", isCheckable: true, isChecked: false }); - Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt to Reduce Material Switches", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false }); - Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Pick Against Model Triangles", isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); Menu.addMenu("Developer > Entities > Culling"); Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Out Of View Mesh Parts", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities > Culling", menuItemName: "Don't Cull Too Small Mesh Parts", isCheckable: true, isChecked: false }); + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); } } diff --git a/examples/editModels.js b/examples/editModels.js index 8e3503b9b2..60ca9b6ca6 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2554,7 +2554,7 @@ function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); Vec3.print("[Mouse] Looking at: ", pickRay.origin); - var foundIntersection = Entities.findRayIntersection(pickRay); + var foundIntersection = Entities.findRayIntersection(pickRay, true); // we want precision picking here if(!foundIntersection.accurate) { return; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 520c83177e..3f8a50af01 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -367,6 +367,7 @@ namespace MenuOption { const QString DontCullTooSmallMeshParts = "Don't Cull Too Small Mesh Parts"; const QString DontReduceMaterialSwitches = "Don't Attempt to Reduce Material Switches"; const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene"; + const QString DontDoPrecisionPicking = "Don't Do Precision Picking"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; @@ -378,6 +379,7 @@ namespace MenuOption { const QString DisplayHandTargets = "Show Hand Targets"; const QString DisplayHermiteData = "Display Hermite Data"; const QString DisplayModelBounds = "Display Model Bounds"; + const QString DisplayModelTriangles = "Display Model Triangles"; const QString DisplayModelElementChildProxies = "Display Model Element Children"; const QString DisplayModelElementProxy = "Display Model Element Bounds"; const QString DisplayTimingDetails = "Display Timing Details"; diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 5aacd36a12..c6a6464438 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -650,7 +650,8 @@ PickRay EntityTreeRenderer::computePickRay(float x, float y) { } -RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType) { +RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, + bool precisionPicking) { RayToEntityIntersectionResult result; if (_tree) { EntityTree* entityTree = static_cast(_tree); @@ -658,7 +659,8 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons OctreeElement* element; EntityItem* intersectedEntity = NULL; result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, - (void**)&intersectedEntity, lockType, &result.accurate); + (void**)&intersectedEntity, lockType, &result.accurate, + precisionPicking); if (result.intersects && intersectedEntity) { result.entityID = intersectedEntity->getEntityItemID(); result.properties = intersectedEntity->getProperties(); @@ -710,7 +712,9 @@ QScriptValueList EntityTreeRenderer::createEntityArgs(const EntityItemID& entity void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { PerformanceTimer perfTimer("EntityTreeRenderer::mousePressEvent"); PickRay ray = computePickRay(event->x(), event->y()); - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock); + + bool precisionPicking = !Menu::getInstance()->isOptionChecked(MenuOption::DontDoPrecisionPicking); + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); if (rayPickResult.intersects) { //qDebug() << "mousePressEvent over entity:" << rayPickResult.entityID; emit mousePressOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); @@ -734,7 +738,8 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { PerformanceTimer perfTimer("EntityTreeRenderer::mouseReleaseEvent"); PickRay ray = computePickRay(event->x(), event->y()); - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock); + bool precisionPicking = !Menu::getInstance()->isOptionChecked(MenuOption::DontDoPrecisionPicking); + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); if (rayPickResult.intersects) { //qDebug() << "mouseReleaseEvent over entity:" << rayPickResult.entityID; emit mouseReleaseOnEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); @@ -768,7 +773,9 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI PerformanceTimer perfTimer("EntityTreeRenderer::mouseMoveEvent"); PickRay ray = computePickRay(event->x(), event->y()); - RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock); + + bool precisionPicking = false; // for mouse moves we do not do precision picking + RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); if (rayPickResult.intersects) { QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index 0042dd495f..40df81b46c 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -117,7 +117,8 @@ private: QList _releasedModels; void renderProxies(const EntityItem* entity, RenderArgs* args); PickRay computePickRay(float x, float y); - RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType); + RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, + bool precisionPicking); EntityItemID _currentHoverOverEntityID; EntityItemID _currentClickingOnEntityID; diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp index 91b2d35106..77dbb5da0b 100644 --- a/interface/src/entities/RenderableLightEntityItem.cpp +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -93,7 +93,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const { + void** intersectedObject, bool precisionPicking) const { // TODO: this isn't really correct because we don't know if we actually live in the main tree of the applications's // EntityTreeRenderer. But we probably do. Technically we could be on the clipboard and someone might be trying to diff --git a/interface/src/entities/RenderableLightEntityItem.h b/interface/src/entities/RenderableLightEntityItem.h index 40fa31a4ce..2113f486cc 100644 --- a/interface/src/entities/RenderableLightEntityItem.h +++ b/interface/src/entities/RenderableLightEntityItem.h @@ -37,7 +37,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const; + void** intersectedObject, bool precisionPicking) const; }; diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index c5f5f0c98a..2dd889538a 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -173,10 +173,18 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); bool dontRenderAsScene = Menu::getInstance()->isOptionChecked(MenuOption::DontRenderEntitiesAsScene); - if (dontRenderAsScene) { - _model->render(alpha, modelRenderMode, args); - } else { - _model->renderInScene(alpha, args); + bool displayModelTriangles = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelTriangles); + bool rendered = false; + if (displayModelTriangles) { + rendered = _model->renderTriangleProxies(); + } + + if (!rendered) { + if (dontRenderAsScene) { + _model->render(alpha, modelRenderMode, args); + } else { + _model->renderInScene(alpha, args); + } } } else { // if we couldn't get a model, then just draw a cube @@ -259,24 +267,21 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const { bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const { + void** intersectedObject, bool precisionPicking) const { - //qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection()...."; - //qDebug() << " this.id:" << getEntityItemID(); - //qDebug() << " this.modelURL:" << getModelURL(); - //qDebug() << " origin:" << origin; glm::vec3 originInMeters = origin * (float)TREE_SCALE; - //qDebug() << " originInMeters:" << originInMeters; QString extraInfo; float localDistance; - bool intersectsModel = _model->findRayIntersectionAgainstSubMeshes(originInMeters, direction, localDistance, face, extraInfo); + qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" << precisionPicking; + + bool intersectsModel = _model->findRayIntersectionAgainstSubMeshes(originInMeters, direction, + localDistance, face, extraInfo, precisionPicking); if (intersectsModel) { // NOTE: findRayIntersectionAgainstSubMeshes() does work in meters, but we're expected to return // results in tree scale. distance = localDistance / (float)TREE_SCALE; - //qDebug() << " --hit this mode -- returning distance:" << distance; } return intersectsModel; // we only got here if we intersected our non-aabox diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index 9ed85beeaa..e187b944d8 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -54,7 +54,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const; + void** intersectedObject, bool precisionPicking) const; Model* getModel(EntityTreeRenderer* renderer); private: diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index a59a76709a..ea075227cc 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -640,7 +640,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g someTriangleHit = false; //qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; if (!_calculatedMeshTrianglesValid) { - recalcuateMeshBoxes(); + recalcuateMeshBoxes(pickAgainstTriangles); } // check our triangles here.... const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7dbcaed8fc..22d956886a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -138,7 +138,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const { return true; } + void** intersectedObject, bool precisionPicking) const { return true; } // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 575a6c1a78..7e09e97f6f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -196,16 +196,17 @@ QVector EntityScriptingInterface::findEntities(const glm::vec3& ce return result; } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::TryLock); +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking) { + return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking); } -RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray) { - return findRayIntersectionWorker(ray, Octree::Lock); +RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking) { + return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray, - Octree::lockType lockType) { + Octree::lockType lockType, + bool precisionPicking) { RayToEntityIntersectionResult result; if (_entityTree) { OctreeElement* element; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index da0c6c9f1a..1233af678d 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -90,11 +90,11 @@ public slots: /// If the scripting context has visible voxels, this will determine a ray intersection, the results /// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate /// will be false. - Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray); + Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false); /// If the scripting context has visible voxels, this will determine a ray intersection, and will block in /// order to return an accurate result - Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray); + Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false); Q_INVOKABLE void setLightsArePickable(bool value); Q_INVOKABLE bool getLightsArePickable() const; @@ -124,7 +124,8 @@ private: void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode - RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType); + RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, + bool precisionPicking); uint32_t _nextCreatorTokenID; EntityTree* _entityTree; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index ac65245f4b..058b4503aa 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -475,7 +475,7 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject, float distanceToElementCube) { + void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... @@ -540,7 +540,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con //qDebug() << " entity->supportsDetailedRayIntersection()...."; if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, - localFace, intersectedObject)) { + localFace, intersectedObject, precisionPicking)) { //qDebug() << " localDistance (detailed):" << localDistance; diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index e59b35189f..4fbe9db323 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -137,7 +137,7 @@ public: virtual bool canRayIntersect() const { return hasEntities(); } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject, float distanceToElementCube); + void** intersectedObject, bool precisionPicking, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 12fdd7a8c4..1960d9623e 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -96,7 +96,7 @@ void SphereEntityItem::recalculateCollisionShape() { bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const { + void** intersectedObject, bool precisionPicking) const { // NOTE: origin and direction are in tree units. But our _sphereShape is in meters, so we need to // do a little math to make these match each other. diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index bb4f41726c..5769498229 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -59,7 +59,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const; + void** intersectedObject, bool precisionPicking) const; protected: virtual void recalculateCollisionShape(); diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 17ef33ee1c..f8f518a581 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -118,7 +118,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const { + void** intersectedObject, bool precisionPicking) const { RayIntersectionInfo rayInfo; rayInfo._rayStart = origin; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index a3d323aefd..c980969bb1 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -44,7 +44,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) const; + void** intersectedObject, bool precisionPicking) const; static const QString DEFAULT_TEXT; void setText(const QString& value) { _text = value; } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index f13f832920..1a432c8e59 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -693,13 +693,14 @@ public: BoxFace& face; void** intersectedObject; bool found; + bool precisionPicking; }; bool findRayIntersectionOp(OctreeElement* element, void* extraData) { RayArgs* args = static_cast(extraData); bool keepSearching = true; if (element->findRayIntersection(args->origin, args->direction, keepSearching, - args->element, args->distance, args->face, args->intersectedObject)) { + args->element, args->distance, args->face, args->intersectedObject, args->precisionPicking)) { args->found = true; } return keepSearching; @@ -707,8 +708,9 @@ bool findRayIntersectionOp(OctreeElement* element, void* extraData) { bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, - Octree::lockType lockType, bool* accurateResult) { - RayArgs args = { origin / (float)(TREE_SCALE), direction, element, distance, face, intersectedObject, false}; + Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { + RayArgs args = { origin / (float)(TREE_SCALE), direction, element, distance, face, + intersectedObject, false, precisionPicking}; distance = FLT_MAX; bool gotLock = false; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 4ac7e22d90..cde8565ca2 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -298,7 +298,9 @@ public: bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElement*& node, float& distance, BoxFace& face, void** intersectedObject = NULL, - Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); + Octree::lockType lockType = Octree::TryLock, + bool* accurateResult = NULL, + bool precisionPicking = false); bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index e3ff06b2d3..29f1d52926 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1334,7 +1334,7 @@ void OctreeElement::notifyUpdateHooks() { bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject) { + void** intersectedObject, bool precisionPicking) { keepSearching = true; // assume that we will continue searching after this. @@ -1346,55 +1346,28 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 AACube debugCube = cube; debugCube.scale((float)TREE_SCALE); - //qDebug() << "OctreeElement::findRayIntersection()...."; - //qDebug() << " origin:" << origin; - //qDebug() << " checking element:" << debugCube << "in meters"; - //qDebug() << " distance:" << distance; - // if the ray doesn't intersect with our cube, we can stop searching! if (!cube.findRayIntersection(origin, direction, distanceToElementCube, localFace)) { - //qDebug() << " didn't intersect cube... done searching..."; keepSearching = false; // no point in continuing to search return false; // we did not intersect } - //qDebug() << " distanceToElementCube:" << distanceToElementCube; - // by default, we only allow intersections with leaves with content if (!canRayIntersect()) { - //qDebug() << " NOT canRayIntersect() -- no point in calling detailed..."; return false; // we don't intersect with non-leaves, and we keep searching } - // we did hit this element, so calculate appropriate distances - //localDistance *= TREE_SCALE; - // if the distance to the element cube is not less than the current best distance, then it's not possible // for any details inside the cube to be closer so we don't need to consider them. if (cube.contains(origin) || distanceToElementCube < distance) { - //qDebug() << " distanceToElementCube < distance:" << (distanceToElementCube < distance); - //qDebug() << " cube.contains(origin):" << (cube.contains(origin)); - //qDebug() << " continue.... call... findDetailedRayIntersection()..."; - //qDebug() << " distanceToElementCube < distance -- continue.... call... findDetailedRayIntersection()..."; + if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, + face, intersectedObject, precisionPicking, distanceToElementCube)) { - if (findDetailedRayIntersection(origin, direction, keepSearching, - element, distanceToElementDetails, face, intersectedObject, distanceToElementCube)) { - - //qDebug() << " findDetailedRayIntersection() -- intersected something"; if (distanceToElementDetails < distance) { - //qDebug() << " distanceToElementDetails < distance -- THIS ONE IS GOOD -------"; - distance = distanceToElementDetails; face = localFace; - - //qDebug() << " distance:" << distance << " -- THIS ONE IS GOOD -------"; - return true; - } else { - //qDebug() << " distanceToElementDetails:" << distanceToElementDetails; - //qDebug() << " distance:" << distance; - //qDebug() << " distanceToElementDetails >= distance -- THIS ONE IS NOT SELECTED even though it INTERSECTED -------"; } } } @@ -1403,7 +1376,7 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject, float distanceToElementCube) { + void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // we did hit this element, so calculate appropriate distances if (hasContent()) { diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 9161a9b171..3bd13a2f3c 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -119,11 +119,11 @@ public: virtual bool canRayIntersect() const { return isLeaf(); } virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& node, float& distance, BoxFace& face, - void** intersectedObject = NULL); + void** intersectedObject = NULL, bool precisionPicking = false); virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject, float distanceToElementCube); + void** intersectedObject, bool precisionPicking, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; From 3bb16ce831bf06e283c589c51f6106a2c271eff8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 12:03:46 -0800 Subject: [PATCH 063/100] properly wire up precision picking in JS api --- interface/src/renderer/Model.cpp | 12 ++++++++---- interface/src/renderer/Model.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 5 ++++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ea075227cc..81ac44872d 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -574,6 +574,7 @@ bool Model::renderTriangleProxies() { bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) { +//qDebug() << "Model::findRayIntersectionAgainstSubMeshes() pickAgainstTriangles:" << pickAgainstTriangles; bool intersectedSomething = false; // if we aren't active, we can't ray pick yet... @@ -640,13 +641,13 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g someTriangleHit = false; //qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; if (!_calculatedMeshTrianglesValid) { - recalcuateMeshBoxes(pickAgainstTriangles); + recalculateMeshBoxes(pickAgainstTriangles); } // check our triangles here.... const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; int t = 0; foreach (const Triangle& triangle, meshTriangles) { - //qDebug() << "checking triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; + // qDebug() << "checking triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; t++; float thisTriangleDistance; @@ -704,8 +705,11 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } -void Model::recalcuateMeshBoxes(bool pickAgainstTriangles) { +// TODO: we seem to call this too often when things haven't actually changed... look into optimizing this +void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { + //qDebug() << "recalculateMeshBoxes() pickAgainstTriangles:" << pickAgainstTriangles; bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; + //qDebug() << "recalculateMeshBoxes() calculatedMeshTrianglesNeeded:" << calculatedMeshTrianglesNeeded; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded) { PerformanceTimer perfTimer("calculatedMeshBoxes"); @@ -787,7 +791,7 @@ void Model::renderSetup(RenderArgs* args) { // against. We cache the results of these calculations so long as the model hasn't been // simulated and the mesh hasn't changed. if (args && !_calculatedMeshBoxesValid) { - recalcuateMeshBoxes(); + recalculateMeshBoxes(); } // set up dilated textures on first render after load/simulate diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 69dc6344ad..43b04b7a46 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -371,7 +371,7 @@ private: QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes bool _calculatedMeshTrianglesValid; - void recalcuateMeshBoxes(bool pickAgainstTriangles = false); + void recalculateMeshBoxes(bool pickAgainstTriangles = false); void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7e09e97f6f..26870ad9bb 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -207,12 +207,15 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlock RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, bool precisionPicking) { + + RayToEntityIntersectionResult result; if (_entityTree) { OctreeElement* element; EntityItem* intersectedEntity = NULL; result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, - (void**)&intersectedEntity, lockType, &result.accurate); + (void**)&intersectedEntity, lockType, &result.accurate, + precisionPicking); if (result.intersects && intersectedEntity) { result.entityID = intersectedEntity->getEntityItemID(); result.properties = intersectedEntity->getProperties(); From 351819708bc1d9855175365b9814315650020746 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Sat, 6 Dec 2014 23:50:30 +0100 Subject: [PATCH 064/100] style fixes --- examples/virtualKeyboard.js | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index e48da8a4d1..c89dc6fb04 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -77,7 +77,6 @@ function deleteChar() { } function updateTextOverlay() { - var textwidth = Overlays.textWidth(text, textText); var textLines = textText.split("\n"); var maxLineWidth = 0; for (textLine in textLines) { @@ -182,16 +181,16 @@ keyboard.onFullyLoaded = function() { }; }; -function KeyboardKey(keyboard, key_properties) { +function KeyboardKey(keyboard, keyProperties) { var tthis = this; this._focus = false; - this._beingpressed = false; - this.event = key_properties.event != undefined ? - key_properties.event : 'keypress'; - this.bounds = key_properties.bounds; - this.states = key_properties.states; + this._beingPressed = false; + this.event = keyProperties.event != undefined ? + keyProperties.event : 'keypress'; + this.bounds = keyProperties.bounds; + this.states = keyProperties.states; this.keyboard = keyboard; - this.key_state = key_properties.key_state != undefined ? key_properties.key_state : KBD_LOWERCASE_DEFAULT; + this.keyState = keyProperties.keyState != undefined ? keyProperties.keyState : KBD_LOWERCASE_DEFAULT; // one overlay per bound vector [this.bounds] this.overlays = []; this.getKeyEvent = function() { @@ -217,7 +216,7 @@ function KeyboardKey(keyboard, key_properties) { tthis.setState(eval('KBD_' + (tthis.keyboard.shift ? 'UPPERCASE' : 'LOWERCASE') + '_' + (tthis._focus ? 'HOVER' : 'DEFAULT'))); }; this.updateColor = function() { - var colorIntensity = this._beingpressed ? 128 : 255; + var colorIntensity = this._beingPressed ? 128 : 255; for (var i = 0; i < tthis.bounds.length; i++) { Overlays.editOverlay(tthis.overlays[i], {color: {red: colorIntensity, green: colorIntensity, blue: colorIntensity}} @@ -225,11 +224,11 @@ function KeyboardKey(keyboard, key_properties) { } }; this.press = function() { - tthis._beingpressed = true; + tthis._beingPressed = true; tthis.updateColor(); }; this.release = function() { - tthis._beingpressed = false; + tthis._beingPressed = false; tthis.updateColor(); }; this.blur = function() { @@ -241,10 +240,10 @@ function KeyboardKey(keyboard, key_properties) { tthis.updateState(); }; this.setState = function(state) { - tthis.key_state = state; + tthis.keyState = state; for (var i = 0; i < tthis.bounds.length; i++) { Overlays.editOverlay(tthis.overlays[i], { - subImage: {width: tthis.bounds[i][BOUND_W], height: tthis.bounds[i][BOUND_H], x: tthis.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * tthis.key_state) + tthis.bounds[i][BOUND_Y]} + subImage: {width: tthis.bounds[i][BOUND_W], height: tthis.bounds[i][BOUND_H], x: tthis.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * tthis.keyState) + tthis.bounds[i][BOUND_Y]} }); } }; @@ -278,7 +277,7 @@ function KeyboardKey(keyboard, key_properties) { y: this.keyboard.getY() + this.bounds[i][BOUND_Y] * keyboard.scale, width: this.bounds[i][BOUND_W] * keyboard.scale, height: this.bounds[i][BOUND_H] * keyboard.scale, - subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.key_state) + this.bounds[i][BOUND_Y]}, + subImage: {width: this.bounds[i][BOUND_W], height: this.bounds[i][BOUND_H], x: this.bounds[i][BOUND_X], y: (KEYBOARD_HEIGHT * this.keyState) + this.bounds[i][BOUND_Y]}, alpha: 1 }); this.overlays.push(newOverlay); @@ -366,7 +365,7 @@ function Keyboard() { this.releaseKeys = function() { for (var i = 0; i < tthis.keys.length; i++) { - if (tthis.keys[i]._beingpressed) { + if (tthis.keys[i]._beingPressed) { if (tthis.keys[i].event != 'shift') { tthis.keys[i].release(); } @@ -504,9 +503,9 @@ function Keyboard() { {bounds: [[899, 355, 263, 67]], event: 'submit'} ]; - this.keyboardtextureloaded = function() { + this.keyboardTextureLoaded = function() { if (Overlays.isLoaded(tthis.background)) { - Script.clearInterval(tthis.keyboardtextureloaded_timer); + Script.clearInterval(tthis.keyboardTextureLoaded_timer); for (var i = 0; i < keyProperties.length; i++) { tthis.keys.push(new KeyboardKey(tthis, keyProperties[i])); } @@ -515,7 +514,7 @@ function Keyboard() { } } }; - this.keyboardtextureloaded_timer = Script.setInterval(this.keyboardtextureloaded, 250); + this.keyboardTextureLoaded_timer = Script.setInterval(this.keyboardTextureLoaded, 250); } function Cursor() { From a03984a561a78d21387f4b27dc9d0c6576acefdb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 14:59:50 -0800 Subject: [PATCH 065/100] removed some debug code --- interface/src/Application.cpp | 17 ----------------- .../src/entities/RenderableModelEntityItem.cpp | 2 +- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 863bca8a85..44f83102e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -434,23 +434,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : #endif this->installEventFilter(this); - - - - - qDebug() << "------------------------------------------------------------"; - qDebug() << " test findRayTrianlgeIntersection()...."; - float distanceA; - bool testA = findRayTrianlgeIntersection(glm::vec3(0.5,0.5,1), glm::vec3(0,0,-1), glm::vec3(0,0,0), glm::vec3(1,0,0), glm::vec3(0,1,0), distanceA); - qDebug() << " testA:" << testA; - qDebug() << " distanceA:" << distanceA; - - float distanceB; - bool testB = findRayTrianlgeIntersection(glm::vec3(0.5,0.5,1), glm::vec3(0,0,-1), glm::vec3(0,0,0), glm::vec3(0,1,0), glm::vec3(1,0,0), distanceB); - qDebug() << " testB:" << testB; - qDebug() << " distanceB:" << distanceB; - qDebug() << "------------------------------------------------------------"; - } void Application::aboutToQuit() { diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 2dd889538a..51f46ff30c 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -273,7 +273,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori QString extraInfo; float localDistance; - qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" << precisionPicking; + //qDebug() << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" << precisionPicking; bool intersectsModel = _model->findRayIntersectionAgainstSubMeshes(originInMeters, direction, localDistance, face, extraInfo, precisionPicking); From c8e648c4d724b86aea1284a3867b560d80114d79 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 15:00:29 -0800 Subject: [PATCH 066/100] removed unused menu item --- interface/src/Menu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3f8a50af01..138828d3e8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -434,7 +434,6 @@ namespace MenuOption { const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString Pair = "Pair"; const QString PasteToVoxel = "Paste to Voxel..."; - const QString PickAgainstModelTriangles = "Pick Against Model Triangles"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString Quit = "Quit"; From 1a1fb18ba11cb966855441dd8a70a56d44f0bb8e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 15:03:26 -0800 Subject: [PATCH 067/100] removed dead code --- interface/src/renderer/Model.cpp | 47 -------------------------------- 1 file changed, 47 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 81ac44872d..91bb4735fd 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -556,10 +556,8 @@ bool Model::renderTriangleProxies() { glPopMatrix(); } - glBegin(GL_TRIANGLES); foreach (const Triangle& triangle, meshTriangles) { - //qDebug() << "triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; glVertex3f( triangle.v0.x, triangle.v0.y, triangle.v0.z); glVertex3f( triangle.v1.x, triangle.v1.y, triangle.v1.z); glVertex3f( triangle.v2.x, triangle.v2.y, triangle.v2.z); @@ -574,7 +572,6 @@ bool Model::renderTriangleProxies() { bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) { -//qDebug() << "Model::findRayIntersectionAgainstSubMeshes() pickAgainstTriangles:" << pickAgainstTriangles; bool intersectedSomething = false; // if we aren't active, we can't ray pick yet... @@ -582,10 +579,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g return intersectedSomething; } - //qDebug() << "Model::findRayIntersectionAgainstSubMeshes()..."; - //qDebug() << " origin:" << origin; - //qDebug() << " direction:" << direction; - // extents is the entity relative, scaled, centered extents of the entity glm::vec3 position = _translation; glm::mat4 rotation = glm::mat4_cast(_rotation); @@ -594,25 +587,18 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix); Extents modelExtents = getMeshExtents(); // NOTE: unrotated - //qDebug() << " modelExtents:" << modelExtents; glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum; glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference AABox modelFrameBox(corner, dimensions); - //qDebug() << " modelFrameBox:" << modelFrameBox; - glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f)); glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f)); - //qDebug() << " modelFrameOrigin:" << modelFrameOrigin; - //qDebug() << " modelFrameDirection:" << modelFrameDirection; // we can use the AABox's ray intersection by mapping our origin and direction into the model frame // and testing intersection there. if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { - //qDebug() << " modelFrameBox.findRayIntersection() HITS!!!"; - float bestDistance = std::numeric_limits::max(); float bestTriangleDistance = std::numeric_limits::max(); bool someTriangleHit = false; @@ -623,23 +609,13 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g const FBXGeometry& geometry = _geometry->getFBXGeometry(); - //qDebug() << " Checking mesh boxes...."; - // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { - //qDebug() << " subMeshBox[" << subMeshIndex <<"]:" << subMeshBox; if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { - //qDebug() << " subMeshBox[" << subMeshIndex <<"].findRayIntersection() HITS!"; - //qDebug() << " subMeshBox[" << subMeshIndex <<"].distanceToSubMesh:" << distanceToSubMesh; - //qDebug() << " bestDistance:" << bestDistance; if (distanceToSubMesh < bestDistance) { - - //qDebug() << " distanceToSubMesh < bestDistance !! looks like a good match!"; - if (pickAgainstTriangles) { someTriangleHit = false; - //qDebug() << " subMeshBox[" << subMeshIndex <<"] --- check triangles!!"; if (!_calculatedMeshTrianglesValid) { recalculateMeshBoxes(pickAgainstTriangles); } @@ -647,15 +623,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; int t = 0; foreach (const Triangle& triangle, meshTriangles) { - // qDebug() << "checking triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2; t++; float thisTriangleDistance; if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { - //qDebug() << "---- HIT triangle["<< t <<"] :" << triangle.v0 << ", "<< triangle.v1 << ", " << triangle.v2 << " -----"; - //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- HITS!!"; - //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] thisTriangleDistance:" << thisTriangleDistance; - //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] bestTriangleDistance:" << bestTriangleDistance; if (thisTriangleDistance < bestDistance) { bestTriangleDistance = thisTriangleDistance; someTriangleHit = true; @@ -664,10 +635,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g intersectedSomething = true; face = subMeshFace; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); - - //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- WOOT! BEST DISTANCE!"; - } else { - //qDebug() << " subMeshBox[" << subMeshIndex <<"].triangle[" << t <<"] --- not best distance???"; } } } @@ -678,28 +645,16 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g face = subMeshFace; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } - } else { - //qDebug() << " distanceToSubMesh >= bestDistance !! TOO FAR AWAY!"; } } subMeshIndex++; } - //qDebug() << "pickAgainstTriangles:" << pickAgainstTriangles; - //qDebug() << "someTriangleHit:" << someTriangleHit; - //qDebug() << "bestTriangleDistance:" << bestTriangleDistance; - //qDebug() << "bestDistance:" << bestDistance; - //qDebug() << "intersectedSomething:" << intersectedSomething; - if (intersectedSomething) { - //qDebug() << " --- we hit this model --- "; distance = bestDistance; - //qDebug() << "distance:" << distance; } return intersectedSomething; - } else { - //qDebug() << "modelFrameBox.findRayIntersection()... DID NOT INTERSECT..."; } return intersectedSomething; @@ -707,9 +662,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g // TODO: we seem to call this too often when things haven't actually changed... look into optimizing this void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { - //qDebug() << "recalculateMeshBoxes() pickAgainstTriangles:" << pickAgainstTriangles; bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; - //qDebug() << "recalculateMeshBoxes() calculatedMeshTrianglesNeeded:" << calculatedMeshTrianglesNeeded; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded) { PerformanceTimer perfTimer("calculatedMeshBoxes"); From 08092e7abe2eaca2aa4bc97bac932a2adc6ab3c0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 15:06:00 -0800 Subject: [PATCH 068/100] removed dead code --- libraries/entities/src/EntityTreeElement.cpp | 39 -------------------- 1 file changed, 39 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 058b4503aa..70def167a2 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -478,11 +478,6 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... - - //qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; - //qDebug() << " origin:" << origin; - //qDebug() << " distance:" << distance; - //qDebug() << " number of entities:" << _entityItems->size(); int entityNumber = 0; QList::iterator entityItr = _entityItems->begin(); @@ -498,16 +493,9 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con float localDistance; BoxFace localFace; - //qDebug() << "EntityTreeElement::findDetailedRayIntersection()...."; - //qDebug() << " checking entity[" << entityNumber << "]:" << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); - //qDebug() << " checking the AABox:" << entityBox; - // if the ray doesn't intersect with our cube, we can stop searching! if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { - //qDebug() << " AABox for entity intersects!"; - //qDebug() << " localDistance:" << localDistance; - // extents is the entity relative, scaled, centered extents of the entity glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); glm::mat4 translation = glm::translate(entity->getPosition()); @@ -525,51 +513,27 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. - //qDebug() << " checking the entityFrameBox:" << entityFrameBox; - if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { - //qDebug() << " entityFrameBox intersects!"; - //qDebug() << " localDistance:" << localDistance; - if (localDistance < distance) { - //qDebug() << " localDistance < distance... continue..."; - // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { - - //qDebug() << " entity->supportsDetailedRayIntersection()...."; - if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, localFace, intersectedObject, precisionPicking)) { - //qDebug() << " localDistance (detailed):" << localDistance; - if (localDistance < distance) { - - //qDebug() << " localDistance < distance..."; - //qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); - distance = localDistance; face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; - } else { - //qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } else { // if the entity type doesn't support a detailed intersection, then just return the non-AABox results if (localDistance < distance) { - - //qDebug() << " localDistance < distance..."; - //qDebug() << " CHOOSING THIS ONE ---> " << entity->getEntityItemID() << "-" << qPrintable(EntityTypes::getEntityTypeName(entity->getType())); - distance = localDistance; face = localFace; *intersectedObject = (void*)entity; somethingIntersected = true; - } else { - //qDebug() << " localDistance >= distance... TOO FAR AWAY"; } } } @@ -579,9 +543,6 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con ++entityItr; entityNumber++; } - - //qDebug() << " EntityTreeElement::findDetailedRayIntersection().... returning somethingIntersected:" << somethingIntersected << "keepSearching:" << keepSearching; - return somethingIntersected; } From 7011162c70e0ccbb442d94de95d4beb863f773e6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 15:07:02 -0800 Subject: [PATCH 069/100] removed dead code --- libraries/octree/src/OctreeElement.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 29f1d52926..c6938ff1f6 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1385,7 +1385,6 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g if (intersectedObject) { *intersectedObject = this; } - //qDebug() << " OctreeElement::findDetailedRayIntersection().... hasContent() -- done searching..."; keepSearching = false; return true; // we did intersect } From 8dd1a2815f625d43ce1b2f6884a63fdb01d259c9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 15:43:17 -0800 Subject: [PATCH 070/100] use precision picking in newEditEntities --- examples/newEditEntities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ef1be8fef9..606ff5955a 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -465,7 +465,7 @@ function rayPlaneIntersection(pickRay, point, normal) { function findClickedEntity(event) { var pickRay = Camera.computePickRay(event.x, event.y); - var foundIntersection = Entities.findRayIntersection(pickRay); + var foundIntersection = Entities.findRayIntersection(pickRay, true); // want precision picking if (!foundIntersection.accurate) { return null; From d698594899a669b9b69f4f4fb61d7380f80274cd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 6 Dec 2014 19:39:02 -0800 Subject: [PATCH 071/100] use common findRayTriangleIntersection --- interface/src/MetavoxelSystem.cpp | 25 +---------- interface/src/renderer/Model.cpp | 2 +- libraries/shared/src/GeometryUtil.cpp | 62 +++++++++------------------ libraries/shared/src/GeometryUtil.h | 6 +-- 4 files changed, 25 insertions(+), 70 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index ebf2188b4d..87060d7dfa 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -1095,30 +1096,6 @@ VoxelBuffer::VoxelBuffer(const QVector& vertices, const QVector _materials(materials) { } -static bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, - const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { - glm::vec3 firstSide = v0 - v1; - glm::vec3 secondSide = v2 - v1; - glm::vec3 normal = glm::cross(secondSide, firstSide); - float dividend = glm::dot(normal, v1) - glm::dot(origin, normal); - if (dividend > 0.0f) { - return false; // origin below plane - } - float divisor = glm::dot(normal, direction); - if (divisor > -EPSILON) { - return false; - } - float t = dividend / divisor; - glm::vec3 point = origin + direction * t; - if (glm::dot(normal, glm::cross(point - v1, firstSide)) > 0.0f && - glm::dot(normal, glm::cross(secondSide, point - v1)) > 0.0f && - glm::dot(normal, glm::cross(point - v0, v2 - v0)) > 0.0f) { - distance = t; - return true; - } - return false; -} - bool VoxelBuffer::findFirstRayIntersection(const glm::vec3& entry, const glm::vec3& origin, const glm::vec3& direction, float& distance) const { float highest = _size - 1.0f; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 91bb4735fd..71f5129a1e 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -626,7 +626,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g t++; float thisTriangleDistance; - if (findRayTrianlgeIntersection(origin, direction, triangle, thisTriangleDistance)) { + if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) { if (thisTriangleDistance < bestDistance) { bestTriangleDistance = thisTriangleDistance; someTriangleHit = true; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index e2736f8502..5376883438 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -252,48 +252,26 @@ bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direct return true; } - -bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, - const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { - - glm::vec3 e1, e2, h, s, q; - float a, f, u, v, t; - - e1 = v1 - v0; - e2 = v2 - v0; - - h = glm::cross(direction, e2); - a = glm::dot(e1, h); - - if (a > EPSILON && a < EPSILON) { - return false; - } - - f = 1/a; - s = origin - v0; - u = f * glm::dot(s,h); - - if (u < 0.0 || u > 1.0) { - return false; - } - - q = glm::cross(s, e1); - v = f * glm::dot(direction, q); - - if (v < 0.0 || u + v > 1.0) { - return false; - } - - // at this stage we can compute t to find out where the intersection point is on the line - t = f * glm::dot(e2,q); - - // ray intersection - if (t > EPSILON) { - distance = t; - return true; - } else { - // this means that there is a line intersection but not a ray intersection - return false; +bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { + glm::vec3 firstSide = v0 - v1; + glm::vec3 secondSide = v2 - v1; + glm::vec3 normal = glm::cross(secondSide, firstSide); + float dividend = glm::dot(normal, v1) - glm::dot(origin, normal); + if (dividend > 0.0f) { + return false; // origin below plane + } + float divisor = glm::dot(normal, direction); + if (divisor > -EPSILON) { + return false; + } + float t = dividend / divisor; + glm::vec3 point = origin + direction * t; + if (glm::dot(normal, glm::cross(point - v1, firstSide)) > 0.0f && + glm::dot(normal, glm::cross(secondSide, point - v1)) > 0.0f && + glm::dot(normal, glm::cross(point - v0, v2 - v0)) > 0.0f) { + distance = t; + return true; } return false; } diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index f439352ca8..a6889ef73e 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -76,7 +76,7 @@ bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& directi bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance); -bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, +bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance); class Triangle { @@ -86,9 +86,9 @@ public: glm::vec3 v2; }; -inline bool findRayTrianlgeIntersection(const glm::vec3& origin, const glm::vec3& direction, +inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const Triangle& triangle, float& distance) { - return findRayTrianlgeIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance); + return findRayTriangleIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance); } From b08d5b87ca7e954a16c115c8d31fff1efb78aa67 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 7 Dec 2014 01:28:06 -0800 Subject: [PATCH 072/100] implement proper ray picking against ellipsoids Conflicts: libraries/entities/src/SphereEntityItem.cpp --- libraries/entities/src/SphereEntityItem.cpp | 28 +++++++++++++-------- libraries/entities/src/SphereEntityItem.h | 2 ++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 12fdd7a8c4..651d4db4ef 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -10,9 +10,12 @@ // +#include + #include #include +#include #include "EntityTree.h" #include "EntityTreeElement.h" @@ -97,18 +100,21 @@ void SphereEntityItem::recalculateCollisionShape() { bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) const { - - // NOTE: origin and direction are in tree units. But our _sphereShape is in meters, so we need to - // do a little math to make these match each other. - RayIntersectionInfo rayInfo; - rayInfo._rayStart = origin * (float)TREE_SCALE; - rayInfo._rayDirection = direction; + // determine the ray in the frame of the entity transformed from a unit sphere + glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 scale = glm::scale(getDimensions()); + glm::mat4 registration = glm::translate(glm::vec3(0.5f,0.5f,0.5f) - getRegistrationPoint()); + glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 1.0f))); - // TODO: Note this is really doing ray intersections against a sphere, which is fine except in cases - // where our dimensions actually make us an ellipsoid. But we'll live with this for now until we - // get a more full fledged physics library - if (_sphereShape.findRayIntersection(rayInfo)) { - distance = rayInfo._hitDistance / (float)TREE_SCALE; + float localDistance; + if (findRaySphereIntersection(entityFrameOrigin, entityFrameDirection, glm::vec3(0.0f), 0.5f, localDistance)) { + glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance); + glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f)); + distance = glm::distance(origin,hitAt); return true; } return false; diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index bb4f41726c..80b026e31d 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -61,6 +61,8 @@ public: bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) const; + bool isCircle() const { return false && _dimensions.x == _dimensions.y && _dimensions.y == _dimensions.z; } + protected: virtual void recalculateCollisionShape(); From b9891748e14730cf2554b90aae440a0d038234c8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 7 Dec 2014 01:32:31 -0800 Subject: [PATCH 073/100] remove dead code --- libraries/entities/src/SphereEntityItem.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 80b026e31d..6553e225a7 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -60,9 +60,7 @@ public: virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject) const; - - bool isCircle() const { return false && _dimensions.x == _dimensions.y && _dimensions.y == _dimensions.z; } - + protected: virtual void recalculateCollisionShape(); From dd4f3a40066af77fa5ca33c83fc6fe7ff8c583d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 7 Dec 2014 20:18:30 -0800 Subject: [PATCH 074/100] coding standard, added comments --- libraries/entities/src/SphereEntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 651d4db4ef..35fe45c0e2 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -104,15 +104,18 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons glm::mat4 translation = glm::translate(getPosition()); glm::mat4 rotation = glm::mat4_cast(getRotation()); glm::mat4 scale = glm::scale(getDimensions()); - glm::mat4 registration = glm::translate(glm::vec3(0.5f,0.5f,0.5f) - getRegistrationPoint()); + glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint()); glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 1.0f))); float localDistance; + // NOTE: unit sphere has center of 0,0,0 and radius of 0.5 if (findRaySphereIntersection(entityFrameOrigin, entityFrameDirection, glm::vec3(0.0f), 0.5f, localDistance)) { + // determine where on the unit sphere the hit point occured glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance); + // then translate back to work coordinates glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f)); distance = glm::distance(origin,hitAt); return true; From 497fbade9bf2db4a730dfb1a4e5f5299a00810fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 06:48:04 -0800 Subject: [PATCH 075/100] fix crash in entity related AC scripts --- libraries/entities/src/EntityTree.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index d3d9e2da53..5f9aa4a159 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -19,9 +19,13 @@ #include "MovingEntitiesOperator.h" #include "UpdateEntityOperator.h" -EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _simulation(NULL) { +EntityTree::EntityTree(bool shouldReaverage) : + Octree(shouldReaverage), + _fbxService(NULL), + _lightsArePickable(true), + _simulation(NULL) +{ _rootElement = createNewElement(); - _lightsArePickable = true; // assume they are by default } EntityTree::~EntityTree() { From 0f5930a43d0281f93815ca6b49353cb87d2f0260 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 06:50:28 -0800 Subject: [PATCH 076/100] add identifyEntity() to butterflies script --- examples/butterflies.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/butterflies.js b/examples/butterflies.js index 069a0d6792..edc33f7625 100644 --- a/examples/butterflies.js +++ b/examples/butterflies.js @@ -103,6 +103,9 @@ function updateButterflies(deltaTime) { var CHANCE_OF_IMPULSE = 0.04; for (var i = 0; i < numButterflies; i++) { if (Math.random() < CHANCE_OF_IMPULSE) { + if (!butterflies[i].isKnownID) { + butterflies[i] = Entities.identifyEntity(butterflies[i]); + } var properties = Entities.getEntityProperties(butterflies[i]); if (Vec3.length(Vec3.subtract(properties.position, flockPosition)) > range) { Entities.editEntity(butterflies[i], { position: flockPosition } ); From cf98bff28b91612bbd7b93872fd12f83e8d5158f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 07:23:45 -0800 Subject: [PATCH 077/100] enforce dimensions for Light and Text entities --- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/LightEntityItem.cpp | 7 +++++++ libraries/entities/src/LightEntityItem.h | 3 +++ libraries/entities/src/TextEntityItem.cpp | 7 +++++++ libraries/entities/src/TextEntityItem.h | 3 +++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7dbcaed8fc..edabcb1f3f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -160,7 +160,7 @@ public: float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - void setDimensions(const glm::vec3& value) { _dimensions = value; recalculateCollisionShape(); } + virtual void setDimensions(const glm::vec3& value) { _dimensions = value; recalculateCollisionShape(); } /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 20f28cd98c..a24fe58c2a 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -47,6 +47,13 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityI _emptyShape.setRadius(0.0f); } +void LightEntityItem::setDimensions(const glm::vec3& value) { + float maxDimension = glm::max(value.x, value.y, value.z); + _dimensions = glm::vec3(maxDimension, maxDimension, maxDimension); + recalculateCollisionShape(); +} + + EntityItemProperties LightEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 2006efb896..eb9a2ed051 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -22,6 +22,9 @@ public: LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); ALLOW_INSTANTIATION // This class can be instantiated + + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + virtual void setDimensions(const glm::vec3& value); // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties() const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 17ef33ee1c..08fbcdfcf7 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -40,6 +40,13 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityIte setProperties(properties, true); } +void TextEntityItem::setDimensions(const glm::vec3& value) { + // NOTE: Text Entities always have a "depth" of 1cm. + float fixedDepth = 0.01f / (float)TREE_SCALE; + _dimensions = glm::vec3(value.x, value.y, fixedDepth); + recalculateCollisionShape(); +} + EntityItemProperties TextEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index a3d323aefd..4bdd8434b6 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -21,6 +21,9 @@ public: TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); ALLOW_INSTANTIATION // This class can be instantiated + + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + virtual void setDimensions(const glm::vec3& value); // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties() const; From aefeda37bdde58c88d7b49692894744813de8dfc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 09:41:58 -0800 Subject: [PATCH 078/100] more debugging --- examples/libraries/entitySelectionTool.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index fa97e9351f..a96eec9bbb 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1772,17 +1772,27 @@ SelectionDisplay = (function () { var centerToZero = Vec3.subtract(center, zero); var centerToIntersect = Vec3.subtract(center, result.intersection); var angleFromZero = Vec3.orientedAngle(centerToZero, centerToIntersect, rotationNormal); - var distanceFromCenter = Vec3.distance(center, result.intersection); var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; - angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - + // for debugging if (debug) { Vec3.print(" result.intersection:",result.intersection); Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); + Vec3.print(" centerToZero:", centerToZero); + Vec3.print(" centerToIntersect:", centerToIntersect); + Vec3.print(" rotationNormal:", rotationNormal); print(" angleFromZero:" + angleFromZero); + print(" distanceFromCenter:" + distanceFromCenter); + print(" snapAngle:" + snapAngle); + } + + angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; + + // for debugging + if (debug) { + print(" angleFromZero:" + angleFromZero + " --- after snap"); } var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); From 299389ccef8ece4cf0cdd87a51f9c122de767ea2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 8 Dec 2014 09:59:33 -0800 Subject: [PATCH 079/100] Fixed typo --- interface/src/Application.cpp | 2 -- interface/src/ui/ApplicationOverlay.cpp | 28 ++++++++++++------------- interface/src/ui/ApplicationOverlay.h | 10 ++++----- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2d92a99cab..6f12957b2d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2347,12 +2347,10 @@ void Application::update(float deltaTime) { if (OculusManager::isConnected() && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode)){ if (_window->cursor().shape() != Qt::BlankCursor) { - qDebug() << "Hiding cursor" << _window->cursor().shape(); cursor = _window->cursor(); _window->setCursor(QCursor(Qt::BlankCursor)); } } else if(_window->cursor().shape() == Qt::BlankCursor) { - qDebug() << "Showing cursor" << _window->cursor().shape(); _window->setCursor(cursor); } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f4e9e627ad..602e99ac31 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -103,7 +103,7 @@ bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, } } -void renderReticule(glm::quat orientation, float alpha) { +void renderReticle(glm::quat orientation, float alpha) { glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); @@ -269,7 +269,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glm::mat4 rotation = glm::toMat4(orientation); glMultMatrixf(&rotation[0][0]); glScalef(scale, scale, scale); - for (int i = 0; i < NUMBER_OF_RETICULES; i++) { + for (int i = 0; i < NUMBER_OF_RETICLES; i++) { if (_magActive[i]) { _magSizeMult[i] += MAG_SPEED; @@ -285,8 +285,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { if (_magSizeMult[i] > 0.0f) { //Render magnifier, but dont show border for mouse magnifier - glm::vec2 projection = screenToOverlay(glm::vec2(_reticulePosition[MOUSE].x(), - _reticulePosition[MOUSE].y())); + glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), + _reticlePosition[MOUSE].y())); renderMagnifier(projection, _magSizeMult[i], i != MOUSE); } @@ -528,7 +528,7 @@ void ApplicationOverlay::renderPointers() { QPoint position = QPoint(application->getTrueMouseX(), application->getTrueMouseY()); static const int MAX_IDLE_TIME = 3; - if (_reticulePosition[MOUSE] != position) { + if (_reticlePosition[MOUSE] != position) { _lastMouseMove = usecTimestampNow(); } else if (usecTimestampNow() - _lastMouseMove > MAX_IDLE_TIME * USECS_PER_SECOND) { float pitch, yaw, roll; @@ -539,7 +539,7 @@ void ApplicationOverlay::renderPointers() { QCursor::setPos(application->getGLWidget()->mapToGlobal(position)); } - _reticulePosition[MOUSE] = position; + _reticlePosition[MOUSE] = position; _reticleActive[MOUSE] = true; _magActive[MOUSE] = true; _reticleActive[LEFT_CONTROLLER] = false; @@ -561,9 +561,9 @@ void ApplicationOverlay::renderControllerPointers() { MyAvatar* myAvatar = application->getAvatar(); //Static variables used for storing controller state - static quint64 pressedTime[NUMBER_OF_RETICULES] = { 0ULL, 0ULL, 0ULL }; - static bool isPressed[NUMBER_OF_RETICULES] = { false, false, false }; - static bool stateWhenPressed[NUMBER_OF_RETICULES] = { false, false, false }; + static quint64 pressedTime[NUMBER_OF_RETICLES] = { 0ULL, 0ULL, 0ULL }; + static bool isPressed[NUMBER_OF_RETICLES] = { false, false, false }; + static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false }; const HandData* handData = Application::getInstance()->getAvatar()->getHandData(); @@ -610,7 +610,7 @@ void ApplicationOverlay::renderControllerPointers() { QPoint point = getPalmClickLocation(palmData); - _reticulePosition[index] = point; + _reticlePosition[index] = point; //When button 2 is pressed we drag the mag window if (isPressed[index]) { @@ -685,16 +685,16 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { float yaw = glm::acos(-tipDirection.z) * ((yawSign == 0.0f) ? 1.0f : yawSign); glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0.0f)); - renderReticule(orientation, _alpha); + renderReticle(orientation, _alpha); } } //Mouse Pointer if (_reticleActive[MOUSE]) { - glm::vec2 projection = screenToSpherical(glm::vec2(_reticulePosition[MOUSE].x(), - _reticulePosition[MOUSE].y())); + glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), + _reticlePosition[MOUSE].y())); glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); - renderReticule(orientation, _alpha); + renderReticle(orientation, _alpha); } glEnable(GL_DEPTH_TEST); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 538a163d0e..269adef4f3 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -94,11 +94,11 @@ private: float _textureFov; float _textureAspectRatio; - enum Reticules { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICULES }; - bool _reticleActive[NUMBER_OF_RETICULES]; - QPoint _reticulePosition[NUMBER_OF_RETICULES]; - bool _magActive[NUMBER_OF_RETICULES]; - float _magSizeMult[NUMBER_OF_RETICULES]; + enum Reticles { MOUSE, LEFT_CONTROLLER, RIGHT_CONTROLLER, NUMBER_OF_RETICLES }; + bool _reticleActive[NUMBER_OF_RETICLES]; + QPoint _reticlePosition[NUMBER_OF_RETICLES]; + bool _magActive[NUMBER_OF_RETICLES]; + float _magSizeMult[NUMBER_OF_RETICLES]; quint64 _lastMouseMove; float _alpha; From 27bc394bed122f155a8bf08fc9d4796b266c4917 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 10:52:53 -0800 Subject: [PATCH 080/100] repair collision info mismatch --- examples/collidingEntities.js | 12 +++++++----- interface/src/Application.cpp | 7 +++++++ interface/src/entities/EntityTreeRenderer.cpp | 12 ++++++++++++ interface/src/entities/EntityTreeRenderer.h | 3 +++ libraries/entities/src/EntityCollisionSystem.cpp | 13 +++++++------ libraries/entities/src/EntityCollisionSystem.h | 8 ++++---- libraries/entities/src/EntityScriptingInterface.h | 4 ++-- libraries/shared/src/RegisteredMetaTypes.cpp | 1 + libraries/shared/src/RegisteredMetaTypes.h | 2 ++ 9 files changed, 45 insertions(+), 17 deletions(-) diff --git a/examples/collidingEntities.js b/examples/collidingEntities.js index 57a3a1f709..4f03a9ee87 100644 --- a/examples/collidingEntities.js +++ b/examples/collidingEntities.js @@ -42,7 +42,7 @@ function draw(deltaTime) { var colorGreen = { red: 0, green: 255, blue: 0 }; var startPosition = { x: 2, - y: 0, + y: 1, z: 2 }; var largeRadius = 0.5; var verySlow = { @@ -55,9 +55,10 @@ function draw(deltaTime) { collisionsWillMove: true, position: startPosition, dimensions: {x: largeRadius, y: largeRadius, z: largeRadius}, + registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, color: colorGreen, - velocity: verySlow, - gravity: gravity, + //velocity: verySlow, + //gravity: gravity, damping: damping, lifetime: 20 }; @@ -71,7 +72,7 @@ function draw(deltaTime) { var center = { x: 0, - y: 0, + y: 1, z: 0 }; var entitySize = 0.1; @@ -97,9 +98,10 @@ function draw(deltaTime) { collisionsWillMove: true, position: center, dimensions: {x: entitySize, y: entitySize, z: entitySize}, + registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, color: color, velocity: velocity, - gravity: gravity, + //gravity: gravity, damping: damping, lifetime: 20 }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2d92a99cab..0ba3727794 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2019,6 +2019,13 @@ void Application::init() { connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, ScriptEngine::getEntityScriptingInterface(), &EntityScriptingInterface::entityCollisionWithEntity); + // connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts + connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithVoxel, + &_entities, &EntityTreeRenderer::entityCollisionWithVoxel); + + connect(&_entityCollisionSystem, &EntityCollisionSystem::entityCollisionWithEntity, + &_entities, &EntityTreeRenderer::entityCollisionWithEntity); + // connect the _entities (EntityTreeRenderer) to our script engine's EntityScriptingInterface for firing // of events related clicking, hovering over, and entering entities _entities.connectSignalsToSlots(ScriptEngine::getEntityScriptingInterface()); diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 055cbf5026..e9c4e456f2 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -884,3 +884,15 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const } } +void EntityTreeRenderer::entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, + const Collision& collision) { + qDebug() << "EntityTreeRenderer::entityCollisionWithVoxel()... "; +} + +void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, + const Collision& collision) { + qDebug() << "EntityTreeRenderer::entityCollisionWithEntity()... "; + qDebug() << " idA:" << idA; + qDebug() << " idB:" << idB; +} + diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index 40df81b46c..a8695db36d 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -106,6 +106,9 @@ public slots: void deletingEntity(const EntityItemID& entityID); void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); void entitySciptChanging(const EntityItemID& entityID); + void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const Collision& collision); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + protected: virtual Octree* createTree() { return new EntityTree(true); } diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 2ac8ea596d..110aef443f 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -70,13 +70,13 @@ void EntityCollisionSystem::checkEntity(EntityItem* entity) { } void EntityCollisionSystem::emitGlobalEntityCollisionWithVoxel(EntityItem* entity, - VoxelDetail* voxelDetails, const CollisionInfo& collision) { + VoxelDetail* voxelDetails, const Collision& collision) { EntityItemID entityItemID = entity->getEntityItemID(); emit entityCollisionWithVoxel(entityItemID, *voxelDetails, collision); } void EntityCollisionSystem::emitGlobalEntityCollisionWithEntity(EntityItem* entityA, - EntityItem* entityB, const CollisionInfo& collision) { + EntityItem* entityB, const Collision& collision) { EntityItemID idA = entityA->getEntityItemID(); EntityItemID idB = entityB->getEntityItemID(); @@ -104,7 +104,8 @@ void EntityCollisionSystem::updateCollisionWithVoxels(EntityItem* entity) { // the results to systems outside of this octree reference frame. collisionInfo._contactPoint = (float)TREE_SCALE * (entity->getPosition() + entity->getRadius() * glm::normalize(collisionInfo._penetration)); // let the global script run their collision scripts for Entities if they have them - emitGlobalEntityCollisionWithVoxel(entity, voxelDetails, collisionInfo); + Collision collision(collisionInfo._contactPoint, collisionInfo._penetration); + emitGlobalEntityCollisionWithVoxel(entity, voxelDetails, collision); // we must scale back down to the octree reference frame before updating the Entity properties collisionInfo._penetration /= (float)(TREE_SCALE); @@ -169,10 +170,10 @@ void EntityCollisionSystem::updateCollisionWithEntities(EntityItem* entityA) { quint64 now = usecTimestampNow(); - CollisionInfo collision; - collision._penetration = penetration; + Collision collision; + collision.penetration = penetration; // for now the contactPoint is the average between the the two paricle centers - collision._contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); + collision.contactPoint = (0.5f * (float)TREE_SCALE) * (entityA->getPosition() + entityB->getPosition()); emitGlobalEntityCollisionWithEntity(entityA, entityB, collision); glm::vec3 axis = glm::normalize(penetration); diff --git a/libraries/entities/src/EntityCollisionSystem.h b/libraries/entities/src/EntityCollisionSystem.h index b4421ffc72..48b7c17ead 100644 --- a/libraries/entities/src/EntityCollisionSystem.h +++ b/libraries/entities/src/EntityCollisionSystem.h @@ -53,15 +53,15 @@ public: void updateCollisionSound(EntityItem* Entity, const glm::vec3 &penetration, float frequency); signals: - void entityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const CollisionInfo& penetration); - void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& penetration); + void entityCollisionWithVoxel(const EntityItemID& entityItemID, const VoxelDetail& voxel, const Collision& collision); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); private: void applyHardCollision(EntityItem* entity, const CollisionInfo& collisionInfo); static bool updateOperation(OctreeElement* element, void* extraData); - void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const CollisionInfo& penetration); - void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const CollisionInfo& penetration); + void emitGlobalEntityCollisionWithVoxel(EntityItem* Entity, VoxelDetail* voxelDetails, const Collision& penetration); + void emitGlobalEntityCollisionWithEntity(EntityItem* entityA, EntityItem* entityB, const Collision& penetration); EntityEditPacketSender* _packetSender; VoxelTree* _voxels; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 1233af678d..20aaf09f9a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -102,8 +102,8 @@ public slots: Q_INVOKABLE void dumpTree() const; signals: - void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const CollisionInfo& collision); - void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const CollisionInfo& collision); + void entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const Collision& collision); + void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void mousePressOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void mouseMoveOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 02b9d5c927..cc8db8783f 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -26,6 +26,7 @@ static int xColorMetaTypeId = qRegisterMetaType(); static int pickRayMetaTypeId = qRegisterMetaType(); static int collisionMetaTypeId = qRegisterMetaType(); + void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 0fd3138b06..b9278c9f2d 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -68,6 +68,8 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); class Collision { public: Collision() : contactPoint(0.0f), penetration(0.0f) { } + Collision(const glm::vec3& contactPoint, const glm::vec3& penetration) : + contactPoint(contactPoint), penetration(penetration) { } glm::vec3 contactPoint; glm::vec3 penetration; }; From 6fdfde31d92803f84e11d93cfc7f1b3d79ede230 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 11:20:27 -0800 Subject: [PATCH 081/100] whoops, forgot to increment the iterator --- libraries/entities/src/SimpleEntitySimulation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index b962f6980e..17dbd46727 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -25,6 +25,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { } else { entity->simulate(now); _entitiesToBeSorted.insert(entity); + ++itemItr; } } } From 3ce1d4a38d5aac469b22485dc1f4bd67b50a5189 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 11:21:01 -0800 Subject: [PATCH 082/100] set dirty bit when script changes simulation stuff also fixes for linear and angular damping --- libraries/entities/src/EntityItem.cpp | 58 +++++++++++++++------------ libraries/entities/src/EntityItem.h | 10 +++-- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d0d07d1227..b271439662 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -29,7 +29,7 @@ const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float EntityItem::DEFAULT_MASS = 1.0f; const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; const QString EntityItem::DEFAULT_USER_DATA = QString(""); -const float EntityItem::DEFAULT_DAMPING = 0.5f; +const float EntityItem::DEFAULT_DAMPING = 2.0f; const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY; @@ -42,7 +42,7 @@ const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center const glm::vec3 EntityItem::NO_ANGULAR_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); const glm::vec3 EntityItem::DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; -const float EntityItem::DEFAULT_ANGULAR_DAMPING = 0.5f; +const float EntityItem::DEFAULT_ANGULAR_DAMPING = 2.0f; const bool EntityItem::DEFAULT_VISIBLE = true; const bool EntityItem::DEFAULT_IGNORE_FOR_COLLISIONS = false; const bool EntityItem::DEFAULT_COLLISIONS_WILL_MOVE = false; @@ -155,7 +155,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet ByteCountCoded typeCoder = getType(); QByteArray encodedType = typeCoder; - quint64 updateDelta = getLastMoved() <= getLastEdited() ? 0 : getLastMoved() - getLastEdited(); + quint64 updateDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited(); ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); @@ -632,13 +632,13 @@ void EntityItem::simulate(const quint64& now) { setRotation(rotation); // handle damping for angular velocity - if (getAngularDamping() > 0.0f) { - glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); - glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); + float dampingTimescale = getAngularDamping(); + if (dampingTimescale > 0.0f) { + float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); + glm::vec3 newAngularVelocity = (1.0f - dampingFactor) * getAngularVelocity(); setAngularVelocity(newAngularVelocity); if (wantDebug) { - qDebug() << " getDamping():" << getDamping(); - qDebug() << " dampingResistance:" << dampingResistance; + qDebug() << " dampingTimescale :" << dampingTimescale; qDebug() << " newAngularVelocity:" << newAngularVelocity; } } @@ -689,13 +689,15 @@ void EntityItem::simulate(const quint64& now) { } // handle damping for velocity - glm::vec3 dampingResistance = velocity * getDamping(); - if (wantDebug) { - qDebug() << " getDamping():" << getDamping(); - qDebug() << " dampingResistance:" << dampingResistance; - qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; + float dampingTimescale = getDamping(); + if (dampingTimescale > 0.0f) { + float dampingFactor = glm::clamp(timeElapsed / dampingTimescale, 0.0f, 1.0f); + velocity *= (1.0f - dampingFactor); + if (wantDebug) { + qDebug() << " dampingTimescale:" << dampingTimescale; + qDebug() << " newVelocity:" << velocity; + } } - velocity -= dampingResistance * timeElapsed; if (wantDebug) { qDebug() << " velocity AFTER dampingResistance:" << velocity; @@ -778,23 +780,23 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc } } - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters); // this will call recalculate collision shape if needed - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocityInMeters); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePositionInMeters); // this will call recalculate collision shape if needed + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensionsInMeters); // NOTE: radius is obsolete + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, updateMass); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravityInMeters); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, updateScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); @@ -1051,4 +1053,10 @@ void EntityItem::updateLifetime(float value) { } } +void EntityItem::updateScript(const QString& value) { + if (_script != value) { + _script = value; + _dirtyFlags |= EntityItem::DIRTY_SCRIPT; + } +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f0d3330087..bde1ebc684 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -48,7 +48,10 @@ public: DIRTY_COLLISION_GROUP = 0x0008, DIRTY_MOTION_TYPE = 0x0010, DIRTY_SHAPE = 0x0020, - DIRTY_LIFETIME = 0x0040 + DIRTY_LIFETIME = 0x0040, + // add new simulation-relevant flags above + // all other flags below + DIRTY_SCRIPT = 0x8000 }; DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly @@ -292,6 +295,7 @@ public: void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); + void updateScript(const QString& value); uint32_t getDirtyFlags() const { return _dirtyFlags; } void clearDirtyFlags(uint32_t mask = 0xffff) { _dirtyFlags &= ~mask; } @@ -323,12 +327,12 @@ protected: float _mass; glm::vec3 _velocity; glm::vec3 _gravity; - float _damping; + float _damping; // timescale float _lifetime; QString _script; glm::vec3 _registrationPoint; glm::vec3 _angularVelocity; - float _angularDamping; + float _angularDamping; // timescale bool _visible; bool _ignoreForCollisions; bool _collisionsWillMove; From b4f18f15d7a4000fc42a10fc2f4ac67e1df58901 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 8 Dec 2014 11:49:42 -0800 Subject: [PATCH 083/100] Ignore Visage resources in .gitignore except for tracker.cfg --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6e6b69cb66..8365108df9 100644 --- a/.gitignore +++ b/.gitignore @@ -32,5 +32,9 @@ DerivedData interface/external/*/* !interface/external/*/readme.txt +# ignore interface optional resources +interface/resources/visage/* +!interface/resources/visage/tracker.cfg + # Ignore interfaceCache for Linux users interface/interfaceCache/ From 716fca6ae7250c2cc05445300e909c3c8e0f0fd1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 8 Dec 2014 11:49:55 -0800 Subject: [PATCH 084/100] tabs to spaces --- examples/Recorder.js | 260 ++++++++++++++-------------- examples/textInputOverlayExample.js | 238 ++++++++++++------------- 2 files changed, 248 insertions(+), 250 deletions(-) diff --git a/examples/Recorder.js b/examples/Recorder.js index ff8c449012..ddfa3e0315 100644 --- a/examples/Recorder.js +++ b/examples/Recorder.js @@ -15,11 +15,11 @@ Script.include("libraries/toolBars.js"); var recordingFile = "recording.rec"; function setPlayerOptions() { - MyAvatar.setPlayFromCurrentLocation(true); - MyAvatar.setPlayerUseDisplayName(false); - MyAvatar.setPlayerUseAttachments(false); - MyAvatar.setPlayerUseHeadModel(false); - MyAvatar.setPlayerUseSkeletonModel(false); + MyAvatar.setPlayFromCurrentLocation(true); + MyAvatar.setPlayerUseDisplayName(false); + MyAvatar.setPlayerUseAttachments(false); + MyAvatar.setPlayerUseHeadModel(false); + MyAvatar.setPlayerUseSkeletonModel(false); } var windowDimensions = Controller.getViewportDimensions(); @@ -47,118 +47,118 @@ setupTimer(); var watchStop = false; function setupToolBar() { - if (toolBar != null) { - print("Multiple calls to Recorder.js:setupToolBar()"); - return; - } + if (toolBar != null) { + print("Multiple calls to Recorder.js:setupToolBar()"); + return; + } Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; - toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); + toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); recordIcon = toolBar.addTool({ - imageURL: TOOL_ICON_URL + "recording-record.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - x: 0, y: 0, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: MyAvatar.isPlaying() ? ALPHA_OFF : ALPHA_ON, - visible: true - }, true, !MyAvatar.isRecording()); + imageURL: TOOL_ICON_URL + "recording-record.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + x: 0, y: 0, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: MyAvatar.isPlaying() ? ALPHA_OFF : ALPHA_ON, + visible: true + }, true, !MyAvatar.isRecording()); var playLoopWidthFactor = 1.65; playIcon = toolBar.addTool({ - imageURL: TOOL_ICON_URL + "play-pause.svg", - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: (MyAvatar.isRecording() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "play-pause.svg", + width: playLoopWidthFactor * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: (MyAvatar.isRecording() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, + visible: true + }, false); playLoopIcon = toolBar.addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: (MyAvatar.isRecording() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFactor * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: (MyAvatar.isRecording() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, + visible: true + }, false); timerOffset = toolBar.width; spacing = toolBar.addSpacing(0); saveIcon = toolBar.addTool({ - imageURL: TOOL_ICON_URL + "recording-save.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: (MyAvatar.isRecording() || MyAvatar.isPlaying() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "recording-save.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: (MyAvatar.isRecording() || MyAvatar.isPlaying() || MyAvatar.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, + visible: true + }, false); loadIcon = toolBar.addTool({ - imageURL: TOOL_ICON_URL + "recording-upload.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: (MyAvatar.isRecording() || MyAvatar.isPlaying()) ? ALPHA_OFF : ALPHA_ON, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "recording-upload.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: (MyAvatar.isRecording() || MyAvatar.isPlaying()) ? ALPHA_OFF : ALPHA_ON, + visible: true + }, false); } function setupTimer() { - timer = Overlays.addOverlay("text", { - font: { size: 15 }, - text: (0.00).toFixed(3), - backgroundColor: COLOR_OFF, - x: 0, y: 0, - width: 0, - height: 0, - alpha: 1.0, + timer = Overlays.addOverlay("text", { + font: { size: 15 }, + text: (0.00).toFixed(3), + backgroundColor: COLOR_OFF, + x: 0, y: 0, + width: 0, + height: 0, + alpha: 1.0, backgroundAlpha: 1.0, - visible: true - }); + visible: true + }); slider = { x: 0, y: 0, - w: 200, h: 20, - pos: 0.0, // 0.0 <= pos <= 1.0 + w: 200, h: 20, + pos: 0.0, // 0.0 <= pos <= 1.0 }; slider.background = Overlays.addOverlay("text", { - text: "", - backgroundColor: { red: 128, green: 128, blue: 128 }, - x: slider.x, y: slider.y, - width: slider.w, - height: slider.h, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); + text: "", + backgroundColor: { red: 128, green: 128, blue: 128 }, + x: slider.x, y: slider.y, + width: slider.w, + height: slider.h, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); slider.foreground = Overlays.addOverlay("text", { - text: "", - backgroundColor: { red: 200, green: 200, blue: 200 }, - x: slider.x, y: slider.y, - width: slider.pos * slider.w, - height: slider.h, - alpha: 1.0, - backgroundAlpha: 1.0, - visible: true - }); + text: "", + backgroundColor: { red: 200, green: 200, blue: 200 }, + x: slider.x, y: slider.y, + width: slider.pos * slider.w, + height: slider.h, + alpha: 1.0, + backgroundAlpha: 1.0, + visible: true + }); } function updateTimer() { - var text = ""; - if (MyAvatar.isRecording()) { - text = formatTime(MyAvatar.recorderElapsed()); + var text = ""; + if (MyAvatar.isRecording()) { + text = formatTime(MyAvatar.recorderElapsed()); - } else { - text = formatTime(MyAvatar.playerElapsed()) + " / " + - formatTime(MyAvatar.playerLength()); - } + } else { + text = formatTime(MyAvatar.playerElapsed()) + " / " + + formatTime(MyAvatar.playerLength()); + } - Overlays.editOverlay(timer, { - text: text - }) + Overlays.editOverlay(timer, { + text: text + }) toolBar.changeSpacing(text.length * 8 + ((MyAvatar.isRecording()) ? 15 : 0), spacing); if (MyAvatar.isRecording()) { @@ -168,57 +168,56 @@ function updateTimer() { } Overlays.editOverlay(slider.foreground, { - width: slider.pos * slider.w - }); + width: slider.pos * slider.w + }); } function formatTime(time) { - var MIN_PER_HOUR = 60; - var SEC_PER_MIN = 60; - var MSEC_PER_SEC = 1000; + var MIN_PER_HOUR = 60; + var SEC_PER_MIN = 60; + var MSEC_PER_SEC = 1000; - var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR)); - time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); + var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR)); + time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR); - var minutes = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN)); - time -= minutes * (MSEC_PER_SEC * SEC_PER_MIN); + var minutes = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN)); + time -= minutes * (MSEC_PER_SEC * SEC_PER_MIN); - var seconds = Math.floor(time / MSEC_PER_SEC); - seconds = time / MSEC_PER_SEC; + var seconds = Math.floor(time / MSEC_PER_SEC); + seconds = time / MSEC_PER_SEC; - var text = ""; - text += (hours > 0) ? hours + ":" : - ""; - text += (minutes > 0) ? ((minutes < 10 && text != "") ? "0" : "") + minutes + ":" : - ""; - text += ((seconds < 10 && text != "") ? "0" : "") + seconds.toFixed(3); - return text; + var text = ""; + text += (hours > 0) ? hours + ":" : + ""; + text += (minutes > 0) ? ((minutes < 10 && text != "") ? "0" : "") + minutes + ":" : + ""; + text += ((seconds < 10 && text != "") ? "0" : "") + seconds.toFixed(3); + return text; } function moveUI() { - var relative = { x: 70, y: 40 }; - toolBar.move(relative.x, - windowDimensions.y - relative.y); - Overlays.editOverlay(timer, { - x: relative.x + timerOffset - ToolBar.SPACING, - y: windowDimensions.y - relative.y - ToolBar.SPACING - }); + var relative = { x: 70, y: 40 }; + toolBar.move(relative.x, windowDimensions.y - relative.y); + Overlays.editOverlay(timer, { + x: relative.x + timerOffset - ToolBar.SPACING, + y: windowDimensions.y - relative.y - ToolBar.SPACING + }); slider.x = relative.x - ToolBar.SPACING; slider.y = windowDimensions.y - relative.y - slider.h - ToolBar.SPACING; Overlays.editOverlay(slider.background, { - x: slider.x, - y: slider.y, - }); + x: slider.x, + y: slider.y, + }); Overlays.editOverlay(slider.foreground, { - x: slider.x, - y: slider.y, - }); + x: slider.x, + y: slider.y, + }); } function mousePressEvent(event) { - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (recordIcon === toolBar.clicked(clickedOverlay, false) && !MyAvatar.isPlaying()) { if (!MyAvatar.isRecording()) { @@ -270,7 +269,7 @@ function mousePressEvent(event) { if (!MyAvatar.isRecording() && !MyAvatar.isPlaying() && MyAvatar.playerLength() != 0) { recordingFile = Window.save("Save recording to file", ".", "Recordings (*.hfr)"); if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { - MyAvatar.saveRecording(recordingFile); + MyAvatar.saveRecording(recordingFile); } } } else if (loadIcon === toolBar.clicked(clickedOverlay)) { @@ -286,8 +285,8 @@ function mousePressEvent(event) { } } } else if (MyAvatar.playerLength() > 0 && - slider.x < event.x && event.x < slider.x + slider.w && - slider.y < event.y && event.y < slider.y + slider.h) { + slider.x < event.x && event.x < slider.x + slider.w && + slider.y < event.y && event.y < slider.y + slider.h) { isSliding = true; slider.pos = (event.x - slider.x) / slider.w; MyAvatar.setPlayerTime(slider.pos * MyAvatar.playerLength()); @@ -311,14 +310,13 @@ function mouseReleaseEvent(event) { } function update() { - var newDimensions = Controller.getViewportDimensions(); - if (windowDimensions.x != newDimensions.x || - windowDimensions.y != newDimensions.y) { - windowDimensions = newDimensions; - moveUI(); - } + var newDimensions = Controller.getViewportDimensions(); + if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) { + windowDimensions = newDimensions; + moveUI(); + } - updateTimer(); + updateTimer(); if (watchStop && !MyAvatar.isPlaying()) { watchStop = false; @@ -329,12 +327,12 @@ function update() { } function scriptEnding() { - if (MyAvatar.isRecording()) { - MyAvatar.stopRecording(); - } - if (MyAvatar.isPlaying()) { - MyAvatar.stopPlaying(); - } + if (MyAvatar.isRecording()) { + MyAvatar.stopRecording(); + } + if (MyAvatar.isPlaying()) { + MyAvatar.stopPlaying(); + } toolBar.cleanup(); Overlays.deleteOverlay(timer); Overlays.deleteOverlay(slider.background); diff --git a/examples/textInputOverlayExample.js b/examples/textInputOverlayExample.js index 8a5fad81cd..258e07fcc8 100644 --- a/examples/textInputOverlayExample.js +++ b/examples/textInputOverlayExample.js @@ -32,168 +32,168 @@ var clickedButton = false; var cursor = "|"; // add more characters to the string if required var keyString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ - ~!@#$%^&*()_+`1234567890-={}|[]\\:\";'<>?,./"; //permitted characters + ~!@#$%^&*()_+`1234567890-={}|[]\\:\";'<>?,./"; //permitted characters // This will create a text overlay that displays what you type var inputWindow = Overlays.addOverlay("text", { - x: locationX, - y: locationY, - width: width, - height: height, - color: textColor, - backgroundColor: backColor, - alpha: backgroundAlpha, - backgroundAlpha: backgroundAlpha, - topMargin: topMargin, - leftMargin: leftMargin, - font: {size: fontSize}, - text: writing, - visible: true - }); + x: locationX, + y: locationY, + width: width, + height: height, + color: textColor, + backgroundColor: backColor, + alpha: backgroundAlpha, + backgroundAlpha: backgroundAlpha, + topMargin: topMargin, + leftMargin: leftMargin, + font: {size: fontSize}, + text: writing, + visible: true +}); // This will create an image overlay of a button. var button1 = Overlays.addOverlay("image", { // green button - x: buttonLocationX, - y: locationY + 10, - width: 40, - height: 35, - subImage: { x: 0, y: 0, width: 39, height: 35 }, - imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", - color: readyColor, - visible: true - }); + x: buttonLocationX, + y: locationY + 10, + width: 40, + height: 35, + subImage: { x: 0, y: 0, width: 39, height: 35 }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", + color: readyColor, + visible: true +}); // This will create an image overlay of another button. var button2 = Overlays.addOverlay("image", { // red button - x: buttonLocationX, - y: locationY + 60, - width: 40, - height: 35, - subImage: { x: 0, y: 0, width: 39, height: 35 }, - imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", - color: { red: 250, green: 2, blue: 2}, - visible: true, - }); + x: buttonLocationX, + y: locationY + 60, + width: 40, + height: 35, + subImage: { x: 0, y: 0, width: 39, height: 35 }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", + color: { red: 250, green: 2, blue: 2}, + visible: true, +}); // When our script shuts down, we should clean up all of our overlays function scriptEnding() { - Overlays.deleteOverlay(inputWindow); - Overlays.deleteOverlay(button1); - Overlays.deleteOverlay(button2); - //Return control of keys to default on script ending - for(var i=0; i Date: Mon, 8 Dec 2014 12:47:37 -0800 Subject: [PATCH 085/100] Swap out the lobby model for the one with the correct light value --- examples/lobby.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/lobby.js b/examples/lobby.js index c5a9645e90..dd011d08a4 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -92,7 +92,7 @@ function drawLobby() { }; var orbShellProps = { - url: HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Lobby_v8/forStephen1/LobbyShell1.fbx", + url: HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Lobby_v8/forStephen1/LobbyShell1.4_LightTag.fbx", position: orbPosition, rotation: towardsMe, dimensions: orbDimensions, From 0592b74a064d13539e99a86aa277aef8c087aa3e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 14:15:03 -0800 Subject: [PATCH 086/100] make collision callbacks work --- examples/collidingEntities.js | 16 ++--------- .../entityScripts/changeColorOnCollision.js | 27 ++++++++++++++++++ interface/src/entities/EntityTreeRenderer.cpp | 28 ++++++++++++++++--- .../entities/src/EntityCollisionSystem.cpp | 2 +- libraries/octree/src/Octree.cpp | 2 +- 5 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 examples/entityScripts/changeColorOnCollision.js diff --git a/examples/collidingEntities.js b/examples/collidingEntities.js index 4f03a9ee87..1feeaa8de5 100644 --- a/examples/collidingEntities.js +++ b/examples/collidingEntities.js @@ -22,11 +22,6 @@ var velocity = { y: 0, z: 1 }; -var gravity = { - x: 0, - y: 0, - z: 0 }; - var damping = 0.1; var color = { @@ -45,25 +40,20 @@ function draw(deltaTime) { y: 1, z: 2 }; var largeRadius = 0.5; - var verySlow = { - x: 0.01, - y: 0, - z: 0.01 }; var properties = { type: "Sphere", + script: "file:///Users/zappoman/Development/HiFi/hifi/examples/entityScripts/changeColorOnCollision.js", collisionsWillMove: true, position: startPosition, dimensions: {x: largeRadius, y: largeRadius, z: largeRadius}, registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, color: colorGreen, - //velocity: verySlow, - //gravity: gravity, damping: damping, lifetime: 20 }; - Entities.addEntity(properties); + //Entities.addEntity(properties); numberEntitiesAdded++; } @@ -95,13 +85,13 @@ function draw(deltaTime) { if (numberEntitiesAdded <= MAX_ENTITIES) { var properties = { type: "Sphere", + script: "file:///Users/zappoman/Development/HiFi/hifi/examples/entityScripts/changeColorOnCollision.js", collisionsWillMove: true, position: center, dimensions: {x: entitySize, y: entitySize, z: entitySize}, registrationPoint: { x: 0.5, y: 0.5, z: 0.5 }, color: color, velocity: velocity, - //gravity: gravity, damping: damping, lifetime: 20 }; diff --git a/examples/entityScripts/changeColorOnCollision.js b/examples/entityScripts/changeColorOnCollision.js new file mode 100644 index 0000000000..e19e63c35b --- /dev/null +++ b/examples/entityScripts/changeColorOnCollision.js @@ -0,0 +1,27 @@ +// +// changeColorOnCollision.js +// examples/entityScripts +// +// Created by Brad Hefta-Gaub on 12/8/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 +// + +print("changeColorOnCollision.js"); + +(function(){ + function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + this.preload = function(myID) { + print("changeColorOnCollision.js--- preload!!!"); + }; + + this.collisionWithEntity = function(myID, otherID, collisionInfo) { + print("collisionWithEntity"); + Entities.editEntity(myID, { color: { red: getRandomInt(128,255), green: getRandomInt(128,255), blue: getRandomInt(128,255)} }); + }; +}) \ No newline at end of file diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index e9c4e456f2..b13cede725 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -886,13 +886,33 @@ void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const void EntityTreeRenderer::entityCollisionWithVoxel(const EntityItemID& entityID, const VoxelDetail& voxel, const Collision& collision) { - qDebug() << "EntityTreeRenderer::entityCollisionWithVoxel()... "; + QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); + if (entityScript.property("collisionWithVoxel").isValid()) { + QScriptValueList args; + args << entityID.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScript.property("collisionWithVoxel").call(entityScript, args); + } } void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - qDebug() << "EntityTreeRenderer::entityCollisionWithEntity()... "; - qDebug() << " idA:" << idA; - qDebug() << " idB:" << idB; + QScriptValue entityScriptA = loadEntityScript(idA); + if (entityScriptA.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idA.toScriptValue(_entitiesScriptEngine); + args << idB.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptA.property("collisionWithEntity").call(entityScriptA, args); + } + + QScriptValue entityScriptB = loadEntityScript(idB); + if (entityScriptB.property("collisionWithEntity").isValid()) { + QScriptValueList args; + args << idB.toScriptValue(_entitiesScriptEngine); + args << idA.toScriptValue(_entitiesScriptEngine); + args << collisionToScriptValue(_entitiesScriptEngine, collision); + entityScriptB.property("collisionWithEntity").call(entityScriptA, args); + } } diff --git a/libraries/entities/src/EntityCollisionSystem.cpp b/libraries/entities/src/EntityCollisionSystem.cpp index 110aef443f..9c82cb4744 100644 --- a/libraries/entities/src/EntityCollisionSystem.cpp +++ b/libraries/entities/src/EntityCollisionSystem.cpp @@ -54,7 +54,7 @@ void EntityCollisionSystem::updateCollisions() { PerformanceTimer perfTimer("collisions"); assert(_entityTree); // update all Entities - if (_entityTree->tryLockForRead()) { + if (_entityTree->tryLockForWrite()) { foreach (EntityItem* entity, _movingEntities) { checkEntity(entity); } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 1a432c8e59..d6aad45b0d 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -46,7 +46,7 @@ Octree::Octree(bool shouldReaverage) : _isDirty(true), _shouldReaverage(shouldReaverage), _stopImport(false), - _lock(), + _lock(QReadWriteLock::Recursive), _isViewing(false), _isServer(false) { From cdeaaf2ca98d41f8c90d0462c7d80967e2f897f4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 15:06:34 -0800 Subject: [PATCH 087/100] fix deadlock in enter/leave events --- interface/src/entities/EntityTreeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index b13cede725..dd9a0b6a4f 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -233,7 +233,7 @@ void EntityTreeRenderer::update() { void EntityTreeRenderer::checkEnterLeaveEntities() { if (_tree) { - _tree->lockForRead(); + _tree->lockForWrite(); // so that our scripts can do edits if they want glm::vec3 avatarPosition = Application::getInstance()->getAvatar()->getPosition() / (float) TREE_SCALE; if (avatarPosition != _lastAvatarPosition) { From 7449821a9bb075f40883e2e3977bd7cc547add59 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 15:06:50 -0800 Subject: [PATCH 088/100] add ID to the properties dialog box --- examples/libraries/entityPropertyDialogBox.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/libraries/entityPropertyDialogBox.js b/examples/libraries/entityPropertyDialogBox.js index a162697560..a686ebb0f2 100644 --- a/examples/libraries/entityPropertyDialogBox.js +++ b/examples/libraries/entityPropertyDialogBox.js @@ -41,6 +41,8 @@ EntityPropertyDialogBox = (function () { array.push({ label: "Entity Type:" + properties.type, type: "header" }); index++; + array.push({ label: "ID:", value: properties.id }); + index++; array.push({ label: "Locked:", type: "checkbox", value: properties.locked }); index++; @@ -265,6 +267,7 @@ EntityPropertyDialogBox = (function () { var properties = propertiesForEditedEntity; var index = 0; index++; // skip type header + index++; // skip id item properties.locked = array[index++].value; if (properties.type == "Model") { properties.modelURL = array[index++].value; From 0d636314ba9ad98d7ea84e1185ab360b46055fd7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 8 Dec 2014 16:20:39 -0800 Subject: [PATCH 089/100] fixed CR feedback --- examples/collidingEntities.js | 4 +--- examples/entityScripts/changeColorOnCollision.js | 7 ------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/examples/collidingEntities.js b/examples/collidingEntities.js index 1feeaa8de5..7edbc9fecc 100644 --- a/examples/collidingEntities.js +++ b/examples/collidingEntities.js @@ -43,7 +43,6 @@ function draw(deltaTime) { var properties = { type: "Sphere", - script: "file:///Users/zappoman/Development/HiFi/hifi/examples/entityScripts/changeColorOnCollision.js", collisionsWillMove: true, position: startPosition, dimensions: {x: largeRadius, y: largeRadius, z: largeRadius}, @@ -53,7 +52,7 @@ function draw(deltaTime) { lifetime: 20 }; - //Entities.addEntity(properties); + Entities.addEntity(properties); numberEntitiesAdded++; } @@ -85,7 +84,6 @@ function draw(deltaTime) { if (numberEntitiesAdded <= MAX_ENTITIES) { var properties = { type: "Sphere", - script: "file:///Users/zappoman/Development/HiFi/hifi/examples/entityScripts/changeColorOnCollision.js", collisionsWillMove: true, position: center, dimensions: {x: entitySize, y: entitySize, z: entitySize}, diff --git a/examples/entityScripts/changeColorOnCollision.js b/examples/entityScripts/changeColorOnCollision.js index e19e63c35b..69a14f4b52 100644 --- a/examples/entityScripts/changeColorOnCollision.js +++ b/examples/entityScripts/changeColorOnCollision.js @@ -9,19 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -print("changeColorOnCollision.js"); - (function(){ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } - this.preload = function(myID) { - print("changeColorOnCollision.js--- preload!!!"); - }; - this.collisionWithEntity = function(myID, otherID, collisionInfo) { - print("collisionWithEntity"); Entities.editEntity(myID, { color: { red: getRandomInt(128,255), green: getRandomInt(128,255), blue: getRandomInt(128,255)} }); }; }) \ No newline at end of file From 27bfc9907f834071a406bb1c870d34c25eaf60af Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 16:31:36 -0800 Subject: [PATCH 090/100] fix bug preventing butterflies from animating (forgot to make base method virtual) --- libraries/entities/src/EntityItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 314b1c23d5..6fb51cfdba 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -130,7 +130,7 @@ public: // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); - bool needsToCallUpdate() const { return false; } + virtual bool needsToCallUpdate() const { return false; } virtual void debugDump() const; From 675a2dd989c5dfe4d8449564f871d93bf49dbb40 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Dec 2014 16:32:25 -0800 Subject: [PATCH 091/100] add DIRTY_UPDATEABLE flag for changes that need it --- libraries/entities/src/EntityItem.h | 1 + libraries/entities/src/ModelEntityItem.cpp | 16 ++++++++++++++ libraries/entities/src/ModelEntityItem.h | 6 ++--- .../entities/src/SimpleEntitySimulation.cpp | 22 +++++++------------ 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 6fb51cfdba..915440ee6a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -49,6 +49,7 @@ public: DIRTY_MOTION_TYPE = 0x0010, DIRTY_SHAPE = 0x0020, DIRTY_LIFETIME = 0x0040, + DIRTY_UPDATEABLE = 0x0080, // add new simulation-relevant flags above // all other flags below DIRTY_SCRIPT = 0x8000 diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 565974d19e..b9bf75178f 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -397,6 +397,11 @@ void ModelEntityItem::debugDump() const { qDebug() << " model URL:" << getModelURL(); } +void ModelEntityItem::setAnimationURL(const QString& url) { + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; + _animationURL = url; +} + void ModelEntityItem::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and @@ -448,6 +453,17 @@ void ModelEntityItem::setAnimationSettings(const QString& value) { } _animationSettings = value; + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; +} + +void ModelEntityItem::setAnimationIsPlaying(bool value) { + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; + _animationLoop.setRunning(value); +} + +void ModelEntityItem::setAnimationFPS(float value) { + _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; + _animationLoop.setFPS(value); } QString ModelEntityItem::getAnimationSettings() const { diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 502b21af12..6b4ca2416a 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -73,16 +73,16 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } - void setAnimationURL(const QString& url) { _animationURL = url; } + void setAnimationURL(const QString& url); static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value) { _animationLoop.setFrameIndex(value); } void setAnimationSettings(const QString& value); static const bool DEFAULT_ANIMATION_IS_PLAYING; - void setAnimationIsPlaying(bool value) { _animationLoop.setRunning(value); } + void setAnimationIsPlaying(bool value); static const float DEFAULT_ANIMATION_FPS; - void setAnimationFPS(float value) { _animationLoop.setFPS(value); } + void setAnimationFPS(float value); void setAnimationLoop(bool loop) { _animationLoop.setLoop(loop); } bool getAnimationLoop() const { return _animationLoop.getLoop(); } diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 17dbd46727..6fd2d7c48c 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -31,12 +31,10 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { } void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { - if (entity->getCollisionsWillMove()) { - if (entity->isMoving()) { - _movingEntities.insert(entity); - } else { - _movableButStoppedEntities.insert(entity); - } + if (entity->isMoving()) { + _movingEntities.insert(entity); + } else if (entity->getCollisionsWillMove()) { + _movableButStoppedEntities.insert(entity); } } @@ -50,14 +48,10 @@ const int SIMPLE_SIMULATION_DIRTY_FLAGS = EntityItem::DIRTY_VELOCITY | EntityIte void SimpleEntitySimulation::entityChangedInternal(EntityItem* entity) { int dirtyFlags = entity->getDirtyFlags(); if (dirtyFlags & SIMPLE_SIMULATION_DIRTY_FLAGS) { - if (entity->getCollisionsWillMove()) { - if (entity->isMoving()) { - _movingEntities.insert(entity); - _movableButStoppedEntities.remove(entity); - } else { - _movingEntities.remove(entity); - _movableButStoppedEntities.insert(entity); - } + if (entity->isMoving()) { + _movingEntities.insert(entity); + } else if (entity->getCollisionsWillMove()) { + _movableButStoppedEntities.remove(entity); } else { _movingEntities.remove(entity); _movableButStoppedEntities.remove(entity); From d0ca75dd2cc06c335ddc3e3dacc45fd0f890f805 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Dec 2014 18:04:45 -0800 Subject: [PATCH 092/100] Reduce the MTU size to deal with Windows networking issue. --- libraries/metavoxels/src/DatagramSequencer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 1aeef8e450..5c5aee49c2 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -19,7 +19,7 @@ #include "MetavoxelMessages.h" // in sequencer parlance, a "packet" may consist of multiple datagrams. clarify when we refer to actual datagrams -const int MAX_DATAGRAM_SIZE = MAX_PACKET_SIZE; +const int MAX_DATAGRAM_SIZE = 1450; const int DEFAULT_MAX_PACKET_SIZE = 3000; From e5aee44ceb60c0261533988e5ea7df740aad3fe0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 9 Dec 2014 08:51:04 -0800 Subject: [PATCH 093/100] Add setting save/load to grid tool --- examples/html/gridControls.html | 6 +-- examples/libraries/gridTool.js | 77 ++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html index d95c9545e4..06090da423 100644 --- a/examples/html/gridControls.html +++ b/examples/html/gridControls.html @@ -29,11 +29,11 @@ elPosY.value = origin.y.toFixed(2); } - if (data.minorGridSpacing) { + if (data.minorGridSpacing !== undefined) { elMinorSpacing.value = data.minorGridSpacing; } - if (data.majorGridEvery) { + if (data.majorGridEvery !== undefined) { elMajorSpacing.value = data.majorGridEvery; } @@ -41,7 +41,7 @@ gridColor = data.gridColor; } - if (data.elSnapToGrid !== undefined) { + if (data.snapToGrid !== undefined) { elSnapToGrid.checked = data.snapToGrid == true; } diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 7d98befec8..1793fb5b4f 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -1,3 +1,9 @@ +var SETTING_GRID_VISIBLE = 'gridVisible'; +var SETTING_GRID_SNAP_TO_GRID = 'gridSnapToGrid'; +var SETTING_GRID_MINOR_WIDTH= 'gridMinorWidth'; +var SETTING_GRID_MAJOR_EVERY = 'gridMajorEvery'; +var SETTING_GRID_COLOR = 'gridColor'; + Grid = function(opts) { var that = {}; @@ -12,9 +18,6 @@ Grid = function(opts) { var worldSize = 16384; - var minorGridWidth = 0.5; - var majorGridWidth = 1.5; - var snapToGrid = false; var gridOverlay = Overlays.addOverlay("grid", { @@ -23,7 +26,7 @@ Grid = function(opts) { color: { red: 0, green: 0, blue: 128 }, alpha: 1.0, rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), - minorGridWidth: 0.1, + minorGridSpacing: 0.1, majorGridEvery: 2, }); @@ -40,16 +43,38 @@ Grid = function(opts) { that.getSnapToGrid = function() { return snapToGrid; }; that.setEnabled = function(enabled) { - that.enabled = enabled; - updateGrid(); + if (that.enabled != enabled) { + that.enabled = enabled; + + if (enabled) { + if (selectionManager.hasSelection()) { + that.setPosition(selectionManager.getBottomPosition()); + } else { + that.setPosition(MyAvatar.position); + } + } + + updateGrid(); + } } that.setVisible = function(visible, noUpdate) { - that.visible = visible; - updateGrid(); + if (visible != that.visible) { + that.visible = visible; + updateGrid(); - if (!noUpdate) { - that.emitUpdate(); + print("Setting visible"); + if (visible) { + if (selectionManager.hasSelection()) { + that.setPosition(selectionManager.getBottomPosition()); + } else { + that.setPosition(MyAvatar.position); + } + } + + if (!noUpdate) { + that.emitUpdate(); + } } } @@ -171,7 +196,7 @@ Grid = function(opts) { Overlays.editOverlay(gridOverlay, { position: { x: origin.y, y: origin.y, z: -origin.y }, visible: that.visible && that.enabled, - minorGridWidth: minorGridSpacing, + minorGridSpacing: minorGridSpacing, majorGridEvery: majorGridEvery, color: gridColor, alpha: gridAlpha, @@ -181,15 +206,43 @@ Grid = function(opts) { } function cleanup() { + saveSettings(); + Overlays.deleteOverlay(gridOverlay); } + function loadSettings() { + that.setVisible(Settings.getValue(SETTING_GRID_VISIBLE) == "true", true); + snapToGrid = Settings.getValue(SETTING_GRID_SNAP_TO_GRID) == "true"; + minorGridSpacing = parseFloat(Settings.getValue(SETTING_GRID_MINOR_WIDTH), 10); + majorGridEvery = parseInt(Settings.getValue(SETTING_GRID_MAJOR_EVERY), 10); + try { + var newColor = JSON.parse(Settings.getValue(SETTING_GRID_COLOR)); + if (newColor.red !== undefined && newColor.green !== undefined && newColor.blue !== undefined) { + gridColor.red = newColor.red; + gridColor.green = newColor.green; + gridColor.blue = newColor.blue; + } + } catch (e) { + } + updateGrid(); + } + + function saveSettings() { + Settings.setValue(SETTING_GRID_VISIBLE, that.visible); + Settings.setValue(SETTING_GRID_SNAP_TO_GRID, snapToGrid); + Settings.setValue(SETTING_GRID_MINOR_WIDTH, minorGridSpacing); + Settings.setValue(SETTING_GRID_MAJOR_EVERY, majorGridEvery); + Settings.setValue(SETTING_GRID_COLOR, JSON.stringify(gridColor)); + } + that.addListener = function(callback) { that.onUpdate = callback; } Script.scriptEnding.connect(cleanup); - updateGrid(); + + loadSettings(); that.onUpdate = null; From 2696f71be93b318098d5217ce455557d9343a13f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 9 Dec 2014 08:54:28 -0800 Subject: [PATCH 094/100] Update edit entities to disable on wasd or arrow keys --- examples/newEditEntities.js | 45 ++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ef1be8fef9..f9f604afe8 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -215,6 +215,28 @@ var toolBar = (function () { Overlays.editOverlay(loadFileMenuItem, { visible: active }); } + + that.setActive = function(active) { + if (active != isActive) { + isActive = active; + if (!isActive) { + entityListTool.setVisible(false); + gridTool.setVisible(false); + grid.setEnabled(false); + propertiesTool.setVisible(false); + selectionManager.clearSelections(); + cameraManager.disable(); + } else { + cameraManager.enable(); + entityListTool.setVisible(true); + gridTool.setVisible(true); + propertiesTool.setVisible(true); + grid.setEnabled(true); + } + } + toolBar.selectTool(activeButton, active); + }; + var RESIZE_INTERVAL = 50; var RESIZE_TIMEOUT = 20000; var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; @@ -290,21 +312,7 @@ var toolBar = (function () { clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (activeButton === toolBar.clicked(clickedOverlay)) { - isActive = !isActive; - if (!isActive) { - entityListTool.setVisible(false); - gridTool.setVisible(false); - grid.setEnabled(false); - propertiesTool.setVisible(false); - selectionManager.clearSelections(); - cameraManager.disable(); - } else { - cameraManager.enable(); - entityListTool.setVisible(true); - gridTool.setVisible(true); - grid.setEnabled(true); - propertiesTool.setVisible(true); - } + that.setActive(!isActive); return true; } @@ -817,6 +825,13 @@ function handeMenuEvent(menuItem) { Menu.menuItemEvent.connect(handeMenuEvent); +Controller.keyPressEvent.connect(function(event) { + if (event.text == 'w' || event.text == 'a' || event.text == 's' || event.text == 'd' + || event.text == 'UP' || event.text == 'DOWN' || event.text == 'LEFT' || event.text == 'RIGHT') { + toolBar.setActive(false); + } +}); + Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items if (event.text == "`") { From 19ba2a1f84a6cd1ac0361e022885e2d1d134bdf4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 9 Dec 2014 08:56:29 -0800 Subject: [PATCH 095/100] Remove print statement --- examples/libraries/gridTool.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index 1793fb5b4f..622822e108 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -63,7 +63,6 @@ Grid = function(opts) { that.visible = visible; updateGrid(); - print("Setting visible"); if (visible) { if (selectionManager.hasSelection()) { that.setPosition(selectionManager.getBottomPosition()); From 1eaa2caa6ccbd37fd871fa144ce9dab4732a60d8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Dec 2014 11:40:47 -0800 Subject: [PATCH 096/100] fix to crash on rapidly switching domains --- interface/src/entities/EntityTreeRenderer.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index dd9a0b6a4f..2c2b81fa3a 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -151,12 +151,19 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { return QScriptValue(); // no entity... } + // NOTE: we keep local variables for the entityID and the script because + // below in loadScriptContents() it's possible for us to execute the + // application event loop, which may cause our entity to be deleted on + // us. We don't really need access the entity after this point, can + // can accomplish all we need to here with just the script "text" and the ID. EntityItemID entityID = entity->getEntityItemID(); + QString entityScript = entity->getScript(); + if (_entityScripts.contains(entityID)) { EntityScriptDetails details = _entityScripts[entityID]; // check to make sure our script text hasn't changed on us since we last loaded it - if (details.scriptText == entity->getScript()) { + if (details.scriptText == entityScript) { return details.scriptObject; // previously loaded } @@ -164,18 +171,18 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { // has changed and so we need to reload it. _entityScripts.remove(entityID); } - if (entity->getScript().isEmpty()) { + if (entityScript.isEmpty()) { return QScriptValue(); // no script } - QString scriptContents = loadScriptContents(entity->getScript()); + QString scriptContents = loadScriptContents(entityScript); QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(scriptContents); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { qDebug() << "EntityTreeRenderer::loadEntityScript() entity:" << entityID; qDebug() << " " << syntaxCheck.errorMessage() << ":" << syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber(); - qDebug() << " SCRIPT:" << entity->getScript(); + qDebug() << " SCRIPT:" << entityScript; return QScriptValue(); // invalid script } @@ -184,12 +191,12 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity) { if (!entityScriptConstructor.isFunction()) { qDebug() << "EntityTreeRenderer::loadEntityScript() entity:" << entityID; qDebug() << " NOT CONSTRUCTOR"; - qDebug() << " SCRIPT:" << entity->getScript(); + qDebug() << " SCRIPT:" << entityScript; return QScriptValue(); // invalid script } QScriptValue entityScriptObject = entityScriptConstructor.construct(); - EntityScriptDetails newDetails = { entity->getScript(), entityScriptObject }; + EntityScriptDetails newDetails = { entityScript, entityScriptObject }; _entityScripts[entityID] = newDetails; return entityScriptObject; // newly constructed From a6f7a1ce15713124825193c143d3b0ba39dec9b8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 9 Dec 2014 11:52:20 -0800 Subject: [PATCH 097/100] guard against NULL _models --- interface/src/entities/RenderableModelEntityItem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 8509fa1f67..080162dc16 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -268,7 +268,10 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const { bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { - + if (!_model) { + return true; + } + glm::vec3 originInMeters = origin * (float)TREE_SCALE; QString extraInfo; float localDistance; From eaaaa0687ca19d1d2a7839616d873f44fc6436de Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 9 Dec 2014 11:53:14 -0800 Subject: [PATCH 098/100] spacing --- libraries/octree/src/ViewFrustum.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 0549c60134..1d23bf800e 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -591,7 +591,7 @@ PickRay ViewFrustum::computePickRay(float x, float y) { } void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const { - origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft); + origin = _nearTopLeft + x * (_nearTopRight - _nearTopLeft) + y * (_nearBottomLeft - _nearTopLeft); direction = glm::normalize(origin - (_position + _orientation * _eyeOffsetPosition)); } From 649940de244b7fc509818448c3addb0aa0c49d51 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 9 Dec 2014 11:53:32 -0800 Subject: [PATCH 099/100] wrong pickray function --- interface/src/ui/NodeBounds.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index 3c6b4c625a..b0d3ddd14f 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -38,7 +38,8 @@ void NodeBounds::draw() { // Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers // itself after the cursor disappears. Application* application = Application::getInstance(); - PickRay pickRay = application->getCamera()->computeViewPickRay(application->getTrueMouseX(), application->getTrueMouseY()); + PickRay pickRay = application->getCamera()->computePickRay(application->getTrueMouseX(), + application->getTrueMouseY()); // Variables to keep track of the selected node and properties to draw the cube later if needed Node* selectedNode = NULL; From 79fc8a5a7114c1d012d859163cfbe8d3f24e5a46 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Dec 2014 11:58:01 -0800 Subject: [PATCH 100/100] remove debug ryans rotate problem --- examples/libraries/entitySelectionTool.js | 74 ----------------------- examples/newEditEntities.js | 2 - 2 files changed, 76 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 382b8de215..8aff9c32ed 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1749,13 +1749,6 @@ SelectionDisplay = (function () { pushCommandForSelections(); }, onMove: function(event) { - var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); - - if (debug) { - print("rotateYaw()..."); - print(" event.x,y:" + event.x + "," + event.y); - } - var pickRay = Camera.computePickRay(event.x, event.y); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); @@ -1763,10 +1756,6 @@ SelectionDisplay = (function () { var result = Overlays.findRayIntersection(pickRay); - if (debug) { - print(" findRayIntersection() .... result.intersects:" + result.intersects); - } - if (result.intersects) { var center = yawCenter; var zero = yawZero; @@ -1776,26 +1765,7 @@ SelectionDisplay = (function () { var distanceFromCenter = Vec3.distance(center, result.intersection); var snapToInner = distanceFromCenter < innerRadius; var snapAngle = snapToInner ? innerSnapAngle : 1.0; - - // for debugging - if (debug) { - Vec3.print(" result.intersection:",result.intersection); - Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); - Vec3.print(" centerToZero:", centerToZero); - Vec3.print(" centerToIntersect:", centerToIntersect); - Vec3.print(" rotationNormal:", rotationNormal); - print(" angleFromZero:" + angleFromZero); - print(" distanceFromCenter:" + distanceFromCenter); - print(" snapAngle:" + snapAngle); - } - angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - - // for debugging - if (debug) { - print(" angleFromZero:" + angleFromZero + " --- after snap"); - } - var yawChange = Quat.fromVec3Degrees({ x: 0, y: angleFromZero, z: 0 }); // Entities should only reposition if we are rotating multiple selections around @@ -1906,23 +1876,12 @@ SelectionDisplay = (function () { pushCommandForSelections(); }, onMove: function(event) { - var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); - - if (debug) { - print("rotatePitch()..."); - print(" event.x,y:" + event.x + "," + event.y); - } - var pickRay = Camera.computePickRay(event.x, event.y); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); var result = Overlays.findRayIntersection(pickRay); - if (debug) { - print(" findRayIntersection() .... result.intersects:" + result.intersects); - } - if (result.intersects) { var properties = Entities.getEntityProperties(selectionManager.selections[0]); var center = pitchCenter; @@ -1936,13 +1895,6 @@ SelectionDisplay = (function () { var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - // for debugging - if (debug) { - Vec3.print(" result.intersection:",result.intersection); - Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); - print(" angleFromZero:" + angleFromZero); - } - var pitchChange = Quat.fromVec3Degrees({ x: angleFromZero, y: 0, z: 0 }); for (var i = 0; i < SelectionManager.selections.length; i++) { @@ -2043,23 +1995,12 @@ SelectionDisplay = (function () { pushCommandForSelections(); }, onMove: function(event) { - var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); - - if (debug) { - print("rotateRoll()..."); - print(" event.x,y:" + event.x + "," + event.y); - } - var pickRay = Camera.computePickRay(event.x, event.y); Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true, visible: false}); Overlays.editOverlay(baseOfEntityProjectionOverlay, { ignoreRayIntersection: true, visible: false }); Overlays.editOverlay(rotateOverlayTarget, { ignoreRayIntersection: false }); var result = Overlays.findRayIntersection(pickRay); - if (debug) { - print(" findRayIntersection() .... result.intersects:" + result.intersects); - } - if (result.intersects) { var properties = Entities.getEntityProperties(selectionManager.selections[0]); var center = rollCenter; @@ -2073,13 +2014,6 @@ SelectionDisplay = (function () { var snapAngle = snapToInner ? innerSnapAngle : 1.0; angleFromZero = Math.floor(angleFromZero / snapAngle) * snapAngle; - // for debugging - if (debug) { - Vec3.print(" result.intersection:",result.intersection); - Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: center, end: result.intersection }); - print(" angleFromZero:" + angleFromZero); - } - var rollChange = Quat.fromVec3Degrees({ x: 0, y: 0, z: angleFromZero }); for (var i = 0; i < SelectionManager.selections.length; i++) { var entityID = SelectionManager.selections[i]; @@ -2310,14 +2244,6 @@ SelectionDisplay = (function () { Overlays.editOverlay(rotateOverlayInner, { visible: true, rotation: overlayOrientation, position: overlayCenter }); Overlays.editOverlay(rotateOverlayOuter, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 360 }); Overlays.editOverlay(rotateOverlayCurrent, { visible: true, rotation: overlayOrientation, position: overlayCenter, startAt: 0, endAt: 0 }); - - // for debugging - var debug = Menu.isOptionChecked("Debug Ryans Rotation Problems"); - if (debug) { - Overlays.editOverlay(rotateZeroOverlay, { visible: true, start: overlayCenter, end: result.intersection }); - Overlays.editOverlay(rotateCurrentOverlay, { visible: true, start: overlayCenter, end: result.intersection }); - } - Overlays.editOverlay(yawHandle, { visible: false }); Overlays.editOverlay(pitchHandle, { visible: false }); Overlays.editOverlay(rollHandle, { visible: false }); diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 90208ba24e..f1b9dd4421 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -666,7 +666,6 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); - Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); @@ -693,7 +692,6 @@ function cleanupModelMenus() { Menu.removeSeparator("File", "Models"); Menu.removeMenuItem("File", "Export Models"); Menu.removeMenuItem("File", "Import Models"); - Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems"); Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);