Merging with master

This commit is contained in:
samcake 2016-04-25 18:48:58 -07:00
commit 5cb346330b
150 changed files with 2532 additions and 1231 deletions

View file

@ -952,6 +952,24 @@ bool OctreeServer::readOptionInt(const QString& optionName, const QJsonObject& s
return optionAvailable;
}
bool OctreeServer::readOptionInt64(const QString& optionName, const QJsonObject& settingsSectionObject, qint64& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = atoll(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString().toLongLong(&optionAvailable);
if (optionAvailable) {
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
}
return optionAvailable;
}
bool OctreeServer::readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
@ -1055,10 +1073,10 @@ void OctreeServer::readConfiguration() {
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
int clockSkew;
if (readOptionInt(QString("clockSkew"), settingsSectionObject, clockSkew)) {
qint64 clockSkew;
if (readOptionInt64(QString("clockSkew"), settingsSectionObject, clockSkew)) {
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkew=%d", clockSkew);
qDebug() << "clockSkew=" << clockSkew;
}
// Check to see if the user passed in a command line option for setting packet send rate

View file

@ -145,6 +145,7 @@ protected:
virtual OctreePointer createTree() = 0;
bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result);
bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result);
bool readOptionInt64(const QString& optionName, const QJsonObject& settingsSectionObject, qint64& result);
bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result);
void readConfiguration();
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { };

View file

@ -7,9 +7,9 @@ endif ()
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple2.zip
URL_MD5 f05d858e8203c32b689da208ad8b39db
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple_1.13.0.zip
URL_MD5 73f833649e904257b35bf4e84f8bdfb5
CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1

View file

@ -404,6 +404,10 @@ var toolBar = (function() {
Window.alert("Can't create " + properties.type + ": " + properties.type + " would be out of bounds.");
}
selectionManager.clearSelections();
entityListTool.sendUpdate();
selectionManager.setSelections([entityID]);
return entityID;
}
@ -1194,6 +1198,30 @@ function deleteSelectedEntities() {
}
}
function toggleSelectedEntitiesLocked() {
if (SelectionManager.hasSelection()) {
var locked = !Entities.getEntityProperties(SelectionManager.selections[0], ["locked"]).locked;
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
Entities.editEntity(entityID, { locked: locked });
}
entityListTool.sendUpdate();
selectionManager._update();
}
}
function toggleSelectedEntitiesVisible() {
if (SelectionManager.hasSelection()) {
var visible = !Entities.getEntityProperties(SelectionManager.selections[0], ["visible"]).visible;
for (var i = 0; i < selectionManager.selections.length; i++) {
var entityID = SelectionManager.selections[i];
Entities.editEntity(entityID, { visible: visible });
}
entityListTool.sendUpdate();
selectionManager._update();
}
}
function handeMenuEvent(menuItem) {
if (menuItem == "Allow Selecting of Small Models") {
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
@ -1522,7 +1550,8 @@ PropertiesTool = function(opts) {
data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS);
}
Entities.editEntity(selectionManager.selections[0], data.properties);
if (data.properties.name != undefined) {
if (data.properties.name !== undefined || data.properties.modelURL !== undefined
|| data.properties.visible !== undefined || data.properties.locked !== undefined) {
entityListTool.sendUpdate();
}
}

View file

@ -63,7 +63,7 @@
}
body {
padding: 24px 12px 24px 12px;
padding: 21px 21px 21px 21px;
color: #afafaf;
background-color: #404040;
@ -164,6 +164,10 @@ tr.selected {
background-color: #00b4ef;
}
tr.selected + tr.selected {
border-top: 1px solid #2e2e2e;
}
th {
text-align: center;
word-wrap: nowrap;
@ -227,6 +231,15 @@ input.search {
border-radius: 14px;
}
input.search:focus {
outline: none;
box-sizing: border-box;
height: 26px;
margin-top: 1px;
margin-bottom: 1px;
box-shadow: 0 0 0px 1px #00b4ef;
}
input:disabled, textarea:disabled {
background-color: #383838;
color: #afafaf;
@ -275,7 +288,9 @@ input[type=number]::-webkit-inner-spin-button:after {
content: "5";
bottom: 6px;
}
input[type="number"]::-webkit-inner-spin-button:hover {
input[type=number].hover-up::-webkit-inner-spin-button:before,
input[type=number].hover-down::-webkit-inner-spin-button:after {
color: #ffffff;
}
@ -294,8 +309,8 @@ input[type=button] {
vertical-align: top;
height: 28px;
min-width: 120px;
padding: 0px 12px;
margin-right: 8px;
padding: 0px 18px;
margin-right: 6px;
border-radius: 5px;
border: none;
color: #fff;
@ -370,6 +385,22 @@ input[type=checkbox]:checked + label:hover {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEySURBVDhPnZLPSsNAEMa/XVPBCE0RhNy0OarP4Av4AD6JB0GwVBA8efBBxHsgh4CQswcRoUIpiIpVAm3zZ5M4szFSbQPBH3xkJvNNZskOer2eLIriKM/ze1JOcS1UHmdZduF5ngEKjr/fN4Z6+oKerwA2gxC4HAFPEWVLsAzgZAvYt3Q6Enw6jg7uBAaTFMNwhpnKdbXCkAJdy8ROu4XrXW2HTJIErHcFDD6nC02Mom8PwymeE2gvS0ZRBBaTlsOXEmdlrfLLOI7Bakrl/zWxCT8T/904f9QW/b06qtrCUdtFCqdjYs2Q2jAPX8c2XQd7Kr/wfV8vwIPs4Ga1ixe5Xrr/YFLTYfKIvWzM6ZtwXZdX7lxXG0L+sxXHcW5t254opRzawQ0S72+dPmjTroIgOP0CQSMt5LDn1T8AAAAASUVORK5CYII=);
}
.icon-input input {
position: relative;
padding-left: 36px;
}
.icon-input span {
position: absolute;
left: 6px;
top: -2px;
font-family: hifi-glyphs;
font-size: 30px;
color: #afafaf;
}
.icon-input input:focus + span {
color: #ffffff;
}
.selectable {
-webkit-touch-callout: text;
-webkit-user-select: text;
@ -396,11 +427,11 @@ input[type=checkbox]:checked + label:hover {
}
.section-header, .sub-section-header {
.section-header, .sub-section-header, hr {
display: table;
width: 100%;
margin: 22px -12px 0 -12px;
padding: 14px 12px 0 12px;
margin: 21px -21px 0 -21px;
padding: 14px 21px 0 21px;
font-family: Raleway-Regular;
font-size: 12px;
color: #afafaf;
@ -414,12 +445,12 @@ input[type=checkbox]:checked + label:hover {
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAqCAIAAAAbNW1vAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAmSURBVChTY1BFAgzhSIDBAQmMcoYHRwIJMCgjAQZ9JMBgBQdWVgBh5XmBV5A2FQAAAABJRU5ErkJggg==) repeat-x top left;
}
.sub-section-header, .no-collapse {
.sub-section-header, .no-collapse, hr {
background: #404040 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAjSURBVBhXY1RVVf3PgARYjIyMoEwIYHRwcEBRwQSloYCBAQCwjgPMiI7W2QAAAABJRU5ErkJggg==) repeat-x top left;
}
.section-header:first-child {
margin-top: 0;
margin-top: -2px;
padding-top: 0;
background: none;
height: auto;
@ -435,11 +466,16 @@ input[type=checkbox]:checked + label:hover {
float: right;
position: absolute;
top: 4px;
right: 6px;
right: 13px;
}
.section-header[collapsed="true"] {
margin-bottom: -22px;
margin-bottom: -21px;
}
hr {
border: none;
padding-top: 2px;
}
.text-group[collapsed="true"] ~ .text-group,
@ -458,20 +494,25 @@ input[type=checkbox]:checked + label:hover {
.property {
display: table;
width: 100%;
margin-top: 22px;
min-height: 29px;
margin-top: 21px;
min-height: 28px;
}
.property.checkbox {
width: auto;
}
.property label {
.property label, .number label {
display: table-cell;
vertical-align: middle;
font-family: Raleway-SemiBold;
font-size: 14px;
}
.property label .unit, .number label .unit {
margin-left: 8px;
font-family: Raleway-Light;
font-size: 13px;
}
.value {
display: block;
@ -499,12 +540,14 @@ input[type=checkbox]:checked + label:hover {
float: left;
}
.property .number + .number {
margin-left: 12px;
margin-left: 10px;
}
.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label {
float: left;
margin-bottom: 4px;
margin-left: 1px;
margin-bottom: 3px;
margin-top: -2px;
}
.number > input {
@ -519,13 +562,6 @@ input[type=checkbox]:checked + label:hover {
clear: both;
}
.unit {
padding-left: 4px;
vertical-align: top;
position: relative;
top: 5px;
}
.dropdown {
position: relative;
margin-bottom: -17px;
@ -544,10 +580,8 @@ input[type=checkbox]:checked + label:hover {
width: 172px;
height: 28px;
padding: 0 28px 0 12px;
color: #afafaf;
background: linear-gradient(#7d7d7d 20%, #686a68 100%);
position: relative;
}
.dropdown dl[dropped="true"] {
@ -606,6 +640,17 @@ input[type=checkbox]:checked + label:hover {
background-color: #00b4ef;
}
.dropdown dl[disabled="disabled"], .dropdown dl[disabled="disabled"][dropped="true"] {
color: #252525;
background: linear-gradient(#575757 20%, #252525 100%);
}
.dropdown dl[disabled="disabled"] dd {
display: none;
}
.dropdown dl[disabled="disabled"] dt:hover {
color: #252525;
}
div.refresh {
box-sizing: border-box;
@ -619,7 +664,7 @@ div.refresh input[type="button"] {
.color-picker {
box-sizing: border-box;
float: left;
margin-bottom: 12px;
margin-bottom: 21px;
width: 36px;
height: 36px;
border: 4px solid #afafaf;
@ -636,32 +681,36 @@ div.refresh input[type="button"] {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABDSURBVChTjcoLCkAhCETRNq0tf97Y5xGZ1gVJ45TH6njThIO+xk2UwhWFcEdH6JCqOuiQiMDi/hcii3crRRb/7ggAPvIMVihQwvSXAAAAAElFTkSuQmCC);
}
.color-picker[disabled="disabled"] {
border-color: #afafaf;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABTSURBVChTjcxBDoAwCETRwTs33sFjwB6uaCE1Ggvav5qQF7CSqu40dllHjYiOT3gh3yV8Ii+Fb+RNMEP9hm3sKENmBhG5P1aImWMH/EMerSAAOAFgTC/R8ZXSXAAAAABJRU5ErkJggg==);
}
.colpick[disabled="disabled"] {
display: none !important;
}
.rgb label {
float: left;
margin-top: 10px;
margin-left: 12px;
margin-left: 21px;
}
.rgb label + * {
clear: both;
}
.tuple {
width: 100%;
text-align: center;
}
.tuple div {
display: inline-block;
position: relative;
min-width: 120px;
min-height: 1px;
margin-right: 6px;
}
.tuple div:nth-child(1) {
float: left;
.tuple div:last-child {
margin-right: 0;
}
.tuple div:nth-child(2) {
}
.tuple div:nth-child(3) {
float: right;
.tuple label {
margin-right: -6px;
}
.rgb .tuple input {
@ -712,31 +761,49 @@ tuple, .blue:focus, .tuple .z:focus, .tuple .roll:focus {
}
.xyz .buttons input {
margin-top: 12px;
margin-top: 14px;
}
.xyz .buttons span {
word-wrap: nowrap;
white-space: nowrap;
}
.row input {
float: left;
.row .property {
width: auto;
display: inline-block;
margin-right: 6px;
}
.row input[type=button] {
margin-left: 8px;
.row .property:last-child {
margin-right: 0;
}
.row .property input {
clear: both;
float: left;
}
.two-column {
display: table;
width: 100%;
}
.two-column > div {
display: table-cell;
width: 50%;
}
.column {
vertical-align: top;
}
.indent {
margin-left: 24px;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background-color: #2e2e2e;
}
::-webkit-scrollbar-thumb {
background-color: #696969;
border: 2px solid #2e2e2e;
@ -760,7 +827,28 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#entity-list-header {
margin-bottom: 24px;
margin-bottom: 36px;
}
#entity-list-header div {
display: inline-block;
width: 65px;
margin-right: 6px;
}
#entity-list-header div input:first-child {
margin-right: 0;
float: left;
width: 33px;
border-right: 1px solid #808080;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
#entity-list-header div input:last-child {
margin-right: 0;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
#delete {
@ -773,6 +861,11 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
position: relative; /* New positioning context. */
}
#entity-list .glyph {
font-family: HiFi-Glyphs;
font-size: 14px;
}
#search-area {
padding-right: 148px;
padding-bottom: 24px;
@ -785,6 +878,8 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
#radius-and-unit {
float: right;
margin-right: -148px;
position: relative;
top: -17px;
}
@ -798,17 +893,39 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
margin-top: 28px;
border-left: 2px solid #575757;
border-right: 2px solid #575757;
}
#entity-table-scroll, #entity-table {
background-color: #1c1c1c;
}
#entity-table {
margin-top: -28px;
margin-bottom: -18px;
table-layout: fixed;
border: none;
background-color: #1c1c1c;
}
#col-type {
width: 16%;
}
#col-name {
width: 34%;
}
#col-url {
width: 34%;
}
#col-locked, #col-visible {
width: 8%;
}
#entity-table thead tr, #entity-table thead tr th,
#entity-table tfoot tr, #entity-table tfoot tr td {
background: none;
}
#entity-table .glyph {
margin: 0 -2px 0 -2px;
vertical-align: middle;
}
#entity-table thead {
@ -817,6 +934,42 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
border-bottom: 1px solid #575757;
position: absolute;
top: 49px;
left: 0;
width: 100%;
}
#entity-table thead th {
box-sizing: border-box;
padding: 0 0 0 8px;
vertical-align: middle;
}
#entity-table th:focus {
outline: none;
}
#entity-table th .glyph {
position: relative;
left: 0;
}
#entity-table thead .sort-order {
display: inline-block;
width: 8px;
margin: -5px 0 -3px 0;
text-align: right;
vertical-align: middle;
}
#entity-table td {
box-sizing: border-box;
}
#entity-table td.glyph {
text-align: center;
padding: 0;
}
#entity-table tfoot {
@ -825,39 +978,6 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
border-top: 1px solid #575757;
}
#entity-table thead tr, #entity-table thead tr th,
#entity-table tfoot tr, #entity-table tfoot tr td {
background: none;
}
#entity-table th:focus {
outline: none;
}
#col-type {
width: 16%;
}
#col-name {
width: 42%;
}
#col-url {
width: 42%;
}
#entity-table thead {
position: absolute;
top: 49px;
left: 0;
width: 100%;
}
#entity-table thead th {
padding: 0;
}
#entity-table tfoot {
position: absolute;
bottom: -21px;
left: 0;
@ -876,25 +996,92 @@ textarea:enabled[scrolling="true"]::-webkit-resizer {
}
#properties-list .property:first-child {
margin-top: 0;
#properties-header {
display: table-row;
height: 28px;
}
#properties-header .property {
display: table-cell;
vertical-align: middle;
}
#properties-header .checkbox {
position: relative;
top: -1px;
}
#properties-header #type-icon {
font-family: hifi-glyphs;
font-size: 31px;
color: #00b4ef;
margin: -4px 12px -4px -2px;
width: auto;
display: none;
vertical-align: middle;
}
#properties-header #property-type {
padding: 5px 24px 5px 0;
border-right: 1px solid #808080;
height: 100%;
width: auto;
display: inline-block;
vertical-align: middle;
}
#properties-header .checkbox:last-child {
padding-left: 24px;
}
#properties-header .checkbox label {
background-position-y: 1px;
}
#properties-header .checkbox label span {
font-family: HiFi-Glyphs;
font-size: 20px;
padding-right: 6px;
vertical-align: top;
position: relative;
top: -4px;
}
#properties-header input[type=checkbox]:checked + label span {
color: #ffffff;
}
#properties-header + hr {
margin-top: 12px;
}
#id label {
width: 24px;
}
#property-id {
display: inline-block;
}
#property-id::selection {
color: #000000;
background-color: #00b4ef;
}
input#property-parent-id {
width: 340px;
}
input#dimension-rescale-button {
min-width: 50px;
margin-left: 6px;
}
.color-set label, .color-set span {
display: block;
input#reset-to-natural-dimensions {
margin-right: 0;
}
.color-set span {
padding-top: 2px;
input#preview-camera-button {
margin-left: 1px;
margin-right: 0;
}
#animation-fps {
margin-top: 48px;
}

View file

