diff --git a/examples/billiards.js b/examples/billiards.js
new file mode 100644
index 0000000000..9bc21ff611
--- /dev/null
+++ b/examples/billiards.js
@@ -0,0 +1,197 @@
+// Pool Table
+var tableParts = [];
+var balls = [];
+
+var LENGTH = 2.84;
+var WIDTH = 1.42;
+var HEIGHT = 0.80;
+var SCALE = 2.0;
+var BALL_SIZE = 0.05715;
+var BUMPER_WIDTH = 0.15;
+var BUMPER_HEIGHT = BALL_SIZE * 2.0;
+var HOLE_SIZE = BALL_SIZE;
+var DROP_HEIGHT = BALL_SIZE * 3.0;
+var GRAVITY = -9.8;
+var BALL_GAP = 0.001;
+
+var startStroke = 0;
+
+HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
+var screenSize = Controller.getViewportDimensions();
+var reticle = Overlays.addOverlay("image", {
+ x: screenSize.x / 2 - 16,
+ y: screenSize.y / 2 - 16,
+ width: 32,
+ height: 32,
+ imageURL: HIFI_PUBLIC_BUCKET + "images/reticle.png",
+ color: { red: 255, green: 255, blue: 255},
+ alpha: 1
+ });
+
+function makeTable(pos) {
+ // Top
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: pos,
+ dimensions: { x: LENGTH * SCALE, y: HEIGHT, z: WIDTH * SCALE },
+ color: { red: 0, green: 255, blue: 0 } }));
+ // Long Bumpers
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x - LENGTH / 2.0,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
+ dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x + LENGTH / 2.0,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z - (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
+ dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x - LENGTH / 2.0,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
+ dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x + LENGTH / 2.0,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z + (WIDTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE },
+ dimensions: { x: (LENGTH - 3.0 * HOLE_SIZE) * SCALE / 2.0, y: BUMPER_HEIGHT, z: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+ // End bumpers
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x + (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z },
+ dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+
+ tableParts.push(Entities.addEntity(
+ { type: "Box",
+ position: { x: pos.x - (LENGTH / 2.0 + BUMPER_WIDTH / 2.0) * SCALE,
+ y: pos.y + (HEIGHT / 2.0 + BUMPER_HEIGHT / 2.0),
+ z: pos.z },
+ dimensions: { z: (WIDTH - 2.0 * HOLE_SIZE) * SCALE, y: BUMPER_HEIGHT, x: BUMPER_WIDTH * SCALE },
+ color: { red: 237, green: 201, blue: 175 } }));
+
+}
+
+function makeBalls(pos) {
+ var colors = [{ red: 255, green: 255, blue: 0}, // Yellow
+ { red: 0, green: 0, blue: 255}, // Blue
+ { red: 255, green: 0, blue: 0}, // Red
+ { red: 128, green: 0, blue: 128}, // Purple
+ { red: 255, green: 165, blue: 0}, // Orange
+ { red: 0, green: 255, blue: 0}, // Green
+ { red: 128, green: 0, blue: 0}, // Maroon
+ { red: 0, green: 0, blue: 0}, // Black
+ { red: 255, green: 255, blue: 224}, // Light Yellow
+ { red: 173, green: 216, blue: 230}, // Light Blue
+ { red: 205, green: 92, blue: 92}, // Indian Red
+ { red: 218, green: 112, blue: 214}, // Orchid
+ { red: 218, green: 165, blue: 32}, // GoldenRod
+ { red: 255, green: 99, blue: 71}, // Tomato
+ { red: 128, green: 128, blue: 128}]; // Gray
+
+ // Object balls
+ var ballPosition = { x: pos.x + (LENGTH / 4.0) * SCALE, y: pos.y + DROP_HEIGHT, z: pos.z };
+ for (var row = 1; row <= 5; row++) {
+ ballPosition.z = pos.z - ((row - 1.0) / 2.0 * (BALL_SIZE + BALL_GAP) * SCALE);
+ for (var spot = 0; spot < row; spot++) {
+ balls.push(Entities.addEntity(
+ { type: "Sphere",
+ position: ballPosition,
+ dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
+ color: colors[balls.length],
+ gravity: { x: 0, y: GRAVITY, z: 0 },
+ ignoreCollisions: false,
+ damping: 0.40,
+ collisionsWillMove: true }));
+ ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE;
+ }
+ ballPosition.x += (BALL_GAP + Math.sqrt(3.0) / 2.0 * BALL_SIZE) * SCALE;
+ }
+ // Cue Ball
+ ballPosition = { x: pos.x - (LENGTH / 4.0) * SCALE, y: pos.y + DROP_HEIGHT, z: pos.z };
+ balls.push(Entities.addEntity(
+ { type: "Sphere",
+ position: ballPosition,
+ dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
+ color: { red: 255, green: 255, blue: 255 },
+ gravity: { x: 0, y: GRAVITY, z: 0 },
+ ignoreCollisions: false,
+ damping: 0.40,
+ collisionsWillMove: true }));
+}
+
+function shootCue(velocity) {
+ var DISTANCE_FROM_CAMERA = BALL_SIZE * 5.0 * SCALE;
+ var camera = Camera.getPosition();
+ var forwardVector = Quat.getFront(Camera.getOrientation());
+ var cuePosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
+ var velocity = Vec3.multiply(forwardVector, velocity);
+ var BULLET_LIFETIME = 3.0;
+ var BULLET_GRAVITY = 0.0;
+ bulletID = Entities.addEntity(
+ { type: "Sphere",
+ position: cuePosition,
+ dimensions: { x: BALL_SIZE * SCALE, y: BALL_SIZE * SCALE, z: BALL_SIZE * SCALE },
+ color: { red: 255, green: 255, blue: 255 },
+ velocity: velocity,
+ lifetime: BULLET_LIFETIME,
+ gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
+ damping: 0.10,
+ density: 1000,
+ ignoreCollisions: false,
+ collisionsWillMove: true
+ });
+}
+
+function keyReleaseEvent(event) {
+ if ((startStroke > 0) && event.text == "SPACE") {
+ var endTime = new Date().getTime();
+ var delta = endTime - startStroke;
+ shootCue(delta / 100.0);
+ startStroke = 0;
+ }
+}
+
+function keyPressEvent(event) {
+ // Fire a cue ball
+ if ((startStroke == 0) && (event.text == "SPACE")) {
+ startStroke = new Date().getTime();
+ }
+}
+
+function cleanup() {
+ for (var i = 0; i < tableParts.length; i++) {
+ if (!tableParts[i].isKnownID) {
+ tableParts[i] = Entities.identifyEntity(tableParts[i]);
+ }
+ Entities.deleteEntity(tableParts[i]);
+ }
+ for (var i = 0; i < balls.length; i++) {
+ if (!balls[i].isKnownID) {
+ balls[i] = Entities.identifyEntity(balls[i]);
+ }
+ Entities.deleteEntity(balls[i]);
+ }
+ Overlays.deleteOverlay(reticle);
+}
+
+var tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
+
+makeTable(tableCenter);
+makeBalls(tableCenter);
+
+Script.scriptEnding.connect(cleanup);
+Controller.keyPressEvent.connect(keyPressEvent);
+Controller.keyReleaseEvent.connect(keyReleaseEvent);
diff --git a/examples/editEntities.js b/examples/editEntities.js
index 0d9c4f68c6..9187b624fd 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;
}
});
@@ -690,8 +696,8 @@ 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: "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",
@@ -703,6 +709,7 @@ 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: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED,
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
@@ -718,7 +725,7 @@ function cleanupModelMenus() {
Menu.removeMenuItem("Edit", "Delete");
}
- Menu.removeMenuItem("Edit", "Model List...");
+ 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");
@@ -755,6 +762,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");
@@ -763,57 +792,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...");
- }
- } 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;
- }
- }
+ deleteSelectedEntities();
} else if (menuItem == "Paste Models") {
modelImporter.paste();
} else if (menuItem == "Export Models") {
@@ -826,6 +805,10 @@ function handeMenuEvent(menuItem) {
}
} else if (menuItem == "Import Models") {
modelImporter.doImport();
+ } else if (menuItem == "Entity List...") {
+ if (isActive) {
+ entityListTool.toggleVisible();
+ }
}
tooltip.show(false);
}
@@ -842,7 +825,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") {
diff --git a/examples/html/entityList.html b/examples/html/entityList.html
index 7caa45f19d..01061f1eb0 100644
--- a/examples/html/entityList.html
+++ b/examples/html/entityList.html
@@ -1,14 +1,32 @@
-
+
-
+
+
+
-
-
-
- Type |
- URL |
-
-
-
-
-
+
+
+
+
+
+ Type ▾ |
+ URL ▾ |
+
+
+
+
+ Type |
+ Type |
+ |
+
+
+
+
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
diff --git a/examples/html/style.css b/examples/html/style.css
index 5023bb4609..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,12 +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 rgb(63, 63, 63)
}
#entity-table tr.selected {
@@ -139,17 +135,22 @@ table#entity-table {
}
#entity-table td {
+ font-size: 11px;
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 {
@@ -226,3 +227,20 @@ table#properties-list {
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..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 = [];
@@ -24,10 +28,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 +78,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();
}
});
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..eeb1c84a4e 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 {
@@ -1480,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 {
@@ -1489,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()) {
@@ -1617,7 +1576,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 +1584,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 };
@@ -1705,7 +1665,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
@@ -1736,13 +1696,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;
@@ -1753,6 +1706,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;
@@ -1767,37 +1722,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, 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) {
@@ -1812,12 +1768,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()) {
@@ -1875,91 +1837,179 @@ 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];
+ crossings[crossingCount - 1].point.y -= y;
+ 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];
+ 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:
+ 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;
+ 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);
+ 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;
+ }
+ }
+
// 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) {
@@ -2107,173 +2157,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
@@ -2407,7 +2290,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 +2312,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);
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;
};
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index 8f9f54c591..b08b429ad0 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -220,7 +220,12 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
} else if (_overlaysWorld.contains(id)) {
thisOverlay = _overlaysWorld[id];
}
- return addOverlay(thisOverlay->createClone());
+
+ if (thisOverlay) {
+ return addOverlay(thisOverlay->createClone());
+ }
+
+ return 0; // Not found
}
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp
index 0c63ecc731..c4a4c4a458 100644
--- a/libraries/networking/src/AccountManager.cpp
+++ b/libraries/networking/src/AccountManager.cpp
@@ -158,7 +158,8 @@ void AccountManager::setAuthURL(const QUrl& authURL) {
void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
- QHttpMultiPart* dataMultiPart) {
+ QHttpMultiPart* dataMultiPart,
+ const QVariantMap& propertyMap) {
QMetaObject::invokeMethod(this, "invokedRequest",
Q_ARG(const QString&, path),
@@ -166,13 +167,15 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan
Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray),
- Q_ARG(QHttpMultiPart*, dataMultiPart));
+ Q_ARG(QHttpMultiPart*, dataMultiPart),
+ Q_ARG(QVariantMap, propertyMap));
}
void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation,
- const JSONCallbackParameters& callbackParams,
- const QByteArray& dataByteArray,
- QHttpMultiPart* dataMultiPart) {
+ const JSONCallbackParameters& callbackParams,
+ const QByteArray& dataByteArray,
+ QHttpMultiPart* dataMultiPart,
+ const QVariantMap& propertyMap) {
QMetaObject::invokeMethod(this, "invokedRequest",
Q_ARG(const QString&, path),
@@ -180,14 +183,16 @@ void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessM
Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray),
- Q_ARG(QHttpMultiPart*, dataMultiPart));
+ Q_ARG(QHttpMultiPart*, dataMultiPart),
+ Q_ARG(QVariantMap, propertyMap));
}
void AccountManager::invokedRequest(const QString& path,
bool requiresAuthentication,
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
- const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
+ const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart,
+ const QVariantMap& propertyMap) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
@@ -235,7 +240,9 @@ void AccountManager::invokedRequest(const QString& path,
} else {
networkReply = networkAccessManager.put(networkRequest, dataMultiPart);
}
- dataMultiPart->setParent(networkReply);
+
+ // make sure dataMultiPart is destroyed when the reply is
+ connect(networkReply, &QNetworkReply::destroyed, dataMultiPart, &QHttpMultiPart::deleteLater);
} else {
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
if (operation == QNetworkAccessManager::PostOperation) {
@@ -255,6 +262,14 @@ void AccountManager::invokedRequest(const QString& path,
}
if (networkReply) {
+ if (!propertyMap.isEmpty()) {
+ // we have properties to set on the reply so the user can check them after
+ foreach(const QString& propertyKey, propertyMap.keys()) {
+ networkReply->setProperty(qPrintable(propertyKey), propertyMap.value(propertyKey));
+ }
+ }
+
+
if (!callbackParams.isEmpty()) {
// if we have information for a callback, insert the callbackParams into our local map
_pendingCallbackMap.insert(networkReply, callbackParams);
diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h
index 53512a8bb3..06fe366d69 100644
--- a/libraries/networking/src/AccountManager.h
+++ b/libraries/networking/src/AccountManager.h
@@ -48,13 +48,15 @@ public:
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(),
- QHttpMultiPart* dataMultiPart = NULL);
+ QHttpMultiPart* dataMultiPart = NULL,
+ const QVariantMap& propertyMap = QVariantMap());
void unauthenticatedRequest(const QString& path,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(),
- QHttpMultiPart* dataMultiPart = NULL);
+ QHttpMultiPart* dataMultiPart = NULL,
+ const QVariantMap& propertyMap = QVariantMap()) ;
const QUrl& getAuthURL() const { return _authURL; }
void setAuthURL(const QUrl& authURL);
@@ -109,7 +111,8 @@ private:
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
- QHttpMultiPart* dataMultiPart);
+ QHttpMultiPart* dataMultiPart,
+ const QVariantMap& propertyMap);
QUrl _authURL;
QMap _pendingCallbackMap;
diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp
index fba3861f43..ff2925beea 100644
--- a/libraries/networking/src/AddressManager.cpp
+++ b/libraries/networking/src/AddressManager.cpp
@@ -119,14 +119,16 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl) {
if (!handleUsername(lookupUrl.authority())) {
// we're assuming this is either a network address or global place name
// check if it is a network address first
- if (!handleNetworkAddress(lookupUrl.host()
+ if (handleNetworkAddress(lookupUrl.host()
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())))) {
+ // we may have a path that defines a relative viewpoint - if so we should jump to that now
+ handleRelativeViewpoint(lookupUrl.path());
+ } else {
// wasn't an address - lookup the place name
- attemptPlaceNameLookup(lookupUrl.host());
+ // we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
+ attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path());
+
}
-
- // we may have a path that defines a relative viewpoint - if so we should jump to that now
- handleRelativeViewpoint(lookupUrl.path());
}
return true;
@@ -164,12 +166,14 @@ void AddressManager::handleAPIResponse(QNetworkReply& requestReply) {
QJsonObject responseObject = QJsonDocument::fromJson(requestReply.readAll()).object();
QJsonObject dataObject = responseObject["data"].toObject();
- goToAddressFromObject(dataObject.toVariantMap());
+ goToAddressFromObject(dataObject.toVariantMap(), requestReply);
emit lookupResultsFinished();
}
-void AddressManager::goToAddressFromObject(const QVariantMap& dataObject) {
+const char OVERRIDE_PATH_KEY[] = "override_path";
+
+void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const QNetworkReply& reply) {
const QString DATA_OBJECT_PLACE_KEY = "place";
const QString DATA_OBJECT_USER_LOCATION_KEY = "location";
@@ -203,6 +207,8 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject) {
if (domainObject.contains(DOMAIN_NETWORK_ADDRESS_KEY)) {
QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString();
+ qDebug() << "Possible domain change required to connect to" << domainHostname
+ << "on" << DEFAULT_DOMAIN_SERVER_PORT;
emit possibleDomainChangeRequired(domainHostname, DEFAULT_DOMAIN_SERVER_PORT);
} else {
QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString();
@@ -211,6 +217,9 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject) {
QString domainIDString = domainObject[DOMAIN_ID_KEY].toString();
QUuid domainID(domainIDString);
+ qDebug() << "Possible domain change required to connect to domain with ID" << domainID
+ << "via ice-server at" << iceServerAddress;
+
emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID);
}
@@ -223,18 +232,29 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject) {
QString newRootPlaceName = rootMap[PLACE_NAME_KEY].toString();
setRootPlaceName(newRootPlaceName);
- // take the path that came back
- const QString PLACE_PATH_KEY = "path";
- QString returnedPath = locationMap[PLACE_PATH_KEY].toString();
+ // check if we had a path to override the path returned
+ QString overridePath = reply.property(OVERRIDE_PATH_KEY).toString();
- bool shouldFaceViewpoint = locationMap.contains(LOCATION_API_ONLINE_KEY);
-
- if (!returnedPath.isEmpty()) {
- // try to parse this returned path as a viewpoint, that's the only thing it could be for now
- if (!handleRelativeViewpoint(returnedPath, shouldFaceViewpoint)) {
- qDebug() << "Received a location path that was could not be handled as a viewpoint -" << returnedPath;
+ if (!overridePath.isEmpty()) {
+ if (!handleRelativeViewpoint(overridePath)){
+ qDebug() << "User entered path could not be handled as a viewpoint - " << overridePath;
+ }
+ } else {
+ // take the path that came back
+ const QString PLACE_PATH_KEY = "path";
+ QString returnedPath = locationMap[PLACE_PATH_KEY].toString();
+
+ bool shouldFaceViewpoint = locationMap.contains(LOCATION_API_ONLINE_KEY);
+
+ if (!returnedPath.isEmpty()) {
+ // try to parse this returned path as a viewpoint, that's the only thing it could be for now
+ if (!handleRelativeViewpoint(returnedPath, shouldFaceViewpoint)) {
+ qDebug() << "Received a location path that was could not be handled as a viewpoint -" << returnedPath;
+ }
}
}
+
+
} else {
qDebug() << "Received an address manager API response with no domain key. Cannot parse.";
qDebug() << locationMap;
@@ -260,12 +280,21 @@ void AddressManager::handleAPIError(QNetworkReply& errorReply) {
const QString GET_PLACE = "/api/v1/places/%1";
-void AddressManager::attemptPlaceNameLookup(const QString& lookupString) {
+void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath) {
// assume this is a place name and see if we can get any info on it
QString placeName = QUrl::toPercentEncoding(lookupString);
+
+ QVariantMap requestParams;
+ if (!overridePath.isEmpty()) {
+ requestParams.insert(OVERRIDE_PATH_KEY, overridePath);
+ }
+
AccountManager::getInstance().unauthenticatedRequest(GET_PLACE.arg(placeName),
QNetworkAccessManager::GetOperation,
- apiCallbackParameters());
+ apiCallbackParameters(),
+ QByteArray(),
+ NULL,
+ requestParams);
}
bool AddressManager::handleNetworkAddress(const QString& lookupString) {
diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h
index 58e4e88330..3071d68ea2 100644
--- a/libraries/networking/src/AddressManager.h
+++ b/libraries/networking/src/AddressManager.h
@@ -47,7 +47,7 @@ public:
const QString& getRootPlaceName() const { return _rootPlaceName; }
void setRootPlaceName(const QString& rootPlaceName);
- void attemptPlaceNameLookup(const QString& lookupString);
+ void attemptPlaceNameLookup(const QString& lookupString, const QString& overridePath = QString());
void setPositionGetter(PositionGetter positionGetter) { _positionGetter = positionGetter; }
void setOrientationGetter(OrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
@@ -57,7 +57,7 @@ public:
public slots:
void handleLookupString(const QString& lookupString);
void goToUser(const QString& username);
- void goToAddressFromObject(const QVariantMap& addressMap);
+ void goToAddressFromObject(const QVariantMap& addressMap, const QNetworkReply& reply);
void storeCurrentAddress();
diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp
index ca14261c3b..a8b168681e 100644
--- a/libraries/physics/src/PhysicsEngine.cpp
+++ b/libraries/physics/src/PhysicsEngine.cpp
@@ -54,14 +54,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;
}
}
}
@@ -306,59 +309,53 @@ void PhysicsEngine::computeCollisionEvents() {
// 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->setRigidBody(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->setRigidBody(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->setRigidBody(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->setRigidBody(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->setRigidBody(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->setRigidBody(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 fdd4107421..73a02607e8 100644
--- a/libraries/physics/src/PhysicsEngine.h
+++ b/libraries/physics/src/PhysicsEngine.h
@@ -78,7 +78,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