├── LICENSE
├── README.md
├── TreeD.html
├── TreeD.js
├── index.html
└── main.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Chris Harrison
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TreeGenerator
2 | Generates a pretty tree in the browser using adjustable parameters.
3 |
4 | Check it out [here,](http://someuser-321.github.io/TreeGenerator/) or in 3D [here!](http://someuser-321.github.io/TreeGenerator/TreeD.html)
5 |
--------------------------------------------------------------------------------
/TreeD.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TreeD thing
5 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/TreeD.js:
--------------------------------------------------------------------------------
1 | var slider_size,
2 | slider_level,
3 | slider_rot,
4 | slider_lenRand,
5 | slider_branchProb,
6 | slider_rotRand,
7 | slider_flowerProb;
8 |
9 | var button_seed,
10 | button_newSeed,
11 | button_randomParams,
12 | button_change,
13 | button_rotation;
14 |
15 | var label_size,
16 | label_level,
17 | label_rot,
18 | label_lenRand,
19 | label_branchProb,
20 | label_rotRand,
21 | label_flowerProb,
22 | label_perf,
23 | label_seed,
24 | label_source,
25 | label_source2;
26 |
27 | var div_inputs;
28 |
29 | var input_seed;
30 |
31 | var size,
32 | maxLevel,
33 | rot,
34 | lenRan,
35 | branchProb,
36 | rotRand,
37 | flowerProb;
38 |
39 | var hide = false,
40 | prog = 1,
41 | growing = false,
42 | mutating = false,
43 | randSeed = 80,
44 | paramSeed = Math.floor(Math.random() * 1000),
45 | randBias = 0;
46 |
47 | var mouseX_,
48 | mouseY_,
49 | rotateX_ = 0,
50 | rotateY_ = 0,
51 | zoom = 2,
52 | doRotate = true;
53 |
54 | function setup()
55 | {
56 | createCanvas(window.innerWidth, window.innerHeight, WEBGL);
57 |
58 | var fov = 60 / 180 * PI;
59 | var cameraZ = (height / 2) / tan(fov / 2);
60 | perspective(60 / 180 * PI, width / height, cameraZ * 0.001, cameraZ * 100);
61 |
62 | rotateX_ = PI/8;
63 |
64 | slider_size = createSlider(0, 1, 0.5, 0.01);
65 | slider_size.position(10, 10);
66 | slider_level = createSlider(1, 12, 9, 1);
67 | slider_level.position(10, 30);
68 | slider_rot = createSlider(0, 1, 0.125, 1 / (3 * 5 * 8));
69 | slider_rot.position(10, 50);
70 | slider_lenRand = createSlider(0, 1, 0.5, 0.01);
71 | slider_lenRand.position(10, 70);
72 | slider_branchProb = createSlider(0, 1, 0.98, 0.01);
73 | slider_branchProb.position(10, 90);
74 | slider_rotRand = createSlider(0, 1, 0.4, 0.01);
75 | slider_rotRand.position(10, 110);
76 | slider_flowerProb = createSlider(0, 1, 0.5, 0.01);
77 | slider_flowerProb.position(10, 130);
78 |
79 | slider_size.input(function(){readInputs(true)});
80 | slider_level.input(function(){readInputs(true)});
81 | slider_rot.input(function(){readInputs(true)});
82 | slider_lenRand.input(function(){readInputs(true)});
83 | slider_branchProb.input(function(){readInputs(true)});
84 | slider_rotRand.input(function(){readInputs(true)});
85 | slider_flowerProb.input(function(){readInputs(true)});
86 |
87 |
88 | label_size = createSpan('Size');
89 | label_size.position(150, 10);
90 | label_level = createSpan('Recursion level');
91 | label_level.position(150, 30);
92 | label_rot = createSpan('Split angle');
93 | label_rot.position(150, 50);
94 | label_lenRand = createSpan('Length variation');
95 | label_lenRand.position(150, 70);
96 | label_branchProb = createSpan('Split probability');
97 | label_branchProb.position(150, 90);
98 | label_rotRand = createSpan('Split rotation variation');
99 | label_rotRand.position(150, 110);
100 | label_flowerProb = createSpan('Flower probability');
101 | label_flowerProb.position(150, 130);
102 |
103 | label_seed = createSpan('Seed:');
104 | label_seed.position(10, 162);
105 |
106 | input_seed = createInput(randSeed);
107 | input_seed.position(50, 160);
108 | input_seed.style('width', '50px')
109 |
110 | button_seed = createButton('Watch it grow!');
111 | button_seed.position(110, 160);
112 | button_seed.mousePressed(function() {
113 | randSeed = input_seed.value();
114 | startGrow();
115 | });
116 |
117 | button_newSeed = createButton('Generate new tree');
118 | button_newSeed.position(10, 190);
119 | button_newSeed.mousePressed(function(){
120 | randSeed = Math.floor(Math.random() * 1000);
121 | prog = 100;
122 | input_seed.value(randSeed);
123 | startGrow();
124 | });
125 |
126 | button_randomParams = createButton('Randomise parameters');
127 | button_randomParams.position(10, 220);
128 | button_randomParams.mousePressed(function(){
129 | randomSeed(paramSeed);
130 |
131 | slider_level.value(1 * slider_level.value() + rand2() * slider_level.attribute('step'));
132 | slider_rot.value(1 * slider_rot.value() + 5 * rand2() * slider_rot.attribute('step'));
133 | slider_lenRand.value(1 * slider_lenRand.value() + 5 * rand2() * slider_lenRand.attribute('step'));
134 | slider_branchProb.value(1 * slider_branchProb.value() + 5 * rand2() * slider_branchProb.attribute('step'));
135 | slider_rotRand.value(1 * slider_rotRand.value() + 5 * rand2() * slider_rotRand.attribute('step'));
136 | slider_flowerProb.value(1 * slider_flowerProb.value() + 5 * rand2() * slider_flowerProb.attribute('step'));
137 |
138 | paramSeed = 1000 * random();
139 | randomSeed(randSeed);
140 |
141 | readInputs(true);
142 | });
143 |
144 | button_change = createButton('Enable wind');
145 | button_change.position(10, 250);
146 | button_change.mousePressed(function(){
147 | if ( !mutating )
148 | {
149 | button_change.html('Disable wind')
150 | mutateTime = millis();
151 | mutating = true;
152 | mutate();
153 | }
154 | else
155 | {
156 | button_change.html('Enable wind')
157 | randBias = 0;
158 | mutating = false;
159 | }
160 | });
161 |
162 | button_rotation = createButton('Disable rotation');
163 | button_rotation.position(10, 280);
164 | button_rotation.mousePressed(function(){
165 | if ( doRotate )
166 | button_rotation.html('Enable rotation')
167 | else
168 | button_rotation.html('Disable rotation')
169 |
170 | doRotate = !doRotate;
171 | });
172 |
173 | button_hide = createButton('Hide UI (click this area to show again)');
174 | button_hide.position(10, 310);
175 | button_hide.mousePressed(hideUI);
176 |
177 | label_perf = createSpan('Generated in #ms');
178 | label_perf.position(10, 340);
179 | //label_perf.style('display', 'none');
180 |
181 | label_source = createA('https://github.com/someuser-321/TreeGenerator', 'Check it out on GitHub!');
182 | label_source.position(10, 360);
183 | label_source2 = createA('https://someuser-321.github.io/TreeGenerator/index.html', 'Original 2D Version');
184 | label_source2.position(10, 380);
185 |
186 | div_inputs = createDiv('');
187 |
188 | mouseX_ = mouseX;
189 | mouseY_ = mouseY;
190 |
191 | button_change.html('Disable wind')
192 | mutateTime = millis();
193 | mutating = true;
194 | mutate();
195 |
196 | readInputs(false);
197 | startGrow();
198 | }
199 |
200 | function mouseDragged()
201 | {
202 | if ( mouseX < 330 && mouseY < 400 )
203 | return true;
204 |
205 | rotateX_ += (mouseY - mouseY_) / 500;
206 | rotateY_ += (mouseX - mouseX_) / 500;
207 |
208 | mouseX_ = mouseX;
209 | mouseY_ = mouseY;
210 |
211 | loop();
212 |
213 | return false;
214 | }
215 |
216 | function mouseMoved()
217 | {
218 | mouseX_ = mouseX;
219 | mouseY_ = mouseY;
220 |
221 | if ( mouseX > 330 || mouseY > 400 )
222 | return false;
223 | }
224 |
225 | function mouseClicked()
226 | {
227 | if ( mouseX > 330 || mouseY > 400 )
228 | return false;
229 | }
230 |
231 | function mouseWheel(event)
232 | {
233 | zoom *= (event.delta > 0 ? 1.1 : 1 / 1.1);
234 | loop();
235 |
236 | return false;
237 | }
238 |
239 | function mouseReleased()
240 | {
241 | if ( mouseX > 330 || mouseY > 400 )
242 | return false;
243 |
244 | if ( hide )
245 | showUI();
246 | hide = !hide;
247 |
248 | }
249 |
250 | function touchEnded()
251 | {
252 | if ( hide )
253 | showUI();
254 | hide = !hide;
255 |
256 | return false;
257 | }
258 |
259 | function showUI()
260 | {
261 | slider_size.style('visibility', 'initial');
262 | slider_level.style('visibility', 'initial');
263 | slider_rot.style('visibility', 'initial');
264 | slider_lenRand.style('visibility', 'initial');
265 | slider_branchProb.style('visibility', 'initial');
266 | slider_rotRand.style('visibility', 'initial');
267 | slider_flowerProb.style('visibility', 'initial');
268 |
269 | button_seed.style('visibility', 'initial');
270 | button_newSeed.style('visibility', 'initial');
271 | button_randomParams.style('visibility', 'initial');
272 | button_change.style('visibility', 'initial');
273 | button_rotation.style('visibility', 'initial');
274 | button_hide.style('visibility', 'initial');
275 |
276 | label_size.style('visibility', 'initial');
277 | label_level.style('visibility', 'initial');
278 | label_rot.style('visibility', 'initial');
279 | label_lenRand.style('visibility', 'initial');
280 | label_branchProb.style('visibility', 'initial');
281 | label_rotRand.style('visibility', 'initial');
282 | label_flowerProb.style('visibility', 'initial');
283 | label_perf.style('visibility', 'initial');
284 | label_seed.style('visibility', 'initial');
285 | label_source.style('visibility', 'initial');
286 | label_source2.style('visibility', 'initial');
287 |
288 | input_seed.style('visibility', 'initial');
289 |
290 | div_inputs.style('visibility', 'initial');
291 | }
292 |
293 | function hideUI()
294 | {
295 | slider_size.style('visibility', 'hidden');
296 | slider_level.style('visibility', 'hidden');
297 | slider_rot.style('visibility', 'hidden');
298 | slider_lenRand.style('visibility', 'hidden');
299 | slider_branchProb.style('visibility', 'hidden');
300 | slider_rotRand.style('visibility', 'hidden');
301 | slider_flowerProb.style('visibility', 'hidden');
302 |
303 | button_seed.style('visibility', 'hidden');
304 | button_newSeed.style('visibility', 'hidden');
305 | button_randomParams.style('visibility', 'hidden');
306 | button_change.style('visibility', 'hidden');
307 | button_rotation.style('visibility', 'hidden');
308 | button_hide.style('visibility', 'hidden');
309 |
310 | label_size.style('visibility', 'hidden');
311 | label_level.style('visibility', 'hidden');
312 | label_rot.style('visibility', 'hidden');
313 | label_lenRand.style('visibility', 'hidden');
314 | label_branchProb.style('visibility', 'hidden');
315 | label_rotRand.style('visibility', 'hidden');
316 | label_flowerProb.style('visibility', 'hidden');
317 | label_perf.style('visibility', 'hidden');
318 | label_seed.style('visibility', 'hidden');
319 | label_source.style('visibility', 'hidden');
320 | label_source2.style('visibility', 'hidden');
321 |
322 | input_seed.style('visibility', 'hidden');
323 |
324 | div_inputs.style('visibility', 'hidden');
325 | }
326 |
327 | function readInputs(updateTree)
328 | {
329 | size = slider_size.value();
330 | maxLevel = slider_level.value();
331 | rot = slider_rot.value();
332 | lenRand = slider_lenRand.value();
333 | branchProb = slider_branchProb.value();
334 | rotRand = slider_rotRand.value();
335 | flowerProb = slider_flowerProb.value();
336 |
337 | if ( updateTree && !growing )
338 | {
339 | prog = maxLevel + 1;
340 | loop();
341 | }
342 | }
343 |
344 | function mutate()
345 | {
346 | var startTime = millis();
347 | randomSeed(paramSeed);
348 |
349 | var n = noise(startTime / 20000) - 0.5;
350 |
351 | randBias = 4 * Math.abs(n) * n * (mutating ? 1 : 0);
352 |
353 | paramSeed = 1000 * random();
354 | randomSeed(randSeed);
355 | readInputs(true);
356 |
357 | var diff = millis() - startTime;
358 |
359 | if ( diff < 20 )
360 | setTimeout(mutate, 20 - diff);
361 | else
362 | setTimeout(mutate, 1);
363 | }
364 |
365 | function windowResized()
366 | {
367 | resizeCanvas(windowWidth, windowHeight);
368 |
369 | var fov = 60 / 180 * PI;
370 | var cameraZ = (height / 2) / tan(fov / 2);
371 | perspective(60 / 180 * PI, width / height, cameraZ * 0.1, cameraZ * 10);
372 |
373 | loop();
374 | }
375 |
376 | function draw()
377 | {
378 | var startFrameTime = millis();
379 | background(0, 0, 0);
380 |
381 |
382 | scale(1, -1);
383 |
384 | /*
385 | ambientMaterial(255, 0, 0);
386 | push();
387 | translate(100, 0, 0);
388 | box(200, 10, 10);
389 | pop();
390 |
391 | ambientMaterial(0, 255, 0);
392 | push();
393 | translate(0, 100, 0);
394 | box(10, 200, 10);
395 | pop();
396 |
397 | ambientMaterial(0, 0, 255);
398 | push();
399 | translate(0, 0, 100);
400 | box(10, 10, 200);
401 | pop();
402 | */
403 |
404 | translate(0, -height * (size+0.25), -zoom * height * size);
405 |
406 |
407 | rotate(-rotateX_, [1, 0, 0]);
408 | rotate(rotateY_, [0, 1, 0]);
409 |
410 | push();
411 | rotate(-PI/2, [1, 0, 0]);
412 | ambientMaterial(255, 255, 255);
413 | plane(1000, -1000);
414 | pop();
415 |
416 | ambientLight(20);
417 | pointLight(255, 255, 255, 1000, 1000, 1000);
418 |
419 |
420 | /*
421 | ambientMaterial(255, 0, 0);
422 | push();
423 | translate(100, 0, 0);
424 | box(200, 5, 5);
425 | pop();
426 |
427 | ambientMaterial(0, 255, 0);
428 | push();
429 | translate(0, 100, 0);
430 | box(5, 200, 5);
431 | pop();
432 |
433 | ambientMaterial(0, 0, 255);
434 | push();
435 | translate(0, 0, 100);
436 | box(5, 5, 200);
437 | pop();
438 | */
439 |
440 | branch(1, randSeed);
441 |
442 | var frameTime = (millis() - startFrameTime);
443 | label_perf.html('Generated in ' + Math.floor(frameTime * 10) / 10 + 'ms');
444 |
445 | var frameTime_ = Math.max(frameTime/1000, 1/(frameRate()||60));
446 |
447 | if ( doRotate )
448 | rotateY_ += 1/180 * 2*PI * frameTime_;
449 |
450 | noLoop();
451 | }
452 |
453 | function branch(level, seed)
454 | {
455 | if ( prog < level )
456 | return;
457 |
458 | randomSeed(seed);
459 |
460 | var seed1 = random(1000),
461 | seed2 = random(1000);
462 |
463 | var growthLevel = (prog - level > 1) || (prog >= maxLevel + 1) ? 1 : (prog - level);
464 |
465 | var width = 50 * size * Math.pow((maxLevel - level + 1) / maxLevel, 2);
466 | var len = growthLevel * size * height * (1 + rand2() * lenRand);
467 |
468 | translate(0, (len / level) / 2, 0);
469 |
470 | ambientMaterial(255, 255, 255);
471 | box(width, len / level, width);
472 |
473 | translate(0, (len / level) / 2, 0);
474 |
475 | var doBranch1 = rand() < branchProb;
476 | var doBranch2 = rand() < branchProb;
477 |
478 | var doFlowers = rand() < flowerProb && prog >= maxLevel && level >= maxLevel;
479 |
480 | if ( level < maxLevel )
481 | {
482 | var r11 = rot * PI * (1 + rand2() * rotRand + randWind());
483 | var r12 = rot * PI * (1 + rand2() * rotRand + randWind());
484 | var r21 = rot * PI * (1 + rand2() * rotRand - randWind());
485 | var r22 = rot * PI * (1 + rand2() * rotRand - randWind());
486 |
487 | if ( doBranch1 )
488 | {
489 | push();
490 | rotate(PI/2 + r11, [0, 1, 0]);
491 | rotate(r12, [1, 0, 0]);
492 | branch(level + 1, seed1);
493 | pop();
494 | }
495 | if ( doBranch2 )
496 | {
497 | push();
498 | rotate(PI/2 + r21, [0, 1, 0]);
499 | rotate(-r22, [1, 0, 0]);
500 | branch(level + 1, seed2);
501 | pop();
502 | }
503 | }
504 |
505 | if ( doFlowers )
506 | {
507 | ambientMaterial(255, 150, 150);
508 | var flowerSize = rand() * growthLevel * size * 50;
509 | for ( var i=0 ; i<4 ; i++ )
510 | {
511 | rotate(PI/4, [1, 0, 0]);
512 | rotate(2 * PI * i/4, [0, 0, 1])
513 |
514 | box(2, flowerSize, 2);
515 | }
516 | }
517 | }
518 |
519 | function startGrow()
520 | {
521 | growing = true;
522 | prog = 1;
523 | grow();
524 | }
525 |
526 | function grow()
527 | {
528 | if ( prog > (maxLevel + 3) )
529 | {
530 | prog = maxLevel + 3;
531 | loop();
532 | growing = false;
533 | return;
534 | }
535 |
536 | var startTime = millis();
537 | loop();
538 | var diff = millis() - startTime;
539 |
540 | prog += maxLevel / 8 * Math.max(diff, 20) / 1000;
541 | setTimeout(grow, Math.max(1, 20 - diff));
542 | }
543 |
544 |
545 | function rand()
546 | {
547 | return random(1000) / 1000;
548 | }
549 |
550 | function rand2()
551 | {
552 | return random(2000) / 1000 - 1;
553 | }
554 |
555 | function randWind()
556 | {
557 | return /*rand2() **/ randBias;
558 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tree thing
5 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | var slider_size,
2 | slider_level,
3 | slider_rot,
4 | slider_lenRand,
5 | slider_branchProb,
6 | slider_rotRand,
7 | slider_leafProb;
8 |
9 | var button_seed,
10 | button_newSeed,
11 | button_randomParams,
12 | button_change;
13 |
14 | var label_size,
15 | label_level,
16 | label_rot,
17 | label_lenRand,
18 | label_branchProb,
19 | label_rotRand,
20 | label_leafProb,
21 | label_perf,
22 | label_seed,
23 | label_source,
24 | label_source2;
25 |
26 | var div_inputs;
27 |
28 | var input_seed,
29 | size,
30 | maxLevel,
31 | rot,
32 | lenRan,
33 | branchProb,
34 | rotRand,
35 | leafProb;
36 |
37 | var hide = false,
38 | prog = 1,
39 | growing = false,
40 | mutating = false,
41 | randSeed = 80,
42 | paramSeed = Math.floor(Math.random()*1000),
43 | randBias = 0;
44 |
45 |
46 | function setup()
47 | {
48 | createCanvas(window.innerWidth, window.innerHeight);
49 |
50 | slider_size = createSlider(100, 200, /mobile/i.test(window.navigator.userAgent) ? 100 : 150, 1);
51 | slider_size.position(10, 10);
52 | slider_level = createSlider(1, 13, 11, 1);
53 | slider_level.position(10, 30);
54 | slider_rot = createSlider(0, PI/2, (PI/2) / 4, (PI/2) / (3 * 5 * 8));
55 | slider_rot.position(10, 50);
56 | slider_lenRand = createSlider(0, 1, 1, 0.01);
57 | slider_lenRand.position(10, 70);
58 | slider_branchProb = createSlider(0, 1, 0.9, 0.01);
59 | slider_branchProb.position(10, 90);
60 | slider_rotRand = createSlider(0, 1, 0.1, 0.01);
61 | slider_rotRand.position(10, 110);
62 | slider_leafProb = createSlider(0, 1, 0.5, 0.01);
63 | slider_leafProb.position(10, 130);
64 |
65 | slider_size.input(function(){readInputs(true)});
66 | slider_level.input(function(){readInputs(true)});
67 | slider_rot.input(function(){readInputs(true)});
68 | slider_lenRand.input(function(){readInputs(true)});
69 | slider_branchProb.input(function(){readInputs(true)});
70 | slider_rotRand.input(function(){readInputs(true)});
71 | slider_leafProb.input(function(){readInputs(true)});
72 |
73 |
74 | label_size = createSpan('Size');
75 | label_size.position(150, 10);
76 | label_level = createSpan('Recursion level');
77 | label_level.position(150, 30);
78 | label_rot = createSpan('Split angle');
79 | label_rot.position(150, 50);
80 | label_lenRand = createSpan('Length variation');
81 | label_lenRand.position(150, 70);
82 | label_branchProb = createSpan('Split probability');
83 | label_branchProb.position(150, 90);
84 | label_rotRand = createSpan('Split rotation variation');
85 | label_rotRand.position(150, 110);
86 | label_leafProb = createSpan('Flower probability');
87 | label_leafProb.position(150, 130);
88 |
89 | label_seed = createSpan('Seed:');
90 | label_seed.position(10, 162);
91 |
92 | input_seed = createInput(randSeed);
93 | input_seed.position(50, 160);
94 | input_seed.style('width', '50px')
95 |
96 | button_seed = createButton('Watch it grow!');
97 | button_seed.position(110, 160);
98 | button_seed.mousePressed(function() {
99 | randSeed = input_seed.value();
100 | startGrow();
101 | });
102 |
103 | button_newSeed = createButton('Generate new tree');
104 | button_newSeed.position(10, 190);
105 | button_newSeed.mousePressed(function(){
106 | randSeed = Math.floor(Math.random() * 1000);
107 | prog = 100;
108 | input_seed.value(randSeed);
109 | startGrow();
110 | });
111 |
112 | button_randomParams = createButton('Randomise parameters');
113 | button_randomParams.position(10, 220);
114 | button_randomParams.mousePressed(function(){
115 | randomSeed(paramSeed);
116 |
117 | slider_level.value(1 * slider_level.value() + 4 * rand2() * slider_level.attribute('step'));
118 | slider_rot.value(1 * slider_rot.value() + 4 * rand2() * slider_rot.attribute('step'));
119 | slider_lenRand.value(1 * slider_lenRand.value() + 4 * rand2() * slider_lenRand.attribute('step'));
120 | slider_branchProb.value(1 * slider_branchProb.value() + 4 * rand2() * slider_branchProb.attribute('step'));
121 | slider_rotRand.value(1 * slider_rotRand.value() + 4 * rand2() * slider_rotRand.attribute('step'));
122 | slider_leafProb.value(1 * slider_leafProb.value() + 4 * rand2() * slider_leafProb.attribute('step'));
123 |
124 | paramSeed = 1000 * random();
125 | randomSeed(randSeed);
126 |
127 | readInputs(true);
128 | });
129 |
130 | button_change = createButton('Enable wind');
131 | button_change.position(10, 250);
132 | button_change.mousePressed(function(){
133 | if ( !mutating )
134 | {
135 | button_change.html('Disable wind')
136 | mutateTime = millis();
137 | mutating = true;
138 | mutate();
139 | }
140 | else
141 | {
142 | button_change.html('Enable wind')
143 | mutating = false;
144 | }
145 | });
146 |
147 | button_hide = createButton('Hide UI (click this area to show again)');
148 | button_hide.position(10, 280);
149 | button_hide.mousePressed(hideUI);
150 |
151 | label_perf = createSpan('Generated in #ms');
152 | label_perf.position(10, 310);
153 | //label_perf.style('display', 'none');
154 |
155 | label_source = createA('https://github.com/someuser-321/TreeGenerator', 'Check it out on GitHub!');
156 | label_source.position(10, 330);
157 | label_source2 = createA('https://someuser-321.github.io/TreeGenerator/TreeD.html', 'See me in 3D!');
158 | label_source2.position(10, 350);
159 |
160 | div_inputs = createDiv('');
161 |
162 | mX = mouseX;
163 | mY = mouseY;
164 | panX = 0;
165 | panY = 0;
166 |
167 | readInputs(false);
168 | startGrow();
169 | }
170 |
171 | function mouseReleased()
172 | {
173 | if ( mouseX > 330 || mouseY > 400 )
174 | return false;
175 |
176 | if ( hide )
177 | showUI();
178 | hide = !hide;
179 | }
180 |
181 | function touchEnded()
182 | {
183 | if ( hide )
184 | showUI();
185 | hide = !hide;
186 |
187 | return false;
188 | }
189 |
190 | function showUI()
191 | {
192 | slider_size.style('visibility', 'initial');
193 | slider_level.style('visibility', 'initial');
194 | slider_rot.style('visibility', 'initial');
195 | slider_lenRand.style('visibility', 'initial');
196 | slider_branchProb.style('visibility', 'initial');
197 | slider_rotRand.style('visibility', 'initial');
198 | slider_leafProb.style('visibility', 'initial');
199 |
200 | button_seed.style('visibility', 'initial');
201 | button_newSeed.style('visibility', 'initial');
202 | button_randomParams.style('visibility', 'initial');
203 | button_change.style('visibility', 'initial');
204 | button_hide.style('visibility', 'initial');
205 |
206 | label_size.style('visibility', 'initial');
207 | label_level.style('visibility', 'initial');
208 | label_rot.style('visibility', 'initial');
209 | label_lenRand.style('visibility', 'initial');
210 | label_branchProb.style('visibility', 'initial');
211 | label_rotRand.style('visibility', 'initial');
212 | label_leafProb.style('visibility', 'initial');
213 | label_perf.style('visibility', 'initial');
214 | label_seed.style('visibility', 'initial');
215 | label_source.style('visibility', 'initial');
216 | label_source2.style('visibility', 'initial');
217 |
218 | input_seed.style('visibility', 'initial');
219 |
220 | div_inputs.style('visibility', 'initial');
221 | }
222 |
223 | function hideUI()
224 | {
225 | slider_size.style('visibility', 'hidden');
226 | slider_level.style('visibility', 'hidden');
227 | slider_rot.style('visibility', 'hidden');
228 | slider_lenRand.style('visibility', 'hidden');
229 | slider_branchProb.style('visibility', 'hidden');
230 | slider_rotRand.style('visibility', 'hidden');
231 | slider_leafProb.style('visibility', 'hidden');
232 |
233 | button_seed.style('visibility', 'hidden');
234 | button_newSeed.style('visibility', 'hidden');
235 | button_randomParams.style('visibility', 'hidden');
236 | button_change.style('visibility', 'hidden');
237 | button_hide.style('visibility', 'hidden');
238 |
239 | label_size.style('visibility', 'hidden');
240 | label_level.style('visibility', 'hidden');
241 | label_rot.style('visibility', 'hidden');
242 | label_lenRand.style('visibility', 'hidden');
243 | label_branchProb.style('visibility', 'hidden');
244 | label_rotRand.style('visibility', 'hidden');
245 | label_leafProb.style('visibility', 'hidden');
246 | label_perf.style('visibility', 'hidden');
247 | label_seed.style('visibility', 'hidden');
248 | label_source.style('visibility', 'hidden');
249 | label_source2.style('visibility', 'hidden');
250 |
251 | input_seed.style('visibility', 'hidden');
252 |
253 | div_inputs.style('visibility', 'hidden');
254 | }
255 |
256 | function readInputs(updateTree)
257 | {
258 | size = slider_size.value();
259 | maxLevel = slider_level.value();
260 | rot = slider_rot.value();
261 | lenRand = slider_lenRand.value();
262 | branchProb = slider_branchProb.value();
263 | rotRand = slider_rotRand.value();
264 | leafProb = slider_leafProb.value();
265 |
266 | if ( updateTree && !growing )
267 | {
268 | prog = maxLevel + 1;
269 | loop();
270 | }
271 | }
272 |
273 | function mutate()
274 | {
275 | if ( !mutating )
276 | return;
277 |
278 | var startTime = millis();
279 | randomSeed(paramSeed);
280 |
281 | var n = noise(startTime/20000) - 0.5;
282 |
283 | randBias = 4 * Math.abs(n) * n;
284 |
285 | paramSeed = 1000 * random();
286 | randomSeed(randSeed);
287 | readInputs(true);
288 |
289 | var diff = millis() - startTime;
290 |
291 | if ( diff < 20 )
292 | setTimeout(mutate, 20 - diff);
293 | else
294 | setTimeout(mutate, 1);
295 | }
296 |
297 | function windowResized()
298 | {
299 | resizeCanvas(windowWidth, windowHeight);
300 | }
301 |
302 | function draw()
303 | {
304 | var startTime = millis();
305 |
306 | stroke(255, 255, 255);
307 |
308 | background(0, 0, 0);
309 | translate(width / 2, height);
310 | scale(1, -1);
311 |
312 | translate(0, 20);
313 |
314 | branch(1, randSeed);
315 |
316 | var endTime = millis();
317 | label_perf.html('Generated in ' + Math.floor((endTime - startTime) * 10) / 10 + 'ms');
318 |
319 | noLoop();
320 | }
321 |
322 | function branch(level, seed)
323 | {
324 | if ( prog < level )
325 | return;
326 |
327 | randomSeed(seed);
328 |
329 | var seed1 = random(1000),
330 | seed2 = random(1000);
331 |
332 | var growthLevel = (prog - level > 1) || (prog >= maxLevel + 1) ? 1 : (prog - level);
333 |
334 | strokeWeight(12 * Math.pow((maxLevel - level + 1) / maxLevel, 2));
335 |
336 | var len = growthLevel * size* (1 + rand2() * lenRand);
337 |
338 | line(0, 0, 0, len / level);
339 | translate(0, len / level);
340 |
341 |
342 | var doBranch1 = rand() < branchProb;
343 | var doBranch2 = rand() < branchProb;
344 |
345 | var doLeaves = rand() < leafProb;
346 |
347 | if ( level < maxLevel )
348 | {
349 |
350 | var r1 = rot * (1 + rrand() * rotRand);
351 | var r2 = -rot * (1 - rrand() * rotRand);
352 |
353 | if ( doBranch1 )
354 | {
355 | push();
356 | rotate(r1);
357 | branch(level + 1, seed1);
358 | pop();
359 | }
360 | if ( doBranch2 )
361 | {
362 | push();
363 | rotate(r2);
364 | branch(level + 1, seed2);
365 | pop();
366 | }
367 | }
368 |
369 | if ( (level >= maxLevel || (!doBranch1 && !doBranch2)) && doLeaves )
370 | {
371 | var p = Math.min(1, Math.max(0, prog - level));
372 |
373 | var flowerSize = (size / 100) * p * (1 / 6) * (len / level);
374 |
375 | strokeWeight(1);
376 | stroke(240 + 15 * rand2(), 140 + 15 * rand2(), 140 + 15 * rand2());
377 |
378 | rotate(-PI);
379 | for ( var i=0 ; i<=8 ; i++ )
380 | {
381 | line(0, 0, 0, flowerSize * (1 + 0.5 * rand2()));
382 | rotate(2 * PI/8);
383 | }
384 | }
385 | }
386 |
387 | function startGrow()
388 | {
389 | growing = true;
390 | prog = 1;
391 | grow();
392 | }
393 |
394 | function grow()
395 | {
396 | if ( prog > (maxLevel + 3) )
397 | {
398 | prog = maxLevel + 3;
399 | loop();
400 | growing = false;
401 | return;
402 | }
403 |
404 | var startTime = millis();
405 | loop();
406 | var diff = millis() - startTime;
407 |
408 | prog += maxLevel / 8 * Math.max(diff, 20) / 1000;
409 | setTimeout(grow, Math.max(1, 20 - diff));
410 | }
411 |
412 |
413 | function rand()
414 | {
415 | return random(1000) / 1000;
416 | }
417 |
418 | function rand2()
419 | {
420 | return random(2000) / 1000 - 1;
421 | }
422 |
423 | function rrand()
424 | {
425 | return rand2() + randBias;
426 | }
--------------------------------------------------------------------------------