Merge branch 'master' of https://github.com/highfidelity/hifi into orange

t :wq
This commit is contained in:
samcake 2015-09-23 09:51:31 -07:00
commit d7d332acd4
47 changed files with 782 additions and 817 deletions

View file

@ -1744,13 +1744,26 @@ void DomainServer::addStaticAssignmentsToQueue() {
// if the domain-server has just restarted, // if the domain-server has just restarted,
// check if there are static assignments that we need to throw into the assignment queue // check if there are static assignments that we need to throw into the assignment queue
QHash<QUuid, SharedAssignmentPointer> staticHashCopy = _allAssignments; auto sharedAssignments = _allAssignments.values();
QHash<QUuid, SharedAssignmentPointer>::iterator staticAssignment = staticHashCopy.begin();
while (staticAssignment != staticHashCopy.end()) { // sort the assignments to put the server/mixer assignments first
qSort(sharedAssignments.begin(), sharedAssignments.end(), [](SharedAssignmentPointer a, SharedAssignmentPointer b){
if (a->getType() == b->getType()) {
return true;
} else if (a->getType() != Assignment::AgentType && b->getType() != Assignment::AgentType) {
return a->getType() < b->getType();
} else {
return a->getType() != Assignment::AgentType;
}
});
auto staticAssignment = sharedAssignments.begin();
while (staticAssignment != sharedAssignments.end()) {
// add any of the un-matched static assignments to the queue // add any of the un-matched static assignments to the queue
// enumerate the nodes and check if there is one with an attached assignment with matching UUID // enumerate the nodes and check if there is one with an attached assignment with matching UUID
if (!DependencyManager::get<LimitedNodeList>()->nodeWithUUID(staticAssignment->data()->getUUID())) { if (!DependencyManager::get<LimitedNodeList>()->nodeWithUUID((*staticAssignment)->getUUID())) {
// this assignment has not been fulfilled - reset the UUID and add it to the assignment queue // this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
refreshStaticAssignmentAndAddToQueue(*staticAssignment); refreshStaticAssignmentAndAddToQueue(*staticAssignment);
} }

View file

@ -1320,7 +1320,7 @@ PropertiesTool = function(opts) {
if (data.action == "moveSelectionToGrid") { if (data.action == "moveSelectionToGrid") {
if (selectionManager.hasSelection()) { if (selectionManager.hasSelection()) {
selectionManager.saveProperties(); selectionManager.saveProperties();
var dY = grid.getOrigin().y - (selectionManager.worldPosition.y - selectionManager.worldDimensions.y / 2), var dY = grid.getOrigin().y - (selectionManager.worldPosition.y - selectionManager.worldDimensions.y / 2);
var diff = { x: 0, y: dY, z: 0 }; var diff = { x: 0, y: dY, z: 0 };
for (var i = 0; i < selectionManager.selections.length; i++) { for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i]]; var properties = selectionManager.savedProperties[selectionManager.selections[i]];

View file

@ -0,0 +1,98 @@
//
// faceBlendCoefficients.js
//
// version 2.0
//
// Created by Bob Long, 9/14/2015
// A simple panel that can select and display the blending coefficient of the Avatar's face model.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include('utilities/tools/cookies.js')
var panel;
var coeff;
var interval;
var item = 0;
var DEVELOPER_MENU = "Developer";
var AVATAR_MENU = DEVELOPER_MENU + " > Avatar";
var SHOW_FACE_BLEND_COEFFICIENTS = "Show face blend coefficients"
function MenuConnect(menuItem) {
if (menuItem == SHOW_FACE_BLEND_COEFFICIENTS) {
if(Menu.isOptionChecked(SHOW_FACE_BLEND_COEFFICIENTS)) {
panel.show();
Overlays.editOverlay(coeff, { visible : true });
} else {
panel.hide();
Overlays.editOverlay(coeff, { visible : false });
}
}
}
// Add a menu item to show/hide the coefficients
function setupMenu() {
if (!Menu.menuExists(DEVELOPER_MENU)) {
Menu.addMenu(DEVELOPER_MENU);
}
if (!Menu.menuExists(AVATAR_MENU)) {
Menu.addMenu(AVATAR_MENU);
}
Menu.addMenuItem({ menuName: AVATAR_MENU, menuItemName: SHOW_FACE_BLEND_COEFFICIENTS, isCheckable: true, isChecked: true });
Menu.menuItemEvent.connect(MenuConnect);
}
function setupPanel() {
panel = new Panel(10, 400);
// Slider to select which coefficient to display
panel.newSlider("Select Coefficient Index",
0,
100,
function(value) { item = value.toFixed(0); },
function() { return item; },
function(value) { return "index = " + item; }
);
// The raw overlay used to show the actual coefficient value
coeff = Overlays.addOverlay("text", {
x: 10,
y: 420,
width: 300,
height: 50,
color: { red: 255, green: 255, blue: 255 },
alpha: 1.0,
backgroundColor: { red: 127, green: 127, blue: 127 },
backgroundAlpha: 0.5,
topMargin: 15,
leftMargin: 20,
text: "Coefficient: 0.0"
});
// Set up the interval (0.5 sec) to update the coefficient.
interval = Script.setInterval(function() {
Overlays.editOverlay(coeff, { text: "Coefficient: " + MyAvatar.getFaceBlendCoef(item).toFixed(4) });
}, 500);
// Mouse event setup
Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
}
// Clean up
function scriptEnding() {
panel.destroy();
Overlays.deleteOverlay(coeff);
Script.clearInterval(interval);
Menu.removeMenuItem(AVATAR_MENU, SHOW_FACE_BLEND_COEFFICIENTS);
}
setupMenu();
setupPanel();
Script.scriptEnding.connect(scriptEnding);

View file

@ -1,5 +1,6 @@
<html> <html>
<head> <head>
<title>Properties</title>
<link rel="stylesheet" type="text/css" href="style.css"> <link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="css/colpick.css"> <link rel="stylesheet" type="text/css" href="css/colpick.css">
<script src="jquery-2.1.4.min.js"></script> <script src="jquery-2.1.4.min.js"></script>
@ -961,7 +962,7 @@
</div> </div>
<div id="id" class="property"> <div id="id" class="property">
<span class="label" style="float: left; margin-right: 6px"> <span class="label" style="float: left; margin-right: 6px">
<label>ID: <label> <label>ID: </label>
</span> </span>
<div class="value"> <div class="value">
<span id="property-id" class="selectable"></span> <span id="property-id" class="selectable"></span>
@ -970,7 +971,7 @@
<div class="property"> <div class="property">
<span class="label" style="float: left; margin-right: 6px">Name</span> <span class="label" style="float: left; margin-right: 6px">Name</span>
<div class="value" style="overflow: hidden;"> <div class="value" style="overflow: hidden;">
<input type="text" id="property-name"></input> <input type="text" id="property-name">
</div> </div>
</div> </div>
@ -1003,13 +1004,13 @@
<div class="property"> <div class="property">
<div class="label">Href</div> <div class="label">Href</div>
<div class="value"> <div class="value">
<input id="property-hyperlink-href" class="url"></input> <input id="property-hyperlink-href" class="url">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Description</div> <div class="label">Description</div>
<div class="value"> <div class="value">
<input id="property-hyperlink-description" class="url"></input> <input id="property-hyperlink-description" class="url">
</div> </div>
</div> </div>
@ -1021,9 +1022,9 @@
<div class="property"> <div class="property">
<div class="label">Position</div> <div class="label">Position</div>
<div class="value"> <div class="value">
<div class="input-area">X <br><input class="coord" type='number' id="property-pos-x"></input></div> <div class="input-area">X <br><input class="coord" type='number' id="property-pos-x"></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-pos-y"></input></div> <div class="input-area">Y <br><input class="coord" type='number' id="property-pos-y"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-pos-z"></input></div> <div class="input-area">Z <br><input class="coord" type='number' id="property-pos-z"></div>
<div> <div>
<input type="button" id="move-selection-to-grid" value="Selection to Grid"> <input type="button" id="move-selection-to-grid" value="Selection to Grid">
<input type="button" id="move-all-to-grid" value="All to Grid"> <input type="button" id="move-all-to-grid" value="All to Grid">
@ -1034,26 +1035,26 @@
<div class="property"> <div class="property">
<div class="label">Registration</div> <div class="label">Registration</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-reg-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-reg-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-reg-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-reg-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-reg-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-reg-z"></div>
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Dimensions</div> <div class="label">Dimensions</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-dim-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-dim-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-dim-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-dim-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-dim-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-dim-z"></div>
<div> <div>
<input type="button" id="reset-to-natural-dimensions" value="Reset to Natural Dimensions"> <input type="button" id="reset-to-natural-dimensions" value="Reset to Natural Dimensions">
</div> </div>
<div class="input-area"> <div class="input-area">
<input class="" type='number' id="dimension-rescale-pct" value=100></input>% <input class="" type='number' id="dimension-rescale-pct" value=100>%
</div> </div>
<span> <span>
<input type="button" id="dimension-rescale-button" value="Rescale"></input> <input type="button" id="dimension-rescale-button" value="Rescale">
</span> </span>
</div> </div>
</div> </div>
@ -1061,9 +1062,9 @@
<div class="poly-vox-section property"> <div class="poly-vox-section property">
<div class="label">Voxel Volume Size</div> <div class="label">Voxel Volume Size</div>
<div class="value"> <div class="value">
<div class="input-area">X <br> <input class="coord" type='number' id="property-voxel-volume-size-x"></input></div> <div class="input-area">X <br> <input class="coord" type='number' id="property-voxel-volume-size-x"></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div> <div class="input-area">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></input></div> <div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></div>
</div> </div>
<div class="label">Surface Extractor</div> <div class="label">Surface Extractor</div>
@ -1078,26 +1079,26 @@
<div class="label">X-axis Texture URL</div> <div class="label">X-axis Texture URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-x-texture-url" class="url"></input> <input type="text" id="property-x-texture-url" class="url">
</div> </div>
<div class="label">Y-axis Texture URL</div> <div class="label">Y-axis Texture URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-y-texture-url" class="url"></input> <input type="text" id="property-y-texture-url" class="url">
</div> </div>
<div class="label">Z-axis Texture URL</div> <div class="label">Z-axis Texture URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-z-texture-url" class="url"></input> <input type="text" id="property-z-texture-url" class="url">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Rotation</div> <div class="label">Rotation</div>
<div class="value"> <div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-rot-x"></input></div> <div class="input-area">Pitch <input class="coord" type='number' id="property-rot-x"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-rot-y"></input></div> <div class="input-area">Yaw <input class="coord" type='number' id="property-rot-y"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"></input></div> <div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"></div>
</div> </div>
</div> </div>
@ -1109,66 +1110,66 @@
<div class="property"> <div class="property">
<div class="label">Linear Velocity</div> <div class="label">Linear Velocity</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lvel-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-lvel-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lvel-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-lvel-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"></div>
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Linear Damping</div> <div class="label">Linear Damping</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-ldamping"></input> <input class="coord" type='number' id="property-ldamping">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Angular Velocity</div> <div class="label">Angular Velocity</div>
<div class="value"> <div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-avel-x"></input></div> <div class="input-area">Pitch <input class="coord" type='number' id="property-avel-x"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-avel-y"></input></div> <div class="input-area">Yaw <input class="coord" type='number' id="property-avel-y"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></input></div> <div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></div>
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Angular Damping</div> <div class="label">Angular Damping</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-adamping"></input> <input class="coord" type='number' id="property-adamping">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Restitution</div> <div class="label">Restitution</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-restitution"></input> <input class="coord" type='number' id="property-restitution">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Friction</div> <div class="label">Friction</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-friction"></input> <input class="coord" type='number' id="property-friction">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Gravity</div> <div class="label">Gravity</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-grav-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-grav-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-grav-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-grav-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-grav-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-grav-z"></div>
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Acceleration</div> <div class="label">Acceleration</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lacc-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-lacc-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lacc-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-lacc-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lacc-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-lacc-z"></div>
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Density</div> <div class="label">Density</div>
<div> <div>
<input type='number' id="property-density"></input> <input type='number' id="property-density">
</div> </div>
</div> </div>
@ -1176,9 +1177,9 @@
<div class="label">Color</div> <div class="label">Color</div>
<div class="value"> <div class="value">
<div id="property-color" class='color-picker'></div> <div id="property-color" class='color-picker'></div>
<div class="input-area">R <input class="coord" type='number' id="property-color-red"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-color-green"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-color-blue"></div>
</div> </div>
</div> </div>
@ -1190,38 +1191,38 @@
<div class="property"> <div class="property">
<span class="label">Ignore For Collisions</span> <span class="label">Ignore For Collisions</span>
<span class="value"> <span class="value">
<input type='checkbox' id="property-ignore-for-collisions"></input> <input type='checkbox' id="property-ignore-for-collisions">
</span> </span>
</div> </div>
<div class="property"> <div class="property">
<span class="label">Collisions Will Move</span> <span class="label">Collisions Will Move</span>
<span class="value"> <span class="value">
<input type='checkbox' id="property-collisions-will-move"></input> <input type='checkbox' id="property-collisions-will-move">
</span> </span>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Collision Sound URL</div> <div class="label">Collision Sound URL</div>
<div class="value"> <div class="value">
<input id="property-collision-sound-url" class="url"></input> <input id="property-collision-sound-url" class="url">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Lifetime</div> <div class="label">Lifetime</div>
<div class="value"> <div class="value">
<input type='number' id="property-lifetime"></input> <input type='number' id="property-lifetime">
</div> </div>
</div> </div>
<div class="property"> <div class="property">
<div class="label">Script URL <div class="label">Script URL
<input type="hidden" id="property-script-timestamp" class="value"></input> <input type="hidden" id="property-script-timestamp" class="value">
<input type="button" id="reload-script-button" value="Reload"></input> <input type="button" id="reload-script-button" value="Reload">
</div> </div>
<div class="value"> <div class="value">
<input id="property-script-url" class="url"></input> <input id="property-script-url" class="url">
</div> </div>
</div> </div>
@ -1233,14 +1234,14 @@
<div class="model-section property"> <div class="model-section property">
<div class="label">Model URL</div> <div class="label">Model URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-model-url" class="url"></input> <input type="text" id="property-model-url" class="url">
</div> </div>
</div> </div>
<div class="model-section zone-section property"> <div class="model-section zone-section property">
<div class="label">Shape Type</div> <div class="label">Shape Type</div>
<div class="value"> <div class="value">
<select name="SelectShapeType" id="property-shape-type" name="SelectShapeType"> <select name="SelectShapeType" id="property-shape-type">
<option value='none'>none</option> <option value='none'>none</option>
<option value='box'>box</option> <option value='box'>box</option>
<option value='sphere'>sphere</option> <option value='sphere'>sphere</option>
@ -1251,13 +1252,13 @@
<div class="model-section zone-section property"> <div class="model-section zone-section property">
<div class="label">Compound Shape URL</div> <div class="label">Compound Shape URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-compound-shape-url" class="url"></input> <input type="text" id="property-compound-shape-url" class="url">
</div> </div>
</div> </div>
<div class="model-section property"> <div class="model-section property">
<div class="label">Animation URL</div> <div class="label">Animation URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-model-animation-url" class="url"></input> <input type="text" id="property-model-animation-url" class="url">
</div> </div>
</div> </div>
<div class="model-section property"> <div class="model-section property">
@ -1269,13 +1270,13 @@
<div class="model-section property"> <div class="model-section property">
<div class="label">Animation FPS</div> <div class="label">Animation FPS</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-model-animation-fps"></input> <input class="coord" type='number' id="property-model-animation-fps">
</div> </div>
</div> </div>
<div class="model-section property"> <div class="model-section property">
<div class="label">Animation Frame</div> <div class="label">Animation Frame</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-model-animation-frame"></input> <input class="coord" type='number' id="property-model-animation-frame">
</div> </div>
</div> </div>
<div class="model-section property"> <div class="model-section property">
@ -1305,7 +1306,7 @@
<div class="web-section property"> <div class="web-section property">
<div class="label">Source URL</div> <div class="label">Source URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-web-source-url" class="url"></input> <input type="text" id="property-web-source-url" class="url">
</div> </div>
</div> </div>
@ -1317,45 +1318,45 @@
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Max Particles</div> <div class="label">Max Particles</div>
<div class="value"> <div class="value">
<input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1"></input> <input type='number' id="property-particle-maxparticles" min="0" max="2048" step="1">
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Life Span</div> <div class="label">Particle Life Span</div>
<div class="value"> <div class="value">
<input type='number' id="property-particle-lifespan" min="0" step="0.1"></input> <input type='number' id="property-particle-lifespan" min="0" step="0.1">
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Emission Rate</div> <div class="label">Particle Emission Rate</div>
<div class="value"> <div class="value">
<input type='number' id="property-particle-emit-rate" min="0" step="0.5"></input> <input type='number' id="property-particle-emit-rate" min="0" step="0.5">
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Emission Direction</div> <div class="label">Particle Emission Direction</div>
<div class="value"> <div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-particle-emit-direction-x"></input></div> <div class="input-area">X <input class="coord" type='number' id="property-particle-emit-direction-x"></div>
<div class="input-area">Y <input class="coord" type='number' id="property-particle-emit-direction-y"></input></div> <div class="input-area">Y <input class="coord" type='number' id="property-particle-emit-direction-y"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></input></div> <div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></div>
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Emission Strength</div> <div class="label">Particle Emission Strength</div>
<div class="value"> <div class="value">
<input type='number' id="property-particle-emit-strength" min="0" step="0.1"></input> <input type='number' id="property-particle-emit-strength" min="0" step="0.1">
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Local Gravity</div> <div class="label">Particle Local Gravity</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-particle-localgravity" step="0.05"></input> <input class="coord" type='number' id="property-particle-localgravity" step="0.05">
</div> </div>
</div> </div>
<div class="particle-section property"> <div class="particle-section property">
<div class="label">Particle Radius</div> <div class="label">Particle Radius</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-particle-radius" min="0" step="0.005"></input> <input class="coord" type='number' id="property-particle-radius" min="0" step="0.005">
</div> </div>
</div> </div>
@ -1367,31 +1368,31 @@
<div class="text-section property"> <div class="text-section property">
<div class="label">Text Content</div> <div class="label">Text Content</div>
<div class="value"> <div class="value">
<input type="text" id="property-text-text"></input> <input type="text" id="property-text-text">
</div> </div>
</div> </div>
<div class="text-section property"> <div class="text-section property">
<div class="label">Line Height</div> <div class="label">Line Height</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-text-line-height" min="0" step="0.005"></input> <input class="coord" type='number' id="property-text-line-height" min="0" step="0.005">
</div> </div>
</div> </div>
<div class="text-section property"> <div class="text-section property">
<div class="label">Text Color</div> <div class="label">Text Color</div>
<div class="value"> <div class="value">
<div class='color-picker' id="property-text-text-color"></div> <div class='color-picker' id="property-text-text-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-text-text-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-text-text-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
</div> </div>
</div> </div>
<div class="text-section property"> <div class="text-section property">
<div class="label">Background Color</div> <div class="label">Background Color</div>
<div class="value"> <div class="value">
<div class='color-picker' id="property-text-background-color"></div> <div class='color-picker' id="property-text-background-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-text-background-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-text-background-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
</div> </div>
</div> </div>
@ -1410,27 +1411,27 @@
<div class="label">Color</div> <div class="label">Color</div>
<div class="value"> <div class="value">
<div class='color-picker' id="property-light-color"></div> <div class='color-picker' id="property-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-light-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-light-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></div>
</div> </div>
</div> </div>
<div class="light-section property"> <div class="light-section property">
<div class="label">Intensity</div> <div class="label">Intensity</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-light-intensity"></input> <input class="coord" type='number' id="property-light-intensity">
</div> </div>
</div> </div>
<div class="light-section property"> <div class="light-section property">
<div class="label">Spot Light Exponent</div> <div class="label">Spot Light Exponent</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-light-exponent"></input> <input class="coord" type='number' id="property-light-exponent">
</div> </div>
</div> </div>
<div class="light-section property"> <div class="light-section property">
<div class="label">Spot Light Cutoff (degrees)</div> <div class="label">Spot Light Cutoff (degrees)</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-light-cutoff"></input> <input class="coord" type='number' id="property-light-cutoff">
</div> </div>
</div> </div>
@ -1450,48 +1451,48 @@
<div class="label">Key Light Color</div> <div class="label">Key Light Color</div>
<div class="value"> <div class="value">
<div class='color-picker' id="property-zone-key-light-color"></div> <div class='color-picker' id="property-zone-key-light-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></div>
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Key Light Intensity</div> <div class="label">Key Light Intensity</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1"></input> <input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Key Light Ambient Intensity</div> <div class="label">Key Light Ambient Intensity</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1"></input> <input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Key Light Direction</div> <div class="label">Key Light Direction</div>
<div class="value"> <div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></input></div> <div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></input></div> <div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></input></div> <div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></div>
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Stage Latitude</div> <div class="label">Stage Latitude</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1"></input> <input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Stage Longitude</div> <div class="label">Stage Longitude</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1"></input> <input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Stage Altitude</div> <div class="label">Stage Altitude</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-stage-altitude" step="1"></input> <input class="coord" type='number' id="property-zone-stage-altitude" step="1">
</div> </div>
</div> </div>
@ -1505,20 +1506,20 @@
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Stage Day</div> <div class="label">Stage Day</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1"></input> <input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Stage Hour</div> <div class="label">Stage Hour</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5"></input> <input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5">
</div> </div>
</div> </div>
<div class="zone-section property"> <div class="zone-section property">
<div class="label">Background Mode</div> <div class="label">Background Mode</div>
<div class="value"> <div class="value">
<select name="SelectBackgroundMode" id="property-zone-background-mode" name="SelectBackgroundMode"> <select name="SelectBackgroundMode" id="property-zone-background-mode">
<option value='inherit'>Nothing</option> <option value='inherit'>Nothing</option>
<option value='skybox'>Skybox</option> <option value='skybox'>Skybox</option>
<option value='atmosphere'>Atmosphere</option> <option value='atmosphere'>Atmosphere</option>
@ -1535,15 +1536,15 @@
<div class="label">Skybox Color</div> <div class="label">Skybox Color</div>
<div class="value"> <div class="value">
<div class='color-picker' id="property-zone-skybox-color"></div> <div class='color-picker' id="property-zone-skybox-color"></div>
<div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></input></div> <div class="input-area">R <input class="coord" type='number' id="property-zone-skybox-color-red"></div>
<div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></input></div> <div class="input-area">G <input class="coord" type='number' id="property-zone-skybox-color-green"></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></input></div> <div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
</div> </div>
</div> </div>
<div class="zone-section skybox-section property"> <div class="zone-section skybox-section property">
<div class="label">Skybox URL</div> <div class="label">Skybox URL</div>
<div class="value"> <div class="value">
<input type="text" id="property-zone-skybox-url" class="url"></input> <input type="text" id="property-zone-skybox-url" class="url">
</div> </div>
</div> </div>
@ -1555,9 +1556,9 @@
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Center</div> <div class="label">Atmosphere Center</div>
<div class="value"> <div class="value">
<div class="input-area">X <br><input class="coord" type='number' id="property-zone-atmosphere-center-x"></input></div> <div class="input-area">X <br><input class="coord" type='number' id="property-zone-atmosphere-center-x"></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-zone-atmosphere-center-y"></input></div> <div class="input-area">Y <br><input class="coord" type='number' id="property-zone-atmosphere-center-y"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-zone-atmosphere-center-z"></input></div> <div class="input-area">Z <br><input class="coord" type='number' id="property-zone-atmosphere-center-z"></div>
<div> <div>
<input type="button" id="center-atmosphere-in-zone" value="Center to Zone"> <input type="button" id="center-atmosphere-in-zone" value="Center to Zone">
</div> </div>
@ -1566,33 +1567,33 @@
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Inner Radius</div> <div class="label">Atmosphere Inner Radius</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-atmosphere-inner-radius" step="1"></input> <input class="coord" type='number' id="property-zone-atmosphere-inner-radius" step="1">
</div> </div>
</div> </div>
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Outer Radius</div> <div class="label">Atmosphere Outer Radius</div>
<div class="value"> <div class="value">
<input class="coord" type='number' id="property-zone-atmosphere-outer-radius" step="1"></input> <input class="coord" type='number' id="property-zone-atmosphere-outer-radius" step="1">
</div> </div>
</div> </div>
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Mie Scattering</div> <div class="label">Atmosphere Mie Scattering</div>
<div class="value"> <div class="value">
<input class="coord no-spin" type='number' id="property-zone-atmosphere-mie-scattering" min="0" max="0.5" step="any"></input> <input class="coord no-spin" type='number' id="property-zone-atmosphere-mie-scattering" min="0" max="0.5" step="any">
</div> </div>
</div> </div>
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Rayleigh Scattering</div> <div class="label">Atmosphere Rayleigh Scattering</div>
<div class="value"> <div class="value">
<input class="coord no-spin" type='number' id="property-zone-atmosphere-rayleigh-scattering" min="0" max="0.5" step="any"></input> <input class="coord no-spin" type='number' id="property-zone-atmosphere-rayleigh-scattering" min="0" max="0.5" step="any">
</div> </div>
</div> </div>
<div class="zone-section atmosphere-section property"> <div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Scattering Wavelenghts</div> <div class="label">Atmosphere Scattering Wavelenghts</div>
<div class="value"> <div class="value">
<div class="input-area">X <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-x" min="0" max="1" step="any"></input></div> <div class="input-area">X <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-x" min="0" max="1" step="any"></div>
<div class="input-area">Y <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-y" min="0" max="1" step="any"></input></div> <div class="input-area">Y <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-y" min="0" max="1" step="any"></div>
<div class="input-area">Z <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-z" min="0" max="1" step="any"></input></div> <div class="input-area">Z <br><input class="coord no-spin" type='number' id="property-zone-atmosphere-scattering-wavelengths-z" min="0" max="1" step="any"></div>
</div> </div>
</div> </div>
<div class="zone-section atmosphere-section property" style="display:none"> <div class="zone-section atmosphere-section property" style="display:none">

View file

@ -1,54 +0,0 @@
// bubble.js
// part of bubblewand
//
// Created by James B. Pollack @imgntn -- 09/03/2015
// Copyright 2015 High Fidelity, Inc.
//
// example of a nested entity. it doesn't do much now besides delete itself if it collides with something (bubbles are fragile! it would be cool if it sometimes merged with other bubbbles it hit)
// todo: play bubble sounds from the bubble itself instead of the wand.
// blocker: needs some sound fixes and a way to find its own position before unload for spatialization
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
(function() {
// Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
// Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
//var popSound;
this.preload = function(entityID) {
// print('bubble preload')
this.entityID = entityID;
// popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
}
this.collisionWithEntity = function(myID, otherID, collision) {
//if(Entites.getEntityProperties(otherID).userData.objectType==='') { merge bubbles?}
// Entities.deleteEntity(myID);
// this.burstBubbleSound(collision.contactPoint)
};
this.unload = function(entityID) {
// this.properties = Entities.getEntityProperties(entityID);
//var location = this.properties.position;
//this.burstBubbleSound();
};
this.burstBubbleSound = function(location) {
// var audioOptions = {
// volume: 0.5,
// position: location
// }
//Audio.playSound(popSound, audioOptions);
}
})

View file

@ -1,42 +1,43 @@
// createWand.js // createWand.js
// part of bubblewand // part of bubblewand
// //
// Script Type: Entity Spawner
// Created by James B. Pollack @imgntn -- 09/03/2015 // Created by James B. Pollack @imgntn -- 09/03/2015
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// Loads a wand model and attaches the bubble wand behavior. // Loads a wand model and attaches the bubble wand behavior.
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
Script.include("../../utilities.js");
Script.include("../../libraries/utils.js");
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx';
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/collisionHull.obj';
var WAND_SCRIPT_URL = Script.resolvePath("wand.js");
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js"); //create the wand in front of the avatar
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
var wandModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx?" + randInt(0, 10000); var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
var scriptURL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/wand.js?" + randInt(1, 100500)
//create the wand in front of the avatar
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
var wand = Entities.addEntity({ var wand = Entities.addEntity({
type: "Model", name: 'Bubble Wand',
modelURL: wandModel, type: "Model",
position: center, modelURL: WAND_MODEL,
dimensions: { position: center,
x: 0.1, gravity: {
y: 1, x: 0,
z: 0.1 y: 0,
}, z: 0,
//must be enabled to be grabbable in the physics engine },
collisionsWillMove: true, dimensions: {
shapeType: 'box', x: 0.05,
script: scriptURL y: 0.25,
}); z: 0.05
},
function cleanup() { //must be enabled to be grabbable in the physics engine
Entities.deleteEntity(wand); collisionsWillMove: true,
} compoundShapeURL: WAND_COLLISION_SHAPE,
script: WAND_SCRIPT_URL
});
Script.scriptEnding.connect(cleanup);

View file

@ -1,317 +1,203 @@
// wand.js // wand.js
// part of bubblewand // part of bubblewand
// //
// Script Type: Entity Script
// Created by James B. Pollack @imgntn -- 09/03/2015 // Created by James B. Pollack @imgntn -- 09/03/2015
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// Makes bubbles when you wave the object around, or hold it near your mouth and make noise into the microphone. // Makes bubbles when you wave the object around.
// //
// For the example, it's attached to a wand -- but you can attach it to whatever entity you want. I dream of BubbleBees :) bzzzz...pop!
//
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
function convertRange(value, r1, r2) { /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
return (value - r1[0]) * (r2[1] - r2[0]) / (r1[1] - r1[0]) + r2[0];
}
(function() { (function () {
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
var bubbleModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx"; Script.include("../../utilities.js");
var bubbleScript = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/bubble.js?' + randInt(1, 10000); Script.include("../../libraries/utils.js");
var popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
var TARGET_SIZE = 0.4; var BUBBLE_MODEL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
var TARGET_COLOR = {
red: 128, var BUBBLE_INITIAL_DIMENSIONS = {
green: 128, x: 0.01,
blue: 128 y: 0.01,
}; z: 0.01
var TARGET_COLOR_HIT = {
red: 0,
green: 255,
blue: 0
}; };
var HAND_SIZE = 0.25; var BUBBLE_LIFETIME_MIN = 3;
var leftCubePosition = MyAvatar.getLeftPalmPosition(); var BUBBLE_LIFETIME_MAX = 8;
var rightCubePosition = MyAvatar.getRightPalmPosition(); var BUBBLE_SIZE_MIN = 0.02;
var BUBBLE_SIZE_MAX = 0.1;
var BUBBLE_LINEAR_DAMPING = 0.4;
var BUBBLE_GRAVITY_MIN = 0.1;
var BUBBLE_GRAVITY_MAX = 0.3;
var GROWTH_FACTOR = 0.005;
var SHRINK_FACTOR = 0.001;
var SHRINK_LOWER_LIMIT = 0.02;
var WAND_TIP_OFFSET = 0.095;
var VELOCITY_THRESHOLD = 0.5;
var leftHand = Overlays.addOverlay("cube", { //this helps us get the time passed since the last function call, for use in velocity calculations
position: leftCubePosition, function interval() {
size: HAND_SIZE, var lastTime = new Date().getTime() / 1000;
color: {
red: 0,
green: 0,
blue: 255
},
alpha: 1,
solid: false
});
var rightHand = Overlays.addOverlay("cube", { return function getInterval() {
position: rightCubePosition, var newTime = new Date().getTime() / 1000;
size: HAND_SIZE, var delta = newTime - lastTime;
color: { lastTime = newTime;
red: 255, return delta;
green: 0, };
blue: 0
},
alpha: 1,
solid: false
});
var gustZoneOverlay = Overlays.addOverlay("cube", {
position: getGustDetectorPosition(),
size: TARGET_SIZE,
color: TARGET_COLOR,
alpha: 1,
solid: false
});
function getGustDetectorPosition() {
//put the zone in front of your avatar's face
var DISTANCE_IN_FRONT = 0.2;
var DISTANCE_UP = 0.5;
var DISTANCE_TO_SIDE = 0.0;
var up = Quat.getUp(MyAvatar.orientation);
var front = Quat.getFront(MyAvatar.orientation);
var right = Quat.getRight(MyAvatar.orientation);
var upOffset = Vec3.multiply(up, DISTANCE_UP);
var rightOffset = Vec3.multiply(right, DISTANCE_TO_SIDE);
var frontOffset = Vec3.multiply(front, DISTANCE_IN_FRONT);
var offset = Vec3.sum(Vec3.sum(rightOffset, frontOffset), upOffset);
var position = Vec3.sum(MyAvatar.position, offset);
return position;
} }
var checkInterval = interval();
var BUBBLE_GRAVITY = { function BubbleWand() {
x: 0, return;
y: -0.05,
z: 0
} }
BubbleWand.prototype = {
var wandEntity = this; timePassed: null,
this.preload = function(entityID) {
// print('PRELOAD')
this.entityID = entityID;
this.properties = Entities.getEntityProperties(this.entityID);
}
this.unload = function(entityID) {
Overlays.deleteOverlay(leftHand);
Overlays.deleteOverlay(rightHand);
Overlays.deleteOverlay(gustZoneOverlay)
Entities.editEntity(entityID, {
name: ""
});
Script.update.disconnect(BubbleWand.update);
Entities.deleteEntity(BubbleWand.currentBubble);
while (BubbleWand.bubbles.length > 0) {
Entities.deleteEntity(BubbleWand.bubbles.pop());
}
};
var BubbleWand = {
bubbles: [],
currentBubble: null, currentBubble: null,
update: function() { preload: function (entityID) {
BubbleWand.internalUpdate(); this.entityID = entityID;
}, },
internalUpdate: function() { getWandTipPosition: function (properties) {
var _t = this; //the tip of the wand is going to be in a different place than the center, so we move in space relative to the model to find that position
//get the current position of the wand var upVector = Quat.getUp(properties.rotation);
var properties = Entities.getEntityProperties(wandEntity.entityID); var upOffset = Vec3.multiply(upVector, WAND_TIP_OFFSET);
var wandTipPosition = Vec3.sum(properties.position, upOffset);
return wandTipPosition;
},
addCollisionsToBubbleAfterCreation: function (bubble) {
//if the bubble collide immediately, we get weird effects. so we add collisions after release
Entities.editEntity(bubble, {
collisionsWillMove: true
});
},
randomizeBubbleGravity: function () {
//change up the gravity a little bit for variation in floating effects
var randomNumber = randFloat(BUBBLE_GRAVITY_MIN, BUBBLE_GRAVITY_MAX);
var gravity = {
x: 0,
y: -randomNumber,
z: 0
};
return gravity;
},
growBubbleWithWandVelocity: function (properties, deltaTime) {
//get the wand and tip position for calculations
var wandPosition = properties.position; var wandPosition = properties.position;
this.getWandTipPosition(properties);
// velocity = change in position / time
var velocity = Vec3.multiply(Vec3.subtract(wandPosition, this.lastPosition), 1 / deltaTime);
//debug overlays for mouth mode
var leftHandPos = MyAvatar.getLeftPalmPosition();
var rightHandPos = MyAvatar.getRightPalmPosition();
Overlays.editOverlay(leftHand, { var velocityStrength = Vec3.length(velocity);
position: leftHandPos
});
Overlays.editOverlay(rightHand, {
position: rightHandPos
});
//if the wand is in the gust detector, activate mouth mode and change the overlay color
var hitTargetWithWand = findSphereSphereHit(wandPosition, HAND_SIZE / 2, getGustDetectorPosition(), TARGET_SIZE / 2)
var mouthMode;
if (hitTargetWithWand) {
Overlays.editOverlay(gustZoneOverlay, {
position: getGustDetectorPosition(),
color: TARGET_COLOR_HIT
})
mouthMode = true;
} else {
Overlays.editOverlay(gustZoneOverlay, {
position: getGustDetectorPosition(),
color: TARGET_COLOR
})
mouthMode = false;
}
var volumeLevel = MyAvatar.audioAverageLoudness;
//volume numbers are pretty large, so lets scale them down.
var convertedVolume = convertRange(volumeLevel, [0, 5000], [0, 10]);
// default is 'wave mode', where waving the object around grows the bubbles
var velocity = Vec3.subtract(wandPosition, BubbleWand.lastPosition)
//store the last position of the wand for velocity calculations //store the last position of the wand for velocity calculations
_t.lastPosition = wandPosition; this.lastPosition = wandPosition;
// velocity numbers are pretty small, so lets make them a bit bigger
var velocityStrength = Vec3.length(velocity) * 100;
if (velocityStrength > 10) {
velocityStrength = 10
}
//actually grow the bubble //actually grow the bubble
var dimensions = Entities.getEntityProperties(_t.currentBubble).dimensions; var dimensions = Entities.getEntityProperties(this.currentBubble, "dimensions").dimensions;
if (velocityStrength > 1 || convertedVolume > 1) {
if (velocityStrength > VELOCITY_THRESHOLD) {
//add some variation in bubble sizes //add some variation in bubble sizes
var bubbleSize = randInt(1, 5); var bubbleSize = randFloat(BUBBLE_SIZE_MIN, BUBBLE_SIZE_MAX);
bubbleSize = bubbleSize / 10;
//release the bubble if its dimensions are bigger than the bubble size //release the bubble if its dimensions are bigger than the bubble size
if (dimensions.x > bubbleSize) { if (dimensions.x > bubbleSize) {
//bubbles pop after existing for a bit -- so set a random lifetime //bubbles pop after existing for a bit -- so set a random lifetime
var lifetime = randInt(3, 8); var lifetime = randInt(BUBBLE_LIFETIME_MIN, BUBBLE_LIFETIME_MAX);
//sound is somewhat unstable at the moment so this is commented out. really audio should be played by the bubbles, but there's a blocker. //edit the bubble properties at release
// Script.setTimeout(function() { Entities.editEntity(this.currentBubble, {
// _t.burstBubbleSound(_t.currentBubble) velocity: velocity,
// }, lifetime * 1000) lifetime: lifetime,
gravity: this.randomizeBubbleGravity()
//todo: angular velocity without the controller -- forward velocity for mouth mode bubbles
// var angularVelocity = Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip);
Entities.editEntity(_t.currentBubble, {
velocity: Vec3.normalize(velocity),
// angularVelocity: Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip),
lifetime: lifetime
}); });
//wait to make the bubbles collidable, so that they dont hit each other and the wand
Script.setTimeout(this.addCollisionsToBubbleAfterCreation(this.currentBubble), lifetime / 2);
//release the bubble -- when we create a new bubble, it will carry on and this update loop will affect the new bubble //release the bubble -- when we create a new bubble, it will carry on and this update loop will affect the new bubble
BubbleWand.spawnBubble(); this.createBubbleAtTipOfWand();
return;
return
} else { } else {
if (mouthMode) { //grow small bubbles
dimensions.x += 0.015 * convertedVolume; dimensions.x += GROWTH_FACTOR * velocityStrength;
dimensions.y += 0.015 * convertedVolume; dimensions.y += GROWTH_FACTOR * velocityStrength;
dimensions.z += 0.015 * convertedVolume; dimensions.z += GROWTH_FACTOR * velocityStrength;
} else {
dimensions.x += 0.015 * velocityStrength;
dimensions.y += 0.015 * velocityStrength;
dimensions.z += 0.015 * velocityStrength;
}
} }
} else { } else {
if (dimensions.x >= 0.02) { // if the wand is not moving, make the current bubble smaller
dimensions.x -= 0.001; if (dimensions.x >= SHRINK_LOWER_LIMIT) {
dimensions.y -= 0.001; dimensions.x -= SHRINK_FACTOR;
dimensions.z -= 0.001; dimensions.y -= SHRINK_FACTOR;
dimensions.z -= SHRINK_FACTOR;
} }
} }
//update the bubble to stay with the wand tip //adjust the bubble dimensions
Entities.editEntity(_t.currentBubble, { Entities.editEntity(this.currentBubble, {
position: _t.wandTipPosition,
dimensions: dimensions dimensions: dimensions
}); });
}, },
burstBubbleSound: function(bubble) { createBubbleAtTipOfWand: function () {
//we want to play the sound at the same location and orientation as the bubble
var position = Entities.getEntityProperties(bubble).position;
var orientation = Entities.getEntityProperties(bubble).orientation;
//set the options for the audio injector
var audioOptions = {
volume: 0.5,
position: position,
orientation: orientation
}
//var audioInjector = Audio.playSound(popSound, audioOptions);
//remove this bubble from the array to keep things clean
var i = BubbleWand.bubbles.indexOf(bubble);
if (i != -1) {
BubbleWand.bubbles.splice(i, 1);
}
},
spawnBubble: function() {
var _t = this;
//create a new bubble at the tip of the wand //create a new bubble at the tip of the wand
//the tip of the wand is going to be in a different place than the center, so we move in space relative to the model to find that position var properties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
var properties = Entities.getEntityProperties(wandEntity.entityID);
var wandPosition = properties.position; var wandPosition = properties.position;
var upVector = Quat.getUp(properties.rotation);
var frontVector = Quat.getFront(properties.rotation);
var upOffset = Vec3.multiply(upVector, 0.5);
var forwardOffset = Vec3.multiply(frontVector, 0.1);
var offsetVector = Vec3.sum(upOffset, forwardOffset);
var wandTipPosition = Vec3.sum(wandPosition, offsetVector);
_t.wandTipPosition = wandTipPosition;
//store the position of the tip on spawn for use in velocity calculations //store the position of the tip for use in velocity calculations
_t.lastPosition = wandTipPosition; this.lastPosition = wandPosition;
//create a bubble at the wand tip //create a bubble at the wand tip
_t.currentBubble = Entities.addEntity({ this.currentBubble = Entities.addEntity({
name: 'Bubble',
type: 'Model', type: 'Model',
modelURL: bubbleModel, modelURL: BUBBLE_MODEL,
position: wandTipPosition, position: this.getWandTipPosition(properties),
dimensions: { dimensions: BUBBLE_INITIAL_DIMENSIONS,
x: 0.01,
y: 0.01,
z: 0.01
},
collisionsWillMove: false, collisionsWillMove: false,
ignoreForCollisions: true, ignoreForCollisions: false,
gravity: BUBBLE_GRAVITY, linearDamping: BUBBLE_LINEAR_DAMPING,
// collisionSoundURL:popSound, shapeType: "sphere"
shapeType: "sphere",
script: bubbleScript,
}); });
//add this bubble to an array of bubbles so we can keep track of them },
_t.bubbles.push(_t.currentBubble) startNearGrab: function () {
//create a bubble to grow at the start of the grab
if (this.currentBubble === null) {
this.createBubbleAtTipOfWand();
}
},
continueNearGrab: function () {
var deltaTime = checkInterval();
//only get the properties that we need
var properties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
var wandTipPosition = this.getWandTipPosition(properties);
//update the bubble to stay with the wand tip
Entities.editEntity(this.currentBubble, {
position: wandTipPosition,
});
this.growBubbleWithWandVelocity(properties, deltaTime);
}, },
init: function() { releaseGrab: function () {
this.spawnBubble(); //delete the current buble and reset state when the wand is released
Script.update.connect(BubbleWand.update); Entities.deleteEntity(this.currentBubble);
} this.currentBubble = null;
} },
BubbleWand.init(); };
}) return new BubbleWand();
});

View file

@ -605,7 +605,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_overlays.init(); // do this before scripts load _overlays.init(); // do this before scripts load
_runningScriptsWidget->setRunningScripts(getRunningScripts()); _runningScriptsWidget->setRunningScripts(getRunningScripts());
connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts()));
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit())); connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
@ -2615,20 +2614,19 @@ void Application::updateMyAvatarLookAtPosition() {
bool isLookingAtSomeone = false; bool isLookingAtSomeone = false;
bool isHMD = _avatarUpdate->isHMDMode(); bool isHMD = _avatarUpdate->isHMDMode();
glm::vec3 lookAtSpot; glm::vec3 lookAtSpot;
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) {
// When I am in mirror mode, just look right at the camera (myself); don't switch gaze points because when physically
// looking in a mirror one's eyes appear steady.
lookAtSpot = _myCamera.getPosition();
} else if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) {
// Look at the point that the user is looking at. // Look at the point that the user is looking at.
glm::vec3 lookAtPosition = eyeTracker->getLookAtPosition();
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
lookAtPosition.x = -lookAtPosition.x;
}
if (isHMD) { if (isHMD) {
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
glm::quat hmdRotation = glm::quat_cast(headPose); glm::quat hmdRotation = glm::quat_cast(headPose);
lookAtSpot = _myCamera.getPosition() + lookAtSpot = _myCamera.getPosition() + _myAvatar->getOrientation() * (hmdRotation * lookAtPosition);
_myAvatar->getOrientation() * (hmdRotation * eyeTracker->getLookAtPosition());
} else { } else {
lookAtSpot = _myAvatar->getHead()->getEyePosition() + lookAtSpot = _myAvatar->getHead()->getEyePosition()
(_myAvatar->getHead()->getFinalOrientationInWorldFrame() * eyeTracker->getLookAtPosition()); + (_myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition);
} }
} else { } else {
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().lock(); AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().lock();
@ -4332,17 +4330,18 @@ void Application::stopAllScripts(bool restart) {
_myAvatar->clearScriptableSettings(); _myAvatar->clearScriptableSettings();
} }
void Application::stopScript(const QString &scriptName, bool restart) { bool Application::stopScript(const QString& scriptHash, bool restart) {
const QString& scriptURLString = QUrl(scriptName).toString(); bool stoppedScript = false;
if (_scriptEnginesHash.contains(scriptURLString)) { if (_scriptEnginesHash.contains(scriptHash)) {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString]; ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash];
if (restart) { if (restart) {
auto scriptCache = DependencyManager::get<ScriptCache>(); auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(scriptName); scriptCache->deleteScript(QUrl(scriptHash));
connect(scriptEngine, SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&))); connect(scriptEngine, SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&)));
} }
scriptEngine->stop(); scriptEngine->stop();
qCDebug(interfaceapp) << "stopping script..." << scriptName; stoppedScript = true;
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
// HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities // HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities
// whenever a script stops in case it happened to have been setting joint rotations. // whenever a script stops in case it happened to have been setting joint rotations.
// TODO: expose animation priorities and provide a layered animation control system. // TODO: expose animation priorities and provide a layered animation control system.
@ -4351,6 +4350,7 @@ void Application::stopScript(const QString &scriptName, bool restart) {
if (_scriptEnginesHash.empty()) { if (_scriptEnginesHash.empty()) {
_myAvatar->clearScriptableSettings(); _myAvatar->clearScriptableSettings();
} }
return stoppedScript;
} }
void Application::reloadAllScripts() { void Application::reloadAllScripts() {

View file

@ -292,7 +292,7 @@ public:
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); } QStringList getRunningScripts() { return _scriptEnginesHash.keys(); }
ScriptEngine* getScriptEngine(QString scriptHash) { return _scriptEnginesHash.contains(scriptHash) ? _scriptEnginesHash[scriptHash] : NULL; } ScriptEngine* getScriptEngine(const QString& scriptHash) { return _scriptEnginesHash.value(scriptHash, NULL); }
bool isLookingAtMyAvatar(AvatarSharedPointer avatar); bool isLookingAtMyAvatar(AvatarSharedPointer avatar);
@ -392,7 +392,7 @@ public slots:
void reloadScript(const QString& scriptName, bool isUserLoaded = true); void reloadScript(const QString& scriptName, bool isUserLoaded = true);
void scriptFinished(const QString& scriptName); void scriptFinished(const QString& scriptName);
void stopAllScripts(bool restart = false); void stopAllScripts(bool restart = false);
void stopScript(const QString& scriptName, bool restart = false); bool stopScript(const QString& scriptHash, bool restart = false);
void reloadAllScripts(); void reloadAllScripts();
void reloadOneScript(const QString& scriptName); void reloadOneScript(const QString& scriptName);
void loadDefaultScripts(); void loadDefaultScripts();

