Draw Polygon C Christmas Tree Graphics

Javascript

Quasirealistic fully 3D procedural fir tree generator.

Featuring: extensive configuration with even more configuration options present in code; a zigzagy trunk; branching branches; growth animation; rotation of a fully grown tree.

Not featuring: jQuery, Underscore.js or any other library; hardware dependency - only canvas support is required; messy code (at least that was the intention)

Live page: http://fiddle.jshell.net/honnza/NMva7/show/

Edit page: http://jsfiddle.net/honnza/NMva7/

screenshot:

fir tree

HTML:

          <canvas id=c width=200 height=300 style="display:none"></canvas> <div id=config></div>                  

Javascript:

          var TAU = 2*Math.PI,     deg = TAU/360,      TRUNK_VIEW      = {lineWidth:3, strokeStyle: "brown", zIndex: 1},     BRANCH_VIEW     = {lineWidth:1, strokeStyle: "green", zIndex: 2},     TRUNK_SPACING   = 1.5,     TRUNK_BIAS_STR  = -0.5,     TRUNK_SLOPE     = 0.25,     BRANCH_LEN      = 1,     BRANCH_P        = 0.01,     MIN_SLOPE       = -5*deg,     MAX_SLOPE       = 20*deg,     INIT_SLOPE      = 10*deg,     MAX_D_SLOPE     =  5*deg,     DIR_KEEP_BIAS   = 10,     GROWTH_MSPF     = 10, //ms per frame     GROWTH_TPF      = 10, //ticks per frame     ROTATE_MSPF     = 10,     ROTATE_RPF      = 1*deg; //radians per frame  var configurables = [ //    {key: "TRUNK_SPACING", name: "Branch spacing", widget: "number", //     description: "Distance between main branches on the trunk, in pixels"},     {key: "TRUNK_BIAS_STR", name: "Branch distribution", widget: "number",      description: "Angular distribution between nearby branches. High values tend towards one-sided trees, highly negative values tend towards planar trees. Zero means that branches grow in independent directions."},     {key: "TRUNK_SLOPE", name: "Trunk slope", widget: "number",      description: "Amount of horizontal movement of the trunk while growing"},     {key: "BRANCH_P", name: "Branch frequency", widget: "number",      description: "Branch frequency - if =1/100, a single twig will branch off approximately once per 100 px"},     {key: "MIN_SLOPE", name: "Minimum slope", widget: "number", scale: deg,      description: "Minimum slope of a branch, in degrees"},     {key: "MAX_SLOPE", name: "Maximum slope", widget: "number", scale: deg,      description: "Maximum slope of a branch, in degrees"},     {key: "INIT_SLOPE", name: "Initial slope", widget: "number", scale: deg,      description: "Angle at which branches leave the trunk"},     {key: "DIR_KEEP_BIAS", name: "Directional inertia", widget: "number",      description: "Tendency of twigs to keep their horizontal direction"},     {get: function(){return maxY}, set: setCanvasSize, name: "Tree height",      widget:"number"}     ];  var config = document.getElementById("config"),     canvas = document.getElementById("c"),     maxX   = canvas.width/2,     maxY   = canvas.height,     canvasRatio = canvas.width / canvas.height,     c;  function setCanvasSize(height){     if(height === 'undefined') return maxY;     maxY = canvas.height = height;     canvas.width = height * canvasRatio;     maxX = canvas.width/2; x}  var nodes = [{x:0, y:0, z:0, dir:'up', isEnd:true}], buds = [nodes[0]],     branches = [],     branch,     trunkDirBias = {x:0, z:0};  ////////////////////////////////////////////////////////////////////////////////  configurables.forEach(function(el){     var widget;     switch(el.widget){         case 'number':             widget = document.createElement("input");             if(el.key){                 widget.value = window[el.key] / (el.scale||1);                 el.set = function(value){window[el.key]=value * (el.scale||1)};             }else{                 widget.value = el.get();             }             widget.onblur = function(){                 el.set(+widget.value);             };             break;         default: throw "unknown widget type";     }     var p = document.createElement("p");     p.textContent = el.name + ": ";     p.appendChild(widget);     p.title = el.description;     config.appendChild(p); }); var button = document.createElement("input"); button.type = "button"; button.value = "grow"; button.onclick = function(){     button.value = "stop";     button.onclick = function(){clearInterval(interval)};     config.style.display="none";     canvas.style.display="";     c=canvas.getContext("2d");     c.translate(maxX, maxY);                     c.scale(1, -1);     interval = setInterval(grow, GROWTH_MSPF); } document.body.appendChild(button); function grow(){     for(var tick=0; tick<GROWTH_TPF; tick++){         var budId = 0 | Math.random() * buds.length,             nodeFrom = buds[budId], nodeTo, branch,             dir, slope, bias          if(nodeFrom.dir === 'up' && nodeFrom.isEnd){             nodeFrom.isEnd = false;              rndArg = Math.random()*TAU;             nodeTo = {                 x:nodeFrom.x + TRUNK_SPACING * TRUNK_SLOPE * Math.sin(rndArg),                 y:nodeFrom.y + TRUNK_SPACING,                 z:nodeFrom.z + TRUNK_SPACING * TRUNK_SLOPE * Math.cos(rndArg),                  dir:'up', isEnd:true}             if(nodeTo.y > maxY){                 console.log("end");                 clearInterval(interval);                 rotateInit();                 return;             }             nodes.push(nodeTo);             buds.push(nodeTo);             branch = {from: nodeFrom, to: nodeTo, view: TRUNK_VIEW};             branches.push(branch);             renderBranch(branch);         }else{ //bud is not a trunk top             if(!(nodeFrom.dir !== 'up' && Math.random() < BRANCH_P)){                 buds.splice(buds.indexOf(nodeFrom), 1)             }             nodeFrom.isEnd = false;              if(nodeFrom.dir === 'up'){                 bias = {x:trunkDirBias.x * TRUNK_BIAS_STR,                         z:trunkDirBias.z * TRUNK_BIAS_STR};                 slope = INIT_SLOPE;             }else{                 bias = {x:nodeFrom.dir.x * DIR_KEEP_BIAS,                         z:nodeFrom.dir.z * DIR_KEEP_BIAS};                 slope = nodeFrom.slope;             }             var rndLen = Math.random(),                 rndArg = Math.random()*TAU;             dir = {x: rndLen * Math.sin(rndArg) + bias.x,                    z: rndLen * Math.cos(rndArg) + bias.z};             var uvFix = 1/Math.sqrt(dir.x*dir.x + dir.z*dir.z);             dir = {x:dir.x*uvFix, z:dir.z*uvFix};             if(nodeFrom.dir === "up") trunkDirBias = dir;             slope += MAX_D_SLOPE * (2*Math.random() - 1);             if(slope > MAX_SLOPE) slope = MAX_SLOPE;             if(slope < MIN_SLOPE) slope = MIN_SLOPE;             var length = BRANCH_LEN * Math.random();             nodeTo = {                 x: nodeFrom.x + length * Math.cos(slope) * dir.x,                 y: nodeFrom.y + length * Math.sin(slope),                 z: nodeFrom.z + length * Math.cos(slope) * dir.z,                 dir: dir, slope: slope, isEnd: true             }             //if(Math.abs(nodeTo.x)/maxX + nodeTo.y/maxY > 1) return;             nodes.push(nodeTo);             buds.push(nodeTo);             branch = {from: nodeFrom, to: nodeTo, view: BRANCH_VIEW};             branches.push(branch);             renderBranch(branch);         }// end if-is-trunk     }// end for-tick }//end func-grow  function rotateInit(){     branches.sort(function(a,b){         return (a.view.zIndex-b.view.zIndex);     });     interval = setInterval(rotate, ROTATE_MSPF); }  var time = 0; var view = {x:1, z:0} function rotate(){     time++;     view = {x: Math.cos(time * ROTATE_RPF),             z: Math.sin(time * ROTATE_RPF)};     c.fillStyle = "white"     c.fillRect(-maxX, 0, 2*maxX, maxY);     branches.forEach(renderBranch);     c.stroke();     c.beginPath(); }  var prevView = null; function renderBranch(branch){     if(branch.view !== prevView){         c.stroke();         for(k in branch.view) c[k] = branch.view[k];         c.beginPath();         prevView = branch.view;     }     c.moveTo(view.x * branch.from.x + view.z * branch.from.z,              branch.from.y);     c.lineTo(view.x * branch.to.x + view.z * branch.to.z,              branch.to.y); }                  

lewinhady1996.blogspot.com

Source: https://codegolf.stackexchange.com/questions/15860/make-a-scalable-christmas-tree

0 Response to "Draw Polygon C Christmas Tree Graphics"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel