diff --git a/src/brushes/cubes.js b/src/brushes/cubes.js index 591259811..0e82c6668 100644 --- a/src/brushes/cubes.js +++ b/src/brushes/cubes.js @@ -7,9 +7,11 @@ AFRAME.registerBrush('cubes', roughness: 0.5, metalness: 0.5, side: THREE.DoubleSide, - shading: THREE.FlatShading + flatShading: true }); this.geometry = new THREE.BoxGeometry(1, 1, 1); + this.drawingEl = document.querySelector('.a-drawing'); + this.drawingEl.object3D.add(this.object3D); }, addPoint: function (position, orientation, pointerPosition, pressure, timestamp) { var box = new THREE.Mesh(this.geometry, this.material); @@ -17,11 +19,14 @@ AFRAME.registerBrush('cubes', var sca = pressure * this.data.size * Math.random(); box.scale.set(sca, sca, sca); box.position.copy(pointerPosition); - box.rotation.copy(orientation); + box.quaternion.copy(orientation); this.object3D.add(box); return true; + }, + undo: function () { + this.drawingEl.object3D.children.pop(); } }, {thumbnail: 'brushes/thumb_cubes.gif', spacing: 0.01} diff --git a/src/brushes/line.js b/src/brushes/line.js index e1ad39ad2..caca21daf 100644 --- a/src/brushes/line.js +++ b/src/brushes/line.js @@ -30,9 +30,9 @@ var onLoaded = require('../onloaded.js'); alphaTest: 0.5 }; - sharedBufferGeometryManager.addSharedBuffer('strip-flat', new THREE.MeshBasicMaterial(optionsBasic), THREE.TriangleStripDrawMode); - sharedBufferGeometryManager.addSharedBuffer('strip-shaded', new THREE.MeshStandardMaterial(optionsStandard), THREE.TriangleStripDrawMode); - sharedBufferGeometryManager.addSharedBuffer('strip-textured', new THREE.MeshStandardMaterial(optionTextured), THREE.TriangleStripDrawMode); + sharedBufferGeometryManager.addSharedBuffer('strip-flat', new THREE.MeshBasicMaterial(optionsBasic)); + sharedBufferGeometryManager.addSharedBuffer('strip-shaded', new THREE.MeshStandardMaterial(optionsStandard)); + sharedBufferGeometryManager.addSharedBuffer('strip-textured', new THREE.MeshStandardMaterial(optionTextured)); }); var line = { @@ -40,6 +40,7 @@ var onLoaded = require('../onloaded.js'); init: function (color, brushSize) { this.sharedBuffer = sharedBufferGeometryManager.getSharedBuffer('strip-' + this.materialOptions.type); this.sharedBuffer.restartPrimitive(); + this.sharedBuffer.strip = true; this.prevIdx = Object.assign({}, this.sharedBuffer.idx); this.idx = Object.assign({}, this.sharedBuffer.idx); @@ -113,12 +114,12 @@ var onLoaded = require('../onloaded.js'); this.idx = Object.assign({}, this.sharedBuffer.idx); this.sharedBuffer.update(); - this.computeStripVertexNormals(); + this.computeVertexNormals(); return true; }; })(), - computeStripVertexNormals: (function () { + computeVertexNormals: (function () { var pA = new THREE.Vector3(); var pB = new THREE.Vector3(); var pC = new THREE.Vector3(); @@ -167,7 +168,7 @@ var onLoaded = require('../onloaded.js'); } /* - first and last vertice (0 and 8) belongs just to one triangle + first and last vertices (0 and 8) belongs just to one triangle second and penultimate (1 and 7) belongs to two triangles the rest of the vertices belongs to three triangles diff --git a/src/brushes/rainbow.js b/src/brushes/rainbow.js index 595e18a92..0090d7d51 100644 --- a/src/brushes/rainbow.js +++ b/src/brushes/rainbow.js @@ -38,22 +38,25 @@ this.idx = 0; this.geometry = new THREE.BufferGeometry(); this.vertices = new Float32Array(this.options.maxPoints * 3 * 3); + this.indices = new Uint32Array(this.options.maxPoints * 4.5 * 4.5) this.uvs = new Float32Array(this.options.maxPoints * 2 * 2); this.linepositions = new Float32Array(this.options.maxPoints); this.geometry.setDrawRange(0, 0); - this.geometry.addAttribute('position', new THREE.BufferAttribute(this.vertices, 3).setDynamic(true)); - this.geometry.addAttribute('uv', new THREE.BufferAttribute(this.uvs, 2).setDynamic(true)); - this.geometry.addAttribute('lineposition', new THREE.BufferAttribute(this.linepositions, 1).setDynamic(true)); + this.geometry.setAttribute('position', new THREE.BufferAttribute(this.vertices, 3).setUsage(THREE.DynamicDrawUsage)); + this.geometry.setIndex(new THREE.BufferAttribute(this.indices, 3).setUsage(THREE.DynamicDrawUsage)); + this.geometry.setAttribute('uv', new THREE.BufferAttribute(this.uvs, 2).setUsage(THREE.DynamicDrawUsage)); + this.geometry.setAttribute('lineposition', new THREE.BufferAttribute(this.linepositions, 1).setUsage(THREE.DynamicDrawUsage)); this.material = material; var mesh = new THREE.Mesh(this.geometry, this.material); - mesh.drawMode = THREE.TriangleStripDrawMode; mesh.frustumCulled = false; mesh.vertices = this.vertices; this.object3D.add(mesh); + this.drawing = document.querySelector('.a-drawing'); + this.drawing.object3D.add(this.object3D); }, addPoint: (function () { var direction = new THREE.Vector3(); @@ -89,11 +92,18 @@ this.vertices[this.idx++] = posB.x; this.vertices[this.idx++] = posB.y; this.vertices[this.idx++] = posB.z; + + // Same principle as line brush strips + if (this.idx > 6) { + this.geometry.index.setXYZ(this.idx / 3 - 4, this.idx / 3 - 4, this.idx / 3 - 3, this.idx / 3 - 2); + this.geometry.index.setXYZ(this.idx / 3 - 3, this.idx / 3 - 2, this.idx / 3 - 3, this.idx / 3 - 1); + } this.geometry.attributes.position.needsUpdate = true; + this.geometry.index.needsUpdate = true; this.geometry.attributes.uv.needsUpdate = true; - this.geometry.setDrawRange(0, this.data.numPoints * 2); + this.geometry.setDrawRange(0, this.data.numPoints * 2 * 6); return true; } @@ -101,6 +111,9 @@ tick: function(timeOffset, delta) { this.material.uniforms.time.value = timeOffset; }, + undo: function () { + this.drawing.object3D.children.pop(); + } }, {thumbnail:'brushes/thumb_rainbow.png', maxPoints: 3000} ); diff --git a/src/brushes/single-sphere.js b/src/brushes/single-sphere.js index 09a49e70a..9ff627ddc 100644 --- a/src/brushes/single-sphere.js +++ b/src/brushes/single-sphere.js @@ -7,12 +7,14 @@ AFRAME.registerBrush('single-sphere', roughness: 0.6, metalness: 0.2, side: THREE.FrontSide, - shading: THREE.SmoothShading + flatShading: true }); this.geometry = new THREE.IcosahedronGeometry(1, 2); this.mesh = new THREE.Mesh(this.geometry, this.material); this.object3D.add(this.mesh); - this.mesh.visible = false + this.mesh.visible = false; + this.drawingEl = document.querySelector('.a-drawing'); + this.drawingEl.object3D.add(this.object3D); }, addPoint: function (position, orientation, pointerPosition, pressure, timestamp) { if (!this.firstPoint) { @@ -23,6 +25,9 @@ AFRAME.registerBrush('single-sphere', var distance = this.firstPoint.distanceTo(pointerPosition); this.mesh.scale.set(distance, distance, distance); return true; + }, + undo: function () { + this.drawingEl.object3D.children.pop(); } }, {thumbnail: 'brushes/thumb_single_sphere.png', spacing: 0.0} diff --git a/src/brushes/spheres.js b/src/brushes/spheres.js index 05b18c926..e6b0bc648 100644 --- a/src/brushes/spheres.js +++ b/src/brushes/spheres.js @@ -8,9 +8,11 @@ AFRAME.registerBrush('spheres', roughness: 0.5, metalness: 0.5, side: THREE.DoubleSide, - shading: THREE.FlatShading + flatShading: true }); this.geometry = new THREE.IcosahedronGeometry(1, 0); + this.drawingEl = document.querySelector('.a-drawing'); + this.drawingEl.object3D.add(this.object3D); }, // This function is called every time we need to add a point to our stroke // It should returns true if the point is added correctly, false otherwise. @@ -28,7 +30,7 @@ AFRAME.registerBrush('spheres', // Set the position of the sphere to match the controller positoin sphere.position.copy(pointerPosition); - sphere.rotation.copy(orientation); + sphere.quaternion.copy(orientation); // Add the sphere to the object3D this.object3D.add(sphere); @@ -45,6 +47,9 @@ AFRAME.registerBrush('spheres', var sin = (Math.sin(sphere.phase + time / 500.0) + 1) / 2 + 0.1; sphere.scale.copy(sphere.initialScale).multiplyScalar(sin); } + }, + undo: function () { + this.drawingEl.object3D.children.pop(); } }, // Define extra options for this brush diff --git a/src/brushes/stamp.js b/src/brushes/stamp.js index d204cfab3..957a04b46 100644 --- a/src/brushes/stamp.js +++ b/src/brushes/stamp.js @@ -22,8 +22,8 @@ var onLoaded = require('../onloaded.js'); alphaTest: 0.5 }); - sharedBufferGeometryManager.addSharedBuffer('tris-flat', flat, THREE.TrianglesDrawMode); - sharedBufferGeometryManager.addSharedBuffer('tris-shaded', shaded, THREE.TrianglesDrawMode); + sharedBufferGeometryManager.addSharedBuffer('tris-flat', flat); + sharedBufferGeometryManager.addSharedBuffer('tris-shaded', shaded); }); var stamp = { @@ -32,7 +32,7 @@ var onLoaded = require('../onloaded.js'); this.sharedBuffer = sharedBufferGeometryManager.getSharedBuffer('tris-' + this.materialOptions.type); this.prevIdx = Object.assign({}, this.sharedBuffer.idx); this.idx = Object.assign({}, this.sharedBuffer.idx); - + this.sharedBuffer.strip = false; this.currAngle = 0; this.subTextures = 1; diff --git a/src/sharedbuffergeometry.js b/src/sharedbuffergeometry.js index 1652ffbab..767b72eae 100644 --- a/src/sharedbuffergeometry.js +++ b/src/sharedbuffergeometry.js @@ -1,10 +1,10 @@ -function SharedBufferGeometry (material, primitiveMode) { +function SharedBufferGeometry (material) { this.material = material; - this.primitiveMode = primitiveMode; this.maxBufferSize = 1000000; this.geometries = []; this.current = null; + this.strip = true; this.addBuffer(false); } @@ -48,6 +48,10 @@ SharedBufferGeometry.prototype = { }, undo: function (prevIdx) { + for (let i = prevIdx.position; i < this.idx.position; i++) { + this.current.attributes.position.setXYZ(i, 0, 0, 0); + this.current.index.setXYZ(i, 0, 0, 0); + } this.idx = prevIdx; this.update(); }, @@ -56,6 +60,7 @@ SharedBufferGeometry.prototype = { var geometry = new THREE.BufferGeometry(); var vertices = new Float32Array(this.maxBufferSize * 3); + var indices = new Uint32Array(this.maxBufferSize * 4.5); var normals = new Float32Array(this.maxBufferSize * 3); var uvs = new Float32Array(this.maxBufferSize * 2); var colors = new Float32Array(this.maxBufferSize * 3); @@ -78,9 +83,15 @@ SharedBufferGeometry.prototype = { geometry.setDrawRange(0, 0); geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3).setUsage(THREE.DynamicDrawUsage)); + geometry.attributes.position.updateRange.count = 0; + geometry.setIndex(new THREE.BufferAttribute(indices, 3).setUsage(THREE.DynamicDrawUsage)); + geometry.index.updateRange.count = 0; geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2).setUsage(THREE.DynamicDrawUsage)); + geometry.attributes.uv.updateRange.count = 0; geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3).setUsage(THREE.DynamicDrawUsage)); + geometry.attributes.normal.updateRange.count = 0; geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3).setUsage(THREE.DynamicDrawUsage)); + geometry.attributes.color.updateRange.count = 0; this.previous = null; @@ -136,6 +147,29 @@ SharedBufferGeometry.prototype = { buffer = this.current.attributes.position; } buffer.setXYZ(this.idx.position++, x, y, z); + if (this.strip) { + if ((this.idx.position + 1) % 2 == 0 && this.idx.position > 1) { + /* Line brushes + 2---3 + | \ | + 0---1 + {0, 1, 2}, {2, 1, 3} + */ + this.current.index.setXYZ(this.idx.position - 3, this.idx.position - 3, this.idx.position - 2, this.idx.position - 1); + this.current.index.setXYZ(this.idx.position - 2, this.idx.position - 1, this.idx.position - 2, this.idx.position); + } + } + else { + if ((this.idx.position + 1) % 3 == 0) { + /* Stamp brushes + 0---1 0 + \ | | \ + 2 3---2 + {0, 1, 2}, {2, 3, 0} + */ + this.current.index.setXYZ(this.idx.position, this.idx.position - 2, this.idx.position - 1, this.idx.position); + } + } }, addUV: function (u, v) { @@ -143,12 +177,20 @@ SharedBufferGeometry.prototype = { }, update: function () { - this.current.setDrawRange(0, this.idx.position); + // Draw one less triangle to prevent indexing into blank positions + // on an even-number-positioned undo + this.current.setDrawRange(0, (this.idx.position * 3) - 4); + this.current.attributes.color.updateRange.count = this.idx.position * 3; this.current.attributes.color.needsUpdate = true; + this.current.attributes.normal.updateRange.count = this.idx.position * 3; this.current.attributes.normal.needsUpdate = true; + this.current.attributes.position.updateRange.count = this.idx.position * 3; this.current.attributes.position.needsUpdate = true; + this.current.attributes.uv.updateRange.count = this.idx.position * 2; this.current.attributes.uv.needsUpdate = true; + this.current.index.updateRange.count = this.idx.position * 3; + this.current.index.needsUpdate = true; } }; diff --git a/src/sharedbuffergeometrymanager.js b/src/sharedbuffergeometrymanager.js index 2f8866195..4e5d26fcb 100644 --- a/src/sharedbuffergeometrymanager.js +++ b/src/sharedbuffergeometrymanager.js @@ -5,8 +5,8 @@ function SharedBufferGeometryManager () { } SharedBufferGeometryManager.prototype = { - addSharedBuffer: function (name, material, primitiveMode) { - var bufferGeometry = new SharedBufferGeometry(material, primitiveMode); + addSharedBuffer: function (name, material) { + var bufferGeometry = new SharedBufferGeometry(material); this.sharedBuffers[name] = bufferGeometry; }, diff --git a/src/systems/brush.js b/src/systems/brush.js index e39ba4cb0..b25df43fa 100644 --- a/src/systems/brush.js +++ b/src/systems/brush.js @@ -185,7 +185,6 @@ AFRAME.registerSystem('brush', { }, clear: function () { // Remove all the stroke entities - //for (var i = 0; i < this.strokes.length; i++) { for (var i = this.strokes.length - 1; i >= 0; i--) { if(this.strokes[i].data.owner !== 'local') continue; var stroke = this.strokes[i];