View file

@ -51,7 +51,6 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
const glm::vec3 greenColor(0.0f, 1.0f, 0.0f); // Color the hand targets red to be different than skin const glm::vec3 greenColor(0.0f, 1.0f, 0.0f); // Color the hand targets red to be different than skin
const glm::vec3 blueColor(0.0f, 0.0f, 1.0f); // Color the hand targets red to be different than skin const glm::vec3 blueColor(0.0f, 0.0f, 1.0f); // Color the hand targets red to be different than skin
const glm::vec3 grayColor(0.5f); const glm::vec3 grayColor(0.5f);
const int NUM_FACETS = 8;
const float SPHERE_RADIUS = 0.03f * avatarScale; const float SPHERE_RADIUS = 0.03f * avatarScale;
gpu::Batch& batch = *renderArgs->_batch; gpu::Batch& batch = *renderArgs->_batch;

View file

@ -110,6 +110,8 @@ public:
Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); } Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); }
Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); } Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); }
Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); } Q_INVOKABLE float getHeadDeltaPitch() const { return getHead()->getDeltaPitch(); }
Q_INVOKABLE int getFaceBlendCoefNum() const { return getHead()->getFaceModel().getBlendshapeCoefficientsNum(); }
Q_INVOKABLE float getFaceBlendCoef(int index) const { return getHead()->getFaceModel().getBlendshapeCoefficient(index); }
Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); } Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); }