@ -14,25 +14,34 @@
<script src="list.min.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script>
var entities = {};
var selectedEntities = [];
var currentSortColumn = 'type';
var currentSortOrder = 'asc';
var currentSortOrder = 'des';
var entityList = null;
var refreshEntityListTimer = null;
const ASCENDING_STRING = '&nbsp;&#x25BE;';
const DESCENDING_STRING = '&nbsp;&#x25B4;';
const ASCENDING_STRING = '&#x25BE;';
const DESCENDING_STRING = '&#x25B4;';
const LOCKED_GLYPH = "&#xe006;";
const VISIBLE_GLYPH = "&#xe007;";
const DELETE = 46; // Key code for the delete key.
const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities.
debugPrint = function (message) {
console.log(message);
};
function loaded() {
openEventBridge(function() {
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url'], page: MAX_ITEMS});
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url', 'locked', 'visible'], page: MAX_ITEMS});
entityList.clear();
elEntityTable = document.getElementById("entity-table");
elEntityTableBody = document.getElementById("entity-table-body");
elRefresh = document.getElementById("refresh");
elToggleLocked = document.getElementById("locked");
elToggleVisible = document.getElementById("visible");
elDelete = document.getElementById("delete");
elTeleport = document.getElementById("teleport");
elRadius = document.getElementById("radius");
@ -50,6 +59,12 @@
document.getElementById("entity-url").onclick = function() {
setSortColumn('url');
};
document.getElementById("entity-locked").onclick = function () {
setSortColumn('locked');
};
document.getElementById("entity-visible").onclick = function () {
setSortColumn('visible');
};
function onRowClicked(clickEvent) {
var id = this.dataset.entityId;
@ -101,19 +116,20 @@
}));
}
function addEntity(id, name, type, url) {
function addEntity(id, name, type, url, locked, visible) {
var urlParts = url.split('/');
var filename = urlParts[urlParts.length - 1];
if (entities[id] === undefined) {
var urlParts = url.split('/');
var filename = urlParts[urlParts.length - 1];
entityList.add([{ id: id, name: name, type: type, url: filename }], function(items) {
entityList.add([{ id: id, name: name, type: type, url: filename, locked: locked, visible: visible }],
function (items) {
var currentElement = items[0].elm;
var id = items[0]._values.id;
entities[id] = {
id: id,
name: name,
el: currentElement,
item: items[0],
item: items[0]
};
currentElement.setAttribute('id', 'entity_' + id);
currentElement.setAttribute('title', url);
@ -128,7 +144,7 @@
refreshEntityListTimer = setTimeout(refreshEntityListObject, 50);
} else {
var item = entities[id].item;
item.values({ name: name, url: url });
item.values({ name: name, url: filename, locked: locked, visible: visible });
}
}
@ -141,19 +157,21 @@
name: document.querySelector('#entity-name .sort-order'),
type: document.querySelector('#entity-type .sort-order'),
url: document.querySelector('#entity-url .sort-order'),
locked: document.querySelector('#entity-locked .sort-order'),
visible: document.querySelector('#entity-visible .sort-order')
}
function setSortColumn(column) {
if (currentSortColumn == column) {
currentSortOrder = currentSortOrder == "asc" ? "desc" : "asc";
} else {
elSortOrder[currentSortColumn].style.display = 'none';
elSortOrder[column].style.display = 'inline';
elSortOrder[currentSortColumn].innerHTML = "";
currentSortColumn = column;
currentSortOrder = "asc";
}
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
entityList.sort(currentSortColumn, { order: currentSortOrder });
}
setSortColumn('type');
function refreshEntities() {
clearEntities();
@ -191,13 +209,24 @@
elFooter.firstChild.nodeValue = entityList.visibleItems.length + " entities found";
}
// HACK: Fixes the footer and header text sometimes not displaying after adding or deleting entities.
// The problem appears to be a bug in the Qt HTML/CSS rendering (Qt 5.5).
document.getElementById("radius").focus();
document.getElementById("radius").blur();
return notFound;
}
elRefresh.onclick = function() {
refreshEntities();
}
elTeleport.onclick = function() {
elToggleLocked.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
}
elToggleVisible.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
}
elTeleport.onclick = function () {
EventBridge.emitWebEvent(JSON.stringify({ type: 'teleport' }));
}
elDelete.onclick = function() {
@ -238,11 +267,14 @@
var newEntities = data.entities;
if (newEntities.length == 0) {
elNoEntitiesMessage.style.display = "block";
elFooter.firstChild.nodeValue = "0 entities found";
} else {
elNoEntitiesMessage.style.display = "none";
for (var i = 0; i < newEntities.length; i++) {
var id = newEntities[i].id;
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url);
addEntity(id, newEntities[i].name, newEntities[i].type, newEntities[i].url,
newEntities[i].locked ? LOCKED_GLYPH : null,
newEntities[i].visible ? VISIBLE_GLYPH : null);
}
updateSelectedEntities(data.selectedIDs);
resize();
@ -254,15 +286,23 @@
function resize() {
// Take up available window space
elEntityTableScroll.style.height = window.innerHeight - 200;
elEntityTableScroll.style.height = window.innerHeight - 207;
// Update the widths of the header cells to match the body
var tds = document.querySelectorAll("#entity-table-body tr:first-child td");
var ths = document.querySelectorAll("#entity-table thead th");
if (tds.length >= ths.length) {
// Update the widths of the header cells to match the body
for (var i = 0; i < ths.length; i++) {
ths[i].style.width = tds[i].offsetWidth;
ths[i].width = tds[i].offsetWidth;
}
} else {
// Reasonable widths if nothing is displayed
var tableWidth = document.getElementById("entity-table").offsetWidth;
ths[0].width = 0.16 * tableWidth;
ths[1].width = 0.34 * tableWidth;
ths[2].width = 0.34 * tableWidth;
ths[3].width = 0.08 * tableWidth;
ths[4].width = 0.08 * tableWidth;
}
};
@ -270,6 +310,8 @@
resize();
});
augmentSpinButtons();
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
@ -280,14 +322,21 @@
<body onload='loaded();'>
<div id="entity-list-header">
<input type="button" class="glyph" id="refresh" value="F" />
<div>
<input type="button" id="locked" class="glyph" value="&#xe006;" />
<input type="button" id="visible" class="glyph" value="&#xe007;" />
</div>
<input type="button" id="teleport" value="Jump To Selection" />
<input type="button" class="red" id="delete" value="Delete" />
</div>
<div id="entity-list">
<div id="search-area">
<input type="text" class="search" id="filter" placeholder="Filter" />
<span id="radius-and-unit"><input type="number" id="radius" value="100" /><span class="unit">m</span></span>
<span class="icon-input"><input type="text" class="search" id="filter" placeholder="Filter" /><span>Y</span></span>
<div id="radius-and-unit" class="number">
<label for="radius">Search radius <span class="unit">m</span></label>
<input type="number" id="radius" value="100" />
</div>
</div>
<div id="entity-table-scroll">
<table id="entity-table">
@ -295,12 +344,16 @@
<col span="1" id="col-type" />
<col span="1" id="col-name" />
<col span="1" id="col-url" />
<col span="1" id="col-locked" />
<col span="1" id="col-visible" />
</colgroup>
<thead>
<tr>
<th id="entity-type" data-sort="type">Type <span class="sort-order" style="display: inline">&nbsp;&#x25BE;</span></th>
<th id="entity-name" data-sort="type">Name <span class="sort-order" style="display: none">&nbsp;&#x25BE;</span></th>
<th id="entity-url" data-sort="url">File <span class="sort-order" style="display: none">&nbsp;&#x25BE;</span></th>
<th id="entity-type" data-sort="type">Type<span class="sort-order"></span></th>
<th id="entity-name" data-sort="type">Name<span class="sort-order"></span></th>
<th id="entity-url" data-sort="url">File<span class="sort-order"></span></th>
<th id="entity-locked" data-sort="locked"><span class="glyph">&#xe006;</span><span class="sort-order"></span></th>
<th colspan="2" id="entity-visible" data-sort="visible"><span class="glyph">&#xe007;</span><span class="sort-order"></span></th>
</tr>
</thead>
<tbody class="list" id="entity-table-body">
@ -308,12 +361,14 @@
<td class="type">Type</td>
<td class="name">Name</td>
<td class="url"><div class='outer'><div class='inner'>URL</div></div></td>
<td class="id" style="display: none">Type</td>
<td class="locked glyph">?</td>
<td class="visible glyph">?</td>
<td class="id" style="display: none">ID</td>
</tr>
</tbody>
<tfoot>
<tr>
<td id="footer-text" colspan="3">Footer text</td>
<td id="footer-text" colspan="5"> </td>
</tr>
</tfoot>
</table>

View file

@ -17,10 +17,25 @@
<script src="colpick.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script>
var PI = 3.14159265358979;
var DEGREES_TO_RADIANS = PI / 180.0;
var RADIANS_TO_DEGREES = 180.0 / PI;
var ICON_FOR_TYPE = {
Box: "V",
Sphere: "n",
ParticleEffect: "&#xe004;",
Model: "&#xe008;",
Web: "q",
Text: "l",
Light: "p",
Zone: "o",
PolyVox: "&#xe005;",
Multiple: "&#xe000;"
}
var colorPickers = [];
debugPrint = function(message) {
EventBridge.emitWebEvent(
@ -44,6 +59,19 @@
}
}
function enableProperties() {
enableChildren(document.getElementById("properties-list"), "input, textarea, checkbox, .dropdown dl, .color-picker");
enableChildren(document, ".colpick");
}
function disableProperties() {
disableChildren(document.getElementById("properties-list"), "input, textarea, checkbox, .dropdown dl, .color-picker");
disableChildren(document, ".colpick");
for (var i = 0; i < colorPickers.length; i++) {
colorPickers[i].colpickHide();
}
}
function showElements(els, show) {
for (var i = 0; i < els.length; i++) {
els[i].style.display = (show) ? 'table' : 'none';
@ -297,6 +325,7 @@
var allSections = [];
var elID = document.getElementById("property-id");
var elType = document.getElementById("property-type");
var elTypeIcon = document.getElementById("type-icon");
var elName = document.getElementById("property-name");
var elLocked = document.getElementById("property-locked");
var elVisible = document.getElementById("property-visible");
@ -368,7 +397,7 @@
var elReloadScriptButton = document.getElementById("reload-script-button");
var elUserData = document.getElementById("property-user-data");
var elColorSection = document.getElementById("color-section");
var elColorSections = document.querySelectorAll(".color-section");
var elColor = document.getElementById("property-color");
var elColorRed = document.getElementById("property-color-red");
var elColorGreen = document.getElementById("property-color-green");
@ -474,32 +503,40 @@
data = JSON.parse(data);
if (data.type == "update") {
if (data.selections.length == 0) {
elType.innerHTML = "<i>No Selection</i>";
elTypeIcon.style.display = "none";
elType.innerHTML = "<i>No selection</i>";
elID.innerHTML = "";
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
disableProperties();
} else if (data.selections.length > 1) {
var selections = data.selections;
var ids = [];
var types = {};
var numTypes = 0;
for (var i = 0; i < selections.length; i++) {
ids.push(selections[i].id);
var type = selections[i].properties.type;
if (types[type] === undefined) {
types[type] = 0;
numTypes += 1;
}
types[type]++;
}
elID.innerHTML = ids.join("<br>");
var typeStrs = [];
for (type in types) {
typeStrs.push(type + " (" + types[type] + ")");
var type;
if (numTypes === 1) {
type = selections[0].properties.type;
} else {
type = "Multiple";
}
elType.innerHTML = typeStrs.join(", ");
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
elType.innerHTML = type + " (" + data.selections.length + ")";
elTypeIcon.innerHTML = ICON_FOR_TYPE[type];
elTypeIcon.style.display = "inline-block";
elID.innerHTML = ids.join("<br>");
disableProperties();
} else {
var activeElement = document.activeElement;
@ -516,14 +553,16 @@
elID.innerHTML = properties.id;
elType.innerHTML = properties.type;
elTypeIcon.innerHTML = ICON_FOR_TYPE[properties.type];
elTypeIcon.style.display = "inline-block";
elLocked.checked = properties.locked;
if (properties.locked) {
disableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
disableProperties();
elLocked.removeAttribute('disabled');
} else {
enableChildren(document.getElementById("properties-list"), 'input, textarea, checkbox');
enableProperties();
}
@ -624,13 +663,17 @@
}
if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") {
elColorSection.style.display = 'table';
for (var i = 0; i < elColorSections.length; i++) {
elColorSections[i].style.display = 'table';
}
elColorRed.value = properties.color.red;
elColorGreen.value = properties.color.green;
elColorBlue.value = properties.color.blue;
elColor.style.backgroundColor = "rgb(" + properties.color.red + "," + properties.color.green + "," + properties.color.blue + ")";
} else {
elColorSection.style.display = 'none';
for (var i = 0; i < elColorSections.length; i++) {
elColorSections[i].style.display = 'none';
}
}
if (properties.type == "Model") {
@ -862,10 +905,10 @@
elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction);
$('#property-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
colorPickers.push($('#property-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: '000000',
onShow: function (colpick) {
$('#property-color').attr('active', 'true');
},
@ -873,12 +916,12 @@
$('#property-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
}));
elLightSpotLight.addEventListener('change', createEmitCheckedPropertyUpdateFunction('isSpotlight'));
var lightColorChangeFunction = createEmitColorPropertyUpdateFunction(
@ -886,10 +929,10 @@
elLightColorRed.addEventListener('change', lightColorChangeFunction);
elLightColorGreen.addEventListener('change', lightColorChangeFunction);
elLightColorBlue.addEventListener('change', lightColorChangeFunction);
$('#property-light-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
colorPickers.push($('#property-light-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: '000000',
onShow: function (colpick) {
$('#property-light-color').attr('active', 'true');
},
@ -897,11 +940,11 @@
$('#property-light-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#'+hex);
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
}
})
}));
elLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('intensity', 1));
elLightFalloffRadius.addEventListener('change', createEmitNumberPropertyUpdateFunction('falloffRadius', 1));
@ -933,7 +976,7 @@
elTextTextColorRed.addEventListener('change', textTextColorChangeFunction);
elTextTextColorGreen.addEventListener('change', textTextColorChangeFunction);
elTextTextColorBlue.addEventListener('change', textTextColorChangeFunction);
$('#property-text-text-color').colpick({
colorPickers.push($('#property-text-text-color').colpick({
colorScheme:'dark',
layout:'hex',
color: '000000',
@ -949,14 +992,14 @@
$(el).attr('active', 'false');
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
}
});
}));
var textBackgroundColorChangeFunction = createEmitColorPropertyUpdateFunction(
'backgroundColor', elTextBackgroundColorRed, elTextBackgroundColorGreen, elTextBackgroundColorBlue);
elTextBackgroundColorRed.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
$('#property-text-background-color').colpick({
colorPickers.push($('#property-text-background-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -971,10 +1014,10 @@
$(el).colpickHide();
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
}
});
}));
elZoneStageSunModelEnabled.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('stage','sunModelEnabled'));
$('#property-zone-key-light-color').colpick({
colorPickers.push($('#property-zone-key-light-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -989,7 +1032,7 @@
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
}
});
}));
var zoneKeyLightColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('keyLight','color', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
@ -1015,7 +1058,7 @@
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorGreen.addEventListener('change', zoneSkyboxColorChangeFunction);
elZoneSkyboxColorBlue.addEventListener('change', zoneSkyboxColorChangeFunction);
$('#property-zone-skybox-color').colpick({
colorPickers.push($('#property-zone-skybox-color').colpick({
colorScheme:'dark',
layout:'hex',
color:'000000',
@ -1030,7 +1073,7 @@
$(el).colpickHide();
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
}
});
}));
elZoneSkyboxURL.addEventListener('change', createEmitGroupTextPropertyUpdateFunction('skybox','url'));
@ -1138,7 +1181,7 @@
};
// Textarea scollbars
// Textarea scrollbars
var elTextareas = document.getElementsByTagName("TEXTAREA");
var textareaOnChangeEvent = function (event) {
@ -1252,6 +1295,8 @@
elDropdowns = document.getElementsByTagName("select");
}
augmentSpinButtons();
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
@ -1262,30 +1307,32 @@
<body onload='loaded();'>
<div id="properties-list">
<div id="type" class="property value">
<label>Type:</label>
<span id="property-type"></span>
</div>
<div id="id" class="property value">
<label>ID:</label>
<span id="property-id" class="selectable"></span>
<div id="properties-header">
<div id="type" class="property value">
<span id="type-icon"></span><label id="property-type"><i>No selection</i></label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-locked">
<label for="property-locked"><span>&#xe006;</span>&nbsp;Locked</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-visible">
<label for="property-visible"><span>&#xe007;</span>&nbsp;Visible</label>
</div>
</div>
<hr />
<div class="property text">
<label for="property-name">Name</label>
<input type="text" id="property-name">
</div>
<div class="property checkbox">
<input type="checkbox" id="property-locked">
<label for="property-locked">Locked</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-visible">
<label for="property-visible">Visible</label>
</div>
<div class="property textarea">
<label for="property-user-data">User data</label>
<textarea id="property-user-data"></textarea>
</div>
<div id="id" class="property value">
<label>ID:</label>
<span id="property-id" class="selectable"></span>
</div>
<div class="section-header hyperlink-group hyperlink-section">
@ -1305,7 +1352,35 @@
<label>Spatial</label><span>M</span>
</div>
<div class="spatial-group property xyz">
<label>Position</label>
<label>Dimensions <span class="unit">m</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-dim-x" step="0.1"><label for="property-dim-x">X:</label></div>
<div><input type="number" class="y" id="property-dim-y" step="0.1"><label for="property-dim-y">Y:</label></div>
<div><input type="number" class="z" id="property-dim-z" step="0.1"><label for="property-dim-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property gen">
<label>Scale <span class="unit">%</span></label>
<div class="row">
<input type="number" id="dimension-rescale-pct" value=100>
<input type="button" class="blue" id="dimension-rescale-button" value="Rescale">
<input type="button" class="red" id="reset-to-natural-dimensions" value="Reset Dimensions">
</div>
</div>
<hr class="spatial-group" />
<div class="spatial-group property pyr">
<label>Rotation <span class="unit">deg</span></label>
<div class="tuple">
<div><input type="number" class="pitch" id="property-rot-x" step="0.1"><label for="property-rot-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-rot-y" step="0.1"><label for="property-rot-y">Yaw:</label></div>
<div><input type="number" class="roll" id="property-rot-z" step="0.1"><label for="property-rot-z">Roll:</label></div>
</div>
</div>
<hr class="spatial-group" />
<div class="spatial-group property xyz">
<label>Position <span class="unit">m</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-pos-x"><label for="property-pos-x">X:</label></div>
<div><input type="number" class="y" id="property-pos-y"><label for="property-pos-y">Y:</label></div>
@ -1317,40 +1392,28 @@
<input type="button" id="preview-camera-button" value="Preview Camera">
</div>
</div>
<div class="spatial-group property text">
<label for="property-parent-id">Parent ID</label>
<input type="text" id="property-parent-id">
</div>
<div class="spatial-group property number">
<label for="property-parent-joint-index">Parent joint index</label>
<input type="number" id="property-parent-joint-index">
<div class="spatial-group row">
<div class="property text">
<label for="property-parent-id">Parent ID</label>
<input type="text" id="property-parent-id">
</div>
<div class="property number">
<label for="property-parent-joint-index">Parent joint index</label>
<input type="number" id="property-parent-joint-index">
</div>
</div>
<div class="spatial-group property xyz">
<label>Registration</label>
<label>Registration <span class="unit">(pivot offset as ratio of dimension)</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-reg-x" step="0.1"><label for="property-reg-x">X:</label></div>
<div><input type="number" class="y" id="property-reg-y" step="0.1"><label for="property-reg-y">Y:</label></div>
<div><input type="number" class="z" id="property-reg-z" step="0.1"><label for="property-reg-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property xyz">
<label>Dimensions</label>
<div class="tuple">
<div><input type="number" class="x" id="property-dim-x" step="0.1"><label for="property-dim-x">X:</label></div>
<div><input type="number" class="y" id="property-dim-y" step="0.1"><label for="property-dim-y">Y:</label></div>
<div><input type="number" class="z" id="property-dim-z" step="0.1"><label for="property-dim-z">Z:</label></div>
</div>
</div>
<div class="spatial-group property gen">
<label>Scale</label>
<div class="row">
<input type="number" id="dimension-rescale-pct" value=100>
<input type="button" class="blue" id="dimension-rescale-button" value="Rescale">
<input type="button" class="red" id="reset-to-natural-dimensions" value="Reset Dimensions">
</div>
</div>
<div class="spatial-group poly-vox-section property XYZ">
<label>Voxel volume size</label>
<hr class="spatial-group poly-vox-section" />
<div class="spatial-group poly-vox-section property xyz">
<label>Voxel volume size <span class="unit">m</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-voxel-volume-size-x"><label for="property-voxel-volume-size-x">X:</label></div>
<div><input type="number" class="y" id="property-voxel-volume-size-y"><label for="property-voxel-volume-size-y">Y:</label></div>
@ -1378,21 +1441,13 @@
<label for="property-z-texture-url">Z-axis texture URL</label>
<input type="text" id="property-z-texture-url">
</div>
<div class="spatial-group property pyr">
<label>Rotation</label>
<div class="tuple">
<div><input type="number" class="pitch" id="property-rot-x" step="0.1"><label for="property-rot-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-rot-y" step="0.1"><label for="property-rot-y">Yaw:</label></div>
<div><input type="number" class="roll" id="property-rot-z" step="0.1"><label for="property-rot-z">Roll:</label></div>
</div>
</div>
<div class="section-header physical-group">
<label>Physical</label><span>M</span>
</div>
<div class="physical-group property xyz">
<label>Linear velocity</label>
<label>Linear velocity <span class="unit">m/s</span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-lvel-x"><label for="property-lvel-x">X:</label></div>
<div><input type="number" class="y" id="property-lvel-y"><label for="property-lvel-y">Y:</label></div>
@ -1403,8 +1458,9 @@
<label>Linear damping</label>
<input type="number" id="property-ldamping">
</div>
<hr class="physical-group" />
<div class="physical-group property pyr">
<label>Angular velocity</label>
<label>Angular velocity <span class="unit">deg/s</span></label>
<div class="tuple">
<div><input type="number" class="pitch" id="property-avel-x"><label for="property-avel-x">Pitch:</label></div>
<div><input type="number" class="yaw" id="property-avel-y"><label for="property-avel-y">Yaw:</label></div>
@ -1415,6 +1471,7 @@
<label>Angular damping</label>
<input type="number" id="property-adamping">
</div>
<hr class="physical-group" />
<div class="physical-group property gen">
<div class="tuple">
<div><label>Restitution</label><input type="number" id="property-restitution"></div>
@ -1422,8 +1479,9 @@
<div><label>Density</label><input type="number" id="property-density"></div>
</div>
</div>
<hr class="physical-group" />
<div class="physical-group property xyz">
<label>Gravity</label>
<label>Gravity <span class="unit">m/s<sup>2</sup></span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-grav-x"><label for="property-grav-x">X:</label></div>
<div><input type="number" class="y" id="property-grav-y"><label for="property-grav-y">Y:</label></div>
@ -1431,14 +1489,15 @@
</div>
</div>
<div class="physical-group property xyz">
<label>Acceleration</label>
<label>Acceleration <span class="unit">m/s<sup>2</sup></span></label>
<div class="tuple">
<div><input type="number" class="x" id="property-lacc-x"><label for="property-lacc-x">X:</label></div>
<div><input type="number" class="y" id="property-lacc-y"><label for="property-lacc-y">Y:</label></div>
<div><input type="number" class="z" id="property-lacc-z"><label for="property-lacc-z">Z:</label></div>
</div>
</div>
<div id="color-section" class="physical-group property rgb">
<hr class="physical-group color-section" />
<div class="physical-group color-section property rgb">
<div id="property-color" class="color-picker"></div>
<label>Entity color</label>
<div class="tuple">
@ -1461,64 +1520,72 @@
<label for="property-dynamic">Dynamic</label>
</div>
<div class="behavior-group sub-section-header">
<span>Collides With</span>
</div>
<div class="behavior-group checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-collide-static">
<label for="property-collide-static">Static entities</label>
<div class="behavior-group two-column">
<div class="column">
<div class="sub-section-header">
<span>Collides With</span>
</div>
<div class="checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-collide-static">
<label for="property-collide-static">Static entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-dynamic">
<label for="property-collide-dynamic">Dynamic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-kinematic">
<label for="property-collide-kinematic">Kinematic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-myAvatar">
<label for="property-collide-myAvatar">My avatar</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-otherAvatar">
<label for="property-collide-otherAvatar">Other avatars</label>
</div>
</div>
</div>
<div class="column">
<div class="sub-section-header">
<span>Grabbing</span>
</div>
<div class="checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-grabbable">
<label for="property-grabbable">Grabbable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-wants-trigger">
<label for="property-wants-trigger">Triggerable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-ignore-ik">
<label for="property-ignore-ik">Ignore inverse kinematics</label>
</div>
</div>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-dynamic">
<label for="property-collide-dynamic">Dynamic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-kinematic">
<label for="property-collide-kinematic">Kinematic entities</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-myAvatar">
<label for="property-collide-myAvatar">My avatar</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-collide-otherAvatar">
<label for="property-collide-otherAvatar">Other avatars</label>
</div>
</div>
<div class="behavior-group sub-section-header">
<span>Grabbing</span>
</div>
<div class="behavior-group checkbox-sub-props">
<div class="property checkbox">
<input type="checkbox" id="property-grabbable">
<label for="property-grabbable">Grabbable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-wants-trigger">
<label for="property-wants-trigger">Triggerable</label>
</div>
<div class="property checkbox">
<input type="checkbox" id="property-ignore-ik">
<label for="property-ignore-ik">Ignore inverse kinematics</label>
</div>
</div>
<hr class="behavior-group" />
<div class="behavior-group property url ">
<label for="property-collision-sound-url">Collision sound URL</label>
<input type="text" id="property-collision-sound-url">
</div>
<div class="behavior-group property number">
<label>Lifetime</label>
<label>Lifetime <span class="unit">s</span></label>
<input type="number" id="property-lifetime">
</div>
<hr class="behavior-group" />
<div class="behavior-group property url ">
<!--
FIXME: If reload buttons at the end of each URL continue to work OK during beta, this reload button and associated
@ -1551,33 +1618,47 @@
<label for="property-compound-shape-url">Compound shape URL</label>
<input type="text" id="property-compound-shape-url">
</div>
<hr class="model-group model-section" />
<div class="model-group model-section property url ">
<label for="property-model-animation-url">Animation URL</label>
<input type="text" id="property-model-animation-url">
</div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-playing">
<label for="property-model-animation-playing">Animation playing</label>
</div>
<div class="model-group model-section property number">
<label>Animation FPS</label>
<input type="number" id="property-model-animation-fps">
</div>
<div class="model-group model-section property number">
<div class="tuple">
<div><label>Animation frame</label><input type="number" id="property-model-animation-frame"></div>
<div><label>First frame</label><input type="number" id="property-model-animation-first-frame"></div>
<div><label>Last frame</label><input type="number" id="property-model-animation-last-frame"></div>
<div class="model-group model-section two-column">
<div class="column">
<div class="property checkbox">
<input type="checkbox" id="property-model-animation-playing">
<label for="property-model-animation-playing">Animation playing</label>
</div>
<div class="property checkbox indent">
<input type="checkbox" id="property-model-animation-loop">
<label for="property-model-animation-loop">Animation loop</label>
</div>
<div class="property checkbox indent">
<input type="checkbox" id="property-model-animation-hold">
<label for="property-model-animation-hold">Animation hold</label>
</div>
<div id="animation-fps" class="property number">
<label>Animation FPS</label>
<input type="number" id="property-model-animation-fps">
</div>
</div>
<div class="column">
<div class="property number">
<label>Animation frame</label>
<input type="number" id="property-model-animation-frame">
</div>
<div class="property number">
<label>First frame</label>
<input type="number" id="property-model-animation-first-frame">
</div>
<div class="property number">
<label>Last frame</label>
<input type="number" id="property-model-animation-last-frame">
</div>
</div>
</div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-loop">
<label for="property-model-animation-loop">Animation loop</label>
</div>
<div class="model-group model-section property checkbox">
<input type="checkbox" id="property-model-animation-hold">
<label for="property-model-animation-hold">Animation hold</label>
</div>
<hr class="model-group model-section" />
<div class="model-group model-section property textarea">
<label for="property-model-textures">Textures</label>
<textarea id="property-model-textures"></textarea>
@ -1596,7 +1677,7 @@
<input type="text" id="property-text-text">
</div>
<div class="text-group text-section property number">
<label>Line height</label>
<label>Line height <span class="unit">m</span></label>
<input type="number" id="property-text-line-height" min="0" step="0.005">
</div>
<div class="text-group text-section property rgb">
@ -1645,8 +1726,8 @@
</div>
<div class="zone-group zone-section keylight-section property gen">
<div class="tuple">
<div><label>Light altitude</label><input type="number" id="property-zone-key-light-direction-x"></div>
<div><label>Light azimuth</label><input type="number" id="property-zone-key-light-direction-y"></div>
<div><label>Light altitude <span class="unit">deg</span></label><input type="number" id="property-zone-key-light-direction-x"></div>
<div><label>Light azimuth <span class="unit">deg</span></label><input type="number" id="property-zone-key-light-direction-y"></div>
<div></div>
</div>
</div>
@ -1664,9 +1745,9 @@
</div>
<div class="zone-group zone-section stage-section property gen">
<div class="tuple">
<div><label>Stage latitude</label><input type="number" id="property-zone-stage-latitude" min="-90" max="90" step="1"></div>
<div><label>Stage longitude</label><input type="number" id="property-zone-stage-longitude" min="-180" max="180" step="1"></div>
<div><label>Stage altitude</label><input type="number" id="property-zone-stage-altitude" step="1"></div>
<div><label>Latitude <span class="unit">deg</span></label><input type="number" id="property-zone-stage-latitude" min="-90" max="90" step="1"></div>
<div><label>Longitude <span class="unit">deg</span></label><input type="number" id="property-zone-stage-longitude" min="-180" max="180" step="1"></div>
<div><label>Altitude <span class="unit">m</span></label><input type="number" id="property-zone-stage-altitude" step="1"></div>
</div>
</div>
<div class="zone-group zone-section stage-section property checkbox">
@ -1676,8 +1757,8 @@
<div class="zone-group zone-section stage-section property gen">
<div class="tuple">
<div><label>Stage day of year</label><input type="number" id="property-zone-stage-day" min="0" max="365" step="1"></div>
<div><label>Stage hour</label><input type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5"></div>
<div><label>Day of year</label><input type="number" id="property-zone-stage-day" min="0" max="365" step="1"></div>
<div><label>Hour</label><input type="number" id="property-zone-stage-hour" min="0" max="24" step="0.5"></div>
<div></div>
</div>
</div>
@ -1735,7 +1816,7 @@
<div class="light-group light-section property gen">
<div class="tuple">
<div><label>Intensity</label><input type="number" id="property-light-intensity" min="0" step="0.1"></div>
<div><label>Fall-off radius</label><input type="number" id="property-light-falloff-radius" min="0" step="0.1"></div>
<div><label>Fall-off radius <span class="unit">m</span></label><input type="number" id="property-light-falloff-radius" min="0" step="0.1"></div>
<div></div>
</div>
</div>

