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,
// check if there are static assignments that we need to throw into the assignment queue
QHash<QUuid, SharedAssignmentPointer> staticHashCopy = _allAssignments;
QHash<QUuid, SharedAssignmentPointer>::iterator staticAssignment = staticHashCopy.begin();
while (staticAssignment != staticHashCopy.end()) {
auto sharedAssignments = _allAssignments.values();
// 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
// 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
refreshStaticAssignmentAndAddToQueue(*staticAssignment);
}

View file

@ -1320,7 +1320,7 @@ PropertiesTool = function(opts) {
if (data.action == "moveSelectionToGrid") {
if (selectionManager.hasSelection()) {
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 };
for (var i = 0; i < selectionManager.selections.length; 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>
<head>
<title>Properties</title>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="css/colpick.css">
<script src="jquery-2.1.4.min.js"></script>
@ -961,7 +962,7 @@
</div>
<div id="id" class="property">
<span class="label" style="float: left; margin-right: 6px">
<label>ID: <label>
<label>ID: </label>
</span>
<div class="value">
<span id="property-id" class="selectable"></span>
@ -970,7 +971,7 @@
<div class="property">
<span class="label" style="float: left; margin-right: 6px">Name</span>
<div class="value" style="overflow: hidden;">
<input type="text" id="property-name"></input>
<input type="text" id="property-name">
</div>
</div>
@ -1003,13 +1004,13 @@
<div class="property">
<div class="label">Href</div>
<div class="value">
<input id="property-hyperlink-href" class="url"></input>
<input id="property-hyperlink-href" class="url">
</div>
</div>
<div class="property">
<div class="label">Description</div>
<div class="value">
<input id="property-hyperlink-description" class="url"></input>
<input id="property-hyperlink-description" class="url">
</div>
</div>
@ -1021,9 +1022,9 @@
<div class="property">
<div class="label">Position</div>
<div class="value">
<div class="input-area">X <br><input class="coord" type='number' id="property-pos-x"></input></div>
<div class="input-area">Y <br><input class="coord" type='number' id="property-pos-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-pos-z"></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"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-pos-z"></div>
<div>
<input type="button" id="move-selection-to-grid" value="Selection to Grid">
<input type="button" id="move-all-to-grid" value="All to Grid">
@ -1034,26 +1035,26 @@
<div class="property">
<div class="label">Registration</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-reg-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-reg-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-reg-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-reg-z"></div>
</div>
</div>
<div class="property">
<div class="label">Dimensions</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-dim-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-dim-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-dim-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-dim-z"></div>
<div>
<input type="button" id="reset-to-natural-dimensions" value="Reset to Natural Dimensions">
</div>
<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>
<span>
<input type="button" id="dimension-rescale-button" value="Rescale"></input>
<input type="button" id="dimension-rescale-button" value="Rescale">
</span>
</div>
</div>
@ -1061,9 +1062,9 @@
<div class="poly-vox-section property">
<div class="label">Voxel Volume Size</div>
<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">Y <br><input class="coord" type='number' id="property-voxel-volume-size-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></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"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-voxel-volume-size-z"></div>
</div>
<div class="label">Surface Extractor</div>
@ -1078,26 +1079,26 @@
<div class="label">X-axis Texture URL</div>
<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 class="label">Y-axis Texture URL</div>
<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 class="label">Z-axis Texture URL</div>
<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 class="property">
<div class="label">Rotation</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-rot-x"></input></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-rot-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"></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"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-rot-z"></div>
</div>
</div>
@ -1109,66 +1110,66 @@
<div class="property">
<div class="label">Linear Velocity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lvel-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lvel-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lvel-z"></div>
</div>
</div>
<div class="property">
<div class="label">Linear Damping</div>
<div class="value">
<input class="coord" type='number' id="property-ldamping"></input>
<input class="coord" type='number' id="property-ldamping">
</div>
</div>
<div class="property">
<div class="label">Angular Velocity</div>
<div class="value">
<div class="input-area">Pitch <input class="coord" type='number' id="property-avel-x"></input></div>
<div class="input-area">Yaw <input class="coord" type='number' id="property-avel-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></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"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-avel-z"></div>
</div>
</div>
<div class="property">
<div class="label">Angular Damping</div>
<div class="value">
<input class="coord" type='number' id="property-adamping"></input>
<input class="coord" type='number' id="property-adamping">
</div>
</div>
<div class="property">
<div class="label">Restitution</div>
<div class="value">
<input class="coord" type='number' id="property-restitution"></input>
<input class="coord" type='number' id="property-restitution">
</div>
</div>
<div class="property">
<div class="label">Friction</div>
<div class="value">
<input class="coord" type='number' id="property-friction"></input>
<input class="coord" type='number' id="property-friction">
</div>
</div>
<div class="property">
<div class="label">Gravity</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-grav-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-grav-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-grav-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-grav-z"></div>
</div>
</div>
<div class="property">
<div class="label">Acceleration</div>
<div class="value">
<div class="input-area">X <input class="coord" type='number' id="property-lacc-x"></input></div>
<div class="input-area">Y <input class="coord" type='number' id="property-lacc-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lacc-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-lacc-z"></div>
</div>
</div>
<div class="property">
<div class="label">Density</div>
<div>
<input type='number' id="property-density"></input>
<input type='number' id="property-density">
</div>
</div>
@ -1176,9 +1177,9 @@
<div class="label">Color</div>
<div class="value">
<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">G <input class="coord" type='number' id="property-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></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"></div>
<div class="input-area">B <input class="coord" type='number' id="property-color-blue"></div>
</div>
</div>
@ -1190,38 +1191,38 @@
<div class="property">
<span class="label">Ignore For Collisions</span>
<span class="value">
<input type='checkbox' id="property-ignore-for-collisions"></input>
<input type='checkbox' id="property-ignore-for-collisions">
</span>
</div>
<div class="property">
<span class="label">Collisions Will Move</span>
<span class="value">
<input type='checkbox' id="property-collisions-will-move"></input>
<input type='checkbox' id="property-collisions-will-move">
</span>
</div>
<div class="property">
<div class="label">Collision Sound URL</div>
<div class="value">
<input id="property-collision-sound-url" class="url"></input>
<input id="property-collision-sound-url" class="url">
</div>
</div>
<div class="property">
<div class="label">Lifetime</div>
<div class="value">
<input type='number' id="property-lifetime"></input>
<input type='number' id="property-lifetime">
</div>
</div>
<div class="property">
<div class="label">Script URL
<input type="hidden" id="property-script-timestamp" class="value"></input>
<input type="button" id="reload-script-button" value="Reload"></input>
<input type="hidden" id="property-script-timestamp" class="value">
<input type="button" id="reload-script-button" value="Reload">
</div>
<div class="value">
<input id="property-script-url" class="url"></input>
<input id="property-script-url" class="url">
</div>
</div>
@ -1233,14 +1234,14 @@
<div class="model-section property">
<div class="label">Model URL</div>
<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 class="model-section zone-section property">
<div class="label">Shape Type</div>
<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='box'>box</option>
<option value='sphere'>sphere</option>
@ -1251,13 +1252,13 @@
<div class="model-section zone-section property">
<div class="label">Compound Shape URL</div>
<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 class="model-section property">
<div class="label">Animation URL</div>
<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 class="model-section property">
@ -1269,13 +1270,13 @@
<div class="model-section property">
<div class="label">Animation FPS</div>
<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 class="model-section property">
<div class="label">Animation Frame</div>
<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 class="model-section property">
@ -1305,7 +1306,7 @@
<div class="web-section property">
<div class="label">Source URL</div>
<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>
@ -1317,45 +1318,45 @@
<div class="particle-section property">
<div class="label">Max Particles</div>
<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 class="particle-section property">
<div class="label">Particle Life Span</div>
<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 class="particle-section property">
<div class="label">Particle Emission Rate</div>
<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 class="particle-section property">
<div class="label">Particle Emission Direction</div>
<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">Y <input class="coord" type='number' id="property-particle-emit-direction-y"></input></div>
<div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></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"></div>
<div class="input-area">Z <input class="coord" type='number' id="property-particle-emit-direction-z"></div>
</div>
</div>
<div class="particle-section property">
<div class="label">Particle Emission Strength</div>
<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 class="particle-section property">
<div class="label">Particle Local Gravity</div>
<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 class="particle-section property">
<div class="label">Particle Radius</div>
<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>
@ -1367,31 +1368,31 @@
<div class="text-section property">
<div class="label">Text Content</div>
<div class="value">
<input type="text" id="property-text-text"></input>
<input type="text" id="property-text-text">
</div>
</div>
<div class="text-section property">
<div class="label">Line Height</div>
<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 class="text-section property">
<div class="label">Text Color</div>
<div class="value">
<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">G <input class="coord" type='number' id="property-text-text-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></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"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-text-color-blue"></div>
</div>
</div>
<div class="text-section property">
<div class="label">Background Color</div>
<div class="value">
<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">G <input class="coord" type='number' id="property-text-background-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></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"></div>
<div class="input-area">B <input class="coord" type='number' id="property-text-background-color-blue"></div>
</div>
</div>
@ -1410,27 +1411,27 @@
<div class="label">Color</div>
<div class="value">
<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">G <input class="coord" type='number' id="property-light-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></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"></div>
<div class="input-area">B <input class="coord" type='number' id="property-light-color-blue"></div>
</div>
</div>
<div class="light-section property">
<div class="label">Intensity</div>
<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 class="light-section property">
<div class="label">Spot Light Exponent</div>
<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 class="light-section property">
<div class="label">Spot Light Cutoff (degrees)</div>
<div class="value">
<input class="coord" type='number' id="property-light-cutoff"></input>
<input class="coord" type='number' id="property-light-cutoff">
</div>
</div>
@ -1450,48 +1451,48 @@
<div class="label">Key Light Color</div>
<div class="value">
<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">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">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">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"></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 class="zone-section property">
<div class="label">Key Light Intensity</div>
<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 class="zone-section property">
<div class="label">Key Light Ambient Intensity</div>
<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 class="zone-section property">
<div class="label">Key Light Direction</div>
<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">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></input></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></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"></div>
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></div>
</div>
</div>
<div class="zone-section property">
<div class="label">Stage Latitude</div>
<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 class="zone-section property">
<div class="label">Stage Longitude</div>
<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 class="zone-section property">
<div class="label">Stage Altitude</div>
<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>
@ -1505,20 +1506,20 @@
<div class="zone-section property">
<div class="label">Stage Day</div>
<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 class="zone-section property">
<div class="label">Stage Hour</div>
<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 class="zone-section property">
<div class="label">Background Mode</div>
<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='skybox'>Skybox</option>
<option value='atmosphere'>Atmosphere</option>
@ -1535,15 +1536,15 @@
<div class="label">Skybox Color</div>
<div class="value">
<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">G <input class="coord" type='number' id="property-zone-skybox-color-green"></input></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></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"></div>
<div class="input-area">B <input class="coord" type='number' id="property-zone-skybox-color-blue"></div>
</div>
</div>
<div class="zone-section skybox-section property">
<div class="label">Skybox URL</div>
<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>
@ -1555,9 +1556,9 @@
<div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Center</div>
<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">Y <br><input class="coord" type='number' id="property-zone-atmosphere-center-y"></input></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-zone-atmosphere-center-z"></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"></div>
<div class="input-area">Z <br><input class="coord" type='number' id="property-zone-atmosphere-center-z"></div>
<div>
<input type="button" id="center-atmosphere-in-zone" value="Center to Zone">
</div>
@ -1566,33 +1567,33 @@
<div class="zone-section atmosphere-section property">
<div class="label">Atmosphere Inner Radius</div>
<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 class="zone-section atmosphere-section property">
<div class="label">Atmosphere Outer Radius</div>
<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 class="zone-section atmosphere-section property">
<div class="label">Atmosphere Mie Scattering</div>
<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 class="zone-section atmosphere-section property">
<div class="label">Atmosphere Rayleigh Scattering</div>
<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 class="zone-section atmosphere-section property">
<div class="label">Atmosphere Scattering Wavelenghts</div>
<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">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">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">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"></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 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
// part of bubblewand
//
// Script Type: Entity Spawner
// Created by James B. Pollack @imgntn -- 09/03/2015
// 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.
// 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");
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
//create the wand in front of the avatar
var wandModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx?" + randInt(0, 10000);
var scriptURL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/wand.js?" + randInt(1, 100500)
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
//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({
type: "Model",
modelURL: wandModel,
position: center,
dimensions: {
x: 0.1,
y: 1,
z: 0.1
},
//must be enabled to be grabbable in the physics engine
collisionsWillMove: true,
shapeType: 'box',
script: scriptURL
});
function cleanup() {
Entities.deleteEntity(wand);
}
Script.scriptEnding.connect(cleanup);
name: 'Bubble Wand',
type: "Model",
modelURL: WAND_MODEL,
position: center,
gravity: {
x: 0,
y: 0,
z: 0,
},
dimensions: {
x: 0.05,
y: 0.25,
z: 0.05
},
//must be enabled to be grabbable in the physics engine
collisionsWillMove: true,
compoundShapeURL: WAND_COLLISION_SHAPE,
script: WAND_SCRIPT_URL
});