View file

@ -635,8 +635,6 @@ void SkeletonModel::computeBoundingShape() {
} }
void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) {
const int BALL_SUBDIVISIONS = 10;
auto geometryCache = DependencyManager::get<GeometryCache>(); auto geometryCache = DependencyManager::get<GeometryCache>();
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
// draw a blue sphere at the capsule top point // draw a blue sphere at the capsule top point

View file

@ -425,6 +425,7 @@ bool ConnexionClient::InitializeRawInput(HWND hwndTarget) {
return false; return false;
} }
// FIXME - http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe
// Get OS version. // Get OS version.
OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO), 0 }; OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO), 0 };
::GetVersionEx(&osvi); ::GetVersionEx(&osvi);

View file

@ -57,16 +57,15 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter); connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter);
connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList); connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList);
connect(ui->reloadAllButton, &QPushButton::clicked, connect(ui->reloadAllButton, &QPushButton::clicked, Application::getInstance(), &Application::reloadAllScripts);
Application::getInstance(), &Application::reloadAllScripts); connect(ui->stopAllButton, &QPushButton::clicked, this, &RunningScriptsWidget::allScriptsStopped);
connect(ui->stopAllButton, &QPushButton::clicked, connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, Application::getInstance(), &Application::loadDialog);
this, &RunningScriptsWidget::allScriptsStopped); connect(ui->loadScriptFromURLButton, &QPushButton::clicked, Application::getInstance(), &Application::loadScriptURLDialog);
connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, connect(&_reloadSignalMapper, static_cast<void(QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped),
Application::getInstance(), &Application::loadDialog); Application::getInstance(), &Application::reloadOneScript);
connect(ui->loadScriptFromURLButton, &QPushButton::clicked,
Application::getInstance(), &Application::loadScriptURLDialog); connect(&_stopSignalMapper, static_cast<void(QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped),
connect(&_reloadSignalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(reloadOneScript(const QString&))); [](const QString& script) { Application::getInstance()->stopScript(script); });
connect(&_stopSignalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&)));
UIUtil::scaleWidgetFontSizes(this); UIUtil::scaleWidgetFontSizes(this);
} }
@ -217,9 +216,6 @@ void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) {
} }
} }
void RunningScriptsWidget::scriptStopped(const QString& scriptName) {
}
void RunningScriptsWidget::allScriptsStopped() { void RunningScriptsWidget::allScriptsStopped() {
Application::getInstance()->stopAllScripts(); Application::getInstance()->stopAllScripts();
} }
@ -227,15 +223,16 @@ void RunningScriptsWidget::allScriptsStopped() {
QVariantList RunningScriptsWidget::getRunning() { QVariantList RunningScriptsWidget::getRunning() {
const int WINDOWS_DRIVE_LETTER_SIZE = 1; const int WINDOWS_DRIVE_LETTER_SIZE = 1;
QVariantList result; QVariantList result;
QStringList runningScripts = Application::getInstance()->getRunningScripts(); foreach(const QString& runningScript, Application::getInstance()->getRunningScripts()) {
for (int i = 0; i < runningScripts.size(); i++) { QUrl runningScriptURL = QUrl(runningScript);
QUrl runningScriptURL = QUrl(runningScripts.at(i));
if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
} }
QVariantMap resultNode; QVariantMap resultNode;
resultNode.insert("name", runningScriptURL.fileName()); resultNode.insert("name", runningScriptURL.fileName());
resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded))); resultNode.insert("url", runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
// The path contains the exact path/URL of the script, which also is used in the stopScript function.
resultNode.insert("path", runningScript);
resultNode.insert("local", runningScriptURL.isLocalFile()); resultNode.insert("local", runningScriptURL.isLocalFile());
result.append(resultNode); result.append(resultNode);
} }
@ -294,3 +291,16 @@ QVariantList RunningScriptsWidget::getLocal() {
} }
return result; return result;
} }
bool RunningScriptsWidget::stopScriptByName(const QString& name) {
foreach (const QString& runningScript, Application::getInstance()->getRunningScripts()) {
if (QUrl(runningScript).fileName().toLower() == name.trimmed().toLower()) {
return Application::getInstance()->stopScript(runningScript, false);
}
}
return false;
}
bool RunningScriptsWidget::stopScript(const QString& name, bool restart) {
return Application::getInstance()->stopScript(name, restart);
}

