├── content-script.js
├── manifest.json
└── samples
├── vr-paint-1474965279604.json
├── vr-paint-1474966268338.json
├── vr-paint-1474966394385.json
└── vr-sculpt-1474965778952.json
/content-script.js:
--------------------------------------------------------------------------------
1 | function main () {
2 |
3 | if ( 'THREE' in window === false ) { console.log( 'VRREPLAY: THREE not found.' ); return; }
4 | if ( 'VRControls' in THREE === false ) { console.log( 'VRREPLAY: THREE.VRControls not found.' ); return; }
5 | if ( 'controls' in window === false ) { console.log( 'VRREPLAY: controls not found.' ); return; }
6 | // if ( 'getVRDisplay' in controls === false ) { console.log( 'VRREC: controls.getVRDisplay() not found.' ); return; }
7 | // if ( 'setVRDisplay' in controls === false ) { console.log( 'VRREC: controls.setVRDisplay() not found.' ); return; }
8 |
9 | if ( 'ViveController' in THREE ) {
10 |
11 | var controller1Available = 'controller1' in window && controller1 instanceof THREE.ViveController;
12 | var controller2Available = 'controller2' in window && controller2 instanceof THREE.ViveController;
13 |
14 | }
15 |
16 | //
17 |
18 | function parseGamepad( gamepad ) {
19 |
20 | if ( gamepad === null ) return null;
21 |
22 | var buttons = gamepad.buttons;
23 |
24 | return {
25 | axes: gamepad.axes,
26 | buttons: [
27 | { pressed: buttons[ 0 ].pressed, touched: buttons[ 0 ].touched, value: buttons[ 0 ].value },
28 | { pressed: buttons[ 1 ].pressed, touched: buttons[ 1 ].touched, value: buttons[ 1 ].value },
29 | { pressed: buttons[ 2 ].pressed, touched: buttons[ 2 ].touched, value: buttons[ 2 ].value },
30 | { pressed: buttons[ 3 ].pressed, touched: buttons[ 3 ].touched, value: buttons[ 3 ].value }
31 | ],
32 | pose: {
33 | position: Array.from( gamepad.pose.position ),
34 | orientation: Array.from( gamepad.pose.orientation )
35 | }
36 | };
37 |
38 | }
39 |
40 | function FakeGamepad() {
41 |
42 | return {
43 | axes: [ 0, 0 ],
44 | buttons: [
45 | { pressed: false, touched: false, value: 0 },
46 | { pressed: false, touched: false, value: 0 },
47 | { pressed: false, touched: false, value: 0 },
48 | { pressed: false, touched: false, value: 0 }
49 | ],
50 | id: "OpenVR Gamepad",
51 | pose: { position: null, orientation: null }
52 | }
53 |
54 | }
55 |
56 | var gamepads = { 0: new FakeGamepad(), 1: new FakeGamepad(), 2: null, 3: null };
57 |
58 | var fakeGetGamepads = function () { return gamepads };
59 | var realGetGamepads = navigator.getGamepads;
60 |
61 | //
62 |
63 | var frames = [];
64 | var currentFrame = 0;
65 |
66 | var isPlaying = false;
67 | var isRecording = false;
68 |
69 | function play() {
70 |
71 | if ( isPlaying === false || frames.length === 0 ) return;
72 |
73 | var frame = frames[ currentFrame ];
74 |
75 | camera.matrix.fromArray( frame[ 0 ] );
76 |
77 | if ( controller1Available ) controller1.standingMatrix.fromArray( frame[ 1 ] );
78 | if ( controller2Available ) controller2.standingMatrix.fromArray( frame[ 1 ] );
79 |
80 | if ( frame[ 2 ] ) Object.assign( navigator.getGamepads()[ 0 ], frame[ 2 ] );
81 | if ( frame[ 3 ] ) Object.assign( navigator.getGamepads()[ 1 ], frame[ 3 ] );
82 |
83 | updateFramesText();
84 |
85 | currentFrame ++;
86 |
87 | if ( currentFrame >= frames.length ) currentFrame = 0;
88 |
89 | requestAnimationFrame( play );
90 |
91 | }
92 |
93 | function record() {
94 |
95 | if ( isRecording === false ) return;
96 |
97 | frames.push( [
98 | camera.matrix.toArray(),
99 | controls.getStandingMatrix().toArray(),
100 | parseGamepad( navigator.getGamepads()[ 0 ] ),
101 | parseGamepad( navigator.getGamepads()[ 1 ] )
102 | ] );
103 |
104 | updateFramesText();
105 |
106 | requestAnimationFrame( record )
107 |
108 | }
109 |
110 | function updateFramesText() {
111 |
112 | framesText.textContent = currentFrame + '/' + frames.length;
113 |
114 | }
115 |
116 | //
117 |
118 | var panel = document.createElement( 'div' );
119 | panel.style.position = 'fixed';
120 | panel.style.top = '0px';
121 | panel.style.left = '0px';
122 | panel.style.padding = '8px';
123 | panel.style.color = 'black';
124 | panel.style.backgroundColor = 'white';
125 | panel.innerHTML = 'VR PLAYER - ';
126 | document.body.appendChild( panel );
127 |
128 | var framesText = document.createTextNode( '0/0' );
129 | panel.appendChild( framesText )
130 |
131 | var hr = document.createElement( 'hr' );
132 | hr.style.cssText = "border: 0px;height: 1px;background-color: #ddd;";
133 | panel.appendChild( hr );
134 |
135 | // LOAD
136 |
137 | var fileInput = document.createElement( 'input' );
138 | fileInput.type = 'file';
139 | fileInput.addEventListener( 'change', function ( event ) {
140 |
141 | var reader = new FileReader();
142 | reader.addEventListener( 'load', function ( event ) {
143 |
144 | var contents = event.target.result;
145 | frames = JSON.parse( contents );
146 |
147 | updateFramesText();
148 |
149 | }, false );
150 | reader.readAsText( fileInput.files[ 0 ] );
151 |
152 | } );
153 |
154 | var loadButton = document.createElement( 'button' );
155 | loadButton.textContent = 'LOAD';
156 | loadButton.addEventListener( 'click', function () {
157 |
158 | fileInput.click();
159 |
160 | } );
161 | panel.appendChild( loadButton );
162 |
163 | // SAVE
164 |
165 | var link = document.createElement( 'a' );
166 | link.style.display = 'none';
167 | document.body.appendChild( link ); // Firefox workaround, see #6594
168 |
169 | var saveButton = document.createElement( 'button' );
170 | saveButton.textContent = 'SAVE';
171 | saveButton.addEventListener( 'click', function () {
172 |
173 | var text = JSON.stringify( frames );
174 |
175 | var blob = new Blob( [ text ], { type: 'text/plain' } );
176 | link.href = URL.createObjectURL( blob );
177 | link.download = 'vr-' + Date.now() + '.json';
178 | link.click();
179 |
180 | } );
181 | panel.appendChild( saveButton );
182 |
183 | // CLEAR
184 |
185 | var clearButton = document.createElement( 'button' );
186 | clearButton.textContent = 'CLEAR';
187 | clearButton.addEventListener( 'click', function () {
188 |
189 | frames = [];
190 | currentFrame = 0;
191 | updateFramesText();
192 |
193 | } );
194 | panel.appendChild( clearButton );
195 |
196 | //
197 |
198 | var hr = document.createElement( 'hr' );
199 | hr.style.cssText = "border: 0px;height: 1px;background-color: #ddd;";
200 | panel.appendChild( hr );
201 |
202 | // PLAY
203 |
204 | var controlsUpdate = controls.update;
205 |
206 | var playButton = document.createElement( 'button' );
207 | playButton.textContent = 'PLAY';
208 | playButton.addEventListener( 'click', function () {
209 |
210 | if ( isPlaying === false ) {
211 |
212 | camera.matrixAutoUpdate = false;
213 |
214 | navigator.getGamepads = fakeGetGamepads;
215 | controls.update = function () {};
216 |
217 | playButton.textContent = 'STOP';
218 |
219 | isPlaying = true;
220 | requestAnimationFrame( play );
221 |
222 | } else {
223 |
224 | camera.matrixAutoUpdate = true;
225 |
226 | navigator.getGamepads = realGetGamepads;
227 | controls.update = controlsUpdate;
228 |
229 | playButton.textContent = 'PLAY';
230 |
231 | isPlaying = false;
232 |
233 | }
234 |
235 | } );
236 | panel.appendChild( playButton );
237 |
238 | // RECORD
239 |
240 | var recordButton = document.createElement( 'button' );
241 | recordButton.textContent = 'RECORD';
242 | recordButton.addEventListener( 'click', function () {
243 |
244 | if ( isRecording === false ) {
245 |
246 | recordButton.textContent = 'STOP';
247 |
248 | isRecording = true;
249 | requestAnimationFrame( record );
250 |
251 | } else {
252 |
253 | recordButton.textContent = 'RECORD';
254 |
255 | isRecording = false;
256 |
257 | }
258 |
259 | } );
260 | panel.appendChild( recordButton );
261 |
262 | }
263 |
264 | var script = document.createElement('script');
265 | script.appendChild(document.createTextNode('('+ main +')();'));
266 | (document.body || document.head || document.documentElement).appendChild(script);
267 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Three.js VR Player",
3 | "description": "",
4 | "version": "1.0",
5 | "content_scripts": [
6 | {
7 | "matches": [""],
8 | "all_frames": true,
9 | "js": ["content-script.js"]
10 | }
11 | ],
12 | "manifest_version": 2
13 | }
14 |
--------------------------------------------------------------------------------