From faa5b1d2f253e3964cc8781fe821cb283d7b171a Mon Sep 17 00:00:00 2001 From: Dev5 Date: Tue, 10 Jun 2014 17:18:32 -0700 Subject: [PATCH 1/2] Added simple tree placement script that has a UI similar to edit voxels. It grows big trees, dont grow near something important. --- examples/growTrees.js | 837 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 837 insertions(+) create mode 100644 examples/growTrees.js diff --git a/examples/growTrees.js b/examples/growTrees.js new file mode 100644 index 0000000000..d853804e77 --- /dev/null +++ b/examples/growTrees.js @@ -0,0 +1,837 @@ +// +// growPlants.js +// examples +// +// Created by Benjamin Arnold on May 29, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// This sample script allows the user to grow different types of plants on the voxels +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting +var previewLineWidth = 2.0; + +var voxelSize = 1; +var windowDimensions = Controller.getViewportDimensions(); +var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/"; + +var MAX_VOXEL_SCALE_POWER = 5; +var MIN_VOXEL_SCALE_POWER = -8; +var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER); +var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER); + + +var linePreviewTop = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewBottom = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewLeft = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + +var linePreviewRight = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 0, green: 255, blue: 0}, + alpha: 1, + visible: false, + lineWidth: previewLineWidth + }); + + +var UIColor = { red: 0, green: 160, blue: 0}; +var activeUIColor = { red: 0, green: 255, blue: 0}; + +var toolHeight = 50; +var toolWidth = 50; + +var editToolsOn = true; + +var voxelToolSelected = false; + +var scaleSelectorWidth = 144; +var scaleSelectorHeight = 37; + +var scaleSelectorX = windowDimensions.x / 5.0; +var scaleSelectorY = windowDimensions.y - scaleSelectorHeight; + +var voxelTool = Overlays.addOverlay("image", { + x: scaleSelectorX + scaleSelectorWidth + 1, y: windowDimensions.y - toolHeight, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: toolIconUrl + "voxel-tool.svg", + visible: editToolsOn, + color: UIColor, + alpha: 0.9 + }); + +var copyScale = true; +function ScaleSelector() { + this.x = scaleSelectorX; + this.y = scaleSelectorY; + this.width = scaleSelectorWidth; + this.height = scaleSelectorHeight; + + this.displayPower = false; + this.scale = 1.0; + this.power = 0; + + this.FIRST_PART = this.width * 40.0 / 100.0; + this.SECOND_PART = this.width * 37.0 / 100.0; + + this.buttonsOverlay = Overlays.addOverlay("image", { + x: this.x, y: this.y, + width: this.width, height: this.height, + //subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight }, + imageURL: toolIconUrl + "voxel-size-selector.svg", + alpha: 0.9, + visible: editToolsOn, + color: activeUIColor + }); + this.textOverlay = Overlays.addOverlay("text", { + x: this.x + this.FIRST_PART, y: this.y, + width: this.SECOND_PART, height: this.height, + topMargin: 13, + text: this.scale.toString(), + alpha: 0.0, + visible: editToolsOn, + color: activeUIColor + }); + this.powerOverlay = Overlays.addOverlay("text", { + x: this.x + this.FIRST_PART, y: this.y, + width: this.SECOND_PART, height: this.height, + leftMargin: 28, + text: this.power.toString(), + alpha: 0.0, + visible: false, + color: activeUIColor + }); + this.setScale = function(scale) { + if (scale > MAX_VOXEL_SCALE) { + scale = MAX_VOXEL_SCALE; + } + if (scale < MIN_VOXEL_SCALE) { + scale = MIN_VOXEL_SCALE; + } + + this.scale = scale; + this.power = Math.floor(Math.log(scale) / Math.log(2)); + this.update(); + } + + this.show = function(doShow) { + Overlays.editOverlay(this.buttonsOverlay, {visible: doShow}); + Overlays.editOverlay(this.textOverlay, {visible: doShow}); + Overlays.editOverlay(this.powerOverlay, {visible: doShow && this.displayPower}); + } + + this.move = function() { + this.x = swatchesX + swatchesWidth; + this.y = swatchesY; + + Overlays.editOverlay(this.buttonsOverlay, { + x: this.x, y: this.y, + }); + Overlays.editOverlay(this.textOverlay, { + x: this.x + this.FIRST_PART, y: this.y, + }); + Overlays.editOverlay(this.powerOverlay, { + x: this.x + this.FIRST_PART, y: this.y, + }); + } + + + this.switchDisplay = function() { + this.displayPower = !this.displayPower; + + if (this.displayPower) { + Overlays.editOverlay(this.textOverlay, { + leftMargin: 18, + text: "2" + }); + Overlays.editOverlay(this.powerOverlay, { + text: this.power.toString(), + visible: editToolsOn + }); + } else { + Overlays.editOverlay(this.textOverlay, { + leftMargin: 13, + text: this.scale.toString() + }); + Overlays.editOverlay(this.powerOverlay, { + visible: false + }); + } + } + + this.update = function() { + if (this.displayPower) { + Overlays.editOverlay(this.powerOverlay, {text: this.power.toString()}); + } else { + Overlays.editOverlay(this.textOverlay, {text: this.scale.toString()}); + } + } + + this.incrementScale = function() { + copyScale = false; + if (this.power < MAX_VOXEL_SCALE_POWER) { + ++this.power; + this.scale *= 2.0; + this.update(); + } + } + + this.decrementScale = function() { + copyScale = false; + if (MIN_VOXEL_SCALE_POWER < this.power) { + --this.power; + this.scale /= 2.0; + this.update(); + } + } + + this.clicked = function(x, y) { + if (this.x < x && x < this.x + this.width && + this.y < y && y < this.y + this.height) { + + if (x < this.x + this.FIRST_PART) { + this.decrementScale(); + } else if (x < this.x + this.FIRST_PART + this.SECOND_PART) { + this.switchDisplay(); + } else { + this.incrementScale(); + } + return true; + } + return false; + } + + this.cleanup = function() { + Overlays.deleteOverlay(this.buttonsOverlay); + Overlays.deleteOverlay(this.textOverlay); + Overlays.deleteOverlay(this.powerOverlay); + } + +} +var scaleSelector = new ScaleSelector(); + + +function calculateVoxelFromIntersection(intersection, operation) { + + var resultVoxel; + + var x; + var y; + var z; + + // if our "target voxel size" is larger than the voxel we intersected with, then we need to find the closest + // ancestor voxel of our target size that contains our intersected voxel. + if (voxelSize > intersection.voxel.s) { + x = Math.floor(intersection.voxel.x / voxelSize) * voxelSize; + y = Math.floor(intersection.voxel.y / voxelSize) * voxelSize; + z = Math.floor(intersection.voxel.z / voxelSize) * voxelSize; + } else { + // otherwise, calculate the enclosed voxel of size voxelSize that the intersection point falls inside of. + // if you have a voxelSize that's smaller than the voxel you're intersecting, this calculation will result + // in the subvoxel that the intersection point falls in, if the target voxelSize matches the intersecting + // voxel this still works and results in returning the intersecting voxel which is what we want + var adjustToCenter = Vec3.multiply(Voxels.getFaceVector(intersection.face), (voxelSize * -0.5)); + + var centerOfIntersectingVoxel = Vec3.sum(intersection.intersection, adjustToCenter); + x = Math.floor(centerOfIntersectingVoxel.x / voxelSize) * voxelSize; + y = Math.floor(centerOfIntersectingVoxel.y / voxelSize) * voxelSize; + z = Math.floor(centerOfIntersectingVoxel.z / voxelSize) * voxelSize; + } + resultVoxel = { x: x, y: y, z: z, s: voxelSize }; + var highlightAt = { x: x, y: y, z: z, s: voxelSize }; + + + + // we only do the "add to the face we're pointing at" adjustment, if the operation is an add + // operation, and the target voxel size is equal to or smaller than the intersecting voxel. + var wantAddAdjust = (operation == "add" && (voxelSize <= intersection.voxel.s)); + + // now we also want to calculate the "edge square" for the face for this voxel + if (intersection.face == "MIN_X_FACE") { + + highlightAt.x = x - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.x -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MAX_X_FACE") { + + highlightAt.x = x + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.x += resultVoxel.s; + } + + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MIN_Y_FACE") { + + highlightAt.y = y - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.y -= voxelSize; + } + + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust }; + + } else if (intersection.face == "MAX_Y_FACE") { + + highlightAt.y = y + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.y += voxelSize; + } + + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust}; + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust}; + + } else if (intersection.face == "MIN_Z_FACE") { + + highlightAt.z = z - zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.z -= voxelSize; + } + + resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; + resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; + + } else if (intersection.face == "MAX_Z_FACE") { + + highlightAt.z = z + voxelSize + zFightingSizeAdjust; + if (wantAddAdjust) { + resultVoxel.z += voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z}; + + } + return resultVoxel; +} + +var trackLastMouseX = 0; +var trackLastMouseY = 0; + +function showPreviewLines() { + + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + + var intersection = Voxels.findRayIntersection(pickRay); + + if (intersection.intersects) { + var resultVoxel = calculateVoxelFromIntersection(intersection, ""); + Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true }); + Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true }); + Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true }); + Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true }); + } else { + Overlays.editOverlay(linePreviewTop, { visible: false }); + Overlays.editOverlay(linePreviewBottom, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + Overlays.editOverlay(linePreviewRight, { visible: false }); + } +} + +function mouseMoveEvent(event) { + trackLastMouseX = event.x; + trackLastMouseY = event.y; + if (!voxelToolSelected) { + return; + } + showPreviewLines(); +} + + +// Array of possible trees, right now there is only one +var treeTypes = []; + +treeTypes.push({ + name: "Tall Green", + // Voxel Colors + wood: { r: 133, g: 81, b: 53 }, + leaves: { r: 22, g: 83, b: 31 }, + + // How tall the tree is + height: { min: 20, max: 60 }, + middleHeight: 0.3, + + // Chance of making a branch + branchChance: { min: 0.01, max: 0.1 }, + branchLength: { min: 30, max: 60 }, + branchThickness: { min: 2, max: 7}, + + // The width of the core, affects width and shape + coreWidth: { min: 1, max: 4 }, + + //TODO: Make this quadratic splines instead of linear + bottomThickness: { min: 2, max: 8 }, + middleThickness: { min: 1, max: 4 }, + topThickness: { min: 3, max: 6 }, + + //Modifies leaves at top + leafCapSizeOffset: 0 +}); + +// Applies noise to color +var colorNoiseRange = 0.2; + + +// Useful constants +var LEFT = 0; +var BACK = 1; +var RIGHT = 2; +var FRONT = 3; +var UP = 4; + +// Interpolates between min and max of treevar based on b +function interpolate(treeVar, b) { + return (treeVar.min + (treeVar.max - treeVar.min) * b); +} + +function makeBranch(x, y, z, step, length, dir, thickness, wood, leaves) { + var moveDir; + + var currentThickness; + //thickness attenuates to thickness - 3 + var finalThickness = thickness - 3; + if (finalThickness < 1) { + finalThickness = 1; + } + //Iterative branch generation + while (true) { + + //If we are at the end, place a ball of leaves + if (step == 0) { + makeSphere(x, y, z, 2 + finalThickness, leaves); + return; + } + //thickness attenuation + currentThickness = Math.round((finalThickness + (thickness - finalThickness) * (step/length))) - 1; + + + // If the branch is thick, grow a vertical slice + if (currentThickness > 0) { + for (var i = -currentThickness; i <= currentThickness; i++) { + var len = currentThickness - Math.abs(i); + switch (dir) { + case 0: //left + case 2: //right + growInDirection(x, y + i * voxelSize, z, len, len, BACK, wood, false, true); + growInDirection(x, y + i * voxelSize, z, len, len, FRONT, wood, false, false) + break; + case 1: //back + case 3: //front + growInDirection(x, y + i * voxelSize, z, len, len, LEFT, wood, false, true); + growInDirection(x, y + i * voxelSize, z, len, len, RIGHT, wood, false, false) + break; + } + } + } else { + //Otherwise place a single voxel + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x, y, z, voxelSize, wood.r * colorNoise, wood.g * colorNoise, wood.b * colorNoise); + } + + // determines random change in direction for branch + var r = Math.floor(Math.random() * 9); + + + if (r >= 6){ + moveDir = dir; //in same direction + } else if (r >= 4) { + moveDir = UP; //up + } + else if (dir == LEFT){ + if (r >= 2){ + moveDir = FRONT; + } + else{ + moveDir = BACK; + } + } + else if (dir == BACK){ + if (r >= 2){ + moveDir = LEFT; + } + else{ + moveDir = RIGHT; + } + } + else if (dir == RIGHT){ + if (r >= 2){ + moveDir = BACK; + } + else{ + moveDir = FRONT; + } + } + else if (dir == FRONT){ + if (r >= 2){ + moveDir = RIGHT; + } + else{ + moveDir = LEFT; + } + } + + //Move the branch by moveDir + switch (moveDir) { + case 0: //left + x = x - voxelSize; + break; + case 1: //back + z = z - voxelSize; + break; + case 2: //right + x = x + voxelSize; + break; + case 3: //front + z = z + voxelSize; + break; + case 4: //up + y = y + voxelSize; + break; + } + + step--; + } +} + +// Places a sphere of voxels +function makeSphere(x, y, z, radius, color) { + if (radius <= 0) { + return; + } + var width = radius * 2 + 1; + var distance; + + for (var i = -radius; i <= radius; i++){ + for (var j = -radius; j <= radius; j++){ + for (var k = -radius; k <= radius; k++){ + distance = Math.sqrt(i * i + j * j + k * k); + if (distance <= radius){ + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x + i * voxelSize, y + j * voxelSize, z + k * voxelSize, voxelSize, color.r * colorNoise, color.g * colorNoise, color.b * colorNoise); + } + } + } + } +} + +function growInDirection(x, y, z, step, length, dir, color, isSideBranching, addVoxel) { + + + if (addVoxel == true) { + var colorNoise = (colorNoiseRange * Math.random() - colorNoiseRange * 0.5) + 1.0; + Voxels.setVoxel(x, y, z, voxelSize, color.r * colorNoise, color.g * colorNoise, color.b * colorNoise); + } + + // If this is a main vein, it will branch outward perpendicular to its motion + if (isSideBranching == true){ + var step2; + if (step >= length - 1){ + step2 = length; + } + else{ + step2 = step + 1; + } + growInDirection(x, y, z, step, length, BACK, color, false, false); + growInDirection(x, y, z, step, length, FRONT, color, false, false); + } + + if (step < 1) return; + + // Recursively move in the direction + if (dir == LEFT) { //left + growInDirection(x - voxelSize, y, z, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == BACK) { //back + growInDirection(x, y, z - voxelSize, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == RIGHT) { //right + growInDirection(x + voxelSize, y, z, step - 1, length, dir, color, isSideBranching, true); + } + else if (dir == FRONT) {//front + growInDirection(x, y, z + voxelSize, step - 1, length, dir, color, isSideBranching, true); + } + +} + +// Grows the thickness of the tree +function growHorizontalSlice(x, y, z, thickness, color, side) { + // The side variable determines which directions we should grow in + // it is an optimization that prevents us from visiting voxels multiple + // times for trees with a coreWidth > 1 + + // side: + // 8 == all directions + // 0 1 2 + // 3 -1 4 + // 5 6 7 + + Voxels.setVoxel(x, y, z, voxelSize, color.r, color.g, color.b); + + //We are done if there is no thickness + if (thickness == 0) { + return; + } + + + switch (side) { + case 0: + growInDirection(x, y, z, thickness, thickness, LEFT, color, true, false); + break; + case 1: + growInDirection(x, y, z, thickness, thickness, BACK, color, false, false); + break; + case 2: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 3: + growInDirection(x, y, z, thickness, thickness, LEFT, color, false, false); + break; + case 4: + growInDirection(x, y, z, thickness, thickness, BACK, color, false, false); + break; + case 5: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 6: + growInDirection(x, y, z, thickness, thickness, FRONT, color, false, false); + break; + case 7: + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false); + break; + case 8: + if (thickness > 1){ + growInDirection(x, y, z, thickness, thickness, LEFT, color, true, false); + growInDirection(x, y, z, thickness, thickness, RIGHT, color, true, false) + } else if (thickness == 1){ + Voxels.setVoxel(x - voxelSize, y, z, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x + voxelSize, y, z, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x, y, z - voxelSize, voxelSize, color.r, color.g, color.b); + Voxels.setVoxel(x, y, z + voxelSize, voxelSize, color.r, color.g, color.b); + } + break; + } +} + +function computeSide(x, z, coreWidth) { + // side: + // 8 == all directions + // 0 1 2 + // 3 -1 4 + // 5 6 7 + + // if the core is only a single block, we can grow out in all directions + if (coreWidth == 1){ + return 8; + } + + // Back face + if (z == 0) { + if (x == 0) { + return 0; + } else if (x == coreWidth - 1) { + return 2; + } else { + return 1; + } + } + + // Front face + if (z == (coreWidth - 1)) { + if (x == 0) { + return 5; + } else if (x == (coreWidth - 1)) { + return 7; + } else { + return 6; + } + } + + // Left face + if (x == 0) { + return 3; + } + + // Right face + if (x == (coreWidth - 1)) { + return 4; + } + + //Interior + return -1; +} + + +function growTree(x, y, z, tree) { + + // The size of the tree, from 0-1 + var treeSize = Math.random(); + + // Get tree properties by interpolating with the treeSize + var height = interpolate(tree.height, treeSize); + var baseHeight = Math.ceil(tree.middleHeight * height); + var bottomThickness = interpolate(tree.bottomThickness, treeSize); + var middleThickness = interpolate(tree.middleThickness, treeSize); + var topThickness = interpolate(tree.topThickness, treeSize); + var coreWidth = Math.ceil(interpolate(tree.coreWidth, treeSize)); + + var thickness; + var side; + + //Loop upwards through each slice of the tree + for (var i = 0; i < height; i++){ + + //Branch properties are based on current height as well as the overall tree size + var branchChance = interpolate(tree.branchChance, i / height); + var branchLength = Math.ceil(interpolate(tree.branchLength, (i / height) * treeSize)); + var branchThickness = Math.round(interpolate(tree.branchThickness, (i / height) * treeSize)); + + // Get the "thickness" of the tree by doing linear interpolation between the middle thickness + // and the top and bottom thickness. + if (i <= baseHeight && baseHeight != 0){ + thickness = (i / (baseHeight) * (middleThickness - bottomThickness) + bottomThickness); + } else { + var denom = ((height - baseHeight)) * (topThickness - middleThickness) + middleThickness; + if (denom != 0) { + thickness = (i - baseHeight) / denom; + } else { + thickness = 0; + } + } + // The core of the tree is a vertical rectangular prism through the middle of the tree + + //Loop through the "core", which helps shape the trunk + var startX = x - Math.floor(coreWidth / 2) * voxelSize; + var startZ = z - Math.floor(coreWidth / 2) * voxelSize; + for (var j = 0; j < coreWidth; j++) { + for (var k = 0; k < coreWidth; k++) { + //determine which side of the tree we are on + side = computeSide(j, k, coreWidth); + //grow a horizontal slice of the tree + growHorizontalSlice(startX + j * voxelSize, y + i * voxelSize, startZ + k * voxelSize, Math.floor(thickness), tree.wood, side); + + // Branches + if (side != -1) { + var r = Math.random(); + if (r <= branchChance){ + var dir = Math.floor((Math.random() * 4)); + makeBranch(startX + j * voxelSize, y + i * voxelSize, startZ + k * voxelSize, branchLength, branchLength, dir, branchThickness, tree.wood, tree.leaves); + + } + } + } + } + } + + makeSphere(x, y + height * voxelSize, z, topThickness + coreWidth + tree.leafCapSizeOffset, tree.leaves); +} + +function mousePressEvent(event) { + var mouseX = event.x; + var mouseY = event.y; + + var clickedOnSomething = false; + // Check if we clicked an overlay + var clickedOverlay = Overlays.getOverlayAtPoint({x: mouseX, y: mouseY}); + + if (clickedOverlay == voxelTool) { + voxelToolSelected = !voxelToolSelected; + + if (voxelToolSelected == true) { + Overlays.editOverlay(voxelTool, { + color: activeUIColor + }); + } else { + Overlays.editOverlay(voxelTool, { + color: UIColor + }); + } + + clickedOnSomething = true; + } else if (scaleSelector.clicked(event.x, event.y)) { + clickedOnSomething = true; + voxelSize = scaleSelector.scale; + } + + // Return if we clicked on the UI or the voxel tool is disabled + if (clickedOnSomething || !voxelToolSelected) { + return; + } + + // Compute the picking ray for the click + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Voxels.findRayIntersection(pickRay); + var resultVoxel = calculateVoxelFromIntersection(intersection, "add"); + + // Currently not in use, could randomly select a tree + var treeIndex = Math.floor(Math.random() * treeTypes.length); + + // Grow the first tree type + growTree(resultVoxel.x, resultVoxel.y, resultVoxel.z, treeTypes[0]); + +} + +function update() { + +} + +function scriptEnding() { + Overlays.deleteOverlay(linePreviewTop); + Overlays.deleteOverlay(linePreviewBottom); + Overlays.deleteOverlay(linePreviewLeft); + Overlays.deleteOverlay(linePreviewRight); + scaleSelector.cleanup(); + Overlays.deleteOverlay(voxelTool); +} + +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseMoveEvent.connect(mouseMoveEvent); + +Script.scriptEnding.connect(scriptEnding); + +Script.update.connect(update); + +Voxels.setPacketsPerSecond(10000); From 41b9c3b7049cc46732cafa9bf833c5c1537b0fd5 Mon Sep 17 00:00:00 2001 From: Dev5 Date: Wed, 11 Jun 2014 09:06:00 -0700 Subject: [PATCH 2/2] Removed empty update function --- examples/growTrees.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/growTrees.js b/examples/growTrees.js index d853804e77..142c72300a 100644 --- a/examples/growTrees.js +++ b/examples/growTrees.js @@ -814,9 +814,6 @@ function mousePressEvent(event) { } -function update() { - -} function scriptEnding() { Overlays.deleteOverlay(linePreviewTop); @@ -832,6 +829,4 @@ Controller.mouseMoveEvent.connect(mouseMoveEvent); Script.scriptEnding.connect(scriptEnding); -Script.update.connect(update); - Voxels.setPacketsPerSecond(10000);