View file

@ -11,21 +11,15 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="edit-style.css">
<link rel="stylesheet" type="text/css" href="css/colpick.css">
<script src="jquery-2.1.4.min.js"></script>
<script src="colpick.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="eventBridgeLoader.js"></script>
<script type="text/javascript" src="spinButtons.js"></script>
<script>
function loaded() {
openEventBridge(function() {
var gridColor = { red: 0, green: 0, blue: 0 };
var gridColors = [
{ red: 0, green: 0, blue: 0 },
{ red: 255, green: 255, blue: 255 },
{ red: 255, green: 0, blue: 0 },
{ red: 0, green: 255, blue: 0},
{ red: 0, green: 0, blue: 255 },
];
var gridColorIndex = 0;
elPosY = document.getElementById("horiz-y");
elMinorSpacing = document.getElementById("minor-spacing");
elMajorSpacing = document.getElementById("major-spacing");
@ -37,12 +31,12 @@
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.origin) {
var origin = data.origin;
elPosY.value = origin.y.toFixed(2);
elPosY.value = origin.y;
}
if (data.minorGridEvery !== undefined) {
elMinorSpacing.value = data.minorGridEvery;
}
@ -73,7 +67,6 @@
minorGridEvery: elMinorSpacing.value,
majorGridEvery: elMajorSpacing.value,
gridColor: gridColor,
colorIndex: gridColorIndex,
snapToGrid: elSnapToGrid.checked,
visible: elHorizontalGridVisible.checked,
}));
@ -100,23 +93,52 @@
}));
});
var gridColorBox = document.getElementById('grid-color');
for (var i = 0; i < gridColors.length; i++) {
var colors = gridColors[i];
var box = document.createElement('div');
box.setAttribute('class', 'color-box');
box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')';
document.getElementById("grid-colors").appendChild(box);
box.addEventListener("click", function(color, index) {
return function() {
gridColor = color;
gridColorIndex = index;
emitUpdate();
}
}({ red: colors.red, green: colors.green, blue: colors.blue }, i));
var gridColor = { red: 255, green: 255, blue: 255 };
var elColor = document.getElementById("grid-color");
var elColorRed = document.getElementById("grid-color-red");
var elColorGreen = document.getElementById("grid-color-green");
var elColorBlue = document.getElementById("grid-color-blue");
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
elColorRed.value = gridColor.red;
elColorGreen.value = gridColor.green;
elColorBlue.value = gridColor.blue;
var colorChangeFunction = function () {
gridColor = { red: elColorRed.value, green: elColorGreen.value, blue: elColorBlue.value };
elColor.style.backgroundColor = "rgb(" + gridColor.red + "," + gridColor.green + "," + gridColor.blue + ")";
emitUpdate();
};
var colorPickFunction = function (red, green, blue) {
elColorRed.value = red;
elColorGreen.value = green;
elColorBlue.value = blue;
gridColor = { red: red, green: green, blue: blue };
emitUpdate();
}
elColorRed.addEventListener('change', colorChangeFunction);
elColorGreen.addEventListener('change', colorChangeFunction);
elColorBlue.addEventListener('change', colorChangeFunction);
$('#grid-color').colpick({
colorScheme: 'dark',
layout: 'hex',
color: { r: gridColor.red, g: gridColor.green, b: gridColor.blue },
onShow: function (colpick) {
$('#grid-color').attr('active', 'true');
},
onHide: function (colpick) {
$('#grid-color').attr('active', 'false');
},
onSubmit: function (hsb, hex, rgb, el) {
$(el).css('background-color', '#' + hex);
$(el).colpickHide();
colorPickFunction(rgb.r, rgb.g, rgb.b);
}
});
augmentSpinButtons();
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
});
@ -146,29 +168,28 @@
<div class="property">
<div class="number">
<label>Major grid size</label>
<span>
<input type="number" id="major-spacing" min="1" step="1" /><span class="unit">m</span>
</span>
<label for="major-spacing">Major grid size <span class="unit">m</span></label>
<input type="number" id="major-spacing" min="1" step="1" />
</div>
<div class="number">
<label>Minor grid size</label>
<span>
<input type="number" id="minor-spacing" min="0.2" step="0.2" /><span class="unit">m</span>
</span>
<label for="minor-spacing">Minor grid size <span class="unit">m</span></label>
<input type="number" id="minor-spacing" min="0.2" step="0.2" />
</div>
</div>
<div class="property number">
<label>Position (Y axis)</label>
<span>
<input type="number" id="horiz-y" step="0.1" /><span class="unit">m</span>
</span>
<label for="horiz-y">Position (Y axis) <span class="unit">m</span></label>
<input type="number" id="horiz-y" step="0.1" />
</div>
<div class="property color-set">
<div class="property rgb">
<div id="grid-color" class="color-picker"></div>
<label>Grid line color</label>
<span id="grid-colors"></span>
<div class="tuple">
<div><input type="number" class="red" id="grid-color-red"><label for="grid-color-red">Red:</label></div>
<div><input type="number" class="green" id="grid-color-green"><label for="grid-color-green">Green:</label></div>
<div><input type="number" class="blue" id="grid-color-blue"><label for="grid-color-blue">Blue:</label></div>
</div>
</div>
<div class="property">

View file

@ -0,0 +1,51 @@
//
// spinButtons.js
//
// Created by David Rowe on 20 Apr 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function hoverSpinButtons(event) {
var input = event.target,
x = event.offsetX,
y = event.offsetY,
width = input.offsetWidth,
height = input.offsetHeight,
SPIN_WIDTH = 11,
SPIN_MARGIN = 2,
maxX = width - SPIN_MARGIN,
minX = maxX - SPIN_WIDTH;
if (minX <= x && x <= maxX) {
if (y < height / 2) {
input.classList.remove("hover-down");
input.classList.add("hover-up");
} else {
input.classList.remove("hover-up");
input.classList.add("hover-down");
}
} else {
input.classList.remove("hover-up");
input.classList.remove("hover-down");
}
}
function unhoverSpinButtons(event) {
event.target.classList.remove("hover-up");
event.target.classList.remove("hover-down");
}
function augmentSpinButtons() {
var inputs, i, length;
inputs = document.getElementsByTagName("INPUT");
for (i = 0, length = inputs.length; i < length; i += 1) {
if (inputs[i].type === "number") {
inputs[i].addEventListener("mousemove", hoverSpinButtons);
inputs[i].addEventListener("mouseout", unhoverSpinButtons);
}
}
}

View file