View file

@ -36,7 +36,7 @@ public:
const ScriptsModel* getScriptsModel() { return &_scriptsModel; } const ScriptsModel* getScriptsModel() { return &_scriptsModel; }
signals: signals:
void stopScriptName(const QString& name, bool restart = false); void scriptStopped(const QString& scriptName);
protected: protected:
virtual bool eventFilter(QObject* sender, QEvent* event); virtual bool eventFilter(QObject* sender, QEvent* event);
@ -45,10 +45,11 @@ protected:
virtual void showEvent(QShowEvent* event); virtual void showEvent(QShowEvent* event);
public slots: public slots:
void scriptStopped(const QString& scriptName);
QVariantList getRunning(); QVariantList getRunning();
QVariantList getPublic(); QVariantList getPublic();
QVariantList getLocal(); QVariantList getLocal();
bool stopScript(const QString& name, bool restart = false);
bool stopScriptByName(const QString& name);
private slots: private slots:
void allScriptsStopped(); void allScriptsStopped();
@ -63,9 +64,6 @@ private:
QSignalMapper _stopSignalMapper; QSignalMapper _stopSignalMapper;
ScriptsModelFilter _scriptsModelFilter; ScriptsModelFilter _scriptsModelFilter;
ScriptsModel _scriptsModel; ScriptsModel _scriptsModel;
ScriptsTableWidget* _recentlyLoadedScriptsTable;
QStringList _recentlyLoadedScripts;
QString _lastStoppedScript;
QVariantList getPublicChildNodes(TreeNodeFolder* parent); QVariantList getPublicChildNodes(TreeNodeFolder* parent);
}; };

