From ce60a410cf7fbecee248124ec8ed3e06ba39a23f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 15:34:26 -0800 Subject: [PATCH 01/22] Reenable entity list tools --- examples/editEntities.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/editEntities.js b/examples/editEntities.js index 172089ed62..24b658dfcd 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -232,6 +232,7 @@ var toolBar = (function () { cameraManager.disable(); } else { hasShownPropertiesTool = false; + entityListTool.setVisible(true); cameraManager.enable(); gridTool.setVisible(true); grid.setEnabled(true); From 9e8458edd92162f7074e3dc77af22714a90791b2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 15:35:19 -0800 Subject: [PATCH 02/22] Add support for teleport, delete, and filtering in entity list --- examples/html/entityList.html | 140 +++++++++++++++++++++++++------ examples/html/style.css | 26 +++++- examples/libraries/entityList.js | 49 +++++++---- 3 files changed, 171 insertions(+), 44 deletions(-) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 7caa45f19d..26a302cb41 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -2,13 +2,30 @@ +
- + + +
- - - - - - - - - -
TypeURL
+
+ + + + + + + + + + +
Type  ▾URL
+
diff --git a/examples/html/style.css b/examples/html/style.css index 7ffbacb15e..12e87baee5 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -114,6 +114,7 @@ table#entity-table { #entity-table tr { cursor: pointer; + border-bottom: 1px solid #e5e5e5; } #entity-table tr.selected { @@ -133,14 +134,18 @@ table#entity-table { border: 0px black solid; word-wrap: nowrap; white-space: nowrap; + text-overflow: ellipsis; +} + +#entity-table td.url { + white-space: nowrap; + overflow: hidden; } th#entity-type { width: 60px; } -th#entity-url { -} div.input-area { @@ -186,3 +191,20 @@ table#properties-table { col#col-label { width: 130px; } + +div.outer { + position: relative; +} +div.inner { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + position: absolute; + width: 100%; +} + +td { + + + vertical-align: top; +} diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index eb01295d97..10a2209309 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -24,10 +24,38 @@ EntityListTool = function(opts) { type: 'selectionUpdate', selectedIDs: selectedIDs, }; + print("Sending: " + JSON.stringify(data)); webView.eventBridge.emitScriptEvent(JSON.stringify(data)); }); + function sendUpdate() { + var entities = []; + var ids = Entities.findEntities(MyAvatar.position, 100); + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + entities.push({ + id: id.id, + type: properties.type, + url: properties.type == "Model" ? properties.modelURL : "", + }); + } + + var selectedIDs = []; + for (var i = 0; i < selectionManager.selections.length; i++) { + selectedIDs.push(selectionManager.selections[i].id); + } + + var data = { + type: "update", + entities: entities, + selectedIDs: selectedIDs, + }; + webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + } + webView.eventBridge.webEventReceived.connect(function(data) { + print("Got: " + data); data = JSON.parse(data); if (data.type == "selectionUpdate") { var ids = data.entityIds; @@ -46,22 +74,13 @@ EntityListTool = function(opts) { Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); } } else if (data.type == "refresh") { - var entities = []; - var ids = Entities.findEntities(MyAvatar.position, 100); - for (var i = 0; i < ids.length; i++) { - var id = ids[i]; - var properties = Entities.getEntityProperties(id); - entities.push({ - id: id.id, - type: properties.type, - url: properties.type == "Model" ? properties.modelURL : "", - }); + sendUpdate(); + } else if (data.type == "teleport") { + if (selectionManager.hasSelection()) { + MyAvatar.position = selectionManager.worldPosition; } - var data = { - type: "update", - entities: entities, - }; - webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + } else if (data.type == "delete") { + deleteSelectedEntities(); } }); From 7ddec78cd52a1ec98a3757efd33a936250ce55d3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 15:36:25 -0800 Subject: [PATCH 03/22] Add list.min.js for entity list tool --- examples/html/list.min.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/html/list.min.js diff --git a/examples/html/list.min.js b/examples/html/list.min.js new file mode 100644 index 0000000000..56c17e398d --- /dev/null +++ b/examples/html/list.min.js @@ -0,0 +1 @@ +!function(){function a(b,c,d){var e=a.resolve(b);if(null==e){d=d||b,c=c||"root";var f=new Error('Failed to require "'+d+'" from "'+c+'"');throw f.path=d,f.parent=c,f.require=!0,f}var g=a.modules[e];if(!g._resolving&&!g.exports){var h={};h.exports={},h.client=h.component=!0,g._resolving=!0,g.call(this,h.exports,a.relative(e),h),delete g._resolving,g.exports=h.exports}return g.exports}a.modules={},a.aliases={},a.resolve=function(b){"/"===b.charAt(0)&&(b=b.slice(1));for(var c=[b,b+".js",b+".json",b+"/index.js",b+"/index.json"],d=0;di;i++)if(h.test(f[i].className)){if(c)return f[i];d[j]=f[i],j++}return d}}()}),a.register("javve-get-attribute/index.js",function(a,b,c){c.exports=function(a,b){var c=a.getAttribute&&a.getAttribute(b)||null;if(!c)for(var d=a.attributes,e=d.length,f=0;e>f;f++)void 0!==b[f]&&b[f].nodeName===b&&(c=b[f].nodeValue);return c}}),a.register("javve-natural-sort/index.js",function(a,b,c){c.exports=function(a,b,c){var d,e,f=/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,g=/(^[ ]*|[ ]*$)/g,h=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,i=/^0x[0-9a-f]+$/i,j=/^0/,c=c||{},k=function(a){return c.insensitive&&(""+a).toLowerCase()||""+a},l=k(a).replace(g,"")||"",m=k(b).replace(g,"")||"",n=l.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),o=m.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),p=parseInt(l.match(i))||1!=n.length&&l.match(h)&&Date.parse(l),q=parseInt(m.match(i))||p&&m.match(h)&&Date.parse(m)||null,r=c.desc?-1:1;if(q){if(q>p)return-1*r;if(p>q)return 1*r}for(var s=0,t=Math.max(n.length,o.length);t>s;s++){if(d=!(n[s]||"").match(j)&&parseFloat(n[s])||n[s]||0,e=!(o[s]||"").match(j)&&parseFloat(o[s])||o[s]||0,isNaN(d)!==isNaN(e))return isNaN(d)?1:-1;if(typeof d!=typeof e&&(d+="",e+=""),e>d)return-1*r;if(d>e)return 1*r}return 0}}),a.register("javve-to-string/index.js",function(a,b,c){c.exports=function(a){return a=void 0===a?"":a,a=null===a?"":a,a=a.toString()}}),a.register("component-type/index.js",function(a,b,c){var d=Object.prototype.toString;c.exports=function(a){switch(d.call(a)){case"[object Date]":return"date";case"[object RegExp]":return"regexp";case"[object Arguments]":return"arguments";case"[object Array]":return"array";case"[object Error]":return"error"}return null===a?"null":void 0===a?"undefined":a!==a?"nan":a&&1===a.nodeType?"element":typeof a.valueOf()}}),a.register("list.js/index.js",function(a,b,c){!function(a,d){"use strict";var e=a.document,f=b("get-by-class"),g=b("extend"),h=b("indexof"),i=function(a,c,i){var j,k=this,l=b("./src/item")(k),m=b("./src/add-async")(k),n=b("./src/parse")(k);j={start:function(){k.listClass="list",k.searchClass="search",k.sortClass="sort",k.page=200,k.i=1,k.items=[],k.visibleItems=[],k.matchingItems=[],k.searched=!1,k.filtered=!1,k.handlers={updated:[]},k.plugins={},k.helpers={getByClass:f,extend:g,indexOf:h},g(k,c),k.listContainer="string"==typeof a?e.getElementById(a):a,k.listContainer&&(k.list=f(k.listContainer,k.listClass,!0),k.templater=b("./src/templater")(k),k.search=b("./src/search")(k),k.filter=b("./src/filter")(k),k.sort=b("./src/sort")(k),this.items(),k.update(),this.plugins())},items:function(){n(k.list),i!==d&&k.add(i)},plugins:function(){for(var a=0;af;f++){var h=null;a[f]instanceof l?(h=a[f],h.reload()):(e=k.items.length>k.page?!0:!1,h=new l(a[f],d,e)),k.items.push(h),c.push(h)}return k.update(),c},this.show=function(a,b){return this.i=a,this.page=b,k.update(),k},this.remove=function(a,b,c){for(var d=0,e=0,f=k.items.length;f>e;e++)k.items[e].values()[a]==b&&(k.templater.remove(k.items[e],c),k.items.splice(e,1),f--,e--,d++);return k.update(),d},this.get=function(a,b){for(var c=[],d=0,e=k.items.length;e>d;d++){var f=k.items[d];f.values()[a]==b&&c.push(f)}return c},this.size=function(){return k.items.length},this.clear=function(){return k.templater.clear(),k.items=[],k},this.on=function(a,b){return k.handlers[a].push(b),k},this.off=function(a,b){var c=k.handlers[a],d=h(c,b);return d>-1&&c.splice(d,1),k},this.trigger=function(a){for(var b=k.handlers[a].length;b--;)k.handlers[a][b](k);return k},this.reset={filter:function(){for(var a=k.items,b=a.length;b--;)a[b].filtered=!1;return k},search:function(){for(var a=k.items,b=a.length;b--;)a[b].found=!1;return k}},this.update=function(){var a=k.items,b=a.length;k.visibleItems=[],k.matchingItems=[],k.templater.clear();for(var c=0;b>c;c++)a[c].matching()&&k.matchingItems.length+1>=k.i&&k.visibleItems.lengthb;b++)j.item(a.items[b])},item:function(a){a.found=!1;for(var b=0,d=c.length;d>b;b++)if(j.values(a.values(),c[b]))return a.found=!0,void 0},values:function(a,c){return a.hasOwnProperty(c)&&(b=f(a[c]).toLowerCase(),""!==g&&b.search(g)>-1)?!0:!1},reset:function(){a.reset.search(),a.searched=!1}},k=function(b){return a.trigger("searchStart"),i.resetList(),i.setSearchString(b),i.setOptions(arguments),i.setColumns(),""===g?j.reset():(a.searched=!0,h?h(g,c):j.list()),a.update(),a.trigger("searchComplete"),a.visibleItems};return a.handlers.searchStart=a.handlers.searchStart||[],a.handlers.searchComplete=a.handlers.searchComplete||[],d.bind(e(a.listContainer,a.searchClass),"keyup",function(b){var c=b.target||b.srcElement,d=""===c.value&&!a.searched;d||k(c.value)}),d.bind(e(a.listContainer,a.searchClass),"input",function(a){var b=a.target||a.srcElement;""===b.value&&k("")}),a.helpers.toString=f,k}}),a.register("list.js/src/sort.js",function(a,b,c){var d=b("natural-sort"),e=b("classes"),f=b("events"),g=b("get-by-class"),h=b("get-attribute");c.exports=function(a){a.sortFunction=a.sortFunction||function(a,b,c){return c.desc="desc"==c.order?!0:!1,d(a.values()[c.valueName],b.values()[c.valueName],c)};var b={els:void 0,clear:function(){for(var a=0,c=b.els.length;c>a;a++)e(b.els[a]).remove("asc"),e(b.els[a]).remove("desc")},getOrder:function(a){var b=h(a,"data-order");return"asc"==b||"desc"==b?b:e(a).has("desc")?"asc":e(a).has("asc")?"desc":"asc"},getInSensitive:function(a,b){var c=h(a,"data-insensitive");b.insensitive="true"===c?!0:!1},setOrder:function(a){for(var c=0,d=b.els.length;d>c;c++){var f=b.els[c];if(h(f,"data-sort")===a.valueName){var g=h(f,"data-order");"asc"==g||"desc"==g?g==a.order&&e(f).add(a.order):e(f).add(a.order)}}}},c=function(){a.trigger("sortStart"),options={};var c=arguments[0].currentTarget||arguments[0].srcElement||void 0;c?(options.valueName=h(c,"data-sort"),b.getInSensitive(c,options),options.order=b.getOrder(c)):(options=arguments[1]||options,options.valueName=arguments[0],options.order=options.order||"asc",options.insensitive="undefined"==typeof options.insensitive?!0:options.insensitive),b.clear(),b.setOrder(options),options.sortFunction=options.sortFunction||a.sortFunction,a.items.sort(function(a,b){return options.sortFunction(a,b,options)}),a.update(),a.trigger("sortComplete")};return a.handlers.sortStart=a.handlers.sortStart||[],a.handlers.sortComplete=a.handlers.sortComplete||[],b.els=g(a.listContainer,a.sortClass),f.bind(b.els,"click",c),a.on("searchStart",b.clear),a.on("filterStart",b.clear),a.helpers.classes=e,a.helpers.naturalSort=d,a.helpers.events=f,a.helpers.getAttribute=h,c}}),a.register("list.js/src/item.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=this;this._values={},this.found=!1,this.filtered=!1;var f=function(b,c,d){if(void 0===c)d?e.values(b,d):e.values(b);else{e.elm=c;var f=a.templater.get(e,b);e.values(f)}};this.values=function(b,c){if(void 0===b)return e._values;for(var d in b)e._values[d]=b[d];c!==!0&&a.templater.set(e,e.values())},this.show=function(){a.templater.show(e)},this.hide=function(){a.templater.hide(e)},this.matching=function(){return a.filtered&&a.searched&&e.found&&e.filtered||a.filtered&&!a.searched&&e.filtered||!a.filtered&&a.searched&&e.found||!a.filtered&&!a.searched},this.visible=function(){return e.elm.parentNode==a.list?!0:!1},f(b,c,d)}}}),a.register("list.js/src/templater.js",function(a,b,c){var d=b("get-by-class"),e=function(a){function b(b){if(void 0===b){for(var c=a.list.childNodes,d=0,e=c.length;e>d;d++)if(void 0===c[d].data)return c[d];return null}if(-1!==b.indexOf("<")){var f=document.createElement("div");return f.innerHTML=b,f.firstChild}return document.getElementById(a.item)}var c=b(a.item),e=this;this.get=function(a,b){e.create(a);for(var c={},f=0,g=b.length;g>f;f++){var h=d(a.elm,b[f],!0);c[b[f]]=h?h.innerHTML:""}return c},this.set=function(a,b){if(!e.create(a))for(var c in b)if(b.hasOwnProperty(c)){var f=d(a.elm,c,!0);f&&("IMG"===f.tagName&&""!==b[c]?f.src=b[c]:f.innerHTML=b[c])}},this.create=function(a){if(void 0!==a.elm)return!1;var b=c.cloneNode(!0);return b.removeAttribute("id"),a.elm=b,e.set(a,a.values()),!0},this.remove=function(b){a.list.removeChild(b.elm)},this.show=function(b){e.create(b),a.list.appendChild(b.elm)},this.hide=function(b){void 0!==b.elm&&b.elm.parentNode===a.list&&a.list.removeChild(b.elm)},this.clear=function(){if(a.list.hasChildNodes())for(;a.list.childNodes.length>=1;)a.list.removeChild(a.list.firstChild)}};c.exports=function(a){return new e(a)}}),a.register("list.js/src/filter.js",function(a,b,c){c.exports=function(a){return a.handlers.filterStart=a.handlers.filterStart||[],a.handlers.filterComplete=a.handlers.filterComplete||[],function(b){if(a.trigger("filterStart"),a.i=1,a.reset.filter(),void 0===b)a.filtered=!1;else{a.filtered=!0;for(var c=a.items,d=0,e=c.length;e>d;d++){var f=c[d];f.filtered=b(f)?!0:!1}}return a.update(),a.trigger("filterComplete"),a.visibleItems}}}),a.register("list.js/src/add-async.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=b.splice(0,100);d=d||[],d=d.concat(a.add(e)),b.length>0?setTimeout(function(){addAsync(b,c,d)},10):(a.update(),c(d))}}}),a.register("list.js/src/parse.js",function(a,b,c){c.exports=function(a){var c=b("./item")(a),d=function(a){for(var b=a.childNodes,c=[],d=0,e=b.length;e>d;d++)void 0===b[d].data&&c.push(b[d]);return c},e=function(b,d){for(var e=0,f=b.length;f>e;e++)a.items.push(new c(d,b[e]))},f=function(b,c){var d=b.splice(0,100);e(d,c),b.length>0?setTimeout(function(){init.items.indexAsync(b,c)},10):a.update()};return function(){var b=d(a.list),c=a.valueNames;a.indexAsync?f(b,c):e(b,c)}}}),a.alias("component-classes/index.js","list.js/deps/classes/index.js"),a.alias("component-classes/index.js","classes/index.js"),a.alias("component-indexof/index.js","component-classes/deps/indexof/index.js"),a.alias("segmentio-extend/index.js","list.js/deps/extend/index.js"),a.alias("segmentio-extend/index.js","extend/index.js"),a.alias("component-indexof/index.js","list.js/deps/indexof/index.js"),a.alias("component-indexof/index.js","indexof/index.js"),a.alias("javve-events/index.js","list.js/deps/events/index.js"),a.alias("javve-events/index.js","events/index.js"),a.alias("component-event/index.js","javve-events/deps/event/index.js"),a.alias("timoxley-to-array/index.js","javve-events/deps/to-array/index.js"),a.alias("javve-get-by-class/index.js","list.js/deps/get-by-class/index.js"),a.alias("javve-get-by-class/index.js","get-by-class/index.js"),a.alias("javve-get-attribute/index.js","list.js/deps/get-attribute/index.js"),a.alias("javve-get-attribute/index.js","get-attribute/index.js"),a.alias("javve-natural-sort/index.js","list.js/deps/natural-sort/index.js"),a.alias("javve-natural-sort/index.js","natural-sort/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","to-string/index.js"),a.alias("javve-to-string/index.js","javve-to-string/index.js"),a.alias("component-type/index.js","list.js/deps/type/index.js"),a.alias("component-type/index.js","type/index.js"),"object"==typeof exports?module.exports=a("list.js"):"function"==typeof define&&define.amd?define(function(){return a("list.js")}):this.List=a("list.js")}(); \ No newline at end of file From c51cac6381e836371c8559f977dd56387b1c115e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jan 2015 15:38:28 -0800 Subject: [PATCH 04/22] Remove Model List dialog --- examples/editEntities.js | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 24b658dfcd..38d3d3af75 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -672,8 +672,7 @@ function setupModelMenus() { print("delete exists... don't add ours"); } - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Model List..." }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true, isChecked: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", @@ -700,7 +699,6 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } - Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); @@ -764,38 +762,6 @@ function handeMenuEvent(menuItem) { } else { print(" Delete Entity.... not holding..."); } - } else if (menuItem == "Model List...") { - var models = new Array(); - models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); - for (var i = 0; i < models.length; i++) { - models[i].properties = Entities.getEntityProperties(models[i]); - models[i].toString = function() { - var modelname; - if (this.properties.type == "Model") { - modelname = decodeURIComponent( - this.properties.modelURL.indexOf("/") != -1 ? - this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : - this.properties.modelURL); - } else { - modelname = this.properties.id; - } - return "[" + this.properties.type + "] " + modelname; - }; - } - var form = [{label: "Model: ", options: models}]; - form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); - form.push({ button: "Cancel" }); - if (Window.form("Model List", form)) { - var selectedModel = form[0].value; - if (form[1].value == "Properties") { - editModelID = selectedModel; - entityPropertyDialogBox.openDialog(editModelID); - } else if (form[1].value == "Delete") { - Entities.deleteEntity(selectedModel); - } else if (form[1].value == "Teleport") { - MyAvatar.position = selectedModel.properties.position; - } - } } else if (menuItem == "Paste Models") { modelImporter.paste(); } else if (menuItem == "Export Models") { From 705e6181a11202189376f3b93fa34f724259c4a6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 15 Jan 2015 11:12:42 -0800 Subject: [PATCH 05/22] Move entity delete action to function --- examples/editEntities.js | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 38d3d3af75..369ab73d17 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -735,6 +735,28 @@ Script.update.connect(function (deltaTime) { selectionDisplay.checkMove(); }); +function deleteSelectedEntities() { + if (SelectionManager.hasSelection()) { + print(" Delete Entities"); + SelectionManager.saveProperties(); + var savedProperties = []; + for (var i = 0; i < selectionManager.selections.length; i++) { + var entityID = SelectionManager.selections[i]; + var initialProperties = SelectionManager.savedProperties[entityID.id]; + SelectionManager.savedProperties[entityID.id]; + savedProperties.push({ + entityID: entityID, + properties: initialProperties + }); + Entities.deleteEntity(entityID); + } + SelectionManager.clearSelections(); + pushCommandForSelections([], savedProperties); + } else { + print(" Delete Entity.... not holding..."); + } +} + function handeMenuEvent(menuItem) { if (menuItem == "Allow Selecting of Small Models") { allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); @@ -743,25 +765,7 @@ function handeMenuEvent(menuItem) { } else if (menuItem == "Allow Selecting of Lights") { Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); } else if (menuItem == "Delete") { - if (SelectionManager.hasSelection()) { - print(" Delete Entities"); - SelectionManager.saveProperties(); - var savedProperties = []; - for (var i = 0; i < selectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; - var initialProperties = SelectionManager.savedProperties[entityID.id]; - SelectionManager.savedProperties[entityID.id]; - savedProperties.push({ - entityID: entityID, - properties: initialProperties - }); - Entities.deleteEntity(entityID); - } - SelectionManager.clearSelections(); - pushCommandForSelections([], savedProperties); - } else { - print(" Delete Entity.... not holding..."); - } + deleteSelectedEntities(); } else if (menuItem == "Paste Models") { modelImporter.paste(); } else if (menuItem == "Export Models") { @@ -790,7 +794,7 @@ Controller.keyPressEvent.connect(function(event) { Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items if (event.text == "BACKSPACE" || event.text == "DELETE") { - handeMenuEvent("Delete"); + deleteSelectedEntities(); } else if (event.text == "TAB") { selectionDisplay.toggleSpaceMode(); } else if (event.text == "f") { From d3a6a411fb74d6acdedf1e515f838564a77b1068 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Jan 2015 16:23:29 -0800 Subject: [PATCH 06/22] Update entity list to use list.js more directly --- examples/html/entityList.html | 61 ++++++++++++++++------------------- examples/html/style.css | 16 ++++----- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 26a302cb41..6c9846f5e4 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -1,4 +1,3 @@ - @@ -14,6 +13,8 @@ var DESC_STRING = ' ▴'; function loaded() { + entityList = new List('entity-list', { valueNames: ['type', 'url']}); + entityList.clear(); elEntityTable = document.getElementById("entity-table"); elEntityTableBody = document.getElementById("entity-table-body"); elRefresh = document.getElementById("refresh"); @@ -37,7 +38,8 @@ selectedEntities = selection; - entities[id].el.className = 'selected'; + this.className = 'selected'; + EventBridge.emitWebEvent(JSON.stringify({ type: "selectionUpdate", focus: false, @@ -46,8 +48,6 @@ } function onRowDoubleClicked() { - var id = this.dataset.entityId; - EventBridge.emitWebEvent(JSON.stringify({ type: "selectionUpdate", focus: true, @@ -60,21 +60,21 @@ var urlParts = url.split('/'); var filename = urlParts[urlParts.length - 1]; - var el = document.createElement('tr'); - el.setAttribute('id', 'entity_' + id); - el.innerHTML += "" + type + ""; - el.innerHTML += "
" + filename + "
"; - el.dataset.entityId = id; - el.onclick = onRowClicked; - el.ondblclick = onRowDoubleClicked; - elEntityTableBody.appendChild(el); - - // Add element to local dict - entities[id] = { - id: id, - name: id, - el: el, - }; + entityList.add([{ id: id, type: type, url: filename }], function(items) { + var el = items[0].elm; + var id = items[0]._values.id; + entities[id] = { + id: id, + name: id, + el: el, + }; + el.setAttribute('id', 'entity_' + id); + el.setAttribute('title', url); + el.dataset.entityId = id; + el.onclick = onRowClicked; + el.ondblclick = onRowDoubleClicked; + el.innerHTML + }); if (refreshEntityListTimer) { clearTimeout(refreshEntityListTimer); @@ -91,10 +91,8 @@ } function clearEntities() { - for (id in entities) { - elEntityTableBody.removeChild(entities[id].el); - } entities = {}; + entityList.clear(); } var elSortOrder = { @@ -122,7 +120,6 @@ function refreshEntityListObject() { refreshEntityListTimer = null; - entityList = new List('entity-list', { valueNames: ['type', 'url']}); entityList.sort(currentSortColumn, { order: currentSortOrder }); entityList.search(document.getElementById("filter").value); } @@ -174,15 +171,6 @@ } }); } - - // var _id = 0; - // setInterval(function() { - // for(var i = 0; i < 2; i++) { - // addEntity(_id, ['Model', 'Light'][i], 'http' + _id); - // _id++; - // } - // }, 5000); - setTimeout(refreshEntities, 1); } @@ -198,11 +186,16 @@ - - + + + + + + +
Type  ▾URL Type  ▾URL
Type
URL
diff --git a/examples/html/style.css b/examples/html/style.css index 42cf37d34a..ad78d0234c 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -5,9 +5,10 @@ body { margin: 0; padding: 0; - background-color: #efefef; + background-color: rgb(76, 76, 76); + color: rgb(204, 204, 204); font-family: Arial; - font-size: 11.5px; + font-size: 11px; -webkit-touch-callout: none; -webkit-user-select: none; @@ -17,12 +18,6 @@ body { user-select: none; } -body.properties { - background-color: rgb(76, 76, 76); - color: rgb(204, 204, 204); - font-size: 11px; -} - .selectable { -webkit-touch-callout: text; -webkit-user-select: text; @@ -117,13 +112,13 @@ input.coord { table#entity-table { border-collapse: collapse; font-family: Sans-Serif; - /* font-size: 12px; */ + font-size: 10px; width: 100%; } #entity-table tr { cursor: pointer; - border-bottom: 1px solid #e5e5e5; + border-bottom: 1px solid rgb(63, 63, 63) } #entity-table tr.selected { @@ -140,6 +135,7 @@ table#entity-table { } #entity-table td { + font-size: 11px; border: 0px black solid; word-wrap: nowrap; white-space: nowrap; From ba752040ddfad0437b33c989504e43cb330cc603 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Jan 2015 16:24:19 -0800 Subject: [PATCH 07/22] Update WebWindow to redefine EventBridge after refresh --- interface/src/scripting/WebWindowClass.cpp | 16 ++++++++++++---- interface/src/scripting/WebWindowClass.h | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index cc6f4fbfff..be87870f26 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -41,19 +41,27 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid _dockWidget = new QDockWidget(title, toolWindow); _dockWidget->setFeatures(QDockWidget::DockWidgetMovable); - QWebView* webView = new QWebView(_dockWidget); - webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); - webView->setUrl(url); - _dockWidget->setWidget(webView); + + _webView = new QWebView(_dockWidget); + _webView->setUrl(url); + addEventBridgeToWindowObject(); + + _dockWidget->setWidget(_webView); toolWindow->addDockWidget(Qt::RightDockWidgetArea, _dockWidget); + connect(_webView->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, + this, &WebWindowClass::addEventBridgeToWindowObject); connect(this, &WebWindowClass::destroyed, _dockWidget, &QWidget::deleteLater); } WebWindowClass::~WebWindowClass() { } +void WebWindowClass::addEventBridgeToWindowObject() { + _webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); +} + void WebWindowClass::setVisible(bool visible) { if (visible) { QMetaObject::invokeMethod( diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index ae0d14ae06..0fa88804f2 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -14,6 +14,7 @@ #include #include +#include class ScriptEventBridge : public QObject { Q_OBJECT @@ -42,9 +43,11 @@ public: public slots: void setVisible(bool visible); ScriptEventBridge* getEventBridge() const { return _eventBridge; } + void addEventBridgeToWindowObject(); private: QDockWidget* _dockWidget; + QWebView* _webView; ScriptEventBridge* _eventBridge; }; From e4f29412d58a4228693844d8974647f43c9d7118 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 19 Jan 2015 18:11:14 -0800 Subject: [PATCH 08/22] cheaper failure adding entity to physics engine --- libraries/physics/src/PhysicsEngine.cpp | 103 ++++++++++++------------ libraries/physics/src/PhysicsEngine.h | 2 +- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 90fd6c65cd..a216e062b3 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -60,14 +60,17 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - EntityMotionState* motionState = new EntityMotionState(entity); - if (addObject(motionState)) { + ShapeInfo shapeInfo; + entity->computeShapeInfo(shapeInfo); + btCollisionShape* shape = _shapeManager.getShape(shapeInfo); + if (shape) { + EntityMotionState* motionState = new EntityMotionState(entity); entity->setPhysicsInfo(static_cast(motionState)); _entityMotionStates.insert(motionState); + addObject(shapeInfo, shape, motionState); } else { // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; - delete motionState; } } } @@ -244,59 +247,53 @@ void PhysicsEngine::stepSimulation() { // CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing // CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing -bool PhysicsEngine::addObject(ObjectMotionState* motionState) { +void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState) { + assert(shape); assert(motionState); - ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - btVector3 inertia(0.0f, 0.0f, 0.0f); - float mass = 0.0f; - btRigidBody* body = NULL; - switch(motionState->computeMotionType()) { - case MOTION_TYPE_KINEMATIC: { - body = new btRigidBody(mass, motionState, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); - body->updateInertiaTensor(); - motionState->_body = body; - motionState->addKinematicController(); - const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec - const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec - body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); - break; - } - case MOTION_TYPE_DYNAMIC: { - mass = motionState->computeMass(shapeInfo); - shape->calculateLocalInertia(mass, inertia); - body = new btRigidBody(mass, motionState, shape, inertia); - body->updateInertiaTensor(); - motionState->_body = body; - motionState->updateObjectVelocities(); - // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. - // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime - const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec - const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec - body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); - break; - } - case MOTION_TYPE_STATIC: - default: { - body = new btRigidBody(mass, motionState, shape, inertia); - body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); - body->updateInertiaTensor(); - motionState->_body = body; - break; - } + + btVector3 inertia(0.0f, 0.0f, 0.0f); + float mass = 0.0f; + btRigidBody* body = NULL; + switch(motionState->computeMotionType()) { + case MOTION_TYPE_KINEMATIC: { + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + body->updateInertiaTensor(); + motionState->_body = body; + motionState->addKinematicController(); + const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec + const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec + body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); + break; + } + case MOTION_TYPE_DYNAMIC: { + mass = motionState->computeMass(shapeInfo); + shape->calculateLocalInertia(mass, inertia); + body = new btRigidBody(mass, motionState, shape, inertia); + body->updateInertiaTensor(); + motionState->_body = body; + motionState->updateObjectVelocities(); + // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. + // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime + const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec + const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec + body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); + break; + } + case MOTION_TYPE_STATIC: + default: { + body = new btRigidBody(mass, motionState, shape, inertia); + body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); + body->updateInertiaTensor(); + motionState->_body = body; + break; } - // wtf? - body->setFlags(BT_DISABLE_WORLD_GRAVITY); - body->setRestitution(motionState->_restitution); - body->setFriction(motionState->_friction); - body->setDamping(motionState->_linearDamping, motionState->_angularDamping); - _dynamicsWorld->addRigidBody(body); - return true; } - return false; + body->setFlags(BT_DISABLE_WORLD_GRAVITY); + body->setRestitution(motionState->_restitution); + body->setFriction(motionState->_friction); + body->setDamping(motionState->_linearDamping, motionState->_angularDamping); + _dynamicsWorld->addRigidBody(body); } bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index f37f12ea8d..4dc4b67156 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -59,7 +59,7 @@ public: /// \param motionState pointer to Object's MotionState /// \return true if Object added - bool addObject(ObjectMotionState* motionState); + void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState); /// \param motionState pointer to Object's MotionState /// \return true if Object removed From 8202c84c794a7231c4cf44d3475db8ae2780821c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:37:39 -0800 Subject: [PATCH 09/22] Add entity list menu option --- examples/editEntities.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 4e06125ea1..ad064d269b 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -44,10 +44,16 @@ var entityListTool = EntityListTool(); var hasShownPropertiesTool = false; +var entityListVisible = false; + selectionManager.addEventListener(function() { selectionDisplay.updateHandles(); if (selectionManager.hasSelection() && !hasShownPropertiesTool) { + // Open properties and model list, but force selection of model list tab + propertiesTool.setVisible(false); + entityListTool.setVisible(false); propertiesTool.setVisible(true); + entityListTool.setVisible(true); hasShownPropertiesTool = true; } }); @@ -232,7 +238,6 @@ var toolBar = (function () { cameraManager.disable(); } else { hasShownPropertiesTool = false; - entityListTool.setVisible(true); cameraManager.enable(); gridTool.setVisible(true); grid.setEnabled(true); @@ -703,6 +708,8 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); + Menu.addMenuItem({ menuName: "Tools", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", afterItem: "Tool Window" }); + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); @@ -727,6 +734,8 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Export Models"); Menu.removeMenuItem("File", "Import Models"); + Menu.removeMenuItem("Tools", "Entity List..."); + Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); } @@ -797,6 +806,10 @@ function handeMenuEvent(menuItem) { } } else if (menuItem == "Import Models") { modelImporter.doImport(); + } else if (menuItem == "Entity List...") { + if (isActive) { + entityListTool.toggleVisible(); + } } tooltip.show(false); } From 891f6fa5138e46dea5c9772c2b5d2135e11c5a26 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:40:16 -0800 Subject: [PATCH 10/22] Move entity list to edit menu --- examples/editEntities.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index ad064d269b..3c11b2d7eb 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -696,7 +696,8 @@ function setupModelMenus() { print("delete exists... don't add ours"); } - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Models" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", afterItem: "Models" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Entity List..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true, isChecked: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", @@ -708,7 +709,6 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); - Menu.addMenuItem({ menuName: "Tools", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", afterItem: "Tool Window" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); From 903921e11f590ad460b6e658429a75a23c4c022d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:40:31 -0800 Subject: [PATCH 11/22] Update entity list to auto-refresh list on start --- examples/html/entityList.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 6c9846f5e4..e1318a225c 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -170,6 +170,7 @@ updateSelectedEntities(data.selectedIDs); } }); + setTimeout(refreshEntities, 1000); } } From bc21faeefb4120dc1a0895c032b937539509228d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:41:58 -0800 Subject: [PATCH 12/22] Add entityListTool.toggleVisible --- examples/libraries/entityList.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index 10a2209309..8fbc40698f 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -13,6 +13,10 @@ EntityListTool = function(opts) { webView.setVisible(visible); }; + that.toggleVisible = function() { + that.setVisible(!visible); + } + selectionManager.addEventListener(function() { var selectedIDs = []; From 3a287a08aba52f4359ca6937059b2b62ee380302 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:43:49 -0800 Subject: [PATCH 13/22] Fix removal of entity list menu item --- examples/editEntities.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 3c11b2d7eb..9187b624fd 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -725,6 +725,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } + Menu.removeMenuItem("Edit", "Entity List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); @@ -734,8 +735,6 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Export Models"); Menu.removeMenuItem("File", "Import Models"); - Menu.removeMenuItem("Tools", "Entity List..."); - Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); } From 1a6557c72d0431fafd2771da2cfd3c35d8b988fd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:46:26 -0800 Subject: [PATCH 14/22] Remove removeEntity from entityList.html --- examples/html/entityList.html | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index e1318a225c..6e7795a3f0 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -83,13 +83,6 @@ } } - function removeEntity(id) { - if (entities[id] !== undefined) { - elEntityTableBody.removeChild(entities[id].el); - delete entities[id]; - } - } - function clearEntities() { entities = {}; entityList.clear(); From 1f86edbfbf04621baf7234223a6cc1f1fe6cda59 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Jan 2015 12:47:19 -0800 Subject: [PATCH 15/22] Remove console.log from entityList.html --- examples/html/entityList.html | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 6e7795a3f0..01061f1eb0 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -101,7 +101,6 @@ currentSortColumn = column; currentSortOrder = "asc"; } - console.log(currentSortColumn, currentSortOrder); elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASC_STRING : DESC_STRING; entityList.sort(currentSortColumn, { order: currentSortOrder }); } From b4cd13f0be1917413b69d7fa8d20b76331a3c48d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jan 2015 13:07:35 -0800 Subject: [PATCH 16/22] Fix for misaligned color/material textures when resolution is greater than the height map. --- .../shaders/metavoxel_heightfield_base.vert | 2 +- .../shaders/metavoxel_heightfield_splat.vert | 2 +- interface/src/MetavoxelSystem.cpp | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_base.vert b/interface/resources/shaders/metavoxel_heightfield_base.vert index 03a99bd57c..38ec891e5a 100644 --- a/interface/resources/shaders/metavoxel_heightfield_base.vert +++ b/interface/resources/shaders/metavoxel_heightfield_base.vert @@ -43,5 +43,5 @@ void main(void) { gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); // pass along the scaled/offset texture coordinates - gl_TexCoord[0] = vec4((heightCoord - heightScale.st) * colorScale, 0.0, 1.0); + gl_TexCoord[0] = vec4((heightCoord - vec2(0.5, 0.5)) * colorScale + vec2(0.5, 0.5), 0.0, 1.0); } diff --git a/interface/resources/shaders/metavoxel_heightfield_splat.vert b/interface/resources/shaders/metavoxel_heightfield_splat.vert index d54da347cc..48681ecdd4 100644 --- a/interface/resources/shaders/metavoxel_heightfield_splat.vert +++ b/interface/resources/shaders/metavoxel_heightfield_splat.vert @@ -58,7 +58,7 @@ void main(void) { gl_TexCoord[3] = textureSpacePosition * vec4(splatTextureScalesS[3], splatTextureScalesT[3], 0.0, 1.0); // compute the alpha values for each texture - float value = texture2D(textureMap, (gl_MultiTexCoord0.st - heightScale) * textureScale).r; + float value = texture2D(textureMap, (gl_MultiTexCoord0.st - vec2(0.5, 0.5)) * textureScale + vec2(0.5, 0.5)).r; vec4 valueVector = vec4(value, value, value, value); alphaValues = step(textureValueMinima, valueVector) * step(valueVector, textureValueMaxima); } diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a566b18b7e..86bdcd8ab9 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -2407,7 +2407,14 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g baseBatch.heightTextureID = _heightTextureID; baseBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, (innerWidth - 1) / -2.0f, (innerHeight - 1) / -2.0f); baseBatch.colorTextureID = _colorTextureID; - baseBatch.colorScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); + float widthMultiplier = 1.0f / (0.5f - 1.5f / width); + float heightMultiplier = 1.0f / (0.5f - 1.5f / height); + if (node->getColor()) { + int colorWidth = node->getColor()->getWidth(); + int colorHeight = node->getColor()->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES); + baseBatch.colorScale = glm::vec2((0.5f - 0.5f / colorWidth) * widthMultiplier, + (0.5f - 0.5f / colorHeight) * heightMultiplier); + } Application::getInstance()->getMetavoxels()->addHeightfieldBaseBatch(baseBatch); if (!(cursor || _networkTextures.isEmpty())) { @@ -2422,7 +2429,12 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g splatBatch.heightTextureID = _heightTextureID; splatBatch.heightScale = glm::vec4(1.0f / width, 1.0f / height, 0.0f, 0.0f); splatBatch.materialTextureID = _materialTextureID; - splatBatch.textureScale = glm::vec2((float)width / innerWidth, (float)height / innerHeight); + if (node->getMaterial()) { + int materialWidth = node->getMaterial()->getWidth(); + int materialHeight = node->getMaterial()->getContents().size() / materialWidth; + splatBatch.textureScale = glm::vec2((0.5f - 0.5f / materialWidth) * widthMultiplier, + (0.5f - 0.5f / materialHeight) * heightMultiplier); + } splatBatch.splatTextureOffset = glm::vec2( glm::dot(translation, rotation * glm::vec3(1.0f, 0.0f, 0.0f)) / scale.x, glm::dot(translation, rotation * glm::vec3(0.0f, 0.0f, 1.0f)) / scale.z); From b2079ab84943f7db0afd1690b6678848194c7539 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jan 2015 14:42:48 -0800 Subject: [PATCH 17/22] Go ahead and generate mipmaps for the terrain color texture. --- interface/src/MetavoxelSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 86bdcd8ab9..7df61c156c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1617,7 +1617,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g glGenTextures(1, &_colorTextureID); glBindTexture(GL_TEXTURE_2D, _colorTextureID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (node->getColor()) { @@ -1625,6 +1625,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, node->getColor()->getWidth(), contents.size() / (node->getColor()->getWidth() * DataBlock::COLOR_BYTES), 0, GL_RGB, GL_UNSIGNED_BYTE, contents.constData()); + glGenerateMipmap(GL_TEXTURE_2D); } else { const quint8 WHITE_COLOR[] = { 255, 255, 255 }; From 460a307ebea1a897597145c1fa188b5083d92591 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jan 2015 18:12:00 -0800 Subject: [PATCH 18/22] Better stitching. --- interface/src/MetavoxelSystem.cpp | 456 +++++++++++++----------------- 1 file changed, 193 insertions(+), 263 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7df61c156c..b9cce33828 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1425,8 +1425,18 @@ public: char material; void setColorMaterial(const StackArray::Entry& entry) { color = entry.color; material = entry.material; } + + void mix(const EdgeCrossing& first, const EdgeCrossing& second, float t); }; +void EdgeCrossing::mix(const EdgeCrossing& first, const EdgeCrossing& second, float t) { + point = glm::mix(first.point, second.point, t); + normal = glm::normalize(glm::mix(first.normal, second.normal, t)); + color = qRgb(glm::mix(qRed(first.color), qRed(second.color), t), glm::mix(qGreen(first.color), qGreen(second.color), t), + glm::mix(qBlue(first.color), qBlue(second.color), t)); + material = (t < 0.5f) ? first.material : second.material; +} + const int MAX_NORMALS_PER_VERTEX = 4; class NormalIndex { @@ -1706,7 +1716,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } const int EDGES_PER_CUBE = 12; - EdgeCrossing crossings[EDGES_PER_CUBE]; + EdgeCrossing crossings[EDGES_PER_CUBE * 2]; // as we scan down the cube generating vertices between grid points, we remember the indices of the last // (element, line, section--x, y, z) so that we can connect generated vertices as quads @@ -1737,13 +1747,6 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g lineSrc[stackWidth].getExtents(minimumY, maximumY); } if (maximumY >= minimumY) { - int position = minimumY; - int count = maximumY - minimumY + 1; - NormalIndex lastIndexY = { { -1, -1, -1, -1 } }; - indicesX.position = position; - indicesX.resize(count); - indicesZ[x].position = position; - indicesZ[x].resize(count); float heightfieldHeight = *heightLineSrc * voxelScale; float nextHeightfieldHeightX = heightLineSrc[1] * voxelScale; float nextHeightfieldHeightZ = heightLineSrc[width] * voxelScale; @@ -1754,6 +1757,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g const int LOWER_RIGHT_CORNER = 8; const int NO_CORNERS = 0; const int ALL_CORNERS = UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER | LOWER_RIGHT_CORNER; + const int CORNER_COUNT = 4; + const int NEXT_CORNERS[] = { 1, 3, 0, 2 }; int corners = NO_CORNERS; if (heightfieldHeight != 0.0f) { corners |= UPPER_LEFT_CORNER; @@ -1768,37 +1773,38 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g corners |= LOWER_RIGHT_CORNER; } bool stitchable = x != 0 && z != 0 && !(corners == NO_CORNERS || corners == ALL_CORNERS); - VoxelPoint cornerPoints[4]; + EdgeCrossing cornerCrossings[CORNER_COUNT]; int clampedX = qMax(x - 1, 0), clampedZ = qMax(z - 1, 0); + int cornerMinimumY = INT_MAX, cornerMaximumY = -1; if (stitchable) { - for (unsigned int i = 0; i < sizeof(cornerPoints) / sizeof(cornerPoints[0]); i++) { + for (int i = 0; i < CORNER_COUNT; i++) { if (!(corners & (1 << i))) { continue; } int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; const quint16* height = heightLineSrc + offsetZ * width + offsetX; - VoxelPoint& point = cornerPoints[i]; - int clampedOffsetX = clampedX + offsetX, clampedOffsetZ = clampedZ + offsetZ; - point.vertex = glm::vec3(clampedOffsetX, *height * voxelScale, clampedOffsetZ) * step; + float heightValue = *height * voxelScale; + int y = (int)heightValue; + cornerMinimumY = qMin(cornerMinimumY, y); + cornerMaximumY = qMax(cornerMaximumY, y); + EdgeCrossing& crossing = cornerCrossings[i]; + crossing.point = glm::vec3(offsetX, heightValue - y, offsetZ); int left = height[-1]; int right = height[1]; int down = height[-width]; int up = height[width]; - glm::vec3 normal = glm::normalize(glm::vec3((left == 0 || right == 0) ? 0.0f : left - right, + crossing.normal = glm::normalize(glm::vec3((left == 0 || right == 0) ? 0.0f : left - right, 2.0f / voxelScale, (up == 0 || down == 0) ? 0.0f : down - up)); - point.normal[0] = normal.x * numeric_limits::max(); - point.normal[1] = normal.y * numeric_limits::max(); - point.normal[2] = normal.z * numeric_limits::max(); + int clampedOffsetX = clampedX + offsetX, clampedOffsetZ = clampedZ + offsetZ; if (colorSrc) { const uchar* color = colorSrc + ((int)(clampedOffsetZ * colorStepZ) * colorWidth + (int)(clampedOffsetX * colorStepX)) * DataBlock::COLOR_BYTES; - point.color[0] = color[0]; - point.color[1] = color[1]; - point.color[2] = color[2]; - + crossing.color = qRgb(color[0], color[1], color[2]); + } else { - point.color[0] = point.color[1] = point.color[2] = numeric_limits::max(); + crossing.color = qRgb(numeric_limits::max(), numeric_limits::max(), + numeric_limits::max()); } int material = 0; if (materialSrc) { @@ -1813,12 +1819,18 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g material = mapping; } } - point.materials[0] = material; - point.materials[1] = point.materials[2] = point.materials[3] = 0; - point.materialWeights[0] = numeric_limits::max(); - point.materialWeights[1] = point.materialWeights[2] = point.materialWeights[3] = 0; + crossing.material = material; } + minimumY = qMin(minimumY, cornerMinimumY); + maximumY = qMax(maximumY, cornerMaximumY); } + int position = minimumY; + int count = maximumY - minimumY + 1; + NormalIndex lastIndexY = { { -1, -1, -1, -1 } }; + indicesX.position = position; + indicesX.resize(count); + indicesZ[x].position = position; + indicesZ[x].resize(count); for (int y = position, end = position + count; y < end; y++) { const StackArray::Entry& entry = lineSrc->getEntry(y, heightfieldHeight); if (displayHermite && x != 0 && z != 0 && !lineSrc->isEmpty() && y >= lineSrc->getPosition()) { @@ -1876,91 +1888,176 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (alphaTotal == 0 || alphaTotal == possibleTotal) { continue; // no corners set/all corners set } + // we first look for crossings with the heightfield corner vertices; these take priority + int crossingCount = 0; + if (y >= cornerMinimumY && y <= cornerMaximumY) { + // first look for set corners, which override any interpolated values + int crossedCorners = NO_CORNERS; + for (int i = 0; i < CORNER_COUNT; i++) { + if (!(corners & (1 << i))) { + continue; + } + int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; + const quint16* height = heightLineSrc + offsetZ * width + offsetX; + float heightValue = *height * voxelScale; + if (heightValue >= y && heightValue < y + 1) { + crossedCorners |= (1 << i); + } + } + switch (crossedCorners) { + case UPPER_LEFT_CORNER: + case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: + case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + case UPPER_LEFT_CORNER | LOWER_RIGHT_CORNER: + crossings[crossingCount++] = cornerCrossings[0]; + break; + + case UPPER_RIGHT_CORNER: + case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: + case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: + crossings[crossingCount++] = cornerCrossings[1]; + break; + + case LOWER_LEFT_CORNER: + case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: + crossings[crossingCount++] = cornerCrossings[2]; + break; + + case LOWER_RIGHT_CORNER: + case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: + case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + crossings[crossingCount++] = cornerCrossings[3]; + break; + + case NO_CORNERS: + for (int i = 0; i < CORNER_COUNT; i++) { + if (!(corners & (1 << i))) { + continue; + } + int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; + const quint16* height = heightLineSrc + offsetZ * width + offsetX; + float heightValue = *height * voxelScale; + if (heightValue >= y && heightValue < y + 1) { + crossings[crossingCount++] = cornerCrossings[i]; + } + int nextIndex = NEXT_CORNERS[i]; + if (!(corners & (1 << nextIndex))) { + continue; + } + int nextOffsetX = (nextIndex & X_MAXIMUM_FLAG) ? 1 : 0; + int nextOffsetZ = (nextIndex & Y_MAXIMUM_FLAG) ? 1 : 0; + const quint16* nextHeight = heightLineSrc + nextOffsetZ * width + nextOffsetX; + float nextHeightValue = *nextHeight * voxelScale; + float divisor = (nextHeightValue - heightValue); + if (divisor == 0.0f) { + continue; + } + float t1 = (y - heightValue) / divisor; + float t2 = (y + 1 - heightValue) / divisor; + if (t1 >= 0.0f && t1 <= 1.0f) { + crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t1); + } + if (t2 >= 0.0f && t2 <= 1.0f) { + crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t2); + } + } + break; + } + } + // the terrifying conditional code that follows checks each cube edge for a crossing, gathering // its properties (color, material, normal) if one is present; as before, boundary edges are excluded - int crossingCount = 0; - const StackArray::Entry& nextEntryY = lineSrc->getEntry(y + 1, heightfieldHeight); - if (middleX) { - const StackArray::Entry& nextEntryX = lineSrc[1].getEntry(y, nextHeightfieldHeightX); - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, nextHeightfieldHeightX); - if (alpha0 != alpha1) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(entry.getHermiteX(crossing.normal), 0.0f, 0.0f); - crossing.setColorMaterial(alpha0 == 0 ? nextEntryX : entry); + if (crossingCount == 0) { + const StackArray::Entry& nextEntryY = lineSrc->getEntry(y + 1, heightfieldHeight); + if (middleX) { + const StackArray::Entry& nextEntryX = lineSrc[1].getEntry(y, nextHeightfieldHeightX); + const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, nextHeightfieldHeightX); + if (alpha0 != alpha1) { + EdgeCrossing& crossing = crossings[crossingCount++]; + crossing.point = glm::vec3(entry.getHermiteX(crossing.normal), 0.0f, 0.0f); + crossing.setColorMaterial(alpha0 == 0 ? nextEntryX : entry); + } + if (alpha1 != alpha3) { + EdgeCrossing& crossing = crossings[crossingCount++]; + crossing.point = glm::vec3(1.0f, nextEntryX.getHermiteY(crossing.normal), 0.0f); + crossing.setColorMaterial(alpha1 == 0 ? nextEntryXY : nextEntryX); + } + if (alpha2 != alpha3) { + EdgeCrossing& crossing = crossings[crossingCount++]; + crossing.point = glm::vec3(nextEntryY.getHermiteX(crossing.normal), 1.0f, 0.0f); + crossing.setColorMaterial(alpha2 == 0 ? nextEntryXY : nextEntryY); + } + if (middleZ) { + const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, + nextHeightfieldHeightZ); + const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( + y, nextHeightfieldHeightXZ); + const StackArray::Entry& nextEntryXYZ = lineSrc[stackWidth + 1].getEntry( + y + 1, nextHeightfieldHeightXZ); + if (alpha1 != alpha5) { + EdgeCrossing& crossing = crossings[crossingCount++]; + crossing.point = glm::vec3(1.0f, 0.0f, nextEntryX.getHermiteZ(crossing.normal)); + crossing.setColorMaterial(alpha1 == 0 ? nextEntryXZ : nextEntryX); + } + if (alpha3 != alpha7) { + EdgeCrossing& crossing = crossings[crossingCount++]; + const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, + nextHeightfieldHeightX); + crossing.point = glm::vec3(1.0f, 1.0f, nextEntryXY.getHermiteZ(crossing.normal)); + crossing.setColorMaterial(alpha3 == 0 ? nextEntryXYZ : nextEntryXY); + } + if (alpha4 != alpha5) { + EdgeCrossing& crossing = crossings[crossingCount++]; + crossing.point = glm::vec3(nextEntryZ.getHermiteX(crossing.normal), 0.0f, 1.0f); + crossing.setColorMaterial(alpha4 == 0 ? nextEntryXZ : nextEntryZ); + } + if (alpha5 != alpha7) { + EdgeCrossing& crossing = crossings[crossingCount++]; + const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( + y, nextHeightfieldHeightXZ); + crossing.point = glm::vec3(1.0f, nextEntryXZ.getHermiteY(crossing.normal), 1.0f); + crossing.setColorMaterial(alpha5 == 0 ? nextEntryXYZ : nextEntryXZ); + } + if (alpha6 != alpha7) { + EdgeCrossing& crossing = crossings[crossingCount++]; + const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry( + y + 1, nextHeightfieldHeightZ); + crossing.point = glm::vec3(nextEntryYZ.getHermiteX(crossing.normal), 1.0f, 1.0f); + crossing.setColorMaterial(alpha6 == 0 ? nextEntryXYZ : nextEntryYZ); + } + } } - if (alpha1 != alpha3) { + if (alpha0 != alpha2) { EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(1.0f, nextEntryX.getHermiteY(crossing.normal), 0.0f); - crossing.setColorMaterial(alpha1 == 0 ? nextEntryXY : nextEntryX); - } - if (alpha2 != alpha3) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(nextEntryY.getHermiteX(crossing.normal), 1.0f, 0.0f); - crossing.setColorMaterial(alpha2 == 0 ? nextEntryXY : nextEntryY); + crossing.point = glm::vec3(0.0f, entry.getHermiteY(crossing.normal), 0.0f); + crossing.setColorMaterial(alpha0 == 0 ? nextEntryY : entry); } if (middleZ) { const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); - const StackArray::Entry& nextEntryXYZ = lineSrc[stackWidth + 1].getEntry( - y + 1, nextHeightfieldHeightXZ); - if (alpha1 != alpha5) { + const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry(y + 1, + nextHeightfieldHeightZ); + if (alpha0 != alpha4) { EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(1.0f, 0.0f, nextEntryX.getHermiteZ(crossing.normal)); - crossing.setColorMaterial(alpha1 == 0 ? nextEntryXZ : nextEntryX); + crossing.point = glm::vec3(0.0f, 0.0f, entry.getHermiteZ(crossing.normal)); + crossing.setColorMaterial(alpha0 == 0 ? nextEntryZ : entry); } - if (alpha3 != alpha7) { + if (alpha2 != alpha6) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, nextHeightfieldHeightX); - crossing.point = glm::vec3(1.0f, 1.0f, nextEntryXY.getHermiteZ(crossing.normal)); - crossing.setColorMaterial(alpha3 == 0 ? nextEntryXYZ : nextEntryXY); + crossing.point = glm::vec3(0.0f, 1.0f, nextEntryY.getHermiteZ(crossing.normal)); + crossing.setColorMaterial(alpha2 == 0 ? nextEntryYZ : nextEntryY); } - if (alpha4 != alpha5) { + if (alpha4 != alpha6) { EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(nextEntryZ.getHermiteX(crossing.normal), 0.0f, 1.0f); - crossing.setColorMaterial(alpha4 == 0 ? nextEntryXZ : nextEntryZ); - } - if (alpha5 != alpha7) { - EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); - crossing.point = glm::vec3(1.0f, nextEntryXZ.getHermiteY(crossing.normal), 1.0f); - crossing.setColorMaterial(alpha5 == 0 ? nextEntryXYZ : nextEntryXZ); - } - if (alpha6 != alpha7) { - EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry( - y + 1, nextHeightfieldHeightZ); - crossing.point = glm::vec3(nextEntryYZ.getHermiteX(crossing.normal), 1.0f, 1.0f); - crossing.setColorMaterial(alpha6 == 0 ? nextEntryXYZ : nextEntryYZ); + crossing.point = glm::vec3(0.0f, nextEntryZ.getHermiteY(crossing.normal), 1.0f); + crossing.setColorMaterial(alpha4 == 0 ? nextEntryYZ : nextEntryZ); } } } - if (alpha0 != alpha2) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(0.0f, entry.getHermiteY(crossing.normal), 0.0f); - crossing.setColorMaterial(alpha0 == 0 ? nextEntryY : entry); - } - if (middleZ) { - const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry(y + 1, nextHeightfieldHeightZ); - if (alpha0 != alpha4) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(0.0f, 0.0f, entry.getHermiteZ(crossing.normal)); - crossing.setColorMaterial(alpha0 == 0 ? nextEntryZ : entry); - } - if (alpha2 != alpha6) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(0.0f, 1.0f, nextEntryY.getHermiteZ(crossing.normal)); - crossing.setColorMaterial(alpha2 == 0 ? nextEntryYZ : nextEntryY); - } - if (alpha4 != alpha6) { - EdgeCrossing& crossing = crossings[crossingCount++]; - crossing.point = glm::vec3(0.0f, nextEntryZ.getHermiteY(crossing.normal), 1.0f); - crossing.setColorMaterial(alpha4 == 0 ? nextEntryYZ : nextEntryZ); - } - } - // determine whether we should ignore this vertex because it will be stitched + // make sure we have valid crossings to include int validCrossings = 0; for (int i = 0; i < crossingCount; i++) { if (qAlpha(crossings[i].color) != 0) { @@ -2108,173 +2205,6 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g point.setNormal(normals[i]); vertices.append(point); } - - if (stitchable) { - int nextIndex = vertices.size(); - const NormalIndex& previousIndexX = lastIndicesX.getClosest(y); - const NormalIndex& previousIndexZ = lastIndicesZ[x].getClosest(y); - switch (corners) { - case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: { - vertices.append(cornerPoints[0]); - vertices.append(cornerPoints[3]); - glm::vec3 normal = glm::cross(cornerPoints[0].vertex - cornerPoints[1].vertex, - cornerPoints[3].vertex - cornerPoints[1].vertex); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - nextIndex, previousIndexX.getClosestIndex(normal, vertices)); - } - break; - } - case UPPER_LEFT_CORNER | LOWER_LEFT_CORNER | LOWER_RIGHT_CORNER: { - vertices.append(cornerPoints[0]); - vertices.append(cornerPoints[3]); - glm::vec3 normal = glm::cross(cornerPoints[3].vertex - cornerPoints[2].vertex, - cornerPoints[0].vertex - cornerPoints[2].vertex); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex, nextIndex + 1, nextIndex + 1); - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexZ.getClosestIndex(normal, vertices), nextIndex); - } - break; - } - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: { - vertices.append(cornerPoints[1]); - vertices.append(cornerPoints[2]); - vertices.append(cornerPoints[3]); - glm::vec3 normal = glm::cross(cornerPoints[3].vertex - cornerPoints[2].vertex, - cornerPoints[1].vertex - cornerPoints[2].vertex); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 2, nextIndex, nextIndex); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex + 2, nextIndex + 2); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexX.getClosestIndex(normal, vertices), nextIndex + 1); - } - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - nextIndex, previousIndexZ.getClosestIndex(normal, vertices)); - } - break; - } - case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: { - vertices.append(cornerPoints[0]); - vertices.append(cornerPoints[1]); - vertices.append(cornerPoints[2]); - glm::vec3 normal = glm::cross(cornerPoints[2].vertex - cornerPoints[0].vertex, - cornerPoints[1].vertex - cornerPoints[0].vertex); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex, nextIndex + 2, nextIndex + 2); - break; - } - case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: { - vertices.append(cornerPoints[0]); - vertices.append(cornerPoints[1]); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(cornerPoints[1].vertex - first, - cornerPoints[0].vertex - first); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - nextIndex, previousIndexX.getClosestIndex(normal, vertices)); - } - break; - } - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: { - vertices.append(cornerPoints[1]); - vertices.append(cornerPoints[3]); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(cornerPoints[3].vertex - first, - cornerPoints[1].vertex - first); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, - firstIndex, nextIndex, previousIndexZ.getClosestIndex(normal, vertices)); - } - break; - } - case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: { - vertices.append(cornerPoints[3]); - vertices.append(cornerPoints[2]); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(cornerPoints[2].vertex - first, - cornerPoints[3].vertex - first); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexX.getClosestIndex(normal, vertices), nextIndex + 1); - } - break; - } - case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: { - vertices.append(cornerPoints[2]); - vertices.append(cornerPoints[0]); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(cornerPoints[0].vertex - first, - cornerPoints[2].vertex - first); - int firstIndex = index.getClosestIndex(normal, vertices); - appendIndices(indices, quadIndices, vertices, step, firstIndex, - nextIndex + 1, nextIndex, nextIndex); - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexZ.getClosestIndex(normal, vertices), nextIndex + 1); - } - break; - } - case UPPER_LEFT_CORNER: { - vertices.append(cornerPoints[0]); - glm::vec3 normal = glm::cross(cornerPoints[0].vertex - - vertices.at(index.indices[0]).vertex, glm::vec3(1.0f, 0.0f, 0.0f)); - int firstIndex = index.getClosestIndex(normal, vertices); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - nextIndex, previousIndexX.getClosestIndex(normal, vertices)); - } - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexZ.getClosestIndex(normal, vertices), nextIndex); - } - break; - } - case UPPER_RIGHT_CORNER: { - vertices.append(cornerPoints[1]); - glm::vec3 normal = glm::cross(cornerPoints[1].vertex - - vertices.at(index.indices[0]).vertex, glm::vec3(1.0f, 0.0f, 0.0f)); - int firstIndex = index.getClosestIndex(normal, vertices); - if (previousIndexZ.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - nextIndex, previousIndexZ.getClosestIndex(normal, vertices)); - } - break; - } - case LOWER_LEFT_CORNER: { - vertices.append(cornerPoints[2]); - glm::vec3 normal = glm::cross(cornerPoints[2].vertex - - vertices.at(index.indices[0]).vertex, glm::vec3(1.0f, 0.0f, 0.0f)); - int firstIndex = index.getClosestIndex(normal, vertices); - if (previousIndexX.isValid()) { - appendIndices(indices, quadIndices, vertices, step, firstIndex, firstIndex, - previousIndexX.getClosestIndex(normal, vertices), nextIndex); - } - break; - } - } - } } // the first x, y, and z are repeated for the boundary edge; past that, we consider generating From 79e18b161d823ebe9f13247310eef2f0cd8c0f5e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jan 2015 18:42:40 -0800 Subject: [PATCH 19/22] Simplification. --- interface/src/MetavoxelSystem.cpp | 54 ------------------------------- 1 file changed, 54 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b9cce33828..dd67f27d79 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1490,7 +1490,6 @@ public: void swap(IndexVector& other) { QVector::swap(other); qSwap(position, other.position); } const NormalIndex& get(int y) const; - const NormalIndex& getClosest(int y) const; }; const NormalIndex& IndexVector::get(int y) const { @@ -1499,56 +1498,6 @@ const NormalIndex& IndexVector::get(int y) const { return (relative >= 0 && relative < size()) ? at(relative) : invalidIndex; } -const NormalIndex& IndexVector::getClosest(int y) const { - static NormalIndex invalidIndex = { { -1, -1, -1, -1 } }; - int relative = y - position; - if (relative < 0 || relative >= size()) { - return invalidIndex; - } - const NormalIndex& first = at(relative); - if (first.isValid()) { - return first; - } - for (int distance = 1; relative - distance >= 0 || relative + distance < size(); distance++) { - int previous = relative - distance; - if (previous >= 0) { - const NormalIndex& previousIndex = at(previous); - if (previousIndex.isValid()) { - return previousIndex; - } - } - int next = relative + distance; - if (next < size()) { - const NormalIndex& nextIndex = at(next); - if (nextIndex.isValid()) { - return nextIndex; - } - } - } - return invalidIndex; -} - -static inline void appendIndices(QVector& indices, QMultiHash& quadIndices, - const QVector& vertices, float step, int i0, int i1, int i2, int i3) { - int newIndices[] = { i0, i1, i2, i3 }; - glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); - int indexIndex = indices.size(); - for (unsigned int i = 0; i < sizeof(newIndices) / sizeof(newIndices[0]); i++) { - int index = newIndices[i]; - indices.append(index); - const glm::vec3& vertex = vertices.at(index).vertex; - minima = glm::min(vertex, minima); - maxima = glm::max(vertex, maxima); - } - for (int z = (int)minima.z, endZ = (int)glm::ceil(maxima.z); z < endZ; z++) { - for (int y = (int)minima.x, endY = (int)glm::ceil(maxima.y); y < endY; y++) { - for (int x = (int)minima.x, endX = (int)glm::ceil(maxima.x); x < endX; x++) { - quadIndices.insert(qRgb(x, y, z), indexIndex); - } - } - } -} - void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -1941,9 +1890,6 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; const quint16* height = heightLineSrc + offsetZ * width + offsetX; float heightValue = *height * voxelScale; - if (heightValue >= y && heightValue < y + 1) { - crossings[crossingCount++] = cornerCrossings[i]; - } int nextIndex = NEXT_CORNERS[i]; if (!(corners & (1 << nextIndex))) { continue; From 10c4408d94edf009b2766f31162f12f4d04668d0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jan 2015 21:52:56 -0800 Subject: [PATCH 20/22] Slight stitching tweak. --- interface/src/MetavoxelSystem.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index dd67f27d79..eeb1c84a4e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1738,7 +1738,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g cornerMinimumY = qMin(cornerMinimumY, y); cornerMaximumY = qMax(cornerMaximumY, y); EdgeCrossing& crossing = cornerCrossings[i]; - crossing.point = glm::vec3(offsetX, heightValue - y, offsetZ); + crossing.point = glm::vec3(offsetX, heightValue, offsetZ); int left = height[-1]; int right = height[1]; int down = height[-width]; @@ -1860,6 +1860,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | LOWER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[0]; + crossings[crossingCount - 1].point.y -= y; break; case UPPER_RIGHT_CORNER: @@ -1867,18 +1868,21 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[1]; + crossings[crossingCount - 1].point.y -= y; break; case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; + crossings[crossingCount - 1].point.y -= y; break; case LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[3]; + crossings[crossingCount - 1].point.y -= y; break; case NO_CORNERS: @@ -1906,9 +1910,11 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g float t2 = (y + 1 - heightValue) / divisor; if (t1 >= 0.0f && t1 <= 1.0f) { crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t1); + crossings[crossingCount - 1].point.y -= y; } if (t2 >= 0.0f && t2 <= 1.0f) { crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t2); + crossings[crossingCount - 1].point.y -= y; } } break; From d19bfa69f2a9942f9bb6abe1334ff1b2ea0c6b1e Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 21 Jan 2015 10:07:10 -0800 Subject: [PATCH 21/22] Even more gpu::Texture in the model rnedering --- libraries/gpu/src/gpu/GLBackendTexture.cpp | 246 ++++++++++++++------ libraries/gpu/src/gpu/Texture.cpp | 10 +- libraries/gpu/src/gpu/Texture.h | 61 ++--- libraries/render-utils/src/Model.cpp | 32 ++- libraries/render-utils/src/TextureCache.cpp | 15 +- libraries/render-utils/src/TextureCache.h | 4 +- 6 files changed, 231 insertions(+), 137 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index 9582354d57..e23f6fdaec 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -29,84 +29,174 @@ public: GLenum format; GLenum type; - static GLTexelFormat evalGLTexelFormat(const Element& pixel) { - GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; + static GLTexelFormat evalGLTexelFormat(const Element& dstFormat, const Element& srcFormat) { + if (dstFormat != srcFormat) { + GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - switch(pixel.getDimension()) { - case gpu::SCALAR: { - texel.format = GL_RED; - texel.type = _elementTypeToGLType[pixel.getType()]; + switch(dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RED; + break; + case gpu::DEPTH: + texel.internalFormat = GL_DEPTH_COMPONENT; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG; + break; + case gpu::DEPTH_STENCIL: + texel.internalFormat = GL_DEPTH_STENCIL; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + + } + break; + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(srcFormat.getSemantic()) { + case gpu::BGRA: + texel.format = GL_BGRA; + break; + case gpu::RGB: + case gpu::RGBA: + default: + break; + }; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; - switch(pixel.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RED; - break; - case gpu::DEPTH: - texel.internalFormat = GL_DEPTH_COMPONENT; - break; default: qDebug() << "Unknown combination of texel format"; } - } - break; + return texel; + } else { + GLTexelFormat texel = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}; - case gpu::VEC2: { - texel.format = GL_RG; - texel.type = _elementTypeToGLType[pixel.getType()]; + switch(dstFormat.getDimension()) { + case gpu::SCALAR: { + texel.format = GL_RED; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RED; + break; + case gpu::DEPTH: + texel.internalFormat = GL_DEPTH_COMPONENT; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; + + case gpu::VEC2: { + texel.format = GL_RG; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RG; + break; + case gpu::DEPTH_STENCIL: + texel.internalFormat = GL_DEPTH_STENCIL; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + + } + break; + + case gpu::VEC3: { + texel.format = GL_RGB; + + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + case gpu::RGBA: + texel.internalFormat = GL_RGB; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; + + case gpu::VEC4: { + texel.format = GL_RGBA; + texel.type = _elementTypeToGLType[dstFormat.getType()]; + + switch(dstFormat.getSemantic()) { + case gpu::RGB: + texel.internalFormat = GL_RGB; + break; + case gpu::RGBA: + texel.internalFormat = GL_RGBA; + break; + default: + qDebug() << "Unknown combination of texel format"; + } + } + break; - switch(pixel.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RG; - break; - case gpu::DEPTH_STENCIL: - texel.internalFormat = GL_DEPTH_STENCIL; - break; default: qDebug() << "Unknown combination of texel format"; } - + return texel; } - break; - - case gpu::VEC3: { - texel.format = GL_RGB; - - texel.type = _elementTypeToGLType[pixel.getType()]; - - switch(pixel.getSemantic()) { - case gpu::RGB: - case gpu::RGBA: - texel.internalFormat = GL_RGB; - break; - default: - qDebug() << "Unknown combination of texel format"; - } - } - break; - - case gpu::VEC4: { - texel.format = GL_RGBA; - texel.type = _elementTypeToGLType[pixel.getType()]; - - switch(pixel.getSemantic()) { - case gpu::RGB: - texel.internalFormat = GL_RGB; - break; - case gpu::RGBA: - texel.internalFormat = GL_RGBA; - break; - default: - qDebug() << "Unknown combination of texel format"; - } - } - break; - - default: - qDebug() << "Unknown combination of texel format"; - } - return texel; } }; @@ -137,16 +227,21 @@ void GLBackend::syncGPUObject(const Texture& texture) { // GO through the process of allocating the correct storage and/or update the content switch (texture.getType()) { case Texture::TEX_2D: { - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat()); if (needUpdate) { - if (texture.isSysmemMipAvailable(0)) { + if (texture.isStoredMipAvailable(0)) { GLint boundTex = -1; glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); + + Texture::PixelsPointer mip = texture.accessStoredMip(0); + const GLvoid* bytes = mip->_sysmem.read(); + Element srcFormat = mip->_format; + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); glBindTexture(GL_TEXTURE_2D, object->_texture); glTexSubImage2D(GL_TEXTURE_2D, 0, texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, - texelFormat.format, texelFormat.type, texture.readMip(0)); + texelFormat.format, texelFormat.type, bytes); if (texture.isAutogenerateMips()) { glGenerateMipmap(GL_TEXTURE_2D); @@ -156,14 +251,21 @@ void GLBackend::syncGPUObject(const Texture& texture) { } } else { const GLvoid* bytes = 0; - if (texture.isSysmemMipAvailable(0)) { - bytes = texture.readMip(0); + Element srcFormat = texture.getTexelFormat(); + if (texture.isStoredMipAvailable(0)) { + Texture::PixelsPointer mip = texture.accessStoredMip(0); + + bytes = mip->_sysmem.read(); + srcFormat = mip->_format; + object->_contentStamp = texture.getDataStamp(); } GLint boundTex = -1; glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTex); glBindTexture(GL_TEXTURE_2D, object->_texture); + + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat); glTexImage2D(GL_TEXTURE_2D, 0, texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0, diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index e0391cb43b..5a52529403 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -218,7 +218,7 @@ uint16 Texture::autoGenerateMips(uint16 maxMip) { } uint16 Texture::getStoredMipWidth(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip && mip->_sysmem.getSize()) { return evalMipWidth(level); } else { @@ -227,7 +227,7 @@ uint16 Texture::getStoredMipWidth(uint16 level) const { } uint16 Texture::getStoredMipHeight(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip && mip->_sysmem.getSize()) { return evalMipHeight(level); } else { @@ -236,7 +236,7 @@ uint16 Texture::getStoredMipHeight(uint16 level) const { } uint16 Texture::getStoredMipDepth(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip && mip->_sysmem.getSize()) { return evalMipDepth(level); } else { @@ -245,7 +245,7 @@ uint16 Texture::getStoredMipDepth(uint16 level) const { } uint32 Texture::getStoredMipNumTexels(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip && mip->_sysmem.getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level); } else { @@ -254,7 +254,7 @@ uint32 Texture::getStoredMipNumTexels(uint16 level) const { } uint32 Texture::getStoredMipSize(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip && mip->_sysmem.getSize()) { return evalMipWidth(level) * evalMipHeight(level) * evalMipDepth(level) * getTexelFormat().getSize(); } else { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 8f63abe005..e9a6afe0f2 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -29,7 +29,7 @@ public: Sysmem _sysmem; Element _format; }; - typedef std::shared_ptr PixelsPointer; + typedef QSharedPointer< Pixels > PixelsPointer; enum Type { TEX_1D = 0, @@ -49,7 +49,7 @@ public: const Stamp getStamp() const { return _stamp; } const Stamp getDataStamp(uint16 level = 0) const { - const Pixels* mip = accessStoredMip(level); + PixelsPointer mip = accessStoredMip(level); if (mip) { return mip->_sysmem.getStamp(); } @@ -87,8 +87,6 @@ public: uint16 getNumSlices() const { return _numSlices; } uint16 getNumSamples() const { return _numSamples; } - - //--------------------------------------------------------------------- // Sub Mips manipulation // The number mips that a dimension could haves @@ -146,29 +144,21 @@ public: // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes); - template< typename T > T* editMip(uint16 level) { - Pixels* mip = accessStoredMip(level); - if (mip) { - return mip->sysmem.edit(); - } - return 0; - } - - template< typename T > const T* readMip(uint16 level) const { - const Pixels* mip = accessStoredMip(level); - if (mip) { - return mip->sysmem.read(); - } - return 0; - } - - bool isSysmemMipAvailable(uint16 level) const { - const Pixels* mip = accessStoredMip(level); + bool isStoredMipAvailable(uint16 level) const { + const PixelsPointer mip = accessStoredMip(level); if (mip) { return mip->_sysmem.isAvailable(); } return false; } + // Access the the sub mips + const PixelsPointer Texture::accessStoredMip(uint16 level) const { + if (level > _mips.size()) { + return 0; + } else { + return _mips[level]; + } + } // access sizes for the stored mips uint16 getStoredMipWidth(uint16 level) const; @@ -207,25 +197,16 @@ protected: Size resize(Type type, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); - // Access the the sub mips - const Pixels* Texture::accessStoredMip(uint16 level) const { - if (level > _mips.size()) { - return 0; - } else { - return _mips[level].get(); - } - } - - // Access the the sub mips - Pixels* Texture::accessStoredMip(uint16 level) { - if (level > _mips.size()) { - return 0; - } else { - return _mips[level].get(); - } - } - void allocateStoredMip(uint16 level); + + // Access the the sub mips + PixelsPointer Texture::accessStoredMip(uint16 level) { + if (level > _mips.size()) { + return 0; + } else { + return _mips[level]; + } + } mutable GPUObject* _gpuObject = NULL; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a91081ccdb..3163aa5f9c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -2351,7 +2351,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod } } - GLBATCH(glPushMatrix)(); + // GLBATCH(glPushMatrix)(); const MeshState& state = _meshStates.at(i); if (state.clusterMatrices.size() > 1) { @@ -2388,7 +2388,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod // apply material properties if (mode == SHADOW_RENDER_MODE) { - GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); + /// GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); } else { if (lastMaterialID != part.materialID) { @@ -2437,19 +2437,26 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod } if (!mesh.tangents.isEmpty()) { - GLBATCH(glActiveTexture)(GL_TEXTURE1); + // GLBATCH(glActiveTexture)(GL_TEXTURE1); Texture* normalMap = networkPart.normalTexture.data(); - GLBATCH(glBindTexture)(GL_TEXTURE_2D, !normalMap ? + /* GLBATCH(glBindTexture)(GL_TEXTURE_2D, !normalMap ? textureCache->getBlueTextureID() : normalMap->getID()); GLBATCH(glActiveTexture)(GL_TEXTURE0); + */ + batch.setUniformTexture(1, !normalMap ? + textureCache->getBlueTexture() : normalMap->getGPUTexture()); + } if (locations->specularTextureUnit >= 0) { - GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->specularTextureUnit); + // GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->specularTextureUnit); Texture* specularMap = networkPart.specularTexture.data(); - GLBATCH(glBindTexture)(GL_TEXTURE_2D, !specularMap ? + /* GLBATCH(glBindTexture)(GL_TEXTURE_2D, !specularMap ? textureCache->getWhiteTextureID() : specularMap->getID()); GLBATCH(glActiveTexture)(GL_TEXTURE0); + */ + batch.setUniformTexture(locations->specularTextureUnit, !specularMap ? + textureCache->getWhiteTexture() : specularMap->getGPUTexture()); } if (args) { @@ -2466,11 +2473,14 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod float emissiveScale = part.emissiveParams.y; GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale); - GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit); + // GLBATCH(glActiveTexture)(GL_TEXTURE0 + locations->emissiveTextureUnit); Texture* emissiveMap = networkPart.emissiveTexture.data(); - GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ? + /* GLBATCH(glBindTexture)(GL_TEXTURE_2D, !emissiveMap ? textureCache->getWhiteTextureID() : emissiveMap->getID()); GLBATCH(glActiveTexture)(GL_TEXTURE0); + */ + batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ? + textureCache->getWhiteTexture() : emissiveMap->getGPUTexture()); } lastMaterialID = part.materialID; @@ -2496,7 +2506,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod } } - if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { + /* if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { GLBATCH(glActiveTexture)(GL_TEXTURE1); GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); GLBATCH(glActiveTexture)(GL_TEXTURE0); @@ -2513,8 +2523,8 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0); GLBATCH(glActiveTexture)(GL_TEXTURE0); } - - GLBATCH(glPopMatrix)(); + */ + // GLBATCH(glPopMatrix)(); } diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 6c623d3eb7..c8bb936b27 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -167,7 +167,7 @@ static void loadSingleColorTexture(const unsigned char* color) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } - +/* GLuint TextureCache::getWhiteTextureID() { if (_whiteTextureID == 0) { glGenTextures(1, &_whiteTextureID); @@ -177,7 +177,7 @@ GLuint TextureCache::getWhiteTextureID() { } return _whiteTextureID; } - +*/ const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (_whiteTexture.isNull()) { _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); @@ -185,7 +185,7 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() { } return _whiteTexture; } - +/* GLuint TextureCache::getBlueTextureID() { if (_blueTextureID == 0) { glGenTextures(1, &_blueTextureID); @@ -195,7 +195,7 @@ GLuint TextureCache::getBlueTextureID() { } return _blueTextureID; } - +*/ const gpu::TexturePointer& TextureCache::getBlueTexture() { if (_blueTexture.isNull()) { @@ -554,7 +554,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo finishedLoading(true); imageLoaded(image); - glBindTexture(GL_TEXTURE_2D, getID()); + /* glBindTexture(GL_TEXTURE_2D, getID()); if (image.hasAlphaChannel()) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); @@ -566,7 +566,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); - + */ if (image.hasAlphaChannel()) { _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), image.width(), image.height())); _gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), image.byteCount(), image.constBits()); @@ -604,6 +604,7 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio painter.fillPath(path, Qt::black); painter.end(); + /* glBindTexture(GL_TEXTURE_2D, texture->getID()); if (dilatedImage.hasAlphaChannel()) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 0, @@ -615,7 +616,7 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); - + */ if (dilatedImage.hasAlphaChannel()) { texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), dilatedImage.width(), dilatedImage.height())); texture->_gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), dilatedImage.byteCount(), dilatedImage.constBits()); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 9591218f80..97523d93d3 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -49,13 +49,13 @@ public: GLuint getPermutationNormalTextureID(); /// Returns the ID of an opaque white texture (useful for a default). - GLuint getWhiteTextureID(); + // GLuint getWhiteTextureID(); /// Returns an opaque white texture (useful for a default). const gpu::TexturePointer& getWhiteTexture(); /// Returns the ID of a pale blue texture (useful for a normal map). - GLuint getBlueTextureID(); + // GLuint getBlueTextureID(); /// Returns the ID of a pale blue texture (useful for a normal map). /// Returns an opaque white texture (useful for a default). From 1e84f260a9f59b63341deb15734d2de402e92cc6 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Wed, 21 Jan 2015 16:53:35 -0800 Subject: [PATCH 22/22] Removing gl calls for texture from TextureCache --- libraries/fbx/src/FBXReader.cpp | 3 +- libraries/gpu/src/gpu/GLBackendTexture.cpp | 12 +- libraries/gpu/src/gpu/Texture.cpp | 146 +++++++++++++------- libraries/gpu/src/gpu/Texture.h | 79 +++++------ libraries/render-utils/src/TextureCache.cpp | 83 ++--------- libraries/render-utils/src/TextureCache.h | 17 +-- 6 files changed, 167 insertions(+), 173 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 3015de52ff..89a46f2be9 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -272,7 +272,8 @@ FBXNode parseBinaryFBXNode(QDataStream& in, int& position) { position += nameLength; for (quint32 i = 0; i < propertyCount; i++) { - node.properties.append(parseBinaryFBXProperty(in, position)); + QVariant var = parseBinaryFBXProperty(in, position); + node.properties.append(var); } while (endOffset > position) { diff --git a/libraries/gpu/src/gpu/GLBackendTexture.cpp b/libraries/gpu/src/gpu/GLBackendTexture.cpp index e23f6fdaec..5fa33a4210 100755 --- a/libraries/gpu/src/gpu/GLBackendTexture.cpp +++ b/libraries/gpu/src/gpu/GLBackendTexture.cpp @@ -215,6 +215,9 @@ void GLBackend::syncGPUObject(const Texture& texture) { // Need to update the content of the GPU object from the source sysmem of the texture needUpdate = true; } + } else if (!texture.isDefined()) { + // NO texture definition yet so let's avoid thinking + return; } // need to have a gpu object? @@ -224,6 +227,7 @@ void GLBackend::syncGPUObject(const Texture& texture) { CHECK_GL_ERROR(); Backend::setGPUObject(texture, object); } + // GO through the process of allocating the correct storage and/or update the content switch (texture.getType()) { case Texture::TEX_2D: { @@ -292,5 +296,11 @@ void GLBackend::syncGPUObject(const Texture& texture) { GLuint GLBackend::getTextureID(const Texture& texture) { GLBackend::syncGPUObject(texture); - return Backend::getGPUObject(texture)->_texture; + GLTexture* object = Backend::getGPUObject(texture); + if (object) { + return object->_texture; + } else { + return 0; + } } + diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 5a52529403..a608e74dd1 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -23,6 +23,63 @@ Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) : Texture::Pixels::~Pixels() { } +Stamp Texture::Storage::getStamp(uint16 level) const { + PixelsPointer mip = getMip(level); + if (mip) { + return mip->_sysmem.getStamp(); + } else { + return 0; + } +} + +void Texture::Storage::reset() { + _mips.clear(); +} + +Texture::PixelsPointer Texture::Storage::editMip(uint16 level) { + if (level > _mips.size()) { + return PixelsPointer(); + } else { + return _mips[level]; + } +} + +const Texture::PixelsPointer Texture::Storage::getMip(uint16 level) const { + if (level > _mips.size()) { + return PixelsPointer(); + } else { + return _mips[level]; + } +} + +bool Texture::Storage::isMipAvailable(uint16 level) const { + PixelsPointer mip = getMip(level); + return (mip && mip->_sysmem.getSize()); +} + +bool Texture::Storage::allocateMip(uint16 level) { + bool changed = false; + if (level >= _mips.size()) { + _mips.resize(level+1, PixelsPointer()); + changed = true; + } + + if (!_mips[level]) { + _mips[level] = PixelsPointer(new Pixels()); + changed = true; + } + + return changed; +} + +bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) { + // Ok we should be able to do that... + allocateMip(level); + _mips[level]->_format = format; + Size allocated = _mips[level]->_sysmem.setData(size, bytes); + return allocated == size; +} + Texture* Texture::create1D(const Element& texelFormat, uint16 width) { return create(TEX_1D, texelFormat, width, 1, 1, 1, 1); } @@ -42,17 +99,25 @@ Texture* Texture::createCube(const Element& texelFormat, uint16 width) { Texture* Texture::create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { Texture* tex = new Texture(); - + tex->_storage.reset(new Storage()); + tex->_storage->_texture = tex; tex->_type = type; - tex->_texelFormat = texelFormat; tex->_maxMip = 0; - tex->resize(type, width, height, depth, numSamples, numSlices); + tex->resize(type, texelFormat, width, height, depth, numSamples, numSlices); return tex; } +Texture* Texture::createFromStorage(Storage* storage) { + Texture* tex = new Texture(); + tex->_storage.reset(storage); + storage->_texture = tex; + return tex; +} + Texture::Texture(): Resource(), + _storage(), _stamp(0), _size(0), _width(1), @@ -61,7 +126,9 @@ Texture::Texture(): _numSamples(1), _numSlices(1), _maxMip(0), - _autoGenerateMips(false) + _type(TEX_1D), + _autoGenerateMips(false), + _defined(false) { } @@ -69,10 +136,15 @@ Texture::~Texture() { } -Texture::Size Texture::resize(Type type, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { +Texture::Size Texture::resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices) { if (width && height && depth && numSamples && numSlices) { bool changed = false; + if ( _type != type) { + _type = type; + changed = true; + } + if (_numSlices != numSlices) { _numSlices = numSlices; changed = true; @@ -100,50 +172,47 @@ Texture::Size Texture::resize(Type type, uint16 width, uint16 height, uint16 dep changed = true; } + // Evaluate the new size with the new format const int DIM_SIZE[] = {1, 1, 1, 6}; - int size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * _texelFormat.getSize(); + int size = DIM_SIZE[_type] *_width * _height * _depth * _numSamples * texelFormat.getSize(); + // If size change then we need to reset if (changed || (size != getSize())) { _size = size; - _mips.clear(); + _storage->reset(); _stamp++; - } + } + + // TexelFormat might have change, but it's mostly interpretation + if (texelFormat != _texelFormat) { + _texelFormat = texelFormat; + _stamp++; + } + + // Here the Texture has been fully defined from the gpu point of view (size and format) + _defined = true; + } else { + _stamp++; } return _size; } Texture::Size Texture::resize1D(uint16 width, uint16 numSamples) { - return resize(TEX_1D, width, 1, 1, numSamples, 1); + return resize(TEX_1D, getTexelFormat(), width, 1, 1, numSamples, 1); } Texture::Size Texture::resize2D(uint16 width, uint16 height, uint16 numSamples) { - return resize(TEX_2D, width, height, 1, numSamples, 1); + return resize(TEX_2D, getTexelFormat(), width, height, 1, numSamples, 1); } Texture::Size Texture::resize3D(uint16 width, uint16 height, uint16 depth, uint16 numSamples) { - return resize(TEX_3D, width, height, depth, numSamples, 1); + return resize(TEX_3D, getTexelFormat(), width, height, depth, numSamples, 1); } Texture::Size Texture::resizeCube(uint16 width, uint16 numSamples) { - return resize(TEX_CUBE, width, 1, 1, numSamples, 1); + return resize(TEX_CUBE, getTexelFormat(), width, 1, 1, numSamples, 1); } - -// Reformat, unless auto mips mode would destroy all the sub mips Texture::Size Texture::reformat(const Element& texelFormat) { - if (texelFormat != _texelFormat) { - - _texelFormat = texelFormat; - - const int DIM_SIZE[] = {1, 1, 1, 6}; - int size = DIM_SIZE[_type] * _width * _height * _depth * _numSamples * _texelFormat.getSize(); - - if (size != getSize()) { - _size = size; - _mips.clear(); - } - _stamp++; - } - - return _size; + return resize(_type, texelFormat, getWidth(), getHeight(), getDepth(), getNumSamples(), getNumSlices()); } bool Texture::isColorRenderTarget() const { @@ -172,19 +241,6 @@ uint16 Texture::maxMip() const { return _maxMip; } -void Texture::allocateStoredMip(uint16 level) { - if (level >= _mips.size()) { - _mips.resize(level+1, 0); - _maxMip = level; - _stamp++; - } - - if (!_mips[level]) { - _mips[level] = PixelsPointer(new Pixels()); - _stamp++; - } -} - bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) { // Check that level accessed make sense if (level != 0) { @@ -198,12 +254,8 @@ bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, co // THen check that the mem buffer passed make sense with its format if (size == evalStoredMipSize(level, format)) { - // Ok we should be able to do that... - allocateStoredMip(level); - _mips[level]->_format = format; - _mips[level]->_sysmem.setData(size, bytes); + _storage->assignMipData(level, format, size, bytes); _stamp++; - return true; } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index e9a6afe0f2..8da500b444 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -31,6 +31,24 @@ public: }; typedef QSharedPointer< Pixels > PixelsPointer; + class Storage { + Texture* _texture; + std::vector _mips; + public: + + Storage() {} + virtual ~Storage() {} + virtual void reset(); + virtual PixelsPointer editMip(uint16 level); + virtual const PixelsPointer getMip(uint16 level) const; + virtual Stamp getStamp(uint16 level) const; + virtual bool allocateMip(uint16 level); + virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes); + virtual bool isMipAvailable(uint16 level) const; + + friend class Texture; + }; + enum Type { TEX_1D = 0, TEX_2D, @@ -43,18 +61,14 @@ public: static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth); static Texture* createCube(const Element& texelFormat, uint16 width); + static Texture* createFromStorage(Storage* storage); + Texture(const Texture& buf); // deep copy of the sysmem texture Texture& operator=(const Texture& buf); // deep copy of the sysmem texture ~Texture(); const Stamp getStamp() const { return _stamp; } - const Stamp getDataStamp(uint16 level = 0) const { - PixelsPointer mip = accessStoredMip(level); - if (mip) { - return mip->_sysmem.getStamp(); - } - return getStamp(); - } + const Stamp getDataStamp(uint16 level = 0) const { return _storage->getStamp(level); } // The size in bytes of data stored in the texture Size getSize() const { return _size; } @@ -87,7 +101,10 @@ public: uint16 getNumSlices() const { return _numSlices; } uint16 getNumSamples() const { return _numSamples; } - // Sub Mips manipulation + // NumSamples can only have certain values based on the hw + static uint16 evalNumSamplesUsed(uint16 numSamplesTried); + + // Mips size evaluation // The number mips that a dimension could haves // = 1 + log2(size) @@ -116,7 +133,6 @@ public: return size * getNumSlices(); } - // max mip is in the range [ 1 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 @@ -137,6 +153,8 @@ public: uint16 autoGenerateMips(uint16 maxMip); bool isAutogenerateMips() const { return _autoGenerateMips; } + // Managing Storage and mips + // Manually allocate the mips down until the specified maxMip // this is just allocating the sysmem version of it // in case autoGen is on, this doesn't allocate @@ -144,35 +162,21 @@ public: // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes); - bool isStoredMipAvailable(uint16 level) const { - const PixelsPointer mip = accessStoredMip(level); - if (mip) { - return mip->_sysmem.isAvailable(); - } - return false; - } - // Access the the sub mips - const PixelsPointer Texture::accessStoredMip(uint16 level) const { - if (level > _mips.size()) { - return 0; - } else { - return _mips[level]; - } - } - + // Access the the sub mips + bool isStoredMipAvailable(uint16 level) const { return _storage->isMipAvailable(level); } + const PixelsPointer accessStoredMip(uint16 level) const { return _storage->getMip(level); } + // access sizes for the stored mips uint16 getStoredMipWidth(uint16 level) const; uint16 getStoredMipHeight(uint16 level) const; uint16 getStoredMipDepth(uint16 level) const; uint32 getStoredMipNumTexels(uint16 level) const; uint32 getStoredMipSize(uint16 level) const; - - - static uint16 evalNumSamplesUsed(uint16 numSamplesTried); + + bool isDefined() const { return _defined; } protected: - - std::vector _mips; + std::unique_ptr< Storage > _storage; Stamp _stamp; @@ -190,23 +194,12 @@ protected: Type _type; bool _autoGenerateMips; - + bool _defined; static Texture* create(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); Texture(); - Size resize(Type type, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); - - void allocateStoredMip(uint16 level); - - // Access the the sub mips - PixelsPointer Texture::accessStoredMip(uint16 level) { - if (level > _mips.size()) { - return 0; - } else { - return _mips[level]; - } - } + Size resize(Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices); mutable GPUObject* _gpuObject = NULL; diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index c8bb936b27..07f3ad6924 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -26,9 +26,7 @@ #include "TextureCache.h" TextureCache::TextureCache() : - _permutationNormalTextureID(0), - _whiteTextureID(0), - _blueTextureID(0), + _permutationNormalTexture(0), _whiteTexture(0), _blueTexture(0), _primaryDepthTextureID(0), @@ -46,12 +44,7 @@ TextureCache::TextureCache() : } TextureCache::~TextureCache() { - if (_permutationNormalTextureID != 0) { - glDeleteTextures(1, &_permutationNormalTextureID); - } - if (_whiteTextureID != 0) { - glDeleteTextures(1, &_whiteTextureID); - } + if (_primaryFramebufferObject) { glDeleteTextures(1, &_primaryDepthTextureID); glDeleteTextures(1, &_primaryNormalTextureID); @@ -126,11 +119,9 @@ const int permutation[256] = #define USE_CHRIS_NOISE 1 -GLuint TextureCache::getPermutationNormalTextureID() { - if (_permutationNormalTextureID == 0) { - glGenTextures(1, &_permutationNormalTextureID); - glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); - +const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() { + if (_permutationNormalTexture.isNull()) { + // the first line consists of random permutation offsets unsigned char data[256 * 2 * 3]; #if (USE_CHRIS_NOISE==1) @@ -150,12 +141,14 @@ GLuint TextureCache::getPermutationNormalTextureID() { data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f; data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); + + _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2)); + _permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data); + + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } - return _permutationNormalTextureID; + return _permutationNormalTexture; } const unsigned char OPAQUE_WHITE[] = { 0xFF, 0xFF, 0xFF, 0xFF }; @@ -167,17 +160,7 @@ static void loadSingleColorTexture(const unsigned char* color) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, color); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } -/* -GLuint TextureCache::getWhiteTextureID() { - if (_whiteTextureID == 0) { - glGenTextures(1, &_whiteTextureID); - glBindTexture(GL_TEXTURE_2D, _whiteTextureID); - loadSingleColorTexture(OPAQUE_WHITE); - glBindTexture(GL_TEXTURE_2D, 0); - } - return _whiteTextureID; -} -*/ + const gpu::TexturePointer& TextureCache::getWhiteTexture() { if (_whiteTexture.isNull()) { _whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1)); @@ -185,17 +168,6 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() { } return _whiteTexture; } -/* -GLuint TextureCache::getBlueTextureID() { - if (_blueTextureID == 0) { - glGenTextures(1, &_blueTextureID); - glBindTexture(GL_TEXTURE_2D, _blueTextureID); - loadSingleColorTexture(OPAQUE_BLUE); - glBindTexture(GL_TEXTURE_2D, 0); - } - return _blueTextureID; -} -*/ const gpu::TexturePointer& TextureCache::getBlueTexture() { if (_blueTexture.isNull()) { @@ -554,19 +526,7 @@ void NetworkTexture::setImage(const QImage& image, bool translucent, const QColo finishedLoading(true); imageLoaded(image); - /* glBindTexture(GL_TEXTURE_2D, getID()); - if (image.hasAlphaChannel()) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, - GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, - GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); - } - // generate mipmaps - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - */ + if (image.hasAlphaChannel()) { _gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), image.width(), image.height())); _gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), image.byteCount(), image.constBits()); @@ -603,20 +563,7 @@ QSharedPointer DilatableNetworkTexture::getDilatedTexture(float dilatio path.addEllipse(QPointF(_image.width() / 2.0, _image.height() / 2.0), radius, radius); painter.fillPath(path, Qt::black); painter.end(); - - /* - glBindTexture(GL_TEXTURE_2D, texture->getID()); - if (dilatedImage.hasAlphaChannel()) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dilatedImage.width(), dilatedImage.height(), 0, - GL_BGRA, GL_UNSIGNED_BYTE, dilatedImage.constBits()); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dilatedImage.width(), dilatedImage.height(), 0, - GL_RGB, GL_UNSIGNED_BYTE, dilatedImage.constBits()); - } - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glBindTexture(GL_TEXTURE_2D, 0); - */ + if (dilatedImage.hasAlphaChannel()) { texture->_gpuTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), dilatedImage.width(), dilatedImage.height())); texture->_gpuTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA), dilatedImage.byteCount(), dilatedImage.constBits()); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 97523d93d3..b7891e5fac 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -46,19 +46,12 @@ public: /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and /// the second, a set of random unit vectors to be used as noise gradients. - GLuint getPermutationNormalTextureID(); - - /// Returns the ID of an opaque white texture (useful for a default). - // GLuint getWhiteTextureID(); + const gpu::TexturePointer& getPermutationNormalTexture(); /// Returns an opaque white texture (useful for a default). const gpu::TexturePointer& getWhiteTexture(); - /// Returns the ID of a pale blue texture (useful for a normal map). - // GLuint getBlueTextureID(); - - /// Returns the ID of a pale blue texture (useful for a normal map). - /// Returns an opaque white texture (useful for a default). + /// Returns the a pale blue texture (useful for a normal map). const gpu::TexturePointer& getBlueTexture(); /// Loads a texture from the specified URL. @@ -108,10 +101,8 @@ private: friend class DilatableNetworkTexture; QOpenGLFramebufferObject* createFramebufferObject(); - - GLuint _permutationNormalTextureID; - GLuint _whiteTextureID; - GLuint _blueTextureID; + + gpu::TexturePointer _permutationNormalTexture; gpu::TexturePointer _whiteTexture; gpu::TexturePointer _blueTexture;