├── .babelrc
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── README.md
├── demo
├── app.js
├── demo.gif
├── demo2.gif
├── index.html
├── style.styl
└── test1.jpg
├── dist
├── threejsTextureTool.js
└── threejsTextureTool.min.js
├── package.json
├── src
├── CanvasTexture.js
├── ImageTexture.js
├── index.js
└── style.styl
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "stage-0"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jeremboo/threejs-texture-tool/f5c4fd894812c3e16eb3c8faad0a8888e5c5bf33/.eslintignore
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "globals": {
4 | "app": true,
5 | "window": true,
6 | "document": true,
7 | "describe": true,
8 | "it": true
9 | },
10 | "parser": "babel-eslint",
11 | "rules": {
12 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### OSX ###
2 | .DS_Store
3 |
4 | # Thumbnails
5 | ._*
6 |
7 |
8 | # NPM
9 |
10 | node_modules/
11 | npm-debug.log
12 |
13 | demo/style.css
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## [ThreejsTextureTool 0.5.1](https://github.com/Jeremboo/threejs-texture-tool)
3 |
4 | A tool to preview and update your canvases or pictures used for your [three.js](https://threejs.org/) textures.
5 |
6 | [demo 0.2.6](http://codepen.io/Jeremboo/full/qqabKY/)
7 |
8 |
9 | ## Getting Started (es6)
10 |
11 | ### Create a texture with a dynamic canvas
12 |
13 | 
14 |
15 | ```javascript
16 | import { createCanvasTexture } from 'threejs-texture-tool';
17 |
18 | // Create a canvasTexture
19 | const canvasTexture = createCanvasTexture({
20 | name: 'myCanvas',
21 | onStart: (props) => {
22 | // Draw once a rectangle and add a mouse move Listener
23 | // To update this canvas
24 | const { width, height, context, canvas, update } = props;
25 | context.rect(0, 0, width, height);
26 | context.fillStyle = '#F6FF49';
27 | context.fill();
28 | canvas.onmousemove = e => {
29 | update(e.offsetX, e.offsetY);
30 | };
31 | },
32 | onUpdate: (x, y) => {
33 | // Called by `canvasTexture.udpate(...)`
34 | const { context } = canvasTexture;
35 | context.beginPath();
36 | context.arc(x, y, 10, 0, 2 * Math.PI, false);
37 | context.fillStyle = mainColor;
38 | context.fill();
39 | context.closePath();
40 | },
41 | });
42 |
43 | // Different accesses
44 | const { texture, material, uniform, canvas } = canvasTexture;
45 | ```
46 |
47 | ### Create a texture with a picture
48 |
49 | 
50 |
51 | ```javascript
52 | import { createImageTexture } from 'threejs-texture-tool';
53 |
54 | // Load the picture
55 | const imgTexture = createImageTexture('./test1.jpg', { name: 'test', onLoad: () => {
56 | // Manipulate params
57 | imgTexture.texture.wrapS =
58 | imgTexture.texture.wrapT =
59 | imgTexture.uniform.value.wrapS =
60 | imgTexture.uniform.value.wrapT =
61 | REPEAT_WRAPPING;
62 | } });
63 |
64 | // Different accesses
65 | const { texture, material, uniform, image } = canvasTexture;
66 | ```
67 | ## Get material / uniform and other transformations
68 |
69 | For the both textureTools, you can get her material and uniform object compatible with three.js
70 |
71 | ```javascript
72 |
73 | // Use it as material
74 | const mesh = THREE.Mesh(
75 | new BoxGeometry(1, 1, 1),
76 | imageOrCanvasTexture.material,
77 | );
78 |
79 | // Into shaderMaterial
80 | const shaderMaterial = new ShaderMaterial({
81 | uniforms: {
82 | imgMap: imageOrCanvasTexture.uniform,
83 | },
84 | vertexShader: shaderVert,
85 | fragmentShader: shaderFrag,
86 | side: DoubleSide,
87 | });
88 |
89 | // Get only the picture
90 | const img = document.createElement('img');
91 | img.src = imageTexture.image;
92 |
93 | // Get only the canvas
94 | const canvas = canvasTexture.canvas;
95 |
96 | ```
97 |
98 | ## TODO / NEXT STEP
99 |
100 | - remplace dragDrop dependencie from scratch
101 |
102 | - drag and move all openned textures anywhere in the view
103 |
104 | - reset each canvas texture with a button
105 |
106 | - functions to generate specific canvas textures :
107 | - noiseTexture
108 | - perlinNoiseTexture
109 | - gradientTexture
110 | - perlinGradientNoiseTexture
111 | - customTexture
112 | - fusionTexture / superposeTextures
113 |
--------------------------------------------------------------------------------
/demo/app.js:
--------------------------------------------------------------------------------
1 | import { Scene, WebGLRenderer, PerspectiveCamera, Object3D, BoxGeometry, MeshFaceMaterial, Mesh } from 'three';
2 | import { createCanvasTexture, createImageTexture } from '../src/index.js';
3 |
4 | import './style.styl';
5 |
6 |
7 | /**/ /* ---- CORE ---- */
8 | /**/ const mainColor = '#323031';
9 | /**/ const secondaryColor = '#DB3A34';
10 | /**/ const bgColor = '#FFC857';
11 | /**/ let windowWidth = window.innerWidth;
12 | /**/ let windowHeight = window.innerHeight;
13 | /**/ class Webgl {
14 | /**/ constructor(w, h) {
15 | /**/ this.meshCount = 0;
16 | /**/ this.meshListeners = [];
17 | /**/ this.renderer = new WebGLRenderer({ antialias: true, alpha: true });
18 | /**/ this.renderer.setPixelRatio(window.devicePixelRatio);
19 | /**/ // this.renderer.setClearColor(new Color(bgColor)));
20 | /**/ this.scene = new Scene();
21 | /**/ this.camera = new PerspectiveCamera(50, w / h, 1, 1000);
22 | /**/ this.camera.position.set(0, 0, 10);
23 | /**/ this.dom = this.renderer.domElement;
24 | /**/ this.update = this.update.bind(this);
25 | /**/ this.resize = this.resize.bind(this);
26 | /**/ this.resize(w, h); // set render size
27 | /**/ }
28 | /**/ add(mesh) {
29 | /**/ this.scene.add(mesh);
30 | /**/ if (!mesh.update) return;
31 | /**/ this.meshListeners.push(mesh.update);
32 | /**/ this.meshCount++;
33 | /**/ }
34 | /**/ update() {
35 | /**/ let i = this.meshCount;
36 | /**/ while (--i >= 0) {
37 | /**/ this.meshListeners[i].apply(this, null);
38 | /**/ }
39 | /**/ this.renderer.render(this.scene, this.camera);
40 | /**/ }
41 | /**/ resize(w, h) {
42 | /**/ this.camera.aspect = w / h;
43 | /**/ this.camera.updateProjectionMatrix();
44 | /**/ this.renderer.setSize(w, h);
45 | /**/ }
46 | /**/ }
47 | /**/ const webgl = new Webgl(windowWidth, windowHeight);
48 | /**/ document.body.appendChild(webgl.dom);
49 | /**/
50 | /**/
51 | /* ---- CREATING ZONE ---- */
52 |
53 | const CUBE_SIZE = 3;
54 |
55 | // OBJECTS
56 | class Block extends Object3D {
57 | constructor() {
58 | super();
59 |
60 | this.materials = [];
61 |
62 | let i;
63 | for (i = 0; i < 4; i++) {
64 | const canvasTexture = createCanvasTexture({
65 | name: 'canvas',
66 | onStart: (canvasTextureProps) => {
67 | const { width, height, context, canvas, update } = canvasTextureProps;
68 | context.rect(0, 0, width, height);
69 | context.fillStyle = bgColor;
70 | context.fill();
71 | // http://codepen.io/jbpenrath/pen/gLObej
72 | let mouseDown = false;
73 | const paint = e => {
74 | // call the method `onUpdate` defined bellow
75 | if (mouseDown) update(e.offsetX, e.offsetY);
76 | };
77 | canvas.onmousedown = e => {
78 | mouseDown = true;
79 | paint(e);
80 | };
81 | canvas.onmouseup = () => {
82 | mouseDown = false;
83 | };
84 | canvas.onmousemove = paint;
85 | },
86 | // custom attributes
87 | onUpdate: (x, y) => {
88 | const { context } = canvasTexture;
89 | context.beginPath();
90 | context.arc(x, y, 10, 0, 2 * Math.PI, false);
91 | context.fillStyle = mainColor;
92 | context.fill();
93 | context.closePath();
94 | },
95 | });
96 | this.materials.push(canvasTexture.material);
97 | }
98 |
99 | // Add imageTexture
100 | this.materials.push(createImageTexture('./test1.jpg').material);
101 | this.materials.push(createImageTexture('./test1.jpg').material);
102 |
103 | this.geometry = new BoxGeometry(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE, 20, 20);
104 | this.material = new MeshFaceMaterial(this.materials);
105 | this.mesh = new Mesh(this.geometry, this.material);
106 | this.mesh.rotation.set(1.52, 0, 0);
107 | this.add(this.mesh);
108 |
109 | this.rotation.set(0.25, 0.7, 0);
110 | this.update = this.update.bind(this);
111 | }
112 |
113 | update() {
114 | this.mesh.rotation.x += 0.01;
115 | this.mesh.rotation.y += 0.01;
116 | }
117 | }
118 |
119 |
120 | // ADDS
121 | webgl.add(new Block());
122 |
123 |
124 | /* ---- CREATING ZONE END ---- */
125 | /**/ /* ---- ON RESIZE ---- */
126 | /**/ function onResize() {
127 | /**/ windowWidth = window.innerWidth;
128 | /**/ windowHeight = window.innerHeight;
129 | /**/ webgl.resize(windowWidth, windowHeight);
130 | /**/ }
131 | /**/ window.addEventListener('resize', onResize);
132 | /**/ window.addEventListener('orientationchange', onResize);
133 | /**/ /* ---- LOOP ---- */
134 | /**/ function _loop() {
135 | /**/ webgl.update();
136 | /**/ requestAnimationFrame(_loop);
137 | /**/ }
138 | /**/ _loop();
139 |
--------------------------------------------------------------------------------
/demo/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jeremboo/threejs-texture-tool/f5c4fd894812c3e16eb3c8faad0a8888e5c5bf33/demo/demo.gif
--------------------------------------------------------------------------------
/demo/demo2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jeremboo/threejs-texture-tool/f5c4fd894812c3e16eb3c8faad0a8888e5c5bf33/demo/demo2.gif
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Threejs Texture Tool
6 |
7 |
8 |
9 | @Jeremboo
10 |
┗|`O´|┛
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/demo/style.styl:
--------------------------------------------------------------------------------
1 | // INIT
2 | mainColor = #084C61
3 | secondaryColor = #FFC857
4 | bgColor = #177E89
5 | bgColorDarken = darken(bgColor, 5);
6 |
7 | body, html
8 | width: 100%;
9 | height: 100%;
10 | overflow: hidden
11 | background: bgColor
12 | background: linear-gradient(to bottom, bgColor 70%, bgColorDarken 100%);
13 | margin: 0
14 | font-family: Century Gothic,CenturyGothic,AppleGothic,sans-serif
15 |
16 | .f
17 | position: fixed
18 | bottom: 5px
19 | right: 15px
20 | font-family: 'Arial'
21 | font-size: 0.7rem
22 | color: mainColor
23 | text-align: center;
24 |
25 | a
26 | font-size: 0.8rem
27 | color: secondaryColor
28 |
--------------------------------------------------------------------------------
/demo/test1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jeremboo/threejs-texture-tool/f5c4fd894812c3e16eb3c8faad0a8888e5c5bf33/demo/test1.jpg
--------------------------------------------------------------------------------
/dist/threejsTextureTool.js:
--------------------------------------------------------------------------------
1 | (function webpackUniversalModuleDefinition(root, factory) {
2 | if(typeof exports === 'object' && typeof module === 'object')
3 | module.exports = factory(require("three"));
4 | else if(typeof define === 'function' && define.amd)
5 | define("threejsTextureTool", ["three"], factory);
6 | else if(typeof exports === 'object')
7 | exports["threejsTextureTool"] = factory(require("three"));
8 | else
9 | root["threejsTextureTool"] = factory(root["three"]);
10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
11 | return /******/ (function(modules) { // webpackBootstrap
12 | /******/ // The module cache
13 | /******/ var installedModules = {};
14 |
15 | /******/ // The require function
16 | /******/ function __webpack_require__(moduleId) {
17 |
18 | /******/ // Check if module is in cache
19 | /******/ if(installedModules[moduleId])
20 | /******/ return installedModules[moduleId].exports;
21 |
22 | /******/ // Create a new module (and put it into the cache)
23 | /******/ var module = installedModules[moduleId] = {
24 | /******/ exports: {},
25 | /******/ id: moduleId,
26 | /******/ loaded: false
27 | /******/ };
28 |
29 | /******/ // Execute the module function
30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31 |
32 | /******/ // Flag the module as loaded
33 | /******/ module.loaded = true;
34 |
35 | /******/ // Return the exports of the module
36 | /******/ return module.exports;
37 | /******/ }
38 |
39 |
40 | /******/ // expose the modules object (__webpack_modules__)
41 | /******/ __webpack_require__.m = modules;
42 |
43 | /******/ // expose the module cache
44 | /******/ __webpack_require__.c = installedModules;
45 |
46 | /******/ // __webpack_public_path__
47 | /******/ __webpack_require__.p = "";
48 |
49 | /******/ // Load entry module and return exports
50 | /******/ return __webpack_require__(0);
51 | /******/ })
52 | /************************************************************************/
53 | /******/ ([
54 | /* 0 */
55 | /***/ function(module, exports, __webpack_require__) {
56 |
57 | 'use strict';
58 |
59 | Object.defineProperty(exports, "__esModule", {
60 | value: true
61 | });
62 | exports.createCanvasTexture = exports.createImageTexture = undefined;
63 |
64 | var _dragDrop = __webpack_require__(6);
65 |
66 | var _dragDrop2 = _interopRequireDefault(_dragDrop);
67 |
68 | var _CanvasTexture = __webpack_require__(2);
69 |
70 | var _CanvasTexture2 = _interopRequireDefault(_CanvasTexture);
71 |
72 | var _ImageTexture = __webpack_require__(3);
73 |
74 | var _ImageTexture2 = _interopRequireDefault(_ImageTexture);
75 |
76 | var _style = __webpack_require__(11);
77 |
78 | var _style2 = _interopRequireDefault(_style);
79 |
80 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
81 |
82 | /**
83 | * #########################
84 | * INIT
85 | * #########################
86 | */
87 |
88 | var textureNameArr = [];
89 |
90 | // Init canvas wrapper into the dom
91 | var textureToolWrapper = document.createElement('ul');
92 | textureToolWrapper.id = 'texture-tool-wrapper';
93 | textureToolWrapper.className = 'ThreejsTextureTool-wrapper';
94 | document.body.appendChild(textureToolWrapper);
95 |
96 | // Add css without style-loader
97 | var style = document.createElement('style');
98 | style.innerHTML = _style2.default.toString();
99 | textureToolWrapper.appendChild(style);
100 |
101 | // Listener on keycode to toggle textureToolWrapper when h pressed
102 | document.body.addEventListener('keydown', function (e) {
103 | if (e.keyCode === 72) {
104 | textureToolWrapper.classList.toggle('ThreejsTextureTool_hidden');
105 | }
106 | });
107 |
108 | /**
109 | * #########################
110 | * FUNCTION
111 | * #########################
112 | */
113 |
114 | /**
115 | * Add a texture viewer in DOM
116 | * @params {String} name
117 | * @params {Object} texture
118 | */
119 | function addInDom(name, texture) {
120 | // HTML
121 | var HTML = '\n \n \n \n \n
\n \n ';
122 | textureToolWrapper.insertAdjacentHTML('beforeend', HTML);
123 |
124 | // ACTIONS
125 | var textureWindow = document.getElementById(name + '-window');
126 | var openBtn = document.getElementById(name + '-open');
127 | openBtn.addEventListener('click', function () {
128 | openBtn.classList.add('TextureTool-hidden');
129 | textureWindow.classList.remove('TextureTool-hidden');
130 | });
131 | var closeBtn = document.getElementById(name + '-close');
132 | closeBtn.addEventListener('click', function () {
133 | openBtn.classList.remove('TextureTool-hidden');
134 | textureWindow.classList.add('TextureTool-hidden');
135 | });
136 | textureWindow.appendChild(texture);
137 | return textureWindow;
138 | }
139 |
140 | /**
141 | * Add a texture name into the array
142 | * @params {String} name
143 | */
144 | function saveTextureName(name) {
145 | var getUniqueName = function getUniqueName(currentName) {
146 | var i = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
147 |
148 | var n = '' + currentName + (i !== 0 ? '-' + i : '');
149 | return textureNameArr.indexOf(n) !== -1 ? getUniqueName(currentName, i + 1) : n;
150 | };
151 | var uniqueName = getUniqueName(name);
152 | textureNameArr.push(uniqueName);
153 | return uniqueName;
154 | }
155 |
156 | /**
157 | * #########################
158 | * EXPORT
159 | * #########################
160 | */
161 |
162 | /**
163 | * Create an texture based on an image
164 | * @params {String} url of the image
165 | * @params {Object} props with :
166 | * - @params {String} name id attribued at the texture
167 | * - @params {Function} onLoad a callback to handle the children
168 | */
169 | var createImageTexture = exports.createImageTexture = function createImageTexture(url) {
170 | var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
171 | _ref$name = _ref.name,
172 | name = _ref$name === undefined ? 'imageTexture' : _ref$name,
173 | _ref$onLoad = _ref.onLoad,
174 | onLoad = _ref$onLoad === undefined ? function (f) {
175 | return f;
176 | } : _ref$onLoad;
177 |
178 | var imgTexture = new _ImageTexture2.default(url, function () {
179 | var elm = addInDom(saveTextureName(name), imgTexture.image);
180 |
181 | // Drag Drop Event
182 | (0, _dragDrop2.default)('#' + elm.id, function (files) {
183 | // Read image from file data
184 | var reader = new FileReader();
185 | reader.addEventListener('load', function (e) {
186 | var bytes = new Uint8Array(e.target.result);
187 | var blob = new Blob([bytes.buffer]);
188 | var URL = window.URL || window.webkitURL;
189 | // remove the old img and update the image
190 | elm.removeChild(imgTexture.image);
191 | // Update the image with a new path
192 | imgTexture.updateImg(URL.createObjectURL(blob), function () {
193 | elm.appendChild(imgTexture.image);
194 | onLoad(imgTexture);
195 | });
196 | });
197 | reader.addEventListener('error', function (err) {
198 | // TODO create true error
199 | console.error('FileReader error' + err);
200 | });
201 |
202 | if (['image/png', 'image/jpg', 'image/jpeg'].indexOf(files[0].type) === -1) {
203 | console.log('FileUpdate error: The file is not at the good format');
204 | return;
205 | }
206 | reader.readAsArrayBuffer(files[0]);
207 | });
208 |
209 | onLoad(imgTexture);
210 | });
211 | return imgTexture;
212 | };
213 |
214 | /**
215 | * Create an texture based on a canvas
216 | * @params {Object} props with :
217 | * - @params {String} name
218 | * - @params {Number} width
219 | * - @params {Number} height
220 | * - @params {Function} onStart The drawing canvas function
221 | * - @params {Function} onUpdate Method called to update the canvas
222 | */
223 | var createCanvasTexture = exports.createCanvasTexture = function createCanvasTexture() {
224 | var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
225 | _ref2$name = _ref2.name,
226 | name = _ref2$name === undefined ? 'canvasTexture' : _ref2$name,
227 | _ref2$width = _ref2.width,
228 | width = _ref2$width === undefined ? 256 : _ref2$width,
229 | _ref2$height = _ref2.height,
230 | height = _ref2$height === undefined ? 256 : _ref2$height,
231 | _ref2$onStart = _ref2.onStart,
232 | onStart = _ref2$onStart === undefined ? function (f) {
233 | return f;
234 | } : _ref2$onStart,
235 | _ref2$onUpdate = _ref2.onUpdate,
236 | onUpdate = _ref2$onUpdate === undefined ? function (f) {
237 | return f;
238 | } : _ref2$onUpdate;
239 |
240 | var canvasTexture = new _CanvasTexture2.default({ width: width, height: height, onStart: onStart, onUpdate: onUpdate });
241 | addInDom(saveTextureName(name), canvasTexture.canvas);
242 | return canvasTexture;
243 | };
244 |
245 | /***/ },
246 | /* 1 */
247 | /***/ function(module, exports) {
248 |
249 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
250 |
251 | /***/ },
252 | /* 2 */
253 | /***/ function(module, exports, __webpack_require__) {
254 |
255 | 'use strict';
256 |
257 | Object.defineProperty(exports, "__esModule", {
258 | value: true
259 | });
260 | exports.default = CanvasTexture;
261 |
262 | var _three = __webpack_require__(1);
263 |
264 | function CanvasTexture(_ref) {
265 | var _this = this;
266 |
267 | var _ref$width = _ref.width,
268 | width = _ref$width === undefined ? 256 : _ref$width,
269 | _ref$height = _ref.height,
270 | height = _ref$height === undefined ? 256 : _ref$height,
271 | _ref$onStart = _ref.onStart,
272 | onStart = _ref$onStart === undefined ? function (f) {
273 | return f;
274 | } : _ref$onStart,
275 | _ref$onUpdate = _ref.onUpdate,
276 | onUpdate = _ref$onUpdate === undefined ? function (f) {
277 | return f;
278 | } : _ref$onUpdate;
279 |
280 | this.width = width;
281 | this.height = height;
282 |
283 | this.canvas = document.createElement('canvas');
284 | this.canvas.width = width;
285 | this.canvas.height = height;
286 |
287 | this.context = this.canvas.getContext('2d');
288 |
289 | this.texture = new _three.Texture(this.canvas);
290 | this.texture.needsUpdate = true;
291 |
292 | this.material = new _three.MeshBasicMaterial({
293 | map: this.texture,
294 | overdraw: true
295 | });
296 |
297 | this.uniform = { type: 't', value: this.texture };
298 |
299 | this.update = function () {
300 | onUpdate.apply(undefined, arguments);
301 | _this.texture.needsUpdate = true;
302 | };
303 |
304 | onStart(this);
305 | }
306 |
307 | /***/ },
308 | /* 3 */
309 | /***/ function(module, exports, __webpack_require__) {
310 |
311 | 'use strict';
312 |
313 | Object.defineProperty(exports, "__esModule", {
314 | value: true
315 | });
316 |
317 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
318 |
319 | var _three = __webpack_require__(1);
320 |
321 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
322 |
323 | var ImageTexture = function () {
324 | function ImageTexture(url, callback) {
325 | var _this = this;
326 |
327 | _classCallCheck(this, ImageTexture);
328 |
329 | this.image = null;
330 | this.material = new _three.MeshBasicMaterial({
331 | overdraw: true
332 | });
333 |
334 | this.texture = new _three.TextureLoader().load(url, function (texture) {
335 | _this.image = texture.image;
336 | _this.material.needsUpdate = true;
337 | _this.material.map = _this.texture;
338 | callback(_this);
339 | }, function (xhr) {
340 | console.log(xhr.loaded / xhr.total * 100 + '% loaded');
341 | }, function (xhr) {
342 | console.log('An error happened', xhr);
343 | });
344 |
345 | this.uniform = { type: 't', value: this.texture };
346 | }
347 |
348 | _createClass(ImageTexture, [{
349 | key: 'updateImg',
350 | value: function updateImg(newPath, callback) {
351 | var _this2 = this;
352 |
353 | this.texture = new _three.TextureLoader().load(newPath, function (texture) {
354 | _this2.image = texture.image;
355 | _this2.material.needsUpdate = true;
356 | _this2.material.map = _this2.texture;
357 | _this2.uniform.value = _this2.texture;
358 | callback(_this2);
359 | }, function (xhr) {
360 | console.log(xhr.loaded / xhr.total * 100 + '% loaded');
361 | }, function (xhr) {
362 | console.log('An error happened', xhr);
363 | });
364 | }
365 | }]);
366 |
367 | return ImageTexture;
368 | }();
369 |
370 | exports.default = ImageTexture;
371 |
372 | /***/ },
373 | /* 4 */
374 | /***/ function(module, exports, __webpack_require__) {
375 |
376 | exports = module.exports = __webpack_require__(5)();
377 | // imports
378 |
379 |
380 | // module
381 | exports.push([module.id, ".ThreejsTextureTool-wrapper{position:fixed;top:5vh;bottom:5vh;left:0;max-height:90vh;margin:0;padding:8px;overflow-x:none;overflow-y:auto;list-style:none;font-family:Century Gothic,CenturyGothic,AppleGothic,sans-serif}.ThreejsTextureTool_hidden{display:none}.TextureTool{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;margin-top:8px}.TextureTool-hidden{display:none}.TextureTool-canvas{position:absolute}.TextureTool-window{position:relative;pointer-events:auto;background-color:rgba(0,0,0,.5);-webkit-transition:.2s;transition:.2s}.TextureTool-window:hover{background-color:#000}.TextureTool-window img{max-width:200px;width:100%}.TextureTool-window canvas{cursor:pointer}.TextureTool-window.drag:after{content:'+';display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:absolute;width:100%;height:100%;top:0;left:0;z-index:1;background-color:rgba(0,0,0,.5);color:#fff;font-size:3em}.TextureTool-button,.TextureTool-close{white-space:nowrap;text-overflow:ellipsis;border:none;font:inherit;line-height:normal;outline:none}.TextureTool-button{max-width:150px;padding:6px 16px;border-radius:2px;background-color:#084c61;color:#fff;overflow:hidden;font-size:.8em;-webkit-transition:.2s;transition:.2s;cursor:pointer;-webkit-transform:translateX(0);transform:translateX(0)}.TextureTool-button:hover{max-width:999px;background-color:#000;padding:6px 32px}.TextureTool-close{position:absolute;width:20px;height:20px;top:5px;left:5px;background-color:#084c61;color:#fff;border-radius:2px;-webkit-transition:.4s;transition:.4s}.TextureTool-close:after{content:'x';position:absolute;top:46%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.TextureTool-close:hover{width:22px;height:22px;top:4px;right:4px;cursor:pointer;padding:4px 8px;background-color:#000}", ""]);
382 |
383 | // exports
384 |
385 |
386 | /***/ },
387 | /* 5 */
388 | /***/ function(module, exports) {
389 |
390 | /*
391 | MIT License http://www.opensource.org/licenses/mit-license.php
392 | Author Tobias Koppers @sokra
393 | */
394 | // css base code, injected by the css-loader
395 | module.exports = function() {
396 | var list = [];
397 |
398 | // return the list of modules as css string
399 | list.toString = function toString() {
400 | var result = [];
401 | for(var i = 0; i < this.length; i++) {
402 | var item = this[i];
403 | if(item[2]) {
404 | result.push("@media " + item[2] + "{" + item[1] + "}");
405 | } else {
406 | result.push(item[1]);
407 | }
408 | }
409 | return result.join("");
410 | };
411 |
412 | // import a list of modules into the list
413 | list.i = function(modules, mediaQuery) {
414 | if(typeof modules === "string")
415 | modules = [[null, modules, ""]];
416 | var alreadyImportedModules = {};
417 | for(var i = 0; i < this.length; i++) {
418 | var id = this[i][0];
419 | if(typeof id === "number")
420 | alreadyImportedModules[id] = true;
421 | }
422 | for(i = 0; i < modules.length; i++) {
423 | var item = modules[i];
424 | // skip already imported module
425 | // this implementation is not 100% perfect for weird media query combinations
426 | // when a module is imported multiple times with different media queries.
427 | // I hope this will never occur (Hey this way we have smaller bundles)
428 | if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
429 | if(mediaQuery && !item[2]) {
430 | item[2] = mediaQuery;
431 | } else if(mediaQuery) {
432 | item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
433 | }
434 | list.push(item);
435 | }
436 | }
437 | };
438 | return list;
439 | };
440 |
441 |
442 | /***/ },
443 | /* 6 */
444 | /***/ function(module, exports, __webpack_require__) {
445 |
446 | module.exports = dragDrop
447 |
448 | var flatten = __webpack_require__(7)
449 | var parallel = __webpack_require__(9)
450 |
451 | function dragDrop (elem, listeners) {
452 | if (typeof elem === 'string') {
453 | var selector = elem
454 | elem = window.document.querySelector(elem)
455 | if (!elem) {
456 | throw new Error('"' + selector + '" does not match any HTML elements')
457 | }
458 | }
459 |
460 | if (!elem) {
461 | throw new Error('"' + elem + '" is not a valid HTML element')
462 | }
463 |
464 | if (typeof listeners === 'function') {
465 | listeners = { onDrop: listeners }
466 | }
467 |
468 | var timeout
469 |
470 | elem.addEventListener('dragenter', onDragEnter, false)
471 | elem.addEventListener('dragover', onDragOver, false)
472 | elem.addEventListener('dragleave', onDragLeave, false)
473 | elem.addEventListener('drop', onDrop, false)
474 |
475 | // Function to remove drag-drop listeners
476 | return function remove () {
477 | removeDragClass()
478 | elem.removeEventListener('dragenter', onDragEnter, false)
479 | elem.removeEventListener('dragover', onDragOver, false)
480 | elem.removeEventListener('dragleave', onDragLeave, false)
481 | elem.removeEventListener('drop', onDrop, false)
482 | }
483 |
484 | function onDragEnter (e) {
485 | if (listeners.onDragEnter) {
486 | listeners.onDragEnter(e)
487 | }
488 |
489 | // Prevent event
490 | e.stopPropagation()
491 | e.preventDefault()
492 | return false
493 | }
494 |
495 | function onDragOver (e) {
496 | e.stopPropagation()
497 | e.preventDefault()
498 | if (e.dataTransfer.items) {
499 | // Only add "drag" class when `items` contains items that are able to be
500 | // handled by the registered listeners (files vs. text)
501 | var items = toArray(e.dataTransfer.items)
502 | var fileItems = items.filter(function (item) { return item.kind === 'file' })
503 | var textItems = items.filter(function (item) { return item.kind === 'string' })
504 |
505 | if (fileItems.length === 0 && !listeners.onDropText) return
506 | if (textItems.length === 0 && !listeners.onDrop) return
507 | if (fileItems.length === 0 && textItems.length === 0) return
508 | }
509 |
510 | elem.classList.add('drag')
511 | clearTimeout(timeout)
512 |
513 | if (listeners.onDragOver) {
514 | listeners.onDragOver(e)
515 | }
516 |
517 | e.dataTransfer.dropEffect = 'copy'
518 | return false
519 | }
520 |
521 | function onDragLeave (e) {
522 | e.stopPropagation()
523 | e.preventDefault()
524 |
525 | if (listeners.onDragLeave) {
526 | listeners.onDragLeave(e)
527 | }
528 |
529 | clearTimeout(timeout)
530 | timeout = setTimeout(removeDragClass, 50)
531 |
532 | return false
533 | }
534 |
535 | function onDrop (e) {
536 | e.stopPropagation()
537 | e.preventDefault()
538 |
539 | if (listeners.onDragLeave) {
540 | listeners.onDragLeave(e)
541 | }
542 |
543 | clearTimeout(timeout)
544 | removeDragClass()
545 |
546 | var pos = {
547 | x: e.clientX,
548 | y: e.clientY
549 | }
550 |
551 | // text drop support
552 | var text = e.dataTransfer.getData('text')
553 | if (text && listeners.onDropText) {
554 | listeners.onDropText(text, pos)
555 | }
556 |
557 | // file drop support
558 | if (e.dataTransfer.items) {
559 | // Handle directories in Chrome using the proprietary FileSystem API
560 | var items = toArray(e.dataTransfer.items).filter(function (item) {
561 | return item.kind === 'file'
562 | })
563 |
564 | if (items.length === 0) return
565 |
566 | parallel(items.map(function (item) {
567 | return function (cb) {
568 | processEntry(item.webkitGetAsEntry(), cb)
569 | }
570 | }), function (err, results) {
571 | // This catches permission errors with file:// in Chrome. This should never
572 | // throw in production code, so the user does not need to use try-catch.
573 | if (err) throw err
574 | if (listeners.onDrop) {
575 | listeners.onDrop(flatten(results), pos)
576 | }
577 | })
578 | } else {
579 | var files = toArray(e.dataTransfer.files)
580 |
581 | if (files.length === 0) return
582 |
583 | files.forEach(function (file) {
584 | file.fullPath = '/' + file.name
585 | })
586 |
587 | if (listeners.onDrop) {
588 | listeners.onDrop(files, pos)
589 | }
590 | }
591 |
592 | return false
593 | }
594 |
595 | function removeDragClass () {
596 | elem.classList.remove('drag')
597 | }
598 | }
599 |
600 | function processEntry (entry, cb) {
601 | var entries = []
602 |
603 | if (entry.isFile) {
604 | entry.file(function (file) {
605 | file.fullPath = entry.fullPath // preserve pathing for consumer
606 | cb(null, file)
607 | }, function (err) {
608 | cb(err)
609 | })
610 | } else if (entry.isDirectory) {
611 | var reader = entry.createReader()
612 | readEntries()
613 | }
614 |
615 | function readEntries () {
616 | reader.readEntries(function (entries_) {
617 | if (entries_.length > 0) {
618 | entries = entries.concat(toArray(entries_))
619 | readEntries() // continue reading entries until `readEntries` returns no more
620 | } else {
621 | doneEntries()
622 | }
623 | })
624 | }
625 |
626 | function doneEntries () {
627 | parallel(entries.map(function (entry) {
628 | return function (cb) {
629 | processEntry(entry, cb)
630 | }
631 | }), cb)
632 | }
633 | }
634 |
635 | function toArray (list) {
636 | return Array.prototype.slice.call(list || [], 0)
637 | }
638 |
639 |
640 | /***/ },
641 | /* 7 */
642 | /***/ function(module, exports) {
643 |
644 | module.exports = function flatten(list, depth) {
645 | depth = (typeof depth == 'number') ? depth : Infinity;
646 |
647 | if (!depth) {
648 | if (Array.isArray(list)) {
649 | return list.map(function(i) { return i; });
650 | }
651 | return list;
652 | }
653 |
654 | return _flatten(list, 1);
655 |
656 | function _flatten(list, d) {
657 | return list.reduce(function (acc, item) {
658 | if (Array.isArray(item) && d < depth) {
659 | return acc.concat(_flatten(item, d + 1));
660 | }
661 | else {
662 | return acc.concat(item);
663 | }
664 | }, []);
665 | }
666 | };
667 |
668 |
669 | /***/ },
670 | /* 8 */
671 | /***/ function(module, exports) {
672 |
673 | // shim for using process in browser
674 | var process = module.exports = {};
675 |
676 | // cached from whatever global is present so that test runners that stub it
677 | // don't break things. But we need to wrap it in a try catch in case it is
678 | // wrapped in strict mode code which doesn't define any globals. It's inside a
679 | // function because try/catches deoptimize in certain engines.
680 |
681 | var cachedSetTimeout;
682 | var cachedClearTimeout;
683 |
684 | function defaultSetTimout() {
685 | throw new Error('setTimeout has not been defined');
686 | }
687 | function defaultClearTimeout () {
688 | throw new Error('clearTimeout has not been defined');
689 | }
690 | (function () {
691 | try {
692 | if (typeof setTimeout === 'function') {
693 | cachedSetTimeout = setTimeout;
694 | } else {
695 | cachedSetTimeout = defaultSetTimout;
696 | }
697 | } catch (e) {
698 | cachedSetTimeout = defaultSetTimout;
699 | }
700 | try {
701 | if (typeof clearTimeout === 'function') {
702 | cachedClearTimeout = clearTimeout;
703 | } else {
704 | cachedClearTimeout = defaultClearTimeout;
705 | }
706 | } catch (e) {
707 | cachedClearTimeout = defaultClearTimeout;
708 | }
709 | } ())
710 | function runTimeout(fun) {
711 | if (cachedSetTimeout === setTimeout) {
712 | //normal enviroments in sane situations
713 | return setTimeout(fun, 0);
714 | }
715 | // if setTimeout wasn't available but was latter defined
716 | if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
717 | cachedSetTimeout = setTimeout;
718 | return setTimeout(fun, 0);
719 | }
720 | try {
721 | // when when somebody has screwed with setTimeout but no I.E. maddness
722 | return cachedSetTimeout(fun, 0);
723 | } catch(e){
724 | try {
725 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
726 | return cachedSetTimeout.call(null, fun, 0);
727 | } catch(e){
728 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
729 | return cachedSetTimeout.call(this, fun, 0);
730 | }
731 | }
732 |
733 |
734 | }
735 | function runClearTimeout(marker) {
736 | if (cachedClearTimeout === clearTimeout) {
737 | //normal enviroments in sane situations
738 | return clearTimeout(marker);
739 | }
740 | // if clearTimeout wasn't available but was latter defined
741 | if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
742 | cachedClearTimeout = clearTimeout;
743 | return clearTimeout(marker);
744 | }
745 | try {
746 | // when when somebody has screwed with setTimeout but no I.E. maddness
747 | return cachedClearTimeout(marker);
748 | } catch (e){
749 | try {
750 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
751 | return cachedClearTimeout.call(null, marker);
752 | } catch (e){
753 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
754 | // Some versions of I.E. have different rules for clearTimeout vs setTimeout
755 | return cachedClearTimeout.call(this, marker);
756 | }
757 | }
758 |
759 |
760 |
761 | }
762 | var queue = [];
763 | var draining = false;
764 | var currentQueue;
765 | var queueIndex = -1;
766 |
767 | function cleanUpNextTick() {
768 | if (!draining || !currentQueue) {
769 | return;
770 | }
771 | draining = false;
772 | if (currentQueue.length) {
773 | queue = currentQueue.concat(queue);
774 | } else {
775 | queueIndex = -1;
776 | }
777 | if (queue.length) {
778 | drainQueue();
779 | }
780 | }
781 |
782 | function drainQueue() {
783 | if (draining) {
784 | return;
785 | }
786 | var timeout = runTimeout(cleanUpNextTick);
787 | draining = true;
788 |
789 | var len = queue.length;
790 | while(len) {
791 | currentQueue = queue;
792 | queue = [];
793 | while (++queueIndex < len) {
794 | if (currentQueue) {
795 | currentQueue[queueIndex].run();
796 | }
797 | }
798 | queueIndex = -1;
799 | len = queue.length;
800 | }
801 | currentQueue = null;
802 | draining = false;
803 | runClearTimeout(timeout);
804 | }
805 |
806 | process.nextTick = function (fun) {
807 | var args = new Array(arguments.length - 1);
808 | if (arguments.length > 1) {
809 | for (var i = 1; i < arguments.length; i++) {
810 | args[i - 1] = arguments[i];
811 | }
812 | }
813 | queue.push(new Item(fun, args));
814 | if (queue.length === 1 && !draining) {
815 | runTimeout(drainQueue);
816 | }
817 | };
818 |
819 | // v8 likes predictible objects
820 | function Item(fun, array) {
821 | this.fun = fun;
822 | this.array = array;
823 | }
824 | Item.prototype.run = function () {
825 | this.fun.apply(null, this.array);
826 | };
827 | process.title = 'browser';
828 | process.browser = true;
829 | process.env = {};
830 | process.argv = [];
831 | process.version = ''; // empty string to avoid regexp issues
832 | process.versions = {};
833 |
834 | function noop() {}
835 |
836 | process.on = noop;
837 | process.addListener = noop;
838 | process.once = noop;
839 | process.off = noop;
840 | process.removeListener = noop;
841 | process.removeAllListeners = noop;
842 | process.emit = noop;
843 |
844 | process.binding = function (name) {
845 | throw new Error('process.binding is not supported');
846 | };
847 |
848 | process.cwd = function () { return '/' };
849 | process.chdir = function (dir) {
850 | throw new Error('process.chdir is not supported');
851 | };
852 | process.umask = function() { return 0; };
853 |
854 |
855 | /***/ },
856 | /* 9 */
857 | /***/ function(module, exports, __webpack_require__) {
858 |
859 | /* WEBPACK VAR INJECTION */(function(process) {module.exports = function (tasks, cb) {
860 | var results, pending, keys
861 | var isSync = true
862 |
863 | if (Array.isArray(tasks)) {
864 | results = []
865 | pending = tasks.length
866 | } else {
867 | keys = Object.keys(tasks)
868 | results = {}
869 | pending = keys.length
870 | }
871 |
872 | function done (err) {
873 | function end () {
874 | if (cb) cb(err, results)
875 | cb = null
876 | }
877 | if (isSync) process.nextTick(end)
878 | else end()
879 | }
880 |
881 | function each (i, err, result) {
882 | results[i] = result
883 | if (--pending === 0 || err) {
884 | done(err)
885 | }
886 | }
887 |
888 | if (!pending) {
889 | // empty
890 | done(null)
891 | } else if (keys) {
892 | // object
893 | keys.forEach(function (key) {
894 | tasks[key](function (err, result) { each(key, err, result) })
895 | })
896 | } else {
897 | // array
898 | tasks.forEach(function (task, i) {
899 | task(function (err, result) { each(i, err, result) })
900 | })
901 | }
902 |
903 | isSync = false
904 | }
905 |
906 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(8)))
907 |
908 | /***/ },
909 | /* 10 */
910 | /***/ function(module, exports, __webpack_require__) {
911 |
912 | /*
913 | MIT License http://www.opensource.org/licenses/mit-license.php
914 | Author Tobias Koppers @sokra
915 | */
916 | var stylesInDom = {},
917 | memoize = function(fn) {
918 | var memo;
919 | return function () {
920 | if (typeof memo === "undefined") memo = fn.apply(this, arguments);
921 | return memo;
922 | };
923 | },
924 | isOldIE = memoize(function() {
925 | return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase());
926 | }),
927 | getHeadElement = memoize(function () {
928 | return document.head || document.getElementsByTagName("head")[0];
929 | }),
930 | singletonElement = null,
931 | singletonCounter = 0,
932 | styleElementsInsertedAtTop = [];
933 |
934 | module.exports = function(list, options) {
935 | if(false) {
936 | if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
937 | }
938 |
939 | options = options || {};
940 | // Force single-tag solution on IE6-9, which has a hard limit on the # of