@ -59,6 +59,8 @@ EntityListTool = function(opts) {
name: properties.name,
type: properties.type,
url: properties.type == "Model" ? properties.modelURL : "",
locked: properties.locked,
visible: properties.visible
});
}
@ -99,6 +101,10 @@ EntityListTool = function(opts) {
}
} else if (data.type == "delete") {
deleteSelectedEntities();
} else if (data.type == "toggleLocked") {
toggleSelectedEntitiesLocked();
} else if (data.type == "toggleVisible") {
toggleSelectedEntitiesVisible();
} else if (data.type === "radius") {
searchRadius = data.radius;
that.sendUpdate();

View file

@ -3,14 +3,7 @@ var GRID_CONTROLS_HTML_URL = Script.resolvePath('../html/gridControls.html');
Grid = function(opts) {
var that = {};
var colors = [
{ red: 0, green: 0, blue: 0 },
{ red: 255, green: 255, blue: 255 },
{ red: 255, green: 0, blue: 0 },
{ red: 0, green: 255, blue: 0 },
{ red: 0, green: 0, blue: 255 },
];
var colorIndex = 0;
var gridColor = { red: 255, green: 255, blue: 255 };
var gridAlpha = 0.6;
var origin = { x: 0, y: +MyAvatar.getJointPosition('LeftToeBase').y.toFixed(1) + 0.1, z: 0 };
var scale = 500;
@ -28,7 +21,7 @@ Grid = function(opts) {
position: origin,
visible: false,
drawInFront: false,
color: colors[0],
color: gridColor,
alpha: gridAlpha,
minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
@ -52,12 +45,6 @@ Grid = function(opts) {
updateGrid();
};
that.getColorIndex = function() { return colorIndex; };
that.setColorIndex = function(value) {
colorIndex = value;
updateGrid();
};
that.getSnapToGrid = function() { return snapToGrid; };
that.setSnapToGrid = function(value) {
snapToGrid = value;
@ -175,8 +162,8 @@ Grid = function(opts) {
majorGridEvery = data.majorGridEvery;
}
if (data.colorIndex !== undefined) {
colorIndex = data.colorIndex;
if (data.gridColor !== undefined) {
gridColor = data.gridColor;
}
if (data.gridSize) {
@ -196,7 +183,7 @@ Grid = function(opts) {
visible: that.visible && that.enabled,
minorGridEvery: minorGridEvery,
majorGridEvery: majorGridEvery,
color: colors[colorIndex],
color: gridColor,
alpha: gridAlpha,
});

View file

@ -3,35 +3,18 @@ float aspect(vec2 v) {
}
vec3 aspectCorrectedTexture() {
vec2 uv = _position.xy;
vec2 uv;
if (abs(_position.y) > 0.4999) {
uv = _position.xz;
} else if (abs(_position.z) > 0.4999) {
uv = _position.xy;
} else {
uv = _position.yz;
}
uv += 0.5;
uv.y = 1.0 - uv.y;
float targetAspect = iWorldScale.x / iWorldScale.y;
float sourceAspect = aspect(iChannelResolution[0].xy);
float aspectCorrection = sourceAspect / targetAspect;
if (aspectCorrection > 1.0) {
float offset = aspectCorrection - 1.0;
float halfOffset = offset / 2.0;
uv.y -= halfOffset;
uv.y *= aspectCorrection;
} else {
float offset = 1.0 - aspectCorrection;
float halfOffset = offset / 2.0;
uv.x -= halfOffset;
uv.x /= aspectCorrection;
}
if (any(lessThan(uv, vec2(0.0)))) {
return vec3(0.0);
}
if (any(greaterThan(uv, vec2(1.0)))) {
return vec3(0.0);
}
vec4 color = texture(iChannel0, uv);
return color.rgb * max(0.5, sourceAspect) * max(0.9, fract(iWorldPosition.x));
return texture(iChannel0, uv).rgb;
}
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {

View file

@ -42,7 +42,7 @@ function createItems(count) {
name: TEST_ENTITY_NAME,
position: AUSTIN.avatarRelativePosition(AUSTIN.randomPositionXZ({ x: 0, y: 0, z: -2 }, RADIUS)),
color: { r: 255, g: 255, b: 255 },
dimensions: AUSTIN.randomDimensions(),
dimensions: { x: 0.5, y: 0.5, z: 0.5 }, //AUSTIN.randomDimensions(),
lifetime: ENTITY_LIFETIME,
userData: JSON.stringify({
ProceduralEntity: {

View file

@ -14,8 +14,8 @@ var qml = Script.resolvePath('stats.qml');
var window = new OverlayWindow({
title: 'Render Stats',
source: qml,
width: 300,
height: 200
width: 320,
height: 720
});
window.setPosition(500, 50);
window.closed.connect(function() { Script.stop(); });

View file

@ -241,7 +241,6 @@ Item {
color: "#E2334D"
}
]
}
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -145,7 +145,7 @@
"id": "rightHandGraspOpen",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_right.fbx",
"url": "animations/hydra_pose_open_right.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 1.0,
@ -157,7 +157,7 @@
"id": "rightHandGraspClosed",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_right.fbx",
"url": "animations/hydra_pose_closed_right.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 1.0,
@ -205,7 +205,7 @@
"id": "leftHandGraspOpen",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_open_left.fbx",
"url": "animations/hydra_pose_open_left.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 1.0,
@ -217,7 +217,7 @@
"id": "leftHandGraspClosed",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/hydra_pose_closed_left.fbx",
"url": "animations/hydra_pose_closed_left.fbx",
"startFrame": 10.0,
"endFrame": 10.0,
"timeScale": 1.0,
@ -495,7 +495,7 @@
"id": "idleStand",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,
@ -507,7 +507,7 @@
"id": "idleTalk",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/talk.fbx",
"url": "animations/talk.fbx",
"startFrame": 0.0,
"endFrame": 801.0,
"timeScale": 1.0,
@ -532,7 +532,7 @@
"id": "walkFwdShort",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_fwd.fbx",
"url": "animations/walk_short_fwd.fbx",
"startFrame": 0.0,
"endFrame": 39.0,
"timeScale": 1.0,
@ -544,7 +544,7 @@
"id": "walkFwdNormal",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_fwd.fbx",
"url": "animations/walk_fwd.fbx",
"startFrame": 0.0,
"endFrame": 35.0,
"timeScale": 1.0,
@ -556,7 +556,7 @@
"id": "walkFwdRun",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/run_fwd.fbx",
"url": "animations/run_fwd.fbx",
"startFrame": 0.0,
"endFrame": 21.0,
"timeScale": 1.0,
@ -570,7 +570,7 @@
"id": "idleToWalkFwd",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle_to_walk.fbx",
"url": "animations/idle_to_walk.fbx",
"startFrame": 1.0,
"endFrame": 19.0,
"timeScale": 1.0,
@ -593,7 +593,7 @@
"id": "walkBwdShort",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_short_bwd.fbx",
"url": "animations/walk_short_bwd.fbx",
"startFrame": 0.0,
"endFrame": 38.0,
"timeScale": 1.0,
@ -605,7 +605,7 @@
"id": "walkBwdNormal",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/walk_bwd.fbx",
"url": "animations/walk_bwd.fbx",
"startFrame": 0.0,
"endFrame": 36.0,
"timeScale": 1.0,
@ -619,7 +619,7 @@
"id": "turnLeft",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_left.fbx",
"url": "animations/turn_left.fbx",
"startFrame": 0.0,
"endFrame": 28.0,
"timeScale": 1.0,
@ -631,7 +631,7 @@
"id": "turnRight",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/turn_right.fbx",
"url": "animations/turn_right.fbx",
"startFrame": 0.0,
"endFrame": 30.0,
"timeScale": 1.0,
@ -654,7 +654,7 @@
"id": "strafeLeftShort",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_left.fbx",
"url": "animations/side_step_short_left.fbx",
"startFrame": 0.0,
"endFrame": 28.0,
"timeScale": 1.0,
@ -666,7 +666,7 @@
"id": "strafeLeftNormal",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_left.fbx",
"url": "animations/side_step_left.fbx",
"startFrame": 0.0,
"endFrame": 30.0,
"timeScale": 1.0,
@ -691,7 +691,7 @@
"id": "strafeRightShort",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_short_right.fbx",
"url": "animations/side_step_short_right.fbx",
"startFrame": 0.0,
"endFrame": 28.0,
"timeScale": 1.0,
@ -703,7 +703,7 @@
"id": "strafeRightNormal",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/side_step_right.fbx",
"url": "animations/side_step_right.fbx",
"startFrame": 0.0,
"endFrame": 30.0,
"timeScale": 1.0,
@ -717,7 +717,7 @@
"id": "fly",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/fly.fbx",
"url": "animations/fly.fbx",
"startFrame": 1.0,
"endFrame": 80.0,
"timeScale": 1.0,
@ -729,7 +729,7 @@
"id": "takeoffStand",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_takeoff.fbx",
"url": "animations/jump_standing_takeoff.fbx",
"startFrame": 17.0,
"endFrame": 25.0,
"timeScale": 1.0,
@ -741,7 +741,7 @@
"id": "takeoffRun",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_takeoff.fbx",
"url": "animations/jump_takeoff.fbx",
"startFrame": 1.0,
"endFrame": 2.5,
"timeScale": 0.01,
@ -761,7 +761,7 @@
"id": "inAirStandPreApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx",
"url": "animations/jump_standing_apex.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 0.0,
@ -773,7 +773,7 @@
"id": "inAirStandApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx",
"url": "animations/jump_standing_apex.fbx",
"startFrame": 1.0,
"endFrame": 1.0,
"timeScale": 1.0,
@ -785,7 +785,7 @@
"id": "inAirStandPostApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_apex.fbx",
"url": "animations/jump_standing_apex.fbx",
"startFrame": 2.0,
"endFrame": 2.0,
"timeScale": 1.0,
@ -807,7 +807,7 @@
"id": "inAirRunPreApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"url": "animations/jump_in_air.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 0.0,
@ -819,7 +819,7 @@
"id": "inAirRunApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"url": "animations/jump_in_air.fbx",
"startFrame": 6.0,
"endFrame": 6.0,
"timeScale": 1.0,
@ -831,7 +831,7 @@
"id": "inAirRunPostApex",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"url": "animations/jump_in_air.fbx",
"startFrame": 11.0,
"endFrame": 11.0,
"timeScale": 1.0,
@ -845,7 +845,7 @@
"id": "landStandImpact",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_land.fbx",
"url": "animations/jump_standing_land.fbx",
"startFrame": 1.0,
"endFrame": 6.0,
"timeScale": 1.0,
@ -857,7 +857,7 @@
"id": "landStand",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_standing_land.fbx",
"url": "animations/jump_standing_land.fbx",
"startFrame": 6.0,
"endFrame": 28.0,
"timeScale": 1.0,
@ -869,7 +869,7 @@
"id": "landRun",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_land.fbx",
"url": "animations/jump_land.fbx",
"startFrame": 1.0,
"endFrame": 6.0,
"timeScale": 0.65,
@ -891,7 +891,7 @@
"id": "userAnimA",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,
@ -903,7 +903,7 @@
"id": "userAnimB",
"type": "clip",
"data": {
"url": "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/idle.fbx",
"url": "animations/idle.fbx",
"startFrame": 0.0,
"endFrame": 90.0,
"timeScale": 1.0,

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,20 +0,0 @@
filename=defaultAvatar/body.fbx
texdir=defaultAvatar
scale=8.666
joint = jointRoot = jointRoot
joint = jointLean = jointSpine
joint = jointNeck = jointNeck
joint = jointHead = jointHeadtop
joint = joint_L_shoulder = joint_L_shoulder
freeJoint = joint_L_arm
freeJoint = joint_L_elbow
joint = jointLeftHand = joint_L_hand
joint = joint_R_shoulder = joint_R_shoulder
freeJoint = joint_R_arm
freeJoint = joint_R_elbow
joint = jointRightHand = joint_R_hand

View file

@ -1,97 +1,135 @@
name = defaultAvatar_full
name = being_of_light
type = body+head
scale = 1
filename = defaultAvatar_full/defaultAvatar_full.fbx
texdir = defaultAvatar_full/textures
joint = jointRightHand = RightHand
joint = jointNeck = Head
filename = being_of_light/being_of_light.fbx
texdir = being_of_light/textures
joint = jointRoot = Hips
joint = jointLeftHand = LeftHand
joint = jointHead = HeadTop_End
joint = jointLean = Spine
joint = jointLeftHand = LeftHand
joint = jointEyeLeft = LeftEye
joint = jointRightHand = RightHand
joint = jointNeck = Head
joint = jointEyeRight = RightEye
freeJoint = LeftArm
freeJoint = LeftForeArm
freeJoint = RightArm
freeJoint = RightForeArm
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
bs = LipsLowerDown_L = Mouth.LipsLowerDown = 0.5
bs = LipsStretch_L = Mouth.LipsStretch_L = 1
bs = MouthLeft = Mouth.MouthLeft = 1
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
bs = Sneer_R = Mouth.Sneer = 0.61
bs = LipsPucker = Mouth.LipsPucker = 1
bs = EyeOpen_R = Reye1.EyeOut_R = 1
bs = LipsLowerDown_R = Mouth.LipsLowerDown = 0.43
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
bs = LipsFunnel = Mouth.LipsFunnel = 1
bs = EyeUp_L = Leye1.EyeUp_L = 1
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
bs = Puff = Mouth.Puff = 1
bs = EyeIn_L = Leye1.EyeIn_L = 1
bs = EyeUp_R = Reye1.EyeUp_R = 0.99
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
bs = MouthRight = Mouth.MouthRight = 1
bs = EyeOut_L = Leye1.EyeOut_L = 1
bs = JawOpen = Mouth.JawOpen = 1
bs = EyeIn_R = Reye1.EyeIn_R = 1
bs = BrowsD_L = Leye1.BrowsD_L = 1
bs = EyeDown_L = Leye1.EyeDown_L = 1
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
bs = EyeOut_R = Reye1.EyeOut_R = 1
bs = LipsUpperUp_L = Mouth.LipsUpperUp = 0.49
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
bs = EyeDown_R = Reye1.EyeDown_R = 1
bs = BrowsD_R = Reye1.BrowsD_R = 1
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
bs = LipsUpperUp_R = Mouth.LipsUpperUp = 0.47
bs = Sneer_L = Mouth.Sneer = 0.5
jointIndex = headphone = 7
jointIndex = LeftUpLeg = 15
jointIndex = Spine = 20
jointIndex = LeftArm = 32
jointIndex = Head = 40
jointIndex = RightUpLeg = 10
jointIndex = hair = 5
jointIndex = Spine1 = 21
jointIndex = RightHandIndex1 = 27
jointIndex = Spine2 = 22
jointIndex = RightHandIndex2 = 28
jointIndex = RightHandIndex3 = 29
jointIndex = RightHandIndex4 = 30
jointIndex = RightToe_End = 14
jointIndex = shield = 4
jointIndex = LeftHandIndex1 = 35
jointIndex = LeftHandIndex2 = 36
jointIndex = RightHand = 26
jointIndex = LeftHandIndex3 = 37
jointIndex = LeftHandIndex4 = 38
jointIndex = LeftShoulder = 31
jointIndex = LeftHand = 34
jointIndex = RightForeArm = 25
jointIndex = RightLeg = 11
jointIndex = RightFoot = 12
jointIndex = mouth = 1
jointIndex = LeftToe_End = 19
jointIndex = Reye = 2
jointIndex = Hips = 9
jointIndex = RightToeBase = 13
jointIndex = HeadTop_End = 41
jointIndex = LeftFoot = 17
jointIndex = RightShoulder = 23
jointIndex = LeftLeg = 16
jointIndex = Leye = 3
jointIndex = LeftForeArm = 33
jointIndex = face = 0
jointIndex = body = 8
jointIndex = LeftToeBase = 18
jointIndex = RightArm = 24
jointIndex = top1 = 6
jointIndex = Neck = 39
rx = 0
ry = 0
rz = 0
tx = 0
ty = 0
tz = 0
bs = MouthFrown_L = Frown_Left = 1
bs = MouthLeft = Midmouth_Left = 1
bs = BrowsU_R = BrowsUp_Right = 1
bs = ChinUpperRaise = UpperLipUp_Right = 0.5
bs = ChinUpperRaise = UpperLipUp_Left = 0.5
bs = MouthSmile_R = Smile_Right = 1
bs = MouthDimple_L = Smile_Left = 0.25
bs = EyeBlink_L = Blink_Left = 1
bs = BrowsD_L = BrowsDown_Left = 1
bs = MouthFrown_R = Frown_Right = 1
bs = MouthDimple_R = Smile_Right = 0.25
bs = Sneer = Squint_Right = 0.5
bs = Sneer = Squint_Left = 0.5
bs = Sneer = NoseScrunch_Right = 0.75
bs = Sneer = NoseScrunch_Left = 0.75
bs = EyeSquint_L = Squint_Left = 1
bs = EyeBlink_R = Blink_Right = 1
bs = JawLeft = JawRotateY_Left = 0.5
bs = BrowsD_R = BrowsDown_Right = 1
bs = EyeSquint_R = Squint_Right = 1
bs = Puff = CheekPuff_Right = 1
bs = Puff = CheekPuff_Left = 1
bs = LipsUpperClose = UpperLipIn = 1
bs = JawOpen = MouthOpen = 0.69999999999999996
bs = LipsUpperUp = UpperLipUp_Right = 0.69999999999999996
bs = LipsUpperUp = UpperLipUp_Left = 0.69999999999999996
bs = LipsLowerDown = LowerLipDown_Right = 0.69999999999999996
bs = LipsLowerDown = LowerLipDown_Left = 0.69999999999999996
bs = LipsLowerOpen = LowerLipOut = 1
bs = EyeOpen_L = EyesWide_Left = 1
bs = LipsPucker = MouthNarrow_Right = 1
bs = LipsPucker = MouthNarrow_Left = 1
bs = EyeOpen_R = EyesWide_Right = 1
bs = JawRight = Jaw_Right = 1
bs = MouthRight = Midmouth_Right = 1
bs = ChinLowerRaise = Jaw_Up = 1
bs = LipsUpperOpen = UpperLipOut = 1
bs = BrowsU_C = BrowsUp_Right = 1
bs = BrowsU_C = BrowsUp_Left = 1
bs = JawFwd = JawForeward = 1
bs = BrowsU_L = BrowsUp_Left = 1
bs = MouthSmile_L = Smile_Left = 1
bs = LipsLowerClose = LowerLipIn = 1
bs = LipsFunnel = TongueUp = 1
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Right = 0.5
bs = LipsFunnel = MouthWhistle_NarrowAdjust_Left = 0.5
bs = LipsFunnel = MouthNarrow_Right = 1
bs = LipsFunnel = MouthNarrow_Left = 1
bs = LipsFunnel = Jaw_Down = 0.35999999999999999
bs = LipsFunnel = JawForeward = 0.39000000000000001
jointIndex = LeftHandIndex1 = 50
jointIndex = LeftHandIndex2 = 51
jointIndex = LeftHandIndex3 = 52
jointIndex = LeftHandIndex4 = 53
jointIndex = Spine1 = 12
jointIndex = Spine2 = 13
jointIndex = RightHandThumb1 = 18
jointIndex = RightHandThumb2 = 19
jointIndex = RightHandThumb3 = 20
jointIndex = RightHandThumb4 = 21
jointIndex = LeftFoot = 8
jointIndex = LeftForeArm = 40
jointIndex = Neck = 62
jointIndex = Head = 63
jointIndex = Hips = 0
jointIndex = RightHandPinky1 = 30
jointIndex = RightHandPinky2 = 31
jointIndex = RightHandPinky3 = 32
jointIndex = RightHandPinky4 = 33
jointIndex = RightLeg = 2
jointIndex = RightForeArm = 16
jointIndex = LeftHandRing1 = 46
jointIndex = LeftHandRing2 = 47
jointIndex = LeftHandRing3 = 48
jointIndex = LeftHandRing4 = 49
jointIndex = LeftHandThumb1 = 54
jointIndex = LeftHandThumb2 = 55
jointIndex = LeftHandThumb3 = 56
jointIndex = LeftHandThumb4 = 57
jointIndex = HeadTop_End = 66
jointIndex = LeftUpLeg = 6
jointIndex = LeftToeBase = 9
jointIndex = LeftHandPinky1 = 42
jointIndex = LeftHandPinky2 = 43
jointIndex = LeftHandPinky3 = 44
jointIndex = LeftHandPinky4 = 45
jointIndex = LeftLeg = 7
jointIndex = RightEye = 65
jointIndex = RightHand = 17
jointIndex = RightToeBase = 4
jointIndex = RightUpLeg = 1
jointIndex = RightArm = 15
jointIndex = RightHandRing1 = 26
jointIndex = RightHandRing2 = 27
jointIndex = RightHandRing3 = 28
jointIndex = RightHandRing4 = 29
jointIndex = RightHandIndex1 = 22
jointIndex = RightHandIndex2 = 23
jointIndex = RightHandIndex3 = 24
jointIndex = RightHandIndex4 = 25
jointIndex = LeftToe_End = 10
jointIndex = LeftHandMiddle1 = 58
jointIndex = LeftHandMiddle2 = 59
jointIndex = LeftHandMiddle3 = 60
jointIndex = LeftShoulder = 38
jointIndex = LeftHandMiddle4 = 61
jointIndex = RightFoot = 3
jointIndex = LeftHand = 41
jointIndex = RightHandMiddle1 = 34
jointIndex = RightHandMiddle2 = 35
jointIndex = RightHandMiddle3 = 36
jointIndex = RightShoulder = 14
jointIndex = LeftEye = 64
jointIndex = RightHandMiddle4 = 37
jointIndex = Body = 67
jointIndex = LeftArm = 39
jointIndex = RightToe_End = 5
jointIndex = Spine = 11

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,45 +0,0 @@
# faceshift target mapping file
name= defaultAvatar_head
filename=defaultAvatar/head.fbx
texdir=defaultAvatar
scale=5.333
rx=0
ry=0
rz=0
tx=0
ty=0
tz=0
joint = jointNeck = jointNeck
bs = BrowsD_L = Leye1.BrowsD_L = 0.97
bs = BrowsD_R = Reye1.BrowsD_R = 1
bs = CheekSquint_L = Leye1.CheekSquint_L = 1
bs = CheekSquint_R = Reye1.CheekSquint_R = 1
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
bs = EyeDown_L = Leye1.EyeDown_L = 1
bs = EyeDown_R = Reye1.EyeDown_R = 0.99
bs = EyeIn_L = Leye1.EyeIn_L = 0.92
bs = EyeIn_R = Reye1.EyeIn_R = 1
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
bs = EyeOpen_R = Reye1.EyeOpen_R = 1
bs = EyeOut_L = Leye1.EyeOut_L = 0.99
bs = EyeOut_R = Reye1.EyeOut_R = 1
bs = EyeUp_L = Leye1.EyeUp_L = 0.93
bs = EyeUp_R = Reye1.EyeUp_R = 1
bs = JawOpen = Mouth.JawOpen = 1
bs = LipsFunnel = Mouth.LipsFunnel = 1
bs = LipsLowerDown = Mouth.LipsLowerDown = 1
bs = LipsPucker = Mouth.LipsPucker = 1
bs = LipsStretch_L = Mouth.LipsStretch_L = 0.96
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
bs = LipsUpperUp = Mouth.LipsUpperUp = 1
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
bs = MouthLeft = Mouth.MouthLeft = 1
bs = MouthRight = Mouth.MouthRight = 1
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
bs = Puff = Mouth.Puff = 1
bs = Sneer = Mouth.Sneer = 1

View file

@ -330,9 +330,10 @@ Window {
HifiControls.ContentSection {
id: assetDirectory
name: "Asset Directory"
spacing: hifi.dimensions.contentSpacing.y
isFirst: true
HifiControls.VerticalSpacer {}
Row {
id: buttonRow
anchors.left: parent.left
@ -343,8 +344,7 @@ Window {
glyph: hifi.glyphs.reload
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 26
width: hifi.dimensions.controlLineHeight
onClicked: root.reload()
}
@ -353,7 +353,6 @@ Window {
text: "ADD TO WORLD"
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 120
enabled: canAddToWorld(assetProxyModel.data(treeView.selection.currentIndex, 0x100))
@ -365,7 +364,6 @@ Window {
text: "RENAME"
color: hifi.buttons.white
colorScheme: root.colorScheme
height: 26
width: 80
onClicked: root.renameFile()
@ -378,7 +376,6 @@ Window {
text: "DELETE"
color: hifi.buttons.red
colorScheme: root.colorScheme
height: 26
width: 80
onClicked: root.deleteFile()
@ -419,7 +416,7 @@ Window {
id: treeView
anchors.top: assetDirectory.bottom
anchors.bottom: uploadSection.top
anchors.margins: 12
anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.left: parent.left
anchors.right: parent.right
@ -448,7 +445,7 @@ Window {
name: "Upload A File"
spacing: hifi.dimensions.contentSpacing.y
anchors.bottom: parent.bottom
height: 92
height: 95
Item {
height: parent.height

View file

@ -30,7 +30,7 @@ Window {
title: "Edit"
property alias tabView: tabView
implicitWidth: 520; implicitHeight: 695
minSize: Qt.vector2d(412, 500)
minSize: Qt.vector2d(456, 500)
HifiConstants { id: hifi }

View file

@ -19,7 +19,7 @@ Original.Button {
property int colorScheme: hifi.colorSchemes.light
width: 120
height: 28
height: hifi.dimensions.controlLineHeight
style: ButtonStyle {

View file

@ -59,7 +59,7 @@ FocusScope {
id: comboBox
anchors.fill: parent
visible: false
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control.
}
FiraSansSemiBold {

View file

@ -46,7 +46,7 @@ Column {
Item {
id: leadingSpace
width: 1
height: isFirst ? hifi.dimensions.contentSpacing.y : 0
height: isFirst ? 7 : 0
anchors.top: parent.top
}
@ -80,14 +80,14 @@ Column {
right: parent.right
top: topBar.bottom
}
height: (isCollapsible ? 3 : 2) * hifi.dimensions.contentSpacing.y
height: isCollapsible ? 36 : 28
RalewayRegular {
id: title
anchors {
left: parent.left
top: parent.top
topMargin: hifi.dimensions.contentSpacing.y
topMargin: 12
}
size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase

View file

@ -28,7 +28,7 @@ SpinBox {
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control.
y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0
@ -51,12 +51,13 @@ SpinBox {
horizontalAlignment: Qt.AlignLeft
padding.left: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding
padding.right: hifi.dimensions.spinnerSize
padding.top: 0
incrementControl: HiFiGlyphs {
id: incrementButton
text: hifi.glyphs.caratUp
x: 6
y: 2
y: 1
size: hifi.dimensions.spinnerSize
color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray
}

View file

@ -20,15 +20,17 @@ TextField {
property int colorScheme: hifi.colorSchemes.light
readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light
property bool isSearchField: false
property string label: ""
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height : 0)
property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0)
placeholderText: textField.placeholderText
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
font.family: firaSansSemiBold.name
font.pixelSize: hifi.fontSizes.textFieldInput
height: implicitHeight + 4 // Make surrounding box higher so that highlight is vertically centered.
font.italic: textField.text == ""
height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered.
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
@ -42,11 +44,22 @@ TextField {
: (textField.focus ? hifi.colors.black : hifi.colors.baseGrayShadow)
border.color: hifi.colors.primaryHighlight
border.width: textField.focus ? 1 : 0
radius: isSearchField ? textField.height / 2 : 0
HiFiGlyphs {
text: hifi.glyphs.search
color: textColor
size: hifi.fontSizes.textFieldSearchIcon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: hifi.dimensions.textPadding - 2
visible: isSearchField
}
}
placeholderTextColor: hifi.colors.lightGray
selectedTextColor: hifi.colors.black
selectionColor: hifi.colors.primaryHighlight
padding.left: hifi.dimensions.textPadding
padding.left: (isSearchField ? textField.height - 2 : 0) + hifi.dimensions.textPadding
padding.right: hifi.dimensions.textPadding
}
@ -56,7 +69,7 @@ TextField {
colorScheme: textField.colorScheme
anchors.left: parent.left
anchors.bottom: parent.top
anchors.bottomMargin: 4
anchors.bottomMargin: 3
visible: label != ""
}
}

View file

@ -51,7 +51,11 @@ Window {
Rectangle {
id: attachmentsBackground
anchors { left: parent.left; right: parent.right; top: parent.top; bottom: newAttachmentButton.top; margins: 8 }
anchors {
left: parent.left; right: parent.right; top: parent.top; bottom: newAttachmentButton.top;
margins: hifi.dimensions.contentMargin.x
bottomMargin: hifi.dimensions.contentSpacing.y
}
color: hifi.colors.baseGrayShadow
radius: 4
@ -129,7 +133,14 @@ Window {
HifiControls.Button {
id: newAttachmentButton
anchors { left: parent.left; right: parent.right; bottom: buttonRow.top; margins: 8 }
anchors {
left: parent.left
right: parent.right
bottom: buttonRow.top
margins: hifi.dimensions.contentMargin.x;
topMargin: hifi.dimensions.contentSpacing.y
bottomMargin: hifi.dimensions.contentSpacing.y
}
text: "New Attachment"
color: hifi.buttons.black
colorScheme: hifi.colorSchemes.dark
@ -151,7 +162,13 @@ Window {
Row {
id: buttonRow
spacing: 8
anchors { right: parent.right; bottom: parent.bottom; margins: 8 }
anchors {
right: parent.right
bottom: parent.bottom
margins: hifi.dimensions.contentMargin.x
topMargin: hifi.dimensions.contentSpacing.y
bottomMargin: hifi.dimensions.contentSpacing.y
}
HifiControls.Button {
action: okAction
color: hifi.buttons.black

View file

@ -24,7 +24,8 @@ Window {
resizable: true
destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 400; implicitHeight: 728
implicitWidth: 400
implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300)
HifiConstants { id: hifi }
@ -32,6 +33,7 @@ Window {
property var scripts: ScriptDiscoveryService;
property var scriptsModel: scripts.scriptsModelFilter
property var runningScriptsModel: ListModel { }
property bool isHMD: false
Settings {
category: "Overlay.RunningScripts"
@ -44,7 +46,10 @@ Window {
onScriptCountChanged: updateRunningScripts();
}
Component.onCompleted: updateRunningScripts()
Component.onCompleted: {
isHMD = HMD.active;
updateRunningScripts();
}
function setDefaultFocus() {
// Work around FocusScope of scrollable window.
@ -109,7 +114,9 @@ Window {
}
}
HifiControls.VerticalSpacer {}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Table {
tableModel: runningScriptsModel
@ -120,7 +127,7 @@ Window {
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Table view draws a little taller than it's height.
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
}
@ -175,16 +182,19 @@ Window {
HifiControls.TextField {
id: filterEdit
isSearchField: true
anchors.left: parent.left
anchors.right: parent.right
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "filter"
placeholderText: "Filter"
onTextChanged: scriptsModel.filterRegExp = new RegExp("^.*" + text + ".*$", "i")
Component.onCompleted: scriptsModel.filterRegExp = new RegExp("^.*$", "i")
}
HifiControls.VerticalSpacer {}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.Tree {
id: treeView
@ -195,7 +205,9 @@ Window {
anchors.right: parent.right
}
HifiControls.VerticalSpacer {}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight + 2 // Add space for border
}
HifiControls.TextField {
id: selectedScript
@ -237,7 +249,7 @@ Window {
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - 3
height: hifi.dimensions.controlInterlineHeight - (!isHMD ? 3 : 0)
}
HifiControls.TextAction {
@ -245,13 +257,15 @@ Window {
icon: hifi.glyphs.script
iconSize: 24
text: "Reveal Scripts Folder"
onClicked: fileDialogHelper.openScriptsDirectory()
onClicked: fileDialogHelper.openDirectory(scripts.defaultScriptsPath)
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
visible: !isHMD
}
HifiControls.VerticalSpacer {
height: hifi.dimensions.controlInterlineHeight - 3
visible: !isHMD
}
}
}

View file

@ -131,8 +131,8 @@ Item {
readonly property bool largeScreen: Screen.width >= 1920 && Screen.height >= 1080
readonly property real borderRadius: largeScreen ? 7.5 : 5.0
readonly property real borderWidth: largeScreen ? 2 : 1
readonly property vector2d contentMargin: Qt.vector2d(12, 24)
readonly property vector2d contentSpacing: Qt.vector2d(8, 12)
readonly property vector2d contentMargin: Qt.vector2d(21, 21)
readonly property vector2d contentSpacing: Qt.vector2d(11, 14)
readonly property real labelPadding: 40
readonly property real textPadding: 8
readonly property real sliderHandleSize: 18
@ -143,8 +143,8 @@ Item {
readonly property real tableHeaderHeight: 40
readonly property vector2d modalDialogMargin: Qt.vector2d(50, 30)
readonly property real modalDialogTitleHeight: 40
readonly property real controlLineHeight: 29 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 22 // 75% of controlLineHeight
readonly property real controlLineHeight: 28 // Height of spinbox control on 1920 x 1080 monitor
readonly property real controlInterlineHeight: 21 // 75% of controlLineHeight
readonly property vector2d menuPadding: Qt.vector2d(14, 12)
}
@ -156,6 +156,7 @@ Item {
readonly property real inputLabel: dimensions.largeScreen ? 14 : 10
readonly property real textFieldInput: dimensions.largeScreen ? 15 : 12
readonly property real textFieldInputLabel: dimensions.largeScreen ? 13 : 9
readonly property real textFieldSearchIcon: dimensions.largeScreen ? 30 : 24
readonly property real tableText: dimensions.largeScreen ? 15 : 12
readonly property real buttonLabel: dimensions.largeScreen ? 13 : 9
readonly property real iconButton: dimensions.largeScreen ? 13 : 9

View file

@ -215,7 +215,7 @@ Fadable {
bottom: parent.bottom
}
width: parent.contentWidth
height: footer.height + 2 * hifi.dimensions.contentSpacing.y
height: footer.height + 2 * hifi.dimensions.contentSpacing.y + 3
color: hifi.colors.baseGray
visible: footer.height > 0

View file

@ -3104,10 +3104,8 @@ void Application::updateMyAvatarLookAtPosition() {
} else {
// I am not looking at anyone else, so just look forward
if (isHMD) {
glm::mat4 headPose = myAvatar->getHMDSensorMatrix();
glm::quat headRotation = glm::quat_cast(headPose);
lookAtSpot = myAvatar->getPosition() +
myAvatar->getOrientation() * (headRotation * glm::vec3(0.0f, 0.0f, -TREE_SCALE));
glm::mat4 worldHMDMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
lookAtSpot = transformPoint(worldHMDMat, glm::vec3(0.0f, 0.0f, -TREE_SCALE));
} else {
lookAtSpot = myAvatar->getHead()->getEyePosition() +
(myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.0f, 0.0f, -TREE_SCALE));

View file

@ -360,6 +360,41 @@ Menu::Menu() {
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false));
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
//const QString = "Automatic Texture Memory";
//const QString = "64 MB";
//const QString = "256 MB";
//const QString = "512 MB";
//const QString = "1024 MB";
//const QString = "2048 MB";
// Developer > Render > Resolution
MenuWrapper* textureMenu = renderOptionsMenu->addMenu(MenuOption::RenderMaxTextureMemory);
QActionGroup* textureGroup = new QActionGroup(textureMenu);
textureGroup->setExclusive(true);
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTextureAutomatic, 0, true));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture64MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture256MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture512MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture1024MB, 0, false));
textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture2048MB, 0, false));
connect(textureGroup, &QActionGroup::triggered, [textureGroup] {
auto checked = textureGroup->checkedAction();
auto text = checked->text();
gpu::Context::Size newMaxTextureMemory { 0 };
if (MenuOption::RenderMaxTexture64MB == text) {
newMaxTextureMemory = MB_TO_BYTES(64);
} else if (MenuOption::RenderMaxTexture256MB == text) {
newMaxTextureMemory = MB_TO_BYTES(256);
} else if (MenuOption::RenderMaxTexture512MB == text) {
newMaxTextureMemory = MB_TO_BYTES(512);
} else if (MenuOption::RenderMaxTexture1024MB == text) {
newMaxTextureMemory = MB_TO_BYTES(1024);
} else if (MenuOption::RenderMaxTexture2048MB == text) {
newMaxTextureMemory = MB_TO_BYTES(2048);
}
gpu::Texture::setAllowedGPUMemoryUsage(newMaxTextureMemory);
});
// Developer > Render > LOD Tools
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 0, dialogsManager.data(), SLOT(lodTools()));

View file

@ -150,6 +150,13 @@ namespace MenuOption {
const QString RenderFocusIndicator = "Show Eye Focus";
const QString RenderLookAtTargets = "Show Look-at Targets";
const QString RenderLookAtVectors = "Show Look-at Vectors";
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
const QString RenderMaxTexture64MB = "64 MB";
const QString RenderMaxTexture256MB = "256 MB";
const QString RenderMaxTexture512MB = "512 MB";
const QString RenderMaxTexture1024MB = "1024 MB";
const QString RenderMaxTexture2048MB = "2048 MB";
const QString RenderResolution = "Scale Resolution";
const QString RenderResolutionOne = "1";
const QString RenderResolutionTwoThird = "2/3";

View file

@ -230,7 +230,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
}
_leftEyePosition = _rightEyePosition = getPosition();
_eyePosition = calculateAverageEyePosition();
_eyePosition = getPosition();
if (!billboard && _owningAvatar) {
auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel();
@ -238,6 +238,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition);
}
}
_eyePosition = calculateAverageEyePosition();
}
void Head::calculateMouthShapes() {

View file

@ -317,6 +317,37 @@ void MyAvatar::update(float deltaTime) {
}
currentEnergy = max(0.0f, min(currentEnergy,1.0f));
emit energyChanged(currentEnergy);
updateEyeContactTarget(deltaTime);
}
void MyAvatar::updateEyeContactTarget(float deltaTime) {
_eyeContactTargetTimer -= deltaTime;
if (_eyeContactTargetTimer < 0.0f) {
const float CHANCE_OF_CHANGING_TARGET = 0.01f;
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
float const FIFTY_FIFTY_CHANCE = 0.5f;
float const EYE_TO_MOUTH_CHANCE = 0.25f;
switch (_eyeContactTarget) {
case LEFT_EYE:
_eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : RIGHT_EYE;
break;
case RIGHT_EYE:
_eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : LEFT_EYE;
break;
case MOUTH:
default:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? RIGHT_EYE : LEFT_EYE;
break;
}
const float EYE_TARGET_DELAY_TIME = 0.33f;
_eyeContactTargetTimer = EYE_TARGET_DELAY_TIME;
}
}
}
extern QByteArray avatarStateToFrame(const AvatarData* _avatar);
@ -944,22 +975,6 @@ void MyAvatar::clearLookAtTargetAvatar() {
}
eyeContactTarget MyAvatar::getEyeContactTarget() {
float const CHANCE_OF_CHANGING_TARGET = 0.01f;
if (randFloat() < CHANCE_OF_CHANGING_TARGET) {
float const FIFTY_FIFTY_CHANCE = 0.5f;
switch (_eyeContactTarget) {
case LEFT_EYE:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? MOUTH : RIGHT_EYE;
break;
case RIGHT_EYE:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? LEFT_EYE : MOUTH;
break;
case MOUTH:
_eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? RIGHT_EYE : LEFT_EYE;
break;
}
}
return _eyeContactTarget;
}
@ -1323,23 +1338,8 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) {
}
void MyAvatar::initAnimGraph() {
// avatar.json
// https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9
//
// ik-avatar.json
// https://gist.github.com/hyperlogic/e58e0a24cc341ad5d060
//
// ik-avatar-hands.json
// https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb
//
// ik-avatar-hands-idle.json
// https://gist.githubusercontent.com/hyperlogic/d951c78532e7a20557ad
//
// or run a local web-server
// python -m SimpleHTTPServer&
//auto graphUrl = QUrl("http://localhost:8000/avatar.json");
auto graphUrl =_animGraphUrl.isEmpty() ?
QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") :
QUrl::fromLocalFile(PathUtils::resourcesPath() + "avatar/avatar-animation.json") :
QUrl(_animGraphUrl);
_rig->initAnimGraph(graphUrl);

View file

@ -331,6 +331,8 @@ private:
bool cameraInsideHead() const;
void updateEyeContactTarget(float deltaTime);
// These are made private for MyAvatar so that you will use the "use" methods instead
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
@ -371,6 +373,7 @@ private:
float _oculusYawOffset;
eyeContactTarget _eyeContactTarget;
float _eyeContactTargetTimer { 0.0f };
glm::vec3 _trackedHeadPosition;

View file

@ -127,9 +127,9 @@ int main(int argc, const char* argv[]) {
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
qint64 clockSkew = atoll(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qCDebug(interfaceapp, "clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
qCDebug(interfaceapp) << "clockSkewOption=" << clockSkewOption << "clockSkew=" << clockSkew;
}
// Oculus initialization MUST PRECEDE OpenGL context creation.

View file

@ -292,6 +292,8 @@ void AssetMappingModel::refresh() {
} else {
emit errorGettingMappings(request->getErrorString());
}
request->deleteLater();
});
request->start();

View file

@ -281,7 +281,7 @@ void ApplicationOverlay::buildFramebufferObject() {
_overlayFramebuffer->setRenderBuffer(0, newColorAttachment);
}
}
// If the overlay framebuffer still has no color attachment, no textures were available for rendering, so build a new one
if (!_overlayFramebuffer->getRenderBuffer(0)) {
const gpu::Sampler OVERLAY_SAMPLER(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP);

View file

@ -515,7 +515,9 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost());
QString incomingRecovered = locale.toString((uint)seqStats.getRecovered());
int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC;
qint64 clockSkewInUsecs = node->getClockSkewUsec();
QString formattedClockSkewString = formatUsecTime(clockSkewInUsecs);
qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC;
QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage());
QString incomingPingTimeString = locale.toString(node->getPingMs());
QString incomingClockSkewString = locale.toString(clockSkewInMS);
@ -536,7 +538,9 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
" Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs";
serverDetails << "<br/>" <<
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs";
" Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" <<
" [" << qPrintable(formattedClockSkewString) << "]";
serverDetails << "<br/>" << "Incoming" <<
" Bytes: " << qPrintable(incomingBytesString) <<

View file

@ -248,7 +248,11 @@ static AnimNode::Pointer loadClipNode(const QJsonObject& jsonObj, const QString&
READ_OPTIONAL_STRING(loopFlagVar, jsonObj);
READ_OPTIONAL_STRING(mirrorFlagVar, jsonObj);
auto node = std::make_shared<AnimClip>(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
// animation urls can be relative to the containing url document.
auto tempUrl = QUrl(url);
tempUrl = jsonUrl.resolved(tempUrl);
auto node = std::make_shared<AnimClip>(id, tempUrl.toString(), startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
if (!startFrameVar.isEmpty()) {
node->setStartFrameVar(startFrameVar);

View file

@ -820,16 +820,24 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
return;
}
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (!entity) {
QString collisionSoundURL;
float mass = 1.0; // value doesn't get used, but set it so compiler is quiet
AACube minAACube;
bool success = false;
_tree->withReadLock([&] {
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (entity) {
collisionSoundURL = entity->getCollisionSoundURL();
mass = entity->computeMass();
minAACube = entity->getMinimumAACube(success);
}
});
if (!success) {
return;
}
const QString& collisionSoundURL = entity->getCollisionSoundURL();
if (collisionSoundURL.isEmpty()) {
return;
}
const float mass = entity->computeMass();
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
// The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact,
// but that first contact depends on exactly where we hit in the physics step.
@ -854,11 +862,6 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
// Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2)
const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f;
bool success;
auto minAACube = entity->getMinimumAACube(success);
if (!success) {
return;
}
const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2);
AudioInjector::playSound(collisionSoundURL, volume, stretchFactor, position);
}

View file

@ -29,7 +29,7 @@ void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer<Received
}
}
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew) {
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew) {
if (type == PacketType::EntityAdd || type == PacketType::EntityEdit) {
EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew);
}

View file

@ -32,7 +32,7 @@ public:
// My server type is the model server
virtual char getMyNodeType() const { return NodeType::EntityServer; }
virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew);
virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, qint64 clockSkew);
public slots:
void processEntityEditNackPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);

View file

@ -370,7 +370,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
return 0;
}
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
qint64 clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
BufferParser parser(data, bytesLeftToRead);
@ -485,7 +485,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
qCDebug(entities) << " now:" << now;
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
qCDebug(entities) << " clockSkew:" << clockSkew;
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
@ -731,7 +731,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// we want to extrapolate the motion forward to compensate for packet travel time, but
// we don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false);
stepKinematicMotion(skipTimeForward);
}
if (overwriteLocalData) {
@ -760,7 +760,7 @@ void EntityItem::debugDump() const {
}
// adjust any internal timestamps to fix clock skew for this server
void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, int clockSkew) {
void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew) {
unsigned char* dataAt = reinterpret_cast<unsigned char*>(buffer.data());
int octets = numberOfThreeBitSectionsInCode(dataAt);
int lengthOfOctcode = (int)bytesRequiredForCodeLength(octets);
@ -872,130 +872,120 @@ void EntityItem::simulate(const quint64& now) {
qCDebug(entities) << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated;
#endif
simulateKinematicMotion(timeElapsed);
if (!hasActions()) {
if (!stepKinematicMotion(timeElapsed)) {
// this entity is no longer moving
// flag it to transition from KINEMATIC to STATIC
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
setAcceleration(Vectors::ZERO);
}
}
_lastSimulated = now;
}
void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
#ifdef WANT_DEBUG
qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed;
#endif
bool EntityItem::stepKinematicMotion(float timeElapsed) {
// get all the data
Transform transform;
glm::vec3 linearVelocity;
glm::vec3 angularVelocity;
getLocalTransformAndVelocities(transform, linearVelocity, angularVelocity);
const float MIN_TIME_SKIP = 0.0f;
const float MAX_TIME_SKIP = 1.0f; // in seconds
timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP);
if (hasActions()) {
return;
// find out if it is moving
bool isSpinning = (glm::length2(angularVelocity) > 0.0f);
float linearSpeedSquared = glm::length2(linearVelocity);
bool isTranslating = linearSpeedSquared > 0.0f;
bool moving = isTranslating || isSpinning;
if (!moving) {
return false;
}
if (hasLocalAngularVelocity()) {
glm::vec3 localAngularVelocity = getLocalAngularVelocity();
if (timeElapsed <= 0.0f) {
// someone gave us a useless time value so bail early
// but return 'true' because it is moving
return true;
}
const float MAX_TIME_ELAPSED = 1.0f; // seconds
if (timeElapsed > MAX_TIME_ELAPSED) {
qCWarning(entities) << "kinematic timestep = " << timeElapsed << " truncated to " << MAX_TIME_ELAPSED;
}
timeElapsed = glm::min(timeElapsed, MAX_TIME_ELAPSED);
if (isSpinning) {
// angular damping
if (_angularDamping > 0.0f) {
localAngularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
#ifdef WANT_DEBUG
qCDebug(entities) << " angularDamping :" << _angularDamping;
qCDebug(entities) << " newAngularVelocity:" << localAngularVelocity;
#endif
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
}
float angularSpeed = glm::length(localAngularVelocity);
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
if (setFlags && angularSpeed > 0.0f) {
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
}
localAngularVelocity = ENTITY_ITEM_ZERO_VEC3;
const float MIN_KINEMATIC_ANGULAR_SPEED_SQUARED =
KINEMATIC_ANGULAR_SPEED_THRESHOLD * KINEMATIC_ANGULAR_SPEED_THRESHOLD;
if (glm::length2(angularVelocity) < MIN_KINEMATIC_ANGULAR_SPEED_SQUARED) {
angularVelocity = Vectors::ZERO;
} else {
// for improved agreement with the way Bullet integrates rotations we use an approximation
// and break the integration into bullet-sized substeps
glm::quat rotation = getRotation();
glm::quat rotation = transform.getRotation();
float dt = timeElapsed;
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) {
glm::quat dQ = computeBulletRotationStep(localAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
while (dt > 0.0f) {
glm::quat dQ = computeBulletRotationStep(angularVelocity, glm::min(dt, PHYSICS_ENGINE_FIXED_SUBSTEP));
rotation = glm::normalize(dQ * rotation);
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
}
// NOTE: this final partial substep can drift away from a real Bullet simulation however
// it only becomes significant for rapidly rotating objects
// (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec).
glm::quat dQ = computeBulletRotationStep(localAngularVelocity, dt);
rotation = glm::normalize(dQ * rotation);
bool success;
setOrientation(rotation, success, false);
transform.setRotation(rotation);
}
setLocalAngularVelocity(localAngularVelocity);
}
if (hasLocalVelocity()) {
// acceleration is in the global frame, so transform it into the local frame.
// TODO: Move this into SpatiallyNestable.
bool success;
Transform transform = getParentTransform(success);
glm::vec3 localAcceleration(glm::vec3::_null);
if (success) {
localAcceleration = glm::inverse(transform.getRotation()) * getAcceleration();
} else {
localAcceleration = getAcceleration();
}
glm::vec3 position = transform.getTranslation();
const float MIN_KINEMATIC_LINEAR_SPEED_SQUARED =
KINEMATIC_LINEAR_SPEED_THRESHOLD * KINEMATIC_LINEAR_SPEED_THRESHOLD;
if (isTranslating) {
glm::vec3 deltaVelocity = Vectors::ZERO;
// linear damping
glm::vec3 localVelocity = getLocalVelocity();
if (_damping > 0.0f) {
localVelocity *= powf(1.0f - _damping, timeElapsed);
#ifdef WANT_DEBUG
qCDebug(entities) << " damping:" << _damping;
qCDebug(entities) << " velocity AFTER dampingResistance:" << localVelocity;
qCDebug(entities) << " glm::length(velocity):" << glm::length(localVelocity);
#endif
deltaVelocity = (powf(1.0f - _damping, timeElapsed) - 1.0f) * linearVelocity;
}
// integrate position forward
glm::vec3 localPosition = getLocalPosition();
glm::vec3 newLocalPosition = localPosition + (localVelocity * timeElapsed) + 0.5f * localAcceleration * timeElapsed * timeElapsed;
const float MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED = 1.0e-4f; // 0.01 m/sec^2
if (glm::length2(_acceleration) > MIN_KINEMATIC_LINEAR_ACCELERATION_SQUARED) {
// yes acceleration
// acceleration is in world-frame but we need it in local-frame
glm::vec3 linearAcceleration = _acceleration;
bool success;
Transform parentTransform = getParentTransform(success);
if (success) {
linearAcceleration = glm::inverse(parentTransform.getRotation()) * linearAcceleration;
}
deltaVelocity += linearAcceleration * timeElapsed;
#ifdef WANT_DEBUG
qCDebug(entities) << " EntityItem::simulate()....";
qCDebug(entities) << " timeElapsed:" << timeElapsed;
qCDebug(entities) << " old AACube:" << getMaximumAACube();
qCDebug(entities) << " old position:" << localPosition;
qCDebug(entities) << " old velocity:" << localVelocity;
qCDebug(entities) << " old getAABox:" << getAABox();
qCDebug(entities) << " newPosition:" << newPosition;
qCDebug(entities) << " glm::distance(newPosition, position):" << glm::distance(newLocalPosition, localPosition);
#endif
localPosition = newLocalPosition;
// apply effective acceleration, which will be the same as gravity if the Entity isn't at rest.
localVelocity += localAcceleration * timeElapsed;
float speed = glm::length(localVelocity);
const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec
if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) {
setVelocity(ENTITY_ITEM_ZERO_VEC3);
if (setFlags && speed > 0.0f) {
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
if (linearSpeedSquared < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
&& glm::length2(deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED
&& glm::length2(linearVelocity + deltaVelocity) < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) {
linearVelocity = Vectors::ZERO;
} else {
// NOTE: we do NOT include the second-order acceleration term (0.5 * a * dt^2)
// when computing the displacement because Bullet also ignores that term. Yes,
// this is an approximation and it works best when dt is small.
position += timeElapsed * linearVelocity;
linearVelocity += deltaVelocity;
}
} else {
setLocalPosition(localPosition);
setLocalVelocity(localVelocity);
// no acceleration
if (linearSpeedSquared < MIN_KINEMATIC_LINEAR_SPEED_SQUARED) {
linearVelocity = Vectors::ZERO;
} else {
// NOTE: we don't use second-order acceleration term for linear displacement
// because Bullet doesn't use it.
position += timeElapsed * linearVelocity;
linearVelocity += deltaVelocity;
}
}
#ifdef WANT_DEBUG
qCDebug(entities) << " new position:" << position;
qCDebug(entities) << " new velocity:" << velocity;
qCDebug(entities) << " new AACube:" << getMaximumAACube();
qCDebug(entities) << " old getAABox:" << getAABox();
#endif
}
transform.setTranslation(position);
setLocalTransformAndVelocities(transform, linearVelocity, angularVelocity);
return true;
}
bool EntityItem::isMoving() const {

View file

@ -144,7 +144,7 @@ public:
static int expectedBytes();
static void adjustEditPacketForClockSkew(QByteArray& buffer, int clockSkew);
static void adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSkew);
// perform update
virtual void update(const quint64& now) { _lastUpdated = now; }
@ -152,7 +152,7 @@ public:
// perform linear extrapolation for SimpleEntitySimulation
void simulate(const quint64& now);
void simulateKinematicMotion(float timeElapsed, bool setFlags=true);
bool stepKinematicMotion(float timeElapsed); // return 'true' if moving
virtual bool needsToCallUpdate() const { return false; }

View file

@ -74,13 +74,18 @@ void EntitySimulation::addEntityInternal(EntityItemPointer entity) {
if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo()) {
QMutexLocker lock(&_mutex);
_simpleKinematicEntities.insert(entity);
entity->setLastSimulated(usecTimestampNow());
}
}
void EntitySimulation::changeEntityInternal(EntityItemPointer entity) {
QMutexLocker lock(&_mutex);
if (entity->isMovingRelativeToParent() && !entity->getPhysicsInfo()) {
int numKinematicEntities = _simpleKinematicEntities.size();
_simpleKinematicEntities.insert(entity);
if (numKinematicEntities != _simpleKinematicEntities.size()) {
entity->setLastSimulated(usecTimestampNow());
}
} else {
_simpleKinematicEntities.remove(entity);
}

View file

@ -33,6 +33,16 @@ QHash<QString, float> COMMENT_SCALE_HINTS = {{"This file uses centimeters as uni
const QString SMART_DEFAULT_MATERIAL_NAME = "High Fidelity smart default material name";
namespace {
template<class T>
T& checked_at(QVector<T>& vector, int i) {
if (i < 0 || i >= vector.size()) {
throw std::out_of_range("index " + std::to_string(i) + "is out of range");
}
return vector[i];
}
}
OBJTokenizer::OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) {
}
@ -455,9 +465,9 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
FaceGroup faceGroup = faceGroups[meshPartCount];
bool specifiesUV = false;
foreach(OBJFace face, faceGroup) {
glm::vec3 v0 = vertices[face.vertexIndices[0]];
glm::vec3 v1 = vertices[face.vertexIndices[1]];
glm::vec3 v2 = vertices[face.vertexIndices[2]];
glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]);
glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]);
glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]);
meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices
mesh.vertices << v0;
meshPart.triangleIndices.append(mesh.vertices.count());
@ -467,19 +477,19 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
glm::vec3 n0, n1, n2;
if (face.normalIndices.count()) {
n0 = normals[face.normalIndices[0]];
n1 = normals[face.normalIndices[1]];
n2 = normals[face.normalIndices[2]];
n0 = checked_at(normals, face.normalIndices[0]);
n1 = checked_at(normals, face.normalIndices[1]);
n2 = checked_at(normals, face.normalIndices[2]);
} else { // generate normals from triangle plane if not provided
n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0);
}
mesh.normals << n0 << n1 << n2;
if (face.textureUVIndices.count()) {
specifiesUV = true;
mesh.texCoords
<< textureUVs[face.textureUVIndices[0]]
<< textureUVs[face.textureUVIndices[1]]
<< textureUVs[face.textureUVIndices[2]];
mesh.texCoords <<
checked_at(textureUVs, face.textureUVIndices[0]) <<
checked_at(textureUVs, face.textureUVIndices[1]) <<
checked_at(textureUVs, face.textureUVIndices[2]);
} else {
glm::vec2 corner(0.0f, 1.0f);
mesh.texCoords << corner << corner << corner;

View file

@ -207,6 +207,7 @@ protected:
static void incrementBufferGPUCount();
static void decrementBufferGPUCount();
static void updateBufferGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
static void incrementTextureGPUCount();
static void decrementTextureGPUCount();
static void updateTextureGPUMemoryUsage(Size prevObjectSize, Size newObjectSize);

View file

@ -14,7 +14,7 @@
#include <assert.h>
#include <memory>
#include <glm/glm.hpp>
#include "Forward.h"
namespace gpu {
@ -37,28 +37,6 @@ private:
friend class Backend;
};
typedef int Stamp;
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uint8;
typedef char int8;
typedef unsigned char Byte;
typedef size_t Offset;
typedef glm::mat4 Mat4;
typedef glm::mat3 Mat3;
typedef glm::vec4 Vec4;
typedef glm::ivec4 Vec4i;
typedef glm::vec3 Vec3;
typedef glm::vec2 Vec2;
typedef glm::ivec2 Vec2i;
typedef glm::uvec2 Vec2u;
// Description of a scalar type
enum Type {

View file

@ -9,69 +9,77 @@
#ifndef hifi_gpu_Forward_h
#define hifi_gpu_Forward_h
#include <stdint.h>
#include <memory>
#include <vector>
#include <glm/glm.hpp>
namespace gpu {
class Batch;
class Backend;
class Context;
typedef std::shared_ptr<Context> ContextPointer;
using ContextPointer = std::shared_ptr<Context>;
class GPUObject;
typedef int Stamp;
typedef uint32_t uint32;
typedef int32_t int32;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint8_t uint8;
typedef int8_t int8;
using Stamp = int;
using uint32 = uint32_t;
using int32 = int32_t;
using uint16 = uint16_t;
using int16 = int16_t;
using uint8 = uint8_t;
using int8 = int8_t;
typedef uint8 Byte;
typedef uint32 Offset;
typedef std::vector<Offset> Offsets;
using Byte = uint8;
using Offset = size_t;
using Offsets = std::vector<Offset>;
typedef glm::mat4 Mat4;
typedef glm::mat3 Mat3;
typedef glm::vec4 Vec4;
typedef glm::ivec4 Vec4i;
typedef glm::vec3 Vec3;
typedef glm::vec2 Vec2;
typedef glm::ivec2 Vec2i;
typedef glm::uvec2 Vec2u;
using Mat4 = glm::mat4;
using Mat3 = glm::mat3;
using Vec4 = glm::vec4;
using Vec4i = glm::ivec4;
using Vec3 = glm::vec3;
using Vec2 = glm::vec2;
using Vec2i = glm::ivec2;
using Vec2u = glm::uvec2;
using Vec3u = glm::uvec3;
using Vec3u = glm::uvec3;
class Element;
typedef Element Format;
using Format = Element;
class Swapchain;
typedef std::shared_ptr<Swapchain> SwapchainPointer;
using SwapchainPointer = std::shared_ptr<Swapchain>;
class Framebuffer;
typedef std::shared_ptr<Framebuffer> FramebufferPointer;
using FramebufferPointer = std::shared_ptr<Framebuffer>;
class Pipeline;
typedef std::shared_ptr<Pipeline> PipelinePointer;
typedef std::vector<PipelinePointer> Pipelines;
using PipelinePointer = std::shared_ptr<Pipeline>;
using Pipelines = std::vector<PipelinePointer>;
class Query;
typedef std::shared_ptr<Query> QueryPointer;
typedef std::vector<QueryPointer> Queries;
using QueryPointer = std::shared_ptr<Query>;
using Queries = std::vector<QueryPointer>;
class Resource;
class Buffer;
typedef std::shared_ptr<Buffer> BufferPointer;
typedef std::vector<BufferPointer> Buffers;
using BufferPointer = std::shared_ptr<Buffer>;
using Buffers = std::vector<BufferPointer>;
class BufferView;
class Shader;
typedef Shader::Pointer ShaderPointer;
typedef std::vector<ShaderPointer> Shaders;
using ShaderPointer = std::shared_ptr<Shader>;
using Shaders = std::vector<ShaderPointer>;
class State;
typedef std::shared_ptr<State> StatePointer;
typedef std::vector<StatePointer> States;
using StatePointer = std::shared_ptr<State>;
using States = std::vector<StatePointer>;
class Stream;
class BufferStream;
typedef std::shared_ptr<BufferStream> BufferStreamPointer;
using BufferStreamPointer = std::shared_ptr<BufferStream>;
class Texture;
class SphericalHarmonics;
typedef std::shared_ptr<SphericalHarmonics> SHPointer;
using SHPointer = std::shared_ptr<SphericalHarmonics>;
class Sampler;
class Texture;
typedef std::shared_ptr<Texture> TexturePointer;
typedef std::vector<TexturePointer> Textures;
using TexturePointer = std::shared_ptr<Texture>;
using Textures = std::vector<TexturePointer>;
class TextureView;
typedef std::vector<TextureView> TextureViews;
using TextureViews = std::vector<TextureView>;
}
#endif

View file

@ -125,7 +125,7 @@ void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) {
if (_depthStencilBuffer) {
_depthStencilBuffer._texture->resize2D(width, height, numSamples);
_numSamples = _depthStencilBuffer._texture->getNumSamples();
++_depthStamp;
++_depthStamp;
}
_width = width;

View file

@ -14,6 +14,8 @@
#include <queue>
#include <list>
#include <glm/gtc/type_ptr.hpp>
#include <GPUIdent.h>
#include <NumericalConstants.h>
#if defined(NSIGHT_FOUND)
#include "nvToolsExt.h"
@ -86,10 +88,18 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
void GLBackend::init() {
static std::once_flag once;
std::call_once(once, [] {
QString vendor{ (const char*)glGetString(GL_VENDOR) };
QString renderer{ (const char*)glGetString(GL_RENDERER) };
qCDebug(gpulogging) << "GL Version: " << QString((const char*) glGetString(GL_VERSION));
qCDebug(gpulogging) << "GL Shader Language Version: " << QString((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION));
qCDebug(gpulogging) << "GL Vendor: " << QString((const char*) glGetString(GL_VENDOR));
qCDebug(gpulogging) << "GL Renderer: " << QString((const char*) glGetString(GL_RENDERER));
qCDebug(gpulogging) << "GL Vendor: " << vendor;
qCDebug(gpulogging) << "GL Renderer: " << renderer;
GPUIdent* gpu = GPUIdent::getInstance(vendor, renderer);
// From here on, GPUIdent::getInstance()->getMumble() should efficiently give the same answers.
qCDebug(gpulogging) << "GPU:";
qCDebug(gpulogging) << "\tcard:" << gpu->getName();
qCDebug(gpulogging) << "\tdriver:" << gpu->getDriver();
qCDebug(gpulogging) << "\tdedicated memory:" << gpu->getMemory() << "MB";
glewExperimental = true;
GLenum err = glewInit();
@ -117,6 +127,50 @@ void GLBackend::init() {
});
}
Context::Size GLBackend::getDedicatedMemory() {
static Context::Size dedicatedMemory { 0 };
static std::once_flag once;
std::call_once(once, [&] {
#ifdef Q_OS_WIN
if (!dedicatedMemory && wglGetGPUIDsAMD && wglGetGPUInfoAMD) {
UINT maxCount = wglGetGPUIDsAMD(0, 0);
std::vector<UINT> ids;
ids.resize(maxCount);
wglGetGPUIDsAMD(maxCount, &ids[0]);
GLuint memTotal;
wglGetGPUInfoAMD(ids[0], WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(GLuint), &memTotal);
dedicatedMemory = MB_TO_BYTES(memTotal);
}
#endif
if (!dedicatedMemory) {
GLint atiGpuMemory[4];
// not really total memory, but close enough if called early enough in the application lifecycle
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, atiGpuMemory);
if (GL_NO_ERROR == glGetError()) {
dedicatedMemory = KB_TO_BYTES(atiGpuMemory[0]);
}
}
if (!dedicatedMemory) {
GLint nvGpuMemory { 0 };
glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &nvGpuMemory);
if (GL_NO_ERROR == glGetError()) {
dedicatedMemory = KB_TO_BYTES(nvGpuMemory);
}
}
if (!dedicatedMemory) {
auto gpuIdent = GPUIdent::getInstance();
if (gpuIdent && gpuIdent->isValid()) {
dedicatedMemory = MB_TO_BYTES(gpuIdent->getMemory());
}
}
});
return dedicatedMemory;
}
Backend* GLBackend::createBackend() {
return new GLBackend();
}
@ -140,6 +194,7 @@ void GLBackend::renderPassTransfer(Batch& batch) {
const Batch::Commands::value_type* command = batch.getCommands().data();
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
_inRenderTransferPass = true;
{ // Sync all the buffers
PROFILE_RANGE("syncGPUBuffer");
@ -187,7 +242,7 @@ void GLBackend::renderPassTransfer(Batch& batch) {
_transform.transfer(batch);
}
_inRenderTransferPass = false;
}
void GLBackend::renderPassDraw(Batch& batch) {
@ -246,24 +301,17 @@ void GLBackend::render(Batch& batch) {
if (!batch.isStereoEnabled()) {
_stereo._enable = false;
}
{
PROFILE_RANGE("Transfer");
renderPassTransfer(batch);
}
{
PROFILE_RANGE(_stereo._enable ? "LeftRender" : "Render");
PROFILE_RANGE(_stereo._enable ? "Render Stereo" : "Render");
renderPassDraw(batch);
}
if (_stereo._enable) {
PROFILE_RANGE("RightRender");
_stereo._pass = 1;
renderPassDraw(batch);
_stereo._pass = 0;
}
// Restore the saved stereo state for the next batch
_stereo._enable = savedStereo;
}
@ -319,17 +367,38 @@ void GLBackend::syncCache() {
glEnable(GL_LINE_SMOOTH);
}
void GLBackend::setupStereoSide(int side) {
ivec4 vp = _transform._viewport;
vp.z /= 2;
glViewport(vp.x + side * vp.z, vp.y, vp.z, vp.w);
_transform.bindCurrentCamera(side);
}
void GLBackend::do_draw(Batch& batch, size_t paramOffset) {
Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint;
GLenum mode = _primitiveToGLmode[primitiveType];
uint32 numVertices = batch._params[paramOffset + 1]._uint;
uint32 startVertex = batch._params[paramOffset + 0]._uint;
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += numVertices / 3;
_stats._DSNumDrawcalls++;
if (isStereo()) {
setupStereoSide(0);
glDrawArrays(mode, startVertex, numVertices);
setupStereoSide(1);
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += 2 * numVertices / 3;
_stats._DSNumDrawcalls += 2;
} else {
glDrawArrays(mode, startVertex, numVertices);
_stats._DSNumTriangles += numVertices / 3;
_stats._DSNumDrawcalls++;
}
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
(void) CHECK_GL_ERROR();
}
void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) {
@ -343,9 +412,19 @@ void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) {
auto typeByteSize = TYPE_SIZE[_input._indexBufferType];
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += numIndices / 3;
_stats._DSNumDrawcalls++;
if (isStereo()) {
setupStereoSide(0);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
setupStereoSide(1);
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += 2 * numIndices / 3;
_stats._DSNumDrawcalls += 2;
} else {
glDrawElements(mode, numIndices, glType, indexBufferByteOffset);
_stats._DSNumTriangles += numIndices / 3;
_stats._DSNumDrawcalls++;
}
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
@ -358,14 +437,35 @@ void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) {
uint32 numVertices = batch._params[paramOffset + 2]._uint;
uint32 startVertex = batch._params[paramOffset + 1]._uint;
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (numInstances * numVertices) / 3;
_stats._DSNumDrawcalls += numInstances;
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
setupStereoSide(0);
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
setupStereoSide(1);
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (trueNumInstances * numVertices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
} else {
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
_stats._DSNumTriangles += (numInstances * numVertices) / 3;
_stats._DSNumDrawcalls += numInstances;
}
_stats._DSNumAPIDrawcalls++;
(void) CHECK_GL_ERROR();
}
void glbackend_glDrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance) {
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
glDrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, primcount, basevertex, baseinstance);
#else
glDrawElementsInstanced(mode, count, type, indices, primcount);
#endif
}
void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
GLint numInstances = batch._params[paramOffset + 4]._uint;
GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 3]._uint];
@ -378,15 +478,23 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) {
auto typeByteSize = TYPE_SIZE[_input._indexBufferType];
GLvoid* indexBufferByteOffset = reinterpret_cast<GLvoid*>(startIndex * typeByteSize + _input._indexBufferOffset);
#if (GPU_INPUT_PROFILE == GPU_CORE_43)
glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
#else
glDrawElementsInstanced(mode, numIndices, glType, indexBufferByteOffset, numInstances);
Q_UNUSED(startInstance);
#endif
_stats._DSNumTriangles += (numInstances * numIndices) / 3;
_stats._DSNumDrawcalls += numInstances;
if (isStereo()) {
GLint trueNumInstances = 2 * numInstances;
setupStereoSide(0);
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
setupStereoSide(1);
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
_stats._DSNumTriangles += (trueNumInstances * numIndices) / 3;
_stats._DSNumDrawcalls += trueNumInstances;
} else {
glbackend_glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance);
_stats._DSNumTriangles += (numInstances * numIndices) / 3;
_stats._DSNumDrawcalls += numInstances;
}
_stats._DSNumAPIDrawcalls++;
(void)CHECK_GL_ERROR();
@ -461,10 +569,9 @@ void GLBackend::resetStages() {
#define ADD_COMMAND_GL(call) _commands.push_back(COMMAND_##call); _commandOffsets.push_back(_params.size());
// As long as we don;t use several versions of shaders we can avoid this more complex code path
// #define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc, isStereo());
#define GET_UNIFORM_LOCATION(shaderUniformLoc) shaderUniformLoc
// THis will be used in the next PR
// #define GET_UNIFORM_LOCATION(shaderUniformLoc) _pipeline._programShader->getUniformLocation(shaderUniformLoc)
void Batch::_glActiveBindTexture(GLenum unit, GLenum target, GLuint texture) {
// clean the cache on the texture unit we are going to use so the next call to setResourceTexture() at the same slot works fine
@ -492,6 +599,7 @@ void Batch::_glUniform1i(GLint location, GLint v0) {
_params.push_back(v0);
_params.push_back(location);
}
void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) {
if (_pipeline._program == 0) {
// We should call updatePipeline() to bind the program but we are not doing that
@ -499,6 +607,7 @@ void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) {
return;
}
updatePipeline();
glUniform1f(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 1]._int),
batch._params[paramOffset + 0]._int);
@ -688,6 +797,7 @@ void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) {
return;
}
updatePipeline();
glUniformMatrix4fv(
GET_UNIFORM_LOCATION(batch._params[paramOffset + 3]._int),
batch._params[paramOffset + 2]._uint,

View file

@ -17,6 +17,7 @@
#include <queue>
#include <utility>
#include <list>
#include <array>
#include <gl/Config.h>
@ -37,6 +38,8 @@ class GLBackend : public Backend {
explicit GLBackend(bool syncCache);
GLBackend();
public:
static Context::Size getDedicatedMemory();
virtual ~GLBackend();
virtual void render(Batch& batch);
@ -82,11 +85,35 @@ public:
const Stamp _storageStamp;
Stamp _contentStamp { 0 };
const GLenum _target;
const uint16 _maxMip;
const uint16 _minMip;
const bool _transferrable;
GLTexture(const gpu::Texture& gpuTexture);
struct DownsampleSource {
using Pointer = std::shared_ptr<DownsampleSource>;
DownsampleSource(GLTexture& oldTexture);
~DownsampleSource();
const GLuint _texture;
const uint16 _minMip;
const uint16 _maxMip;
};
DownsampleSource::Pointer _downsampleSource;
GLTexture(bool transferrable, const gpu::Texture& gpuTexture);
GLTexture(GLTexture& originalTexture, const gpu::Texture& gpuTexture);
~GLTexture();
// Return a floating point value indicating how much of the allowed
// texture memory we are currently consuming. A value of 0 indicates
// no texture memory usage, while a value of 1 indicates all available / allowed memory
// is consumed. A value above 1 indicates that there is a problem.
static float getMemoryPressure();
void withPreservedTexture(std::function<void()> f);
void createTexture();
void allocateStorage();
GLuint size() const { return _size; }
GLuint virtualSize() const { return _virtualSize; }
@ -118,26 +145,34 @@ public:
// Is the texture in a state where it can be rendered with no work?
bool isReady() const;
// Is this texture pushing us over the memory limit?
bool isOverMaxMemory() const;
// Move the image bits from the CPU to the GPU
void transfer() const;
// Execute any post-move operations that must occur only on the main thread
void postTransfer();
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
static const size_t CUBE_NUM_FACES = 6;
static const GLenum CUBE_FACE_LAYOUT[6];
private:
friend class GLTextureTransferHelper;
GLTexture(bool transferrable, const gpu::Texture& gpuTexture, bool init);
// at creation the true texture is created in GL
// it becomes public only when ready.
GLuint _privateTexture{ 0 };
void setSize(GLuint size);
void setVirtualSize(GLuint size);
const std::vector<GLenum>& getFaceTargets() const;
GLuint _size; // true size as reported by the gl api
GLuint _virtualSize; // theorical size as expected
GLuint _numLevels{ 0 };
void setSize(GLuint size);
const GLuint _virtualSize; // theorical size as expected
GLuint _size { 0 }; // true size as reported by the gl api
void transferMip(uint16_t mipLevel, uint8_t face = 0) const;
@ -167,24 +202,24 @@ public:
};
using ShaderObjects = std::array< ShaderObject, NumVersions >;
using UniformMapping = std::map<GLint, GLint>;
using UniformMappingVersions = std::vector<UniformMapping>;
GLShader();
~GLShader();
ShaderObjects _shaderObjects;
UniformMappingVersions _uniformMappings;
GLuint getProgram() const {
return _shaderObjects[Mono].glprogram;
GLuint getProgram(Version version = Mono) const {
return _shaderObjects[version].glprogram;
}
GLint getUniformLocation(GLint srcLoc) {
GLint getUniformLocation(GLint srcLoc, Version version = Mono) {
// THIS will be used in the future PR as we grow the number of versions
// return _uniformMappings[version][srcLoc];
return srcLoc;
// THIS will be used in the next PR
// return _uniformMappings[Mono][srcLoc];
}
};
@ -319,9 +354,15 @@ public:
void do_setStateColorWriteMask(uint32 mask);
protected:
static const size_t INVALID_OFFSET = (size_t)-1;
bool _inRenderTransferPass;
void renderPassTransfer(Batch& batch);
void renderPassDraw(Batch& batch);
void setupStereoSide(int side);
void initTextureTransferHelper();
static void transferGPUObject(const TexturePointer& texture);
@ -404,7 +445,8 @@ protected:
void resetTransformStage();
struct TransformStageState {
using TransformCameras = std::vector<TransformCamera>;
using CameraBufferElement = TransformCamera;
using TransformCameras = std::vector<CameraBufferElement>;
TransformCamera _camera;
TransformCameras _cameras;
@ -428,9 +470,11 @@ protected:
using List = std::list<Pair>;
List _cameraOffsets;
mutable List::const_iterator _camerasItr;
mutable size_t _currentCameraOffset{ INVALID_OFFSET };
void preUpdate(size_t commandIndex, const StereoState& stereo);
void update(size_t commandIndex, const StereoState& stereo) const;
void bindCurrentCamera(int stereoSide) const;
void transfer(const Batch& batch) const;
} _transform;

View file

@ -84,7 +84,9 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
}
// check the program cache
// pick the program version
GLuint glprogram = pipelineObject->_program->getProgram();
if (_pipeline._program != glprogram) {
_pipeline._program = glprogram;
_pipeline._programShader = pipelineObject->_program;

View file

@ -312,12 +312,10 @@ GLBackend::GLShader* compileBackendShader(const Shader& shader) {
// Domain specific defines
const std::string domainDefines[NUM_SHADER_DOMAINS] = {
"#define VERTEX_SHADER",
"#define PIXEL_SHADER"
"#define GPU_VERTEX_SHADER",
"#define GPU_PIXEL_SHADER"
};
// Versions specific of the shader
const std::string versionDefines[GLBackend::GLShader::NumVersions] = {
""
@ -375,7 +373,6 @@ GLBackend::GLShader* compileBackendProgram(const Shader& program) {
makeProgramBindings(programObject);
}
// So far so good, the program versions have all been created successfully
GLBackend::GLShader* object = new GLBackend::GLShader();
object->_shaderObjects = programObjects;

View file

@ -10,6 +10,8 @@
//
#include "GPULogging.h"
#include <unordered_set>
#include <unordered_map>
#include <QtCore/QThread>
#include "GLBackendShared.h"
@ -35,44 +37,166 @@ GLenum gpuToGLTextureType(const Texture& texture) {
}
GLuint allocateSingleTexture() {
Backend::incrementTextureGPUCount();
GLuint result;
glGenTextures(1, &result);
return result;
}
// FIXME placeholder for texture memory over-use
#define DEFAULT_MAX_MEMORY_MB 256
float GLBackend::GLTexture::getMemoryPressure() {
// Check for an explicit memory limit
auto availableTextureMemory = Texture::getAllowedGPUMemoryUsage();
// If no memory limit has been set, use a percentage of the total dedicated memory
if (!availableTextureMemory) {
auto totalGpuMemory = GLBackend::getDedicatedMemory();
// If no limit has been explicitly set, and the dedicated memory can't be determined,
// just use a fallback fixed value of 256 MB
if (!totalGpuMemory) {
totalGpuMemory = MB_TO_BYTES(DEFAULT_MAX_MEMORY_MB);
}
// Allow 75% of all available GPU memory to be consumed by textures
// FIXME overly conservative?
availableTextureMemory = (totalGpuMemory >> 2) * 3;
}
// Return the consumed texture memory divided by the available texture memory.
auto consumedGpuMemory = Context::getTextureGPUMemoryUsage();
return (float)consumedGpuMemory / (float)availableTextureMemory;
}
GLBackend::GLTexture::DownsampleSource::DownsampleSource(GLTexture& oldTexture) :
_texture(oldTexture._privateTexture),
_minMip(oldTexture._minMip),
_maxMip(oldTexture._maxMip)
{
// Take ownership of the GL texture
oldTexture._texture = oldTexture._privateTexture = 0;
}
GLBackend::GLTexture::DownsampleSource::~DownsampleSource() {
if (_texture) {
Backend::decrementTextureGPUCount();
glDeleteTextures(1, &_texture);
}
}
const GLenum GLBackend::GLTexture::CUBE_FACE_LAYOUT[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
// Create the texture and allocate storage
GLBackend::GLTexture::GLTexture(const Texture& texture) :
static std::map<uint16, size_t> _textureCountByMips;
static uint16 _currentMaxMipCount { 0 };
GLBackend::GLTexture::GLTexture(bool transferrable, const Texture& texture, bool init) :
_storageStamp(texture.getStamp()),
_target(gpuToGLTextureType(texture)),
_size(0),
_virtualSize(0),
_numLevels(texture.maxMip() + 1),
_maxMip(texture.maxMip()),
_minMip(texture.minMip()),
_transferrable(transferrable),
_virtualSize(texture.evalTotalSize()),
_size(_virtualSize),
_gpuTexture(texture)
{
Backend::incrementTextureGPUCount();
Backend::setGPUObject(texture, this);
{
Q_UNUSED(init);
// updateSize();
GLuint virtualSize = _gpuTexture.evalTotalSize();
setVirtualSize(virtualSize);
setSize(virtualSize);
if (_transferrable) {
uint16 mipCount = usedMipLevels();
_currentMaxMipCount = std::max(_currentMaxMipCount, mipCount);
if (!_textureCountByMips.count(mipCount)) {
_textureCountByMips[mipCount] = 1;
} else {
++_textureCountByMips[mipCount];
}
} else {
withPreservedTexture([&] {
createTexture();
});
_contentStamp = _gpuTexture.getDataStamp();
postTransfer();
}
Backend::updateTextureGPUMemoryUsage(0, _size);
Backend::updateTextureGPUVirtualMemoryUsage(0, _virtualSize);
}
void GLBackend::GLTexture::createTexture() {
_privateTexture = allocateSingleTexture();
// Create the texture and allocate storage
GLBackend::GLTexture::GLTexture(bool transferrable, const Texture& texture) :
GLTexture(transferrable, texture, true)
{
Backend::setGPUObject(texture, this);
}
GLsizei width = _gpuTexture.getWidth();
GLsizei height = _gpuTexture.getHeight();
// Create the texture and copy from the original higher resolution version
GLBackend::GLTexture::GLTexture(GLTexture& originalTexture, const gpu::Texture& texture) :
GLTexture(originalTexture._transferrable, texture, true)
{
if (!originalTexture._texture) {
qFatal("Invalid original texture");
}
Q_ASSERT(_minMip >= originalTexture._minMip);
// Our downsampler takes ownership of the texture
_downsampleSource = std::make_shared<DownsampleSource>(originalTexture);
_texture = _downsampleSource->_texture;
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat());
// Set the GPU object last because that implicitly destroys the originalTexture object
Backend::setGPUObject(texture, this);
}
GLBackend::GLTexture::~GLTexture() {
if (_privateTexture != 0) {
Backend::decrementTextureGPUCount();
glDeleteTextures(1, &_privateTexture);
}
if (_transferrable) {
uint16 mipCount = usedMipLevels();
Q_ASSERT(_textureCountByMips.count(mipCount));
auto& numTexturesForMipCount = _textureCountByMips[mipCount];
--numTexturesForMipCount;
if (0 == numTexturesForMipCount) {
_textureCountByMips.erase(mipCount);
if (mipCount == _currentMaxMipCount) {
_currentMaxMipCount = _textureCountByMips.rbegin()->first;
}
}
}
Backend::updateTextureGPUMemoryUsage(_size, 0);
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
}
const std::vector<GLenum>& GLBackend::GLTexture::getFaceTargets() const {
static std::vector<GLenum> cubeFaceTargets {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
static std::vector<GLenum> faceTargets {
GL_TEXTURE_2D
};
switch (_target) {
case GL_TEXTURE_2D:
return faceTargets;
case GL_TEXTURE_CUBE_MAP:
return cubeFaceTargets;
default:
Q_UNREACHABLE();
break;
}
Q_UNREACHABLE();
return faceTargets;
}
void GLBackend::GLTexture::withPreservedTexture(std::function<void()> f) {
GLint boundTex = -1;
switch (_target) {
case GL_TEXTURE_2D:
@ -88,47 +212,46 @@ void GLBackend::GLTexture::createTexture() {
}
(void)CHECK_GL_ERROR();
glBindTexture(_target, _privateTexture);
(void)CHECK_GL_ERROR();
// Fixme: this usage of TexStorage doesn;t work wtih compressed texture, altuogh it should.
// GO through the process of allocating the correct storage
if (GLEW_VERSION_4_2 && !_gpuTexture.getTexelFormat().isCompressed()) {
glTexStorage2D(_target, _numLevels, texelFormat.internalFormat, width, height);
(void)CHECK_GL_ERROR();
} else {
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _numLevels - 1);
for (uint16_t l = 0; l < _numLevels; l++) {
if (_gpuTexture.getType() == gpu::Texture::TEX_CUBE) {
for (size_t face = 0; face < CUBE_NUM_FACES; face++) {
glTexImage2D(CUBE_FACE_LAYOUT[face], l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
}
} else {
glTexImage2D(_target, l, texelFormat.internalFormat, width, height, 0, texelFormat.format, texelFormat.type, NULL);
}
width = std::max(1, (width / 2));
height = std::max(1, (height / 2));
}
(void)CHECK_GL_ERROR();
}
syncSampler(_gpuTexture.getSampler(), _gpuTexture.getType(), this);
(void)CHECK_GL_ERROR();
f();
glBindTexture(_target, boundTex);
(void)CHECK_GL_ERROR();
}
GLBackend::GLTexture::~GLTexture() {
if (_privateTexture != 0) {
glDeleteTextures(1, &_privateTexture);
void GLBackend::GLTexture::createTexture() {
_privateTexture = allocateSingleTexture();
glBindTexture(_target, _privateTexture);
(void)CHECK_GL_ERROR();
allocateStorage();
(void)CHECK_GL_ERROR();
syncSampler(_gpuTexture.getSampler(), _gpuTexture.getType(), this);
(void)CHECK_GL_ERROR();
}
void GLBackend::GLTexture::allocateStorage() {
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, 0);
(void)CHECK_GL_ERROR();
glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip);
(void)CHECK_GL_ERROR();
if (GLEW_VERSION_4_2 && !_gpuTexture.getTexelFormat().isCompressed()) {
// Get the dimensions, accounting for the downgrade level
Vec3u dimensions = _gpuTexture.evalMipDimensions(_minMip);
glTexStorage2D(_target, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR();
} else {
for (uint16_t l = _minMip; l <= _maxMip; l++) {
// Get the mip level dimensions, accounting for the downgrade level
Vec3u dimensions = _gpuTexture.evalMipDimensions(l);
for (GLenum target : getFaceTargets()) {
glTexImage2D(target, l - _minMip, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, NULL);
(void)CHECK_GL_ERROR();
}
}
}
Backend::updateTextureGPUMemoryUsage(_size, 0);
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, 0);
Backend::decrementTextureGPUCount();
}
@ -137,16 +260,10 @@ void GLBackend::GLTexture::setSize(GLuint size) {
_size = size;
}
void GLBackend::GLTexture::setVirtualSize(GLuint size) {
Backend::updateTextureGPUVirtualMemoryUsage(_virtualSize, size);
_virtualSize = size;
}
void GLBackend::GLTexture::updateSize() {
GLuint virtualSize = _gpuTexture.evalTotalSize();
setVirtualSize(virtualSize);
setSize(_virtualSize);
if (!_texture) {
setSize(virtualSize);
return;
}
if (_gpuTexture.getTexelFormat().isCompressed()) {
@ -161,7 +278,7 @@ void GLBackend::GLTexture::updateSize() {
(void)CHECK_GL_ERROR();
if (gpuSize) {
for (GLuint level = 0; level < _numLevels; level++) {
for (GLuint level = _minMip; level < _maxMip; level++) {
GLint levelSize{ 0 };
glGetTexLevelParameteriv(proxyType, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &levelSize);
levelSize *= numFaces;
@ -172,24 +289,32 @@ void GLBackend::GLTexture::updateSize() {
gpuSize += levelSize;
}
(void)CHECK_GL_ERROR();
setSize(gpuSize);
} else {
setSize(virtualSize);
}
} else {
setSize(virtualSize);
}
return;
}
}
}
bool GLBackend::GLTexture::isInvalid() const {
return _storageStamp < _gpuTexture.getStamp();
}
bool GLBackend::GLTexture::isOutdated() const {
return _contentStamp < _gpuTexture.getDataStamp();
return GLTexture::Idle == _syncState && _contentStamp < _gpuTexture.getDataStamp();
}
bool GLBackend::GLTexture::isOverMaxMemory() const {
// FIXME switch to using the max mip count used from the previous frame
if (usedMipLevels() < _currentMaxMipCount) {
return false;
}
Q_ASSERT(usedMipLevels() == _currentMaxMipCount);
if (getMemoryPressure() < 1.0f) {
return false;
}
return true;
}
bool GLBackend::GLTexture::isReady() const {
@ -203,23 +328,28 @@ bool GLBackend::GLTexture::isReady() const {
auto syncState = _syncState.load();
if (isOutdated()) {
return Pending == syncState;
return Idle != syncState;
}
return Idle == syncState;
if (Idle != syncState) {
return false;
}
return true;
}
// Move content bits from the CPU to the GPU for a given mip / face
void GLBackend::GLTexture::transferMip(uint16_t mipLevel, uint8_t face) const {
auto mip = _gpuTexture.accessStoredMipFace(mipLevel, face);
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuTexture.getTexelFormat(), mip->getFormat());
//GLenum target = getFaceTargets()[face];
GLenum target = _target == GL_TEXTURE_2D ? GL_TEXTURE_2D : CUBE_FACE_LAYOUT[face];
uvec2 size = uvec2(_gpuTexture.getWidth(), _gpuTexture.getHeight());
size >>= mipLevel;
auto size = _gpuTexture.evalMipDimensions(mipLevel);
glTexSubImage2D(target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
(void)CHECK_GL_ERROR();
}
// This should never happen on the main thread
// Move content bits from the CPU to the GPU
void GLBackend::GLTexture::transfer() const {
PROFILE_RANGE(__FUNCTION__);
@ -229,15 +359,39 @@ void GLBackend::GLTexture::transfer() const {
return;
}
//_secretTexture
glBindTexture(_target, _privateTexture);
// glBindTexture(_target, _texture);
// GO through the process of allocating the correct storage and/or update the content
switch (_gpuTexture.getType()) {
case Texture::TEX_2D:
for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) {
if (_gpuTexture.isStoredMipFaceAvailable(i)) {
transferMip(i);
(void)CHECK_GL_ERROR();
if (_downsampleSource) {
GLuint fbo { 0 };
glGenFramebuffers(1, &fbo);
(void)CHECK_GL_ERROR();
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
(void)CHECK_GL_ERROR();
// Find the distance between the old min mip and the new one
uint16 mipOffset = _minMip - _downsampleSource->_minMip;
for (uint16 i = _minMip; i <= _maxMip; ++i) {
uint16 targetMip = i - _minMip;
uint16 sourceMip = targetMip + mipOffset;
Vec3u dimensions = _gpuTexture.evalMipDimensions(i);
for (GLenum target : getFaceTargets()) {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, _downsampleSource->_texture, sourceMip);
(void)CHECK_GL_ERROR();
glCopyTexSubImage2D(target, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y);
(void)CHECK_GL_ERROR();
}
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
} else {
// GO through the process of allocating the correct storage and/or update the content
switch (_gpuTexture.getType()) {
case Texture::TEX_2D:
{
for (uint16_t i = _minMip; i <= _maxMip; ++i) {
if (_gpuTexture.isStoredMipFaceAvailable(i)) {
transferMip(i);
}
}
}
break;
@ -256,8 +410,8 @@ void GLBackend::GLTexture::transfer() const {
default:
qCWarning(gpulogging) << __FUNCTION__ << " case for Texture Type " << _gpuTexture.getType() << " not supported";
break;
}
}
if (_gpuTexture.isAutogenerateMips()) {
glGenerateMipmap(_target);
(void)CHECK_GL_ERROR();
@ -271,6 +425,8 @@ void GLBackend::GLTexture::postTransfer() {
// The public gltexture becaomes available
_texture = _privateTexture;
_downsampleSource.reset();
// At this point the mip pixels have been loaded, we can notify the gpu texture to abandon it's memory
switch (_gpuTexture.getType()) {
case Texture::TEX_2D:
@ -307,39 +463,38 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const TexturePointer& texturePoin
// If the object hasn't been created, or the object definition is out of date, drop and re-create
GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(texture);
if (object && object->isReady()) {
return object;
}
// Object isn't ready, check what we need to do...
// Create the texture if need be (force re-creation if the storage stamp changes
// for easier use of immutable storage)
if (!object || object->isInvalid()) {
// This automatically destroys the old texture
object = new GLTexture(texture);
// This automatically any previous texture
object = new GLTexture(needTransfer, texture);
}
// Object maybe doens't neet to be tranasferred after creation
if (!needTransfer) {
object->createTexture();
object->_contentStamp = texturePointer->getDataStamp();
if (!object->_transferrable) {
return object;
}
// If we just did a transfer, return the object after doing post-transfer work
if (GLTexture::Transferred == object->getSyncState()) {
object->postTransfer();
return object;
}
// Object might be outdated, if so, start the transfer
// (outdated objects that are already in transfer will have reported 'true' for ready()
if (object->isOutdated()) {
Backend::incrementTextureGPUTransferCount();
if (object->isReady()) {
// Do we need to reduce texture memory usage?
if (object->isOverMaxMemory() && texturePointer->incremementMinMip()) {
// This automatically destroys the old texture
object = new GLTexture(*object, texture);
_textureTransferHelper->transferTexture(texturePointer);
}
} else if (object->isOutdated()) {
// Object might be outdated, if so, start the transfer
// (outdated objects that are already in transfer will have reported 'true' for ready()
_textureTransferHelper->transferTexture(texturePointer);
}
if (GLTexture::Transferred == object->getSyncState()) {
Backend::decrementTextureGPUTransferCount();
object->postTransfer();
}
return object;
}
@ -359,8 +514,14 @@ GLuint GLBackend::getTextureID(const TexturePointer& texture, bool sync) {
} else {
object = Backend::getGPUObject<GLBackend::GLTexture>(*texture);
}
if (object && object->getSyncState() == GLTexture::Idle) {
return object->_texture;
if (object) {
if (object->getSyncState() == GLTexture::Idle) {
return object->_texture;
} else if (object->_downsampleSource) {
return object->_downsampleSource->_texture;
} else {
return 0;
}
} else {
return 0;
}
@ -425,7 +586,7 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, const GL
glTexParameteri(object->_target, GL_TEXTURE_WRAP_R, wrapModes[sampler.getWrapModeW()]);
glTexParameterfv(object->_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, sampler.getMipOffset());
glTexParameteri(object->_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset());
glTexParameterf(object->_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(object->_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());

View file

@ -11,11 +11,8 @@
#include "GLBackendShared.h"
#ifdef THREADED_TEXTURE_TRANSFER
#include <gl/OffscreenGLCanvas.h>
#include <gl/QOpenGLContextWrapper.h>
#endif
using namespace gpu;
@ -46,12 +43,20 @@ GLTextureTransferHelper::~GLTextureTransferHelper() {
void GLTextureTransferHelper::transferTexture(const gpu::TexturePointer& texturePointer) {
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
Backend::incrementTextureGPUTransferCount();
#ifdef THREADED_TEXTURE_TRANSFER
TextureTransferPackage package{ texturePointer, 0};
GLsync fence { 0 };
//fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
//glFlush();
TextureTransferPackage package { texturePointer, fence };
object->setSyncState(GLBackend::GLTexture::Pending);
queueItem(package);
#else
object->transfer();
object->withPreservedTexture([&] {
do_transfer(*object);
});
object->_contentStamp = texturePointer->getDataStamp();
object->setSyncState(GLBackend::GLTexture::Transferred);
#endif
}
@ -70,6 +75,12 @@ void GLTextureTransferHelper::shutdown() {
#endif
}
void GLTextureTransferHelper::do_transfer(GLBackend::GLTexture& texture) {
texture.createTexture();
texture.transfer();
texture.updateSize();
Backend::decrementTextureGPUTransferCount();
}
bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
for (auto package : messages) {
@ -79,14 +90,16 @@ bool GLTextureTransferHelper::processQueueItems(const Queue& messages) {
continue;
}
if (package.fence) {
glClientWaitSync(package.fence, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(package.fence);
package.fence = 0;
}
GLBackend::GLTexture* object = Backend::getGPUObject<GLBackend::GLTexture>(*texturePointer);
object->createTexture();
object->transfer();
object->updateSize();
do_transfer(*object);
glBindTexture(object->_target, 0);
auto writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glClientWaitSync(writeSync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(writeSync);

View file

@ -6,11 +6,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtGlobal>
#include <QSharedPointer>
#include <GenericQueueThread.h>
#include "GLBackendShared.h"
#ifdef Q_OS_WIN
#define THREADED_TEXTURE_TRANSFER
#endif
class OffscreenGLCanvas;
@ -32,33 +35,10 @@ protected:
void setup() override;
void shutdown() override;
bool processQueueItems(const Queue& messages) override;
void transferTextureSynchronous(const gpu::Texture& texture);
void do_transfer(GLBackend::GLTexture& texturePointer);
private:
QSharedPointer<OffscreenGLCanvas> _canvas;
};
template <typename F>
void withPreservedTexture(GLenum target, F f) {
GLint boundTex = -1;
switch (target) {
case GL_TEXTURE_2D:
glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex);
break;
case GL_TEXTURE_CUBE_MAP:
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &boundTex);
break;
default:
qFatal("Unsupported texture type");
}
(void)CHECK_GL_ERROR();
f();
glBindTexture(target, boundTex);
(void)CHECK_GL_ERROR();
}
}

View file

@ -31,17 +31,10 @@ void GLBackend::do_setProjectionTransform(Batch& batch, size_t paramOffset) {
void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) {
memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i));
ivec4& vp = _transform._viewport;
// Where we assign the GL viewport
if (_stereo._enable) {
vp.z /= 2;
if (_stereo._pass) {
vp.x += vp.z;
}
}
glViewport(vp.x, vp.y, vp.z, vp.w);
if (!_inRenderTransferPass && !isStereo()) {
ivec4& vp = _transform._viewport;
glViewport(vp.x, vp.y, vp.z, vp.w);
}
// The Viewport is tagged invalid because the CameraTransformUBO is not up to date and will need update on next drawcall
_transform._invalidViewport = true;
@ -65,7 +58,7 @@ void GLBackend::initTransform() {
#ifndef GPU_SSBO_DRAW_CALL_INFO
glGenTextures(1, &_transform._objectBufferTexture);
#endif
size_t cameraSize = sizeof(TransformCamera);
size_t cameraSize = sizeof(TransformStageState::CameraBufferElement);
while (_transform._cameraUboSize < cameraSize) {
_transform._cameraUboSize += _uboAlignment;
}
@ -111,15 +104,14 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
if (_invalidView || _invalidProj || _invalidViewport) {
size_t offset = _cameraUboSize * _cameras.size();
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
if (stereo._enable) {
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
for (int i = 0; i < 2; ++i) {
_cameras.push_back(_camera.getEyeCamera(i, stereo, _view));
}
_cameras.push_back((_camera.getEyeCamera(0, stereo, _view)));
_cameras.push_back((_camera.getEyeCamera(1, stereo, _view)));
} else {
_cameraOffsets.push_back(TransformStageState::Pair(commandIndex, offset));
_cameras.push_back(_camera.recomputeDerived(_view));
_cameras.push_back((_camera.recomputeDerived(_view)));
}
}
// Flags are clean
@ -132,7 +124,7 @@ void GLBackend::TransformStageState::transfer(const Batch& batch) const {
if (!_cameras.empty()) {
bufferData.resize(_cameraUboSize * _cameras.size());
for (size_t i = 0; i < _cameras.size(); ++i) {
memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(TransformCamera));
memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(CameraBufferElement));
}
glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer);
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
@ -179,27 +171,33 @@ void GLBackend::TransformStageState::transfer(const Batch& batch) const {
#endif
CHECK_GL_ERROR();
// Make sure the current Camera offset is unknown before render Draw
_currentCameraOffset = INVALID_OFFSET;
}
void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const {
static const size_t INVALID_OFFSET = (size_t)-1;
size_t offset = INVALID_OFFSET;
while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) {
offset = (*_camerasItr).second;
_currentCameraOffset = offset;
++_camerasItr;
}
if (offset != INVALID_OFFSET) {
// We include both camera offsets for stereo
if (stereo._enable && stereo._pass) {
offset += _cameraUboSize;
}
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT,
_cameraBuffer, offset, sizeof(Backend::TransformCamera));
}
if (offset != INVALID_OFFSET) {
if (!stereo._enable) {
bindCurrentCamera(0);
}
}
(void)CHECK_GL_ERROR();
}
void GLBackend::TransformStageState::bindCurrentCamera(int eye) const {
if (_currentCameraOffset != INVALID_OFFSET) {
glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _cameraBuffer, _currentCameraOffset + eye * _cameraUboSize, sizeof(CameraBufferElement));
}
}
void GLBackend::updateTransform(const Batch& batch) {
_transform.update(_commandIndex, _stereo);

View file

@ -12,6 +12,9 @@
#include "Texture.h"
#include <glm/gtc/constants.hpp>
#include <NumericalConstants.h>
#include "GPULogging.h"
#include "Context.h"
@ -21,6 +24,7 @@ static int TexturePointerMetaTypeId = qRegisterMetaType<TexturePointer>();
std::atomic<uint32_t> Texture::_textureCPUCount{ 0 };
std::atomic<Texture::Size> Texture::_textureCPUMemoryUsage{ 0 };
std::atomic<Texture::Size> Texture::_allowedCPUMemoryUsage { 0 };
void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
if (prevObjectSize == newObjectSize) {
@ -57,6 +61,15 @@ uint32_t Texture::getTextureGPUTransferCount() {
return Context::getTextureGPUTransferCount();
}
Texture::Size Texture::getAllowedGPUMemoryUsage() {
return _allowedCPUMemoryUsage;
}
void Texture::setAllowedGPUMemoryUsage(Size size) {
qDebug() << "New MAX texture memory " << BYTES_TO_MB(size) << " MB";
_allowedCPUMemoryUsage = size;
}
uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 };
Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
@ -333,10 +346,6 @@ uint16 Texture::evalNumMips() const {
return 1 + (uint16) val;
}
uint16 Texture::maxMip() const {
return _maxMip;
}
bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) {
// Check that level accessed make sense
if (level != 0) {
@ -870,3 +879,18 @@ bool TextureSource::isDefined() const {
}
}
bool Texture::setMinMip(uint16 newMinMip) {
uint16 oldMinMip = _minMip;
_minMip = std::min(std::max(_minMip, newMinMip), _maxMip);
return oldMinMip != _minMip;
}
bool Texture::incremementMinMip(uint16 count) {
return setMinMip(_minMip + count);
}
Vec3u Texture::evalMipDimensions(uint16 level) const {
auto dimensions = getDimensions();
dimensions >>= level;
return glm::max(dimensions, Vec3u(1));
}

View file

@ -11,14 +11,15 @@
#ifndef hifi_gpu_Texture_h
#define hifi_gpu_Texture_h
#include "Resource.h"
#include <algorithm> //min max and more
#include <bitset>
#include <QMetaType>
#include <QUrl>
#include "Forward.h"
#include "Resource.h"
namespace gpu {
// THe spherical harmonics is a nice tool for cubemap, so if required, the irradiance SH can be automatically generated
@ -141,6 +142,7 @@ protected:
class Texture : public Resource {
static std::atomic<uint32_t> _textureCPUCount;
static std::atomic<Size> _textureCPUMemoryUsage;
static std::atomic<Size> _allowedCPUMemoryUsage;
static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
public:
static uint32_t getTextureCPUCount();
@ -149,6 +151,8 @@ public:
static Size getTextureGPUMemoryUsage();
static Size getTextureGPUVirtualMemoryUsage();
static uint32_t getTextureGPUTransferCount();
static Size getAllowedGPUMemoryUsage();
static void setAllowedGPUMemoryUsage(Size size);
class Usage {
public:
@ -313,6 +317,7 @@ public:
const Element& getTexelFormat() const { return _texelFormat; }
bool hasBorder() const { return false; }
Vec3u getDimensions() const { return Vec3u(_width, _height, _depth); }
uint16 getWidth() const { return _width; }
uint16 getHeight() const { return _height; }
uint16 getDepth() const { return _depth; }
@ -346,6 +351,8 @@ public:
// Eval the size that the mips level SHOULD have
// not the one stored in the Texture
static const uint MIN_DIMENSION = 1;
Vec3u evalMipDimensions(uint16 level) const;
uint16 evalMipWidth(uint16 level) const { return std::max(_width >> level, 1); }
uint16 evalMipHeight(uint16 level) const { return std::max(_height >> level, 1); }
uint16 evalMipDepth(uint16 level) const { return std::max(_depth >> level, 1); }
@ -363,7 +370,7 @@ public:
uint32 evalTotalSize() const {
uint32 size = 0;
uint16 minMipLevel = 0;
uint16 minMipLevel = minMip();
uint16 maxMipLevel = maxMip();
for (uint16 l = minMipLevel; l <= maxMipLevel; l++) {
size += evalMipSize(l);
@ -371,10 +378,19 @@ public:
return size * getNumSlices();
}
// max mip is in the range [ 1 if no sub mips, log2(max(width, height, depth))]
// max mip is in the range [ 0 if no sub mips, log2(max(width, height, depth))]
// if autoGenerateMip is on => will provide the maxMIp level specified
// else provide the deepest mip level provided through assignMip
uint16 maxMip() const;
uint16 maxMip() const { return _maxMip; }
uint16 minMip() const { return _minMip; }
uint16 mipLevels() const { return _maxMip + 1; }
uint16 usedMipLevels() const { return (_maxMip - _minMip) + 1; }
bool setMinMip(uint16 newMinMip);
bool incremementMinMip(uint16 count = 1);
// Generate the mips automatically
// But the sysmem version is not available
@ -451,7 +467,8 @@ protected:
uint16 _numSamples = 1;
uint16 _numSlices = 1;
uint16 _maxMip = 0;
uint16 _maxMip { 0 };
uint16 _minMip { 0 };
Type _type = TEX_1D;

View file

@ -23,6 +23,7 @@ struct TransformCamera {
layout(std140) uniform transformCameraBuffer {
TransformCamera _camera;
};
TransformCamera getTransformCamera() {
return _camera;
}
@ -68,8 +69,8 @@ TransformObject getTransformObject() {
<@func declareStandardTransform()@>
<$declareStandardObjectTransform()$>
<$declareStandardCameraTransform()$>
<$declareStandardObjectTransform()$>
<@endfunc@>
<@func transformCameraViewport(cameraTransform, viewport)@>

Some files were not shown because too many files have changed in this diff Show more