View file

@ -97,7 +97,8 @@ bool ScriptEditorWidget::setRunning(bool run) {
if (run) { if (run) {
const QString& scriptURLString = QUrl(_currentScript).toString(); const QString& scriptURLString = QUrl(_currentScript).toString();
_scriptEngine = Application::getInstance()->loadScript(scriptURLString, true, true); // Reload script so that an out of date copy is not retrieved from the cache
_scriptEngine = Application::getInstance()->loadScript(scriptURLString, true, true, false, true);
connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged);
connect(_scriptEngine, &ScriptEngine::errorMessage, this, &ScriptEditorWidget::onScriptError); connect(_scriptEngine, &ScriptEngine::errorMessage, this, &ScriptEditorWidget::onScriptError);
connect(_scriptEngine, &ScriptEngine::printedMessage, this, &ScriptEditorWidget::onScriptPrint); connect(_scriptEngine, &ScriptEngine::printedMessage, this, &ScriptEditorWidget::onScriptPrint);

View file

@ -89,7 +89,6 @@ void Circle3DOverlay::render(RenderArgs* args) {
const float SLICES = 180.0f; // The amount of segment to create the circle const float SLICES = 180.0f; // The amount of segment to create the circle
const float SLICE_ANGLE = FULL_CIRCLE / SLICES; const float SLICE_ANGLE = FULL_CIRCLE / SLICES;
//const int slices = 15;
xColor colorX = getColor(); xColor colorX = getColor();
const float MAX_COLOR = 255.0f; const float MAX_COLOR = 255.0f;
glm::vec4 color(colorX.red / MAX_COLOR, colorX.green / MAX_COLOR, colorX.blue / MAX_COLOR, alpha); glm::vec4 color(colorX.red / MAX_COLOR, colorX.green / MAX_COLOR, colorX.blue / MAX_COLOR, alpha);

View file

@ -32,7 +32,6 @@ void Sphere3DOverlay::render(RenderArgs* args) {
return; // do nothing if we're not visible return; // do nothing if we're not visible
} }
const int SLICES = 15;
float alpha = getAlpha(); float alpha = getAlpha();
xColor color = getColor(); xColor color = getColor();
const float MAX_COLOR = 255.0f; const float MAX_COLOR = 255.0f;

View file

@ -29,11 +29,7 @@
#include <OffscreenQmlSurface.h> #include <OffscreenQmlSurface.h>
// #include "Application.h"
// #include "GeometryUtil.h"
static const float DPI = 30.47f; static const float DPI = 30.47f;
static const float METERS_TO_INCHES = 39.3701f;
static const float INCHES_TO_METERS = 1.0f / 39.3701f; static const float INCHES_TO_METERS = 1.0f / 39.3701f;
QString const Web3DOverlay::TYPE = "web3d"; QString const Web3DOverlay::TYPE = "web3d";

View file

@ -33,8 +33,10 @@ void AnimInverseKinematics::loadPoses(const AnimPoseVec& poses) {
assert(_skeleton && ((poses.size() == 0) || (_skeleton->getNumJoints() == (int)poses.size()))); assert(_skeleton && ((poses.size() == 0) || (_skeleton->getNumJoints() == (int)poses.size())));
if (_skeleton->getNumJoints() == (int)poses.size()) { if (_skeleton->getNumJoints() == (int)poses.size()) {
_relativePoses = poses; _relativePoses = poses;
_accumulators.resize(_relativePoses.size());
} else { } else {
_relativePoses.clear(); _relativePoses.clear();
_accumulators.clear();
} }
} }
@ -82,22 +84,8 @@ static int findRootJointInSkeleton(AnimSkeleton::ConstPointer skeleton, int inde
return rootIndex; return rootIndex;
} }
struct IKTarget { void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets) {
AnimPose pose; // build a list of valid targets from _targetVarVec and animVars
int index;
int rootIndex;
};
//virtual
const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, float dt, AnimNode::Triggers& triggersOut) {
// NOTE: we assume that _relativePoses are up to date (e.g. loadPoses() was just called)
if (_relativePoses.empty()) {
return _relativePoses;
}
// build a list of targets from _targetVarVec
std::vector<IKTarget> targets;
bool removeUnfoundJoints = false; bool removeUnfoundJoints = false;
for (auto& targetVar : _targetVarVec) { for (auto& targetVar : _targetVarVec) {
if (targetVar.jointIndex == -1) { if (targetVar.jointIndex == -1) {
@ -113,15 +101,13 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
} }
} else { } else {
// TODO: get this done without a double-lookup of each var in animVars // TODO: get this done without a double-lookup of each var in animVars
if (animVars.hasKey(targetVar.positionVar) || animVars.hasKey(targetVar.rotationVar)) { IKTarget target;
IKTarget target; AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses);
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses); target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans); target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot); target.rootIndex = targetVar.rootIndex;
target.rootIndex = targetVar.rootIndex; target.index = targetVar.jointIndex;
target.index = targetVar.jointIndex; targets.push_back(target);
targets.push_back(target);
}
} }
} }
@ -141,154 +127,160 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
} }
} }
} }
}
if (targets.empty()) { void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vector<IKTarget>& targets) {
// no IK targets but still need to enforce constraints // compute absolute poses that correspond to relative target poses
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin(); AnimPoseVec absolutePoses;
while (constraintItr != _constraints.end()) { computeAbsolutePoses(absolutePoses);
int index = constraintItr->first;
glm::quat rotation = _relativePoses[index].rot;
constraintItr->second->apply(rotation);
_relativePoses[index].rot = rotation;
++constraintItr;
}
} else {
// clear the accumulators before we start the IK solver
for (auto& accumulatorPair: _accumulators) {
accumulatorPair.second.clear();
}
// compute absolute poses that correspond to relative target poses // clear the accumulators before we start the IK solver
AnimPoseVec absolutePoses; for (auto& accumulator: _accumulators) {
computeAbsolutePoses(absolutePoses); accumulator.clearAndClean();
}
float largestError = 0.0f; float largestError = 0.0f;
const float ACCEPTABLE_RELATIVE_ERROR = 1.0e-3f; const float ACCEPTABLE_RELATIVE_ERROR = 1.0e-3f;
int numLoops = 0; int numLoops = 0;
const int MAX_IK_LOOPS = 16; const int MAX_IK_LOOPS = 16;
const quint64 MAX_IK_TIME = 10 * USECS_PER_MSEC; const quint64 MAX_IK_TIME = 10 * USECS_PER_MSEC;
quint64 expiry = usecTimestampNow() + MAX_IK_TIME; quint64 expiry = usecTimestampNow() + MAX_IK_TIME;
do { do {
largestError = 0.0f; largestError = 0.0f;
int lowestMovedIndex = _relativePoses.size(); int lowestMovedIndex = _relativePoses.size();
for (auto& target: targets) {
int tipIndex = target.index;
AnimPose targetPose = target.pose;
int rootIndex = target.rootIndex;
if (rootIndex != -1) {
// transform targetPose into skeleton's absolute frame
AnimPose& rootPose = _relativePoses[rootIndex];
targetPose.trans = rootPose.trans + rootPose.rot * targetPose.trans;
targetPose.rot = rootPose.rot * targetPose.rot;
}
glm::vec3 tip = absolutePoses[tipIndex].trans;
float error = glm::length(targetPose.trans - tip);
// descend toward root, pivoting each joint to get tip closer to target
int pivotIndex = _skeleton->getParentIndex(tipIndex);
while (pivotIndex != -1 && error > ACCEPTABLE_RELATIVE_ERROR) {
// compute the two lines that should be aligned
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
glm::vec3 leverArm = tip - jointPosition;
glm::vec3 targetLine = targetPose.trans - jointPosition;
// compute the axis of the rotation that would align them
glm::vec3 axis = glm::cross(leverArm, targetLine);
float axisLength = glm::length(axis);
if (axisLength > EPSILON) {
// compute deltaRotation for alignment (brings tip closer to target)
axis /= axisLength;
float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine)));
// NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is
// still possible for the angle to be zero so we also check that to avoid unnecessary calculations.
if (angle > EPSILON) {
// reduce angle by half: slows convergence but adds stability to IK solution
angle = 0.5f * angle;
glm::quat deltaRotation = glm::angleAxis(angle, axis);
int parentIndex = _skeleton->getParentIndex(pivotIndex);
if (parentIndex == -1) {
// TODO? apply constraints to root?
// TODO? harvest the root's transform as movement of entire skeleton?
} else {
// compute joint's new parent-relative rotation
// Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q
glm::quat newRot = glm::normalize(glm::inverse(
absolutePoses[parentIndex].rot) *
deltaRotation *
absolutePoses[pivotIndex].rot);
RotationConstraint* constraint = getConstraint(pivotIndex);
if (constraint) {
bool constrained = constraint->apply(newRot);
if (constrained) {
// the constraint will modify the movement of the tip so we have to compute the modified
// model-frame deltaRotation
// Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^
deltaRotation = absolutePoses[parentIndex].rot *
newRot *
glm::inverse(absolutePoses[pivotIndex].rot);
}
}
// store the rotation change in the accumulator
_accumulators[pivotIndex].add(newRot);
}
// this joint has been changed so we check to see if it has the lowest index
if (pivotIndex < lowestMovedIndex) {
lowestMovedIndex = pivotIndex;
}
// keep track of tip's new position as we descend towards root
tip = jointPosition + deltaRotation * leverArm;
error = glm::length(targetPose.trans - tip);
}
}
pivotIndex = _skeleton->getParentIndex(pivotIndex);
}
if (largestError < error) {
largestError = error;
}
}
++numLoops;
// harvest accumulated rotations and apply the average
for (auto& accumulatorPair: _accumulators) {
RotationAccumulator& accumulator = accumulatorPair.second;
if (accumulator.size() > 0) {
_relativePoses[accumulatorPair.first].rot = accumulator.getAverage();
accumulator.clear();
}
}
// only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex
for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) {
int parentIndex = _skeleton->getParentIndex(i);
if (parentIndex != -1) {
absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i];
}
}
} while (largestError > ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry);
// finally set the relative rotation of each tip to agree with absolute target rotation
for (auto& target: targets) { for (auto& target: targets) {
int tipIndex = target.index; int tipIndex = target.index;
int parentIndex = _skeleton->getParentIndex(tipIndex); AnimPose targetPose = target.pose;
if (parentIndex != -1) {
AnimPose targetPose = target.pose; glm::vec3 tip = absolutePoses[tipIndex].trans;
// compute tip's new parent-relative rotation float error = glm::length(targetPose.trans - tip);
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot; // descend toward root, pivoting each joint to get tip closer to target
RotationConstraint* constraint = getConstraint(tipIndex); int pivotIndex = _skeleton->getParentIndex(tipIndex);
if (constraint) { while (pivotIndex != -1 && error > ACCEPTABLE_RELATIVE_ERROR) {
constraint->apply(newRelativeRotation); // compute the two lines that should be aligned
// TODO: ATM the final rotation target just fails but we need to provide glm::vec3 jointPosition = absolutePoses[pivotIndex].trans;
// feedback to the IK system so that it can adjust the bones up the skeleton glm::vec3 leverArm = tip - jointPosition;
// to help this rotation target get met. glm::vec3 targetLine = targetPose.trans - jointPosition;
// compute the axis of the rotation that would align them
glm::vec3 axis = glm::cross(leverArm, targetLine);
float axisLength = glm::length(axis);
if (axisLength > EPSILON) {
// compute deltaRotation for alignment (brings tip closer to target)
axis /= axisLength;
float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine)));
// NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is
// still possible for the angle to be zero so we also check that to avoid unnecessary calculations.
if (angle > EPSILON) {
// reduce angle by half: slows convergence but adds stability to IK solution
angle = 0.5f * angle;
glm::quat deltaRotation = glm::angleAxis(angle, axis);
int parentIndex = _skeleton->getParentIndex(pivotIndex);
if (parentIndex == -1) {
// TODO? apply constraints to root?
// TODO? harvest the root's transform as movement of entire skeleton?
} else {
// compute joint's new parent-relative rotation
// Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q
glm::quat newRot = glm::normalize(glm::inverse(
absolutePoses[parentIndex].rot) *
deltaRotation *
absolutePoses[pivotIndex].rot);
RotationConstraint* constraint = getConstraint(pivotIndex);
if (constraint) {
bool constrained = constraint->apply(newRot);
if (constrained) {
// the constraint will modify the movement of the tip so we have to compute the modified
// model-frame deltaRotation
// Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^
deltaRotation = absolutePoses[parentIndex].rot *
newRot *
glm::inverse(absolutePoses[pivotIndex].rot);
}
}
// store the rotation change in the accumulator
_accumulators[pivotIndex].add(newRot);
}
// this joint has been changed so we check to see if it has the lowest index
if (pivotIndex < lowestMovedIndex) {
lowestMovedIndex = pivotIndex;
}
// keep track of tip's new position as we descend towards root
tip = jointPosition + deltaRotation * leverArm;
error = glm::length(targetPose.trans - tip);
}
} }
_relativePoses[tipIndex].rot = newRelativeRotation; pivotIndex = _skeleton->getParentIndex(pivotIndex);
absolutePoses[tipIndex].rot = targetPose.rot;
} }
if (largestError < error) {
largestError = error;
}
}
++numLoops;
// harvest accumulated rotations and apply the average
const int numJoints = (int)_accumulators.size();
for (int i = 0; i < numJoints; ++i) {
if (_accumulators[i].size() > 0) {
_relativePoses[i].rot = _accumulators[i].getAverage();
_accumulators[i].clear();
}
}
// only update the absolutePoses that need it: those between lowestMovedIndex and _maxTargetIndex
for (int i = lowestMovedIndex; i <= _maxTargetIndex; ++i) {
int parentIndex = _skeleton->getParentIndex(i);
if (parentIndex != -1) {
absolutePoses[i] = absolutePoses[parentIndex] * _relativePoses[i];
}
}
} while (largestError > ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry);
// finally set the relative rotation of each tip to agree with absolute target rotation
for (auto& target: targets) {
int tipIndex = target.index;
int parentIndex = _skeleton->getParentIndex(tipIndex);
if (parentIndex != -1) {
AnimPose targetPose = target.pose;
// compute tip's new parent-relative rotation
// Q = Qp * q --> q' = Qp^ * Q
glm::quat newRelativeRotation = glm::inverse(absolutePoses[parentIndex].rot) * targetPose.rot;
RotationConstraint* constraint = getConstraint(tipIndex);
if (constraint) {
constraint->apply(newRelativeRotation);
// TODO: ATM the final rotation target just fails but we need to provide
// feedback to the IK system so that it can adjust the bones up the skeleton
// to help this rotation target get met.
}
_relativePoses[tipIndex].rot = newRelativeRotation;
absolutePoses[tipIndex].rot = targetPose.rot;
}
}
}
//virtual
const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVars, float dt, AnimNode::Triggers& triggersOut) {
if (!_relativePoses.empty()) {
// build a list of targets from _targetVarVec
std::vector<IKTarget> targets;
computeTargets(animVars, targets);
if (targets.empty()) {
// no IK targets but still need to enforce constraints
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
while (constraintItr != _constraints.end()) {
int index = constraintItr->first;
glm::quat rotation = _relativePoses[index].rot;
constraintItr->second->apply(rotation);
_relativePoses[index].rot = rotation;
++constraintItr;
}
} else {
solveWithCyclicCoordinateDescent(targets);
} }
} }
return _relativePoses; return _relativePoses;
@ -309,7 +301,11 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
int numJoints = (int)_relativePoses.size(); int numJoints = (int)_relativePoses.size();
for (int i = 0; i < numJoints; ++i) { for (int i = 0; i < numJoints; ++i) {
float dotSign = copysignf(1.0f, glm::dot(_relativePoses[i].rot, underPoses[i].rot)); float dotSign = copysignf(1.0f, glm::dot(_relativePoses[i].rot, underPoses[i].rot));
_relativePoses[i].rot = glm::normalize(glm::lerp(_relativePoses[i].rot, dotSign * underPoses[i].rot, blend)); if (_accumulators[i].isDirty()) {
_relativePoses[i].rot = glm::normalize(glm::lerp(_relativePoses[i].rot, dotSign * underPoses[i].rot, blend));
} else {
_relativePoses[i].rot = underPoses[i].rot;
}
} }
} }
return evaluate(animVars, dt, triggersOut); return evaluate(animVars, dt, triggersOut);
@ -652,18 +648,3 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
clearConstraints(); clearConstraints();
} }
} }
void AnimInverseKinematics::relaxTowardDefaults(float dt) {
// NOTE: for now we just use a single relaxation timescale for all joints, but in the future
// we could vary the timescale on a per-joint basis or do other fancy things.
// for each joint: lerp towards the default pose
const float RELAXATION_TIMESCALE = 0.25f;
const float alpha = glm::clamp(dt / RELAXATION_TIMESCALE, 0.0f, 1.0f);
int numJoints = (int)_relativePoses.size();
for (int i = 0; i < numJoints; ++i) {
float dotSign = copysignf(1.0f, glm::dot(_relativePoses[i].rot, _defaultRelativePoses[i].rot));
_relativePoses[i].rot = glm::normalize(glm::lerp(_relativePoses[i].rot, dotSign * _defaultRelativePoses[i].rot, alpha));
}
}

