Add files via upload
BIN
assets/armor_stand.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
assets/brush.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
assets/hud.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/inventory_full.png
Normal file
After Width: | Height: | Size: 1022 B |
BIN
assets/inventory_nine.png
Normal file
After Width: | Height: | Size: 386 B |
BIN
assets/item_frame.png
Normal file
After Width: | Height: | Size: 599 B |
BIN
assets/missing.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
assets/north.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
assets/player_skin.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
assets/zombie.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
build/background.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
build/icon.ico
Normal file
After Width: | Height: | Size: 358 KiB |
BIN
build/icon.png
Normal file
After Width: | Height: | Size: 150 KiB |
5
css/font-awesome.min.css
vendored
Normal file
7
css/jquery-ui.min.css
vendored
Normal file
1888
css/style.css
Normal file
210
css/w3.css
Normal file
@ -0,0 +1,210 @@
|
||||
/* W3.CSS 4.04 Apr 2017 by Jan Egil and Borge Refsnes */
|
||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}
|
||||
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||
a{background-color:transparent;-webkit-text-decoration-skip:objects}
|
||||
a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||
dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}svg:not(:root){overflow:hidden}
|
||||
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
|
||||
button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||
button,input{overflow:visible}button,select{text-transform:none}
|
||||
button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
||||
button::-moz-focus-inner, [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||
button:-moz-focusring, [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||
[type=checkbox],[type=radio]{padding:0}
|
||||
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
||||
[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||
::-webkit-input-placeholder{color:inherit;opacity:0.54}
|
||||
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||
/* End extract */
|
||||
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
||||
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}.w3-serif{font-family:serif}
|
||||
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
||||
.w3-image{max-width:100%;height:auto}img{margin-bottom:-5px}a{color:inherit}
|
||||
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
||||
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||
.w3-btn,.w3-button{border:none;display:inline-block;outline:0;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
||||
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
||||
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
||||
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
||||
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||
.w3-dropdown-hover:hover .w3-dropdown-content{display:block;z-index:1}
|
||||
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0}
|
||||
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
||||
.w3-main,#main{transition:margin-left .4s}
|
||||
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
||||
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;outline:none;display:block}
|
||||
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||
.w3-bar .w3-button{white-space:normal}
|
||||
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;outline:none;white-space:normal;float:none}
|
||||
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
||||
.w3-responsive{overflow-x:auto}
|
||||
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
||||
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
||||
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
||||
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
||||
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
||||
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
||||
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
||||
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
||||
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
||||
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
||||
.w3-content{max-width:980px;margin:auto}.w3-rest{overflow:hidden}
|
||||
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
||||
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
||||
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}}
|
||||
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||
.w3-display-position{position:absolute}
|
||||
.w3-circle{border-radius:50%}
|
||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
||||
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
||||
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
||||
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
||||
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
||||
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
||||
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
||||
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
||||
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
||||
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||
.w3-hover-none:hover{box-shadow:none!important}
|
||||
/* Colors */
|
||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#bbb!important}
|
||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#ffeb3b!important}
|
||||
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||
.w3-text-amber{color:#ffc107!important}
|
||||
.w3-text-aqua{color:#00ffff!important}
|
||||
.w3-text-light-blue{color:#87CEEB!important}
|
||||
.w3-text-brown{color:#795548!important}
|
||||
.w3-text-cyan{color:#00bcd4!important}
|
||||
.w3-text-blue-grey,.w3-text-blue-gray{color:#607d8b!important}
|
||||
.w3-text-light-green{color:#8bc34a!important}
|
||||
.w3-text-indigo{color:#3f51b5!important}
|
||||
.w3-text-khaki{color:#b4aa50!important}
|
||||
.w3-text-lime{color:#cddc39!important}
|
||||
.w3-text-orange{color:#ff9800!important}
|
||||
.w3-text-deep-orange{color:#ff5722!important}
|
||||
.w3-text-pink{color:#e91e63!important}
|
||||
.w3-text-purple{color:#9c27b0!important}
|
||||
.w3-text-deep-purple{color:#673ab7!important}
|
||||
.w3-text-sand{color:#fdf5e6!important}
|
||||
.w3-text-teal{color:#009688!important}
|
||||
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#bbb!important}
|
BIN
favicon.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
font/FontAwesome.otf
Normal file
BIN
font/MaterialIcons-Regular.ttf
Normal file
BIN
font/MaterialIcons-Regular.woff
Normal file
BIN
font/MaterialIcons-Regular.woff2
Normal file
BIN
font/Montserrat-Regular.ttf
Normal file
BIN
font/fontawesome-webfont.eot
Normal file
2671
font/fontawesome-webfont.svg
Normal file
After Width: | Height: | Size: 434 KiB |
BIN
font/fontawesome-webfont.ttf
Normal file
BIN
font/fontawesome-webfont.woff
Normal file
BIN
font/fontawesome-webfont.woff2
Normal file
BIN
font/icomoon.eot
Normal file
21
font/icomoon.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="icomoon" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" glyph-name="x11" d="M95.492 339.172h244.617v-354.968h-244.617v354.968zM391.492 205.172h244.617v-217.789h-244.617v217.789zM683.492 870.048h244.617v-883.876h-244.617v883.876z" />
|
||||
<glyph unicode="" glyph-name="baby_zombie" d="M357.625 933.25l-14-483.375 130.125-14-5.25-12.125c-141.25 9.173-231.492 14.842-271.25 17.25-21.675 1.313-32.936 1.94-38.875 2.25-2.97 0.155-4.531 0.208-5.625 0.25s-4.875 0-4.875 0l-32-2.5-0.625-157.375 344.25-24.875 2.875-284.375h228.5l12.25 443.875h168.125l14 511.375z" />
|
||||
<glyph unicode="" glyph-name="armor_stand" d="M455.514 567.482h104.385v161.959l2.821 105.862-107.206-0.905zM264.723 486.552h476.677l-5.309 86.908c-142.18-0.098-314.246-0.196-471.368-0.294zM350.114-41.974h105.841v329.148l2.861 215.141-108.702-1.839zM559.398-41.993h105.88v324.041l2.861 211.803-108.742-1.81zM861.295-4.873l82.656 23.311-81.12 329.569-50.789 216.047-84.437-25.782zM63.46 11.515l84.107-17.365 79.735 329.907 54.391 215.168-86.825 15.991zM259.066-59.334h476.677l-5.309 86.908c-142.18-0.096-314.246-0.198-471.368-0.294z" />
|
||||
<glyph unicode="" glyph-name="armor_stand_small" d="M479.778 452.094h82.515v189.025l2.23 123.553-84.745-1.056zM327.961 371.667h378.741l-4.218 94.8c-112.968-0.107-249.682-0.214-374.523-0.321zM381.959 57.137h97.532v206.337l2.636 134.868-100.168-1.153zM562.27 57.213h93.76v203.030l2.534 132.707-96.294-1.134zM836.627 10.238l86.879 19.613-85.264 277.283-53.383 181.771-88.751-21.692zM97.998 23.838l93.728-14.563 88.856 276.676 60.613 180.451-96.757 13.411zM323.191 1.42h379.279l-4.224 71.322c-113.129-0.077-250.037-0.16-375.056-0.243z" />
|
||||
<glyph unicode="" glyph-name="ground" d="M501.5 550.875c-33.116-2.315-53.035-4.943-95.25-29.25-15.568-8.964-30.113-23.073-47.25-41.625s-35.618-41.233-52.75-65.625c-34.264-48.785-65.701-100.914-64-150.875 0.844-24.773 12.521-46.84 29-62.875s37.425-27.263 60.5-35.875c50.816-14.145 52.303-18.359 147.125-24.25l0.625-0.128c25.804-0.64 42.145-1.3 80.25-2.125 78.857 1.225 134.386 16.463 172.875 39s60.511 49.945 62.75 80.625c2.101 28.792-10.411 55.18-26.25 85.878s-36.78 63.148-58 91.25l-0.75 1-0.75 0.875c-36.096 39.749-68.488 93.859-135.125 110.875-19.978 5.102-38.802 5.516-73 3.125zM74.5 84.875c0-33.292 0-66.583 0-99.875h860.75v99.875z" />
|
||||
<glyph unicode="" glyph-name="hud" d="M8.75 177.75v-188.125h1012v188.125zM43 143.5h943.625v-119.625h-943.625zM10.75 323v-74.375h473.625v74.375zM520.5 322v-73.125h499.25v73.125zM9 409.625c0-22.333 0-44.667 0-67h473.25v67zM7.5 232.875v-42.25h1012.625v42.25z" />
|
||||
<glyph unicode="" glyph-name="inventory_full" d="M756.75 725.625v-108.5h105.75v108.5zM781.125 701.25h57v-59.75h-57zM89.125 164.125v-32h842.875v32zM182 884.875v-432.625h32v432.625zM517.125 759.625v-173.625h179.125v173.625zM541.5 735.25h130.375v-124.875h-130.375zM380.25 922.75c0-165.042 0-330.083 0-495.125h587.625v495.125zM437.875 865.25h472.375v-380h-472.375zM47.625 920.75v-493.125h390.25v493.125zM105.125 863.25h275.125v-378h-275.125zM47.625 485.25v-493.25h920.25v493.25zM105.125 427.625h805.125v-378h-805.125z" />
|
||||
<glyph unicode="" glyph-name="inventory_nine" d="M376.25 308.25h293.5v284.125c-349.612 19.848-293.5 0.814-293.5-284.125zM365.125 907.625l7.5-900.125 306.875 2.625-7.375 886.375-16.5 0.625zM399.75 872l238.125-8.75 6.875-819-238-2zM90 598.375l-0.75-16.5-12.875-293h891.875v309.5zM122.875 563.875h811v-240.625h-821.625zM67.625 910.375v-915.25h910.125v915.25zM123.625 854.375h798.125v-803.25h-798.125z" />
|
||||
<glyph unicode="" glyph-name="inventory_single" d="M86.75 887.25v-873h875.75v873zM164.5 809.5h720.375v-717.5h-720.375z" />
|
||||
<glyph unicode="" glyph-name="player_head" d="M146 216.25l-91.625-282.875 912.5-2.003-71.25 284.875zM302.625 646l-15.875-414.625h28.5l469.625 0.625-11.875 414zM355.25 591.25h364.625l8.75-304.5-385-0.627z" />
|
||||
<glyph unicode="" glyph-name="zombie" d="M428.375 922.875l-8.5-404.75 81.625-4.125-5.625-14.25c-289.841 20.179-359.5 23.25-359.5 23.25l-37.875-0.875-0.75-169.25 409.375-32.375-3.125-375h212l34.5 552.25 109.125 3.375 12.125 417.375z" />
|
||||
</font></defs></svg>
|
After Width: | Height: | Size: 4.4 KiB |
BIN
font/icomoon.ttf
Normal file
BIN
font/icomoon.woff
Normal file
552
js/JSONLoader.js
Normal file
@ -0,0 +1,552 @@
|
||||
import { Loader } from './Loader';
|
||||
import { AnimationClip } from '../animation/AnimationClip';
|
||||
import { Vector3 } from '../math/Vector3';
|
||||
import { Vector4 } from '../math/Vector4';
|
||||
import { Color } from '../math/Color';
|
||||
import { Vector2 } from '../math/Vector2';
|
||||
import { Face3 } from '../core/Face3';
|
||||
import { Geometry } from '../core/Geometry';
|
||||
import { FileLoader } from './FileLoader';
|
||||
import { DefaultLoadingManager } from './LoadingManager';
|
||||
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
*/
|
||||
|
||||
function JSONLoader( manager ) {
|
||||
|
||||
if ( typeof manager === 'boolean' ) {
|
||||
|
||||
console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
|
||||
manager = undefined;
|
||||
|
||||
}
|
||||
|
||||
this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
|
||||
|
||||
this.withCredentials = false;
|
||||
|
||||
}
|
||||
|
||||
Object.assign( JSONLoader.prototype, {
|
||||
|
||||
load: function( url, onLoad, onProgress, onError ) {
|
||||
|
||||
var scope = this;
|
||||
|
||||
var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : Loader.prototype.extractUrlBase( url );
|
||||
|
||||
var loader = new FileLoader( this.manager );
|
||||
loader.setWithCredentials( this.withCredentials );
|
||||
loader.load( url, function ( text ) {
|
||||
|
||||
var json = JSON.parse( text );
|
||||
var metadata = json.metadata;
|
||||
|
||||
if ( metadata !== undefined ) {
|
||||
|
||||
var type = metadata.type;
|
||||
|
||||
if ( type !== undefined ) {
|
||||
|
||||
if ( type.toLowerCase() === 'object' ) {
|
||||
|
||||
console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if ( type.toLowerCase() === 'scene' ) {
|
||||
|
||||
console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var object = scope.parse( json, texturePath );
|
||||
onLoad( object.geometry, object.materials );
|
||||
|
||||
}, onProgress, onError );
|
||||
|
||||
},
|
||||
|
||||
setTexturePath: function ( value ) {
|
||||
|
||||
this.texturePath = value;
|
||||
|
||||
},
|
||||
|
||||
parse: function ( json, texturePath ) {
|
||||
|
||||
var geometry = new Geometry(),
|
||||
scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
|
||||
|
||||
parseModel( scale );
|
||||
|
||||
parseSkin();
|
||||
parseMorphing( scale );
|
||||
parseAnimations();
|
||||
|
||||
geometry.computeFaceNormals();
|
||||
geometry.computeBoundingSphere();
|
||||
|
||||
function parseModel( scale ) {
|
||||
|
||||
function isBitSet( value, position ) {
|
||||
|
||||
return value & ( 1 << position );
|
||||
|
||||
}
|
||||
|
||||
var i, j, fi,
|
||||
|
||||
offset, zLength,
|
||||
|
||||
colorIndex, normalIndex, uvIndex, materialIndex,
|
||||
|
||||
type,
|
||||
isQuad,
|
||||
hasMaterial,
|
||||
hasFaceVertexUv,
|
||||
hasFaceNormal, hasFaceVertexNormal,
|
||||
hasFaceColor, hasFaceVertexColor,
|
||||
|
||||
vertex, face, faceA, faceB, hex, normal,
|
||||
|
||||
uvLayer, uv, u, v,
|
||||
|
||||
faces = json.faces,
|
||||
vertices = json.vertices,
|
||||
normals = json.normals,
|
||||
colors = json.colors,
|
||||
|
||||
nUvLayers = 0;
|
||||
|
||||
if ( json.uvs !== undefined ) {
|
||||
|
||||
// disregard empty arrays
|
||||
|
||||
for ( i = 0; i < json.uvs.length; i ++ ) {
|
||||
|
||||
if ( json.uvs[ i ].length ) nUvLayers ++;
|
||||
|
||||
}
|
||||
|
||||
for ( i = 0; i < nUvLayers; i ++ ) {
|
||||
|
||||
geometry.faceVertexUvs[ i ] = [];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
zLength = vertices.length;
|
||||
|
||||
while ( offset < zLength ) {
|
||||
|
||||
vertex = new Vector3();
|
||||
|
||||
vertex.x = vertices[ offset ++ ] * scale;
|
||||
vertex.y = vertices[ offset ++ ] * scale;
|
||||
vertex.z = vertices[ offset ++ ] * scale;
|
||||
|
||||
geometry.vertices.push( vertex );
|
||||
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
zLength = faces.length;
|
||||
|
||||
while ( offset < zLength ) {
|
||||
|
||||
type = faces[ offset ++ ];
|
||||
|
||||
|
||||
isQuad = isBitSet( type, 0 );
|
||||
hasMaterial = isBitSet( type, 1 );
|
||||
hasFaceVertexUv = isBitSet( type, 3 );
|
||||
hasFaceNormal = isBitSet( type, 4 );
|
||||
hasFaceVertexNormal = isBitSet( type, 5 );
|
||||
hasFaceColor = isBitSet( type, 6 );
|
||||
hasFaceVertexColor = isBitSet( type, 7 );
|
||||
|
||||
// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
|
||||
|
||||
if ( isQuad ) {
|
||||
|
||||
faceA = new Face3();
|
||||
faceA.a = faces[ offset ];
|
||||
faceA.b = faces[ offset + 1 ];
|
||||
faceA.c = faces[ offset + 3 ];
|
||||
|
||||
faceB = new Face3();
|
||||
faceB.a = faces[ offset + 1 ];
|
||||
faceB.b = faces[ offset + 2 ];
|
||||
faceB.c = faces[ offset + 3 ];
|
||||
|
||||
offset += 4;
|
||||
|
||||
if ( hasMaterial ) {
|
||||
|
||||
materialIndex = faces[ offset ++ ];
|
||||
faceA.materialIndex = materialIndex;
|
||||
faceB.materialIndex = materialIndex;
|
||||
|
||||
}
|
||||
|
||||
// to get face <=> uv index correspondence
|
||||
|
||||
fi = geometry.faces.length;
|
||||
|
||||
if ( hasFaceVertexUv ) {
|
||||
|
||||
for ( i = 0; i < nUvLayers; i ++ ) {
|
||||
|
||||
uvLayer = json.uvs[ i ];
|
||||
|
||||
geometry.faceVertexUvs[ i ][ fi ] = [];
|
||||
geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
|
||||
|
||||
for ( j = 0; j < 4; j ++ ) {
|
||||
|
||||
uvIndex = faces[ offset ++ ];
|
||||
|
||||
u = uvLayer[ uvIndex * 2 ];
|
||||
v = uvLayer[ uvIndex * 2 + 1 ];
|
||||
|
||||
uv = new Vector2( u, v );
|
||||
|
||||
if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
|
||||
if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( hasFaceNormal ) {
|
||||
|
||||
normalIndex = faces[ offset ++ ] * 3;
|
||||
|
||||
faceA.normal.set(
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ]
|
||||
);
|
||||
|
||||
faceB.normal.copy( faceA.normal );
|
||||
|
||||
}
|
||||
|
||||
if ( hasFaceVertexNormal ) {
|
||||
|
||||
for ( i = 0; i < 4; i ++ ) {
|
||||
|
||||
normalIndex = faces[ offset ++ ] * 3;
|
||||
|
||||
normal = new Vector3(
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ]
|
||||
);
|
||||
|
||||
|
||||
if ( i !== 2 ) faceA.vertexNormals.push( normal );
|
||||
if ( i !== 0 ) faceB.vertexNormals.push( normal );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( hasFaceColor ) {
|
||||
|
||||
colorIndex = faces[ offset ++ ];
|
||||
hex = colors[ colorIndex ];
|
||||
|
||||
faceA.color.setHex( hex );
|
||||
faceB.color.setHex( hex );
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( hasFaceVertexColor ) {
|
||||
|
||||
for ( i = 0; i < 4; i ++ ) {
|
||||
|
||||
colorIndex = faces[ offset ++ ];
|
||||
hex = colors[ colorIndex ];
|
||||
|
||||
if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );
|
||||
if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
geometry.faces.push( faceA );
|
||||
geometry.faces.push( faceB );
|
||||
|
||||
} else {
|
||||
|
||||
face = new Face3();
|
||||
face.a = faces[ offset ++ ];
|
||||
face.b = faces[ offset ++ ];
|
||||
face.c = faces[ offset ++ ];
|
||||
|
||||
if ( hasMaterial ) {
|
||||
|
||||
materialIndex = faces[ offset ++ ];
|
||||
face.materialIndex = materialIndex;
|
||||
|
||||
}
|
||||
|
||||
// to get face <=> uv index correspondence
|
||||
|
||||
fi = geometry.faces.length;
|
||||
|
||||
if ( hasFaceVertexUv ) {
|
||||
|
||||
for ( i = 0; i < nUvLayers; i ++ ) {
|
||||
|
||||
uvLayer = json.uvs[ i ];
|
||||
|
||||
geometry.faceVertexUvs[ i ][ fi ] = [];
|
||||
|
||||
for ( j = 0; j < 3; j ++ ) {
|
||||
|
||||
uvIndex = faces[ offset ++ ];
|
||||
|
||||
u = uvLayer[ uvIndex * 2 ];
|
||||
v = uvLayer[ uvIndex * 2 + 1 ];
|
||||
|
||||
uv = new Vector2( u, v );
|
||||
|
||||
geometry.faceVertexUvs[ i ][ fi ].push( uv );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( hasFaceNormal ) {
|
||||
|
||||
normalIndex = faces[ offset ++ ] * 3;
|
||||
|
||||
face.normal.set(
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( hasFaceVertexNormal ) {
|
||||
|
||||
for ( i = 0; i < 3; i ++ ) {
|
||||
|
||||
normalIndex = faces[ offset ++ ] * 3;
|
||||
|
||||
normal = new Vector3(
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ++ ],
|
||||
normals[ normalIndex ]
|
||||
);
|
||||
|
||||
face.vertexNormals.push( normal );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( hasFaceColor ) {
|
||||
|
||||
colorIndex = faces[ offset ++ ];
|
||||
face.color.setHex( colors[ colorIndex ] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( hasFaceVertexColor ) {
|
||||
|
||||
for ( i = 0; i < 3; i ++ ) {
|
||||
|
||||
colorIndex = faces[ offset ++ ];
|
||||
face.vertexColors.push( new Color( colors[ colorIndex ] ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
geometry.faces.push( face );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function parseSkin() {
|
||||
|
||||
var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
|
||||
|
||||
if ( json.skinWeights ) {
|
||||
|
||||
for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
|
||||
|
||||
var x = json.skinWeights[ i ];
|
||||
var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
|
||||
var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
|
||||
var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
|
||||
|
||||
geometry.skinWeights.push( new Vector4( x, y, z, w ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( json.skinIndices ) {
|
||||
|
||||
for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
|
||||
|
||||
var a = json.skinIndices[ i ];
|
||||
var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
|
||||
var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
|
||||
var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
|
||||
|
||||
geometry.skinIndices.push( new Vector4( a, b, c, d ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
geometry.bones = json.bones;
|
||||
|
||||
if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
|
||||
|
||||
console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
|
||||
geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function parseMorphing( scale ) {
|
||||
|
||||
if ( json.morphTargets !== undefined ) {
|
||||
|
||||
for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
|
||||
|
||||
geometry.morphTargets[ i ] = {};
|
||||
geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
|
||||
geometry.morphTargets[ i ].vertices = [];
|
||||
|
||||
var dstVertices = geometry.morphTargets[ i ].vertices;
|
||||
var srcVertices = json.morphTargets[ i ].vertices;
|
||||
|
||||
for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
|
||||
|
||||
var vertex = new Vector3();
|
||||
vertex.x = srcVertices[ v ] * scale;
|
||||
vertex.y = srcVertices[ v + 1 ] * scale;
|
||||
vertex.z = srcVertices[ v + 2 ] * scale;
|
||||
|
||||
dstVertices.push( vertex );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
|
||||
|
||||
console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
|
||||
|
||||
var faces = geometry.faces;
|
||||
var morphColors = json.morphColors[ 0 ].colors;
|
||||
|
||||
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
||||
|
||||
faces[ i ].color.fromArray( morphColors, i * 3 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function parseAnimations() {
|
||||
|
||||
var outputAnimations = [];
|
||||
|
||||
// parse old style Bone/Hierarchy animations
|
||||
var animations = [];
|
||||
|
||||
if ( json.animation !== undefined ) {
|
||||
|
||||
animations.push( json.animation );
|
||||
|
||||
}
|
||||
|
||||
if ( json.animations !== undefined ) {
|
||||
|
||||
if ( json.animations.length ) {
|
||||
|
||||
animations = animations.concat( json.animations );
|
||||
|
||||
} else {
|
||||
|
||||
animations.push( json.animations );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( var i = 0; i < animations.length; i ++ ) {
|
||||
|
||||
var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
|
||||
if ( clip ) outputAnimations.push( clip );
|
||||
|
||||
}
|
||||
|
||||
// parse implicit morph animations
|
||||
if ( geometry.morphTargets ) {
|
||||
|
||||
// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
|
||||
var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
|
||||
outputAnimations = outputAnimations.concat( morphAnimationClips );
|
||||
|
||||
}
|
||||
|
||||
if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
|
||||
|
||||
}
|
||||
|
||||
if ( json.materials === undefined || json.materials.length === 0 ) {
|
||||
|
||||
return { geometry: geometry };
|
||||
|
||||
} else {
|
||||
|
||||
var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin );
|
||||
|
||||
return { geometry: geometry, materials: materials };
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { JSONLoader };
|
212
js/OBJExporter.js
Normal file
@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
THREE.OBJExporter = function () {};
|
||||
|
||||
THREE.OBJExporter.prototype = {
|
||||
|
||||
constructor: THREE.OBJExporter,
|
||||
|
||||
parse: function ( object, mtlFileName ) {
|
||||
|
||||
var output = '';
|
||||
var materials = {};
|
||||
|
||||
var indexVertex = 0;
|
||||
var indexVertexUvs = 0;
|
||||
var indexNormals = 0;
|
||||
|
||||
output += 'mtllib ' + mtlFileName + '.mtl\n';
|
||||
|
||||
var parseMesh = function ( mesh ) {
|
||||
|
||||
var nbVertex = 0;
|
||||
var nbVertexUvs = 0;
|
||||
var nbNormals = 0;
|
||||
|
||||
var geometry = mesh.geometry;
|
||||
var element = TreeElements.findRecursive('uuid', mesh.name)
|
||||
|
||||
if (element === undefined) return;
|
||||
if (element.display.export === false) return;
|
||||
|
||||
if ( geometry instanceof THREE.Geometry ) {
|
||||
|
||||
output += 'o ' + mesh.name + '\n';
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
|
||||
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
|
||||
|
||||
var vertex = vertices[ i ].clone();
|
||||
vertex.applyMatrix4( mesh.matrixWorld );
|
||||
|
||||
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
|
||||
|
||||
nbVertex ++;
|
||||
|
||||
}
|
||||
|
||||
// uvs
|
||||
|
||||
var faces = geometry.faces;
|
||||
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
|
||||
var hasVertexUvs = faces.length === faceVertexUvs.length;
|
||||
|
||||
if ( hasVertexUvs ) {
|
||||
|
||||
for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {
|
||||
|
||||
var vertexUvs = faceVertexUvs[ i ];
|
||||
|
||||
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
|
||||
|
||||
var uv = vertexUvs[ j ];
|
||||
|
||||
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
|
||||
|
||||
nbVertexUvs ++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// normals
|
||||
|
||||
var normalMatrixWorld = new THREE.Matrix3();
|
||||
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
|
||||
|
||||
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
||||
|
||||
var face = faces[ i ];
|
||||
var vertexNormals = face.vertexNormals;
|
||||
|
||||
if ( vertexNormals.length === 3 ) {
|
||||
|
||||
for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {
|
||||
|
||||
var normal = vertexNormals[ j ].clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
nbNormals ++;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var normal = face.normal.clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
for ( var j = 0; j < 3; j ++ ) {
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
nbNormals ++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// material
|
||||
for (var key in element.faces) {
|
||||
if (element.faces.hasOwnProperty(key)) {
|
||||
var id = element.faces[key].texture
|
||||
if (id !== undefined && id !== '$transparent') {
|
||||
id = id.replace('#', '')
|
||||
if (materials[id] === undefined) {
|
||||
materials[id] = getTextureById(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
|
||||
|
||||
var face = faces[ i ];
|
||||
|
||||
if (i % 2 === 0) {
|
||||
output += getMtlFace(element, i)
|
||||
}
|
||||
|
||||
output += 'f ';
|
||||
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
|
||||
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
|
||||
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', mesh );
|
||||
// TODO: Support only BufferGeometry and use use setFromObject()
|
||||
|
||||
}
|
||||
|
||||
// update index
|
||||
indexVertex += nbVertex;
|
||||
indexVertexUvs += nbVertexUvs;
|
||||
indexNormals += nbNormals;
|
||||
|
||||
};
|
||||
|
||||
object.traverse( function ( child ) {
|
||||
|
||||
if ( child instanceof THREE.Mesh ) parseMesh( child );
|
||||
|
||||
} );
|
||||
|
||||
// mtl output
|
||||
|
||||
var mtlOutput = '';
|
||||
|
||||
for (var key in materials) {
|
||||
if (materials.hasOwnProperty(key) && materials[key]) {
|
||||
mtlOutput += 'newmtl ' +key+ '\n'
|
||||
mtlOutput += 'map_Kd '+ materials[key].name +'\n';
|
||||
//mtlOutput += 'illum 2\n';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
obj: output,
|
||||
mtl: mtlOutput,
|
||||
images: materials
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
function getMtlFace(obj, index) {
|
||||
if (index % 2 == 1) index--;
|
||||
var key = 'north'
|
||||
switch (index) {
|
||||
case 10: key = 'north'; break;
|
||||
case 0: key = 'east'; break;
|
||||
case 8: key = 'south'; break;
|
||||
case 2: key = 'west'; break;
|
||||
case 4: key = 'up'; break;
|
||||
case 6: key = 'down'; break;
|
||||
}
|
||||
|
||||
var id = obj.faces[key].texture
|
||||
|
||||
if (id === '$transparent') {
|
||||
return 'usemtl none'
|
||||
} else if (id === undefined) {
|
||||
return 'usemtl none'
|
||||
} else {
|
||||
id = id.replace('#', '')
|
||||
return 'usemtl ' + id + '\n';
|
||||
}
|
||||
}
|
1067
js/OrbitControls.js
Normal file
127
js/OrthographicCamera.js
Normal file
@ -0,0 +1,127 @@
|
||||
import { Camera } from './Camera';
|
||||
import { Object3D } from '../core/Object3D';
|
||||
|
||||
/**
|
||||
* @author alteredq / http://alteredqualia.com/
|
||||
* @author arose / http://github.com/arose
|
||||
*/
|
||||
|
||||
function OrthographicCamera( left, right, top, bottom, near, far ) {
|
||||
|
||||
Camera.call( this );
|
||||
|
||||
this.type = 'OrthographicCamera';
|
||||
|
||||
this.zoom = 1;
|
||||
this.view = null;
|
||||
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.top = top;
|
||||
this.bottom = bottom;
|
||||
|
||||
this.near = ( near !== undefined ) ? near : 0.1;
|
||||
this.far = ( far !== undefined ) ? far : 2000;
|
||||
|
||||
this.updateProjectionMatrix();
|
||||
|
||||
}
|
||||
|
||||
OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
|
||||
|
||||
constructor: OrthographicCamera,
|
||||
|
||||
isOrthographicCamera: true,
|
||||
|
||||
copy: function ( source ) {
|
||||
|
||||
Camera.prototype.copy.call( this, source );
|
||||
|
||||
this.left = source.left;
|
||||
this.right = source.right;
|
||||
this.top = source.top;
|
||||
this.bottom = source.bottom;
|
||||
this.near = source.near;
|
||||
this.far = source.far;
|
||||
|
||||
this.zoom = source.zoom;
|
||||
this.view = source.view === null ? null : Object.assign( {}, source.view );
|
||||
|
||||
return this;
|
||||
|
||||
},
|
||||
|
||||
setViewOffset: function( fullWidth, fullHeight, x, y, width, height ) {
|
||||
|
||||
this.view = {
|
||||
fullWidth: fullWidth,
|
||||
fullHeight: fullHeight,
|
||||
offsetX: x,
|
||||
offsetY: y,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
this.updateProjectionMatrix();
|
||||
|
||||
},
|
||||
|
||||
clearViewOffset: function() {
|
||||
|
||||
this.view = null;
|
||||
this.updateProjectionMatrix();
|
||||
|
||||
},
|
||||
|
||||
updateProjectionMatrix: function () {
|
||||
|
||||
var dx = ( this.right - this.left ) / ( 2 * this.zoom );
|
||||
var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
|
||||
var cx = ( this.right + this.left ) / 2;
|
||||
var cy = ( this.top + this.bottom ) / 2;
|
||||
|
||||
var left = cx - dx;
|
||||
var right = cx + dx;
|
||||
var top = cy + dy;
|
||||
var bottom = cy - dy;
|
||||
|
||||
if ( this.view !== null ) {
|
||||
|
||||
var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
|
||||
var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
|
||||
var scaleW = ( this.right - this.left ) / this.view.width;
|
||||
var scaleH = ( this.top - this.bottom ) / this.view.height;
|
||||
|
||||
left += scaleW * ( this.view.offsetX / zoomW );
|
||||
right = left + scaleW * ( this.view.width / zoomW );
|
||||
top -= scaleH * ( this.view.offsetY / zoomH );
|
||||
bottom = top - scaleH * ( this.view.height / zoomH );
|
||||
|
||||
}
|
||||
|
||||
this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
|
||||
|
||||
},
|
||||
|
||||
toJSON: function ( meta ) {
|
||||
|
||||
var data = Object3D.prototype.toJSON.call( this, meta );
|
||||
|
||||
data.object.zoom = this.zoom;
|
||||
data.object.left = this.left;
|
||||
data.object.right = this.right;
|
||||
data.object.top = this.top;
|
||||
data.object.bottom = this.bottom;
|
||||
data.object.near = this.near;
|
||||
data.object.far = this.far;
|
||||
|
||||
if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
|
||||
export { OrthographicCamera };
|
477
js/THREE.MeshLine.js
Normal file
@ -0,0 +1,477 @@
|
||||
;(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
var root = this
|
||||
|
||||
var has_require = typeof require !== 'undefined'
|
||||
|
||||
var THREE = root.THREE || has_require && require('three')
|
||||
if( !THREE )
|
||||
throw new Error( 'MeshLine requires three.js' )
|
||||
|
||||
function MeshLine() {
|
||||
|
||||
this.positions = [];
|
||||
|
||||
this.previous = [];
|
||||
this.next = [];
|
||||
this.side = [];
|
||||
this.width = [];
|
||||
this.indices_array = [];
|
||||
this.uvs = [];
|
||||
this.counters = [];
|
||||
this.geometry = new THREE.BufferGeometry();
|
||||
|
||||
this.widthCallback = null;
|
||||
|
||||
}
|
||||
|
||||
MeshLine.prototype.setGeometry = function( g, c ) {
|
||||
|
||||
this.widthCallback = c;
|
||||
|
||||
this.positions = [];
|
||||
this.counters = [];
|
||||
|
||||
if( g instanceof THREE.Geometry ) {
|
||||
for( var j = 0; j < g.vertices.length; j++ ) {
|
||||
var v = g.vertices[ j ];
|
||||
var c = j/g.vertices.length;
|
||||
this.positions.push( v.x, v.y, v.z );
|
||||
this.positions.push( v.x, v.y, v.z );
|
||||
this.counters.push(c);
|
||||
this.counters.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
if( g instanceof THREE.BufferGeometry ) {
|
||||
// read attribute positions ?
|
||||
}
|
||||
|
||||
if( g instanceof Float32Array || g instanceof Array ) {
|
||||
for( var j = 0; j < g.length; j += 3 ) {
|
||||
var c = j/g.length;
|
||||
this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
|
||||
this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
|
||||
this.counters.push(c);
|
||||
this.counters.push(c);
|
||||
}
|
||||
}
|
||||
|
||||
this.process();
|
||||
|
||||
}
|
||||
|
||||
MeshLine.prototype.compareV3 = function( a, b ) {
|
||||
|
||||
var aa = a * 6;
|
||||
var ab = b * 6;
|
||||
return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] );
|
||||
|
||||
}
|
||||
|
||||
MeshLine.prototype.copyV3 = function( a ) {
|
||||
|
||||
var aa = a * 6;
|
||||
return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ];
|
||||
|
||||
}
|
||||
|
||||
MeshLine.prototype.process = function() {
|
||||
|
||||
var l = this.positions.length / 6;
|
||||
|
||||
this.previous = [];
|
||||
this.next = [];
|
||||
this.side = [];
|
||||
this.width = [];
|
||||
this.indices_array = [];
|
||||
this.uvs = [];
|
||||
|
||||
for( var j = 0; j < l; j++ ) {
|
||||
this.side.push( 1 );
|
||||
this.side.push( -1 );
|
||||
}
|
||||
|
||||
var w;
|
||||
for( var j = 0; j < l; j++ ) {
|
||||
if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) );
|
||||
else w = 1;
|
||||
this.width.push( w );
|
||||
this.width.push( w );
|
||||
}
|
||||
|
||||
for( var j = 0; j < l; j++ ) {
|
||||
this.uvs.push( j / ( l - 1 ), 0 );
|
||||
this.uvs.push( j / ( l - 1 ), 1 );
|
||||
}
|
||||
|
||||
var v;
|
||||
|
||||
if( this.compareV3( 0, l - 1 ) ){
|
||||
v = this.copyV3( l - 2 );
|
||||
} else {
|
||||
v = this.copyV3( 0 );
|
||||
}
|
||||
this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
for( var j = 0; j < l - 1; j++ ) {
|
||||
v = this.copyV3( j );
|
||||
this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
}
|
||||
|
||||
for( var j = 1; j < l; j++ ) {
|
||||
v = this.copyV3( j );
|
||||
this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
}
|
||||
|
||||
if( this.compareV3( l - 1, 0 ) ){
|
||||
v = this.copyV3( 1 );
|
||||
} else {
|
||||
v = this.copyV3( l - 1 );
|
||||
}
|
||||
this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
|
||||
|
||||
for( var j = 0; j < l - 1; j++ ) {
|
||||
var n = j * 2;
|
||||
this.indices_array.push( n, n + 1, n + 2 );
|
||||
this.indices_array.push( n + 2, n + 1, n + 3 );
|
||||
}
|
||||
|
||||
if (!this.attributes) {
|
||||
this.attributes = {
|
||||
position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ),
|
||||
previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ),
|
||||
next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ),
|
||||
side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ),
|
||||
width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ),
|
||||
uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ),
|
||||
index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 ),
|
||||
counters: new THREE.BufferAttribute( new Float32Array( this.counters ), 1 )
|
||||
}
|
||||
} else {
|
||||
this.attributes.position.copyArray(new Float32Array(this.positions));
|
||||
this.attributes.position.needsUpdate = true;
|
||||
this.attributes.previous.copyArray(new Float32Array(this.previous));
|
||||
this.attributes.previous.needsUpdate = true;
|
||||
this.attributes.next.copyArray(new Float32Array(this.next));
|
||||
this.attributes.next.needsUpdate = true;
|
||||
this.attributes.side.copyArray(new Float32Array(this.side));
|
||||
this.attributes.side.needsUpdate = true;
|
||||
this.attributes.width.copyArray(new Float32Array(this.width));
|
||||
this.attributes.width.needsUpdate = true;
|
||||
this.attributes.uv.copyArray(new Float32Array(this.uvs));
|
||||
this.attributes.uv.needsUpdate = true;
|
||||
this.attributes.index.copyArray(new Uint16Array(this.indices_array));
|
||||
this.attributes.index.needsUpdate = true;
|
||||
}
|
||||
|
||||
this.geometry.addAttribute( 'position', this.attributes.position );
|
||||
this.geometry.addAttribute( 'previous', this.attributes.previous );
|
||||
this.geometry.addAttribute( 'next', this.attributes.next );
|
||||
this.geometry.addAttribute( 'side', this.attributes.side );
|
||||
this.geometry.addAttribute( 'width', this.attributes.width );
|
||||
this.geometry.addAttribute( 'uv', this.attributes.uv );
|
||||
this.geometry.addAttribute( 'counters', this.attributes.counters );
|
||||
|
||||
this.geometry.setIndex( this.attributes.index );
|
||||
|
||||
}
|
||||
|
||||
function memcpy (src, srcOffset, dst, dstOffset, length) {
|
||||
var i
|
||||
|
||||
src = src.subarray || src.slice ? src : src.buffer
|
||||
dst = dst.subarray || dst.slice ? dst : dst.buffer
|
||||
|
||||
src = srcOffset ? src.subarray ?
|
||||
src.subarray(srcOffset, length && srcOffset + length) :
|
||||
src.slice(srcOffset, length && srcOffset + length) : src
|
||||
|
||||
if (dst.set) {
|
||||
dst.set(src, dstOffset)
|
||||
} else {
|
||||
for (i=0; i<src.length; i++) {
|
||||
dst[i + dstOffset] = src[i]
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast method to advance the line by one position. The oldest position is removed.
|
||||
* @param position
|
||||
*/
|
||||
MeshLine.prototype.advance = function(position) {
|
||||
|
||||
var positions = this.attributes.position.array;
|
||||
var previous = this.attributes.previous.array;
|
||||
var next = this.attributes.next.array;
|
||||
var l = positions.length;
|
||||
|
||||
// PREVIOUS
|
||||
memcpy( positions, 0, previous, 0, l );
|
||||
|
||||
// POSITIONS
|
||||
memcpy( positions, 6, positions, 0, l - 6 );
|
||||
|
||||
positions[l - 6] = position.x;
|
||||
positions[l - 5] = position.y;
|
||||
positions[l - 4] = position.z;
|
||||
positions[l - 3] = position.x;
|
||||
positions[l - 2] = position.y;
|
||||
positions[l - 1] = position.z;
|
||||
|
||||
// NEXT
|
||||
memcpy( positions, 6, next, 0, l - 6 );
|
||||
|
||||
next[l - 6] = position.x;
|
||||
next[l - 5] = position.y;
|
||||
next[l - 4] = position.z;
|
||||
next[l - 3] = position.x;
|
||||
next[l - 2] = position.y;
|
||||
next[l - 1] = position.z;
|
||||
|
||||
this.attributes.position.needsUpdate = true;
|
||||
this.attributes.previous.needsUpdate = true;
|
||||
this.attributes.next.needsUpdate = true;
|
||||
|
||||
};
|
||||
|
||||
function MeshLineMaterial( parameters ) {
|
||||
|
||||
var vertexShaderSource = [
|
||||
'precision highp float;',
|
||||
'',
|
||||
'attribute vec3 position;',
|
||||
'attribute vec3 previous;',
|
||||
'attribute vec3 next;',
|
||||
'attribute float side;',
|
||||
'attribute float width;',
|
||||
'attribute vec2 uv;',
|
||||
'attribute float counters;',
|
||||
'',
|
||||
'uniform mat4 projectionMatrix;',
|
||||
'uniform mat4 modelViewMatrix;',
|
||||
'uniform vec2 resolution;',
|
||||
'uniform float lineWidth;',
|
||||
'uniform vec3 color;',
|
||||
'uniform float opacity;',
|
||||
'uniform float near;',
|
||||
'uniform float far;',
|
||||
'uniform float sizeAttenuation;',
|
||||
'',
|
||||
'varying vec2 vUV;',
|
||||
'varying vec4 vColor;',
|
||||
'varying float vCounters;',
|
||||
'',
|
||||
'vec2 fix( vec4 i, float aspect ) {',
|
||||
'',
|
||||
' vec2 res = i.xy / i.w;',
|
||||
' res.x *= aspect;',
|
||||
' vCounters = counters;',
|
||||
' return res;',
|
||||
'',
|
||||
'}',
|
||||
'',
|
||||
'void main() {',
|
||||
'',
|
||||
' float aspect = resolution.x / resolution.y;',
|
||||
' float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);',
|
||||
'',
|
||||
' vColor = vec4( color, opacity );',
|
||||
' vUV = uv;',
|
||||
'',
|
||||
' mat4 m = projectionMatrix * modelViewMatrix;',
|
||||
' vec4 finalPosition = m * vec4( position, 1.0 );',
|
||||
' vec4 prevPos = m * vec4( previous, 1.0 );',
|
||||
' vec4 nextPos = m * vec4( next, 1.0 );',
|
||||
'',
|
||||
' vec2 currentP = fix( finalPosition, aspect );',
|
||||
' vec2 prevP = fix( prevPos, aspect );',
|
||||
' vec2 nextP = fix( nextPos, aspect );',
|
||||
'',
|
||||
' float pixelWidth = finalPosition.w * pixelWidthRatio;',
|
||||
' float w = 1.8 * pixelWidth * lineWidth * width;',
|
||||
'',
|
||||
' if( sizeAttenuation == 1. ) {',
|
||||
' w = 1.8 * lineWidth * width;',
|
||||
' }',
|
||||
'',
|
||||
' vec2 dir;',
|
||||
' if( nextP == currentP ) dir = normalize( currentP - prevP );',
|
||||
' else if( prevP == currentP ) dir = normalize( nextP - currentP );',
|
||||
' else {',
|
||||
' vec2 dir1 = normalize( currentP - prevP );',
|
||||
' vec2 dir2 = normalize( nextP - currentP );',
|
||||
' dir = normalize( dir1 + dir2 );',
|
||||
'',
|
||||
' vec2 perp = vec2( -dir1.y, dir1.x );',
|
||||
' vec2 miter = vec2( -dir.y, dir.x );',
|
||||
' //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );',
|
||||
'',
|
||||
' }',
|
||||
'',
|
||||
' //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;',
|
||||
' vec2 normal = vec2( -dir.y, dir.x );',
|
||||
' normal.x /= aspect;',
|
||||
' normal *= .5 * w;',
|
||||
'',
|
||||
' vec4 offset = vec4( normal * side, 0.0, 1.0 );',
|
||||
' finalPosition.xy += offset.xy;',
|
||||
'',
|
||||
' gl_Position = finalPosition;',
|
||||
'',
|
||||
'}' ];
|
||||
|
||||
var fragmentShaderSource = [
|
||||
'#extension GL_OES_standard_derivatives : enable',
|
||||
'precision mediump float;',
|
||||
'',
|
||||
'uniform sampler2D map;',
|
||||
'uniform sampler2D alphaMap;',
|
||||
'uniform float useMap;',
|
||||
'uniform float useAlphaMap;',
|
||||
'uniform float useDash;',
|
||||
'uniform vec2 dashArray;',
|
||||
'uniform float visibility;',
|
||||
'uniform float alphaTest;',
|
||||
'uniform vec2 repeat;',
|
||||
'',
|
||||
'varying vec2 vUV;',
|
||||
'varying vec4 vColor;',
|
||||
'varying float vCounters;',
|
||||
'',
|
||||
'void main() {',
|
||||
'',
|
||||
' vec4 c = vColor;',
|
||||
' if( useMap == 1. ) c *= texture2D( map, vUV * repeat );',
|
||||
' if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a;',
|
||||
' if( c.a < alphaTest ) discard;',
|
||||
' if( useDash == 1. ){',
|
||||
' ',
|
||||
' }',
|
||||
' gl_FragColor = c;',
|
||||
' gl_FragColor.a *= step(vCounters,visibility);',
|
||||
'}' ];
|
||||
|
||||
function check( v, d ) {
|
||||
if( v === undefined ) return d;
|
||||
return v;
|
||||
}
|
||||
|
||||
THREE.Material.call( this );
|
||||
|
||||
parameters = parameters || {};
|
||||
|
||||
this.lineWidth = check( parameters.lineWidth, 1 );
|
||||
this.map = check( parameters.map, null );
|
||||
this.useMap = check( parameters.useMap, 0 );
|
||||
this.alphaMap = check( parameters.alphaMap, null );
|
||||
this.useAlphaMap = check( parameters.useAlphaMap, 0 );
|
||||
this.color = check( parameters.color, new THREE.Color( 0xffffff ) );
|
||||
this.opacity = check( parameters.opacity, 1 );
|
||||
this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) );
|
||||
this.sizeAttenuation = check( parameters.sizeAttenuation, 1 );
|
||||
this.near = check( parameters.near, 1 );
|
||||
this.far = check( parameters.far, 1 );
|
||||
this.dashArray = check( parameters.dashArray, [] );
|
||||
this.useDash = ( this.dashArray !== [] ) ? 1 : 0;
|
||||
this.visibility = check( parameters.visibility, 1 );
|
||||
this.alphaTest = check( parameters.alphaTest, 0 );
|
||||
this.repeat = check( parameters.repeat, new THREE.Vector2( 1, 1 ) );
|
||||
|
||||
var material = new THREE.RawShaderMaterial( {
|
||||
uniforms:{
|
||||
lineWidth: { type: 'f', value: this.lineWidth },
|
||||
map: { type: 't', value: this.map },
|
||||
useMap: { type: 'f', value: this.useMap },
|
||||
alphaMap: { type: 't', value: this.alphaMap },
|
||||
useAlphaMap: { type: 'f', value: this.useAlphaMap },
|
||||
color: { type: 'c', value: this.color },
|
||||
opacity: { type: 'f', value: this.opacity },
|
||||
resolution: { type: 'v2', value: this.resolution },
|
||||
sizeAttenuation: { type: 'f', value: this.sizeAttenuation },
|
||||
near: { type: 'f', value: this.near },
|
||||
far: { type: 'f', value: this.far },
|
||||
dashArray: { type: 'v2', value: new THREE.Vector2( this.dashArray[ 0 ], this.dashArray[ 1 ] ) },
|
||||
useDash: { type: 'f', value: this.useDash },
|
||||
visibility: {type: 'f', value: this.visibility},
|
||||
alphaTest: {type: 'f', value: this.alphaTest},
|
||||
repeat: { type: 'v2', value: this.repeat }
|
||||
},
|
||||
vertexShader: vertexShaderSource.join( '\r\n' ),
|
||||
fragmentShader: fragmentShaderSource.join( '\r\n' )
|
||||
});
|
||||
|
||||
delete parameters.lineWidth;
|
||||
delete parameters.map;
|
||||
delete parameters.useMap;
|
||||
delete parameters.alphaMap;
|
||||
delete parameters.useAlphaMap;
|
||||
delete parameters.color;
|
||||
delete parameters.opacity;
|
||||
delete parameters.resolution;
|
||||
delete parameters.sizeAttenuation;
|
||||
delete parameters.near;
|
||||
delete parameters.far;
|
||||
delete parameters.dashArray;
|
||||
delete parameters.visibility;
|
||||
delete parameters.alphaTest;
|
||||
delete parameters.repeat;
|
||||
|
||||
material.type = 'MeshLineMaterial';
|
||||
|
||||
material.setValues( parameters );
|
||||
|
||||
return material;
|
||||
|
||||
};
|
||||
|
||||
MeshLineMaterial.prototype = Object.create( THREE.Material.prototype );
|
||||
MeshLineMaterial.prototype.constructor = MeshLineMaterial;
|
||||
|
||||
MeshLineMaterial.prototype.copy = function ( source ) {
|
||||
|
||||
THREE.Material.prototype.copy.call( this, source );
|
||||
|
||||
this.lineWidth = source.lineWidth;
|
||||
this.map = source.map;
|
||||
this.useMap = source.useMap;
|
||||
this.alphaMap = source.alphaMap;
|
||||
this.useAlphaMap = source.useAlphaMap;
|
||||
this.color.copy( source.color );
|
||||
this.opacity = source.opacity;
|
||||
this.resolution.copy( source.resolution );
|
||||
this.sizeAttenuation = source.sizeAttenuation;
|
||||
this.near = source.near;
|
||||
this.far = source.far;
|
||||
this.dashArray.copy( source.dashArray );
|
||||
this.useDash = source.useDash;
|
||||
this.visibility = source.visibility;
|
||||
this.alphaTest = source.alphaTest;
|
||||
this.repeat.copy( source.repeat );
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
if( typeof exports !== 'undefined' ) {
|
||||
if( typeof module !== 'undefined' && module.exports ) {
|
||||
exports = module.exports = { MeshLine: MeshLine, MeshLineMaterial: MeshLineMaterial };
|
||||
}
|
||||
exports.MeshLine = MeshLine;
|
||||
exports.MeshLineMaterial = MeshLineMaterial;
|
||||
}
|
||||
else {
|
||||
root.MeshLine = MeshLine;
|
||||
root.MeshLineMaterial = MeshLineMaterial;
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
|
959
js/TransformControls.js
Normal file
@ -0,0 +1,959 @@
|
||||
/**
|
||||
* @author arodic / https://github.com/arodic
|
||||
*/
|
||||
|
||||
( function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var GizmoMaterial = function ( parameters ) {
|
||||
|
||||
THREE.MeshBasicMaterial.call( this );
|
||||
|
||||
this.depthTest = false;
|
||||
this.depthWrite = false;
|
||||
this.side = THREE.FrontSide;
|
||||
this.transparent = true;
|
||||
|
||||
this.setValues( parameters );
|
||||
|
||||
this.oldColor = this.color.clone();
|
||||
this.oldOpacity = this.opacity;
|
||||
|
||||
this.highlight = function( highlighted ) {
|
||||
|
||||
if ( highlighted ) {
|
||||
|
||||
this.color.setHex( parseInt(app_colors.accent.hex.replace('#', ''), 16) );
|
||||
this.opacity = 1;
|
||||
|
||||
} else {
|
||||
|
||||
this.color.copy( this.oldColor );
|
||||
this.opacity = this.oldOpacity;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
GizmoMaterial.prototype = Object.create( THREE.MeshBasicMaterial.prototype );
|
||||
GizmoMaterial.prototype.constructor = GizmoMaterial;
|
||||
|
||||
|
||||
var GizmoLineMaterial = function ( parameters ) {
|
||||
|
||||
THREE.LineBasicMaterial.call( this );
|
||||
|
||||
this.depthTest = false;
|
||||
this.depthWrite = false;
|
||||
this.transparent = true;
|
||||
this.linewidth = 1;
|
||||
|
||||
this.setValues( parameters );
|
||||
|
||||
this.oldColor = this.color.clone();
|
||||
this.oldOpacity = this.opacity;
|
||||
|
||||
this.highlight = function( highlighted ) {
|
||||
|
||||
if ( highlighted ) {
|
||||
|
||||
this.color.setHex( parseInt(app_colors.accent.hex.replace('#', ''), 16) );
|
||||
this.opacity = 1;
|
||||
|
||||
} else {
|
||||
|
||||
this.color.copy( this.oldColor );
|
||||
this.opacity = this.oldOpacity;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
GizmoLineMaterial.prototype = Object.create( THREE.LineBasicMaterial.prototype );
|
||||
GizmoLineMaterial.prototype.constructor = GizmoLineMaterial;
|
||||
|
||||
|
||||
var pickerMaterial = new GizmoMaterial( { visible: false, transparent: false } );
|
||||
|
||||
|
||||
THREE.TransformGizmo = function () {
|
||||
|
||||
var scope = this;
|
||||
|
||||
this.init = function () {
|
||||
|
||||
THREE.Object3D.call( this );
|
||||
|
||||
this.handles = new THREE.Object3D();
|
||||
this.pickers = new THREE.Object3D();
|
||||
this.planes = new THREE.Object3D();
|
||||
|
||||
this.add( this.handles );
|
||||
this.add( this.pickers );
|
||||
this.add( this.planes );
|
||||
|
||||
//// PLANES
|
||||
|
||||
var planeGeometry = new THREE.PlaneBufferGeometry( 50, 50, 2, 2 );
|
||||
var planeMaterial = new THREE.MeshBasicMaterial( { visible: false, side: THREE.DoubleSide } );
|
||||
|
||||
var planes = {
|
||||
"XY": new THREE.Mesh( planeGeometry, planeMaterial ),
|
||||
"YZ": new THREE.Mesh( planeGeometry, planeMaterial ),
|
||||
"XZ": new THREE.Mesh( planeGeometry, planeMaterial ),
|
||||
"XYZE": new THREE.Mesh( planeGeometry, planeMaterial )
|
||||
};
|
||||
|
||||
this.activePlane = planes[ "XYZE" ];
|
||||
|
||||
planes[ "YZ" ].rotation.set( 0, Math.PI / 2, 0 );
|
||||
planes[ "XZ" ].rotation.set( - Math.PI / 2, 0, 0 );
|
||||
|
||||
for ( var i in planes ) {
|
||||
|
||||
planes[ i ].name = i;
|
||||
this.planes.add( planes[ i ] );
|
||||
this.planes[ i ] = planes[ i ];
|
||||
|
||||
}
|
||||
|
||||
//// HANDLES AND PICKERS
|
||||
|
||||
var setupGizmos = function( gizmoMap, parent ) {
|
||||
|
||||
for ( var name in gizmoMap ) {
|
||||
|
||||
for ( i = gizmoMap[ name ].length; i --; ) {
|
||||
|
||||
var object = gizmoMap[ name ][ i ][ 0 ];
|
||||
var position = gizmoMap[ name ][ i ][ 1 ];
|
||||
var rotation = gizmoMap[ name ][ i ][ 2 ];
|
||||
|
||||
if (object.name.length === 0) {
|
||||
object.name = name;
|
||||
}
|
||||
object.renderDepth = 999
|
||||
|
||||
if ( position ) object.position.set( position[ 0 ], position[ 1 ], position[ 2 ] );
|
||||
if ( rotation ) object.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ] );
|
||||
|
||||
parent.add( object );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
setupGizmos( this.handleGizmos, this.handles );
|
||||
setupGizmos( this.pickerGizmos, this.pickers );
|
||||
|
||||
// reset Transformations
|
||||
|
||||
this.traverse( function ( child ) {
|
||||
|
||||
if ( child instanceof THREE.Mesh ) {
|
||||
|
||||
child.updateMatrix();
|
||||
|
||||
var tempGeometry = child.geometry.clone();
|
||||
tempGeometry.applyMatrix( child.matrix );
|
||||
child.geometry = tempGeometry;
|
||||
|
||||
child.position.set( 0, 0, 0 );
|
||||
child.rotation.set( 0, 0, 0 );
|
||||
child.scale.set( 1, 1, 1 );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
this.highlight = function ( axis ) {
|
||||
|
||||
this.traverse( function( child ) {
|
||||
|
||||
if ( child.material && child.material.highlight ) {
|
||||
|
||||
if ( child.name === axis ) {
|
||||
|
||||
child.material.highlight( true );
|
||||
|
||||
} else {
|
||||
|
||||
child.material.highlight( false );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
THREE.TransformGizmo.prototype = Object.create( THREE.Object3D.prototype );
|
||||
THREE.TransformGizmo.prototype.constructor = THREE.TransformGizmo;
|
||||
|
||||
THREE.TransformGizmo.prototype.update = function ( rotation, eye ) {
|
||||
|
||||
var vec1 = new THREE.Vector3( 0, 0, 0 );
|
||||
var vec2 = new THREE.Vector3( 0, 1, 0 );
|
||||
var lookAtMatrix = new THREE.Matrix4();
|
||||
|
||||
this.traverse( function( child ) {
|
||||
|
||||
if ( child.name.search( "E" ) !== - 1 ) {
|
||||
|
||||
child.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( eye, vec1, vec2 ) );
|
||||
|
||||
} else if ( child.name.search( "X" ) !== - 1 || child.name.search( "Y" ) !== - 1 || child.name.search( "Z" ) !== - 1 ) {
|
||||
|
||||
child.quaternion.setFromEuler( rotation );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
};
|
||||
|
||||
THREE.TransformGizmoTranslate = function () {
|
||||
|
||||
THREE.TransformGizmo.call( this );
|
||||
|
||||
var arrowGeometry = new THREE.Geometry();
|
||||
var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) );
|
||||
mesh.position.y = 0.5;
|
||||
mesh.updateMatrix();
|
||||
|
||||
arrowGeometry.merge( mesh.geometry, mesh.matrix );
|
||||
|
||||
var lineXGeometry = new THREE.BufferGeometry();
|
||||
lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
|
||||
lineXGeometry.name = 'gizmo_x'
|
||||
|
||||
var lineYGeometry = new THREE.BufferGeometry();
|
||||
lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
|
||||
lineYGeometry.name = 'gizmo_y'
|
||||
|
||||
var lineZGeometry = new THREE.BufferGeometry();
|
||||
lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
|
||||
lineZGeometry.name = 'gizmo_z'
|
||||
|
||||
this.handleGizmos = {
|
||||
X: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ],
|
||||
[ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ]
|
||||
],
|
||||
Y: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ],
|
||||
[ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ]
|
||||
],
|
||||
Z: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ],
|
||||
[ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ]
|
||||
]
|
||||
};
|
||||
|
||||
this.pickerGizmos = {
|
||||
X: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ]
|
||||
],
|
||||
Y: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ]
|
||||
],
|
||||
Z: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ]
|
||||
]
|
||||
};
|
||||
|
||||
this.setActivePlane = function ( axis, eye ) {
|
||||
|
||||
var tempMatrix = new THREE.Matrix4();
|
||||
eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) );
|
||||
|
||||
if ( axis === "X" ) {
|
||||
this.activePlane = this.planes[ "XY" ];
|
||||
if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ];
|
||||
}
|
||||
|
||||
if ( axis === "Y" ) {
|
||||
this.activePlane = this.planes[ "XY" ];
|
||||
if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ];
|
||||
}
|
||||
|
||||
if ( axis === "Z" ) {
|
||||
this.activePlane = this.planes[ "XZ" ];
|
||||
if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ];
|
||||
}
|
||||
};
|
||||
|
||||
this.init();
|
||||
|
||||
};
|
||||
|
||||
THREE.TransformGizmoTranslate.prototype = Object.create( THREE.TransformGizmo.prototype );
|
||||
THREE.TransformGizmoTranslate.prototype.constructor = THREE.TransformGizmoTranslate;
|
||||
|
||||
THREE.TransformGizmoScale = function () {
|
||||
|
||||
THREE.TransformGizmo.call( this );
|
||||
|
||||
var arrowGeometry = new THREE.Geometry();
|
||||
var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) );
|
||||
mesh.position.y = 0.5;
|
||||
mesh.updateMatrix();
|
||||
|
||||
arrowGeometry.merge( mesh.geometry, mesh.matrix );
|
||||
|
||||
var lineXGeometry = new THREE.BufferGeometry();
|
||||
lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) );
|
||||
|
||||
var lineYGeometry = new THREE.BufferGeometry();
|
||||
lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
|
||||
|
||||
var lineZGeometry = new THREE.BufferGeometry();
|
||||
lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
|
||||
|
||||
this.handleGizmos = {
|
||||
X: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ],
|
||||
[ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ],
|
||||
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ -1.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ],
|
||||
[ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ), [ -1, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ]
|
||||
],
|
||||
Y: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ],
|
||||
[ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ],
|
||||
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, -1.5, 0 ] ],
|
||||
[ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ), [ 0, -1, 0 ] ]
|
||||
],
|
||||
Z: [
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ],
|
||||
[ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ],
|
||||
|
||||
[ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, -1.5 ], [ Math.PI / 2, 0, 0 ] ],
|
||||
[ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ), [ 0, 0, -1 ] ]
|
||||
]
|
||||
};
|
||||
this.handleGizmos.X[2][0].name = 'NX'
|
||||
this.handleGizmos.X[3][0].name = 'NX'
|
||||
this.handleGizmos.Y[2][0].name = 'NY'
|
||||
this.handleGizmos.Y[3][0].name = 'NY'
|
||||
this.handleGizmos.Z[2][0].name = 'NZ'
|
||||
this.handleGizmos.Z[3][0].name = 'NZ'
|
||||
|
||||
this.pickerGizmos = {
|
||||
X: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ],
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ -0.6, 0, 0 ], [ 0, 0, Math.PI / 2 ] ]
|
||||
],
|
||||
Y: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ],
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, -0.6, 0 ], [Math.PI / 1, 0, 0 ] ]
|
||||
],
|
||||
Z: [
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ],
|
||||
[ new THREE.Mesh( new THREE.CylinderBufferGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, -0.6 ], [ - Math.PI / 2, 0, 0 ] ]
|
||||
]
|
||||
};
|
||||
this.pickerGizmos.X[1][0].name = 'NX'
|
||||
this.pickerGizmos.Y[1][0].name = 'NY'
|
||||
this.pickerGizmos.Z[1][0].name = 'NZ'
|
||||
|
||||
this.setActivePlane = function ( axis, eye ) {
|
||||
|
||||
var tempMatrix = new THREE.Matrix4();
|
||||
eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) );
|
||||
|
||||
if ( axis === "X" || axis === "NX" ) {
|
||||
|
||||
this.activePlane = this.planes[ "XY" ];
|
||||
if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ];
|
||||
}
|
||||
if ( axis === "Y" || axis === "NY" ) {
|
||||
|
||||
this.activePlane = this.planes[ "XY" ];
|
||||
if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ];
|
||||
}
|
||||
if ( axis === "Z" || axis === "NZ" ) {
|
||||
|
||||
this.activePlane = this.planes[ "XZ" ];
|
||||
if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ];
|
||||
}
|
||||
};
|
||||
this.init();
|
||||
|
||||
};
|
||||
|
||||
THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype );
|
||||
THREE.TransformGizmoScale.prototype.constructor = THREE.TransformGizmoScale;
|
||||
|
||||
THREE.TransformControls = function ( cam, domElement ) {
|
||||
|
||||
THREE.Object3D.call( this );
|
||||
|
||||
domElement = ( domElement !== undefined ) ? domElement : document;
|
||||
|
||||
this.camera = cam
|
||||
this.objects = [];
|
||||
this.visible = false;
|
||||
this.translationSnap = null;
|
||||
this.rotationSnap = null;
|
||||
this.space = "world";
|
||||
this.size = 1;
|
||||
this.axis = null;
|
||||
this.hoverAxis = null;
|
||||
this.direction = true;
|
||||
|
||||
this.firstLocation = [0,0,0]
|
||||
|
||||
|
||||
var scope = this;
|
||||
|
||||
var _mode = "translate";
|
||||
var _dragging = false;
|
||||
var _plane = "XY";
|
||||
var _gizmo = {
|
||||
|
||||
"translate": new THREE.TransformGizmoTranslate(),
|
||||
"scale": new THREE.TransformGizmoScale()
|
||||
};
|
||||
|
||||
for ( var type in _gizmo ) {
|
||||
|
||||
var gizmoObj = _gizmo[ type ];
|
||||
|
||||
gizmoObj.visible = ( type === _mode );
|
||||
this.add( gizmoObj );
|
||||
|
||||
}
|
||||
|
||||
|
||||
this.children[0].children[0].children.forEach(function(s) {
|
||||
s.renderOrder = 999
|
||||
})
|
||||
this.children[1].children[0].children.forEach(function(s) {
|
||||
s.renderOrder = 999
|
||||
})
|
||||
|
||||
//Vars
|
||||
var changeEvent = { type: "change" };
|
||||
var mouseDownEvent = { type: "mouseDown" };
|
||||
var mouseUpEvent = { type: "mouseUp", mode: _mode };
|
||||
var objectChangeEvent = { type: "objectChange" };
|
||||
|
||||
var ray = new THREE.Raycaster();
|
||||
var pointerVector = new THREE.Vector2();
|
||||
|
||||
var point = new THREE.Vector3();
|
||||
var offset = new THREE.Vector3();
|
||||
|
||||
var rotation = new THREE.Vector3();
|
||||
var offsetRotation = new THREE.Vector3();
|
||||
var scale = 1;
|
||||
|
||||
var lookAtMatrix = new THREE.Matrix4();
|
||||
var eye = new THREE.Vector3();
|
||||
|
||||
var tempMatrix = new THREE.Matrix4();
|
||||
var tempVector = new THREE.Vector3();
|
||||
var tempQuaternion = new THREE.Quaternion();
|
||||
var unitX = new THREE.Vector3( 1, 0, 0 );
|
||||
var unitY = new THREE.Vector3( 0, 1, 0 );
|
||||
var unitZ = new THREE.Vector3( 0, 0, 1 );
|
||||
|
||||
var quaternionXYZ = new THREE.Quaternion();
|
||||
var quaternionX = new THREE.Quaternion();
|
||||
var quaternionY = new THREE.Quaternion();
|
||||
var quaternionZ = new THREE.Quaternion();
|
||||
var quaternionE = new THREE.Quaternion();
|
||||
|
||||
var oldRotationMatrix = new THREE.Vector4()
|
||||
var oldPositionArray = []
|
||||
var oldScaleArray = []
|
||||
var parentRotationArray = []
|
||||
var oldScale = 0;
|
||||
var oldScaleTranslation = 0;
|
||||
var positionSnapOffset = new THREE.Vector3()
|
||||
var previousValue = 0;
|
||||
var tempScale = 1;
|
||||
var oldOriginPosition = new THREE.Vector3()
|
||||
|
||||
var parentRotationMatrix = new THREE.Matrix4();
|
||||
var parentScale = new THREE.Vector3();
|
||||
|
||||
var worldPosition = new THREE.Vector3();
|
||||
var worldRotation = new THREE.Euler();
|
||||
var worldRotationMatrix = new THREE.Matrix4();
|
||||
var camPosition = new THREE.Vector3();
|
||||
var camRotation = new THREE.Euler();
|
||||
|
||||
domElement.addEventListener( "mousedown", onPointerDown, false );
|
||||
domElement.addEventListener( "touchstart", onPointerDown, false );
|
||||
|
||||
domElement.addEventListener( "mousemove", onPointerHover, false );
|
||||
domElement.addEventListener( "touchmove", onPointerHover, false );
|
||||
|
||||
domElement.addEventListener( "mousemove", onPointerMove, false );
|
||||
domElement.addEventListener( "touchmove", onPointerMove, false );
|
||||
|
||||
domElement.addEventListener( "mouseup", onPointerUp, false );
|
||||
domElement.addEventListener( "mouseout", onPointerUp, false );
|
||||
domElement.addEventListener( "touchend", onPointerUp, false );
|
||||
domElement.addEventListener( "touchcancel", onPointerUp, false );
|
||||
domElement.addEventListener( "touchleave", onPointerUp, false );
|
||||
|
||||
this.dispose = function () {
|
||||
|
||||
domElement.removeEventListener( "mousedown", onPointerDown );
|
||||
domElement.removeEventListener( "touchstart", onPointerDown );
|
||||
|
||||
domElement.removeEventListener( "mousemove", onPointerHover );
|
||||
domElement.removeEventListener( "touchmove", onPointerHover );
|
||||
|
||||
domElement.removeEventListener( "mousemove", onPointerMove );
|
||||
domElement.removeEventListener( "touchmove", onPointerMove );
|
||||
|
||||
domElement.removeEventListener( "mouseup", onPointerUp );
|
||||
domElement.removeEventListener( "mouseout", onPointerUp );
|
||||
domElement.removeEventListener( "touchend", onPointerUp );
|
||||
domElement.removeEventListener( "touchcancel", onPointerUp );
|
||||
domElement.removeEventListener( "touchleave", onPointerUp );
|
||||
};
|
||||
|
||||
this.attach = function ( object ) {
|
||||
|
||||
this.objects.push(object);
|
||||
this.visible = true;
|
||||
this.update();
|
||||
};
|
||||
|
||||
this.detach = function () {
|
||||
|
||||
this.objects.length = 0
|
||||
this.visible = false;
|
||||
this.axis = null;
|
||||
};
|
||||
|
||||
this.getMode = function () {
|
||||
|
||||
return _mode;
|
||||
};
|
||||
|
||||
this.setMode = function ( mode ) {
|
||||
|
||||
_mode = mode ? mode : _mode;
|
||||
|
||||
if ( _mode === "scale" ) scope.space = "local";
|
||||
|
||||
for ( var type in _gizmo ) _gizmo[ type ].visible = ( type === _mode );
|
||||
|
||||
this.update();
|
||||
this.updateVisibleAxes()
|
||||
scope.dispatchEvent( changeEvent );
|
||||
};
|
||||
|
||||
this.setTranslationSnap = function ( translationSnap ) {
|
||||
|
||||
scope.translationSnap = translationSnap;
|
||||
};
|
||||
this.setSize = function ( size ) {
|
||||
|
||||
scope.size = size;
|
||||
this.update();
|
||||
scope.dispatchEvent( changeEvent );
|
||||
};
|
||||
|
||||
this.setSpace = function ( space ) {
|
||||
|
||||
scope.space = space;
|
||||
this.update();
|
||||
scope.dispatchEvent(changeEvent);
|
||||
};
|
||||
|
||||
this.updateVisibleAxes = function () {
|
||||
if (_mode === 'translate') {
|
||||
scope.children[0].children[0].children.forEach(function(s, i) {
|
||||
if (cameraOrtho.axis === null) {
|
||||
s.visible = true
|
||||
} else if (s.name.includes(cameraOrtho.axis.toUpperCase()) === true) {
|
||||
s.visible = false;
|
||||
} else {
|
||||
s.visible = true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
scope.children[1].children[0].children.forEach(function(s, i) {
|
||||
if (cameraOrtho.axis === null) {
|
||||
s.visible = true
|
||||
} else if (s.name.includes(cameraOrtho.axis.toUpperCase()) === true) {
|
||||
s.visible = false;
|
||||
} else {
|
||||
s.visible = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
|
||||
if ( scope.objects.length == 0 ) return;
|
||||
|
||||
scope.camera.updateMatrixWorld();
|
||||
camPosition.setFromMatrixPosition( scope.camera.matrixWorld );
|
||||
camRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.camera.matrixWorld ) );
|
||||
|
||||
scale = worldPosition.distanceTo( camPosition ) / 6 * (settings.control_size.value / 20);
|
||||
//this.position.copy( worldPosition );
|
||||
|
||||
if ( scope.camera instanceof THREE.PerspectiveCamera ) {
|
||||
|
||||
eye.copy( camPosition ).sub( worldPosition ).normalize();
|
||||
|
||||
} else if ( scope.camera instanceof THREE.OrthographicCamera ) {
|
||||
|
||||
eye.copy( camPosition ).normalize();
|
||||
scale = (6 / cameraOrtho.zoom) * (settings.control_size.value / 20);
|
||||
|
||||
}
|
||||
this.scale.set( scale, scale, scale );
|
||||
|
||||
if ( scope.space === "local" ) {
|
||||
|
||||
_gizmo[ _mode ].update( worldRotation, eye );
|
||||
|
||||
} else if ( scope.space === "world" ) {
|
||||
|
||||
_gizmo[ _mode ].update( new THREE.Euler(), eye );
|
||||
|
||||
}
|
||||
|
||||
_gizmo[ _mode ].highlight( scope.axis );
|
||||
|
||||
|
||||
};
|
||||
|
||||
this.calcPosition = function(offset) {
|
||||
|
||||
if (selected.length === 0) return;
|
||||
scope.children[0].rotation.set(0, 0, 0)
|
||||
|
||||
var center = [0, 0, 0]
|
||||
var i = 0;
|
||||
selected.forEach(function(s) {
|
||||
var obj = elements[s]
|
||||
i = 0;
|
||||
while (i < 3) {
|
||||
center[i] += obj.from[i]
|
||||
center[i] += obj.to[i]
|
||||
i++;
|
||||
}
|
||||
})
|
||||
i = 0;
|
||||
while (i < 3) {
|
||||
center[i] = center[i] / (selected.length * 2)
|
||||
i++;
|
||||
}
|
||||
var vec = new THREE.Vector3()
|
||||
vec.set(center[0], center[1], center[2])
|
||||
if (offset !== undefined) {
|
||||
vec.add(offset)
|
||||
if (movementAxis === true) {
|
||||
var obj = elements[selected[0]]
|
||||
if (obj.rotation) {
|
||||
vec.setFromMatrixPosition(obj.display.mesh.matrixWorld)
|
||||
scope.children[0].rotation[obj.rotation.axis] = Math.PI / (180 / obj.rotation.angle)
|
||||
vec.x -= obj.rotation.origin[0]
|
||||
vec.y -= obj.rotation.origin[1]
|
||||
vec.z -= obj.rotation.origin[2]
|
||||
}
|
||||
}
|
||||
scope.position.copy(vec)
|
||||
//scope.position.add(vec)
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerHover( event ) {
|
||||
|
||||
if ( scope.objects.length === 0 || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return;
|
||||
|
||||
var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event;
|
||||
|
||||
var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children );
|
||||
|
||||
scope.hoverAxis = null;
|
||||
|
||||
if ( intersect ) {
|
||||
scope.hoverAxis = intersect.object.name;
|
||||
if (scope.hoverAxis.toLowerCase() === cameraOrtho.axis) {
|
||||
scope.hoverAxis = null
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
if ( scope.axis !== scope.hoverAxis ) {
|
||||
|
||||
scope.axis = scope.hoverAxis;
|
||||
scope.update();
|
||||
scope.dispatchEvent( changeEvent );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onPointerDown( event ) {
|
||||
|
||||
if ( scope.objects.length === 0 || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return;
|
||||
var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event;
|
||||
if ( pointer.button === 0 || pointer.button === undefined ) {
|
||||
|
||||
var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children );
|
||||
|
||||
if ( intersect ) {
|
||||
|
||||
if (intersect.object.name.toLowerCase() === cameraOrtho.axis) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
scope.dispatchEvent( mouseDownEvent );
|
||||
|
||||
scope.axis = intersect.object.name;
|
||||
|
||||
scope.update();
|
||||
tempScale = 1
|
||||
oldScaleTranslation = 0;
|
||||
|
||||
eye.copy( camPosition ).sub( worldPosition ).normalize();
|
||||
|
||||
_gizmo[ _mode ].setActivePlane( scope.axis, eye );
|
||||
|
||||
var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] );
|
||||
|
||||
if ( planeIntersect ) {
|
||||
|
||||
oldScale = elements[selected[0]].size(getAxisNumber(scope.axis.toLowerCase().replace('n', '')))
|
||||
|
||||
oldPositionArray.length = 0
|
||||
oldScaleArray.length = 0
|
||||
parentRotationArray.length = 0
|
||||
|
||||
scope.objects.forEach(function(s) {
|
||||
|
||||
oldPositionArray.push(new THREE.Vector3());
|
||||
oldScaleArray.push(new THREE.Vector3());
|
||||
//parentRotationArray.push(s.rotation);
|
||||
oldOriginPosition = new THREE.Vector3()
|
||||
oldOriginPosition.copy(scope.position)
|
||||
|
||||
|
||||
oldPositionArray[ oldPositionArray.length-1 ].copy( s.position );
|
||||
oldScaleArray[ oldScaleArray.length-1 ].copy( s.scale );
|
||||
|
||||
parentScale.setFromMatrixScale( tempMatrix.getInverse( s.parent.matrixWorld ) );
|
||||
|
||||
})
|
||||
|
||||
offset.copy( planeIntersect.point );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_dragging = true;
|
||||
|
||||
}
|
||||
|
||||
function onPointerMove( event ) {
|
||||
|
||||
if ( scope.objects === undefined || scope.axis === null || _dragging === false || ( event.button !== undefined && event.button !== 0 ) ) return;
|
||||
|
||||
controls.hasMoved = true
|
||||
|
||||
var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event;
|
||||
|
||||
var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] );
|
||||
|
||||
if ( planeIntersect === false ) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
point.copy( planeIntersect.point );
|
||||
point.sub( offset );
|
||||
|
||||
if (Prop.tool === 'scale') {
|
||||
|
||||
//Scale
|
||||
if (scope.axis.substr(0, 1) === 'N') {
|
||||
var axis = scope.axis.substr(1, 1).toLowerCase()
|
||||
scope.direction = false
|
||||
} else {
|
||||
var axis = scope.axis.toLowerCase()
|
||||
scope.direction = true
|
||||
}
|
||||
//if (axis !== 'x') point.x = 0;
|
||||
//if (axis !== 'y') point.y = 0;
|
||||
//if (axis !== 'z') point.z = 0;
|
||||
|
||||
var axisNumber = getAxisNumber(axis)
|
||||
var snap_factor = getSnapFactor(event)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor
|
||||
|
||||
|
||||
if (previousValue !== point[axis]) {
|
||||
|
||||
selected.forEach(function(s, i) {
|
||||
var obj = elements[s]
|
||||
var mesh = scope.objects[i]
|
||||
if (scope.direction === true) { //Positive
|
||||
scaleCube(obj, limitNumber(oldScale + point[axis], 0, 48), axisNumber)
|
||||
} else {
|
||||
scaleCubeNegative(obj, limitNumber(oldScale - point[axis], 0, 48), axisNumber)
|
||||
}
|
||||
if (settings.entity_mode.value === true) {
|
||||
Canvas.updateUV(s)
|
||||
}
|
||||
})
|
||||
Canvas.updatePositions(true)
|
||||
centerTransformer()
|
||||
previousValue = point[axis]
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//Translate
|
||||
var axis = scope.axis.toLowerCase()
|
||||
|
||||
if ( scope.axis !== "X") point.x = 0;
|
||||
if ( scope.axis !== "Y") point.y = 0;
|
||||
if ( scope.axis !== "Z") point.z = 0;
|
||||
|
||||
var snap_factor = getSnapFactor(event)
|
||||
point[axis] = Math.round( point[axis] / snap_factor ) * snap_factor
|
||||
|
||||
|
||||
if (previousValue !== point[axis]) {
|
||||
|
||||
var axis = getAxisNumber(scope.axis.toLowerCase())
|
||||
var difference = scope.position.getComponent(axis) - oldOriginPosition.getComponent(axis)
|
||||
var in_boundaries = true;
|
||||
|
||||
selected.forEach(function(s) {
|
||||
if (elements[s].from[axis] + difference < -16) in_boundaries = false;
|
||||
if (elements[s].to[axis] + difference > 32) in_boundaries = false;
|
||||
})
|
||||
|
||||
var nslide_number = trimFloatNumber( limitNumber( elements[selected[0]].from[axis] + difference ) )
|
||||
$('div.nslide[n-action="pos_'+scope.axis.toLowerCase()+'"]:not(".editing")').text(nslide_number)
|
||||
|
||||
var rotatedPoint = new THREE.Vector3();
|
||||
rotatedPoint.copy(point)
|
||||
if (movementAxis === true) {
|
||||
rotatedPoint.applyEuler( scope.objects[0].rotation )
|
||||
}
|
||||
|
||||
scope.objects.forEach(function(s, i) {
|
||||
s.position.copy( oldPositionArray[i] );
|
||||
s.position.add( rotatedPoint );
|
||||
})
|
||||
centerTransformer(rotatedPoint)
|
||||
previousValue = point.getComponent(axis)
|
||||
}
|
||||
}
|
||||
scope.dispatchEvent( changeEvent );
|
||||
scope.dispatchEvent( objectChangeEvent );
|
||||
|
||||
}
|
||||
|
||||
function onPointerUp( event ) {
|
||||
event.preventDefault(); // Prevent MouseEvent on mobile
|
||||
|
||||
if ( event.button !== undefined && event.button !== 0 && event.button !== 2 ) return;
|
||||
|
||||
if ( _dragging && scope.axis !== null ) {
|
||||
|
||||
mouseUpEvent.mode = _mode;
|
||||
scope.dispatchEvent( mouseUpEvent );
|
||||
controls.stopMovement()
|
||||
|
||||
if (Prop.tool === 'scale') {
|
||||
//Scale
|
||||
setUndo('Scaled cube'+pluralS(selected))
|
||||
Canvas.updatePositions()
|
||||
|
||||
} else if (scope.axis !== null) {
|
||||
//Translate
|
||||
|
||||
var rotatedPoint = new THREE.Vector3();
|
||||
rotatedPoint.copy(point)
|
||||
if (movementAxis === true && scope.objects.length > 0) {
|
||||
rotatedPoint.applyEuler( scope.objects[0].rotation )
|
||||
}
|
||||
|
||||
|
||||
var axis = scope.axis.toLowerCase()
|
||||
var difference = scope.position.distanceTo(oldOriginPosition)
|
||||
if (scope.position[axis] < oldOriginPosition[axis]) {
|
||||
difference *= -1
|
||||
}
|
||||
|
||||
selected.forEach(function(s) {
|
||||
moveCube(elements[s], elements[s].from[getAxisNumber(axis)] + difference, getAxisNumber(axis))
|
||||
})
|
||||
|
||||
setUndo('Moved cube'+pluralS(selected))
|
||||
Canvas.updatePositions()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_dragging = false;
|
||||
|
||||
if ( 'TouchEvent' in window && event instanceof TouchEvent ) {
|
||||
|
||||
// Force "rollover"
|
||||
|
||||
scope.axis = null;
|
||||
scope.update();
|
||||
scope.dispatchEvent( changeEvent );
|
||||
|
||||
} else {
|
||||
|
||||
onPointerHover( event );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function intersectObjects( pointer, objects ) {
|
||||
|
||||
var rect = domElement.getBoundingClientRect();
|
||||
var x = ( pointer.clientX - rect.left ) / rect.width;
|
||||
var y = ( pointer.clientY - rect.top ) / rect.height;
|
||||
|
||||
pointerVector.set( ( x * 2 ) - 1, - ( y * 2 ) + 1 );
|
||||
ray.setFromCamera( pointerVector, scope.camera );
|
||||
|
||||
var intersections = ray.intersectObjects( objects, true );
|
||||
return intersections[ 0 ] ? intersections[ 0 ] : false;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
THREE.TransformControls.prototype = Object.create( THREE.Object3D.prototype );
|
||||
THREE.TransformControls.prototype.constructor = THREE.TransformControls;
|
||||
|
||||
}() );
|
305
js/api.js
Normal file
@ -0,0 +1,305 @@
|
||||
class API {
|
||||
constructor() {
|
||||
this.elements = elements;
|
||||
this.textures = textures;
|
||||
this.display_settings = display;
|
||||
this.isWeb = !isApp;
|
||||
this.version = appVersion;
|
||||
this.platform = 'web'
|
||||
this.selection = selected;
|
||||
this.flags = []
|
||||
if (isApp) {
|
||||
this.platform = require('os').platform()
|
||||
if (this.platform.includes('win32') === true) osfs = '\\'
|
||||
}
|
||||
}
|
||||
registerEdit(name) {
|
||||
setUndo(name)
|
||||
};
|
||||
|
||||
addMenuEntry(name, icon, cb) {
|
||||
var entry = $('<li><i class="material-icons">' + icon + '</i><span>' + name + '</span></li>')
|
||||
entry.click(cb)
|
||||
$('#plugin_submenu').append(entry)
|
||||
$('.plugin_submenu_hide').show()
|
||||
}
|
||||
removeMenuEntry(name) {
|
||||
$('#plugin_submenu li').each(function(i, s) {
|
||||
if ($(s).find('span').text() === name) {
|
||||
$(s).remove()
|
||||
}
|
||||
})
|
||||
if ($('#plugin_submenu li').length === 0) {
|
||||
$('.plugin_submenu_hide').hide()
|
||||
}
|
||||
}
|
||||
|
||||
showMessage(message, location) {
|
||||
if (location === 'status_bar') {
|
||||
showStatusMessage(message)
|
||||
} else if (location === 'center') {
|
||||
showQuickMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
import(type, cb, extensions) {
|
||||
type = type.replace('.', '')
|
||||
if (Blockbench.isWeb) {
|
||||
fileLoaderLoad('.'+type, false, function() {
|
||||
hideDialog()
|
||||
var file = $('#file_upload').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
cb(reader.result)
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsText(file)
|
||||
}
|
||||
})
|
||||
$('#file_folder').val('')
|
||||
} else {
|
||||
if (!extensions) {
|
||||
extensions = []
|
||||
extensions.push(type)
|
||||
}
|
||||
app.dialog.showOpenDialog(currentwindow, {filters: [{name: type, extensions: extensions}] }, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
fs.readFile(fileNames[0], 'utf-8', function (err, data) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return;
|
||||
}
|
||||
cb(data, fileNames[0])
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export(content, name, type) {
|
||||
type = type.replace('.', '')
|
||||
if (Blockbench.isWeb) {
|
||||
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, name+'.'+type)
|
||||
} else {
|
||||
app.dialog.showSaveDialog(currentwindow, {
|
||||
filters: [ {
|
||||
name: type,
|
||||
extensions: [type]
|
||||
} ],
|
||||
defaultPath: name
|
||||
}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
fs.writeFile(fileName, content, function (err) {
|
||||
if (err) {
|
||||
console.log('Error Exporting File: '+err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
dispatchEvent(event_name, event) {
|
||||
if (!this.listeners) {
|
||||
return;
|
||||
}
|
||||
var i = 0;
|
||||
while (i < this.listeners.length) {
|
||||
if (this.listeners[i].name === event_name) {
|
||||
this.listeners[i].callback(event)
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
addListener(event_name, cb) {
|
||||
if (!this.listeners) {
|
||||
this.listeners = []
|
||||
}
|
||||
this.listeners.push({name: event_name, callback: cb})
|
||||
}
|
||||
removeListener(event_name, cb) {
|
||||
if (!this.listeners) {
|
||||
return;
|
||||
}
|
||||
var i = 0;
|
||||
while (i < this.listeners.length) {
|
||||
if (this.listeners[i].name === event_name && this.listeners[i].callback === cb) {
|
||||
this.listeners.splice(i, 1)
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
reload() {
|
||||
preventClosing = false
|
||||
Blockbench.flags.push('allow_reload')
|
||||
currentwindow.reload()
|
||||
}
|
||||
//Flags
|
||||
addFlag(flag) {
|
||||
if (!this.hasFlag(flag)) {
|
||||
this.flags.push(flag)
|
||||
}
|
||||
}
|
||||
removeFlag(flag) {
|
||||
this.flags.remove(flag)
|
||||
}
|
||||
hasFlag(flag) {
|
||||
return this.flags.includes(flag)
|
||||
}
|
||||
}
|
||||
|
||||
function Dialog(settings) {
|
||||
var scope = this;
|
||||
this.title = settings.title
|
||||
this.lines = settings.lines
|
||||
this.id = settings.id
|
||||
this.width = settings.width
|
||||
this.fadeTime = settings.fadeTime
|
||||
this.draggable = settings.draggable
|
||||
this.singleButton = settings.singleButton
|
||||
if (!parseInt(settings.fadeTime)) this.fadeTime = 200
|
||||
|
||||
|
||||
this.hide = function() {
|
||||
$('#blackout').fadeOut(this.fadeTime)
|
||||
$(scope.object).fadeOut(this.fadeTime)
|
||||
open_dialog = false;
|
||||
setTimeout(function() {
|
||||
$(scope.object).remove()
|
||||
},this.fadeTime)
|
||||
console.log('Hiding Dialog')
|
||||
}
|
||||
|
||||
this.confirmEnabled = settings.confirmEnabled === false ? false : true
|
||||
this.cancelEnabled = settings.cancelEnabled === false ? false : true
|
||||
this.onConfirm = settings.onConfirm ? settings.onConfirm : this.hide
|
||||
this.onCancel = settings.onCancel ? settings.onCancel : this.hide
|
||||
|
||||
this.object;
|
||||
|
||||
this.confirm = function() {
|
||||
$(this.object).find('.confirm_btn:not([disabled])').click()
|
||||
}
|
||||
this.cancel = function() {
|
||||
$(this.object).find('.cancel_btn:not([disabled])').click()
|
||||
}
|
||||
this.show = function() {
|
||||
var jq_dialog = $('<div class="dialog paddinged" style="width: auto;" id="'+scope.id+'"><h2 class="dialog_handle">'+scope.title+'</h2></div>')
|
||||
scope.object = jq_dialog.get(0)
|
||||
scope.lines.forEach(function(l) {
|
||||
jq_dialog.append(l)
|
||||
})
|
||||
if (this.singleButton) {
|
||||
jq_dialog.append('<div class="dialog_bar">' +
|
||||
'<button type="button" class="large cancel_btn confirm_btn"'+ (this.confirmEnabled ? '' : ' disabled') +'>Close</button>' +
|
||||
'</div>')
|
||||
} else {
|
||||
jq_dialog.append(['<div class="dialog_bar">',
|
||||
'<button type="button" class="large confirm_btn"'+ (this.confirmEnabled ? '' : ' disabled') +'>Confirm</button>',
|
||||
'<button type="button" class="large cancel_btn"'+ (this.cancelEnabled ? '' : ' disabled') +'>Cancel</button>',
|
||||
'</div>'].join(''))
|
||||
}
|
||||
jq_dialog.append('<div id="dialog_close_button" onclick="$(\'.dialog#\'+open_dialog).find(\'.cancel_btn:not([disabled])\').click()"><i class="material-icons">clear</i></div>')
|
||||
$(this.object).find('.confirm_btn').click(this.onConfirm)
|
||||
$(this.object).find('.cancel_btn').click(this.onCancel)
|
||||
//Draggable
|
||||
if (this.draggable !== false) {
|
||||
jq_dialog.addClass('draggable')
|
||||
jq_dialog.draggable({
|
||||
handle: ".dialog_handle"
|
||||
})
|
||||
var x = ($(window).width()-540)/2
|
||||
jq_dialog.css('left', x+'px')
|
||||
jq_dialog.css('position', 'absolute')
|
||||
}
|
||||
$('#plugin_dialog_wrapper').append(jq_dialog)
|
||||
$('.dialog').hide(0)
|
||||
$('#blackout').fadeIn(scope.fadeTime)
|
||||
jq_dialog.fadeIn(scope.fadeTime)
|
||||
jq_dialog.css('top', limitNumber($(window).height()/2-jq_dialog.height()/2, 0, 100)+'px')
|
||||
if (this.width) {
|
||||
jq_dialog.css('width', this.width+'px')
|
||||
}
|
||||
setTimeout(function() {
|
||||
$('.context_handler.ctx').removeClass('ctx')
|
||||
}, 64)
|
||||
open_dialog = scope.id
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ContextMenu(event, array) {
|
||||
function getEntryFromObject(s, parent) {
|
||||
if (s.local_only && !isApp) return;
|
||||
|
||||
var icon = ''
|
||||
if (typeof s.icon === 'string') {
|
||||
if (s.icon.substr(0, 2) === 'fa') {
|
||||
icon = '<i class="fa fa_big ' + s.icon + '"></i>'
|
||||
} else {
|
||||
icon = '<i class="material-icons">' + s.icon + '</i>'
|
||||
}
|
||||
var entry = $('<li>' + icon + s.name + '</li>')
|
||||
} else {
|
||||
var entry = $('<li></li>')
|
||||
entry.append(s.icon)
|
||||
entry.append(s.name)
|
||||
|
||||
}
|
||||
|
||||
if (s.children && s.children) {
|
||||
if (typeof s.children === 'function') {
|
||||
s.children = s.children()
|
||||
}
|
||||
entry.addClass('parent')
|
||||
var childlist = $('<ul class="contextMenu sub"></ul>')
|
||||
s.children.forEach(function(c) {
|
||||
childlist.append(getEntryFromObject(c, childlist))
|
||||
})
|
||||
entry.append(childlist)
|
||||
//HERE
|
||||
entry.mouseenter(function(event) {
|
||||
//Left
|
||||
childlist.css('left', '0')
|
||||
var offset = childlist.offset()
|
||||
var el_width = -childlist.width()
|
||||
var p_width = parent.width()
|
||||
if (offset.left + childlist.width() > $(window).width()-100) {
|
||||
childlist.css('left', el_width + 'px')
|
||||
} else {
|
||||
childlist.css('left', p_width + 'px')
|
||||
}
|
||||
//Top
|
||||
})
|
||||
}
|
||||
|
||||
entry.click(s.click)
|
||||
return entry
|
||||
}
|
||||
|
||||
var ctxmenu = $('<ul class="contextMenu"></ul>')
|
||||
array.forEach(function(s, i) {
|
||||
ctxmenu.append(getEntryFromObject(s, ctxmenu))
|
||||
})
|
||||
$('body').append(ctxmenu)
|
||||
|
||||
var el_width = ctxmenu.width()
|
||||
|
||||
var offset_left = event.clientX
|
||||
var offset_top = event.clientY
|
||||
|
||||
if (offset_left > $(window).width() - el_width) offset_left -= el_width
|
||||
if (offset_top > $(window).height() - 35 * array.length ) offset_top -= 35 * array.length
|
||||
|
||||
ctxmenu.css('left', offset_left+'px')
|
||||
ctxmenu.css('top', offset_top +'px')
|
||||
|
||||
ctxmenu.click(function() {
|
||||
this.remove()
|
||||
})
|
||||
return ctxmenu;
|
||||
}
|
||||
|
||||
var Blockbench = new API()
|
521
js/app.js
Normal file
@ -0,0 +1,521 @@
|
||||
var app = require('electron').remote,
|
||||
fs = require('fs'),
|
||||
nativeImage = require('electron').nativeImage,
|
||||
exec = require('child_process').exec,
|
||||
originalFs = require('original-fs'),
|
||||
http = require('http'),
|
||||
currentwindow = app.getCurrentWindow(),
|
||||
dialog_win = null,
|
||||
latest_version= false,
|
||||
preventClosing= true;
|
||||
|
||||
const shell = require('electron').shell;
|
||||
const {clipboard} = require('electron')
|
||||
|
||||
$(document).ready(function() {
|
||||
if (app.process.argv.length >= 2) {
|
||||
if (app.process.argv[1].substr(-5) == '.json') {
|
||||
readFile(app.process.argv[1], true)
|
||||
}
|
||||
}
|
||||
$('.open-in-browser').click((event) => {
|
||||
event.preventDefault();
|
||||
shell.openExternal(event.target.href);
|
||||
return true;
|
||||
});
|
||||
$('.web_only').remove()
|
||||
if (__dirname.includes('C:\\xampp\\htdocs\\blockbench\\web')) {
|
||||
Blockbench.addFlag('dev')
|
||||
$('#file_menu_list').append('<li class="menu_seperator"></li>')
|
||||
$('#file_menu_list').append('<li onclick="Blockbench.reload()"><i class="material-icons">refresh</i>Reload</li>')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
getLatestVersion(true)
|
||||
//Called on start to show message
|
||||
function getLatestVersion(init) {
|
||||
$.getJSON('http://blockbench.net/api/index.json', function(data) {
|
||||
if (data.version) {
|
||||
latest_version = data.version
|
||||
if (latest_version !== appVersion && init === true) {
|
||||
showDialog('update_notification')
|
||||
$('.dialog#update_notification h2 span').text(latest_version)
|
||||
console.log('Found new version: '+latest_version)
|
||||
} else if (init === false) {
|
||||
checkForUpdates()
|
||||
}
|
||||
}
|
||||
}).fail(function() {
|
||||
latest_version = false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
function checkForUpdates(instant) {
|
||||
showDialog('updater')
|
||||
setProgressBar('update_bar', 0, 1)
|
||||
var data;
|
||||
if (latest_version === false) {
|
||||
data = [
|
||||
'<div class="tool" onclick="refreshUpdateDialog()">',
|
||||
'<i class="material-icons">refresh</i>',
|
||||
'<div class="tooltip">Refresh</div>',
|
||||
'</div>',
|
||||
'<div class="dialog_bar narrow">',
|
||||
'<i class="material-icons blue_icon">cloud_off</i>No internet connection',
|
||||
'</div>'
|
||||
].join('')
|
||||
} else if (latest_version !== appVersion) {
|
||||
data = [
|
||||
'<div class="dialog_bar narrow">Latest version: '+latest_version+'</div>',
|
||||
'<div class="dialog_bar narrow">Installed version: '+appVersion+'</div>',
|
||||
'<div class=""><button type="button" class="large uc_btn" id="update_button" onclick="installUpdate()">Update</button></div>'
|
||||
].join('')
|
||||
if (instant) {
|
||||
setTimeout(function() {
|
||||
installUpdate()
|
||||
}, 60)
|
||||
}
|
||||
} else {
|
||||
data = [
|
||||
'<div class="tool" onclick="refreshUpdateDialog()">',
|
||||
'<i class="material-icons">refresh</i>',
|
||||
'<div class="tooltip">Refresh</div>',
|
||||
'</div>',
|
||||
'<div class="dialog_bar narrow">',
|
||||
'<i class="material-icons blue_icon">check</i>Blockbench is up-to-date!',
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
$('#updater_content').html(data)
|
||||
}
|
||||
function refreshUpdateDialog() {
|
||||
data = '<div class="dialog_bar narrow"><i class="material-icons blue_icon spinning">refresh</i>Clearing cache data</div>'
|
||||
$('#updater_content').html(data)
|
||||
currentwindow.webContents.session.clearCache(function() {
|
||||
data = '<div class="dialog_bar narrow"><i class="material-icons blue_icon spinning">refresh</i>Connecting to server</div>'
|
||||
$('#updater_content').html(data)
|
||||
getLatestVersion(false)
|
||||
})
|
||||
}
|
||||
|
||||
function installUpdate() {
|
||||
console.log('Starting Update')
|
||||
var received_bytes = 0;
|
||||
var total_bytes = 0;
|
||||
|
||||
$('.uc_btn').attr('disabled', true)
|
||||
|
||||
var asar_path = __dirname
|
||||
if (asar_path.includes('.asar') === false) {
|
||||
asar_path = asar_path + osfs+'resources'+osfs+'app.asar'
|
||||
}
|
||||
|
||||
var file = originalFs.createWriteStream(asar_path)
|
||||
|
||||
var request = http.get("http://blockbench.net/api/app.asar", function(response) {
|
||||
response.pipe(file);
|
||||
|
||||
total_bytes = parseInt(response.headers['content-length']);
|
||||
|
||||
response.on('end', updateInstallationEnd)
|
||||
response.on('data', function(chunk) {
|
||||
received_bytes += chunk.length;
|
||||
setProgressBar('update_bar', received_bytes / total_bytes, 1);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function updateInstallationEnd() {
|
||||
hideDialog()
|
||||
var exe_path = __dirname.split(osfs)
|
||||
exe_path.splice(-2)
|
||||
exe_path = exe_path.join(osfs)+osfs+'blockbench.exe'
|
||||
if (showSaveDialog(true)) {
|
||||
exec(exe_path)
|
||||
} else {
|
||||
showQuickMessage('Restart the app to update')
|
||||
}
|
||||
}
|
||||
|
||||
function openDefaultTexturePath() {
|
||||
var answer = app.dialog.showMessageBox(currentwindow, {
|
||||
type: 'info',
|
||||
buttons: ['Remove', 'Continue'],
|
||||
noLink: true,
|
||||
title: 'Info',
|
||||
message: 'Select "textures"-folder of the default resource pack',
|
||||
detail: 'Extract the default resource pack from the Minecraft jar or google and download it. Then locate the "textures" folder and open it. Blockbench will remember that location and try to fetch textures from there if it can\'t find them in the current resource pack.',
|
||||
})
|
||||
if (answer === 0) {
|
||||
settings.default_path = {value: false, hidden: true}
|
||||
} else {
|
||||
app.dialog.showOpenDialog(currentwindow, {
|
||||
title: 'Select default "textures" Folder',
|
||||
properties: ['openDirectory'],
|
||||
}, function(filePaths) {
|
||||
settings.default_path = {value: filePaths[0], hidden: true}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Save Dialogs
|
||||
function saveFileBlock() {
|
||||
app.dialog.showSaveDialog(currentwindow, {
|
||||
filters: [ {
|
||||
name: 'JSON Model',
|
||||
extensions: ['json']
|
||||
}],
|
||||
defaultPath: Project.name
|
||||
}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
Prop.file_path = fileName;
|
||||
saveFile()
|
||||
})
|
||||
}
|
||||
function saveFileOptifine() {
|
||||
app.dialog.showSaveDialog(currentwindow, {
|
||||
filters: [ {
|
||||
name: 'Optifine Model',
|
||||
extensions: ['jpm']
|
||||
} ],
|
||||
defaultPath: Project.name
|
||||
}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
var content = buildOptifineModel()
|
||||
fs.writeFile(fileName, content, function (err) {
|
||||
if (err) {
|
||||
console.log('Error Saving Entity Model: '+err)
|
||||
}
|
||||
showQuickMessage('Saved as Optifine entity model')
|
||||
})
|
||||
})
|
||||
}
|
||||
function saveFileEntity() {
|
||||
app.dialog.showSaveDialog(currentwindow, {
|
||||
filters: [ {
|
||||
name: 'Entity Model',
|
||||
extensions: ['json']
|
||||
}],
|
||||
defaultPath: Project.name
|
||||
}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
var content = buildEntityModel(false)
|
||||
|
||||
fs.readFile(fileName, 'utf-8', function (errx, data) {
|
||||
var obj = {}
|
||||
if (!errx) {
|
||||
try {
|
||||
obj = JSON.parse(data)
|
||||
} catch (err) {
|
||||
err = err+''
|
||||
var answer = app.dialog.showMessageBox(currentwindow, {
|
||||
type: 'warning',
|
||||
buttons: ['Create Backup and Overwrite', 'Overwrite', 'Cancel'],
|
||||
title: 'Blockbench',
|
||||
message: 'Blockbench cannot combine this model with the old file',
|
||||
detail: err,
|
||||
noLink: false
|
||||
})
|
||||
if (answer === 0) {
|
||||
var backup_file_name = pathToName(fileName, true) + ' backup ' + new Date().toLocaleString().split(':').join('_')
|
||||
backup_file_name = fileName.replace(pathToName(fileName, false), backup_file_name)
|
||||
fs.writeFile(backup_file_name, data, function (err2) {
|
||||
if (err2) {
|
||||
console.log('Error saving backup model: ', err2)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (answer === 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
var model_name = Project.parent
|
||||
if (model_name == '') model_name = 'geometry.unknown'
|
||||
obj[model_name] = content
|
||||
content = autoStringify(obj)
|
||||
|
||||
fs.writeFile(fileName, content, function (err) {
|
||||
if (err) {
|
||||
console.log('Error Saving Entity Model: '+err)
|
||||
}
|
||||
showQuickMessage('Saved as bedrock entity model')
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
function saveFileObj() {
|
||||
app.dialog.showSaveDialog(currentwindow, {filters: [ {name: 'Alias Wavefront', extensions: ['obj']} ]}, function (fileName) {
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
scene.remove(three_grid)
|
||||
scene.remove(Transformer)
|
||||
var exporter = new THREE.OBJExporter();
|
||||
var content = exporter.parse( scene, pathToName(fileName, false));
|
||||
scene.add(three_grid)
|
||||
scene.add(Transformer)
|
||||
|
||||
//OBJECT
|
||||
fs.writeFile(fileName, content.obj, function (err) {})
|
||||
|
||||
//MATERIAL
|
||||
fs.writeFile(fileName.split('.obj').join('.mtl'), content.mtl, function (err) {})
|
||||
|
||||
//IMAGES
|
||||
if (settings.obj_textures.value === true) {
|
||||
for (var key in content.images) {
|
||||
if (content.images.hasOwnProperty(key) && content.images[key].path) {
|
||||
var native_image_instance = nativeImage.createFromPath(content.images[key].path)
|
||||
var image = native_image_instance.toPNG()
|
||||
var image_path = fileName.split(osfs)
|
||||
image_path.pop()
|
||||
image_path = image_path.join(osfs) + osfs + content.images[key].name
|
||||
|
||||
fs.writeFile(image_path, image, function (err) {})
|
||||
}
|
||||
}
|
||||
}
|
||||
showQuickMessage('Saved as obj model')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//Writers
|
||||
function saveFile(props) {
|
||||
if (Prop.file_path !== 'Unknown') {
|
||||
var content = buildBlockModel(true)
|
||||
Prop.project_saved = true;
|
||||
$('title').text(pathToName(Prop.file_path, false)+' - Blockbench')
|
||||
fs.writeFile(Prop.file_path, content, function (err) {
|
||||
if (err) {
|
||||
console.log('Error Saving File: '+err)
|
||||
}
|
||||
if (props && props.closeAfter) {
|
||||
preventClosing = false
|
||||
setTimeout(function() {
|
||||
currentwindow.close()
|
||||
}, 12)
|
||||
}
|
||||
showQuickMessage('Saved as '+ pathToName(Prop.file_path, true))
|
||||
})
|
||||
} else {
|
||||
saveFileBlock()
|
||||
}
|
||||
}
|
||||
|
||||
//Open
|
||||
function openFile(makeNew) {
|
||||
app.dialog.showOpenDialog(currentwindow, {filters: [{name: 'Model', extensions: ['json']}]}, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
readFile(fileNames[0], makeNew)
|
||||
}
|
||||
})
|
||||
}
|
||||
function readFile(filepath, makeNew) {
|
||||
fs.readFile(filepath, 'utf-8', function (err, data) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return;
|
||||
}
|
||||
loadFile(data, filepath, makeNew)
|
||||
})
|
||||
}
|
||||
function openTexture() {
|
||||
var start_path;
|
||||
if (textures.length > 0) {
|
||||
var arr = textures[0].path.split(osfs)
|
||||
arr.splice(-1)
|
||||
start_path = arr.join(osfs)
|
||||
} else if (Prop.file_name) {
|
||||
var arr = Prop.file_path.split(osfs)
|
||||
arr.splice(-3)
|
||||
arr.push('textures')
|
||||
start_path = arr.join(osfs)
|
||||
}
|
||||
app.dialog.showOpenDialog(currentwindow, {
|
||||
properties: ['openFile', 'multiSelections'],
|
||||
defaultPath: start_path,
|
||||
filters: [{
|
||||
name: 'PNG Texture',
|
||||
extensions: ['png']
|
||||
}]
|
||||
}, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
fileNames.forEach(function(path) {
|
||||
fs.readFile(path, function (err) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
}
|
||||
new Texture().fromPath(path).add().fillParticle()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
function importExtrusion(makeNew) {
|
||||
app.dialog.showOpenDialog(currentwindow, {
|
||||
properties: ['openFile'],
|
||||
filters: [{
|
||||
name: 'PNG Texture',
|
||||
extensions: ['png']
|
||||
}]
|
||||
}, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
var path = fileNames[0]
|
||||
fs.readFile(path, function (err) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
}
|
||||
if (makeNew === true) {
|
||||
if (newProject() == false) return;
|
||||
}
|
||||
g_makeNew = makeNew
|
||||
|
||||
new Texture().fromPath(path).add().fillParticle()
|
||||
|
||||
showDialog('image_extruder')
|
||||
drawExtrusionImage(path)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function dropTexture(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
function loadBackgroundImage(event) {
|
||||
if (event !== undefined) {
|
||||
if (event.altKey === true) {
|
||||
textPrompt('Background Image Path', 'active_scene.background.image', true)
|
||||
return;
|
||||
}
|
||||
}
|
||||
app.dialog.showOpenDialog(currentwindow, {properties: ['openFile'], filters: [{name: 'Image', extensions: ['png', 'jpg', 'jpg', 'jpeg', 'gif']}]}, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
active_scene.background.image = fileNames[0]
|
||||
enterScene(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function setZoomLevel(mode) {
|
||||
switch (mode) {
|
||||
case 'in': Prop.zoom += 5; break;
|
||||
case 'out': Prop.zoom -= 5; break;
|
||||
case 'reset': Prop.zoom = 100; break;
|
||||
}
|
||||
var level = (Prop.zoom - 100) / 12
|
||||
currentwindow.webContents.setZoomLevel(level)
|
||||
setScreenRatio()
|
||||
}
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
if (preventClosing === true) {
|
||||
setTimeout(function() {
|
||||
showSaveDialog(true)
|
||||
}, 2)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
document.ondragover = document.ondrop = (ev) => {
|
||||
ev.preventDefault()
|
||||
}
|
||||
document.body.ondrop = (ev) => {
|
||||
if (ev.dataTransfer == undefined) {
|
||||
return;
|
||||
}
|
||||
if (ev.dataTransfer.files[0] != undefined) {
|
||||
ev.preventDefault()
|
||||
if (ev.dataTransfer.files[0].path.substr(-4).toUpperCase() == 'JSON') {
|
||||
readFile(ev.dataTransfer.files[0].path, true)
|
||||
} else if (ev.dataTransfer.files[0].path.substr(-7).toUpperCase() == 'BBSTYLE') {
|
||||
|
||||
fs.readFile(ev.dataTransfer.files[0].path, 'utf-8', function (err, data) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return;
|
||||
}
|
||||
applyBBStyle(data)
|
||||
})
|
||||
|
||||
|
||||
} else if (ev.dataTransfer.files[0].path.substr(-3).toUpperCase() == 'PNG') {
|
||||
|
||||
if (ev.target == canvas1) {
|
||||
active_scene.background.image = ev.dataTransfer.files[0].path
|
||||
enterScene(true)
|
||||
} else {
|
||||
|
||||
var fileArray = ev.dataTransfer.files;
|
||||
var len = fileArray.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
new Texture().fromPath(fileArray[i].path).add().fillParticle()
|
||||
}
|
||||
|
||||
|
||||
textures.forEach(function(s) {
|
||||
if (s === textures[textures.length-1]) {
|
||||
s.selected = true;
|
||||
} else {
|
||||
s.selected = false;
|
||||
}
|
||||
})
|
||||
loadTextureDraggable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showSaveDialog(close) {
|
||||
if (Blockbench.flags.includes('allow_reload')) {
|
||||
close = false
|
||||
}
|
||||
if (Prop.project_saved === false && elements.length > 0) {
|
||||
var answer = app.dialog.showMessageBox(currentwindow, {
|
||||
type: 'question',
|
||||
buttons: ['Save', 'Discard', 'Cancel'],
|
||||
title: 'Blockbench',
|
||||
message: 'Do you want to save your model?',
|
||||
noLink: true
|
||||
})
|
||||
if (answer === 0) {
|
||||
saveFile({closeAfter: close})
|
||||
return false;
|
||||
} else if (answer === 2) {
|
||||
return false;
|
||||
} else {
|
||||
if (close === true) {
|
||||
preventClosing = false
|
||||
setTimeout(function() {
|
||||
currentwindow.close()
|
||||
}, 12)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (close === true) {
|
||||
preventClosing = false
|
||||
setTimeout(function() {
|
||||
currentwindow.close()
|
||||
}, 12)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
1715
js/blockbench.js
Normal file
1056
js/canvas.js
Normal file
1446
js/display.js
Normal file
33
js/electron_updater.js
Normal file
@ -0,0 +1,33 @@
|
||||
showDialog('updater')
|
||||
$('#updater h2').text('Updating Electron. Please wait...')
|
||||
var received_bytes = 0;
|
||||
var total_bytes = 0;
|
||||
|
||||
$('.uc_btn').attr('disabled', true)
|
||||
|
||||
var installer_path = __dirname
|
||||
installer_path = installer_path.replace('app.asar', 'bbstp.exe')
|
||||
|
||||
var file = originalFs.createWriteStream(installer_path)
|
||||
|
||||
var request = http.get("http://blockbench.net/api/bbstp.exe", function(response) {
|
||||
response.pipe(file);
|
||||
|
||||
total_bytes = parseInt(response.headers['content-length']);
|
||||
|
||||
response.on('data', function(chunk) {
|
||||
received_bytes += chunk.length;
|
||||
setProgressBar('update_bar', received_bytes / total_bytes, 1);
|
||||
})
|
||||
response.on('end', function() {
|
||||
$('#updater h2').text('Painting cubes...')
|
||||
setProgressBar('update_bar', 0, 1);
|
||||
setProgressBar('update_bar', 1, 12000);
|
||||
|
||||
setTimeout(function() {
|
||||
exec(installer_path)
|
||||
preventClosing = false
|
||||
app.getCurrentWindow().close()
|
||||
}, 11111)
|
||||
})
|
||||
});
|
1233
js/elements.js
Normal file
200
js/extrude.js
Normal file
@ -0,0 +1,200 @@
|
||||
var ctx, ext_img, extrusion_canvas, ext_height, ext_width;
|
||||
var pixel_opacity_tolerance = 10
|
||||
|
||||
function drawExtrusionImage(path) {
|
||||
extrusion_canvas = $('#extrusion_canvas').get(0)
|
||||
ctx = extrusion_canvas.getContext('2d')
|
||||
|
||||
setProgressBar('extrusion_bar', 0)
|
||||
$('#scan_tolerance').on('input', function() {
|
||||
$('#scan_tolerance_label').text($(this).val())
|
||||
})
|
||||
|
||||
ext_img = new Image()
|
||||
ext_img.src = path
|
||||
ext_img.style.imageRendering = 'pixelated'
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
|
||||
ext_img.onload = function() {
|
||||
ctx.clearRect(0, 0, 256, 256);
|
||||
ctx.drawImage(ext_img, 0, 0, 256, 256)
|
||||
ext_width = ext_img.naturalWidth
|
||||
ext_height = ext_img.naturalHeight
|
||||
|
||||
if (ext_width > 128) return;
|
||||
|
||||
var g = 256 / ext_width;
|
||||
var p = 0
|
||||
ctx.beginPath();
|
||||
|
||||
for (var x = 0; x <= 256; x += g) {
|
||||
ctx.moveTo(0.5 + x + p, p);
|
||||
ctx.lineTo(0.5 + x + p, 256 + p);
|
||||
}
|
||||
for (var x = 0; x <= 256; x += g) {
|
||||
ctx.moveTo(p, 0.5 + x + p);
|
||||
ctx.lineTo(256 + p, 0.5 + x + p);
|
||||
}
|
||||
|
||||
ctx.strokeStyle = "black";
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
//Grid
|
||||
}
|
||||
|
||||
function convertExtrusionImage() {
|
||||
var scan_mode = $('select#scan_mode option:selected').attr('id') /*areas, lines, columns, pixels*/
|
||||
var texture_index = '#'+textures[textures.length-1].id
|
||||
var isNewProject = elements.length === 0;
|
||||
|
||||
pixel_opacity_tolerance = $('#scan_tolerance').val()
|
||||
function isOpaquePixel(px_x, px_y) {
|
||||
var pixel = ctx.getImageData(256*(px_x/ext_width)+1, 256*(px_y/ext_height)+1, 1, 1).data
|
||||
return pixel[3] >= pixel_opacity_tolerance;
|
||||
}
|
||||
|
||||
var ext_x, ext_y;
|
||||
var finished_pixels = []
|
||||
var cube_nr = 0;
|
||||
var cube_name = textures[textures.length-1].name.split('.')[0]
|
||||
selected = []
|
||||
//Scale Index
|
||||
var scale_i = 1;
|
||||
if (ext_width < ext_height) {
|
||||
ext_width = ext_height;
|
||||
}
|
||||
scale_i = 16 / ext_width;
|
||||
|
||||
//Scanning
|
||||
ext_y = 0;
|
||||
|
||||
asyncLoop({
|
||||
length : ext_height,
|
||||
functionToLoop : function(async_loop, i){
|
||||
setTimeout(function(){
|
||||
|
||||
ext_x = 0;
|
||||
while (ext_x < ext_width) {
|
||||
if (finished_pixels.includes(ext_x+'.'+ext_y) === false && isOpaquePixel(ext_x, ext_y) === true) {
|
||||
|
||||
//Search From New Pixel
|
||||
var loop = true;
|
||||
var rect = {x: ext_x, y: ext_y, x2: ext_x, y2: ext_y}
|
||||
|
||||
//Expanding Loop
|
||||
while (loop === true) {
|
||||
var y_check, x_check, canExpandX, canExpandY;
|
||||
//Expand X
|
||||
if (scan_mode === 'areas' || scan_mode === 'lines') {
|
||||
y_check = rect.y
|
||||
x_check = rect.x2 + scale_i
|
||||
canExpandX = true
|
||||
while (y_check <= rect.y2) {
|
||||
//Check If Row is Free
|
||||
if (isOpaquePixel(x_check, y_check) === false || finished_pixels.includes(x_check+'.'+y_check) === true) {
|
||||
canExpandX = false;
|
||||
}
|
||||
y_check += scale_i
|
||||
}
|
||||
if (canExpandX === true) {
|
||||
rect.x2 += scale_i
|
||||
}
|
||||
} else {
|
||||
canExpandX = false;
|
||||
}
|
||||
//Expand Y
|
||||
if (scan_mode === 'areas' || scan_mode === 'columns') {
|
||||
x_check = rect.x
|
||||
y_check = rect.y2 + scale_i
|
||||
canExpandY = true
|
||||
while (x_check <= rect.x2) {
|
||||
//Check If Row is Free
|
||||
if (isOpaquePixel(x_check, y_check) === false || finished_pixels.includes(x_check+'.'+y_check) === true) {
|
||||
canExpandY = false
|
||||
}
|
||||
x_check += scale_i
|
||||
}
|
||||
if (canExpandY === true) {
|
||||
rect.y2 += scale_i
|
||||
}
|
||||
} else {
|
||||
canExpandY = false;
|
||||
}
|
||||
//Conclusion
|
||||
if (canExpandX === false && canExpandY === false) {
|
||||
loop = false;
|
||||
}
|
||||
}
|
||||
if (scan_mode === 'areas' || scan_mode === 'columns') {
|
||||
rect.x2 += scale_i-1;
|
||||
}
|
||||
if (scan_mode === 'areas' || scan_mode === 'columns') {
|
||||
rect.y2 += scale_i-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Draw Rectangle
|
||||
var draw_x = rect.x
|
||||
var draw_y = rect.y
|
||||
while (draw_y <= rect.y2) {
|
||||
draw_x = rect.x
|
||||
while (draw_x <= rect.x2) {
|
||||
finished_pixels.push(draw_x+'.'+draw_y)
|
||||
draw_x++;
|
||||
}
|
||||
draw_y++;
|
||||
}
|
||||
var current_cube = new Cube(cube_name+'_'+cube_nr)
|
||||
|
||||
current_cube.from = [rect.x*scale_i, 0, rect.y*scale_i]
|
||||
current_cube.to = [(rect.x2+1)*scale_i, scale_i, (rect.y2+1)*scale_i]
|
||||
current_cube.display.autouv = false
|
||||
|
||||
//Sides
|
||||
current_cube.faces.up = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index}
|
||||
current_cube.faces.down = {uv:[rect.x*scale_i, (rect.y2+1)*scale_i, (rect.x2+1)*scale_i, rect.y*scale_i], texture: texture_index}
|
||||
|
||||
current_cube.faces.north = {uv:[(rect.x2+1)*scale_i, rect.y*scale_i, rect.x*scale_i, (rect.y+1)*scale_i], texture: texture_index}
|
||||
current_cube.faces.south = {uv:[rect.x*scale_i, rect.y2*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index}
|
||||
|
||||
current_cube.faces.east = {uv:[rect.x2*scale_i, rect.y*scale_i, (rect.x2+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 90}
|
||||
current_cube.faces.west = {uv:[rect.x*scale_i, rect.y*scale_i, (rect.x+1)*scale_i, (rect.y2+1)*scale_i], texture: texture_index, rotation: 270}
|
||||
|
||||
elements.push(current_cube)
|
||||
selected.push(elements.length-1)
|
||||
cube_nr++;
|
||||
}
|
||||
|
||||
|
||||
ext_x++;
|
||||
}
|
||||
setProgressBar('extrusion_bar', ext_y/ext_height, ext_width*2)
|
||||
ext_y++;
|
||||
async_loop()
|
||||
|
||||
},ext_width*2);
|
||||
},
|
||||
callback : function(){
|
||||
setProgressBar('extrusion_bar', 1)
|
||||
|
||||
var group = new Group(cube_name).addTo()
|
||||
selected.forEach(function(s) {
|
||||
elements[s].addTo(group)
|
||||
})
|
||||
if (g_makeNew === true || isNewProject) {
|
||||
Prop.file_name = cube_name
|
||||
Project.name = cube_name
|
||||
$('title').text(cube_name+' - Blockbench')
|
||||
Prop.project_saved = false;
|
||||
}
|
||||
|
||||
Canvas.updateAll()
|
||||
setUndo()
|
||||
hideDialog()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
188
js/file_saver.js
Normal file
@ -0,0 +1,188 @@
|
||||
/* FileSaver.js
|
||||
* A saveAs() FileSaver implementation.
|
||||
* 1.3.2
|
||||
* 2016-06-16 18:25:19
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
* License: MIT
|
||||
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
/*global self */
|
||||
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
|
||||
|
||||
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||
|
||||
var saveAs = saveAs || (function(view) {
|
||||
"use strict";
|
||||
// IE <10 is explicitly unsupported
|
||||
if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
|
||||
return;
|
||||
}
|
||||
var
|
||||
doc = view.document
|
||||
// only get URL when necessary in case Blob.js hasn't overridden it yet
|
||||
, get_URL = function() {
|
||||
return view.URL || view.webkitURL || view;
|
||||
}
|
||||
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||
, can_use_save_link = "download" in save_link
|
||||
, click = function(node) {
|
||||
var event = new MouseEvent("click");
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
|
||||
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
|
||||
, throw_outside = function(ex) {
|
||||
(view.setImmediate || view.setTimeout)(function() {
|
||||
throw ex;
|
||||
}, 0);
|
||||
}
|
||||
, force_saveable_type = "application/octet-stream"
|
||||
// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
|
||||
, arbitrary_revoke_timeout = 1000 * 40 // in ms
|
||||
, revoke = function(file) {
|
||||
var revoker = function() {
|
||||
if (typeof file === "string") { // file is an object URL
|
||||
get_URL().revokeObjectURL(file);
|
||||
} else { // file is a File
|
||||
file.remove();
|
||||
}
|
||||
};
|
||||
setTimeout(revoker, arbitrary_revoke_timeout);
|
||||
}
|
||||
, dispatch = function(filesaver, event_types, event) {
|
||||
event_types = [].concat(event_types);
|
||||
var i = event_types.length;
|
||||
while (i--) {
|
||||
var listener = filesaver["on" + event_types[i]];
|
||||
if (typeof listener === "function") {
|
||||
try {
|
||||
listener.call(filesaver, event || filesaver);
|
||||
} catch (ex) {
|
||||
throw_outside(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
, auto_bom = function(blob) {
|
||||
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
, FileSaver = function(blob, name, no_auto_bom) {
|
||||
if (!no_auto_bom) {
|
||||
blob = auto_bom(blob);
|
||||
}
|
||||
// First try a.download, then web filesystem, then object URLs
|
||||
var
|
||||
filesaver = this
|
||||
, type = blob.type
|
||||
, force = type === force_saveable_type
|
||||
, object_url
|
||||
, dispatch_all = function() {
|
||||
dispatch(filesaver, "writestart progress write writeend".split(" "));
|
||||
}
|
||||
// on any filesys errors revert to saving with object URLs
|
||||
, fs_error = function() {
|
||||
if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
|
||||
// Safari doesn't allow downloading of blob urls
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {
|
||||
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
|
||||
var popup = view.open(url, '_blank');
|
||||
if(!popup) view.location.href = url;
|
||||
url=undefined; // release reference before dispatching
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
filesaver.readyState = filesaver.INIT;
|
||||
return;
|
||||
}
|
||||
// don't create more object URLs than needed
|
||||
if (!object_url) {
|
||||
object_url = get_URL().createObjectURL(blob);
|
||||
}
|
||||
if (force) {
|
||||
view.location.href = object_url;
|
||||
} else {
|
||||
var opened = view.open(object_url, "_blank");
|
||||
if (!opened) {
|
||||
// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
|
||||
view.location.href = object_url;
|
||||
}
|
||||
}
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
dispatch_all();
|
||||
revoke(object_url);
|
||||
}
|
||||
;
|
||||
filesaver.readyState = filesaver.INIT;
|
||||
|
||||
if (can_use_save_link) {
|
||||
object_url = get_URL().createObjectURL(blob);
|
||||
setTimeout(function() {
|
||||
save_link.href = object_url;
|
||||
save_link.download = name;
|
||||
click(save_link);
|
||||
dispatch_all();
|
||||
revoke(object_url);
|
||||
filesaver.readyState = filesaver.DONE;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fs_error();
|
||||
}
|
||||
, FS_proto = FileSaver.prototype
|
||||
, saveAs = function(blob, name, no_auto_bom) {
|
||||
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
|
||||
}
|
||||
;
|
||||
// IE 10+ (native saveAs)
|
||||
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
|
||||
return function(blob, name, no_auto_bom) {
|
||||
name = name || blob.name || "download";
|
||||
|
||||
if (!no_auto_bom) {
|
||||
blob = auto_bom(blob);
|
||||
}
|
||||
return navigator.msSaveOrOpenBlob(blob, name);
|
||||
};
|
||||
}
|
||||
|
||||
FS_proto.abort = function(){};
|
||||
FS_proto.readyState = FS_proto.INIT = 0;
|
||||
FS_proto.WRITING = 1;
|
||||
FS_proto.DONE = 2;
|
||||
|
||||
FS_proto.error =
|
||||
FS_proto.onwritestart =
|
||||
FS_proto.onprogress =
|
||||
FS_proto.onwrite =
|
||||
FS_proto.onabort =
|
||||
FS_proto.onerror =
|
||||
FS_proto.onwriteend =
|
||||
null;
|
||||
|
||||
return saveAs;
|
||||
}(
|
||||
typeof self !== "undefined" && self
|
||||
|| typeof window !== "undefined" && window
|
||||
|| this.content
|
||||
));
|
||||
// `self` is undefined in Firefox for Android content script context
|
||||
// while `this` is nsIContentFrameMessageManager
|
||||
// with an attribute `content` that corresponds to the window
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports.saveAs = saveAs;
|
||||
} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) {
|
||||
define("FileSaver.js", function() {
|
||||
return saveAs;
|
||||
});
|
||||
}
|
416
js/interface.js
Normal file
@ -0,0 +1,416 @@
|
||||
var app_colors, canvas_scenes, active_scene;
|
||||
scenesSetup()
|
||||
|
||||
function colorSettingsSetup(reset) {
|
||||
app_colors = {
|
||||
back: {hex: '#21252b'},
|
||||
dark: {hex: '#17191d'},
|
||||
border: {hex: '#181a1f'},
|
||||
ui: {hex: '#282c34'},
|
||||
accent: {hex: '#3e90ff'},
|
||||
grid: {hex: '#495061'},
|
||||
button: {hex: '#3a3f4b'},
|
||||
hover: {hex: '#495061'},
|
||||
text: {hex: '#cacad4'},
|
||||
light: {hex: '#f4f3ff'},
|
||||
text_acc: {hex: '#000006'},
|
||||
main: {font: ''},
|
||||
headline: {font: ''},
|
||||
css: ''
|
||||
}
|
||||
if (reset) {
|
||||
$('#layout_font_main').val('')
|
||||
$('#layout_font_headline').val('')
|
||||
changeUIFont('main')
|
||||
changeUIFont('headline')
|
||||
$('style#bbstyle').text('')
|
||||
setScreenRatio()
|
||||
}
|
||||
if (localStorage.getItem('app_colors') != null && reset != true) {
|
||||
var stored_app_colors = JSON.parse(localStorage.getItem('app_colors'))
|
||||
$.extend(app_colors, stored_app_colors)
|
||||
}
|
||||
updateUIColor()
|
||||
calcCanvasGridSize()
|
||||
buildGrid()
|
||||
}
|
||||
|
||||
function showDialog(dialog) {
|
||||
var obj = $('.dialog#'+dialog)
|
||||
$('.dialog').hide(0)
|
||||
$('#blackout').fadeIn(200)
|
||||
obj.fadeIn(200)
|
||||
setTimeout(function() {
|
||||
$('.context_handler.ctx').removeClass('ctx')
|
||||
}, 64)
|
||||
open_dialog = dialog
|
||||
//Draggable
|
||||
if (obj.hasClass('draggable')) {
|
||||
obj.draggable({
|
||||
handle: ".dialog_handle",
|
||||
containment: 'body'
|
||||
})
|
||||
var x = ($(window).width()-obj.width())/2
|
||||
obj.css('left', x+'px')
|
||||
obj.css('top', '64px')
|
||||
}
|
||||
|
||||
//Specific
|
||||
if (dialog === 'file_loader') {
|
||||
$('#file_upload').val('')
|
||||
$('#file_folder').val('')
|
||||
$('#web_import_btn').unbind()
|
||||
} else if (dialog === 'selection_creator') {
|
||||
$('#selection_creator input#selgen_name').select()
|
||||
} else if (dialog === 'plugins') {
|
||||
$('#plugin_list').css('max-height', ($(window).height() - 320) +'px')
|
||||
}
|
||||
}
|
||||
function hideDialog() {
|
||||
$('#blackout').fadeOut(200)
|
||||
$('.dialog').fadeOut(200)
|
||||
open_dialog = false;
|
||||
}
|
||||
function setSettingsTab(tab) {
|
||||
$('#settings .tab.open').removeClass('open')
|
||||
$('#settings .tab#'+tab).addClass('open')
|
||||
$('#settings .tab_content').addClass('hidden')
|
||||
$('#settings .tab_content#'+tab).removeClass('hidden')
|
||||
if (tab === 'keybindings') {
|
||||
//Keybinds
|
||||
$('#keybindlist').css('max-height', ($(window).height() - 320) +'px')
|
||||
} else if (tab === 'setting') {
|
||||
//Settings
|
||||
$('#settingslist').css('max-height', ($(window).height() - 320) +'px')
|
||||
} else if (tab === 'layout_settings') {
|
||||
$('#layout_font_main').val(app_colors.main.font)
|
||||
$('#layout_font_headline').val(app_colors.headline.font)
|
||||
}
|
||||
}
|
||||
function textPrompt(title, var_string, value, callback) {
|
||||
showDialog('text_input')
|
||||
$('#text_input h2').text(title)
|
||||
if (value === true) {
|
||||
//Get Previous Value For Input
|
||||
eval('value = '+var_string)
|
||||
try {
|
||||
eval('value = '+var_string)
|
||||
} catch(err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
$('#text_input input#text_input_field').val(value).select()
|
||||
$('#text_input button.confirm_btn').off()
|
||||
$('#text_input button.confirm_btn').click(function() {
|
||||
var s = $('#text_input input#text_input_field').val()
|
||||
if (callback !== undefined) {
|
||||
callback(s)
|
||||
}
|
||||
if (var_string == '') return;
|
||||
try {
|
||||
eval(var_string + ' = "'+s+'"')
|
||||
} catch(err) {
|
||||
console.error(err)
|
||||
}
|
||||
})
|
||||
// textPrompt('Texture Name', 'textures[0].name')
|
||||
}
|
||||
function renameCubeList(name) {
|
||||
selected.forEach(function(s, i) {
|
||||
elements[s].name = name.split('%').join(s).split('$').join(i)
|
||||
})
|
||||
}
|
||||
|
||||
//Scenes
|
||||
function enterScene(scene) {
|
||||
var container = $('div#preview')
|
||||
var scene_controls = $('#scene_controls')
|
||||
if (scene !== true) {
|
||||
active_scene = canvas_scenes[scene]
|
||||
} else {
|
||||
}
|
||||
if (active_scene.background.image !== false) {
|
||||
|
||||
//Background
|
||||
container.css('background-image', 'url("'+active_scene.background.image.split('\\').join('/')+'")')
|
||||
updateScenePosition()
|
||||
|
||||
//Panel
|
||||
scene_controls.fadeIn(100)
|
||||
$('#scene_controls_panel').hide(0)
|
||||
scene_controls.find('img').attr('src', active_scene.background.image)
|
||||
scene_controls.find('#scene_controls_toggle i').text('first_page')
|
||||
|
||||
if (active_scene.background.lock === 'disabled') {
|
||||
scene_controls.find('.scene_lock').hide()
|
||||
} else {
|
||||
scene_controls.find('.scene_lock').show()
|
||||
}
|
||||
|
||||
} else {
|
||||
container.css('background-image', 'none')
|
||||
scene_controls.fadeOut(100)
|
||||
}
|
||||
}
|
||||
function clearBackgroundImage() {
|
||||
active_scene.background.image = false;
|
||||
enterScene(true)
|
||||
}
|
||||
function updateScenePosition(zoom) {
|
||||
if (zoom === undefined) zoom = 1
|
||||
if (isOrtho === true && active_scene.background.lock === false) zoom = cameraOrtho.zoom
|
||||
if (active_scene.background.lock === true) zoom = 1
|
||||
|
||||
var offset = [0, 0];
|
||||
|
||||
if (isOrtho === true && active_scene.background.lock !== true) {
|
||||
|
||||
offset.forEach(function(s, i) {
|
||||
s = cameraOrtho.backgroundHandle[i].n === true ? 1 : -1
|
||||
s = s * controls.target[cameraOrtho.backgroundHandle[i].a]
|
||||
s = s * zoom * 40;
|
||||
offset[i] = s
|
||||
})
|
||||
}
|
||||
|
||||
var pos_x = offset[0] + (active_scene.background.x * zoom) + c_width/2 - (active_scene.background.size * zoom) / 2
|
||||
var pos_y = offset[1] + (active_scene.background.y * zoom) + c_height/2 - ((active_scene.background.size / active_scene.background.ratio) * zoom) / 2
|
||||
|
||||
$('div#preview').css('background-position', pos_x + 'px ' + pos_y+'px')
|
||||
.css('background-size', active_scene.background.size * zoom +'px')
|
||||
|
||||
}
|
||||
function updateBackgroundRatio() {
|
||||
//Update Ratio
|
||||
var img = $('#scene_controls img')[0]
|
||||
active_scene.background.ratio = img.naturalWidth / img.naturalHeight
|
||||
updateScenePosition()
|
||||
}
|
||||
function toggleScenePanel() {
|
||||
var scene_controls = $('#scene_controls')
|
||||
if (scene_controls.find('#scene_controls_panel').is(':visible')) {
|
||||
//Hide
|
||||
scene_controls.find('#scene_controls_panel').hide(200)
|
||||
scene_controls.find('#scene_controls_toggle i').text('first_page')
|
||||
} else {
|
||||
//Show
|
||||
scene_controls.find('#scene_controls_panel').show(200)
|
||||
scene_controls.find('#scene_controls_toggle i').text('last_page')
|
||||
|
||||
scene_controls.find('input#scene_size').val(active_scene.background.size)
|
||||
scene_controls.find('input#scene_x').val(active_scene.background.x)
|
||||
scene_controls.find('input#scene_y').val(active_scene.background.y)
|
||||
scene_controls.find('input#scene_fixed').prop('checked', active_scene.background.y === true)
|
||||
}
|
||||
}
|
||||
function updateScenePanelControls() {
|
||||
var scene_controls = $('#scene_controls')
|
||||
active_scene.background.size = limitNumber(parseInt( scene_controls.find('input#scene_size').val()) )
|
||||
active_scene.background.x = limitNumber(parseInt( scene_controls.find('input#scene_x').val()) )
|
||||
active_scene.background.y = limitNumber(parseInt( scene_controls.find('input#scene_y').val()) )
|
||||
active_scene.background.lock = scene_controls.find('input#scene_fixed').is(':checked')
|
||||
updateScenePosition()
|
||||
}
|
||||
|
||||
function scenesSetup(reset) {
|
||||
canvas_scenes = {
|
||||
normal: {name: 'Normal', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
ortho0: {name: 'Ortho 0', background: {image: false, size: 1000, x: 0, y: 0}},
|
||||
ortho1: {name: 'Ortho 1', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: false}},
|
||||
ortho2: {name: 'Ortho 2', background: {image: false, size: 1200, x: 0, y: 0, ratio: 1, lock: false}},
|
||||
ortho3: {name: 'Ortho 3', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: false}},
|
||||
ortho4: {name: 'Ortho 4', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: false}},
|
||||
ortho5: {name: 'Ortho 5', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: false}},
|
||||
|
||||
thirdperson_righthand: {name: 'thirdperson_righthand', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
thirdperson_lefthand: {name: 'thirdperson_lefthand', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
firstperson_righthand: {name: 'firstperson_righthand', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
firstperson_lefthand: {name: 'firstperson_lefthand', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
|
||||
head: {name: 'head', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
ground: {name: 'ground', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
fixed: {name: 'fixed', background: {image: false, size: 1000, x: 0, y: 0, ratio: 1, lock: 'disabled'}},
|
||||
gui: {name: 'gui', background: {image: './assets/inventory.png', size: 1020, x: 0, y: 0, ratio: 1, lock: false}}
|
||||
}
|
||||
if (localStorage.getItem('canvas_scenes') != null && reset != true) {
|
||||
var stored_canvas_scenes = JSON.parse(localStorage.getItem('canvas_scenes'))
|
||||
$.extend(canvas_scenes, stored_canvas_scenes)
|
||||
}
|
||||
active_scene = canvas_scenes.normal
|
||||
}
|
||||
|
||||
|
||||
//Color
|
||||
function initUIColor(event) {
|
||||
var type = $(event.target).attr('id').split('color_')[1]
|
||||
$('input#color_'+type).val(app_colors[type].hex)
|
||||
}
|
||||
function changeUIColor(event) {
|
||||
var type = $(event.target).attr('id').split('color_')[1]
|
||||
|
||||
app_colors[type].hex = $('input#color_'+type).val()
|
||||
updateUIColor()
|
||||
}
|
||||
function changeUIFont(type) {
|
||||
var font = $('#layout_font_'+type).val()
|
||||
app_colors[type].font = font
|
||||
if (type === 'main') {
|
||||
$('body').css('font-family', app_colors[type].font)
|
||||
} else {
|
||||
$('h1, h2, h3, h4, h5').css('font-family', app_colors[type].font)
|
||||
}
|
||||
}
|
||||
function updateUIColor() {
|
||||
for (var type in app_colors) {
|
||||
if (app_colors.hasOwnProperty(type)) {
|
||||
if (type === 'css') {
|
||||
$('style#bbstyle').text(app_colors.css)
|
||||
} else if (app_colors[type].hex) {
|
||||
document.body.style.setProperty('--color-'+type, app_colors[type].hex);
|
||||
} else if (app_colors[type].font) {
|
||||
if (type === 'main') {
|
||||
$('body').css('font-family', app_colors[type].font)
|
||||
} else {
|
||||
$('h1, h2, h3, h4, h5').css('font-family', app_colors[type].font)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var grid_color = '0x'+app_colors.hover.hex.replace('#', '')
|
||||
|
||||
try {
|
||||
three_grid.getObjectByName('grid').material.color = new THREE.Color(parseInt(grid_color, 16))
|
||||
} catch(err) {}
|
||||
|
||||
localStorage.setItem('app_colors', JSON.stringify(app_colors))
|
||||
}
|
||||
|
||||
function importLayout() {
|
||||
Blockbench.import('bbstyle', function(content) {
|
||||
applyBBStyle(content)
|
||||
})
|
||||
}
|
||||
function applyBBStyle(data) {
|
||||
if (typeof data === 'string') {
|
||||
try {
|
||||
data = JSON.parse(data)
|
||||
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (typeof data !== 'object') return;
|
||||
$.extend(app_colors, data)
|
||||
if (data.css) {
|
||||
$('style#bbstyle').text(data.css)
|
||||
setScreenRatio()
|
||||
}
|
||||
updateUIColor()
|
||||
}
|
||||
function exportLayout() {
|
||||
Blockbench.export(autoStringify(app_colors), 'layout', 'bbstyle')
|
||||
}
|
||||
|
||||
function showQuickMessage(message, time) {
|
||||
var quick_message_box = $('<div id="quick_message_box" class="hidden"></div>')
|
||||
$('body').append(quick_message_box)
|
||||
|
||||
quick_message_box.text(message)
|
||||
quick_message_box.fadeIn(100)
|
||||
setTimeout(function() {
|
||||
quick_message_box.fadeOut(100)
|
||||
setTimeout(function() {
|
||||
quick_message_box.remove()
|
||||
}, 100)
|
||||
}, time ? time : 1000)
|
||||
}
|
||||
function showStatusMessage(message, time) { //Shows a quick message in the status bar
|
||||
var status_message = $('#status_message')
|
||||
var status_name = $('#status_name')
|
||||
|
||||
status_message.text(message)
|
||||
|
||||
status_name.hide(100)
|
||||
status_message.show(100)
|
||||
|
||||
setTimeout(function() {
|
||||
status_message.hide(100)
|
||||
status_name.show(100)
|
||||
}, time ? time : 600)
|
||||
}
|
||||
function setProgressBar(id, val, time) {
|
||||
$('#'+id+' > .progress_bar_inner').animate({width: val*488}, time-1)
|
||||
}
|
||||
|
||||
//Tooltip
|
||||
|
||||
function showShiftTooltip() {
|
||||
$(':hover').find('.tooltip_shift').css('display', 'inline')
|
||||
}
|
||||
$(document).keyup(function(event) {
|
||||
if (event.which === 16) {
|
||||
$('.tooltip_shift').hide()
|
||||
}
|
||||
})
|
||||
/*
|
||||
function updateCubeList() {
|
||||
Vue.nextTick(function() {
|
||||
$('.cube_context').on('click', function(event) {
|
||||
var ul = $(this).find('ul')
|
||||
var pos = $(window).height() - event.clientY
|
||||
if (pos < 110) {
|
||||
ul.css('top', '-120px');
|
||||
} else {
|
||||
ul.css('top', '24px');
|
||||
}
|
||||
})
|
||||
})
|
||||
}*/
|
||||
|
||||
function setInterfaceMode(mode) {
|
||||
$('.mode_tab').removeClass('open')
|
||||
$('.mode_tab#mode_'+mode+'_tab').addClass('open')
|
||||
setScreenRatio()
|
||||
}
|
||||
|
||||
//Menu
|
||||
function updateMenu() {
|
||||
//Settings Dependent
|
||||
$('header .settings_dependent').each(function(i, o) {
|
||||
var set = $(o).attr('setting')
|
||||
if (settings[set] && settings[set].value === true) {
|
||||
$(o).text('check_box')
|
||||
} else {
|
||||
$(o).text('check_box_outline_blank')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Mobile
|
||||
function setMobileTab(mode) {
|
||||
$('.mobile_mode_tab').removeClass('open')
|
||||
$('#mobile_tab_'+mode).addClass('open')
|
||||
//
|
||||
$('.sidebar').css('grid-area', '')
|
||||
$('#preview').css('grid-area', '')
|
||||
$('header').css('grid-area', '')
|
||||
switch (mode) {
|
||||
case 'preview':
|
||||
$('#preview').css('grid-area', 'main')
|
||||
break;
|
||||
case 'textures':
|
||||
$('#left_bar').css('grid-area', 'main')
|
||||
break;
|
||||
case 'elements':
|
||||
$('#right_bar').css('grid-area', 'main')
|
||||
break;
|
||||
case 'menu':
|
||||
$('header').css('grid-area', 'main')
|
||||
break;
|
||||
}
|
||||
setScreenRatio()
|
||||
}
|
480
js/io.js
Normal file
@ -0,0 +1,480 @@
|
||||
|
||||
//IO
|
||||
function buildBlockModel(options) { //Export Blockmodel
|
||||
if (options === undefined) options = {}
|
||||
var clear_elements = []
|
||||
var textures_used = []
|
||||
var element_index_lut = []
|
||||
|
||||
function computeCube(s) {
|
||||
if (s.display.export == false) return;
|
||||
//Create Element
|
||||
var element = {}
|
||||
$.extend(true, element, s)
|
||||
element_index_lut[s.index()] = clear_elements.length
|
||||
|
||||
if (element.shade === true) {
|
||||
delete element.shade
|
||||
}
|
||||
if (settings.minifiedout.value === true && element.name !== undefined) {
|
||||
delete element.name
|
||||
}
|
||||
clear_elements.push(omitKeys(element, ['display', 'uuid', 'title', 'icon', 'isParent', 'buttons']))
|
||||
//Gather Textures
|
||||
for (var face in s.faces) {
|
||||
if (s.faces.hasOwnProperty(face)) {
|
||||
if (!textures_used.includes(s.faces[face].texture)) {
|
||||
textures_used.push(s.faces[face].texture)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function iterate(arr) {
|
||||
var i = 0;
|
||||
if (!arr || !arr.length) {
|
||||
console.log('return')
|
||||
return;
|
||||
}
|
||||
for (i=0; i<arr.length; i++) {
|
||||
if (arr[i].title === 'Cube') {
|
||||
computeCube(arr[i])
|
||||
console.log(arr[i])
|
||||
} else if (arr[i].title === 'Group') {
|
||||
console.log('g')
|
||||
iterate(arr[i].children)
|
||||
}
|
||||
}
|
||||
}
|
||||
iterate(TreeElements)
|
||||
|
||||
|
||||
clear_elements.forEach(function(s) {
|
||||
for (var face in s.faces) {
|
||||
if (s.faces.hasOwnProperty(face)) {
|
||||
if (s.faces[face].texture === '$transparent') {
|
||||
delete s.faces[face]
|
||||
} else if (s.faces[face].texture == undefined) {
|
||||
s.faces[face].texture = '#missing'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function checkExport(key, condition) {
|
||||
key = options[key]
|
||||
if (key === undefined) {
|
||||
return condition;
|
||||
} else {
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
var texturesObj = {}
|
||||
textures.forEach(function(s, i){
|
||||
if (!textures_used.includes('#'+s.id)) return;
|
||||
texturesObj[s.id] = s.javaTextureLink()
|
||||
if (s.particle) {
|
||||
texturesObj.particle = s.javaTextureLink()
|
||||
}
|
||||
})
|
||||
|
||||
var blockmodel = {}
|
||||
if (checkExport('description', Project.description !== '')) {
|
||||
blockmodel.description = Project.description;
|
||||
}
|
||||
if (checkExport('comment', settings.comment.value === true)) {
|
||||
blockmodel.credit = settings.comment_text.value
|
||||
}
|
||||
if (checkExport('parent', Project.parent != '')) {
|
||||
blockmodel.parent = Project.parent
|
||||
}
|
||||
if (checkExport('ambientocclusion', Project.ambientocclusion)) {
|
||||
blockmodel.ambientocclusion = false
|
||||
}
|
||||
if (checkExport('textures', Object.keys(texturesObj).length >= 1)) {
|
||||
blockmodel.textures = texturesObj
|
||||
}
|
||||
if (checkExport('elements', elements.length >= 1)) {
|
||||
blockmodel.elements = clear_elements
|
||||
}
|
||||
if (checkExport('groups', settings.export_groups.value)) {
|
||||
blockmodel.groups = compileGroups(undefined, element_index_lut)
|
||||
}
|
||||
if (checkExport('display', Object.keys(display).length >= 1)) {
|
||||
blockmodel.display = display
|
||||
}
|
||||
if (options.raw) {
|
||||
return blockmodel
|
||||
} else {
|
||||
return autoStringify(blockmodel)
|
||||
}
|
||||
}
|
||||
function loadFile(data, filepath, makeNew) { //Load File Into GUI
|
||||
var previous_length = 0
|
||||
var previous_texture_length = 0
|
||||
if (makeNew === true) {
|
||||
//Create New Project
|
||||
if (newProject() == false) return;
|
||||
Prop.file_path = filepath
|
||||
Prop.file_name = pathToName(Prop.file_path, true)
|
||||
Project.name = pathToName(Prop.file_path, false)
|
||||
if (Project.name.length > 0) {
|
||||
$('title').text(Project.name+' - Blockbench')
|
||||
} else {
|
||||
$('title').text('Blockbench')
|
||||
}
|
||||
Prop.project_saved = true;
|
||||
} else {
|
||||
//Add to Current Project
|
||||
previous_length = elements.length
|
||||
previous_texture_length = textures.length
|
||||
added_model_index++;
|
||||
var import_group = new Group(pathToName(Prop.file_path, false))
|
||||
}
|
||||
|
||||
data = JSON.parse(data)
|
||||
|
||||
//Check if PE Model
|
||||
for (var key in data) {
|
||||
if (key.includes('geometry.')) {
|
||||
loadPEModelFile(data)
|
||||
return;
|
||||
}
|
||||
}
|
||||
settings.entity_mode.value = false;
|
||||
saveSettings()
|
||||
|
||||
|
||||
//Load
|
||||
if (data.display !== undefined) {
|
||||
display = data.display
|
||||
}
|
||||
|
||||
if (data.elements) {
|
||||
data.elements.forEach(function(s) {
|
||||
base_cube = new Cube()
|
||||
base_cube.extend(s)
|
||||
for (var face in base_cube.faces) {
|
||||
if (s.faces[face] === undefined) {
|
||||
base_cube.faces[face].texture = '$transparent'
|
||||
base_cube.faces[face].uv = [0,0,0,0]
|
||||
}
|
||||
}
|
||||
base_cube.uuid = guid()
|
||||
base_cube.display.autouv = false;
|
||||
elements.push(base_cube);
|
||||
if (makeNew === true) {
|
||||
base_cube.addTo()
|
||||
} else if (import_group) {
|
||||
base_cube.addTo(import_group)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (data.groups && data.groups.length > 0) {
|
||||
parseGroups(data.groups)
|
||||
if (import_group) {
|
||||
TreeElements.forEach(function(s) {
|
||||
s.addTo(import_group)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (import_group) {
|
||||
import_group.addTo()
|
||||
}
|
||||
|
||||
//Create Path Array to fetch textures
|
||||
var path_arr = filepath.split(osfs)
|
||||
path_arr.splice(-3)
|
||||
path_arr = path_arr.join(osfs)
|
||||
var texture_arr = data.textures
|
||||
var names = []
|
||||
for (var tex in texture_arr) {
|
||||
if (texture_arr.hasOwnProperty(tex)) {
|
||||
if (tex != 'particle') {
|
||||
var path = path_arr+osfs+'textures'+osfs+texture_arr[tex].split('/').join(osfs)+'.png'
|
||||
new Texture({id: tex}).fromPath(path).add()
|
||||
|
||||
names.push(texture_arr[tex])
|
||||
}
|
||||
}
|
||||
}
|
||||
if (texture_arr === undefined) texture_arr = {}
|
||||
if (texture_arr.particle) {
|
||||
var path = path_arr+osfs+'textures'+osfs+texture_arr.particle.split('/').join(osfs)+'.png'
|
||||
if (names.includes(texture_arr.particle)) {
|
||||
textures.forEach(function(s) {
|
||||
if (s.path == path) {
|
||||
s.enableParticle()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
new Texture({id: 'particle'}).enableParticle().fromPath(path).add()
|
||||
}
|
||||
}
|
||||
//Get Rid Of ID overlapping
|
||||
textures.forEach(function(t, i) {
|
||||
if (i >= previous_texture_length) {
|
||||
if (getTexturesById(t.id).length > 1) {
|
||||
var before = t.id
|
||||
t.id = added_model_index + '_' + t.id
|
||||
elements.forEach(function(s, si) {
|
||||
if (si >= previous_length) {
|
||||
for (var face in s.faces) {
|
||||
if (s.faces[face].texture === '#'+before) {
|
||||
s.faces[face].texture = '#'+t.id
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
//Select Last Texture
|
||||
if (textures.length > 0) {
|
||||
textures.forEach(function(s) {
|
||||
s.selected = false;
|
||||
})
|
||||
textures[textures.length-1].selected = true;
|
||||
}
|
||||
//Set Parent
|
||||
if (data.parent !== undefined) {
|
||||
Project.parent = data.parent;
|
||||
}
|
||||
//Set Ambient Occlusion
|
||||
if (data.ambientocclusion === false) {
|
||||
Project.ambientocclusion = false;
|
||||
}
|
||||
loadTextureDraggable()
|
||||
Canvas.updateAll()
|
||||
setUndo('Opened project')
|
||||
if (makeNew) {
|
||||
Prop.project_saved = true;
|
||||
}
|
||||
}
|
||||
function loadPEModelFile(data) {
|
||||
pe_list_data.length = 0
|
||||
entityMode.join()
|
||||
saveSettings()
|
||||
|
||||
for (var key in data) {
|
||||
if (key.includes('geometry.') && data.hasOwnProperty(key)) {
|
||||
var base_model = {name: key, bonecount: 0, selected: false, object: data[key]}
|
||||
if (data[key].bones) {
|
||||
base_model.bonecount = data[key].bones.length
|
||||
}
|
||||
pe_list_data.push(base_model)
|
||||
}
|
||||
}
|
||||
|
||||
if (pe_list == undefined) {
|
||||
pe_list = new Vue({
|
||||
el: '#pe_list',
|
||||
data: {
|
||||
search_text: '',
|
||||
list: pe_list_data
|
||||
},
|
||||
methods: {
|
||||
selectE: function(item, event) {
|
||||
var index = pe_list_data.indexOf(item)
|
||||
pe_list_data.forEach(function(s) {
|
||||
s.selected = false;
|
||||
})
|
||||
pe_list_data[index].selected = true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
searched() {
|
||||
var scope = this;
|
||||
return this.list.filter(item => {
|
||||
return item.name.toUpperCase().includes(scope.search_text)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// pe_list._data = {pe_list_data}
|
||||
// pe_list.$forceUpdate();
|
||||
}
|
||||
showDialog('entity_import')
|
||||
$('#pe_list').css('max-height', ($(window).height() - 320) +'px')
|
||||
//texturelist._data.elements = textures
|
||||
}
|
||||
function loadPEModel() {
|
||||
var data;
|
||||
pe_list_data.forEach(function(s) {
|
||||
if (s.selected === true) {
|
||||
data = s
|
||||
}
|
||||
})
|
||||
if (data == undefined) {
|
||||
data = pe_list_data[0]
|
||||
}
|
||||
Project.parent = data.name
|
||||
if (data.object.texturewidth !== undefined) {
|
||||
Project.texture_width = data.object.texturewidth
|
||||
}
|
||||
if (data.object.textureheight !== undefined) {
|
||||
Project.texture_height = data.object.textureheight
|
||||
}
|
||||
|
||||
if (data.object.bones) {
|
||||
data.object.bones.forEach(function(b) {
|
||||
var group = new Group(b.name)
|
||||
if (b.pivot) {
|
||||
group.origin = b.pivot
|
||||
} else {
|
||||
group.origin = [0, 0, 0]
|
||||
}
|
||||
if (b.rotation) {
|
||||
group.rotation = b.rotation
|
||||
}
|
||||
group.reset = b.reset === true
|
||||
|
||||
if (b.cubes) {
|
||||
b.cubes.forEach(function(s) {
|
||||
var base_cube = new Cube(b.name, true)
|
||||
base_cube.display.autouv = false;
|
||||
if (s.origin) {
|
||||
base_cube.from = s.origin
|
||||
if (s.size) {
|
||||
base_cube.to[0] = s.size[0] + base_cube.from[0]
|
||||
base_cube.to[1] = s.size[1] + base_cube.from[1]
|
||||
base_cube.to[2] = s.size[2] + base_cube.from[2]
|
||||
}
|
||||
}
|
||||
if (s.uv) {
|
||||
base_cube.faces.north.uv[0] = (s.uv[0] / Project.texture_width) * 16
|
||||
base_cube.faces.north.uv[1] = (s.uv[1] / Project.texture_height) * 16
|
||||
base_cube.faces.north.uv[2] = 16
|
||||
base_cube.faces.north.uv[3] = 16
|
||||
}
|
||||
elements.push(base_cube)
|
||||
base_cube.addTo(group)
|
||||
})
|
||||
}
|
||||
group.addTo()
|
||||
})
|
||||
}
|
||||
pe_list_data.length = 0;
|
||||
hideDialog()
|
||||
|
||||
loadTextureDraggable()
|
||||
Canvas.updateAll()
|
||||
setUndo('Opened entity model')
|
||||
}
|
||||
function buildEntityModel(options) {
|
||||
var entitymodel = {}
|
||||
entitymodel.texturewidth = Project.texture_width;
|
||||
entitymodel.textureheight = Project.texture_height;
|
||||
var bones = []
|
||||
TreeElements.forEach(function(g) {
|
||||
if (g.title !== 'Group') return;
|
||||
//Bone
|
||||
var bone = {}
|
||||
bone.name = g.name
|
||||
bone.pivot = g.origin
|
||||
if (g.rotation.join('_') !== '0_0_0') {
|
||||
bone.rotation = g.rotation
|
||||
}
|
||||
if (g.reset) {
|
||||
bone.reset = true
|
||||
}
|
||||
//Cubes
|
||||
bone.cubes = []
|
||||
g.children.forEach(function(s) {
|
||||
if (s === undefined) return;
|
||||
if (s.display.export === false) return;
|
||||
var cube = {}
|
||||
cube.origin = s.from
|
||||
cube.size = s.size()
|
||||
cube.uv = [(s.faces.north.uv[0]/16) * Project.texture_width, (s.faces.north.uv[1]/16) * Project.texture_height]
|
||||
bone.cubes.push(cube)
|
||||
})
|
||||
bones.push(bone)
|
||||
})
|
||||
entitymodel.bones = bones
|
||||
|
||||
return entitymodel
|
||||
}
|
||||
function buildOptifineModel() {
|
||||
var jpm = {}
|
||||
if (textures[0]) {
|
||||
jpm.texture = pathToName(textures[0].name, false)
|
||||
} else {
|
||||
showQuickMessage('No texture found')
|
||||
}
|
||||
jpm.textureSize = [Project.texture_width, Project.texture_height]
|
||||
|
||||
if (settings.comment.value === true) {
|
||||
jpm.credit = settings.comment_text.value
|
||||
}
|
||||
if (Project.description !== '') {
|
||||
jpm.description = Project.description;
|
||||
}
|
||||
|
||||
var submodels = []
|
||||
|
||||
elements.forEach(function(s) {
|
||||
if (s.display.export === false) return;
|
||||
var submodel = {boxes: [{}]}
|
||||
var box = submodel.boxes[0]
|
||||
submodel.id = s.name
|
||||
box.coordinates = [s.from[0], s.from[1], s.from[2], s.size(0), s.size(1), s.size(2)]
|
||||
|
||||
for (var face in s.faces) {
|
||||
if (s.faces.hasOwnProperty(face)) {
|
||||
if (s.faces[face].texture !== undefined && s.faces[face].texture !== '$transparent') {
|
||||
box['uv'+capitalizeFirstLetter(face)] = [
|
||||
s.faces[face].uv[0] / 16 * Project.texture_width,
|
||||
s.faces[face].uv[1] / 16 * Project.texture_height,
|
||||
s.faces[face].uv[2] / 16 * Project.texture_width,
|
||||
s.faces[face].uv[3] / 16 * Project.texture_height
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
submodels.push(submodel)
|
||||
})
|
||||
jpm.submodels = submodels
|
||||
|
||||
|
||||
return autoStringify(jpm)
|
||||
}
|
||||
function newProject(entity_mode) {
|
||||
if (showSaveDialog()) {
|
||||
if (display_mode === true) exitDisplaySettings()
|
||||
TextureAnimator
|
||||
projectTagSetup()
|
||||
elements.length = 0;
|
||||
TreeElements.length = 1
|
||||
TreeElements.splice(0, 1)
|
||||
textures.length = 0
|
||||
selected.length = 0
|
||||
display = {}
|
||||
Prop.file_path = 'Unknown';
|
||||
Prop.file_name = '-';
|
||||
$('title').text('Blockbench')
|
||||
Canvas.updateAll()
|
||||
outliner.$forceUpdate();
|
||||
texturelist.$forceUpdate();
|
||||
Undo.history.length = 0;
|
||||
Undo.index = 0;
|
||||
added_model_index = 0;
|
||||
if (entity_mode) {
|
||||
entityMode.join()
|
||||
} else {
|
||||
entityMode.leave()
|
||||
}
|
||||
setUndo('Created project')
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function newEntityProject() {
|
||||
newProject(function () {
|
||||
settings.entity_mode.value = true
|
||||
entity_mode.join()
|
||||
})
|
||||
}
|
13
js/jquery-ui.min.js
vendored
Normal file
4
js/jquery.js
vendored
Normal file
202
js/mtlexport.js
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @author mrdoob / http://mrdoob.com/
|
||||
*/
|
||||
|
||||
THREE.OBJExporter = function () {};
|
||||
|
||||
THREE.OBJExporter.prototype = {
|
||||
|
||||
constructor: THREE.OBJExporter,
|
||||
|
||||
parse: function ( object ) {
|
||||
|
||||
var output = '';
|
||||
var materials = {};
|
||||
|
||||
var indexVertex = 0;
|
||||
var indexVertexUvs = 0;
|
||||
var indexNormals = 0;
|
||||
|
||||
var mtlFileName = 'objmaterial'; // maybe this value can be passed as parameter
|
||||
output += 'mtllib ' + mtlFileName + '.mtl\n';
|
||||
|
||||
var parseMesh = function ( mesh ) {
|
||||
|
||||
var nbVertex = 0;
|
||||
var nbVertexUvs = 0;
|
||||
var nbNormals = 0;
|
||||
|
||||
var geometry = mesh.geometry;
|
||||
var material = mesh.material;
|
||||
|
||||
if ( geometry instanceof THREE.Geometry ) {
|
||||
|
||||
output += 'o ' + mesh.name + '\n';
|
||||
|
||||
var vertices = geometry.vertices;
|
||||
|
||||
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
|
||||
|
||||
var vertex = vertices[ i ].clone();
|
||||
vertex.applyMatrix4( mesh.matrixWorld );
|
||||
|
||||
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
|
||||
|
||||
nbVertex ++;
|
||||
|
||||
}
|
||||
|
||||
// uvs
|
||||
|
||||
var faces = geometry.faces;
|
||||
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
|
||||
var hasVertexUvs = faces.length === faceVertexUvs.length;
|
||||
|
||||
if ( hasVertexUvs ) {
|
||||
|
||||
for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {
|
||||
|
||||
var vertexUvs = faceVertexUvs[ i ];
|
||||
|
||||
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
|
||||
|
||||
var uv = vertexUvs[ j ];
|
||||
|
||||
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
|
||||
|
||||
nbVertexUvs ++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// normals
|
||||
|
||||
var normalMatrixWorld = new THREE.Matrix3();
|
||||
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
|
||||
|
||||
for ( var i = 0, l = faces.length; i < l; i ++ ) {
|
||||
|
||||
var face = faces[ i ];
|
||||
var vertexNormals = face.vertexNormals;
|
||||
|
||||
if ( vertexNormals.length === 3 ) {
|
||||
|
||||
for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {
|
||||
|
||||
var normal = vertexNormals[ j ].clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
nbNormals ++;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var normal = face.normal.clone();
|
||||
normal.applyMatrix3( normalMatrixWorld );
|
||||
|
||||
for ( var j = 0; j < 3; j ++ ) {
|
||||
|
||||
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
|
||||
|
||||
nbNormals ++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// material
|
||||
|
||||
if (material.name !== '')
|
||||
output += 'usemtl ' + material.name + '\n';
|
||||
else
|
||||
output += 'usemtl material' + material.id + '\n';
|
||||
|
||||
materials[material.id] = material;
|
||||
|
||||
// faces
|
||||
|
||||
|
||||
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
|
||||
|
||||
var face = faces[ i ];
|
||||
|
||||
output += 'f ';
|
||||
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
|
||||
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
|
||||
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', mesh );
|
||||
// TODO: Support only BufferGeometry and use use setFromObject()
|
||||
|
||||
}
|
||||
|
||||
// update index
|
||||
indexVertex += nbVertex;
|
||||
indexVertexUvs += nbVertexUvs;
|
||||
indexNormals += nbNormals;
|
||||
|
||||
};
|
||||
|
||||
object.traverse( function ( child ) {
|
||||
|
||||
if ( child instanceof THREE.Mesh ) parseMesh( child );
|
||||
|
||||
} );
|
||||
|
||||
// mtl output
|
||||
|
||||
var mtlOutput = '';
|
||||
|
||||
for (var key in materials) {
|
||||
|
||||
var mat = materials[key];
|
||||
|
||||
if (mat.name !== '')
|
||||
mtlOutput += 'newmtl ' + mat.name + '\n';
|
||||
else
|
||||
mtlOutput += 'newmtl material' + mat.id + '\n';
|
||||
|
||||
mtlOutput += 'Ns 10.0000\n';
|
||||
mtlOutput += 'Ni 1.5000\n';
|
||||
mtlOutput += 'd 1.0000\n';
|
||||
mtlOutput += 'Tr 0.0000\n';
|
||||
mtlOutput += 'Tf 1.0000 1.0000 1.0000\n';
|
||||
mtlOutput += 'illum 2\n';
|
||||
mtlOutput += 'Ka 0 0 1\n';
|
||||
mtlOutput += 'Kd 0 0 1\n';
|
||||
mtlOutput += 'Ks 0.0000 0.0000 0.0000\n';
|
||||
mtlOutput += 'Ke 0.0000 0.0000 0.0000\n';
|
||||
mtlOutput += 'map_Kd '+mat.materials[0].map.image.baseURI+'\n';
|
||||
console.log(mat)
|
||||
|
||||
if (mat.map && mat.map instanceof THREE.Texture) {
|
||||
|
||||
var file = mat.map.image.currentSrc.slice( mat.map.image.currentSrc.slice.lastIndexOf("/"), mat.map.image.currentSrc.length - 1 );
|
||||
|
||||
mtlOutput += 'map_Ka ' + file + '\n';
|
||||
mtlOutput += 'map_Kd ' + file + '\n';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
obj: output,
|
||||
mtl: mtlOutput
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
318
js/plugin_loader.js
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
Plugin Loader for Blockbench
|
||||
By JannisX11
|
||||
*/
|
||||
var onUninstall, onInstall;
|
||||
var Plugins = {
|
||||
apipath: 'http://blockbench.net/api/plugins.json',
|
||||
Vue: [], //Vue Object
|
||||
installed: [], //Simple List of Names
|
||||
json: undefined, //Json from website
|
||||
data: [], //Vue Object Data
|
||||
loadingStep: false,
|
||||
updateSearch: function() {
|
||||
Plugins.Vue._data.showAll = !Plugins.Vue._data.showAll
|
||||
Plugins.Vue._data.showAll = !Plugins.Vue._data.showAll
|
||||
},
|
||||
devReload: function() {
|
||||
Plugins.data.forEach(function(pl) {
|
||||
if (pl.fromFile) {
|
||||
pl.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (isApp) {
|
||||
Plugins.path = __dirname.replace('resources'+osfs+'app.asar', 'plugins'+osfs)
|
||||
fs.readdir(Plugins.path, function(err) {
|
||||
if (err) {
|
||||
fs.mkdir(Plugins.path, function(a) {})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Plugins.apipath = '../api/plugins.json'
|
||||
}
|
||||
$.getJSON('http://blockbench.net/api/plugins.json', function(data) {
|
||||
Plugins.json = data
|
||||
if (Plugins.loadingStep === true) {
|
||||
loadInstalledPlugins()
|
||||
} else {
|
||||
Plugins.loadingStep = true
|
||||
}
|
||||
}).fail(function() {
|
||||
console.log('Could not connect to plugin server')
|
||||
$('#plugin_available_empty').text('Could not connect to plugin server')
|
||||
if (Plugins.loadingStep === true) {
|
||||
loadInstalledPlugins()
|
||||
} else {
|
||||
Plugins.loadingStep = true
|
||||
}
|
||||
})
|
||||
|
||||
$(document).ready(function() {
|
||||
if (Plugins.loadingStep === true) {
|
||||
loadInstalledPlugins()
|
||||
} else {
|
||||
Plugins.loadingStep = true
|
||||
}
|
||||
})
|
||||
|
||||
function loadInstalledPlugins() {
|
||||
var storage_data = localStorage.getItem('installed_plugins')
|
||||
if (storage_data !== null) {
|
||||
Plugins.installed = JSON.parse(storage_data)
|
||||
}
|
||||
if (Plugins.json !== undefined) {
|
||||
for (var id in Plugins.json) {
|
||||
var plugin = Plugins.json[id]
|
||||
var obj = {
|
||||
id: id,
|
||||
title: plugin.title,
|
||||
author: plugin.author,
|
||||
description: plugin.description,
|
||||
icon: plugin.icon,
|
||||
variant: plugin.variant,
|
||||
installed: Plugins.installed.includes(id)
|
||||
}
|
||||
if (obj.installed) {
|
||||
loadPlugin(id)
|
||||
}
|
||||
Plugins.data.push(obj)
|
||||
Plugins.data.sort(function(a,b) {
|
||||
return sort_collator.compare(a.title, b.title)
|
||||
});
|
||||
}
|
||||
} else if (Plugins.installed.length > 0) {
|
||||
Plugins.installed.forEach(function(id) {
|
||||
loadPlugin(id, function() {
|
||||
//Plugin Data Comes from the plugin file
|
||||
if (plugin_data === undefined) return;
|
||||
var obj = {
|
||||
id: id,
|
||||
title: plugin_data.title,
|
||||
author: plugin_data.author,
|
||||
description: plugin_data.description,
|
||||
icon: plugin_data.icon,
|
||||
variant: plugin_data.variant,
|
||||
installed: true
|
||||
}
|
||||
Plugins.data.push(obj)
|
||||
Plugins.data.sort(function(a,b) {
|
||||
return sort_collator.compare(a.title, b.title)
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
if (Plugins.installed.length > 0) {
|
||||
console.log('Loaded '+Plugins.installed.length+' plugin'+pluralS(Plugins.installed.length))
|
||||
}
|
||||
|
||||
|
||||
Plugins.Vue = new Vue({
|
||||
el: '#plugin_list',
|
||||
data: {
|
||||
showAll: false,
|
||||
items: Plugins.data
|
||||
},
|
||||
computed: {
|
||||
installedPlugins() {
|
||||
var name = $('#plugin_search_bar').val().toUpperCase()
|
||||
return this.items.filter(item => {
|
||||
if (this.showAll || item.installed) {
|
||||
if (name.length > 0) {
|
||||
return (
|
||||
item.id.toUpperCase().includes(name) ||
|
||||
item.title.toUpperCase().includes(name) ||
|
||||
item.description.toUpperCase().includes(name) ||
|
||||
item.author.toUpperCase().includes(name)
|
||||
)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
install: function(event) {
|
||||
var id = $(event.target.parentElement.parentElement).attr('plugin')
|
||||
if (isApp) {
|
||||
downloadPlugin(id)
|
||||
} else {
|
||||
loadPlugin(id)
|
||||
}
|
||||
},
|
||||
uninstall: function() {
|
||||
var id = $(event.target.parentElement.parentElement).attr('plugin')
|
||||
uninstallPlugin(id)
|
||||
},
|
||||
update: function() {
|
||||
if (isApp) {
|
||||
var id = $(event.target.parentElement.parentElement).attr('plugin')
|
||||
downloadPlugin(id)
|
||||
}
|
||||
},
|
||||
checkIfInstallable: function(plugin) {
|
||||
var result =
|
||||
plugin.variant === 'both' ||
|
||||
(
|
||||
isApp === (plugin.variant === 'desktop') &&
|
||||
isApp !== (plugin.variant === 'web')
|
||||
);
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
function saveInstalledPlugins() {
|
||||
localStorage.setItem('installed_plugins', JSON.stringify(Plugins.installed))
|
||||
hideDialog()
|
||||
}
|
||||
function loadPlugin(id, cb, install) {
|
||||
if (isApp === true) {
|
||||
$.getScript(Plugins.path + id + '.js', function(a) {
|
||||
if (onUninstall) {
|
||||
Plugins.data.findInArray('id', id).uninstall = onUninstall
|
||||
onUninstall = undefined
|
||||
}
|
||||
if (install && onInstall) {
|
||||
onInstall()
|
||||
}
|
||||
onInstall = undefined
|
||||
if (cb !== undefined) cb()
|
||||
}).fail(function() {
|
||||
console.log('Could not find file of plugin "'+id+'". Uninstalling it instead.')
|
||||
var index = Plugins.installed.indexOf(id)
|
||||
if (index > -1) {
|
||||
Plugins.installed.splice(index, 1)
|
||||
}
|
||||
var data_obj = Plugins.data.findInArray('id', id)
|
||||
data_obj.installed = false
|
||||
if (data_obj.uninstall) {
|
||||
data_obj.uninstall()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
$.getScript('http://blockbench.net/api/plugins/'+id+'.js', function() {
|
||||
if (onUninstall) {
|
||||
Plugins.data.findInArray('id', id).uninstall = onUninstall
|
||||
onUninstall = undefined
|
||||
}
|
||||
if (install && onInstall) {
|
||||
onInstall()
|
||||
}
|
||||
onInstall = undefined
|
||||
if (cb) cb()
|
||||
})
|
||||
}
|
||||
if (Plugins.installed.includes(id) === false) {
|
||||
Plugins.installed.push(id)
|
||||
}
|
||||
Plugins.data.findInArray('id', id).installed = true
|
||||
}
|
||||
function loadPluginFromFile() {
|
||||
function readFromPluginFile(content, path, hideWarning) {
|
||||
if (!hideWarning) {
|
||||
if (isApp) {
|
||||
if (!confirm('Do you want to allow this plugin to make changes to your PC? Only load plugins from people you trust.')) return;
|
||||
} else {
|
||||
if (!confirm('Do you want to load this plugin? Only load plugins from people you trust.')) return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
eval(content)
|
||||
} catch (err) {
|
||||
showQuickMessage('Invalid Plugin File, See Console')
|
||||
console.error(err)
|
||||
return;
|
||||
}
|
||||
var obj = {
|
||||
author: 'x11',
|
||||
icon: 'refresh',
|
||||
installed: true,
|
||||
id: 'test',
|
||||
title: 'Plugin',
|
||||
variant: 'both',
|
||||
description: '',
|
||||
fromFile: true,
|
||||
filePath: path,
|
||||
uninstall: function() {
|
||||
var index = Plugins.data.indexOf(this)
|
||||
if (index >= 0) Plugins.data.splice(index, 1)
|
||||
if (this.uninstallMethod) {
|
||||
this.uninstallMethod()
|
||||
}
|
||||
},
|
||||
reload: function() {
|
||||
if (isApp) {
|
||||
obj.uninstall()
|
||||
fs.readFile(path, 'utf-8', function (err, data) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
return;
|
||||
}
|
||||
readFromPluginFile(data, path, true)
|
||||
})
|
||||
}
|
||||
},
|
||||
uninstallMethod: false
|
||||
}
|
||||
$.extend(true, obj, plugin_data)
|
||||
obj.uninstallMethod = onUninstall
|
||||
onUninstall = undefined
|
||||
Plugins.data.push(obj)
|
||||
Plugins.data.sort(function(a,b) {
|
||||
return sort_collator.compare(a.title, b.title)
|
||||
});
|
||||
}
|
||||
Blockbench.import('.js', readFromPluginFile, ['bbplugin', 'js'])
|
||||
}
|
||||
function downloadPlugin(id) {
|
||||
//$('.uc_btn').attr('disabled', true)
|
||||
|
||||
var file = originalFs.createWriteStream(Plugins.path+id+'.js')
|
||||
var request = http.get('http://blockbench.net/api/plugins/'+id+'.js', function(response) {
|
||||
response.pipe(file);
|
||||
response.on('end', function() {
|
||||
setTimeout(function() {
|
||||
loadPlugin(id, undefined, true)
|
||||
}, 100)
|
||||
})
|
||||
});
|
||||
}
|
||||
function uninstallPlugin(id) {
|
||||
if (isApp) {
|
||||
var filepath = Plugins.path + id + '.js'
|
||||
if (fs.existsSync(filepath)) {
|
||||
fs.unlink(filepath, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//File does not exist
|
||||
}
|
||||
}
|
||||
var index = Plugins.installed.indexOf(id)
|
||||
if (index > -1) {
|
||||
Plugins.installed.splice(index, 1)
|
||||
}
|
||||
var data_obj = Plugins.data.findInArray('id', id)
|
||||
data_obj.installed = false
|
||||
if (data_obj.uninstall) {
|
||||
data_obj.uninstall()
|
||||
}
|
||||
}
|
||||
function switchPluginTabs(installed) {
|
||||
$('#plugins .tab').removeClass('open')
|
||||
if (installed) {
|
||||
$('#installed_plugins').addClass('open')
|
||||
Plugins.Vue._data.showAll = false
|
||||
} else {
|
||||
$('#all_plugins').addClass('open')
|
||||
Plugins.Vue._data.showAll = true
|
||||
}
|
||||
}
|
560
js/settings.js
Normal file
@ -0,0 +1,560 @@
|
||||
var keybinds, settings, display_presets;
|
||||
|
||||
var Project = new Object()
|
||||
projectTagSetup()
|
||||
keybindSetup()
|
||||
settingSetup()
|
||||
displayPresetsSetup()
|
||||
|
||||
$(document).keydown(function(e) {
|
||||
holding_shift = e.shiftKey;
|
||||
});
|
||||
|
||||
$(document).keyup(function(e) {
|
||||
holding_shift = false;
|
||||
});
|
||||
//Setup
|
||||
function keybindSetup(get) {
|
||||
var obj = {
|
||||
headline1: {is_title: true, title: "Misc"},
|
||||
canvas_rotate: {shift: false, ctrl: false, alt: false, code: 1, name: 'Rotate View', char: 'Left-Click', update: true},
|
||||
canvas_drag:{shift: false, ctrl: false, alt: false, code: 3, name: 'Drag View', char: 'Right-Click', update: true},
|
||||
confirm: {shift: false, ctrl: false, alt: false, code: 13, name: 'Confirm', char: 'ENTER'},
|
||||
cancel: {shift: false, ctrl: false, alt: false, code: 27, name: 'Cancel', char: 'ESCAPE'},
|
||||
screenshot_clean:{shift: false, ctrl: true, alt: false, code: 80, name: 'Screenshot', char: 'Ctrl + P'},
|
||||
|
||||
headline2: {is_title: true, title: "File"},
|
||||
open_file: {shift: false, ctrl: true, alt: false, code: 79, name: 'Open File', char: 'Ctrl + O'},
|
||||
save: {shift: false, ctrl: true, alt: false, code: 83, name: 'Save', char: 'Ctrl + S'},
|
||||
save_as: {shift: true, ctrl: true, alt: false, code: 83, name: 'Save As', char: 'Ctrl + Shift + S'},
|
||||
open_texture: {shift: false, ctrl: true, alt: false, code: 84, name: 'Import Texture', char: 'Ctrl + T'},
|
||||
toggle_mode:{shift: false, ctrl: true, alt: false, code: 9, name: 'Toggle Mode', char: 'Ctrl + TAB'},
|
||||
settings: {shift: false, ctrl: true, alt: false, code: 69, name: 'Settings', char: 'Ctrl + E'},
|
||||
|
||||
headline3: {is_title: true, title: "Edit"},
|
||||
undo: {shift: false, ctrl: true, alt: false, code: 90, name: 'Undo', char: 'Ctrl + Z'},
|
||||
redo: {shift: false, ctrl: true, alt: false, code: 89, name: 'Redo', char: 'Ctrl + Y'},
|
||||
create_selection:{shift: false, ctrl: true, alt: false, code: 70, name: 'Create Selection', char: 'Ctrl + F'},
|
||||
select_all: {shift: false, ctrl: true, alt: false, code: 65, name: 'Select All', char: 'Ctrl + A'},
|
||||
invert_select:{shift:false,ctrl: true, alt: false, code: 65, name: 'Select All', char: 'Ctrl + A'},
|
||||
add_cube: {shift: false, ctrl: true, alt: false, code: 78, name: 'Add Cube', char: 'Ctrl + N'},
|
||||
new_group: {shift: false, ctrl: true, alt: false, code: 71, name: 'Add Group', char: 'Ctrl + G'},
|
||||
duplicate: {shift: false, ctrl: true, alt: false, code: 68, name: 'Duplicate Cube', char: 'Ctrl + D'},
|
||||
delete: {shift: false, ctrl: false, alt: false,code: 46, name: 'Delete Selected', char: 'DELETE'},
|
||||
rename: {shift: false, ctrl: false, alt: false,code: 113,name: 'Rename', char: 'F2'},
|
||||
|
||||
headline4: {is_title: true, title: "Textures"},
|
||||
uv_copy: {shift: false, ctrl: true, alt: false, code: 67, name: 'Copy UV', char: 'Ctrl + C'},
|
||||
uv_copy_all:{shift: true, ctrl: true, alt: false, code: 67, name: 'Copy UV All', char: 'Ctrl + Shift + C'},
|
||||
uv_paste: {shift: false, ctrl: true, alt: false, code: 86, name: 'Paste UV', char: 'Ctrl + V'},
|
||||
uv_paste_all:{shift: true, ctrl: true, alt: false, code: 86, name: 'Paste UV All', char: 'Ctrl + Shift + V'},
|
||||
|
||||
headline5: {is_title: true, title: "Display Mode"},
|
||||
copy_disp: {shift: false, ctrl: true, alt: false, code: 67, name: 'Copy Display Settings', char: 'Ctrl + C'},
|
||||
paste_disp: {shift: false, ctrl: true, alt: false, code: 86, name: 'Paste Display Settings', char: 'Ctrl + V'},
|
||||
reload_tex: {shift: false, ctrl: true, alt: false, code: 82, name: 'Reload Textures', char: 'Ctrl + R'},
|
||||
|
||||
headline6: {is_title: true, title: "Tool"},
|
||||
tool_translate:{shift: false, ctrl: false, alt: false, code: 86, name: 'Move Tool', char: 'V'},
|
||||
tool_scale: {shift: false, ctrl: false, alt: false, code: 83, name: 'Scale Tool', char: 'S'},
|
||||
tool_brush: {shift: false, ctrl: false, alt: false, code: 66, name: 'Brush', char: 'B'},
|
||||
tool_swap: {shift: false, ctrl: false, alt: false, code: 32, name: 'Swap Move and Scale', char: 'SPACE'},
|
||||
|
||||
headline7: {is_title: true, title: "Movement"},
|
||||
move_north: {shift: false, ctrl: false, alt: false, code: 38, name: 'Move South', char: 'ARROWUP'},
|
||||
move_south: {shift: false, ctrl: false, alt: false, code: 40, name: 'Move North', char: 'ARROWDOWN'},
|
||||
move_west: {shift: false, ctrl: false, alt: false, code: 37, name: 'Move West', char: 'ARROWLEFT'},
|
||||
move_east: {shift: false, ctrl: false, alt: false, code: 39, name: 'Move East', char: 'ARROWRIGHT'},
|
||||
move_up: {shift: false, ctrl: false, alt: false, code: 33, name: 'Move Up', char: 'PAGEUP'},
|
||||
move_down: {shift: false, ctrl: false, alt: false, code: 34, name: 'Move Down', char: 'PAGEDOWN'},
|
||||
|
||||
headline8: {is_title: true, title: "View"},
|
||||
wireframe: {shift: false, ctrl: false, alt: false, code: 90, name: 'Toggle Wireframe', char: 'Z'},
|
||||
reset_view: {shift: false, ctrl: false, alt: false, code: 96, name: 'Reset View', char: 'NUMPAD 0'},
|
||||
view_normal: {shift: false, ctrl: false, alt: false, code: 101, name: 'Normal View', char: 'NUMPAD 5'},
|
||||
view_0: {shift: false, ctrl: false, alt: false, code: 104, name: 'Top View', char: 'NUMPAD 8'},
|
||||
view_1: {shift: false, ctrl: false, alt: false, code: 98, name: 'Bottom View', char: 'NUMPAD 2'},
|
||||
view_2: {shift: false, ctrl: false, alt: false, code: 100, name: 'South View', char: 'NUMPAD 4'},
|
||||
view_3: {shift: false, ctrl: false, alt: false, code: 102, name: 'North View', char: 'NUMPAD 6'},
|
||||
view_4: {shift: false, ctrl: false, alt: false, code: 103, name: 'East View', char: 'NUMPAD 7'},
|
||||
view_5: {shift: false, ctrl: false, alt: false, code: 105, name: 'West View', char: 'NUMPAD 9'}
|
||||
}
|
||||
if (get !== true) {
|
||||
keybinds = obj
|
||||
if (localStorage.getItem('keybinds') != null) {
|
||||
var stored_keys = JSON.parse(localStorage.getItem('keybinds'))
|
||||
for (var key in stored_keys) {
|
||||
if (stored_keys.hasOwnProperty(key) && !stored_keys[key].is_title && keybinds.hasOwnProperty(key)) {
|
||||
keybinds[key].shift = stored_keys[key].shift
|
||||
keybinds[key].ctrl = stored_keys[key].ctrl
|
||||
keybinds[key].alt = stored_keys[key].alt
|
||||
keybinds[key].code = stored_keys[key].code
|
||||
keybinds[key].char = stored_keys[key].char
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
function settingSetup() {
|
||||
settings = {
|
||||
//Preview
|
||||
headline2: {is_title: true, title: "Preview"},
|
||||
origin: {value: true, name: 'Rotation Origin', desc: 'Show object origin'},
|
||||
control_size: {value: 10, is_number: true, name: 'Axis Control Size', desc: 'Size of the 3 axis control tool'},
|
||||
shading: {value: true, name: 'Shading', desc: 'Enable shading'},
|
||||
transparency: {value: true, name: 'Transparency', desc: 'Render transparent textures transparent'},
|
||||
texture_fps: {value: 2, is_number: true, name: 'Animated Texture FPS', desc: 'Frames per second for animated textures'},
|
||||
status_bar: {value: true, name: 'Status Bar', desc: 'Show the status bar that displays fps etc.'},
|
||||
swap_sidebar: {value: false, name: 'Swap Sidebars', desc: 'Swaps the right and the left sidebar'},
|
||||
//Grid
|
||||
headline1: {is_title: true, title: "Grid"},
|
||||
base_grid: {value: true, name: 'Small Grid', desc: 'Show small grid and axes'},
|
||||
large_grid: {value: false, name: 'Large Grid', desc: 'Show 3x3 block grid'},
|
||||
full_grid: {value: false, name: 'Full Large Grid', desc: 'Show 3x3 precise grid'},
|
||||
large_box: {value: false, name: 'Large Box', desc: 'Show 3x3 block boundaries'},
|
||||
display_grid: {value: true, name: 'Display Mode', desc: 'Show grid in display mode'},
|
||||
//Edit
|
||||
headline3: {is_title: true, title: "Edit"},
|
||||
entity_mode: {value: false, name: 'Entity Model Mode', desc: 'Unrestricted editing mode for Bedrock and Optifine models'},
|
||||
undo_limit: {value: 20, is_number: true, name: 'Undo Limit', desc: 'Number of steps you can undo'},
|
||||
move_origin: {value: false, name: 'Move on Relative Axes', desc: 'Move rotated elements on their own axes if possible'},
|
||||
snapnslide: {value: false, name: 'Snap Slider', desc: 'Snaps combo-sliders to their valid positions'},
|
||||
autouv: {value: true, name: 'Auto UV', desc: 'Enable AutoUV by default'},
|
||||
create_rename:{value: false, name: 'Rename new Cube', desc: 'Focus name field when creating new element or group'},
|
||||
canvas_unselect:{value: false, name: 'Canvas Click Unselect', desc: 'Unselects all elements when clicking on the canvas background'},
|
||||
edit_size: {value: 16, is_number: true, name: 'Grid Resolution', desc: 'Resolution of the grid that cubes snap to'},
|
||||
show_actions: {value: false, name: 'Tell Actions', desc: 'Display every action in the status bar'},
|
||||
//Export
|
||||
headline4: {is_title: true, title: "Export"},
|
||||
minifiedout: {value: false,name: 'Minified Export', desc: 'Write JSON file in one line'},
|
||||
max_json_length:{value: 56, is_number: true, name: 'Maximum Line Length', desc: 'Break JSON lines after this number'},
|
||||
round_digits: {value: 4, is_number: true, name: 'Round numbers', desc: 'Round numbers'},
|
||||
export_groups:{value: true, name: 'Export Groups', desc: 'Save groups in blockmodel files'},
|
||||
obj_textures: {value: true, name: 'Export Textures', desc: 'Export textures when exporting OBJ file'},
|
||||
comment: {value: true, name: 'File Comment', desc: 'Add a credit comment to file'},
|
||||
comment_text: {value: 'Made with Blockbench, a free, modern block model editor by JannisX11', is_string: true},
|
||||
default_path: {value: false, hidden: true}
|
||||
}
|
||||
if (localStorage.getItem('settings') != null) {
|
||||
var stored_settings = JSON.parse(localStorage.getItem('settings'))
|
||||
for (var key in stored_settings) {
|
||||
if (stored_settings.hasOwnProperty(key) && !stored_settings[key].is_title && settings.hasOwnProperty(key)) {
|
||||
settings[key].value = stored_settings[key].value
|
||||
}
|
||||
}
|
||||
if (settings.edit_size.value < 3) {
|
||||
settings.edit_size.value = 16
|
||||
}
|
||||
}
|
||||
}
|
||||
function projectTagSetup() {
|
||||
Project.name = "";
|
||||
Project.parent = "";
|
||||
Project.description = "";
|
||||
Project.texture_width = 64;
|
||||
Project.texture_height = 32;
|
||||
Project.ambientocclusion = true;
|
||||
}
|
||||
function displayPresetsSetup() {
|
||||
display_presets = [
|
||||
{name: 'Vanilla Item', fixed: true, areas: {
|
||||
ground: {
|
||||
rotation: [ 0, 0, 0 ],
|
||||
translation: [ 0, 2, 0],
|
||||
scale:[ 0.5, 0.5, 0.5 ]
|
||||
},
|
||||
head: {
|
||||
rotation: [ 0, 180, 0 ],
|
||||
translation: [ 0, 13, 7],
|
||||
scale:[ 1, 1, 1]
|
||||
},
|
||||
thirdperson_righthand: {
|
||||
rotation: [ 0, 0, 0 ],
|
||||
translation: [ 0, 3, 1 ],
|
||||
scale: [ 0.55, 0.55, 0.55 ]
|
||||
},
|
||||
thirdperson_lefthand: {
|
||||
rotation: [ 0, 0, 0 ],
|
||||
translation: [ 0, 3, 1 ],
|
||||
scale: [ 0.55, 0.55, 0.55 ]
|
||||
},
|
||||
firstperson_righthand: {
|
||||
rotation: [ 0, -90, 25 ],
|
||||
translation: [ 1.13, 3.2, 1.13],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
},
|
||||
firstperson_lefthand: {
|
||||
rotation: [ 0, -90, 25 ],
|
||||
translation: [ 1.13, 3.2, 1.13],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
},
|
||||
fixed: {
|
||||
rotation: [ 0, 180, 0 ],
|
||||
translation: [ 0, 0, 0 ],
|
||||
scale: [ 1, 1, 1 ],
|
||||
}
|
||||
}
|
||||
},
|
||||
{name: 'Vanilla Block', fixed: true, areas: {
|
||||
gui: {
|
||||
rotation: [ 30, 225, 0 ],
|
||||
translation: [ 0, 0, 0],
|
||||
scale:[ 0.625, 0.625, 0.625 ]
|
||||
},
|
||||
ground: {
|
||||
rotation: [ 0, 0, 0 ],
|
||||
translation: [ 0, 3, 0],
|
||||
scale:[ 0.25, 0.25, 0.25 ]
|
||||
},
|
||||
fixed: {
|
||||
rotation: [ 0, 0, 0 ],
|
||||
translation: [ 0, 0, 0],
|
||||
scale:[ 0.5, 0.5, 0.5 ]
|
||||
},
|
||||
thirdperson_righthand: {
|
||||
rotation: [ 75, 45, 0 ],
|
||||
translation: [ 0, 2.5, 0],
|
||||
scale: [ 0.375, 0.375, 0.375 ]
|
||||
},
|
||||
thirdperson_lefthand: {
|
||||
rotation: [ 75, 45, 0 ],
|
||||
translation: [ 0, 2.5, 0],
|
||||
scale: [ 0.375, 0.375, 0.375 ]
|
||||
},
|
||||
firstperson_righthand: {
|
||||
rotation: [ 0, 45, 0 ],
|
||||
translation: [ 0, 0, 0 ],
|
||||
scale: [ 0.40, 0.40, 0.40 ]
|
||||
},
|
||||
firstperson_lefthand: {
|
||||
rotation: [ 0, 225, 0 ],
|
||||
translation: [ 0, 0, 0 ],
|
||||
scale: [ 0.40, 0.40, 0.40 ]
|
||||
}
|
||||
}
|
||||
},
|
||||
{name: 'Vanilla Handheld', fixed: true, areas: {
|
||||
thirdperson_righthand: {
|
||||
rotation: [ 0, -90, 55 ],
|
||||
translation: [ 0, 4.0, 0.5 ],
|
||||
scale: [ 0.85, 0.85, 0.85 ]
|
||||
},
|
||||
thirdperson_lefthand: {
|
||||
rotation: [ 0, 90, -55 ],
|
||||
translation: [ 0, 4.0, 0.5 ],
|
||||
scale: [ 0.85, 0.85, 0.85 ]
|
||||
},
|
||||
firstperson_righthand: {
|
||||
rotation: [ 0, -90, 25 ],
|
||||
translation: [ 1.13, 3.2, 1.13 ],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
},
|
||||
firstperson_lefthand: {
|
||||
rotation: [ 0, 90, -25 ],
|
||||
translation: [ 1.13, 3.2, 1.13 ],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
}
|
||||
}
|
||||
},
|
||||
{name: 'Vanilla Handheld Rod', fixed: true, areas: {
|
||||
thirdperson_righthand: {
|
||||
rotation: [ 0, 90, 55 ],
|
||||
translation: [ 0, 4.0, 2.5 ],
|
||||
scale: [ 0.85, 0.85, 0.85 ]
|
||||
},
|
||||
thirdperson_lefthand: {
|
||||
rotation: [ 0, -90, -55 ],
|
||||
translation: [ 0, 4.0, 2.5 ],
|
||||
scale: [ 0.85, 0.85, 0.85 ]
|
||||
},
|
||||
firstperson_righthand: {
|
||||
rotation: [ 0, 90, 25 ],
|
||||
translation: [ 0, 1.6, 0.8 ],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
},
|
||||
firstperson_lefthand: {
|
||||
rotation: [ 0, -90, -25 ],
|
||||
translation: [ 0, 1.6, 0.8 ],
|
||||
scale: [ 0.68, 0.68, 0.68 ]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
if (localStorage.getItem('display_presets') != null) {
|
||||
var stored_display_presets = JSON.parse(localStorage.getItem('display_presets'))
|
||||
$.extend(display_presets, stored_display_presets)
|
||||
}
|
||||
}
|
||||
$(document).keydown(function(e) {
|
||||
if (e.which === 16) {
|
||||
showShiftTooltip()
|
||||
}
|
||||
if (e.ctrlKey === true && e.which == 73 && isApp) {
|
||||
app.getCurrentWindow().toggleDevTools()
|
||||
}
|
||||
|
||||
if (open_dialog !== false) {
|
||||
if (open_dialog === 'uv_dialog') {
|
||||
if (compareKeys(e, keybinds.uv_copy)) {
|
||||
uv_dialog.copy(e)
|
||||
}
|
||||
if (compareKeys(e, keybinds.uv_paste)) {
|
||||
uv_dialog.paste(e)
|
||||
}
|
||||
}
|
||||
if (compareKeys(e, keybinds.confirm)) {
|
||||
$('.dialog#'+open_dialog).find('.confirm_btn:not([disabled])').click()
|
||||
} else if (compareKeys(e, keybinds.cancel) === true) {
|
||||
$('.dialog#'+open_dialog).find('.cancel_btn:not([disabled])').click()
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (currently_renaming === true) {
|
||||
if (compareKeys(e, keybinds.confirm)) {
|
||||
stopRenameCubes()
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ($('input[type="text"]:focus, input[type="number"]:focus, div[contenteditable="true"]:focus').length > 0) {
|
||||
if (compareKeys(e, keybinds.confirm)) {
|
||||
$(document).click()
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (compareKeys(e, keybinds.screenshot_clean)) {
|
||||
Screencam.cleanCanvas()
|
||||
}
|
||||
|
||||
if (compareKeys(e, keybinds.open_file)) {
|
||||
openFile(true)
|
||||
}
|
||||
if (compareKeys(e, keybinds.save)) {
|
||||
saveFile()
|
||||
}
|
||||
if (compareKeys(e, keybinds.save_as)) {
|
||||
saveFileBlock()
|
||||
}
|
||||
if (compareKeys(e, keybinds.open_texture)) {
|
||||
openTexture()
|
||||
}
|
||||
if (compareKeys(e, keybinds.toggle_mode)) {
|
||||
display_mode ? exitDisplaySettings() : enterDisplaySettings()
|
||||
}
|
||||
if (compareKeys(e, keybinds.settings)) {
|
||||
showDialog('settings');setSettingsTab('setting')
|
||||
}
|
||||
if (compareKeys(e, keybinds.wireframe)) {
|
||||
toggleWireframe()
|
||||
}
|
||||
if (display_mode === false) {
|
||||
//Edit Mode
|
||||
|
||||
if (compareKeys(e, keybinds.undo)) {
|
||||
Undo.undo()
|
||||
} else if (compareKeys(e, keybinds.redo)) {
|
||||
Undo.redo()
|
||||
}
|
||||
if (compareKeys(e, keybinds.add_cube)) {
|
||||
addCube(0,0,0,canvas_grid,canvas_grid,canvas_grid)
|
||||
}
|
||||
if (compareKeys(e, keybinds.new_group)) {
|
||||
addGroup()
|
||||
}
|
||||
if (compareKeys(e, keybinds.duplicate)) {
|
||||
duplicateCubes()
|
||||
}
|
||||
if (compareKeys(e, keybinds.rename)) {
|
||||
renameCubes()
|
||||
}
|
||||
if (compareKeys(e, keybinds.select_all)) {
|
||||
e.preventDefault()
|
||||
selectAll()
|
||||
}
|
||||
if (compareKeys(e, keybinds.delete)) {
|
||||
if ($(':focus, .editing').length == 0) {
|
||||
deleteCubes()
|
||||
}
|
||||
}
|
||||
if (compareKeys(e, keybinds.reload_tex) === true && isApp) {
|
||||
reloadTextures()
|
||||
}
|
||||
if (compareKeys(e, keybinds.create_selection)) {
|
||||
showDialog('selection_creator')
|
||||
}
|
||||
if (compareKeys(e, keybinds.tool_translate)) {
|
||||
setTool('translate')
|
||||
} else if (compareKeys(e, keybinds.tool_scale)) {
|
||||
setTool('scale')
|
||||
} else if (compareKeys(e, keybinds.tool_brush)) {
|
||||
setTool('brush')
|
||||
} else if (compareKeys(e, keybinds.tool_swap)) {
|
||||
toggleTools()
|
||||
}
|
||||
|
||||
|
||||
if (selected.length > 0) {
|
||||
//Selected
|
||||
if (compareKeys(e, keybinds.uv_copy)) {
|
||||
main_uv.copy({shiftKey: false})
|
||||
}
|
||||
if (compareKeys(e, keybinds.uv_copy_all)) {
|
||||
main_uv.copy({shiftKey: true})
|
||||
}
|
||||
if (compareKeys(e, keybinds.uv_paste)) {
|
||||
main_uv.paste({shiftKey: false})
|
||||
}
|
||||
if (compareKeys(e, keybinds.uv_paste_all)) {
|
||||
main_uv.paste({shiftKey: true})
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_north)) {
|
||||
moveCubesRelative(-1, 2)
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_south)) {
|
||||
moveCubesRelative(1, 2)
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_west)) {
|
||||
moveCubesRelative(-1, 0)
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_east)) {
|
||||
moveCubesRelative(1, 0)
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_up)) {
|
||||
moveCubesRelative(-1, 1)
|
||||
}
|
||||
if (compareKeys(e, keybinds.move_down)) {
|
||||
moveCubesRelative(1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
//View
|
||||
if (compareKeys(e, keybinds.view_normal)) {
|
||||
setCameraType('pers')
|
||||
} else if (compareKeys(e, keybinds.reset_view)) {
|
||||
resetCamera()
|
||||
//Ortho
|
||||
} else if (compareKeys(e, keybinds.view_0)) {
|
||||
setCameraType('ortho', 0)
|
||||
} else if (compareKeys(e, keybinds.view_1)) {
|
||||
setCameraType('ortho', 1)
|
||||
} else if (compareKeys(e, keybinds.view_2)) {
|
||||
setCameraType('ortho', 2)
|
||||
} else if (compareKeys(e, keybinds.view_3)) {
|
||||
setCameraType('ortho', 3)
|
||||
} else if (compareKeys(e, keybinds.view_4)) {
|
||||
setCameraType('ortho', 4)
|
||||
} else if (compareKeys(e, keybinds.view_5)) {
|
||||
setCameraType('ortho', 5)
|
||||
}
|
||||
|
||||
} else if (display_mode === true) { //Display Mode
|
||||
if (compareKeys(e, keybinds.copy_disp)) {
|
||||
copyDisplaySlot()
|
||||
}
|
||||
if (compareKeys(e, keybinds.paste_disp)) {
|
||||
pasteDisplaySlot()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function saveLocalStorages() {
|
||||
localStorage.setItem('canvas_scenes', JSON.stringify(canvas_scenes))
|
||||
localStorage.setItem('settings', JSON.stringify(omitKeys(settings, ['name', 'desc'], true)) )
|
||||
}
|
||||
function saveSettings() {
|
||||
updateMenu()
|
||||
for (var mat in Canvas.materials) {
|
||||
if (Canvas.materials.hasOwnProperty(mat))
|
||||
Canvas.materials[mat].transparent = settings.transparency.value
|
||||
}
|
||||
setScreenRatio()
|
||||
calcCanvasGridSize()
|
||||
buildGrid()
|
||||
setShading()
|
||||
if (settings.snapnslide.value === true) {
|
||||
$('.nslide').draggable( "option", "grid", [ 50, 100 ] );
|
||||
} else {
|
||||
$('.nslide').draggable( "option", "grid", false );
|
||||
}
|
||||
if (settings.swap_sidebar.value === true) {
|
||||
$('body').addClass('rtl')
|
||||
} else {
|
||||
$('body').removeClass('rtl')
|
||||
}
|
||||
if (settings.status_bar.value) {
|
||||
$('body').css('grid-template-rows', '32px calc(100% - 58px) 26px')
|
||||
} else {
|
||||
$('body').css('grid-template-rows', '32px calc(100% - 32px) 0px')
|
||||
}
|
||||
if (entityMode.state !== settings.entity_mode.value) {
|
||||
entityMode.state = settings.entity_mode.value
|
||||
settings.entity_mode.value ? entityMode.join() : entityMode.leave()
|
||||
}
|
||||
TextureAnimator.updateSpeed()
|
||||
hideDialog()
|
||||
updateUIColor()
|
||||
updateSelection()
|
||||
Blockbench.dispatchEvent( 'update_settings')
|
||||
}
|
||||
function toggleSetting(setting) {
|
||||
if (settings[setting].value === true) {
|
||||
settings[setting].value = false
|
||||
} else {
|
||||
settings[setting].value = true
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
function toggleWireframe() {
|
||||
Prop.wireframe = !Prop.wireframe
|
||||
Canvas.updateAll()
|
||||
}
|
||||
var entityMode = {
|
||||
state: false,
|
||||
join: function() {
|
||||
settings.entity_mode.value = true
|
||||
$('body').addClass('entity_mode')
|
||||
$('label[for="project_parent"]').text('Mob Geometry Name')
|
||||
$('#cube_rescale_tool div').text('Reset Bone')
|
||||
$('input#cube_rotate').attr('min', '-180').attr('max', '180').attr('step', '5.625').addClass('entity_mode')
|
||||
main_uv.buildDom().setToMainSlot().setFace('north')
|
||||
$('.block_mode_only').hide()
|
||||
},
|
||||
leave: function() {
|
||||
settings.entity_mode.value = false
|
||||
$('body').removeClass('entity_mode')
|
||||
$('label[for="project_parent"]').text('Parent Model')
|
||||
$('#cube_rescale_tool div').text('Rescale')
|
||||
$('input#cube_rotate').attr('min', '-67.5').attr('max', '67.5').attr('step', '22.5').removeClass('entity_mode')
|
||||
$('.block_mode_only').show()
|
||||
main_uv.buildDom(true).setToMainSlot()
|
||||
elements.forEach(function(s, i) {
|
||||
//Push elements into 3x3 block box
|
||||
[0, 1, 2].forEach(function(ax) {
|
||||
var overlap = s.from[ax] + s.to[ax] - 32
|
||||
if (overlap > 0) {
|
||||
//If positive site overlaps
|
||||
s.from[ax] -= overlap
|
||||
s.to[ax] -= overlap
|
||||
|
||||
overlap = 16 + s.from[ax]
|
||||
if (overlap < 0) {
|
||||
s.from[ax] = -16
|
||||
}
|
||||
} else {
|
||||
overlap = s.from[ax] + 16
|
||||
if (overlap < 0) {
|
||||
s.from[ax] -= overlap
|
||||
s.to[ax] -= overlap
|
||||
|
||||
if (s.from[ax] + s.to[ax] > 32) {
|
||||
s.to[ax] = 32
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
412
js/textures.js
Normal file
@ -0,0 +1,412 @@
|
||||
//Textures
|
||||
class Texture {
|
||||
constructor(data) {
|
||||
this.path = ''
|
||||
this.name = ''
|
||||
this.folder = '';
|
||||
this.iconpath = ''
|
||||
this.particle = false
|
||||
this.selected = false
|
||||
this.error = false;
|
||||
this.frameCount = 1
|
||||
this.show_icon = true
|
||||
this.average_color = {r:0, g:0, b:0}
|
||||
this.dark_box = false
|
||||
this.img = 0;
|
||||
this.uuid = guid()
|
||||
|
||||
if (typeof data === 'object') {
|
||||
this.extend(data)
|
||||
}
|
||||
if (!this.id) {
|
||||
var i = 0;
|
||||
while (true) {
|
||||
var matches = $.grep(textures, function(e) {return e.id == i})
|
||||
if (matches.length > 0) {
|
||||
i++;
|
||||
} else {
|
||||
this.id = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
load(isDefault) {
|
||||
var scope = this;
|
||||
|
||||
this.error = false;
|
||||
this.show_icon = true
|
||||
this.frameCount = 1
|
||||
|
||||
if (Canvas.materials[scope.uuid] !== undefined) {
|
||||
Canvas.materials[scope.uuid].dispose()
|
||||
}
|
||||
|
||||
var img = this.img = new Image()
|
||||
|
||||
img.src = this.iconpath
|
||||
img.onerror = function() {
|
||||
this.src = 'assets/missing.png'
|
||||
scope.error = true;
|
||||
scope.show_icon = false
|
||||
console.log('Error loading '+scope.iconpath)
|
||||
if (isApp && !isDefault) {
|
||||
scope.fromDefaultPack()
|
||||
}
|
||||
}
|
||||
|
||||
var tex = new THREE.Texture(img)
|
||||
img.tex = tex;
|
||||
img.tex.magFilter = THREE.NearestFilter
|
||||
img.tex.minFilter = THREE.NearestFilter
|
||||
|
||||
img.onload = function() {
|
||||
|
||||
this.tex.needsUpdate = true;
|
||||
scope.res = img.naturalWidth;
|
||||
|
||||
scope.average_color = getAverageRGB(this)
|
||||
scope.dark_box = (scope.average_color.r + scope.average_color.g + scope.average_color.b) >= 383
|
||||
|
||||
//Width / Animation
|
||||
if (img.naturalWidth !== img.naturalHeight) {
|
||||
if (img.naturalHeight % img.naturalWidth === 0) {
|
||||
scope.frameCount = img.naturalHeight / img.naturalWidth
|
||||
Canvas.updateAllUVs()
|
||||
} else if (settings.entity_mode.value === false) {
|
||||
scope.error = true;
|
||||
showQuickMessage('Texture needs to be square')
|
||||
}
|
||||
}
|
||||
if (textures.indexOf(scope) === 0) {
|
||||
Project.texture_width = img.naturalWidth
|
||||
Project.texture_height = img.naturalHeight
|
||||
}
|
||||
if ($('.dialog#texture_edit:visible').length >= 1 && scope.selected === true) {
|
||||
loadTextureMenu(scope)
|
||||
}
|
||||
TextureAnimator.updateButton()
|
||||
Canvas.updateAllFaces()
|
||||
}
|
||||
var mat = new THREE.MeshLambertMaterial({color: 0xffffff, map: tex, transparent: settings.transparency.value});
|
||||
Canvas.materials[this.uuid] = mat
|
||||
return this;
|
||||
}
|
||||
fromPath(path) {
|
||||
this.path = path
|
||||
this.name = pathToName(path, true)
|
||||
if (path.includes('data:image')) {
|
||||
this.iconpath = path
|
||||
} else {
|
||||
this.iconpath = path + '?' + tex_version
|
||||
}
|
||||
this.generateFolder(path)
|
||||
|
||||
if (!isApp && Project.dataURLTextures) {
|
||||
if (this.img && this.img.src) {
|
||||
this.img.src = 'assets/missing.png'
|
||||
}
|
||||
this.error = true;
|
||||
this.show_icon = false
|
||||
} else {
|
||||
this.load()
|
||||
}
|
||||
return this;
|
||||
}
|
||||
fromDataURL(data_url) {
|
||||
this.path = this.folder+'/'+this.name
|
||||
this.iconpath = data_url
|
||||
this.load()
|
||||
return this;
|
||||
}
|
||||
fromDefaultPack() {
|
||||
if (settings.default_path && settings.default_path.value) {
|
||||
console.log('Trying to get texture from default pack')
|
||||
this.path = settings.default_path.value + osfs + this.folder + osfs + this.name
|
||||
this.iconpath = this.path + '?' + tex_version
|
||||
this.load(true)
|
||||
}
|
||||
}
|
||||
reopen() {
|
||||
var scope = this;
|
||||
if (isApp) {
|
||||
app.dialog.showOpenDialog(currentwindow, {filters: [{name: 'PNG Texture', extensions: ['png']}]}, function (fileNames) {
|
||||
if (fileNames !== undefined) {
|
||||
fs.readFile(fileNames[0], function (err) {
|
||||
if (err) {
|
||||
console.log(err)
|
||||
}
|
||||
scope.path = fileNames[0]
|
||||
scope.iconpath = scope.path + '?' + tex_version;
|
||||
scope.name = scope.path.split(osfs).slice(-1)[0]
|
||||
|
||||
if (scope.path.includes(osfs +'textures'+osfs)) {
|
||||
var arr = scope.path.split(osfs+'textures'+osfs)
|
||||
arr = arr[arr.length-1].split(osfs)
|
||||
arr.pop()
|
||||
scope.folder = arr.join('/')
|
||||
} else {
|
||||
var arr = scope.path.split(osfs)
|
||||
scope.folder = arr[arr.length-2]
|
||||
}
|
||||
|
||||
var img = new Image()
|
||||
try {
|
||||
img.src = fileNames[0]
|
||||
} catch(err) {
|
||||
img.src = 'missing.png'
|
||||
}
|
||||
var tex = new THREE.Texture(img)
|
||||
img.tex = tex;
|
||||
img.tex.magFilter = THREE.NearestFilter
|
||||
img.tex.minFilter = THREE.LinearMipMapLinearFilter
|
||||
img.onload = function() {
|
||||
this.tex.needsUpdate = true;
|
||||
scope.res = img.naturalWidth;
|
||||
}
|
||||
Canvas.materials[scope.uuid] = new THREE.MeshBasicMaterial({color: 0xffffff, map: tex, transparent: true});
|
||||
|
||||
scope.load()
|
||||
Canvas.updateAllFaces()
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
var file = $('.dialog:visible #texture_change').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
|
||||
scope.iconpath = reader.result
|
||||
var img = new Image()
|
||||
try {
|
||||
img.src = reader.result
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
img.src = 'missing.png'
|
||||
}
|
||||
var tex = new THREE.Texture(img)
|
||||
img.tex = tex;
|
||||
img.tex.magFilter = THREE.NearestFilter
|
||||
img.tex.minFilter = THREE.LinearMipMapLinearFilter
|
||||
img.onload = function() {
|
||||
this.tex.needsUpdate = true;
|
||||
scope.res = img.naturalWidth;
|
||||
}
|
||||
Canvas.materials[scope.uuid] = new THREE.MeshLambertMaterial({color: 0xffffff, map: tex, transparent: true});
|
||||
scope.load()
|
||||
Canvas.updateAllFaces()
|
||||
main_uv.loadData()
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
}
|
||||
Blockbench.dispatchEvent( 'change_texture_path', {texture: scope} )
|
||||
}
|
||||
refresh(single) {
|
||||
if (single) {
|
||||
tex_version++;
|
||||
}
|
||||
this.iconpath = this.path + '?' + tex_version;
|
||||
this.iconpath = this.iconpath.replace(/\?\d+$/, '?' + tex_version)
|
||||
this.load()
|
||||
if (single) {
|
||||
Canvas.updateAllFaces()
|
||||
main_uv.loadData()
|
||||
loadTextureDraggable()
|
||||
}
|
||||
}
|
||||
reloadTexture() {
|
||||
this.refresh(true)
|
||||
}
|
||||
enableParticle() {
|
||||
textures.forEach(function(s) {
|
||||
s.particle = false;
|
||||
})
|
||||
this.particle = true
|
||||
return this;
|
||||
}
|
||||
javaTextureLink() {
|
||||
return this.folder+'/'+this.name.split('.png').join('')
|
||||
}
|
||||
fillParticle() {
|
||||
var particle_tex = false
|
||||
textures.forEach(function(t) {
|
||||
if (t.particle) {
|
||||
particle_tex = t
|
||||
}
|
||||
})
|
||||
if (!particle_tex) {
|
||||
this.enableParticle()
|
||||
}
|
||||
return this;
|
||||
}
|
||||
select() {
|
||||
textures.forEach(function(s) {
|
||||
s.selected = false;
|
||||
})
|
||||
this.selected = true
|
||||
textures.selected = this
|
||||
return this;
|
||||
}
|
||||
generateFolder(path) {
|
||||
if (path.includes(osfs+'textures'+osfs)) {
|
||||
var arr = path.split(osfs+'textures'+osfs)
|
||||
arr = arr[arr.length-1].split(osfs)
|
||||
arr.pop()
|
||||
this.folder = arr.join('/')
|
||||
} else {
|
||||
var arr = path.split(osfs)
|
||||
this.folder = arr[arr.length-2]
|
||||
}
|
||||
return this;
|
||||
}
|
||||
add() {
|
||||
if (!textures.includes(this)) {
|
||||
textures.push(this)
|
||||
}
|
||||
Blockbench.dispatchEvent( 'add_texture', {texture: this})
|
||||
loadTextureDraggable()
|
||||
return this;
|
||||
}
|
||||
extend(properties) {
|
||||
for (var key in properties) {
|
||||
if (properties.hasOwnProperty(key)) {
|
||||
this[key] = properties[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
apply(all) {
|
||||
if (selected.length === 0) return;
|
||||
var scope = this;
|
||||
if (all || settings.entity_mode.value) {
|
||||
var sides = ['north', 'east', 'south', 'west', 'up', 'down']
|
||||
} else {
|
||||
var sides = [main_uv.face]
|
||||
}
|
||||
selected.forEach(function(s) {
|
||||
sides.forEach(function(side) {
|
||||
elements[s].faces[side].texture = '#'+scope.id
|
||||
})
|
||||
})
|
||||
Canvas.updateSelectedFaces()
|
||||
main_uv.loadData()
|
||||
setUndo('Applied texture')
|
||||
}
|
||||
openFolder() {
|
||||
if (!isApp) return;
|
||||
shell.showItemInFolder(this.path)
|
||||
}
|
||||
remove() {
|
||||
textures.splice(textures.indexOf(this), 1)
|
||||
Canvas.updateAll()
|
||||
$('#uv_frame').css('background', 'transparent')
|
||||
TextureAnimator.updateButton()
|
||||
hideDialog()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function applyTexture(all, id) {
|
||||
if (selected.length === 0) return;
|
||||
if (id === undefined) {
|
||||
textures.forEach(function(s) {
|
||||
if (s.selected) {
|
||||
id = s.id
|
||||
}
|
||||
})
|
||||
}
|
||||
if (id === undefined) return;
|
||||
getTextureById(id).apply(all)
|
||||
}
|
||||
function reloadTextures() {
|
||||
tex_version++;
|
||||
textures.forEach(function(t) {
|
||||
t.iconpath = t.path + '?' + tex_version;
|
||||
t.refresh(false)
|
||||
})
|
||||
Canvas.updateAllFaces()
|
||||
main_uv.loadData()
|
||||
loadTextureDraggable()
|
||||
}
|
||||
function getSelectedTextureIndex() {
|
||||
var index = false
|
||||
textures.forEach(function(s, i) {
|
||||
if (s.selected === true) {
|
||||
index = i
|
||||
}
|
||||
})
|
||||
return index;
|
||||
}
|
||||
function openTextureMenu(index) {
|
||||
if (index === undefined) {
|
||||
index = getSelectedTextureIndex()
|
||||
if (index === false) return;
|
||||
} else {
|
||||
textures[index].select()
|
||||
}
|
||||
showDialog('texture_edit')
|
||||
|
||||
loadTextureMenu(textures.selected)
|
||||
|
||||
if (isApp) {
|
||||
$('#texture_edit #change_file_button').click( function() {
|
||||
textures.selected.reopen()
|
||||
})
|
||||
} else {
|
||||
$('#texture_edit #texture_change').off('change')
|
||||
$('#texture_edit #texture_change').on('change', function() {
|
||||
textures.selected.reopen()
|
||||
})
|
||||
}
|
||||
}
|
||||
function loadTextureMenu(tex) {
|
||||
var arr = tex.path.split(osfs)
|
||||
arr.splice(-1)
|
||||
var path = arr.join('<span class="slash">/</span>') + '<span class="slash">/</span><span class="accent_color">' + tex.name + '</span>'
|
||||
$('#texture_edit #te_title').text(tex.name)
|
||||
$('#texture_edit #te_path').html(path)
|
||||
$('#texture_edit input#te_variable').val(tex.id)
|
||||
$('#texture_edit input#te_folder').val(tex.folder)
|
||||
$('#texture_menu_thumbnail').html(tex.img)
|
||||
}
|
||||
function saveTextureMenu() {
|
||||
hideDialog()
|
||||
index = getSelectedTextureIndex()
|
||||
if (index === false) return;
|
||||
var tex = textures[index]
|
||||
tex.id = $('#texture_edit input#te_variable').val()
|
||||
tex.folder = $('#texture_edit input#te_folder').val()
|
||||
|
||||
$('#texture_edit #change_file_button').unbind('click')
|
||||
$('#texture_edit #file_upload').unbind('input')
|
||||
}
|
||||
function loadTextureDraggable() {
|
||||
Vue.nextTick(function() {
|
||||
setTimeout(function() {
|
||||
$('li.texture').draggable({
|
||||
revertDuration: 0,
|
||||
helper: function(e) {
|
||||
var t = $(e.target)
|
||||
if (!t.hasClass('texture')) t = t.parent()
|
||||
if (!t.hasClass('texture')) t = t.parent()
|
||||
return t.find('.texture_icon_wrapper').clone().addClass('texture_drag_helper').attr('texid', t.attr('texid'))
|
||||
},
|
||||
cursorAt: { left: 24, top: 24 },
|
||||
revert: 'invalid',
|
||||
appendTo: 'body',
|
||||
zIndex: 19,
|
||||
stop: function(event, ui) {
|
||||
setTimeout(function() {
|
||||
if ($('canvas#canvas:hover').length > 0) {
|
||||
if (canvasClick(event)) {
|
||||
getTextureById(ui.helper.attr('texid')).apply()
|
||||
}
|
||||
}
|
||||
}, 10)
|
||||
}
|
||||
})
|
||||
}, 42)
|
||||
})
|
||||
}
|
43378
js/three.js
Normal file
86
js/tree.vue.js
Normal file
@ -0,0 +1,86 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
var VueTreeItem = Vue.extend({
|
||||
template:
|
||||
'<li class="outliner_node" v-bind:class="{ parent_li: node.children && node.children.length > 0}" v-bind:id="node.uuid">' +
|
||||
'<div @contextmenu.prevent.stop="node.showContextMenu($event)" class="outliner_object" v-on:dblclick="node.rename($event)" v-on:click="node.select($event)" :title="node.title" v-bind:class="{ cube: node.title === \'Cube\', group: node.title === \'Group\', selected: node.display.isselected }">' +
|
||||
//Opener
|
||||
'<i v-if="node.children && node.children.length > 0" v-on:click="toggle(node)" class="fa icon-open-state" :class=\'{"fa-caret-right": !node.isOpen, "fa-caret-down": node.isOpen}\'></i>' +
|
||||
'<i v-else class="outliner_opener_placeholder"></i>' +
|
||||
//Main
|
||||
'<i v-if="showIcon(node)" :class="nodeClass(node)"></i>' +
|
||||
'<input type="text" class="cube_name" v-model="node.name" disabled>' +
|
||||
'<a v-for="btn in node.buttons" class="ml5" href="javascript:" :title="btn.title" v-on:click.stop="btnClick(btn, node)" v-bind:class="{advanced_option: btn.advanced_option}">' +
|
||||
'<i v-if="node.isIconEnabled(btn.title) === true" :class="btn.icon"></i>' +
|
||||
'<i v-else :class="btn.icon_off"></i>' +
|
||||
'</a>' +
|
||||
'</div>' +
|
||||
//Other Entries
|
||||
'<ul v-show="node.isOpen">' +
|
||||
//'<li v-show="node.showLoading && node._loading"><i class="fa fa-spinner fa-pulse"></i></li>' +
|
||||
'<vue-tree-item v-for="item in node.children" :node="item" v-key="item.uuid"></vue-tree-item>' +
|
||||
'</ul>' +
|
||||
'</li>',
|
||||
props: {
|
||||
node: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showIcon: function (node) {
|
||||
return node.icon || node.openedIcon || node.closedIcon;
|
||||
},
|
||||
nodeClass: function (node) {
|
||||
if (node.isOpen) {
|
||||
return node.openedIcon || node.icon;
|
||||
} else {
|
||||
return node.closedIcon || node.icon;
|
||||
}
|
||||
},
|
||||
toggle: function (node) {
|
||||
if (node.hasOwnProperty('isOpen')) {
|
||||
node.isOpen = !node.isOpen;
|
||||
} else {
|
||||
Vue.set(node, 'isOpen', true);
|
||||
}
|
||||
},
|
||||
btnClick: function (btn, node) {
|
||||
if (typeof btn.click === 'function') {
|
||||
btn.click(node);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'node.isOpen': function (val) {
|
||||
if (!this.node.hasOwnProperty('_loading')) {
|
||||
Vue.set(this.node, '_loading', false);
|
||||
}
|
||||
if (val) {
|
||||
if (typeof this.node.onOpened === 'function') {
|
||||
this.node.onOpened(this.node);
|
||||
}
|
||||
} else {
|
||||
if (typeof this.node.onClosed === 'function') {
|
||||
this.node.onClosed(this.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Vue.component('vue-tree-item', VueTreeItem);
|
||||
|
||||
var VueTree = Vue.extend({
|
||||
template: '<div class="vue-tree"><ul>' +
|
||||
'<tree-item :node.sync="option.root"></tree-item>' +
|
||||
'</ul></div>',
|
||||
props: {
|
||||
option: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'tree-item': VueTreeItem
|
||||
}
|
||||
});
|
||||
Vue.component('vue-tree', VueTree);
|
||||
})();
|
302
js/util.js
Normal file
@ -0,0 +1,302 @@
|
||||
var asyncLoop = function(o){
|
||||
var i=-1;
|
||||
|
||||
var async_loop = function(){
|
||||
i++;
|
||||
if(i==o.length){o.callback(); return;}
|
||||
o.functionToLoop(async_loop, i);
|
||||
}
|
||||
async_loop();//init
|
||||
}
|
||||
function pathToName(path, extension) {
|
||||
var path_array = path.split('/').join('\\').split('\\')
|
||||
if (extension) {
|
||||
return path_array[path_array.length-1]
|
||||
} else {
|
||||
return path_array[path_array.length-1].split('.').slice(0, -1).join('.')
|
||||
}
|
||||
}
|
||||
|
||||
function guid() {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
||||
s4() + '-' + s4() + s4() + s4();
|
||||
}
|
||||
|
||||
Array.prototype.equals = function (array) {
|
||||
if (!array)
|
||||
return false;
|
||||
|
||||
if (this.length != array.length)
|
||||
return false;
|
||||
|
||||
for (var i = 0, l=this.length; i < l; i++) {
|
||||
if (this[i] instanceof Array && array[i] instanceof Array) {
|
||||
if (!this[i].equals(array[i]))
|
||||
return false;
|
||||
}
|
||||
else if (this[i] != array[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Array.prototype.remove = function (item) { {
|
||||
var index = this.indexOf(item)
|
||||
if (index > -1) {
|
||||
this.splice(index, 1)
|
||||
return index;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Object.defineProperty(Array.prototype, "equals", {enumerable: false});
|
||||
|
||||
function omitKeys(obj, keys, dual_level) {
|
||||
var dup = {};
|
||||
for (key in obj) {
|
||||
if (keys.indexOf(key) == -1) {
|
||||
if (dual_level === true && typeof obj[key] === 'object') {
|
||||
dup[key] = {}
|
||||
for (key2 in obj[key]) {
|
||||
if (keys.indexOf(key2) == -1) {
|
||||
dup[key][key2] = obj[key][key2];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
dup[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
function stringify (obj, options) {
|
||||
options = options || {}
|
||||
var indent = JSON.stringify([1], null, get(options, 'indent', 2)).slice(2, -3)
|
||||
var maxLength = (indent === '' ? Infinity : get(options, 'maxLength', 80))
|
||||
|
||||
return (function _stringify (obj, currentIndent, reserved) {
|
||||
if (obj && typeof obj.toJSON === 'function') {
|
||||
obj = obj.toJSON()
|
||||
}
|
||||
|
||||
var string = JSON.stringify(obj)
|
||||
|
||||
if (string === undefined) {
|
||||
return string
|
||||
}
|
||||
|
||||
var length = maxLength - currentIndent.length - reserved
|
||||
|
||||
if (string.length <= length) {
|
||||
var prettified = prettify(string)
|
||||
if (prettified.length <= length) {
|
||||
return prettified
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof obj === 'object' && obj !== null) {
|
||||
var nextIndent = currentIndent + indent
|
||||
var items = []
|
||||
var delimiters
|
||||
var comma = function (array, index) {
|
||||
return (index === array.length - 1 ? 0 : 1)
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
for (var index = 0; index < obj.length; index++) {
|
||||
items.push(
|
||||
_stringify(obj[index], nextIndent, comma(obj, index)) || 'null'
|
||||
)
|
||||
}
|
||||
delimiters = '[]'
|
||||
} else {
|
||||
Object.keys(obj).forEach(function (key, index, array) {
|
||||
var keyPart = JSON.stringify(key) + ': '
|
||||
var value = _stringify(obj[key], nextIndent,
|
||||
keyPart.length + comma(array, index))
|
||||
if (value !== undefined) {
|
||||
items.push(keyPart + value)
|
||||
}
|
||||
})
|
||||
delimiters = '{}'
|
||||
}
|
||||
|
||||
if (items.length > 0) {
|
||||
return [
|
||||
delimiters[0],
|
||||
indent + items.join(',\n' + nextIndent),
|
||||
delimiters[1]
|
||||
].join('\n' + currentIndent)
|
||||
}
|
||||
}
|
||||
|
||||
return string
|
||||
}(obj, '', 0))
|
||||
}
|
||||
var stringOrChar = /("(?:[^"]|\\.)*")|[:,]/g
|
||||
function prettify (string) {
|
||||
return string.replace(stringOrChar, function (match, string) {
|
||||
return string ? match : match + ' '
|
||||
})
|
||||
}
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
function trimFloatNumber(val) {
|
||||
if (val == '') return val;
|
||||
var string = val.toFixed(4)
|
||||
string = string.replace(/0+$/g, '').replace(/\.$/g, '')
|
||||
return string;
|
||||
}
|
||||
Array.prototype.findInArray = function(key, value) {
|
||||
if (this.length === 0) return {};
|
||||
var i = 0
|
||||
while (i < this.length) {
|
||||
if (this[i][key] === value) return this[i]
|
||||
i++;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function get (options, name, defaultValue) {
|
||||
return (name in options ? options[name] : defaultValue)
|
||||
}
|
||||
function getKeyByValue(object, value) {
|
||||
return Object.keys(object).find(key => object[key] === value);
|
||||
}
|
||||
function compareKeys(event, action) {
|
||||
if (action &&
|
||||
action.code === event.which &&
|
||||
action.ctrl === event.ctrlKey &&
|
||||
action.shift === event.shiftKey &&
|
||||
action.alt === event.altKey) {
|
||||
event.preventDefault()
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function getAverageRGB(imgEl) {
|
||||
|
||||
var blockSize = 5, // only visit every 5 pixels
|
||||
defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
|
||||
canvas = document.createElement('canvas'),
|
||||
context = canvas.getContext && canvas.getContext('2d'),
|
||||
data, width, height,
|
||||
i = -4,
|
||||
length,
|
||||
rgb = {r:0,g:0,b:0},
|
||||
count = 0;
|
||||
|
||||
if (!context) {
|
||||
return defaultRGB;
|
||||
}
|
||||
|
||||
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
|
||||
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
|
||||
|
||||
context.drawImage(imgEl, 0, 0);
|
||||
|
||||
try {
|
||||
data = context.getImageData(0, 0, width, height);
|
||||
} catch(e) {
|
||||
/* security error, img on diff domain */alert('x');
|
||||
return defaultRGB;
|
||||
}
|
||||
|
||||
length = data.data.length;
|
||||
|
||||
while ( (i += blockSize * 4) < length ) {
|
||||
++count;
|
||||
rgb.r += data.data[i];
|
||||
rgb.g += data.data[i+1];
|
||||
rgb.b += data.data[i+2];
|
||||
}
|
||||
|
||||
// ~~ used to floor values
|
||||
rgb.r = ~~(rgb.r/count);
|
||||
rgb.g = ~~(rgb.g/count);
|
||||
rgb.b = ~~(rgb.b/count);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
function autoStringify(object) {
|
||||
if (settings.minifiedout.value === true) {
|
||||
var string = JSON.stringify(object)
|
||||
} else {
|
||||
var string = stringify(object, {indent: '\t', maxLength: parseInt(settings.max_json_length.value)})
|
||||
}
|
||||
string.replace(/-?[0-9]+\.-?[0-9]{5,16}/g, function(s) {
|
||||
var parts = s.split('.')
|
||||
if (parts[1].length > settings.round_digits.value) {
|
||||
return parts[0] + '.' + parts[1].substr(0, settings.round_digits.value)
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
})
|
||||
return string;
|
||||
}
|
||||
|
||||
function pluralS(arr) {
|
||||
if (arr.length === 1 || arr === 1) {
|
||||
return '';
|
||||
} else {
|
||||
return 's';
|
||||
}
|
||||
}
|
||||
|
||||
function getAxisLetter(number) {
|
||||
switch (number) {
|
||||
case 0: return 'x'; break;
|
||||
case 1: return 'y'; break;
|
||||
case 2: return 'z'; break;
|
||||
}
|
||||
}
|
||||
function getAxisNumber(letter) {
|
||||
switch (letter.toLowerCase()) {
|
||||
case 'x': return 0; break;
|
||||
case 'y': return 1; break;
|
||||
case 'z': return 2; break;
|
||||
}
|
||||
}
|
||||
function limitNumber(number, min, max) {
|
||||
if (number > max) number = max;
|
||||
if (number < min) number = min;
|
||||
return number;
|
||||
}
|
||||
function getSnapFactor(event) {
|
||||
if (event.shiftKey) {
|
||||
return canvas_grid / 4;
|
||||
} else if (event.ctrlKey) {
|
||||
return canvas_grid / 10;
|
||||
} else {
|
||||
return canvas_grid;
|
||||
}
|
||||
}
|
||||
function compareVersions(string1/*new*/, string2/*old*/) {
|
||||
// Is string1 newer than string2 ?
|
||||
var arr1 = string1.split('.')
|
||||
var arr2 = string2.split('.')
|
||||
var i = 0;
|
||||
var num1 = 0;
|
||||
var num2 = 0;
|
||||
while (i < arr1.length) {
|
||||
num1 = parseInt(arr1[i])
|
||||
num2 = parseInt(arr2[i])
|
||||
if (num1 > num2) {
|
||||
return true;
|
||||
} else if (num1 < num2) {
|
||||
return false
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
8
js/vue.min.js
vendored
Normal file
281
js/web.js
Normal file
@ -0,0 +1,281 @@
|
||||
(function() {
|
||||
$.getScript("js/file_saver.js");
|
||||
})()
|
||||
|
||||
$('.open-in-browser').click((event) => {
|
||||
event.preventDefault();
|
||||
window.open(event.target.href, '_blank');
|
||||
});
|
||||
var lastImportEvent;
|
||||
|
||||
function tryLoadPOSTModel() {
|
||||
if ($('#post_model').text() !== '') {
|
||||
if ($('#post_textures').text() !== '') {
|
||||
Project.dataURLTextures = true
|
||||
}
|
||||
loadFile($('#post_model').text(), 'model', true)
|
||||
$('#post_model').remove()
|
||||
if ($('#post_textures').text() !== '') {
|
||||
var data = JSON.parse( $('#post_textures').text() )
|
||||
for (var key in data) {
|
||||
if (data.hasOwnProperty(key)) {
|
||||
var tex = getTextureById(key+'');
|
||||
if (!tex) return;
|
||||
tex.img.src = ''
|
||||
tex.iconpath = data[key]
|
||||
}
|
||||
}
|
||||
textures.forEach(function(tex) {
|
||||
tex.load()
|
||||
})
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return showSplashScreen
|
||||
}
|
||||
}
|
||||
|
||||
//Loader Open
|
||||
function openFile(makeNew) {
|
||||
g_makeNew = makeNew
|
||||
fileLoaderLoad('.json', false, readFile)
|
||||
$('#file_folder').val('')
|
||||
}
|
||||
function importExtrusion(makeNew) {
|
||||
g_makeNew = makeNew
|
||||
fileLoaderLoad('.png', true, readExtrusion)
|
||||
}
|
||||
//Texture
|
||||
function openTexture() {
|
||||
fileLoaderLoad('.png', true, readTexture)
|
||||
}
|
||||
function loadBackgroundImage(event) {
|
||||
if (event !== undefined) {
|
||||
if (event.altKey === true) {
|
||||
textPrompt('Background Image Path', 'active_scene.background.image', true)
|
||||
return;
|
||||
}
|
||||
}
|
||||
fileLoaderLoad('image/*', false, readBackgroundImage)
|
||||
}
|
||||
//Main
|
||||
function fileLoaderLoad(type, showInputs, importFunction) {
|
||||
//Meta
|
||||
$('#file_name').val('')
|
||||
if (showInputs === true) {
|
||||
$('#file_loader_meta').show()
|
||||
} else {
|
||||
$('#file_loader_meta').hide()
|
||||
}
|
||||
//Loader
|
||||
$('#file_upload').attr('accept', type)
|
||||
|
||||
//Clear Events
|
||||
try {
|
||||
$('#web_import_btn')[0].removeEventListener('click', lastImportEvent)
|
||||
$('#file_upload')[0].removeEventListener('change', lastImportEvent)
|
||||
} catch (err) {}
|
||||
//Add Events
|
||||
$('#web_import_btn')[0].addEventListener('click', importFunction)
|
||||
$('#file_upload')[0].addEventListener('change', function() {
|
||||
var path_parts = $(this).val().split('\\')
|
||||
$('#file_name').val(path_parts[path_parts.length-1])
|
||||
})
|
||||
lastImportEvent = importFunction
|
||||
|
||||
showDialog('file_loader')
|
||||
}
|
||||
|
||||
|
||||
//Loader Read
|
||||
function readTexture() {
|
||||
hideDialog()
|
||||
var file = $('#file_upload').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
var path = reader.result
|
||||
|
||||
var name = $('#file_name').val()
|
||||
if (name == undefined) {
|
||||
name = 'Texture'
|
||||
}
|
||||
|
||||
var folder = $('#file_folder').val()
|
||||
if (folder == "") {
|
||||
folder = "blocks"
|
||||
}
|
||||
|
||||
new Texture({folder: folder, name: name}).add().fromDataURL(path).fillParticle()
|
||||
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
function readFile() {
|
||||
hideDialog()
|
||||
var file = $('#file_upload').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
|
||||
loadFile(reader.result, 'model', g_makeNew)
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsText(file)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
function reopenTexture(texture) {
|
||||
var file = $('.dialog:visible #texture_change').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
|
||||
texture.iconpath = reader.result
|
||||
var img = new Image()
|
||||
try {
|
||||
img.src = reader.result
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
img.src = 'missing.png'
|
||||
}
|
||||
var tex = new THREE.Texture(img)
|
||||
img.tex = tex;
|
||||
img.tex.magFilter = THREE.NearestFilter
|
||||
img.tex.minFilter = THREE.LinearMipMapLinearFilter
|
||||
var thisTexture = texture;
|
||||
img.onload = function() {
|
||||
this.tex.needsUpdate = true;
|
||||
thisTexture.res = img.naturalWidth;
|
||||
}
|
||||
texture.material = new THREE.MeshBasicMaterial({color: 0xffffff, map: tex, transparent: true});
|
||||
texture.reload()
|
||||
Canvas.updateAllFaces()
|
||||
Blockbench.dispatchEvent( 'change_texture_path', {texture: texture} )
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
}
|
||||
function readExtrusion() {
|
||||
hideDialog()
|
||||
var file = $('#file_upload').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
|
||||
reader.onloadend = function() {
|
||||
if (g_makeNew) {
|
||||
if (newProject() == false) return;
|
||||
}
|
||||
var path = reader.result
|
||||
|
||||
var name = $('#file_name').val()
|
||||
if (name == undefined) {
|
||||
name = 'Texture'
|
||||
}
|
||||
|
||||
var folder = $('#file_folder').val()
|
||||
if (folder == "") {
|
||||
folder = "blocks"
|
||||
}
|
||||
|
||||
new Texture({folder: folder, name: name}).add().fromDataURL(path).fillParticle()
|
||||
|
||||
showDialog('image_extruder')
|
||||
drawExtrusionImage(path)
|
||||
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
function readBackgroundImage() {
|
||||
hideDialog()
|
||||
var file = $('#file_upload').get(0).files[0]
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function() {
|
||||
var path = reader.result
|
||||
active_scene.background.image = path
|
||||
enterScene(true)
|
||||
}
|
||||
if (file) {
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
}
|
||||
|
||||
//Saver
|
||||
function saveFileBlock() {
|
||||
saveFile()
|
||||
}
|
||||
function saveFileOptifine() {
|
||||
var data = buildOptifineModel()
|
||||
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, 'model.jpm')
|
||||
showQuickMessage('Saved Optifine entity model')
|
||||
}
|
||||
function saveFileEntity() {
|
||||
var obj = {}
|
||||
var model_name = Project.parent
|
||||
if (model_name == '') model_name = 'geometry.unknown'
|
||||
obj[model_name] = buildEntityModel()
|
||||
|
||||
var data = autoStringify(obj)
|
||||
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, 'model.json')
|
||||
showQuickMessage('Saved as bedrock entity model')
|
||||
}
|
||||
function saveFileObj() {
|
||||
scene.remove(three_grid)
|
||||
scene.remove(Transformer)
|
||||
var exporter = new THREE.OBJExporter();
|
||||
var content = exporter.parse( scene, 'model');
|
||||
scene.add(three_grid)
|
||||
scene.add(Transformer)
|
||||
|
||||
//OBJECT
|
||||
var blob = new Blob([content.obj], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, 'model.obj')
|
||||
|
||||
//MATERIAL
|
||||
var blob = new Blob([content.mtl], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, 'model.mtl')
|
||||
showQuickMessage('Saved as .obj model')
|
||||
}
|
||||
|
||||
function saveFile() {
|
||||
var data = buildBlockModel()
|
||||
var blob = new Blob([data], {type: "text/plain;charset=utf-8"});
|
||||
saveAs(blob, 'model.json')
|
||||
}
|
||||
|
||||
//Misc
|
||||
window.onbeforeunload = function() {
|
||||
if (Prop.project_saved === false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function showSaveDialog(close) {
|
||||
if (Prop.project_saved === false && elements.length > 0) {
|
||||
var answer = confirm('Your current work will be lost. Are you sure?')
|
||||
if (answer == true) {
|
||||
if (close) {
|
||||
//preventClosing = false
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (close) {
|
||||
preventClosing = false
|
||||
app.getCurrentWindow().close()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function checkForUpdates() {
|
||||
showQuickMessage('Webapp is up-to-date')
|
||||
}
|
44
main.js
Normal file
@ -0,0 +1,44 @@
|
||||
const {app, BrowserWindow} = require('electron')
|
||||
const path = require('path')
|
||||
const url = require('url')
|
||||
|
||||
let win
|
||||
|
||||
function createWindow () {
|
||||
win = new BrowserWindow({
|
||||
icon:'icon.ico',
|
||||
show: false,
|
||||
backgroundColor: '#21252b',
|
||||
webPreferences: {
|
||||
experimentalFeatures: true,
|
||||
webgl: true
|
||||
}
|
||||
})
|
||||
win.setMenu(null);
|
||||
win.maximize()
|
||||
win.show()
|
||||
win.loadURL(url.format({
|
||||
pathname: path.join(__dirname, 'index.php'),
|
||||
protocol: 'file:',
|
||||
slashes: true
|
||||
}))
|
||||
win.on('closed', () => {
|
||||
win = null
|
||||
})
|
||||
//win.webContents.openDevTools()
|
||||
}
|
||||
|
||||
app.on('ready', createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
app.on('activate', () => {
|
||||
if (win === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
25
package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"description": "Minecraft Block Model Editor",
|
||||
"version": "1.9.2",
|
||||
"author": "JannisX11",
|
||||
"main": "main.js",
|
||||
"build": {
|
||||
"appId": "blockbench",
|
||||
"mac": {
|
||||
"category": "macOS.application"
|
||||
}
|
||||
},
|
||||
"mac": {
|
||||
"target": "dmg"
|
||||
},
|
||||
"scripts": {
|
||||
"pack": "build --dir",
|
||||
"dist": "build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.4.1",
|
||||
"electron": "^1.7.5",
|
||||
"electron-winstaller": "^2.5.2"
|
||||
}
|
||||
}
|