-
Notifications
You must be signed in to change notification settings - Fork 200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Screenshot WIP for feedback #179
base: master
Are you sure you want to change the base?
Changes from 5 commits
d6ccae4
c22b2c0
1156832
b97f826
237333d
4d603b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,9 @@ AFRAME.registerComponent('brush', { | |
|
||
var self = this; | ||
|
||
this.el.addEventListener('trigger-mode-changed', this.triggerModeChanged.bind(this)); | ||
this.triggerModeChanged(); | ||
|
||
this.el.addEventListener('axismove', function (evt) { | ||
if (evt.detail.axis[0] === 0 && evt.detail.axis[1] === 0) { | ||
return; | ||
|
@@ -37,15 +40,15 @@ AFRAME.registerComponent('brush', { | |
}); | ||
|
||
this.el.addEventListener('buttondown', function (evt) { | ||
if (!self.data.enabled) { return; } | ||
if (!self.enabled) { return; } | ||
// Grip | ||
if (evt.detail.id === 2) { | ||
self.system.undo(); | ||
} | ||
}); | ||
|
||
this.el.addEventListener('buttonchanged', function (evt) { | ||
if (!self.data.enabled) { return; } | ||
if (!self.enabled) { return; } | ||
// Trigger | ||
if (evt.detail.id === 1) { | ||
var value = evt.detail.state.value; | ||
|
@@ -65,7 +68,14 @@ AFRAME.registerComponent('brush', { | |
} | ||
}); | ||
}, | ||
|
||
triggerModeChanged: function() { | ||
this.enabled = this.data.enabled && this.el.getAttribute('trigger-mode') == 'brush' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the proper way to do this to have another component that manages the trigger-mode attribute to data.enabled binding? To make this more reusable it would be nice if this didn't have to worry about the external trigger-mode attribute |
||
}, | ||
|
||
update: function (oldData) { | ||
this.triggerModeChanged(); | ||
|
||
var data = this.data; | ||
if (oldData.color !== data.color) { | ||
this.color.set(data.color); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* globals AFRAME THREE */ | ||
AFRAME.registerComponent('screenshot-camera', { | ||
schema: { | ||
width: {default: 1024, min: 1, max: 2048}, | ||
height: {default: 768, min: 1, max: 1516}, | ||
}, | ||
init: function () { | ||
var data = this.data; | ||
var width = data.width; | ||
var height = data.height; | ||
this.sceneEl = document.querySelector('a-scene'); | ||
this.scene = this.sceneEl.object3D | ||
|
||
this.renderTarget = new THREE.WebGLRenderTarget(width, height, { | ||
format: THREE.RGBAFormat, | ||
type: THREE.UnsignedByteType, | ||
}) | ||
|
||
var ratio = width / height; | ||
this.camera = new THREE.PerspectiveCamera(55, ratio, 0.01, 1000 ); | ||
this.camera.rotation.x = Math.PI / 2 | ||
this.camera.rotation.y = Math.PI | ||
this.camera.rotation.z = Math.PI | ||
this.screen = new THREE.Mesh( | ||
new THREE.PlaneBufferGeometry(ratio * 0.2, 0.2), | ||
new THREE.MeshBasicMaterial({ | ||
side: THREE.DoubleSide, | ||
map: this.renderTarget | ||
}) | ||
) | ||
this.screen.rotation.set(3 * Math.PI / 2, 0, 0) | ||
this.screen.position.set(0.2, 0, -0.2) | ||
this.el.object3D.add(this.screen) | ||
this.el.object3D.add(this.camera) | ||
|
||
this.el.addEventListener('trigger-mode-changed', this.triggerModeChanged.bind(this)) | ||
this.triggerModeChanged(); | ||
this.canTakePicture = true | ||
this.el.addEventListener('triggerchanged', function (evt) { | ||
if (!this.enabled) { | ||
return | ||
} | ||
|
||
if (evt.detail.value == 1 && this.canTakePicture) { | ||
this.saveNextTick = true | ||
this.canTakePicture = false | ||
} else if (evt.detail.value < 1) { | ||
this.canTakePicture = true | ||
} | ||
}.bind(this)); | ||
|
||
this.canvas = document.createElement('canvas') | ||
this.canvas.width = width | ||
this.canvas.height = height | ||
}, | ||
|
||
triggerModeChanged: function() { | ||
this.enabled = this.el.getAttribute('trigger-mode') == 'camera' | ||
this.screen.visible = this.enabled | ||
}, | ||
|
||
tick: function(time, timeDelta) { | ||
if (!this.enabled) return | ||
this.sceneEl.renderer.render(this.scene, this.camera, this.renderTarget, true) | ||
if (this.saveNextTick) { | ||
this.saveCapture(); | ||
this.saveNextTick = false; | ||
} | ||
}, | ||
|
||
saveCapture: function () { | ||
var width = this.data.width | ||
var height = this.data.height | ||
this.pixels = new Uint8Array(4 * width * height) | ||
var renderer = this.sceneEl.renderer | ||
|
||
var _gl = renderer.context | ||
var framebuffer = renderer.properties.get(this.renderTarget).__webglFramebuffer | ||
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); | ||
_gl.readPixels( 0, 0, width, height, _gl.RGBA,_gl.UNSIGNED_BYTE, this.pixels ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't get WebGLRenderer.readRenderTargetPixels to work here, unsure why as this looks like the same code. Is there a good way to debug Threejs while working on a-painter? |
||
this.pixels = this.flipPixelsVertically(this.pixels, width, height) | ||
|
||
this.imageData = new ImageData(new Uint8ClampedArray(this.pixels), width, height) | ||
this.canvas.getContext('2d').putImageData(this.imageData, 0, 0) | ||
this.canvas.toBlob(function (blob) { | ||
var url = URL.createObjectURL(blob); | ||
var fileName = 'screenshot-' + document.title + '-' + Date.now() + '.png'; | ||
var aEl = document.createElement('a'); | ||
aEl.href = url; | ||
aEl.setAttribute('download', fileName); | ||
aEl.innerHTML = 'downloading...'; | ||
aEl.style.display = 'none'; | ||
document.body.appendChild(aEl); | ||
setTimeout(function () { | ||
aEl.click(); | ||
document.body.removeChild(aEl); | ||
}, 1); | ||
}, 'image/png'); | ||
}, | ||
|
||
flipPixelsVertically: function (pixels, width, height) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This flipping seems to cause frame skipping. It actually kind of works because the white flash feels like taking a flash photograph, but it should probably be moved into a web worker or something. |
||
var flippedPixels = pixels.slice(0); | ||
for (var x = 0; x < width; ++x) { | ||
for (var y = 0; y < height; ++y) { | ||
flippedPixels[x * 4 + y * width * 4] = pixels[x * 4 + (height - y) * width * 4]; | ||
flippedPixels[x * 4 + 1 + y * width * 4] = pixels[x * 4 + 1 + (height - y) * width * 4]; | ||
flippedPixels[x * 4 + 2 + y * width * 4] = pixels[x * 4 + 2 + (height - y) * width * 4]; | ||
flippedPixels[x * 4 + 3 + y * width * 4] = pixels[x * 4 + 3 + (height - y) * width * 4]; | ||
} | ||
} | ||
return flippedPixels; | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
/* globals AFRAME THREE */ | ||
AFRAME.registerComponent('ui', { | ||
schema: { brightness: { default: 1.0, max: 1.0, min: 0.0 } }, | ||
dependencies: ['ui-raycaster'], | ||
dependencies: ['ui-raycaster', 'screenshot-camera', 'brush'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason brush wasn't a dependency before? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'brush' is a dependency of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think i misunderstood dependencies. Is And are you thinking |
||
|
||
init: function () { | ||
var el = this.el; | ||
|
@@ -156,6 +156,7 @@ AFRAME.registerComponent('ui', { | |
} | ||
case name === 'clear': { | ||
if (!this.pressedObjects[name]) { | ||
this.toggleCaptureCamera(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to get another button in the menu for this. If people like the change maybe @feiss can hook up a camera button. |
||
this.el.sceneEl.systems.brush.clear(); | ||
} | ||
break; | ||
|
@@ -355,6 +356,12 @@ AFRAME.registerComponent('ui', { | |
this.handEl.setAttribute('brush', 'size', brushSize); | ||
}, | ||
|
||
toggleCaptureCamera: function() { | ||
var enableCamera = this.handEl.getAttribute('trigger-mode') != 'camera' | ||
this.handEl.setAttribute('trigger-mode', enableCamera ? 'camera' : 'brush') | ||
this.handEl.emit('trigger-mode-changed') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a built-in way to listen for any attribute changes, or do i need to emit custom events each time i change? |
||
}, | ||
|
||
handleHover: function () { | ||
this.updateHoverObjects(); | ||
this.updateMaterials(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ require('./components/line.js'); | |
require('./components/look-controls-alt.js'); | ||
require('./components/orbit-controls.js'); | ||
require('./components/paint-controls.js'); | ||
require('./components/screenshot-camera.js'); | ||
require('./components/ui.js'); | ||
require('./components/ui-raycaster.js'); | ||
|
||
|
@@ -27,3 +28,9 @@ require('./brushes/stamp.js'); | |
require('./brushes/spheres.js'); | ||
require('./brushes/cubes.js'); | ||
require('./brushes/rainbow.js'); | ||
|
||
var f = function() { | ||
requestAnimationFrame(f) | ||
AFRAME.TWEEN.update() | ||
} | ||
requestAnimationFrame(f) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just to fix the chrome animation frame timing bug, will remove before committing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could develop on Firefox Nightly now and you don't need it and get better latency ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this should be called action-mode since it might support more than just the trigger button, IE using the grips for scaling instead of undo