View file

@ -37,13 +37,19 @@ public:
virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override;
protected: protected:
struct IKTarget {
AnimPose pose;
int index;
int rootIndex;
};
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets);
void solveWithCyclicCoordinateDescent(std::vector<IKTarget>& targets);
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton); virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton);
// for AnimDebugDraw rendering // for AnimDebugDraw rendering
virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; } virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }
void relaxTowardDefaults(float dt);
RotationConstraint* getConstraint(int index); RotationConstraint* getConstraint(int index);
void clearConstraints(); void clearConstraints();
void initConstraints(); void initConstraints();
@ -64,7 +70,7 @@ protected:
}; };
std::map<int, RotationConstraint*> _constraints; std::map<int, RotationConstraint*> _constraints;
std::map<int, RotationAccumulator> _accumulators; std::vector<RotationAccumulator> _accumulators;
std::vector<IKTargetVar> _targetVarVec; std::vector<IKTargetVar> _targetVarVec;
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
AnimPoseVec _relativePoses; // current relative poses AnimPoseVec _relativePoses; // current relative poses

View file

@ -0,0 +1,54 @@
//
// AnimNode.cpp
//
// Created by Anthony J. Thibault on 9/2/15.
// Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AnimNode.h"
void AnimNode::removeChild(AnimNode::Pointer child) {
auto iter = std::find(_children.begin(), _children.end(), child);
if (iter != _children.end()) {
_children.erase(iter);
}
}
AnimNode::Pointer AnimNode::getChild(int i) const {
assert(i >= 0 && i < (int)_children.size());
return _children[i];
}
void AnimNode::setSkeleton(const AnimSkeleton::Pointer skeleton) {
setSkeletonInternal(skeleton);
for (auto&& child : _children) {
child->setSkeleton(skeleton);
}
}
const AnimPose AnimNode::getRootPose(int jointIndex) const {
AnimPose pose = AnimPose::identity;
if (_skeleton && jointIndex != -1) {
const AnimPoseVec& poses = getPosesInternal();
int numJoints = (int)(poses.size());
if (jointIndex < numJoints) {
int parentIndex = _skeleton->getParentIndex(jointIndex);
while (parentIndex != -1 && parentIndex < numJoints) {
jointIndex = parentIndex;
parentIndex = _skeleton->getParentIndex(jointIndex);
}
pose = poses[jointIndex];
}
}
return pose;
}
void AnimNode::setCurrentFrame(float frame) {
setCurrentFrameInternal(frame);
for (auto&& child : _children) {
child->setCurrentFrameInternal(frame);
}
}

View file

@ -60,25 +60,13 @@ public:
// hierarchy accessors // hierarchy accessors
void addChild(Pointer child) { _children.push_back(child); } void addChild(Pointer child) { _children.push_back(child); }
void removeChild(Pointer child) { void removeChild(Pointer child);
auto iter = std::find(_children.begin(), _children.end(), child);
if (iter != _children.end()) { Pointer getChild(int i) const;
_children.erase(iter);
}
}
Pointer getChild(int i) const {
assert(i >= 0 && i < (int)_children.size());
return _children[i];
}
int getChildCount() const { return (int)_children.size(); } int getChildCount() const { return (int)_children.size(); }
// pair this AnimNode graph with a skeleton. // pair this AnimNode graph with a skeleton.
void setSkeleton(const AnimSkeleton::Pointer skeleton) { void setSkeleton(const AnimSkeleton::Pointer skeleton);
setSkeletonInternal(skeleton);
for (auto&& child : _children) {
child->setSkeleton(skeleton);
}
}
AnimSkeleton::ConstPointer getSkeleton() const { return _skeleton; } AnimSkeleton::ConstPointer getSkeleton() const { return _skeleton; }
@ -87,19 +75,14 @@ public:
return evaluate(animVars, dt, triggersOut); return evaluate(animVars, dt, triggersOut);
} }
const AnimPose getRootPose(int jointIndex) const;
protected: protected:
void setCurrentFrame(float frame) { void setCurrentFrame(float frame);
setCurrentFrameInternal(frame);
for (auto&& child : _children) {
child->setCurrentFrameInternal(frame);
}
}
virtual void setCurrentFrameInternal(float frame) {} virtual void setCurrentFrameInternal(float frame) {}
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { _skeleton = skeleton; }
_skeleton = skeleton;
}
// for AnimDebugDraw rendering // for AnimDebugDraw rendering
virtual const AnimPoseVec& getPosesInternal() const = 0; virtual const AnimPoseVec& getPosesInternal() const = 0;