View file

@ -1,317 +1,203 @@
// wand.js
// part of bubblewand
//
// Script Type: Entity Script
// Created by James B. Pollack @imgntn -- 09/03/2015
// 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.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
function convertRange(value, r1, r2) {
return (value - r1[0]) * (r2[1] - r2[0]) / (r1[1] - r1[0]) + r2[0];
}
/*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 */
(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");
(function () {
var bubbleModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
var bubbleScript = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/bubble.js?' + randInt(1, 10000);
var popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
Script.include("../../utilities.js");
Script.include("../../libraries/utils.js");
var TARGET_SIZE = 0.4;
var TARGET_COLOR = {
red: 128,
green: 128,
blue: 128
};
var TARGET_COLOR_HIT = {
red: 0,
green: 255,
blue: 0
var BUBBLE_MODEL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
var BUBBLE_INITIAL_DIMENSIONS = {
x: 0.01,
y: 0.01,
z: 0.01
};
var HAND_SIZE = 0.25;
var leftCubePosition = MyAvatar.getLeftPalmPosition();
var rightCubePosition = MyAvatar.getRightPalmPosition();
var BUBBLE_LIFETIME_MIN = 3;
var BUBBLE_LIFETIME_MAX = 8;
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", {
position: leftCubePosition,
size: HAND_SIZE,
color: {
red: 0,
green: 0,
blue: 255
},
alpha: 1,
solid: false
});
//this helps us get the time passed since the last function call, for use in velocity calculations
function interval() {
var lastTime = new Date().getTime() / 1000;
var rightHand = Overlays.addOverlay("cube", {
position: rightCubePosition,
size: HAND_SIZE,
color: {
red: 255,
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;
return function getInterval() {
var newTime = new Date().getTime() / 1000;
var delta = newTime - lastTime;
lastTime = newTime;
return delta;
};
}
var checkInterval = interval();
var BUBBLE_GRAVITY = {
x: 0,
y: -0.05,
z: 0
function BubbleWand() {
return;
}
var wandEntity = this;
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: [],
BubbleWand.prototype = {
timePassed: null,
currentBubble: null,
update: function() {
BubbleWand.internalUpdate();
preload: function (entityID) {
this.entityID = entityID;
},
internalUpdate: function() {
var _t = this;
//get the current position of the wand
var properties = Entities.getEntityProperties(wandEntity.entityID);
getWandTipPosition: function (properties) {
//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 upVector = Quat.getUp(properties.rotation);
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;
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, {
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)
var velocityStrength = Vec3.length(velocity);
//store the last position of the wand for velocity calculations
_t.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
}
this.lastPosition = wandPosition;
//actually grow the bubble
var dimensions = Entities.getEntityProperties(_t.currentBubble).dimensions;
if (velocityStrength > 1 || convertedVolume > 1) {
var dimensions = Entities.getEntityProperties(this.currentBubble, "dimensions").dimensions;
if (velocityStrength > VELOCITY_THRESHOLD) {
//add some variation in bubble sizes
var bubbleSize = randInt(1, 5);
bubbleSize = bubbleSize / 10;
var bubbleSize = randFloat(BUBBLE_SIZE_MIN, BUBBLE_SIZE_MAX);
//release the bubble if its dimensions are bigger than the bubble size
if (dimensions.x > bubbleSize) {
//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.
// Script.setTimeout(function() {
// _t.burstBubbleSound(_t.currentBubble)
// }, lifetime * 1000)
//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
//edit the bubble properties at release
Entities.editEntity(this.currentBubble, {
velocity: velocity,
lifetime: lifetime,
gravity: this.randomizeBubbleGravity()
});
//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
BubbleWand.spawnBubble();
return
this.createBubbleAtTipOfWand();
return;
} else {
if (mouthMode) {
dimensions.x += 0.015 * convertedVolume;
dimensions.y += 0.015 * convertedVolume;
dimensions.z += 0.015 * convertedVolume;
} else {
dimensions.x += 0.015 * velocityStrength;
dimensions.y += 0.015 * velocityStrength;
dimensions.z += 0.015 * velocityStrength;
}
//grow small bubbles
dimensions.x += GROWTH_FACTOR * velocityStrength;
dimensions.y += GROWTH_FACTOR * velocityStrength;
dimensions.z += GROWTH_FACTOR * velocityStrength;
}
} else {
if (dimensions.x >= 0.02) {
dimensions.x -= 0.001;
dimensions.y -= 0.001;
dimensions.z -= 0.001;
// if the wand is not moving, make the current bubble smaller
if (dimensions.x >= SHRINK_LOWER_LIMIT) {
dimensions.x -= SHRINK_FACTOR;
dimensions.y -= SHRINK_FACTOR;
dimensions.z -= SHRINK_FACTOR;
}
}
//update the bubble to stay with the wand tip
Entities.editEntity(_t.currentBubble, {
position: _t.wandTipPosition,
//adjust the bubble dimensions
Entities.editEntity(this.currentBubble, {
dimensions: dimensions
});
},
burstBubbleSound: function(bubble) {
//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;
createBubbleAtTipOfWand: function () {
//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
//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(wandEntity.entityID);
var properties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
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
_t.lastPosition = wandTipPosition;
//store the position of the tip for use in velocity calculations
this.lastPosition = wandPosition;
//create a bubble at the wand tip
_t.currentBubble = Entities.addEntity({
this.currentBubble = Entities.addEntity({
name: 'Bubble',
type: 'Model',
modelURL: bubbleModel,
position: wandTipPosition,
dimensions: {
x: 0.01,
y: 0.01,
z: 0.01
},
modelURL: BUBBLE_MODEL,
position: this.getWandTipPosition(properties),
dimensions: BUBBLE_INITIAL_DIMENSIONS,
collisionsWillMove: false,
ignoreForCollisions: true,
gravity: BUBBLE_GRAVITY,
// collisionSoundURL:popSound,
shapeType: "sphere",
script: bubbleScript,
ignoreForCollisions: false,
linearDamping: BUBBLE_LINEAR_DAMPING,
shapeType: "sphere"
});
//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() {
this.spawnBubble();
Script.update.connect(BubbleWand.update);
}
}
releaseGrab: function () {
//delete the current buble and reset state when the wand is released
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
_runningScriptsWidget->setRunningScripts(getRunningScripts());
connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveScripts()));
connect(this, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
@ -2615,20 +2614,19 @@ void Application::updateMyAvatarLookAtPosition() {
bool isLookingAtSomeone = false;
bool isHMD = _avatarUpdate->isHMDMode();
glm::vec3 lookAtSpot;
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
// 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())) {
if (eyeTracker->isTracking() && (isHMD || eyeTracker->isSimulating())) {
// 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) {
glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose();
glm::quat hmdRotation = glm::quat_cast(headPose);
lookAtSpot = _myCamera.getPosition() +
_myAvatar->getOrientation() * (hmdRotation * eyeTracker->getLookAtPosition());
lookAtSpot = _myCamera.getPosition() + _myAvatar->getOrientation() * (hmdRotation * lookAtPosition);
} else {
lookAtSpot = _myAvatar->getHead()->getEyePosition() +
(_myAvatar->getHead()->getFinalOrientationInWorldFrame() * eyeTracker->getLookAtPosition());
lookAtSpot = _myAvatar->getHead()->getEyePosition()
+ (_myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition);
}
} else {
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().lock();
@ -4332,17 +4330,18 @@ void Application::stopAllScripts(bool restart) {
_myAvatar->clearScriptableSettings();
}
void Application::stopScript(const QString &scriptName, bool restart) {
const QString& scriptURLString = QUrl(scriptName).toString();
if (_scriptEnginesHash.contains(scriptURLString)) {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURLString];
bool Application::stopScript(const QString& scriptHash, bool restart) {
bool stoppedScript = false;
if (_scriptEnginesHash.contains(scriptHash)) {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash];
if (restart) {
auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(scriptName);
scriptCache->deleteScript(QUrl(scriptHash));
connect(scriptEngine, SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&)));
}
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
// 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.
@ -4351,6 +4350,7 @@ void Application::stopScript(const QString &scriptName, bool restart) {
if (_scriptEnginesHash.empty()) {
_myAvatar->clearScriptableSettings();
}
return stoppedScript;
}
void Application::reloadAllScripts() {

View file

@ -292,7 +292,7 @@ public:
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
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);
@ -392,7 +392,7 @@ public slots:
void reloadScript(const QString& scriptName, bool isUserLoaded = true);
void scriptFinished(const QString& scriptName);
void stopAllScripts(bool restart = false);
void stopScript(const QString& scriptName, bool restart = false);
bool stopScript(const QString& scriptHash, bool restart = false);
void reloadAllScripts();
void reloadOneScript(const QString& scriptName);
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 blueColor(0.0f, 0.0f, 1.0f); // Color the hand targets red to be different than skin
const glm::vec3 grayColor(0.5f);
const int NUM_FACETS = 8;
const float SPHERE_RADIUS = 0.03f * avatarScale;
gpu::Batch& batch = *renderArgs->_batch;

View file

@ -110,6 +110,8 @@ public:
Q_INVOKABLE float getHeadFinalRoll() const { return getHead()->getFinalRoll(); }
Q_INVOKABLE float getHeadFinalPitch() const { return getHead()->getFinalPitch(); }
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(); }

View file

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

View file

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

View file

@ -57,16 +57,15 @@ RunningScriptsWidget::RunningScriptsWidget(QWidget* parent) :
connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &RunningScriptsWidget::updateFileFilter);
connect(ui->scriptTreeView, &QTreeView::doubleClicked, this, &RunningScriptsWidget::loadScriptFromList);
connect(ui->reloadAllButton, &QPushButton::clicked,
Application::getInstance(), &Application::reloadAllScripts);
connect(ui->stopAllButton, &QPushButton::clicked,
this, &RunningScriptsWidget::allScriptsStopped);
connect(ui->loadScriptFromDiskButton, &QPushButton::clicked,
Application::getInstance(), &Application::loadDialog);
connect(ui->loadScriptFromURLButton, &QPushButton::clicked,
Application::getInstance(), &Application::loadScriptURLDialog);
connect(&_reloadSignalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(reloadOneScript(const QString&)));
connect(&_stopSignalMapper, SIGNAL(mapped(QString)), Application::getInstance(), SLOT(stopScript(const QString&)));
connect(ui->reloadAllButton, &QPushButton::clicked, Application::getInstance(), &Application::reloadAllScripts);
connect(ui->stopAllButton, &QPushButton::clicked, this, &RunningScriptsWidget::allScriptsStopped);
connect(ui->loadScriptFromDiskButton, &QPushButton::clicked, Application::getInstance(), &Application::loadDialog);
connect(ui->loadScriptFromURLButton, &QPushButton::clicked, Application::getInstance(), &Application::loadScriptURLDialog);
connect(&_reloadSignalMapper, static_cast<void(QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped),
Application::getInstance(), &Application::reloadOneScript);
connect(&_stopSignalMapper, static_cast<void(QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped),
[](const QString& script) { Application::getInstance()->stopScript(script); });
UIUtil::scaleWidgetFontSizes(this);
}
@ -217,9 +216,6 @@ void RunningScriptsWidget::keyPressEvent(QKeyEvent *keyEvent) {
}
}
void RunningScriptsWidget::scriptStopped(const QString& scriptName) {
}
void RunningScriptsWidget::allScriptsStopped() {
Application::getInstance()->stopAllScripts();
}
@ -227,15 +223,16 @@ void RunningScriptsWidget::allScriptsStopped() {
QVariantList RunningScriptsWidget::getRunning() {
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
QVariantList result;
QStringList runningScripts = Application::getInstance()->getRunningScripts();
for (int i = 0; i < runningScripts.size(); i++) {
QUrl runningScriptURL = QUrl(runningScripts.at(i));
foreach(const QString& runningScript, Application::getInstance()->getRunningScripts()) {
QUrl runningScriptURL = QUrl(runningScript);
if (runningScriptURL.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
runningScriptURL = QUrl::fromLocalFile(runningScriptURL.toDisplayString(QUrl::FormattingOptions(QUrl::FullyEncoded)));
}
QVariantMap resultNode;
resultNode.insert("name", runningScriptURL.fileName());
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());
result.append(resultNode);
}
@ -294,3 +291,16 @@ QVariantList RunningScriptsWidget::getLocal() {
}
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; }
signals:
void stopScriptName(const QString& name, bool restart = false);
void scriptStopped(const QString& scriptName);
protected:
virtual bool eventFilter(QObject* sender, QEvent* event);
@ -45,10 +45,11 @@ protected:
virtual void showEvent(QShowEvent* event);
public slots:
void scriptStopped(const QString& scriptName);
QVariantList getRunning();
QVariantList getPublic();
QVariantList getLocal();
bool stopScript(const QString& name, bool restart = false);
bool stopScriptByName(const QString& name);
private slots:
void allScriptsStopped();
@ -63,9 +64,6 @@ private:
QSignalMapper _stopSignalMapper;
ScriptsModelFilter _scriptsModelFilter;
ScriptsModel _scriptsModel;
ScriptsTableWidget* _recentlyLoadedScriptsTable;
QStringList _recentlyLoadedScripts;
QString _lastStoppedScript;
QVariantList getPublicChildNodes(TreeNodeFolder* parent);
};

View file

@ -97,7 +97,8 @@ bool ScriptEditorWidget::setRunning(bool run) {
if (run) {
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::errorMessage, this, &ScriptEditorWidget::onScriptError);
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 SLICE_ANGLE = FULL_CIRCLE / SLICES;
//const int slices = 15;
xColor colorX = getColor();
const float MAX_COLOR = 255.0f;
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
}
const int SLICES = 15;
float alpha = getAlpha();
xColor color = getColor();
const float MAX_COLOR = 255.0f;

View file

@ -29,11 +29,7 @@
#include <OffscreenQmlSurface.h>
// #include "Application.h"
// #include "GeometryUtil.h"
static const float DPI = 30.47f;
static const float METERS_TO_INCHES = 39.3701f;
static const float INCHES_TO_METERS = 1.0f / 39.3701f;
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())));
if (_skeleton->getNumJoints() == (int)poses.size()) {
_relativePoses = poses;
_accumulators.resize(_relativePoses.size());
} else {
_relativePoses.clear();
_accumulators.clear();
}
}
@ -82,22 +84,8 @@ static int findRootJointInSkeleton(AnimSkeleton::ConstPointer skeleton, int inde
return rootIndex;
}
struct IKTarget {
AnimPose pose;
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;
void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets) {
// build a list of valid targets from _targetVarVec and animVars
bool removeUnfoundJoints = false;
for (auto& targetVar : _targetVarVec) {
if (targetVar.jointIndex == -1) {
@ -113,15 +101,13 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
}
} else {
// TODO: get this done without a double-lookup of each var in animVars
if (animVars.hasKey(targetVar.positionVar) || animVars.hasKey(targetVar.rotationVar)) {
IKTarget target;
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses);
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
target.rootIndex = targetVar.rootIndex;
target.index = targetVar.jointIndex;
targets.push_back(target);
}
IKTarget target;
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses);
target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans);
target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
target.rootIndex = targetVar.rootIndex;
target.index = targetVar.jointIndex;
targets.push_back(target);
}
}
@ -141,154 +127,160 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
}
}
}
}
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 {
// clear the accumulators before we start the IK solver
for (auto& accumulatorPair: _accumulators) {
accumulatorPair.second.clear();
}
void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vector<IKTarget>& targets) {
// compute absolute poses that correspond to relative target poses
AnimPoseVec absolutePoses;
computeAbsolutePoses(absolutePoses);
// compute absolute poses that correspond to relative target poses
AnimPoseVec absolutePoses;
computeAbsolutePoses(absolutePoses);
// clear the accumulators before we start the IK solver
for (auto& accumulator: _accumulators) {
accumulator.clearAndClean();
}
float largestError = 0.0f;
const float ACCEPTABLE_RELATIVE_ERROR = 1.0e-3f;
int numLoops = 0;
const int MAX_IK_LOOPS = 16;
const quint64 MAX_IK_TIME = 10 * USECS_PER_MSEC;
quint64 expiry = usecTimestampNow() + MAX_IK_TIME;
do {
largestError = 0.0f;
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
float largestError = 0.0f;
const float ACCEPTABLE_RELATIVE_ERROR = 1.0e-3f;
int numLoops = 0;
const int MAX_IK_LOOPS = 16;
const quint64 MAX_IK_TIME = 10 * USECS_PER_MSEC;
quint64 expiry = usecTimestampNow() + MAX_IK_TIME;
do {
largestError = 0.0f;
int lowestMovedIndex = _relativePoses.size();
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.
AnimPose targetPose = target.pose;
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);
}
}
_relativePoses[tipIndex].rot = newRelativeRotation;
absolutePoses[tipIndex].rot = targetPose.rot;
pivotIndex = _skeleton->getParentIndex(pivotIndex);
}
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;
@ -309,7 +301,11 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
int numJoints = (int)_relativePoses.size();
for (int i = 0; i < numJoints; ++i) {
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);
@ -652,18 +648,3 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
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;
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);
// for AnimDebugDraw rendering
virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }
void relaxTowardDefaults(float dt);
RotationConstraint* getConstraint(int index);
void clearConstraints();
void initConstraints();
@ -64,7 +70,7 @@ protected:
};
std::map<int, RotationConstraint*> _constraints;
std::map<int, RotationAccumulator> _accumulators;
std::vector<RotationAccumulator> _accumulators;
std::vector<IKTargetVar> _targetVarVec;
AnimPoseVec _defaultRelativePoses; // poses of the relaxed state
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
void addChild(Pointer child) { _children.push_back(child); }
void removeChild(Pointer child) {
auto iter = std::find(_children.begin(), _children.end(), child);
if (iter != _children.end()) {
_children.erase(iter);
}
}
Pointer getChild(int i) const {
assert(i >= 0 && i < (int)_children.size());
return _children[i];
}
void removeChild(Pointer child);
Pointer getChild(int i) const;
int getChildCount() const { return (int)_children.size(); }
// pair this AnimNode graph with a skeleton.
void setSkeleton(const AnimSkeleton::Pointer skeleton) {
setSkeletonInternal(skeleton);
for (auto&& child : _children) {
child->setSkeleton(skeleton);
}
}
void setSkeleton(const AnimSkeleton::Pointer skeleton);
AnimSkeleton::ConstPointer getSkeleton() const { return _skeleton; }
@ -87,19 +75,14 @@ public:
return evaluate(animVars, dt, triggersOut);
}
const AnimPose getRootPose(int jointIndex) const;
protected:
void setCurrentFrame(float frame) {
setCurrentFrameInternal(frame);
for (auto&& child : _children) {
child->setCurrentFrameInternal(frame);
}
}
void setCurrentFrame(float frame);
virtual void setCurrentFrameInternal(float frame) {}
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) {
_skeleton = skeleton;
}
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) { _skeleton = skeleton; }
// for AnimDebugDraw rendering
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) {
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.
glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) *
glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) *
glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS));
_animVars.set("headRotation", realLocalHeadOrientation);
// There's a theory that when not in hmd, we should _animVars.unset("headPosition").
// However, until that works well, let's always request head be positioned where requested by hmd, camera, or default.
_animVars.set("headPosition", params.localHeadPosition);
if (params.isInHMD) {
int headIndex = _animSkeleton->nameToJointIndex("Head");
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) {
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) {
if (_enableAnimGraph && _animSkeleton) {
if (_enableAnimGraph && _animSkeleton && _animNode) {
// 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));
int leftHandIndex = _animSkeleton->nameToJointIndex("LeftHand");
AnimPose rootPose = _animNode->getRootPose(leftHandIndex);
if (params.isLeftEnabled) {
_animVars.set("leftHandPosition", yFlipHACK * params.leftPosition);
_animVars.set("leftHandRotation", yFlipHACK * params.leftOrientation);
_animVars.set("leftHandPosition", rootPose.trans + rootPose.rot * yFlipHACK * params.leftPosition);
_animVars.set("leftHandRotation", rootPose.rot * yFlipHACK * params.leftOrientation);
} else {
_animVars.unset("leftHandPosition");
_animVars.unset("leftHandRotation");
}
if (params.isRightEnabled) {
_animVars.set("rightHandPosition", yFlipHACK * params.rightPosition);
_animVars.set("rightHandRotation", yFlipHACK * params.rightOrientation);
_animVars.set("rightHandPosition", rootPose.trans + rootPose.rot * yFlipHACK * params.rightPosition);
_animVars.set("rightHandRotation", rootPose.rot * yFlipHACK * params.rightOrientation);
} else {
_animVars.unset("rightHandPosition");
_animVars.unset("rightHandRotation");

View file

@ -11,17 +11,23 @@
#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)
_rotationSum += copysignf(1.0f, glm::dot(_rotationSum, rotation)) * rotation;
++_numRotations;
_isDirty = true;
}
glm::quat RotationAccumulator::getAverage() {
return (_numRotations > 0) ? glm::normalize(_rotationSum) : glm::quat();
}
void RotationAccumulator::clear() {
void RotationAccumulator::clear() {
_rotationSum *= 0.0f;
_numRotations = 0;
}
void RotationAccumulator::clearAndClean() {
clear();
_isDirty = false;
}

View file

@ -14,19 +14,27 @@
class RotationAccumulator {
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; }
void add(glm::quat rotation);
void add(const glm::quat& rotation);
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();
/// \brief clear accumulated rotation and set _isDirty to false
void clearAndClean();
private:
glm::quat _rotationSum;
int _numRotations;
bool _isDirty;
};
#endif // hifi_RotationAccumulator_h

View file

@ -25,8 +25,8 @@ void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, Render
gpu::Batch& batch = *args->_batch;
auto shapeTransform = entity->getTransformToCenter();
if (puffedOut != 0.0) {
shapeTransform.postScale(1.0 + puffedOut);
if (puffedOut != 0.0f) {
shapeTransform.postScale(1.0f + puffedOut);
}
batch.setModelTransform(Transform()); // we want to include the scale as well
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);
}
} 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,
QString("")};
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);
foreach (const FBXNode& subobject, object.children) {
bool properties = false;
QByteArray propertyName;

View file

@ -136,6 +136,16 @@ public:
class FBXMaterial {
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 specularColor;
glm::vec3 emissiveColor;

View file

@ -487,11 +487,10 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
groupMaterialName = SMART_DEFAULT_MATERIAL_NAME;
}
if (!groupMaterialName.isEmpty()) {
OBJMaterial* material = &materials[groupMaterialName];
// TODO Fix this once the transision is understood
/*// The code behind this is in transition. Some things are set directly in the FXBMeshPart...
OBJMaterial* material = &materials[groupMaterialName];
meshPart.materialID = groupMaterialName;
meshPart.diffuseTexture.filename = material->diffuseTextureFilename;
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);
(void)CHECK_GL_ERROR();
Q_UNUSED(startInstance);
}
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>;
const ElementArray& getDefaultElements() {
static ElementArray defaultElements{
static ElementArray defaultElements{{
//POSITION = 0,
Element::VEC3F_XYZ,
//NORMAL = 1,
@ -42,7 +42,7 @@ const ElementArray& getDefaultElements() {
//INSTANCE_XFM = 10,
// FIXME make a matrix element
Element::VEC4F_XYZW
};
}};
return defaultElements;
}

View file

@ -271,7 +271,7 @@ static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBas
networkMesh->_mesh = mesh._mesh;
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>();
NetworkMaterial* networkMaterial = new NetworkMaterial();
int totalIndices = 0;
bool checkForTexcoordLightmap = false;
//bool checkForTexcoordLightmap = false;
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->emissiveTextureName = material.emissiveTexture.name;
checkForTexcoordLightmap = true;
//checkForTexcoordLightmap = true;
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
@ -493,9 +492,9 @@ void NetworkGeometry::modelParseError(int error, QString str) {
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
if ((shapeID >= 0) && (shapeID < _shapes.size())) {
if ((shapeID >= 0) && (shapeID < (int)_shapes.size())) {
int materialID = _shapes[shapeID]->_materialID;
if ((materialID >= 0) && (materialID < _materials.size())) {
if ((materialID >= 0) && ((unsigned int)materialID < _materials.size())) {
return _materials[materialID].get();
} else {
return 0;

View file

@ -15,18 +15,6 @@
using namespace model;
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() :
_key(0),
_schemaBuffer(),

View file

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

View file

@ -59,7 +59,7 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
int opaquePixels = 0;
int translucentPixels = 0;
bool isTransparent = false;
//bool isTransparent = false;
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
const int EIGHT_BIT_MAXIMUM = 255;
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,
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
isTransparent = (translucentPixels >= imageArea / 2);
//isTransparent = (translucentPixels >= imageArea / 2);
}
gpu::Texture* theTexture = nullptr;
@ -269,7 +269,7 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c
int opaquePixels = 0;
int translucentPixels = 0;
bool isTransparent = false;
//bool isTransparent = false;
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
const int EIGHT_BIT_MAXIMUM = 255;
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,
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
isTransparent = (translucentPixels >= imageArea / 2);
//isTransparent = (translucentPixels >= imageArea / 2);
}
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) {
_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) {
_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) {
_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) {
_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) {
_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) {
_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->getStereoViews(eyeViews);
float halfWidth = 0.5 * sWidth;
float halfWidth = 0.5f * sWidth;
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

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;
static const uint FLOATS_PER_VERTEX = 3;
static const uint VERTICES_PER_TRIANGLE = 3;
static const uint TRIANGLES_PER_QUAD = 2;
static const uint CUBE_FACES = 6;
static const uint CUBE_VERTICES_PER_FACE = 4;
static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE;
static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX;
static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE;
static const uint SPHERE_LATITUDES = 24;
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 int VERTICES_PER_TRIANGLE = 3;
//static const uint FLOATS_PER_VERTEX = 3;
//static const uint TRIANGLES_PER_QUAD = 2;
//static const uint CUBE_FACES = 6;
//static const uint CUBE_VERTICES_PER_FACE = 4;
//static const uint CUBE_VERTICES = CUBE_FACES * CUBE_VERTICES_PER_FACE;
//static const uint CUBE_VERTEX_POINTS = CUBE_VERTICES * FLOATS_PER_VERTEX;
//static const uint CUBE_INDICES = CUBE_FACES * TRIANGLES_PER_QUAD * VERTICES_PER_TRIANGLE;
//static const uint SPHERE_LATITUDES = 24;
//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 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() {
static const float phi = (1.0 + sqrt(5.0)) / 2.0;
static const float a = 0.5;
static const float b = 1.0 / (2.0 * phi);
static const float phi = (1.0f + sqrtf(5.0f)) / 2.0f;
static const float a = 0.5f;
static const float b = 1.0f / (2.0f * phi);
static const VertexVector vertices{ //
vec3(0, b, -a), vec3(-b, a, 0), vec3(b, a, 0), //
@ -152,7 +153,7 @@ const VertexVector& icosahedronVertices() {
}
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 B = vec3(0, -1, 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_OFFSET = 0;
static const size_t NORMAL_OFFSET = 1;
for (size_t i = 0; i < vertices.size(); ++i) {
auto vertexIndex = i;
@ -323,7 +323,7 @@ void GeometryCache::buildShapes() {
20, 21, 21, 22, 22, 23, 23, 20, // back
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;
}
@ -374,7 +374,7 @@ void GeometryCache::buildShapes() {
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;
}

View file

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

View file

@ -191,6 +191,11 @@ public:
const std::unordered_set<int>& getCauterizeBoneSet() const { return _cauterizeBoneSet; }
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:
void setPupilDilation(float dilation) { _pupilDilation = dilation; }

View file

@ -24,6 +24,11 @@
#define OGLPLUS_NO_SITE_CONFIG 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/all.hpp>
@ -34,6 +39,10 @@
#include <oglplus/shapes/wrapper.hpp>
#include <oglplus/shapes/plane.hpp>
#ifdef _WIN32
#pragma warning(pop)
#endif
#include "NumericalConstants.h"
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() {
testByteCountCodedStable<T>(0);
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());
}

View file

@ -175,8 +175,6 @@ public:
}
void draw() {
static auto startTime = usecTimestampNow();
if (!isVisible()) {
return;
}
@ -192,7 +190,7 @@ public:
glm::vec3 unitscale { 1.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_up(0, 1, 0);
@ -251,9 +249,9 @@ public:
static auto startUsecs = usecTimestampNow();
float seconds = getSeconds(startUsecs);
seconds /= 4.0;
seconds /= 4.0f;
int shapeIndex = ((int)seconds) % 4;
bool wire = seconds - floor(seconds) > 0.5f;
bool wire = seconds - (float)floor(seconds) > 0.5f;
batch.setModelTransform(Transform());
batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f);