View file

@ -986,16 +986,20 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa
void Rig::updateNeckJoint(int index, const HeadParameters& params) { void Rig::updateNeckJoint(int index, const HeadParameters& params) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
if (_enableAnimGraph && _animSkeleton) { if (_enableAnimGraph && _animSkeleton && _animNode) {
// the params.localHeadOrientation is composed incorrectly, so re-compose it correctly from pitch, yaw and roll. // the params.localHeadOrientation is composed incorrectly, so re-compose it correctly from pitch, yaw and roll.
glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) * glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) *
glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) * glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) *
glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS)); glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS));
_animVars.set("headRotation", realLocalHeadOrientation); _animVars.set("headRotation", realLocalHeadOrientation);
// There's a theory that when not in hmd, we should _animVars.unset("headPosition"). if (params.isInHMD) {
// However, until that works well, let's always request head be positioned where requested by hmd, camera, or default. int headIndex = _animSkeleton->nameToJointIndex("Head");
_animVars.set("headPosition", params.localHeadPosition); AnimPose rootPose = _animNode->getRootPose(headIndex);
_animVars.set("headPosition", rootPose.trans + params.localHeadPosition); // rootPose.rot is handled in params?d
} else {
_animVars.unset("headPosition");
}
} else if (!_enableAnimGraph) { } else if (!_enableAnimGraph) {
auto& state = _jointStates[index]; auto& state = _jointStates[index];
@ -1044,20 +1048,22 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
void Rig::updateFromHandParameters(const HandParameters& params, float dt) { void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
if (_enableAnimGraph && _animSkeleton) { if (_enableAnimGraph && _animSkeleton && _animNode) {
// TODO: figure out how to obtain the yFlip from where it is actually stored // TODO: figure out how to obtain the yFlip from where it is actually stored
glm::quat yFlipHACK = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); glm::quat yFlipHACK = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
int leftHandIndex = _animSkeleton->nameToJointIndex("LeftHand");
AnimPose rootPose = _animNode->getRootPose(leftHandIndex);
if (params.isLeftEnabled) { if (params.isLeftEnabled) {
_animVars.set("leftHandPosition", yFlipHACK * params.leftPosition); _animVars.set("leftHandPosition", rootPose.trans + rootPose.rot * yFlipHACK * params.leftPosition);
_animVars.set("leftHandRotation", yFlipHACK * params.leftOrientation); _animVars.set("leftHandRotation", rootPose.rot * yFlipHACK * params.leftOrientation);
} else { } else {
_animVars.unset("leftHandPosition"); _animVars.unset("leftHandPosition");
_animVars.unset("leftHandRotation"); _animVars.unset("leftHandRotation");
} }
if (params.isRightEnabled) { if (params.isRightEnabled) {
_animVars.set("rightHandPosition", yFlipHACK * params.rightPosition); _animVars.set("rightHandPosition", rootPose.trans + rootPose.rot * yFlipHACK * params.rightPosition);
_animVars.set("rightHandRotation", yFlipHACK * params.rightOrientation); _animVars.set("rightHandRotation", rootPose.rot * yFlipHACK * params.rightOrientation);
} else { } else {
_animVars.unset("rightHandPosition"); _animVars.unset("rightHandPosition");
_animVars.unset("rightHandRotation"); _animVars.unset("rightHandRotation");

View file

@ -11,17 +11,23 @@
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
void RotationAccumulator::add(glm::quat rotation) { void RotationAccumulator::add(const glm::quat& rotation) {
// make sure both quaternions are on the same hyper-hemisphere before we add them linearly (lerp) // make sure both quaternions are on the same hyper-hemisphere before we add them linearly (lerp)
_rotationSum += copysignf(1.0f, glm::dot(_rotationSum, rotation)) * rotation; _rotationSum += copysignf(1.0f, glm::dot(_rotationSum, rotation)) * rotation;
++_numRotations; ++_numRotations;
_isDirty = true;
} }
glm::quat RotationAccumulator::getAverage() { glm::quat RotationAccumulator::getAverage() {
return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat(); return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat();
} }
void RotationAccumulator::clear() { void RotationAccumulator::clear() {
_rotationSum *= 0.0f; _rotationSum *= 0.0f;
_numRotations = 0; _numRotations = 0;
} }
void RotationAccumulator::clearAndClean() {
clear();
_isDirty = false;
}

View file

@ -14,19 +14,27 @@
class RotationAccumulator { class RotationAccumulator {
public: public:
RotationAccumulator() : _rotationSum(0.0f, 0.0f, 0.0f, 0.0f), _numRotations(0) { } RotationAccumulator() : _rotationSum(0.0f, 0.0f, 0.0f, 0.0f), _numRotations(0), _isDirty(false) { }
int size() const { return _numRotations; } int size() const { return _numRotations; }
void add(glm::quat rotation); void add(const glm::quat& rotation);
glm::quat getAverage(); glm::quat getAverage();
/// \return true if any rotations were accumulated
bool isDirty() const { return _isDirty; }
/// \brief clear accumulated rotation but don't change _isDirty
void clear(); void clear();
/// \brief clear accumulated rotation and set _isDirty to false
void clearAndClean();
private: private:
glm::quat _rotationSum; glm::quat _rotationSum;
int _numRotations; int _numRotations;
bool _isDirty;
}; };
#endif // hifi_RotationAccumulator_h #endif // hifi_RotationAccumulator_h

View file

@ -25,8 +25,8 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
auto shapeTransform = entity->getTransformToCenter(); auto shapeTransform = entity->getTransformToCenter();
if (puffedOut != 0.0) { if (puffedOut != 0.0f) {
shapeTransform.postScale(1.0 + puffedOut); shapeTransform.postScale(1.0f + puffedOut);
} }
batch.setModelTransform(Transform()); // we want to include the scale as well batch.setModelTransform(Transform()); // we want to include the scale as well
DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, color); DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, color);

View file

@ -934,8 +934,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
_textureContent.insert(filename, content); _textureContent.insert(filename, content);
} }
} else if (object.name == "Material") { } else if (object.name == "Material") {
FBXMaterial material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), glm::vec2(0.f, 1.0f), 96.0f, 1.0f, FBXMaterial material(glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f), glm::vec3(), glm::vec2(0.f, 1.0f), 96.0f, 1.0f);
QString("")};
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
bool properties = false; bool properties = false;
QByteArray propertyName; QByteArray propertyName;

View file

@ -136,6 +136,16 @@ public:
class FBXMaterial { class FBXMaterial {
public: public:
FBXMaterial() {};
FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
const glm::vec2& emissiveParams, float shininess, float opacity) :
diffuseColor(diffuseColor),
specularColor(specularColor),
emissiveColor(emissiveColor),
emissiveParams(emissiveParams),
shininess(shininess),
opacity(opacity) {}
glm::vec3 diffuseColor; glm::vec3 diffuseColor;
glm::vec3 specularColor; glm::vec3 specularColor;
glm::vec3 emissiveColor; glm::vec3 emissiveColor;

View file

@ -487,11 +487,10 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
} }
if (!groupMaterialName.isEmpty()) { if (!groupMaterialName.isEmpty()) {
OBJMaterial* material = &materials[groupMaterialName];
// TODO Fix this once the transision is understood // TODO Fix this once the transision is understood
/*// The code behind this is in transition. Some things are set directly in the FXBMeshPart... /*// The code behind this is in transition. Some things are set directly in the FXBMeshPart...
OBJMaterial* material = &materials[groupMaterialName];
meshPart.materialID = groupMaterialName; meshPart.materialID = groupMaterialName;
meshPart.diffuseTexture.filename = material->diffuseTextureFilename; meshPart.diffuseTexture.filename = material->diffuseTextureFilename;
meshPart.specularTexture.filename = material->specularTextureFilename; meshPart.specularTexture.filename = material->specularTextureFilename;

View file

@ -337,6 +337,8 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) {
glDrawElementsInstanced(mode, numIndices, glType, reinterpret_cast<GLvoid*>(startIndex + _input._indexBufferOffset), numInstances); glDrawElementsInstanced(mode, numIndices, glType, reinterpret_cast<GLvoid*>(startIndex + _input._indexBufferOffset), numInstances);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
Q_UNUSED(startInstance);
} }
void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) { void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) {

View file

@ -18,7 +18,7 @@ using namespace gpu;
using ElementArray = std::array<Element, Stream::NUM_INPUT_SLOTS>; using ElementArray = std::array<Element, Stream::NUM_INPUT_SLOTS>;
const ElementArray& getDefaultElements() { const ElementArray& getDefaultElements() {
static ElementArray defaultElements{ static ElementArray defaultElements{{
//POSITION = 0, //POSITION = 0,
Element::VEC3F_XYZ, Element::VEC3F_XYZ,
//NORMAL = 1, //NORMAL = 1,
@ -42,7 +42,7 @@ const ElementArray& getDefaultElements() {
//INSTANCE_XFM = 10, //INSTANCE_XFM = 10,
// FIXME make a matrix element // FIXME make a matrix element
Element::VEC4F_XYZW Element::VEC4F_XYZW
}; }};
return defaultElements; return defaultElements;
} }

View file

@ -271,7 +271,7 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas
networkMesh->_mesh = mesh._mesh; networkMesh->_mesh = mesh._mesh;
int totalIndices = 0; int totalIndices = 0;
bool checkForTexcoordLightmap = false; //bool checkForTexcoordLightmap = false;
@ -394,8 +394,7 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
auto textureCache = DependencyManager::get<TextureCache>(); auto textureCache = DependencyManager::get<TextureCache>();
NetworkMaterial* networkMaterial = new NetworkMaterial(); NetworkMaterial* networkMaterial = new NetworkMaterial();
int totalIndices = 0; //bool checkForTexcoordLightmap = false;
bool checkForTexcoordLightmap = false;
networkMaterial->_material = material._material; networkMaterial->_material = material._material;
@ -431,7 +430,7 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content); networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
networkMaterial->emissiveTextureName = material.emissiveTexture.name; networkMaterial->emissiveTextureName = material.emissiveTexture.name;
checkForTexcoordLightmap = true; //checkForTexcoordLightmap = true;
auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource); lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
@ -493,9 +492,9 @@ void NetworkGeometry::modelParseError(int error, QString str) {
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) { const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
if ((shapeID >= 0) && (shapeID < _shapes.size())) { if ((shapeID >= 0) && (shapeID < (int)_shapes.size())) {
int materialID = _shapes[shapeID]->_materialID; int materialID = _shapes[shapeID]->_materialID;
if ((materialID >= 0) && (materialID < _materials.size())) { if ((materialID >= 0) && ((unsigned int)materialID < _materials.size())) {
return _materials[materialID].get(); return _materials[materialID].get();
} else { } else {
return 0; return 0;

View file

@ -15,18 +15,6 @@
using namespace model; using namespace model;
using namespace gpu; using namespace gpu;
float componentSRGBToLinear(float cs) {
if (cs > 0.04045) {
return pow(((cs + 0.055)/1.055), 2.4);
} else {
return cs / 12.92;
}
}
glm::vec3 convertSRGBToLinear(const glm::vec3& srgb) {
return glm::vec3(componentSRGBToLinear(srgb.x), componentSRGBToLinear(srgb.y), componentSRGBToLinear(srgb.z));
}
Material::Material() : Material::Material() :
_key(0), _key(0),
_schemaBuffer(), _schemaBuffer(),

View file

@ -20,8 +20,6 @@
namespace model { namespace model {
static glm::vec3 convertSRGBToLinear(const glm::vec3& srgb);
class TextureMap; class TextureMap;
typedef std::shared_ptr< TextureMap > TextureMapPointer; typedef std::shared_ptr< TextureMap > TextureMapPointer;

View file

@ -59,7 +59,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
int opaquePixels = 0; int opaquePixels = 0;
int translucentPixels = 0; int translucentPixels = 0;
bool isTransparent = false; //bool isTransparent = false;
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
const int EIGHT_BIT_MAXIMUM = 255; const int EIGHT_BIT_MAXIMUM = 255;
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM); QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
@ -112,7 +112,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
averageColor = QColor(redTotal / imageArea, averageColor = QColor(redTotal / imageArea,
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea); greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
isTransparent = (translucentPixels >= imageArea / 2); //isTransparent = (translucentPixels >= imageArea / 2);
} }
gpu::Texture* theTexture = nullptr; gpu::Texture* theTexture = nullptr;
@ -269,7 +269,7 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c
int opaquePixels = 0; int opaquePixels = 0;
int translucentPixels = 0; int translucentPixels = 0;
bool isTransparent = false; //bool isTransparent = false;
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0; int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
const int EIGHT_BIT_MAXIMUM = 255; const int EIGHT_BIT_MAXIMUM = 255;
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM); QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
@ -322,7 +322,7 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c
averageColor = QColor(redTotal / imageArea, averageColor = QColor(redTotal / imageArea,
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea); greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
isTransparent = (translucentPixels >= imageArea / 2); //isTransparent = (translucentPixels >= imageArea / 2);
} }
gpu::Texture* theTexture = nullptr; gpu::Texture* theTexture = nullptr;

View file

@ -85,30 +85,30 @@ static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1.0 - EWMA_CURRENT_SAMPLE_WEI
void ConnectionStats::recordSendRate(int sample) { void ConnectionStats::recordSendRate(int sample) {
_currentSample.sendRate = sample; _currentSample.sendRate = sample;
_total.sendRate = (_total.sendRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.sendRate = (int)((_total.sendRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }
void ConnectionStats::recordReceiveRate(int sample) { void ConnectionStats::recordReceiveRate(int sample) {
_currentSample.receiveRate = sample; _currentSample.receiveRate = sample;
_total.receiveRate = (_total.receiveRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.receiveRate = (int)((_total.receiveRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }
void ConnectionStats::recordEstimatedBandwidth(int sample) { void ConnectionStats::recordEstimatedBandwidth(int sample) {
_currentSample.estimatedBandwith = sample; _currentSample.estimatedBandwith = sample;
_total.estimatedBandwith = (_total.estimatedBandwith * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.estimatedBandwith = (int)((_total.estimatedBandwith * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }
void ConnectionStats::recordRTT(int sample) { void ConnectionStats::recordRTT(int sample) {
_currentSample.rtt = sample; _currentSample.rtt = sample;
_total.rtt = (_total.rtt * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.rtt = (int)((_total.rtt * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }
void ConnectionStats::recordCongestionWindowSize(int sample) { void ConnectionStats::recordCongestionWindowSize(int sample) {
_currentSample.congestionWindowSize = sample; _currentSample.congestionWindowSize = sample;
_total.congestionWindowSize = (_total.congestionWindowSize * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.congestionWindowSize = (int)((_total.congestionWindowSize * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }
void ConnectionStats::recordPacketSendPeriod(int sample) { void ConnectionStats::recordPacketSendPeriod(int sample) {
_currentSample.packetSendPeriod = sample; _currentSample.packetSendPeriod = sample;
_total.packetSendPeriod = (_total.packetSendPeriod * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT); _total.packetSendPeriod = (int)((_total.packetSendPeriod * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT));
} }

View file

@ -435,7 +435,7 @@ void DeferredLightingEffect::render(RenderArgs* args) {
args->_context->getStereoProjections(projMats); args->_context->getStereoProjections(projMats);
args->_context->getStereoViews(eyeViews); args->_context->getStereoViews(eyeViews);
float halfWidth = 0.5 * sWidth; float halfWidth = 0.5f * sWidth;
for (int i = 0; i < numPasses; i++) { for (int i = 0; i < numPasses; i++) {
// In stereo, the 2 sides are layout side by side in the mono viewport and their width is half // In stereo, the 2 sides are layout side by side in the mono viewport and their width is half

View file

@ -1,9 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/08/06.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GLEscrow.h"

View file

@ -36,17 +36,18 @@
const int GeometryCache::UNKNOWN_ID = -1; const int GeometryCache::UNKNOWN_ID = -1;
static const uint FLOATS_PER_VERTEX = 3; static const int VERTICES_PER_TRIANGLE = 3;
static const uint VERTICES_PER_TRIANGLE = 3;
static const uint TRIANGLES_PER_QUAD = 2; //static const uint FLOATS_PER_VERTEX = 3;
static const uint CUBE_FACES = 6; //static const uint TRIANGLES_PER_QUAD = 2;
static const uint CUBE_VERTICES_PER_FACE = 4; //static const uint CUBE_FACES = 6;
static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE; //static const uint CUBE_VERTICES_PER_FACE = 4;
static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX; //static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE;
static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; //static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX;
static const uint SPHERE_LATITUDES = 24; //static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE;
static const uint SPHERE_MERIDIANS = SPHERE_LATITUDES * 2; //static const uint SPHERE_LATITUDES = 24;
static const uint SPHERE_INDICES = SPHERE_MERIDIANS * (SPHERE_LATITUDES - 1) * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE; //static const uint SPHERE_MERIDIANS = SPHERE_LATITUDES * 2;
//static const uint SPHERE_INDICES = SPHERE_MERIDIANS * (SPHERE_LATITUDES - 1) * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE;
static const gpu::Element POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; static const gpu::Element POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
static const gpu::Element NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; static const gpu::Element NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ };
@ -122,9 +123,9 @@ void GeometryCache::ShapeData::drawWireInstances(gpu::Batch& batch, size_t count
} }
const VertexVector& icosahedronVertices() { const VertexVector& icosahedronVertices() {
static const float phi = (1.0 + sqrt(5.0)) / 2.0; static const float phi = (1.0f + sqrtf(5.0f)) / 2.0f;
static const float a = 0.5; static const float a = 0.5f;
static const float b = 1.0 / (2.0 * phi); static const float b = 1.0f / (2.0f * phi);
static const VertexVector vertices{ // static const VertexVector vertices{ //
vec3(0, b, -a), vec3(-b, a, 0), vec3(b, a, 0), // vec3(0, b, -a), vec3(-b, a, 0), vec3(b, a, 0), //
@ -152,7 +153,7 @@ const VertexVector& icosahedronVertices() {
} }
const VertexVector& tetrahedronVertices() { const VertexVector& tetrahedronVertices() {
static const float a = 1.0f / sqrt(2.0f); static const float a = 1.0f / sqrtf(2.0f);
static const auto A = vec3(0, 1, a); static const auto A = vec3(0, 1, a);
static const auto B = vec3(0, -1, a); static const auto B = vec3(0, -1, a);
static const auto C = vec3(1, 0, -a); static const auto C = vec3(1, 0, -a);
@ -294,7 +295,6 @@ void GeometryCache::buildShapes() {
static const size_t VERTEX_FORMAT_SIZE = 2; static const size_t VERTEX_FORMAT_SIZE = 2;
static const size_t VERTEX_OFFSET = 0; static const size_t VERTEX_OFFSET = 0;
static const size_t NORMAL_OFFSET = 1;
for (size_t i = 0; i < vertices.size(); ++i) { for (size_t i = 0; i < vertices.size(); ++i) {
auto vertexIndex = i; auto vertexIndex = i;
@ -323,7 +323,7 @@ void GeometryCache::buildShapes() {
20, 21, 21, 22, 22, 23, 23, 20, // back 20, 21, 21, 22, 22, 23, 23, 20, // back
0, 23, 1, 22, 2, 21, 3, 20 // sides 0, 23, 1, 22, 2, 21, 3, 20 // sides
}; };
for (int i = 0; i < wireIndices.size(); ++i) { for (unsigned int i = 0; i < wireIndices.size(); ++i) {
indices[i] += startingIndex; indices[i] += startingIndex;
} }
@ -374,7 +374,7 @@ void GeometryCache::buildShapes() {
0, 3, 1, 3, 2, 3, 0, 3, 1, 3, 2, 3,
}; };
for (int i = 0; i < wireIndices.size(); ++i) { for (unsigned int i = 0; i < wireIndices.size(); ++i) {
wireIndices[i] += startingIndex; wireIndices[i] += startingIndex;
} }

View file

@ -1756,9 +1756,7 @@ void Model::segregateMeshGroups() {
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0; int shapeID = 0;
for (int i = 0; i < (int)networkMeshes.size(); i++) { for (int i = 0; i < (int)networkMeshes.size(); i++) {
const NetworkMesh& networkMesh = *(networkMeshes.at(i).get());
const FBXMesh& mesh = geometry.meshes.at(i); const FBXMesh& mesh = geometry.meshes.at(i);
const MeshState& state = _meshStates.at(i);
// Create the render payloads // Create the render payloads
int totalParts = mesh.parts.size(); int totalParts = mesh.parts.size();

View file

@ -191,6 +191,11 @@ public:
const std::unordered_set<int>& getCauterizeBoneSet() const { return _cauterizeBoneSet; } const std::unordered_set<int>& getCauterizeBoneSet() const { return _cauterizeBoneSet; }
void setCauterizeBoneSet(const std::unordered_set<int>& boneSet) { _cauterizeBoneSet = boneSet; } void setCauterizeBoneSet(const std::unordered_set<int>& boneSet) { _cauterizeBoneSet = boneSet; }
int getBlendshapeCoefficientsNum() const { return _blendshapeCoefficients.size(); }
float getBlendshapeCoefficient(int index) const {
return ((index < 0) && (index >= _blendshapeCoefficients.size())) ? 0.0f : _blendshapeCoefficients.at(index);
}
protected: protected:
void setPupilDilation(float dilation) { _pupilDilation = dilation; } void setPupilDilation(float dilation) { _pupilDilation = dilation; }

View file

@ -24,6 +24,11 @@
#define OGLPLUS_NO_SITE_CONFIG 1 #define OGLPLUS_NO_SITE_CONFIG 1
#define OGLPLUS_LOW_PROFILE 1 #define OGLPLUS_LOW_PROFILE 1
// NOTE: oglplus does some naked "#pragma GCC" without proper platform wrapping, so we need to disable this warning.
#ifdef _WIN32
#pragma warning(push)
#pragma warning( disable : 4068 )
#endif
#include <oglplus/gl.hpp> #include <oglplus/gl.hpp>
#include <oglplus/all.hpp> #include <oglplus/all.hpp>
@ -34,6 +39,10 @@
#include <oglplus/shapes/wrapper.hpp> #include <oglplus/shapes/wrapper.hpp>
#include <oglplus/shapes/plane.hpp> #include <oglplus/shapes/plane.hpp>
#ifdef _WIN32
#pragma warning(pop)
#endif
#include "NumericalConstants.h" #include "NumericalConstants.h"
using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>; using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;

View file

@ -1,9 +0,0 @@
//
// Created by Bradley Austin Davis
// 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
//
#include "MatrixStack.h"

View file

@ -1,10 +0,0 @@
//
// Created by Bradley Austin Davis on 2015/09/10
// Copyright 2013-2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ReadWriteLockable.h"

View file

@ -93,10 +93,6 @@ template <typename T>
void testByteCountCoded() { void testByteCountCoded() {
testByteCountCodedStable<T>(0); testByteCountCodedStable<T>(0);
testByteCountCodedStable<T>(1); testByteCountCodedStable<T>(1);
// These two can't possibly be right. TODO: figure out what was being tested, here
// testByteCountCodedStable<T>(1 << 8*sizeof(T));
// testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 8*sizeof(T));
testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 8);
testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 1); testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 1);
testByteCountCodedStable<T>(std::numeric_limits<T>::max()); testByteCountCodedStable<T>(std::numeric_limits<T>::max());
} }

View file

@ -175,8 +175,6 @@ public:
} }
void draw() { void draw() {
static auto startTime = usecTimestampNow();
if (!isVisible()) { if (!isVisible()) {
return; return;
} }
@ -192,7 +190,7 @@ public:
glm::vec3 unitscale { 1.0f }; glm::vec3 unitscale { 1.0f };
glm::vec3 up { 0.0f, 1.0f, 0.0f }; glm::vec3 up { 0.0f, 1.0f, 0.0f };
glm::vec3 camera_position { 1.5f * sinf(t), 0.0f, 1.5f * cos(t) }; glm::vec3 camera_position { 1.5f * sinf(t), 0.0f, 1.5f * cosf(t) };
static const vec3 camera_focus(0); static const vec3 camera_focus(0);
static const vec3 camera_up(0, 1, 0); static const vec3 camera_up(0, 1, 0);
@ -251,9 +249,9 @@ public:
static auto startUsecs = usecTimestampNow(); static auto startUsecs = usecTimestampNow();
float seconds = getSeconds(startUsecs); float seconds = getSeconds(startUsecs);
seconds /= 4.0; seconds /= 4.0f;
int shapeIndex = ((int)seconds) % 4; int shapeIndex = ((int)seconds) % 4;
bool wire = seconds - floor(seconds) > 0.5f; bool wire = seconds - (float)floor(seconds) > 0.5f;
batch.setModelTransform(Transform()); batch.setModelTransform(Transform());
batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f);