mirror of
https://github.com/lalbornoz/roar.git
synced 2024-11-23 07:36:37 +00:00
Initial commit.
This commit is contained in:
parent
fed2fbe90e
commit
449a186b8e
139
css/ak.css
Normal file
139
css/ak.css
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
.fa{color:#fff}.fb{color:#000}.fc{color:#00007F}.fd{color:#009300}.fe{color:red}.ff{color:#7f0000}.fg{color:#9C009C}.fh{color:#FC7F00}.fi{color:#FF0}.fj{color:#00FC00}.fk{color:#009393}.fl{color:#0FF}.fm{color:#0000FC}.fn{color:#F0F}.fo{color:#7F7F7F}.fp{color:#D2D2D2}
|
||||||
|
.ba{background-color:#fff}.bb{background-color:#000}.bc{background-color:#00007F}.bd{background-color:#009300}.be{background-color:red}.bf{background-color:#7f0000}.bg{background-color:#9C009C}.bh{background-color:#FC7F00}.bi{background-color:#FF0}.bj{background-color:#00FC00}.bk{background-color:#009393}.bl{background-color:#0FF}.bm{background-color:#0000FC}.bn{background-color:#F0F}.bo{background-color:#7F7F7F}.bp{background-color:#D2D2D2}
|
||||||
|
|
||||||
|
.winxp .fa{color:rgb(255,255,255)}
|
||||||
|
.winxp .fb{color:rgb(0,0,0)}
|
||||||
|
.winxp .fc{color:rgb(0,0,128)}
|
||||||
|
.winxp .fd{color:rgb(0,128,0)}
|
||||||
|
.winxp .fe{color:rgb(255,0,0)}
|
||||||
|
.winxp .ff{color:rgb(128,0,0)}
|
||||||
|
.winxp .fg{color:rgb(128,0,128)}
|
||||||
|
.winxp .fh{color:rgb(255,128,0)}
|
||||||
|
.winxp .fi{color:rgb(255,255,0)}
|
||||||
|
.winxp .fj{color:rgb(0,255,0)}
|
||||||
|
.winxp .fk{color:rgb(0,128,128)}
|
||||||
|
.winxp .fl{color:rgb(0,255,255)}
|
||||||
|
.winxp .fm{color:rgb(0,0,255)}
|
||||||
|
.winxp .fn{color:rgb(255,0,255)}
|
||||||
|
.winxp .fo{color:rgb(128,128,128)}
|
||||||
|
.winxp .fp{color:rgb(192,192,192)}
|
||||||
|
|
||||||
|
.winxp .ba{background-color:rgb(255,255,255)}
|
||||||
|
.winxp .bb{background-color:rgb(0,0,0)}
|
||||||
|
.winxp .bc{background-color:rgb(0,0,128)}
|
||||||
|
.winxp .bd{background-color:rgb(0,128,0)}
|
||||||
|
.winxp .be{background-color:rgb(255,0,0)}
|
||||||
|
.winxp .bf{background-color:rgb(128,0,0)}
|
||||||
|
.winxp .bg{background-color:rgb(128,0,128)}
|
||||||
|
.winxp .bh{background-color:rgb(255,128,0)}
|
||||||
|
.winxp .bi{background-color:rgb(255,255,0)}
|
||||||
|
.winxp .bj{background-color:rgb(0,255,0)}
|
||||||
|
.winxp .bk{background-color:rgb(0,128,128)}
|
||||||
|
.winxp .bl{background-color:rgb(0,255,255)}
|
||||||
|
.winxp .bm{background-color:rgb(0,0,255)}
|
||||||
|
.winxp .bn{background-color:rgb(255,0,255)}
|
||||||
|
.winxp .bo{background-color:rgb(128,128,128)}
|
||||||
|
.winxp .bp{background-color:rgb(192,192,192)}
|
||||||
|
|
||||||
|
.vga .fa{color:rgb(255,255,255)}
|
||||||
|
.vga .fb{color:rgb(0,0,0)}
|
||||||
|
.vga .fc{color:rgb(0,0,170)}
|
||||||
|
.vga .fd{color:rgb(0,170,0)}
|
||||||
|
.vga .fe{color:rgb(255,85,85)}
|
||||||
|
.vga .ff{color:rgb(170,0,0)}
|
||||||
|
.vga .fg{color:rgb(170,0,170)}
|
||||||
|
.vga .fh{color:rgb(170,85,0)}
|
||||||
|
.vga .fi{color:rgb(255,255,85)}
|
||||||
|
.vga .fj{color:rgb(85,255,85)}
|
||||||
|
.vga .fk{color:rgb(0,170,170)}
|
||||||
|
.vga .fl{color:rgb(85,255,255)}
|
||||||
|
.vga .fm{color:rgb(85,85,255)}
|
||||||
|
.vga .fn{color:rgb(255,85,255)}
|
||||||
|
.vga .fo{color:rgb(85,85,85)}
|
||||||
|
.vga .fp{color:rgb(170,170,170)}
|
||||||
|
|
||||||
|
|
||||||
|
.vga .ba{background-color:rgb(255,255,255)}
|
||||||
|
.vga .bb{background-color:rgb(0,0,0)}
|
||||||
|
.vga .bc{background-color:rgb(0,0,170)}
|
||||||
|
.vga .bd{background-color:rgb(0,170,0)}
|
||||||
|
.vga .be{background-color:rgb(255,85,85)}
|
||||||
|
.vga .bf{background-color:rgb(170,0,0)}
|
||||||
|
.vga .bg{background-color:rgb(170,0,170)}
|
||||||
|
.vga .bh{background-color:rgb(170,85,0)}
|
||||||
|
.vga .bi{background-color:rgb(255,255,85)}
|
||||||
|
.vga .bj{background-color:rgb(85,255,85)}
|
||||||
|
.vga .bk{background-color:rgb(0,170,170)}
|
||||||
|
.vga .bl{background-color:rgb(85,255,255)}
|
||||||
|
.vga .bm{background-color:rgb(85,85,255)}
|
||||||
|
.vga .bn{background-color:rgb(255,85,255)}
|
||||||
|
.vga .bo{background-color:rgb(85,85,85)}
|
||||||
|
.vga .bp{background-color:rgb(170,170,170)}
|
||||||
|
|
||||||
|
.c64 .fa{color:rgb(255,255,255)}
|
||||||
|
.c64 .fb{color:rgb(0,0,0)}
|
||||||
|
.c64 .fc{color:rgb(69,32,170)}
|
||||||
|
.c64 .fd{color:rgb(101,170,69)}
|
||||||
|
.c64 .fe{color:rgb(138,101,32)}
|
||||||
|
.c64 .ff{color:rgb(138,69,32)}
|
||||||
|
.c64 .fg{color:rgb(138,69,170)}
|
||||||
|
.c64 .fh{color:rgb(101,69,0)}
|
||||||
|
.c64 .fi{color:rgb(207,207,101)}
|
||||||
|
.c64 .fj{color:rgb(170,239,138)}
|
||||||
|
.c64 .fk{color:rgb(138,138,138)}
|
||||||
|
.c64 .fl{color:rgb(101,170,207)}
|
||||||
|
.c64 .fm{color:rgb(138,101,223)}
|
||||||
|
.c64 .fn{color:rgb(207,138,101)}
|
||||||
|
.c64 .fo{color:rgb(69,69,69)}
|
||||||
|
.c64 .fp{color:rgb(170,170,170)}
|
||||||
|
|
||||||
|
.c64 .ba{background-color:rgb(255,255,255)}
|
||||||
|
.c64 .bb{background-color:rgb(0,0,0)}
|
||||||
|
.c64 .bc{background-color:rgb(69,32,170)}
|
||||||
|
.c64 .bd{background-color:rgb(101,170,69)}
|
||||||
|
.c64 .be{background-color:rgb(138,101,32)}
|
||||||
|
.c64 .bf{background-color:rgb(138,69,32)}
|
||||||
|
.c64 .bg{background-color:rgb(138,69,170)}
|
||||||
|
.c64 .bh{background-color:rgb(101,69,0)}
|
||||||
|
.c64 .bi{background-color:rgb(207,207,101)}
|
||||||
|
.c64 .bj{background-color:rgb(170,239,138)}
|
||||||
|
.c64 .bk{background-color:rgb(138,138,138)}
|
||||||
|
.c64 .bl{background-color:rgb(101,170,207)}
|
||||||
|
.c64 .bm{background-color:rgb(138,101,223)}
|
||||||
|
.c64 .bn{background-color:rgb(207,138,101)}
|
||||||
|
.c64 .bo{background-color:rgb(69,69,69)}
|
||||||
|
.c64 .bp{background-color:rgb(170,170,170)}
|
||||||
|
|
||||||
|
.appleii .fa{color:rgb(255,255,255)}
|
||||||
|
.appleii .fb{color:rgb(0,0,0)}
|
||||||
|
.appleii .fc{color:rgb(64,53,121)}
|
||||||
|
.appleii .fd{color:rgb(64,75,7)}
|
||||||
|
.appleii .fe{color:rgb(191,180,248)}
|
||||||
|
.appleii .ff{color:rgb(109,41,64)}
|
||||||
|
.appleii .fg{color:rgb(218,60,241)}
|
||||||
|
.appleii .fh{color:rgb(218,104,15)}
|
||||||
|
.appleii .fi{color:rgb(191,202,134)}
|
||||||
|
.appleii .fj{color:rgb(38,195,16)}
|
||||||
|
.appleii .fk{color:rgb(19,87,64)}
|
||||||
|
.appleii .fl{color:rgb(146,214,191)}
|
||||||
|
.appleii .fm{color:rgb(37,151,240)}
|
||||||
|
.appleii .fn{color:rgb(236,168,191)}
|
||||||
|
.appleii .fo{color:rgb(128,128,128)}
|
||||||
|
.appleii .fp{color:rgb(128,128,128)}
|
||||||
|
|
||||||
|
.appleii .ba{background-color:rgb(255,255,255)}
|
||||||
|
.appleii .bb{background-color:rgb(0,0,0)}
|
||||||
|
.appleii .bc{background-color:rgb(64,53,121)}
|
||||||
|
.appleii .bd{background-color:rgb(64,75,7)}
|
||||||
|
.appleii .be{background-color:rgb(191,180,248)}
|
||||||
|
.appleii .bf{background-color:rgb(109,41,64)}
|
||||||
|
.appleii .bg{background-color:rgb(218,60,241)}
|
||||||
|
.appleii .bh{background-color:rgb(218,104,15)}
|
||||||
|
.appleii .bi{background-color:rgb(191,202,134)}
|
||||||
|
.appleii .bj{background-color:rgb(38,195,16)}
|
||||||
|
.appleii .bk{background-color:rgb(19,87,64)}
|
||||||
|
.appleii .bl{background-color:rgb(146,214,191)}
|
||||||
|
.appleii .bm{background-color:rgb(37,151,240)}
|
||||||
|
.appleii .bn{background-color:rgb(236,168,191)}
|
||||||
|
.appleii .bo{background-color:rgb(128,128,128)}
|
||||||
|
.appleii .bp{background-color:rgb(128,128,128)}
|
255
css/sally.css
Normal file
255
css/sally.css
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
textarea,input[type=text],body {
|
||||||
|
margin:0;
|
||||||
|
font-family: 'FixedsysExcelsior301Regular';
|
||||||
|
font-size: 12pt;
|
||||||
|
font-weight: 100;
|
||||||
|
line-height: 11pt;
|
||||||
|
color: #6d6b6d;
|
||||||
|
-webkit-font-smoothing: antialiased !important;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #000000 !important;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FixedsysExcelsior301Regular';
|
||||||
|
src: url('../fonts/fsex300-webfont.eot');
|
||||||
|
src: url('../fonts/fsex300-webfont.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('../fonts/fsex300-webfont.woff') format('woff'),
|
||||||
|
url('../fonts/fsex300-webfont.ttf') format('truetype'),
|
||||||
|
url('../fonts/fsex300-webfont.svg#FixedsysExcelsior301Regular') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {display: block}
|
||||||
|
a:link, a:visited {text-decoration: none; color: #6b6760}
|
||||||
|
a:hover { text-decoration: underline }
|
||||||
|
|
||||||
|
.faded { color: #404040; }
|
||||||
|
.rapper, .block {
|
||||||
|
float: left;
|
||||||
|
height:auto;
|
||||||
|
width:auto;
|
||||||
|
background-color: #000000;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.rapper {
|
||||||
|
white-space:pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
#gallery_rapper {
|
||||||
|
display: inline
|
||||||
|
}
|
||||||
|
#ui_rapper .block {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
padding:4px;
|
||||||
|
}
|
||||||
|
.block:nth-child(n+2) {
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
#textarea_mode { padding: 4px; }
|
||||||
|
.tool {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.tool.radio {
|
||||||
|
margin: 0 8px 0 0;
|
||||||
|
}
|
||||||
|
.tool.radio.focused {
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
background-color: #6d6d6d;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.transparent {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: url(../img/gray-dither.gif);
|
||||||
|
background-size: 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (-webkit-min-device-pixel-ratio: 2) {
|
||||||
|
.transparent {
|
||||||
|
background-size: 4px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span,a { min-width: 8px; line-height: 15px; display: inline-block; }
|
||||||
|
body.pixels {
|
||||||
|
line-height: 8px;
|
||||||
|
}
|
||||||
|
.pixels #brush_rapper span,
|
||||||
|
.pixels #brush_rapper a,
|
||||||
|
.pixels #canvas_rapper span,
|
||||||
|
.pixels #canvas_rapper a { line-height: 8px; overflow: hidden; }
|
||||||
|
.rapper { cursor: crosshair; }
|
||||||
|
body.grid span { border-right: 1px solid #444; border-bottom: 1px solid #444; }
|
||||||
|
body.grid div { border-left: 1px solid #444; }
|
||||||
|
body.grid #canvas_rapper > div:first-child,
|
||||||
|
body.grid #palette_rapper > div:first-child,
|
||||||
|
body.grid #letters_rapper > div:first-child,
|
||||||
|
body.grid #brush_rapper > div:first-child { border-top: 1px solid #444; }
|
||||||
|
body.grid .tool { border: 1px solid #444; }
|
||||||
|
.ed { color: #fff; }
|
||||||
|
.locked { border-bottom: 1px solid; color: #bbb; text-decoration: none; }
|
||||||
|
.tool.locked.focused { box-shadow: 0 0; }
|
||||||
|
.focused { box-shadow: inset 0 0px 2px #fff; border-color: #fff; }
|
||||||
|
.ba.focused { box-shadow: inset 0 0px 2px #000, inset 0 0px 2px #000; border-color: #000; }
|
||||||
|
.tool.focused, .ed.focused { color: white; text-decoration: underline; }
|
||||||
|
.focused { box-shadow: inset 1px 0 2px white, inset -1px 0 2px white, inset 0 1px 2px white, inset 0 -1px 2px white; }
|
||||||
|
.faba.focused, .fbba.focused, .fcba.focused, .fdba.focused, .feba.focused, .ffba.focused, .fgba.focused, .fhba.focused,
|
||||||
|
.fiba.focused, .fjba.focused, .fkba.focused, .flba.focused, .fmba.focused, .fnba.focused, .foba.focused, .fpba.focused
|
||||||
|
{ box-shadow: inset 1px 0 2px #888, inset -1px 0 2px #888, inset 0 1px 2px #888, inset 0 -1px 2px #888; }
|
||||||
|
body.loading { opacity: 0; }
|
||||||
|
body { transition: 0.1s linear; }
|
||||||
|
#import_textarea { font-size: 9pt; }
|
||||||
|
textarea { font-size:12pt; width: 37vw; height: 300px; background: #333; color: #0f0; border: 0; font-family: 'FixedsysExcelsior301Regular'; outline: 0; border: 1px solid #333; background:#010;}
|
||||||
|
#shader_rapper { display: none; }
|
||||||
|
#import_rapper { display: none; }
|
||||||
|
#canvas_rapper {
|
||||||
|
white-space: pre;
|
||||||
|
box-shadow: 0 0 2px rgba(255,255,255,0.3);
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui_rapper { clear:both; float: left; width: 100vw; }
|
||||||
|
#workspace_rapper { width: 100%; }
|
||||||
|
|
||||||
|
.loading .vertical #ui_rapper { clear: none }
|
||||||
|
.vertical #ui_rapper { width: 320px; float: left; clear: none; }
|
||||||
|
.vertical .rapper, .vertical .block { float: left; }
|
||||||
|
.vertical #canvas_rapper,
|
||||||
|
.vertical #canvas_rapper div,
|
||||||
|
.vertical #tools_rapper,
|
||||||
|
.vertical #palette_rapper,
|
||||||
|
.vertical #brush_container { display: inline-block; float: left; }
|
||||||
|
.vertical #workspace_rapper { width: auto; position: relative; float: left; }
|
||||||
|
.vertical #palette_rapper { margin-right: 10px; }
|
||||||
|
.vertical #tools_block { min-width: 100%; }
|
||||||
|
|
||||||
|
#secret_rapper { float: left; clear: right; }
|
||||||
|
#secret_rapper span { float: left; }
|
||||||
|
.vertical #secret_rapper { margin-right: 10px; }
|
||||||
|
.vertical #secret_rapper span { float: left; clear: both; }
|
||||||
|
.nopaint #brush_rapper { min-height: 70px; min-width: 50px; }
|
||||||
|
|
||||||
|
#nopaint_rapper.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotated #canvas_rapper {
|
||||||
|
transform: translateX(-50%) translateY(-50%) translateZ(0) rotate(-90deg);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tools_block > * {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
#brush_rapper, #letters_rapper {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
.dropper #canvas_rapper {
|
||||||
|
cursor: url(../img/dropper.gif) 0 15, auto;
|
||||||
|
}
|
||||||
|
.bucket #canvas_rapper {
|
||||||
|
cursor: url(../img/bucket.png) 3 15, auto;
|
||||||
|
}
|
||||||
|
#brush_rapper {
|
||||||
|
border: 1px solid;
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
#letters_rapper {
|
||||||
|
display: inline-block;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.close { position: absolute; top: 20px; right: 20px; z-index: 2; padding: 10px; background: black; cursor: pointer; }
|
||||||
|
#webcam_rapper { display: none; position: absolute; top: 0px; left: 0px; width:100%;height:100%; box-sizing:border-box; border: 40px solid rgba(0,0,0,0.5); background-color: rgba(0,0,0,0.5); }
|
||||||
|
#webcam_iframe { position: absolute; top: 0px; left: 0px; width:100%;height:100%; background-color: rgba(0,0,0,0.5); border: 0; }
|
||||||
|
#experimental_palette_toggle.focused { box-shadow: none; }
|
||||||
|
#cursor_input { position: fixed; top: 0; right: 0; width:30px; opacity: 0; font-size: 16px; }
|
||||||
|
.selector_el {
|
||||||
|
border: 1px dashed #fff !important;
|
||||||
|
padding-top: 1px;
|
||||||
|
position:absolute;
|
||||||
|
margin-top: -1px;
|
||||||
|
top:-999px;left:-999px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.selector_el.dragging {
|
||||||
|
color: #0f0;
|
||||||
|
}
|
||||||
|
.selector_el.creating div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.custom {
|
||||||
|
float: left;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
#username_input {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
outline: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
width: 76px;
|
||||||
|
}
|
||||||
|
#username_input:focus {
|
||||||
|
border: 1px solid #0f0;
|
||||||
|
color: #0f0;
|
||||||
|
}
|
||||||
|
#upload_input {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
outline: 0;
|
||||||
|
border: 1px solid #0f0;
|
||||||
|
color: #0f0;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 360px;
|
||||||
|
}
|
||||||
|
#upload_button.uploading {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: 'FixedsysExcelsior301Regular';
|
||||||
|
-webkit-animation: rainbow 1.0s infinite;
|
||||||
|
animation: rainbow 2.0s infinite;
|
||||||
|
padding: 0; margin: 0;
|
||||||
|
}
|
||||||
|
@keyframes rainbow {
|
||||||
|
0% { color: hsl(0,100%,50%) }
|
||||||
|
33% { color: hsl(90,100%,50%) }
|
||||||
|
50% { color: #fff }
|
||||||
|
66% { color: hsl(320,100%,50%) }
|
||||||
|
100% { color: hsl(360,100%,50%) }
|
||||||
|
}
|
||||||
|
|
||||||
|
.panke #send_to_irc_el {
|
||||||
|
color: white;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.panke #shader_el,
|
||||||
|
.panke #load_el,
|
||||||
|
.panke #gallery_el,
|
||||||
|
.panke #import_textarea,
|
||||||
|
.panke #doc_el,
|
||||||
|
.panke #gallery_el,
|
||||||
|
.panke #save_button,
|
||||||
|
.panke #upload_button,
|
||||||
|
.panke #export_button,
|
||||||
|
.panke #username_input,
|
||||||
|
.panke #upload_input,
|
||||||
|
.panke #grid_el,
|
||||||
|
.panke #save_el,
|
||||||
|
.panke #vertical_checkbox,
|
||||||
|
.panke #add_custom_el,
|
||||||
|
.panke #format_el { display: none !important; }
|
38
doc/index.html
Normal file
38
doc/index.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!-- http://jollo.org/licensing/public/LNT-1.txt -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="stylesheet" href="../css/sally.css" type="text/css" charset="utf-8" />
|
||||||
|
<link rel="stylesheet" href="../css/ak.css" type="text/css" charset="utf-8" />
|
||||||
|
<link rel="stylesheet" href="http://jollo.org/assets/jibber/css/nitelite.css" type="text/css" charset="utf-8" />
|
||||||
|
<style>
|
||||||
|
body { font-family: 'FixedsysExcelsior301Regular'; }
|
||||||
|
a:nth-of-type(2n+1), a { color: #0f0; }
|
||||||
|
a:nth-of-type(2n+2), a { color: #ff0; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<center>
|
||||||
|
|
||||||
|
<table border=35 cellpadding=10>
|
||||||
|
<tr><td style="background: rgba(0,0,100,0.5)">
|
||||||
|
<h1>asdf.us/ascii documentation</h1>
|
||||||
|
|
||||||
|
<span style="white-space: pre; color: white;">
|
||||||
|
These are some handy documents which address some of the more obscure
|
||||||
|
features of the asdf.us color code tool:
|
||||||
|
|
||||||
|
* <a href="tips.txt">tips.txt</a> - Tips on using the keyboard
|
||||||
|
* <a href="irssi.txt">irssi.txt</a> - Instructions on using IRSSI to make color codes.
|
||||||
|
* <a href="nopaint.txt">nopaint.txt</a> - A guide to "No Paint"
|
||||||
|
|
||||||
|
Documents on Shaders
|
||||||
|
|
||||||
|
* <a href="shadetut.txt">shadetut.txt</a> - A brief tutorial on ASCII shaders.
|
||||||
|
* <a href="shaders/brush.txt">shaders/brush.txt</a> - Shaders designed to work on the brush
|
||||||
|
* <a href="shaders/canvas.txt">shaders/canvas.txt</a> - Shaders designed to work on the canvas
|
||||||
|
* <a href="shaders/util.txt">shaders/util.txt</a> - Miscellaneous utilities / snippets
|
||||||
|
|
||||||
|
For more information on IRC, Color Codes, and much more, visit the
|
||||||
|
<a href="http://jollo.org/LNT/doc/">documentation sitemap</a>, part of the <a href="http://jollo.org/">Jollo IRC Network</a>.
|
||||||
|
|
||||||
|
<a href="/ascii/">asdf.us/ascii</a>
|
||||||
|
|
153
doc/irssi.txt
Normal file
153
doc/irssi.txt
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
__________________________________________________________________________
|
||||||
|
____ ____ _____ ____ ___ ___ ____
|
||||||
|
/_____ _____/ / ___ \ / ____/ / ____/ /_____ _____/
|
||||||
|
/ / / / \ \ / / / / / /
|
||||||
|
/ / / /____/ / \ \__ \ \__ / /
|
||||||
|
/ / / ___ __/ \__ \ \__ \ / /
|
||||||
|
/ / / / \ \ \ \ \ \ / /
|
||||||
|
_____/ /_____ / / \ \ ____/ / ____/ /____/ /_____
|
||||||
|
___/ /__/ /_______\ \__/ /___/ // /____
|
||||||
|
__________________________________________________________________________
|
||||||
|
|
||||||
|
|
||||||
|
OPTIMIZE YOUR TERMINAL FOR COLOR CODES ON OSX
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
You can use terminal, some nerds seem to prefer iterm2, but it's up to you
|
||||||
|
... http://iterm2.com/
|
||||||
|
|
||||||
|
To see color codes correctly, make sure your term type is xterm-256color --
|
||||||
|
|
||||||
|
If you use iterm: https://s3.amazonaws.com/luckyplop/a1b0f0e3d6eae746c82194876f2ccd8b200bc3bb.png
|
||||||
|
If you use terminal: https://s3.amazonaws.com/luckyplop/6a2270b58ea1cfac587607215e1b829f41d47355.png
|
||||||
|
|
||||||
|
Restart iterm after changing this setting.
|
||||||
|
|
||||||
|
The default iterm colors are kind of ugly for color codes, so you may want to change them
|
||||||
|
to something like this..
|
||||||
|
|
||||||
|
https://s3.amazonaws.com/luckyplop/c5f3a1f2b8e2f8a745fa2638c21af7d26117b91b.png
|
||||||
|
|
||||||
|
You can download this iTerm color preset here:
|
||||||
|
|
||||||
|
http://asdf.us/ascii/doc/bamboo.itermcolors
|
||||||
|
|
||||||
|
|
||||||
|
INSTALLING IRSSI ON OSX
|
||||||
|
=======================
|
||||||
|
|
||||||
|
For me the easiest thing is to install homebrew >> http://brew.sh/
|
||||||
|
|
||||||
|
Follow les instructions and then..
|
||||||
|
|
||||||
|
brew install irssi
|
||||||
|
|
||||||
|
Then you run irssi from a terminal by typing the magic word..
|
||||||
|
|
||||||
|
irssi
|
||||||
|
|
||||||
|
|
||||||
|
SETTING UP IRSSI FOR COLOR CODES
|
||||||
|
================================
|
||||||
|
|
||||||
|
Use these commands for proper unicode support --
|
||||||
|
|
||||||
|
/set term_charset utf-8
|
||||||
|
/set recode_autodetect_utf8 ON
|
||||||
|
/set recode_fallback ISO-8859-15
|
||||||
|
/set recode ON
|
||||||
|
|
||||||
|
Use these commands to dump color codes quickly and efficiently --
|
||||||
|
|
||||||
|
/set cmd_queue_speed 0msec
|
||||||
|
/set cmds_max_at_once 1
|
||||||
|
/set flood_max_msgs 0
|
||||||
|
/set flood_timecheck 0
|
||||||
|
|
||||||
|
To make your log go back very far --
|
||||||
|
|
||||||
|
/set scrollback_lines 20000
|
||||||
|
/set scrollback_time 10day
|
||||||
|
|
||||||
|
Remember to type /save after doing a /set to save your changes!
|
||||||
|
|
||||||
|
/save
|
||||||
|
|
||||||
|
Your irssi configuration will be stored in your home directory in..
|
||||||
|
|
||||||
|
.irssi/config
|
||||||
|
|
||||||
|
|
||||||
|
NORMAL IRSSI OPERATION
|
||||||
|
======================
|
||||||
|
|
||||||
|
If you do not want to do the autojoin thing these are the commands you'd normally use to connect:
|
||||||
|
|
||||||
|
/server -ssl irc.asdf.us 7777
|
||||||
|
/join #ascii
|
||||||
|
|
||||||
|
|
||||||
|
SETTING UP IRSSI TO AUTOJOIN #ASCII
|
||||||
|
===================================
|
||||||
|
|
||||||
|
First run irssi, then paste in these commands.
|
||||||
|
Please change YOUR_NICK_HERE to your preferred username!
|
||||||
|
|
||||||
|
/network add -nick YOUR_NICK_HERE -user YOUR_NICK_HERE -realname "YOUR NAME HERE" asdf
|
||||||
|
/server add -network asdf -auto -ssl irc.asdf.us 7777
|
||||||
|
/channel add -auto #ascii asdf
|
||||||
|
/save
|
||||||
|
/quit
|
||||||
|
|
||||||
|
Now run irssi again.. it should autoconnect to the channels and stuff.
|
||||||
|
If you want it to move you into #ascii by default, you can do ctrl-N and then
|
||||||
|
|
||||||
|
/layout save
|
||||||
|
/save
|
||||||
|
|
||||||
|
|
||||||
|
IRC TIPS
|
||||||
|
========
|
||||||
|
|
||||||
|
/join #ascii -- join a channel :)
|
||||||
|
/part #ascii -- leave a channel ;(
|
||||||
|
/quit blabla -- quit irc (with the quit message 'blabla')
|
||||||
|
/list -- list channels
|
||||||
|
/nick booboo -- change your nick to booboo
|
||||||
|
/who #ascii -- show complete list of people on #ascii
|
||||||
|
/names -- show quick list of names
|
||||||
|
/msg nick blabla -- send someone a private message ;)
|
||||||
|
|
||||||
|
|
||||||
|
IRSSI TIPS
|
||||||
|
==========
|
||||||
|
|
||||||
|
Ctrl-N -- move to next window
|
||||||
|
Ctrl-P -- move to previous window
|
||||||
|
/window close -- close a window
|
||||||
|
Fn-up arrow -- page up (if you don't have a pageup key)
|
||||||
|
Fn-down arrow -- page down (if you don't have a pagedown key)
|
||||||
|
|
||||||
|
|
||||||
|
IRSSI SCRIPTING
|
||||||
|
===============
|
||||||
|
|
||||||
|
This is its own can of worms. May we suggest:
|
||||||
|
|
||||||
|
http://scripts.irssi.org/scripts/noticelogic.pl
|
||||||
|
http://scripts.irssi.org/scripts/nickcolor.pl
|
||||||
|
|
||||||
|
To make it run on startup, copy it into ~/.irssi/scripts/autorun/ (and restart irssi)
|
||||||
|
|
||||||
|
Another fun IRC thing is running an XDCC server for sharing files..
|
||||||
|
-- for more info see http://asdf.us/xdcc/
|
||||||
|
|
||||||
|
|
||||||
|
AND REMEMBER...
|
||||||
|
===============
|
||||||
|
|
||||||
|
Have fun and be safe online!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
58
doc/nopaint.txt
Normal file
58
doc/nopaint.txt
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
"" 88
|
||||||
|
9,88m, ,8888, 9,88m, ,888, mm 9,88m, 8888
|
||||||
|
88 88 86 98 88 88 ,mm88 88 88 88 88
|
||||||
|
88 88 '8888' 88888' "nn89 88 88 88 "8m
|
||||||
|
88 a brief tutorial :)
|
||||||
|
|
||||||
|
Last month or so I encountered Jeffrey Scudder's tool 'No Paint' -
|
||||||
|
|
||||||
|
https://www.nopaint.org/
|
||||||
|
|
||||||
|
- an automatic drawing tool with a minimal interface: you control it using
|
||||||
|
just two buttons. The No Paint tool provided much entertainment on #sally,
|
||||||
|
so during some downtime I added similar functionality to the asdf.us/ascii
|
||||||
|
tool. Under the brush, you should see two buttons - to kick it off, click
|
||||||
|
'paint' and it will begin drawing.
|
||||||
|
|
||||||
|
If you don't like what it's doing, click 'no' -
|
||||||
|
- this will remove the current line and start drawing a new line.
|
||||||
|
|
||||||
|
If you like what it's doing, click 'paint' -
|
||||||
|
- the line will be applied to the canvas, and it will start drawing anew.
|
||||||
|
|
||||||
|
While it's going, you can also click 'pause' and it will stop, so you can
|
||||||
|
save it or draw on it yourself.
|
||||||
|
|
||||||
|
|
||||||
|
Keyboard shortcuts -
|
||||||
|
|
||||||
|
left arrow - 'no'
|
||||||
|
right arrow - 'paint'
|
||||||
|
down arrow - 'pause'
|
||||||
|
|
||||||
|
|
||||||
|
Right-click toggles -
|
||||||
|
|
||||||
|
If you RIGHT-CLICK on "Paint" it will switch tools automatically.
|
||||||
|
|
||||||
|
If you RIGHT-CLICK on "No" it will engage TURBO MODE.
|
||||||
|
|
||||||
|
|
||||||
|
Some tools currently implemented -
|
||||||
|
|
||||||
|
- solid brush
|
||||||
|
- erase brush
|
||||||
|
- color-changing brush
|
||||||
|
- hue brush
|
||||||
|
- letter brush
|
||||||
|
- clone tool
|
||||||
|
- smear tool
|
||||||
|
- fill tool
|
||||||
|
- stars brush
|
||||||
|
- canvas slide
|
||||||
|
- canvas scale
|
||||||
|
- canvas rotate
|
||||||
|
- canvas colorcycle
|
||||||
|
|
||||||
|
|
126
doc/shaders/brush.txt
Normal file
126
doc/shaders/brush.txt
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
BRUSH SHADERS
|
||||||
|
=============
|
||||||
|
|
||||||
|
Unless noted, these shaders were written to work on the brush itself.
|
||||||
|
Make sure "brush" is selected and "animate" is checked.
|
||||||
|
|
||||||
|
|
||||||
|
>> distressed texture brush
|
||||||
|
|
||||||
|
Sample use of the "choice" function to get a random color.
|
||||||
|
|
||||||
|
var char = choice(" abcdef ")
|
||||||
|
lex.bg = +choice("0124")
|
||||||
|
lex.fg = +choice("01234")
|
||||||
|
lex.char = char
|
||||||
|
lex.opacity = char == " " ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> foggy terrain brush
|
||||||
|
|
||||||
|
var char = choice(" abcdef ")
|
||||||
|
lex.bg = choice([14,15])
|
||||||
|
lex.fg = choice("367")
|
||||||
|
lex.char = char
|
||||||
|
lex.opacity = char == " " ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> mirror brush (left-right)
|
||||||
|
|
||||||
|
NOTE: Animate this on the canvas, then draw:
|
||||||
|
|
||||||
|
if (x > w/2) {
|
||||||
|
lex.assign( canvas.aa[y][w-x] )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> mirror brush (up-down)
|
||||||
|
|
||||||
|
NOTE: Animate this on the canvas, then draw:
|
||||||
|
|
||||||
|
if (x > h/2) {
|
||||||
|
lex.assign( canvas.aa[h-y][x] )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> rainbow stardust brush
|
||||||
|
|
||||||
|
Uncheck BG and animate this to brush:
|
||||||
|
|
||||||
|
lex.fg = hue(t)
|
||||||
|
lex.char = choice(" ,'.,.','****** ")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> noise brushes, works on a black background:
|
||||||
|
|
||||||
|
lex.bg = max(5, yellow(randint(t)))
|
||||||
|
lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> simple rainbow:
|
||||||
|
|
||||||
|
if (lex.bg != 1) lex.bg = randint(t)
|
||||||
|
lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> self-erasing:
|
||||||
|
|
||||||
|
if (lex.bg != 1) lex.bg = yellow(randint(t))
|
||||||
|
lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> cycling rainbow brush
|
||||||
|
|
||||||
|
if (lex.bg != 1) lex.bg = hue( all_color_hue_order.indexOf( color_names[ lex.bg ] ) + 1 )
|
||||||
|
lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> "stars" brush.. set your brush to paint just the character "#"
|
||||||
|
|
||||||
|
if (lex.char == "#") {
|
||||||
|
lex.fg = hue(randint(15))
|
||||||
|
lex.char = random() > 0.1 ? " " : "+@*.,\"+'*-"[randint(10)]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> use fg char to mask mask what you're drawing on the bg
|
||||||
|
|
||||||
|
if (lex.char != "/") { lex.bg = 1 }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> sharded glitch brush
|
||||||
|
|
||||||
|
Example: http://asdf.us/z/kksnvs.png
|
||||||
|
|
||||||
|
Use on a brush:
|
||||||
|
|
||||||
|
lex.bg = t/y/x
|
||||||
|
lex.opacity = lex.bg % 1 ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> incremental brush
|
||||||
|
|
||||||
|
Set your brush to be the ^ character, square, about 10x10
|
||||||
|
Draw "char" only
|
||||||
|
Then animate this shader on the canvas:
|
||||||
|
|
||||||
|
if (lex.char=="^") {
|
||||||
|
lex.bg += 1
|
||||||
|
lex.char = " "
|
||||||
|
}
|
||||||
|
lex.bg += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
237
doc/shaders/canvas.txt
Normal file
237
doc/shaders/canvas.txt
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
CANVAS SHADERS
|
||||||
|
==============
|
||||||
|
|
||||||
|
These shaders were written to work on areas of canvas.
|
||||||
|
Make sure "canvas" is selected and "animate" is checked.
|
||||||
|
|
||||||
|
|
||||||
|
>> original shader..
|
||||||
|
|
||||||
|
lex.bg = hue((x+y*y+t/10)/20)
|
||||||
|
lex.fg = (x+y)%16
|
||||||
|
lex.char = (y%2) ? ":" : "%"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> energy ball ascii shader
|
||||||
|
|
||||||
|
d = dist(x/2+w/4, y, w/2, h/2)
|
||||||
|
an = angle(x/2+w/4, y, w/2,h/2)+t/4200
|
||||||
|
r=10.2
|
||||||
|
|
||||||
|
if (d < r) lex.bg = randint(r)
|
||||||
|
|
||||||
|
ll=abs(an|0)+""
|
||||||
|
lex.char=ll[ll.length-1]
|
||||||
|
|
||||||
|
if (d > r) {
|
||||||
|
lex.bg = randint(d)
|
||||||
|
lex.fg = randint(d)
|
||||||
|
lex.char = ll[ll.length-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> drifting fire
|
||||||
|
|
||||||
|
t += sin(x/1000)*100000
|
||||||
|
pos = y/h*6 + sin(x*3) - cos(y*t/10000-10)
|
||||||
|
pos = clamp(pos, 0, 6)
|
||||||
|
lex.bg = hue(pos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> the "bJoel56" shader
|
||||||
|
|
||||||
|
yy=y
|
||||||
|
x-=w/2
|
||||||
|
y-=h/2
|
||||||
|
|
||||||
|
lex.bg = blue(yy/h+random())
|
||||||
|
lex.fg = green(yy/h*4 + sin(x/100+random()/2)) // hue(t/1000)|0;
|
||||||
|
|
||||||
|
var abcd=".'~:;!>+=icjtJYSGSXDQKHNWM";
|
||||||
|
function chara (aa,n) { return aa[clamp(n*aa.length, 0, aa.length)|0] }
|
||||||
|
lex.char = chara(abcd, y/h*(5/3 + tan(x/100)+random()/1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> frog shader v2
|
||||||
|
|
||||||
|
t/=-100
|
||||||
|
d = sinp( (dist(x/2+w/4, y, w/2, h/2) + t)/2 ) * 10
|
||||||
|
|
||||||
|
lex.char=',./>"ASE$#'[(floor(d))]
|
||||||
|
lex.fg = [1,3,9][floor(d*3)%3]
|
||||||
|
lex.bg=1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> frog shader v3
|
||||||
|
|
||||||
|
// set period to like 0.2 for a normal circle
|
||||||
|
period = y/10
|
||||||
|
|
||||||
|
t/=-100
|
||||||
|
d = sinp( (dist(x/2+w/4, y, w/2, h/2) + t) * period )
|
||||||
|
dd = d * 10.5
|
||||||
|
d3 = dd < 8 ? 0 : 1
|
||||||
|
|
||||||
|
lex.char=' .,"+/>OXEN'[(floor(dd))]
|
||||||
|
lex.fg = [3,9][floor(d3)]
|
||||||
|
lex.bg=1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> spaceships
|
||||||
|
|
||||||
|
many cool shaders are possible with this technique.. changing the char
|
||||||
|
gradient (lex.char=...) etc. i love how the dots move on v4.
|
||||||
|
|
||||||
|
this is a variation that looks like a bunch of ships flying across the screen.
|
||||||
|
has a really cool 3d look to it cuz the rows move at different speeds.
|
||||||
|
|
||||||
|
period = sin(y)
|
||||||
|
|
||||||
|
t/=-100
|
||||||
|
d = sinp( (dist(x/2+w/4, y, w/2, h/2) + t) * period )
|
||||||
|
dd = d * 10.5
|
||||||
|
d3 = dd < 8 ? 0 : 1
|
||||||
|
|
||||||
|
lex.char=' .,"+/>\^+'[(floor(dd))]
|
||||||
|
lex.fg = [3,9][floor(d3)]
|
||||||
|
lex.bg=1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> concentric circles with a wavy "sunburst" pattern going around them
|
||||||
|
|
||||||
|
x -= w/2
|
||||||
|
y -= h/2
|
||||||
|
|
||||||
|
x /= h
|
||||||
|
y /= h/2 + 2
|
||||||
|
|
||||||
|
r = dist(x,y,0,0)
|
||||||
|
ang = angle(x,y,0,0)
|
||||||
|
|
||||||
|
if (r < 0.6) {
|
||||||
|
if (abs(mod(sin((r*t)/100000000000) + ang*18,TWO_PI)) < 2)
|
||||||
|
lex.bg = 12
|
||||||
|
else
|
||||||
|
lex.bg = 5
|
||||||
|
}
|
||||||
|
else if (r < 0.65)
|
||||||
|
lex.bg = 4
|
||||||
|
else if (abs(mod(sin((r*t)/100000000000) + ang*18,TWO_PI)) < 2)
|
||||||
|
lex.bg = 7
|
||||||
|
else
|
||||||
|
lex.bg = 8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> slash-based interference patterns
|
||||||
|
|
||||||
|
if (x > h*2) x=h-x
|
||||||
|
y-=h/2
|
||||||
|
t/=2000
|
||||||
|
|
||||||
|
if (sin(x-y*t) > 0) {
|
||||||
|
lex.bg=1
|
||||||
|
lex.fg=4
|
||||||
|
lex.char= Math.floor(x-y*10001+t)%2 ? '\/' : '\\'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lex.bg=1
|
||||||
|
lex.fg=9
|
||||||
|
lex.char= Math.floor(3*x+y+t)%2 ? '\\' : ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> sparkling stars
|
||||||
|
|
||||||
|
if (lex.char != " ") {
|
||||||
|
lex.fg =floor( Math.random()*10 )
|
||||||
|
var az="Xx+*"
|
||||||
|
lex.char=az[floor(az.indexOf(lex.char)+ t/10000000 +Math.random())%az.length]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> coogi x/y doodle
|
||||||
|
|
||||||
|
xx=x
|
||||||
|
t/=1000
|
||||||
|
x/=w/2
|
||||||
|
y/=h/2
|
||||||
|
y-=1
|
||||||
|
x-=1
|
||||||
|
x*=x-sin(y/t)
|
||||||
|
y*=1
|
||||||
|
|
||||||
|
lex.bg = 1 // gray( sin(x/(y/3-1)+t) + sin(y/4+t) )
|
||||||
|
lex.fg = hue( sin((y/5)+t) - cos(x*t) *5 )
|
||||||
|
lex.char = " _.,:;\"~| "[Math.round(xx*(y+1+(x+t/102)/4)*13)%13]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> glitch shader - produces odd combinations of fg/bg
|
||||||
|
|
||||||
|
lex.char=String.fromCharCode(lex.char.charCodeAt(0)+1)
|
||||||
|
lex.bg+=7
|
||||||
|
lex.fg+=5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> dots / lines shader
|
||||||
|
|
||||||
|
xx = ((t/10*x)*y/10)%8
|
||||||
|
lex.bg = colors.black
|
||||||
|
lex.fg = green(x*3+y*5)
|
||||||
|
lex.char = ((xx%1) !== 0) ? " " : " .,;=+!@"[xx]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> munching squares horizon
|
||||||
|
|
||||||
|
t/=100
|
||||||
|
y+=10
|
||||||
|
x-=w/2
|
||||||
|
x/=y/10
|
||||||
|
lex.bg=hue((x^y)+t)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> grayscale vertical interlacing
|
||||||
|
|
||||||
|
First, make a canvas that's totally white.
|
||||||
|
|
||||||
|
Run this shader:
|
||||||
|
|
||||||
|
if (lex.bg == 0) {
|
||||||
|
lex.bg = ((x)%2) ? 15 : 14
|
||||||
|
}
|
||||||
|
|
||||||
|
Then set your brush to a white square.
|
||||||
|
|
||||||
|
Run this shader w/ animate:
|
||||||
|
|
||||||
|
if (lex.bg == 0) {
|
||||||
|
lex.bg = ((x)%2) ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> nice purple/orange texture
|
||||||
|
|
||||||
|
lex.bg=colors.purple
|
||||||
|
lex.fg=colors.orange
|
||||||
|
x/=3
|
||||||
|
x=floor(x+y/2.1) // <- this is cool number to change
|
||||||
|
if (x+10*sin(x)+10*cos(y/(t%100)) < y/3) {
|
||||||
|
lex.char="abcdefghijklmnopqrstuvwxyz"[x%26]
|
||||||
|
} else {
|
||||||
|
lex.char="abcdefghijklmnopqrstuvwxyz".toUpperCase()[x%26]
|
||||||
|
}
|
||||||
|
|
38
doc/shaders/util.txt
Normal file
38
doc/shaders/util.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
SHADER UTILITIES
|
||||||
|
================
|
||||||
|
|
||||||
|
These are little snippets which may be useful in writing your own shaders.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> basic way to slow the frame rate of a shader.
|
||||||
|
|
||||||
|
window.zz=window.zz||0
|
||||||
|
if(!(x+y)) zz++
|
||||||
|
if (lex.bg != 1 && !(zz % 4)) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
>> handy for brushes - use color to mask brush shape
|
||||||
|
|
||||||
|
lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
Tip: Set to "animate brush", then use option+shift (alt+shift) to
|
||||||
|
copy color from the canvas. Brush will have the "shape" of the
|
||||||
|
copied color only. Can be a cool effect when used with fg/bg only.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> copy color from canvas at x/y
|
||||||
|
|
||||||
|
lex.assign( canvas.get(x,y) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
>> animate canvas up and to the left..
|
||||||
|
|
||||||
|
lex.assign( canvas.get(x+1,y+1) )
|
||||||
|
|
||||||
|
|
156
doc/shadetut.txt
Normal file
156
doc/shadetut.txt
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
ASCII SHADER TUTORIAL
|
||||||
|
=====================
|
||||||
|
|
||||||
|
In the asdf.us/ascii shaders, you write a little math function that executes on every
|
||||||
|
pixel on the selected area. The shaders can affect either the brush, the selected region,
|
||||||
|
or the whole canvas.
|
||||||
|
|
||||||
|
Shaders can also be animated, so they update live. With a shader applied to the brush,
|
||||||
|
the brush changes continuously as you draw.
|
||||||
|
|
||||||
|
|
||||||
|
THE LEX OBJECT
|
||||||
|
==============
|
||||||
|
|
||||||
|
Essentially you are writing a Javascript function that modifies this "lex" object, which
|
||||||
|
has four properties
|
||||||
|
|
||||||
|
1) lex.bg = this is the background color
|
||||||
|
2) lex.fg = this is the foreground color (text color)
|
||||||
|
3) lex.char = this is the letter that you see in the space
|
||||||
|
4) lex.opacity = this is whether the pixel actually draws or not
|
||||||
|
- so like a circular brush is opacity 1 in the middle and opacity 0 on the corners
|
||||||
|
|
||||||
|
|
||||||
|
THE COLOR CODE NUMBERS
|
||||||
|
======================
|
||||||
|
|
||||||
|
With lex.bg and lex.fg, the goal is to have a number between 0 and 15, corresponding to
|
||||||
|
the color code values from mIRC.
|
||||||
|
|
||||||
|
If you shift-click on the color palette, you can cycle it around to the one which shows
|
||||||
|
the actual order of the mIRC colors.
|
||||||
|
|
||||||
|
The mIRC colors are the ones that go white, black, dark blue, green, red, dark red ...
|
||||||
|
and these correspond to the numbers 0, 1, 2, 3, 4 ...
|
||||||
|
|
||||||
|
|
||||||
|
COLOR CYCLING
|
||||||
|
=============
|
||||||
|
|
||||||
|
Additionally there are some color functions that might help -
|
||||||
|
These functions make it easier to cycle through colors in a way that makes sense logically
|
||||||
|
(since the mIRC colors are in a weird order)
|
||||||
|
|
||||||
|
- hue(...) = this creates a cycle of colors in terms of their hue or color name,
|
||||||
|
so you get a rainbow that goes from dark red through yellow, green, blue,
|
||||||
|
purple, and back
|
||||||
|
- gray(...) = cycles through grayscale
|
||||||
|
- red(...) yellow(...) green(...) blue(...) purple(...) = use smaller palettes
|
||||||
|
- inv_hue(...) fire(...) dark_gray(...) = these are oddities i made for fun
|
||||||
|
|
||||||
|
|
||||||
|
VARIABLES
|
||||||
|
=========
|
||||||
|
|
||||||
|
Variables you have at your disposal are similar to the asdf.us/shader tool -
|
||||||
|
|
||||||
|
- x, y = the coordinates of the pixel
|
||||||
|
- mouse.x, mouse.y = the coordinate of the mouse as it hovers over the canvas
|
||||||
|
- t = the current time, in milliseconds
|
||||||
|
|
||||||
|
TIP: The time will increase very quickly - it's good to add t /= 1000 at the top of
|
||||||
|
your shader so it goes slowly (and won't cause a seizure).
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
=========
|
||||||
|
|
||||||
|
Remember, this is Javascript. You have the basic operators:
|
||||||
|
|
||||||
|
+ - / *
|
||||||
|
|
||||||
|
And the bitwise operators:
|
||||||
|
|
||||||
|
& | ^ ~
|
||||||
|
|
||||||
|
You can do if statements with the standard comparison operators:
|
||||||
|
|
||||||
|
< > == <= >=
|
||||||
|
|
||||||
|
You also have access to all the functions on the Math object:
|
||||||
|
|
||||||
|
floor, ceil, round
|
||||||
|
abs, sign, mod(n,m), xor
|
||||||
|
pow, exp, sqrt
|
||||||
|
cos, sin, tan
|
||||||
|
acos, asin, atan, atan2
|
||||||
|
random() rand(n) randint(n) randrange(a,b)
|
||||||
|
E, PI, PHI
|
||||||
|
|
||||||
|
And some utility functions which might help:
|
||||||
|
|
||||||
|
clamp(n,min,max)
|
||||||
|
mix(n,a,b) (lerp)
|
||||||
|
step(a,b)
|
||||||
|
smoothstep(min,max,n)
|
||||||
|
avg(m,n,a)
|
||||||
|
cosp, sinp (mapped to [0,1])
|
||||||
|
pixel(x,y) == 4*(y*w+h)
|
||||||
|
dist(x,y,a,b)
|
||||||
|
angle(x,y,a,b)
|
||||||
|
choice(array)
|
||||||
|
deg(radians), rad(degrees)
|
||||||
|
|
||||||
|
|
||||||
|
BEYOND BASIC COLORS
|
||||||
|
===================
|
||||||
|
|
||||||
|
Other weird effects are possible if you combine these color functions.
|
||||||
|
|
||||||
|
For instance, if you do hue(x+y) you'll get a rainbow. But remember, this is just
|
||||||
|
outputting a number between 0 and 15. So you can do hue(x+y) + 1 and get a different
|
||||||
|
cycle which does not really have anything to do with the rainbow, but looks cool.
|
||||||
|
|
||||||
|
|
||||||
|
HOW DRAWING WORKS IN THE ASCII TOOL
|
||||||
|
===================================
|
||||||
|
|
||||||
|
When you click and drag to draw a line, your mouse produces a series of points which
|
||||||
|
describe the line you tried to draw. But these points do not necessarily make a
|
||||||
|
continuous line - more like a series of dots, which it then draw lines between to make
|
||||||
|
a "line" or "brush stroke".
|
||||||
|
|
||||||
|
A line between two points is made by stamping the brush at regular intervals between the
|
||||||
|
points which, with these brushes, ends up filling the space in between so it looks like
|
||||||
|
you drew a continuous line.
|
||||||
|
|
||||||
|
This is why when you draw a line with a big brush, it smears the outer edges.. The stamps
|
||||||
|
happen right next to each other, so you wind up seeing mostly brush edges.
|
||||||
|
|
||||||
|
You can visualize this effect with the following shader:
|
||||||
|
|
||||||
|
lex.bg = mouse.x + mouse.y
|
||||||
|
|
||||||
|
Drawing strokes quickly, or slowly.
|
||||||
|
Make sure to make it animate to brush.
|
||||||
|
Results could look like this:
|
||||||
|
|
||||||
|
http://i.asdf.us/im/f9/1458658781640-ascii-bamboo.png
|
||||||
|
|
||||||
|
|
||||||
|
SAMPLE SHADERS
|
||||||
|
==============
|
||||||
|
|
||||||
|
You can see a list of example shaders here:
|
||||||
|
|
||||||
|
http://asdf.us/ascii/doc/shaderz.txt
|
||||||
|
|
||||||
|
If you make a cool shader and want to see it on the list, please get in touch!
|
||||||
|
You can find me on irc.jollo.org:9999 (ssl) in #sally, making color codes with my friends.
|
||||||
|
|
||||||
|
Thanks and have fun!
|
||||||
|
|
||||||
|
~ Bamboo, 22 Marzo 2016
|
||||||
|
|
||||||
|
|
16
doc/tips.txt
Normal file
16
doc/tips.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
asdf.us/ascii tips
|
||||||
|
==================
|
||||||
|
|
||||||
|
These keyboard commands work in brush mode (square, circle, cross):
|
||||||
|
|
||||||
|
[ brush smaller
|
||||||
|
] brush bigger
|
||||||
|
ctrl~click on brush erase cell
|
||||||
|
ctrl~click on canvas draw with bg color
|
||||||
|
shift~click on canvas draw line from last position
|
||||||
|
alt~click on canvas fill brush with sampled color
|
||||||
|
alt~shift~click on canvas copy canvas to brush
|
||||||
|
rightclick on palette set bg color (when drawing with a letter)
|
||||||
|
|
||||||
|
h/t timb for guide
|
||||||
|
|
BIN
fonts/fsex300-webfont.eot
Normal file
BIN
fonts/fsex300-webfont.eot
Normal file
Binary file not shown.
BIN
fonts/fsex300-webfont.eot?
Normal file
BIN
fonts/fsex300-webfont.eot?
Normal file
Binary file not shown.
6006
fonts/fsex300-webfont.svg
Normal file
6006
fonts/fsex300-webfont.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 1.1 MiB |
BIN
fonts/fsex300-webfont.ttf
Normal file
BIN
fonts/fsex300-webfont.ttf
Normal file
Binary file not shown.
BIN
fonts/fsex300-webfont.woff
Normal file
BIN
fonts/fsex300-webfont.woff
Normal file
Binary file not shown.
BIN
img/bucket.png
Normal file
BIN
img/bucket.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
img/dropper.gif
Normal file
BIN
img/dropper.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
img/gray-dither.gif
Normal file
BIN
img/gray-dither.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
166
index.html
Normal file
166
index.html
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>asciiblaster</title>
|
||||||
|
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=yes" />
|
||||||
|
<link rel="stylesheet" href="css/sally.css" type="text/css" charset="utf-8" />
|
||||||
|
<link rel="stylesheet" href="css/ak.css" type="text/css" charset="utf-8" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="loading panke">
|
||||||
|
|
||||||
|
<div id="goodies_rapper">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="workspace_rapper">
|
||||||
|
<div id="canvas_rapper" class="rapper"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="ui_rapper">
|
||||||
|
<div class="block" id="tools_block">
|
||||||
|
<div id="palette_rapper"></div>
|
||||||
|
<div id="secret_rapper">
|
||||||
|
<span id="experimental_palette_toggle">.</span>
|
||||||
|
<!-- <span id="nopaint_toggle">N</span> -->
|
||||||
|
</div>
|
||||||
|
<div id="letters_rapper"></div>
|
||||||
|
<div id="custom_rapper"></div>
|
||||||
|
</div>
|
||||||
|
<div id="brush_container" class="block">
|
||||||
|
<div id="brush_rapper">
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<span id="fg_checkbox" class="tool">x fg</span><br>
|
||||||
|
<span id="bg_checkbox" class="tool">x bg</span><br>
|
||||||
|
<span id="char_checkbox" class="tool">x char</span><br>
|
||||||
|
<br>
|
||||||
|
<span id="add_custom_el" class="tool">+ add</span>
|
||||||
|
<span id="mirror_x_checkbox" class="tool">_ mirror x</span><br>
|
||||||
|
<span id="mirror_y_checkbox" class="tool">_ mirror y</span><br>
|
||||||
|
<br>
|
||||||
|
<span id="undo_el" class="tool hidden">undo</span><br>
|
||||||
|
<span id="redo_el" class="tool hidden">redo</span><br>
|
||||||
|
</div>
|
||||||
|
<div id="tools_rapper" class="block">
|
||||||
|
<span id="square_el" class="tool">square</span><br>
|
||||||
|
<span id="circle_el" class="tool">circle</span><br>
|
||||||
|
<span id="cross_el" class="tool">cross</span><br>
|
||||||
|
<span id="text_el" class="tool">text</span><br>
|
||||||
|
<span id="fill_el" class="tool">fill</span><br>
|
||||||
|
<span id="select_el" class="tool">select</span><br>
|
||||||
|
<br>
|
||||||
|
<span id="rotate_el" class="tool">rotate</span><br>
|
||||||
|
<span id="scale_el" class="tool">scale</span><br>
|
||||||
|
<span id="translate_el" class="tool">translate</span><br>
|
||||||
|
<span id="slice_el" class="tool">slice</span><br>
|
||||||
|
|
||||||
|
<span id="grid_el" class="tool">_ grid</span>
|
||||||
|
<!-- <span id="rotate_checkbox" class="tool">_ rotate</span><br> -->
|
||||||
|
<span id="vertical_checkbox" class="tool">x vertical</span>
|
||||||
|
<!-- <span id="pixels_checkbox" class="tool">_ pixels</span><br> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="textarea_mode" style="float: left">
|
||||||
|
<div>
|
||||||
|
<span id="clear_el" class="tool">new</span>
|
||||||
|
<span id="save_el" class="tool">save</span>
|
||||||
|
<span id="load_el" class="tool">load</span>
|
||||||
|
<br>
|
||||||
|
<span id="shader_el" class="tool">shader</span>
|
||||||
|
<span id="webcam_el" class="tool">webcam</span>
|
||||||
|
<a id="doc_el" href="/asciiblaster/doc/" target="_blank">doc</a>
|
||||||
|
<a id="gallery_el" href="//asdf.us/im/gallery/?tag=ascii&limit=80" target="_blank">gallery</a>
|
||||||
|
<br>
|
||||||
|
<span id="advanced_checkbox" class="tool">_ advanced</span>
|
||||||
|
<br>
|
||||||
|
<span id="send_to_irc_el" class="tool">> send to IRC</span>
|
||||||
|
<br>
|
||||||
|
<div id="nopaint_rapper">
|
||||||
|
<br>
|
||||||
|
<span id="nopaint_no_el" class="tool">no</span><br>
|
||||||
|
<span id="nopaint_paint_el" class="tool">paint</span><br>
|
||||||
|
<span id="nopaint_pause_el" class="tool hidden">pause</span><br>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
brush: <span id="brush_w_el" class="ed">5</span> x <span id="brush_h_el" class="ed">5</span><br>
|
||||||
|
canvas: <span id="canvas_w_el" class="ed">100</span> x <span id="canvas_h_el" class="ed">30</span><br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="import_rapper">
|
||||||
|
<span id="format_el">ascii *irssi mirc ansi</span>
|
||||||
|
<span id="import_buttons">
|
||||||
|
<button id="import_button">import</button>
|
||||||
|
</span>
|
||||||
|
<div id="gallery_rapper">
|
||||||
|
<input id="username_input" type="text" placeholder="username">
|
||||||
|
<input id="upload_input" type="text" placeholder="uploaded url">
|
||||||
|
<button id="export_button">export</button>
|
||||||
|
<button id="save_button">save</button>
|
||||||
|
<button id="upload_button">upload</button>
|
||||||
|
</div><br>
|
||||||
|
<div id="cutoff_warning_el">colorcode is too wide for irc and is cutoff</div>
|
||||||
|
<textarea id="import_textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="shader_rapper">
|
||||||
|
<span id="animate_checkbox" class="tool">_ animate</span>
|
||||||
|
to <span id="shader_target_el">*canvas brush selection</span>
|
||||||
|
<span id="shader_fps_el" class="hidden faded"></span><br>
|
||||||
|
<textarea id="shader_textarea"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="webcam_rapper" class="transparent">
|
||||||
|
<span class="close" id="webcam_close">x</span>
|
||||||
|
<iframe id="webcam_iframe"></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="text" id="cursor_input">
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript-shader" id="demo_shader">
|
||||||
|
// lex.bg = hue((x+y*y+t/10)/20)
|
||||||
|
// lex.fg = colors.white
|
||||||
|
// lex.char = " "
|
||||||
|
// lex.opacity = 1
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script src="js/vendor/colorcode.js"></script>
|
||||||
|
<script src="js/vendor/text-encoder-lite.js"></script>
|
||||||
|
<script src="js/vendor/dataUriToBlob.js"></script>
|
||||||
|
<script src="js/vendor/FileSaver.js"></script>
|
||||||
|
<script src="js/vendor/oktween.js"></script>
|
||||||
|
|
||||||
|
<script src="js/util.js"></script>
|
||||||
|
<script src="js/png.js"></script>
|
||||||
|
<script src="js/unicode.js"></script>
|
||||||
|
<script src="js/color.js"></script>
|
||||||
|
<script src="js/dither.js"></script>
|
||||||
|
<script src="js/undo.js"></script>
|
||||||
|
<script src="js/clipboard.js"></script>
|
||||||
|
<script src="js/upload.js"></script>
|
||||||
|
<script src="js/user.js"></script>
|
||||||
|
|
||||||
|
<script src="js/lex.js"></script>
|
||||||
|
<script src="js/matrix.js"></script>
|
||||||
|
<script src="js/blit.js"></script>
|
||||||
|
<script src="js/tool.js"></script>
|
||||||
|
<script src="js/shader.js"></script>
|
||||||
|
<script src="js/draw.js"></script>
|
||||||
|
|
||||||
|
<script src="js/ui/brush.js"></script>
|
||||||
|
<script src="js/ui/canvas.js"></script>
|
||||||
|
<script src="js/ui/custom.js"></script>
|
||||||
|
<script src="js/ui/goodies.js"></script>
|
||||||
|
<script src="js/ui/keys.js"></script>
|
||||||
|
<script src="js/ui/controls.js"></script>
|
||||||
|
<script src="js/ui/palette.js"></script>
|
||||||
|
<script src="js/ui/letters.js"></script>
|
||||||
|
<script src="js/ui/selection.js"></script>
|
||||||
|
<script src="js/ui/transform.js"></script>
|
||||||
|
<script src="js/ui/nopaint.js"></script>
|
||||||
|
|
||||||
|
<script src="js/app.js"></script>
|
||||||
|
</html>
|
||||||
|
|
100
js/app.js
Normal file
100
js/app.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
var dragging = false
|
||||||
|
var drawing = false
|
||||||
|
var erasing = false
|
||||||
|
var selecting = false
|
||||||
|
var filling = false
|
||||||
|
var changed = false
|
||||||
|
var transforming = false
|
||||||
|
var mirror_x = false
|
||||||
|
var mirror_y = false
|
||||||
|
var focused
|
||||||
|
|
||||||
|
var canvas, tools, palette, controls, brush, mode
|
||||||
|
var current_tool, current_filetool, current_canvas
|
||||||
|
var mouse = { x: 0, y: 0 }
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
build()
|
||||||
|
bind()
|
||||||
|
clipboard.load_from_location()
|
||||||
|
}
|
||||||
|
function build () {
|
||||||
|
shader.init()
|
||||||
|
// shader.run(canvas)
|
||||||
|
shader.animate()
|
||||||
|
|
||||||
|
canvas.append(canvas_rapper)
|
||||||
|
brush.append(brush_rapper)
|
||||||
|
palette.append(palette_rapper)
|
||||||
|
letters.append(letters_rapper)
|
||||||
|
letters.repaint("Basic Latin")
|
||||||
|
|
||||||
|
controls.circle.focus()
|
||||||
|
// controls.shader.focus()
|
||||||
|
|
||||||
|
brush.bg = colors.red
|
||||||
|
brush.generate()
|
||||||
|
brush.build()
|
||||||
|
|
||||||
|
// controls.grid.use()
|
||||||
|
canvas.resize_rapper()
|
||||||
|
}
|
||||||
|
function bind () {
|
||||||
|
canvas.bind()
|
||||||
|
palette.bind()
|
||||||
|
letters.bind()
|
||||||
|
brush.bind()
|
||||||
|
controls.bind()
|
||||||
|
keys.bind()
|
||||||
|
clipboard.bind()
|
||||||
|
|
||||||
|
window.addEventListener('mouseup', function(e){
|
||||||
|
dragging = erasing = false
|
||||||
|
// if (current_filetool.name != 'shader' && current_filetool.name != 'load' && current_filetool.name != 'save' && is_desktop) {
|
||||||
|
// cursor_input.focus()
|
||||||
|
// }
|
||||||
|
|
||||||
|
var ae = document.activeElement
|
||||||
|
|
||||||
|
if (ae !== shader_textarea && ae !== import_textarea && ae !== username_input && ae !== upload_input) {
|
||||||
|
if (is_desktop) cursor_input.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selecting) {
|
||||||
|
selection.up(e)
|
||||||
|
}
|
||||||
|
else if (transforming) {
|
||||||
|
transform.up(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.addEventListener("touchend", function(){
|
||||||
|
if (current_tool.name === "text") {
|
||||||
|
if (is_desktop) cursor_input.focus()
|
||||||
|
}
|
||||||
|
dragging = false
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('mousedown', function(e){
|
||||||
|
// if (current_filetool.name != 'shader' && is_desktop) { cursor_input.focus() }
|
||||||
|
})
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function(){
|
||||||
|
if (is_desktop) { cursor_input.focus() }
|
||||||
|
document.body.classList.remove('loading')
|
||||||
|
})
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
// if (changed && !in_iframe()) return "You have edited this drawing."
|
||||||
|
}
|
||||||
|
|
||||||
|
function in_iframe () {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
105
js/blit.js
Normal file
105
js/blit.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
var blit = (function(){
|
||||||
|
var blit = {}
|
||||||
|
blit.and = blit.atop = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.getCell(u+x, v+y)
|
||||||
|
if (cell && lex.opacity > 0) {
|
||||||
|
cell.assign(lex)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.or = blit.under = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.getCell(u+x, v+y)
|
||||||
|
if (cell && cell.opacity == 0) {
|
||||||
|
cell.assign(lex)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// copy the region of A beginning at x,y into B
|
||||||
|
blit.copy_from = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.getCell(u+x, v+y)
|
||||||
|
if (cell) {
|
||||||
|
lex.assign(cell)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.copy_toroidal_from = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.get(u+x, v+y)
|
||||||
|
if (cell) {
|
||||||
|
lex.assign(cell)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.copy_to = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.getCell(u+x, v+y)
|
||||||
|
if (cell) {
|
||||||
|
cell.assign(lex)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.invert = function(A, B, x, y){
|
||||||
|
x = x || 0 ; y = y || 0
|
||||||
|
B.forEach(function(lex, u, v){
|
||||||
|
var cell = A.getCell(u+x, v+y)
|
||||||
|
if (cell && lex.opacity > 0) {
|
||||||
|
cell.fg = get_inverse(cell.fg)
|
||||||
|
cell.bg = get_inverse(cell.bg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var distance_rect = function(x, y, ratio){
|
||||||
|
return Math.sqrt((Math.pow(y * ratio, 2)) + Math.pow(x, 2))
|
||||||
|
}
|
||||||
|
var distance_square = function(x, y, ratio){
|
||||||
|
return Math.sqrt((Math.pow(y * ratio, 2)) + Math.pow(x * ratio, 2))
|
||||||
|
}
|
||||||
|
blit.circle = function(A, lex){
|
||||||
|
var hw = brush.w/2, hh = brush.h/2
|
||||||
|
var ratio, distance
|
||||||
|
|
||||||
|
if (brush.w === brush.h){
|
||||||
|
distance = distance_square
|
||||||
|
ratio = hw / hh * (brush.w === 3 || brush.w === 5 ? 1.2 : 1.05)
|
||||||
|
} else {
|
||||||
|
distance = distance_rect
|
||||||
|
ratio = hw / hh
|
||||||
|
}
|
||||||
|
|
||||||
|
A.forEach(function(lex,x,y) {
|
||||||
|
if (distance(x - hw + 0.5, y - hh + 0.5, ratio) > hw){
|
||||||
|
lex.clear()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.cross = function(A, lex){
|
||||||
|
A.forEach(function(lex,x,y) {
|
||||||
|
if ((x+y)%2) {
|
||||||
|
lex.clear()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.inverted_cross = function(A, lex){
|
||||||
|
// 1x1 brush should still draw something
|
||||||
|
if (A.w == 1 && A.h == 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
A.forEach(function(lex,x,y) {
|
||||||
|
if (!((x+y)%2)) {
|
||||||
|
lex.clear()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
blit.square = function(A, lex){
|
||||||
|
// i.e. no transparency
|
||||||
|
}
|
||||||
|
return blit
|
||||||
|
})()
|
330
js/clipboard.js
Normal file
330
js/clipboard.js
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
var clipboard = (function () {
|
||||||
|
|
||||||
|
var exports = {
|
||||||
|
format: "irssi",
|
||||||
|
importing: false,
|
||||||
|
visible: false,
|
||||||
|
canvas: document.createElement("canvas"),
|
||||||
|
canvas_r: document.createElement("canvas"),
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
// import_ascii.addEventListener("change", exports.setFormat("ascii"))
|
||||||
|
// import_irssi.addEventListener("change", exports.setFormat("irssi"))
|
||||||
|
// import_mirc.addEventListener("change", exports.setFormat("mirc"))
|
||||||
|
import_button.addEventListener("click", exports.import_colorcode)
|
||||||
|
export_button.addEventListener("click", exports.export_data)
|
||||||
|
save_button.addEventListener("click", exports.save_png)
|
||||||
|
upload_button.addEventListener("click", exports.upload_png)
|
||||||
|
import_textarea.addEventListener("focus", exports.focus)
|
||||||
|
import_textarea.addEventListener("blur", exports.blur)
|
||||||
|
import_textarea.addEventListener('paste', exports.paste)
|
||||||
|
// import_irssi.setAttribute("checked", true)
|
||||||
|
},
|
||||||
|
setFormat: function (name) {
|
||||||
|
return function () {
|
||||||
|
clipboard.format = name
|
||||||
|
if (! clipboard.importing) { clipboard.export_data() }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show: function () { import_rapper.style.display = "block"; clipboard.visible = true; changed = false },
|
||||||
|
hide: function () { import_rapper.style.display = "none"; clipboard.visible = false },
|
||||||
|
focus: function () {
|
||||||
|
if (! clipboard.importing) {
|
||||||
|
import_textarea.focus()
|
||||||
|
import_textarea.select()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
blur: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
import_mode: function () {
|
||||||
|
focus()
|
||||||
|
clipboard.importing = true
|
||||||
|
gallery_rapper.style.display = 'none'
|
||||||
|
format_el.style.display = 'none'
|
||||||
|
cutoff_warning_el.style.display = 'none'
|
||||||
|
import_buttons.style.display = "inline"
|
||||||
|
import_textarea.value = ""
|
||||||
|
},
|
||||||
|
export_mode: function () {
|
||||||
|
focus()
|
||||||
|
clipboard.importing = false
|
||||||
|
import_buttons.style.display = "none"
|
||||||
|
format_el.style.display = 'inline'
|
||||||
|
cutoff_warning_el.style.display = 'none'
|
||||||
|
gallery_rapper.style.display = 'inline'
|
||||||
|
clipboard.export_data()
|
||||||
|
},
|
||||||
|
|
||||||
|
paste: function (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
// images will come through as files
|
||||||
|
var types = toArray(e.clipboardData.types)
|
||||||
|
import_textarea.value = ""
|
||||||
|
types.forEach(function(type, i){
|
||||||
|
console.log(type)
|
||||||
|
// this can be text/plain or text/html..
|
||||||
|
if (type.match('text/plain')) {
|
||||||
|
import_textarea.value = e.clipboardData.getData(type)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error("unknown type!", item.type)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
import_colorcode: function (data, no_undo) {
|
||||||
|
if (data && data.preventDefault) {
|
||||||
|
data = import_textarea.value
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data = data || import_textarea.value
|
||||||
|
}
|
||||||
|
|
||||||
|
var irssi_style_regex = /^\s*\/exec -out printf ("%b" )?"/;
|
||||||
|
|
||||||
|
// turn irssi style into mirc style
|
||||||
|
if (data.match(irssi_style_regex)){
|
||||||
|
data = data.replace(/\\x03/gm, '\x03')
|
||||||
|
.replace(/(\\x..)+/gm, unicode.unescapeFromEscapedBytes)
|
||||||
|
.replace(/\\x5C/g, '\\')
|
||||||
|
.replace(/\\n/gm, '\n')
|
||||||
|
.replace(/\\`/gm, '`')
|
||||||
|
.replace(/\\"/gm, '"')
|
||||||
|
.replace(/\\\$/gm, '$')
|
||||||
|
.replace(irssi_style_regex, '')
|
||||||
|
.replace(/"\s*$/, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
// not a colorcode
|
||||||
|
if (!data.match(/\x03/))
|
||||||
|
return exports.import_text();
|
||||||
|
|
||||||
|
var json = colorcode.to_json(data, {fg:0, bg:1})
|
||||||
|
|
||||||
|
if (!no_undo) undo.new()
|
||||||
|
if (!no_undo) undo.save_rect(0,0, canvas.w, canvas.h)
|
||||||
|
if (json.w !== canvas.w || json.h !== canvas.h){
|
||||||
|
if (!no_undo) undo.save_size(canvas.w, canvas.h)
|
||||||
|
canvas.resize(json.w, json.h, true)
|
||||||
|
}
|
||||||
|
canvas.clear()
|
||||||
|
|
||||||
|
for (var y = 0, line; line = json.lines[y]; y++){
|
||||||
|
var row = canvas.aa[y]
|
||||||
|
for (var x = 0, char; char = line[x]; x++){
|
||||||
|
var lex = row[x]
|
||||||
|
lex.char = String.fromCharCode(char.value)
|
||||||
|
lex.fg = char.fg
|
||||||
|
lex.bg = char.bg
|
||||||
|
lex.opacity = 1
|
||||||
|
lex.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_filetool && current_filetool.blur()
|
||||||
|
},
|
||||||
|
|
||||||
|
import_text: function () {
|
||||||
|
var data = import_textarea.value
|
||||||
|
var lines = data.split("\n")
|
||||||
|
var width = lines.reduce(function(a,b){ console.log(a,b); return Math.max(a, b.length) }, 0)
|
||||||
|
var height = lines.length
|
||||||
|
if (width > canvas.max) {
|
||||||
|
return alert("input too wide")
|
||||||
|
}
|
||||||
|
if (height > canvas.max) {
|
||||||
|
return alert("input too tall")
|
||||||
|
}
|
||||||
|
undo.new()
|
||||||
|
undo.save_rect(0,0, canvas.w, canvas.h)
|
||||||
|
canvas.clear()
|
||||||
|
lines.forEach(function(line, y){
|
||||||
|
var row = canvas.aa[y]
|
||||||
|
if (! row) return
|
||||||
|
for (var x = 0; x < line.length; x++) {
|
||||||
|
var lex = row[x]
|
||||||
|
if (! lex) return
|
||||||
|
lex.char = line[x]
|
||||||
|
lex.fg = brush.bg
|
||||||
|
lex.opacity = 1
|
||||||
|
lex.build()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// TODO: some notion of a "selected" region which cuts/clones the underlying region
|
||||||
|
|
||||||
|
// var pasted_region = new Matrix (width, height, function(x,y){
|
||||||
|
// var lex = new Lex (x,y)
|
||||||
|
// lex.char = lines[y][x] || " "
|
||||||
|
// lex.build()
|
||||||
|
// return lex
|
||||||
|
// })
|
||||||
|
},
|
||||||
|
export_data: function () {
|
||||||
|
var output
|
||||||
|
// switch (clipboard.format) {
|
||||||
|
switch (controls.save_format.value) {
|
||||||
|
case 'ascii':
|
||||||
|
output = canvas.ascii()
|
||||||
|
break
|
||||||
|
case 'mirc':
|
||||||
|
output = canvas.mirc({cutoff: 400})
|
||||||
|
break
|
||||||
|
case 'irssi':
|
||||||
|
output = canvas.irssi({cutoff: 400})
|
||||||
|
break
|
||||||
|
case 'ansi':
|
||||||
|
output = canvas.ansi()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (output.cutoff){
|
||||||
|
cutoff_warning_el.style.display = 'block'
|
||||||
|
} else {
|
||||||
|
cutoff_warning_el.style.display = 'none'
|
||||||
|
}
|
||||||
|
import_textarea.value = output
|
||||||
|
clipboard.focus()
|
||||||
|
return output
|
||||||
|
},
|
||||||
|
|
||||||
|
rotate_canvas: function(){
|
||||||
|
var cr = clipboard.canvas_r, c = clipboard.canvas
|
||||||
|
cr.width = c.height
|
||||||
|
cr.height = c.width
|
||||||
|
var ctx = cr.getContext('2d')
|
||||||
|
ctx.resetTransform()
|
||||||
|
ctx.translate(0, cr.height)
|
||||||
|
ctx.rotate(-Math.PI / 2)
|
||||||
|
ctx.drawImage(c, 0, 0)
|
||||||
|
return cr
|
||||||
|
},
|
||||||
|
|
||||||
|
export_canvas: function (done_fn) {
|
||||||
|
var opts = {
|
||||||
|
palette: 'mirc',
|
||||||
|
font: canvas.pixels ? 'fixedsys_8x8' : 'fixedsys_8x15',
|
||||||
|
fg: 0,
|
||||||
|
bg: 1,
|
||||||
|
canvas: clipboard.canvas
|
||||||
|
}
|
||||||
|
opts.done = function(){
|
||||||
|
var c = canvas.rotated ? clipboard.rotate_canvas() : clipboard.canvas
|
||||||
|
if (done_fn) done_fn(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = Date.now();
|
||||||
|
colorcode.to_canvas(canvas.mirc(), opts)
|
||||||
|
var total = Date.now() - start;
|
||||||
|
console.log("took " + total)
|
||||||
|
},
|
||||||
|
|
||||||
|
filename: function () {
|
||||||
|
return [ +new Date, "ascii", user.username ].join("-")
|
||||||
|
},
|
||||||
|
|
||||||
|
save_png: function () {
|
||||||
|
var save_fn = function(canvas_out){
|
||||||
|
var filename = clipboard.filename() + ".png"
|
||||||
|
var blob = PNG.canvas_to_blob_with_colorcode(canvas_out, canvas.mirc())
|
||||||
|
saveAs(blob, filename);
|
||||||
|
}
|
||||||
|
clipboard.export_canvas(save_fn)
|
||||||
|
},
|
||||||
|
|
||||||
|
upload_png: function () {
|
||||||
|
var upload_fn = function(canvas_out){
|
||||||
|
var blob = PNG.canvas_to_blob_with_colorcode(canvas_out, canvas.mirc())
|
||||||
|
var filename = clipboard.filename()
|
||||||
|
var tag = 'ascii'
|
||||||
|
upload(blob, filename, tag, canvas.mirc())
|
||||||
|
}
|
||||||
|
clipboard.export_canvas(upload_fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// http...?a=1&b=2&b=3 -> {a: '1', b: ['2', '3']}
|
||||||
|
function parse_url_search_params(url){
|
||||||
|
var params = {}
|
||||||
|
url = url.split('?')
|
||||||
|
if (url.length < 2) return params
|
||||||
|
|
||||||
|
var search = url[1].split('&')
|
||||||
|
for (var i = 0, pair; pair = search[i]; i++){
|
||||||
|
pair = pair.split('=')
|
||||||
|
if (pair.length < 2) continue
|
||||||
|
var key = pair[0]
|
||||||
|
var val = pair[1]
|
||||||
|
if (key in params){
|
||||||
|
if (typeof params[key] === 'string'){
|
||||||
|
params[key] = [params[key], val]
|
||||||
|
}
|
||||||
|
else params[key].push(val)
|
||||||
|
}
|
||||||
|
else params[key] = val
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_filetype(txt){
|
||||||
|
txt = txt.split('.')
|
||||||
|
return txt[txt.length - 1].toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetch_url(url, f, type){
|
||||||
|
type = type || 'arraybuffer'
|
||||||
|
url = "/cgi-bin/proxy?" + url
|
||||||
|
//url = "http://198.199.72.134/cors/" + url
|
||||||
|
var xhr = new XMLHttpRequest()
|
||||||
|
xhr.open('GET', url, true)
|
||||||
|
xhr.responseType = type
|
||||||
|
xhr.addEventListener('load', function(){ f(xhr.response) })
|
||||||
|
xhr.send()
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_text(txt){
|
||||||
|
clipboard.import_colorcode(txt, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_png(buf){
|
||||||
|
var chunks = PNG.decode(buf)
|
||||||
|
if (!chunks) return
|
||||||
|
var itxt_chunks = []
|
||||||
|
for (var i=0, c; c=chunks[i]; i++){
|
||||||
|
if (c.type !== 'iTXt') continue
|
||||||
|
var itxt = PNG.decode_itxt_chunk(c)
|
||||||
|
if (!itxt.keyword || itxt.keyword !== 'colorcode') continue
|
||||||
|
clipboard.import_colorcode(itxt.data, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sally_url_convert(url){
|
||||||
|
var png_regex = /^https?:\/\/jollo\.org\/den\/sallies\/([0-9]+)\/([^.]+)\.png$/
|
||||||
|
var matches = url.match(png_regex)
|
||||||
|
if (!matches) return url
|
||||||
|
return 'http://jollo.org/den/sallies/' + matches[1] + '/raw-' + matches[2] + '?.txt'
|
||||||
|
// txt suffix to force asdf proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.load_from_location = function(){
|
||||||
|
var params = parse_url_search_params(window.location + '')
|
||||||
|
if (!params.url) return
|
||||||
|
var url = params.url
|
||||||
|
url = sally_url_convert(url)
|
||||||
|
var type = get_filetype(url)
|
||||||
|
switch (type){
|
||||||
|
case 'txt':
|
||||||
|
fetch_url(url, load_text, 'text')
|
||||||
|
break
|
||||||
|
case 'png':
|
||||||
|
fetch_url(url, load_png)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return exports
|
||||||
|
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
106
js/color.js
Normal file
106
js/color.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
var fillColor = 1 // black
|
||||||
|
|
||||||
|
var color_names = ("white black dark-blue green red dark-red purple orange " +
|
||||||
|
"yellow lime teal cyan blue magenta dark-gray light-gray").split(" ");
|
||||||
|
|
||||||
|
var all_color_hue_order = "dark-red red orange yellow lime green teal cyan blue dark-blue purple magenta black dark-gray light-gray white".split(" ");
|
||||||
|
var all_color_inv_order = "cyan teal blue dark-blue purple magenta dark-red red orange yellow lime green white light-gray dark-gray black".split(" ");
|
||||||
|
var color_hue_order = "dark-red red orange yellow lime cyan teal blue dark-blue purple magenta".split(" ");
|
||||||
|
var color_inv_order = "cyan teal blue dark-blue purple magenta dark-red red orange yellow lime green".split(" ");
|
||||||
|
var gray_names = ("black dark-gray light-gray white").split(" ")
|
||||||
|
|
||||||
|
var fire_names = ("black dark-red red orange yellow white cyan").split(" ")
|
||||||
|
var red_names = ("black dark-red red").split(" ")
|
||||||
|
var yellow_names = ("black orange yellow white").split(" ")
|
||||||
|
var green_names = ("teal green lime").split(" ")
|
||||||
|
var blue_names = ("black dark-blue blue").split(" ")
|
||||||
|
var purple_names = ("dark-blue purple magenta red").split(" ")
|
||||||
|
var dark_gray_names = ("black dark-blue teal dark-gray light-gray white").split(" ")
|
||||||
|
var color_alphabet = "abcdefghijklmnop";
|
||||||
|
var colors = {}
|
||||||
|
color_names.forEach(function(name, i){
|
||||||
|
colors[name.replace("-", "")] = i
|
||||||
|
colors[name] = i
|
||||||
|
})
|
||||||
|
colors.brown = 5
|
||||||
|
|
||||||
|
function get_inverse (n) { return colors[all_color_inv_order.indexOf(color_names[n])] }
|
||||||
|
|
||||||
|
function mirc_color (n) { return mod(n, 16)|0 }
|
||||||
|
function mirc_color_reverse (n) { return mod(-(n+1), 16)|0 }
|
||||||
|
function all_hue (n) { return colors[all_color_hue_order[mod(n, 16)|0]] }
|
||||||
|
function all_inv_hue (n) { return colors[all_color_inv_order[mod(n, 16)|0]] }
|
||||||
|
function hue (n) { return colors[color_hue_order[mod(n, 11)|0]] }
|
||||||
|
function rand_hue () { return colors[color_hue_order[randint(11)]] }
|
||||||
|
function rand_gray () { return colors[gray_names[randint(4)]] }
|
||||||
|
function inv_hue (n) { return colors[color_inv_order[mod(n, 11)|0]] }
|
||||||
|
function gray (n) { return colors[gray_names[mod(n, 4)|0]] }
|
||||||
|
function fire (n) { return colors[fire_names[mod(n, 7)|0]] }
|
||||||
|
function red (n) { return colors[red_names[mod(n, 3)|0]] }
|
||||||
|
function yellow (n) { return colors[yellow_names[mod(n, 4)|0]] }
|
||||||
|
function green (n) { return colors[green_names[mod(n, 3)|0]] }
|
||||||
|
function blue (n) { return colors[blue_names[mod(n, 3)|0]] }
|
||||||
|
function purple (n) { return colors[purple_names[mod(n, 4)|0]] }
|
||||||
|
function dark_gray (n) { return colors[dark_gray_names[mod(n, 4)|0]] }
|
||||||
|
|
||||||
|
var css_lookup = {
|
||||||
|
'rgb(255, 255, 255)': 'A',
|
||||||
|
'rgb(0, 0, 0)': 'B',
|
||||||
|
'rgb(0, 0, 127)': 'C',
|
||||||
|
'rgb(0, 147, 0)': 'D',
|
||||||
|
'red': 'E',
|
||||||
|
'rgb(127, 0, 0)': 'F',
|
||||||
|
'rgb(156, 0, 156)': 'G',
|
||||||
|
'rgb(252, 127, 0)': 'H',
|
||||||
|
'rgb(255, 255, 0)': 'I',
|
||||||
|
'rgb(0, 252, 0)': 'J',
|
||||||
|
'rgb(0, 147, 147)': 'K',
|
||||||
|
'rgb(0, 255, 255)': 'L',
|
||||||
|
'rgb(0, 0, 252)': 'M',
|
||||||
|
'rgb(255, 0, 255)': 'N',
|
||||||
|
'rgb(127, 127, 127)': 'O',
|
||||||
|
'rgb(210, 210, 210)': 'P',
|
||||||
|
};
|
||||||
|
var css_reverse_lookup = {}
|
||||||
|
Object.keys(css_lookup).forEach(function(color){
|
||||||
|
css_reverse_lookup[ css_lookup[color].charCodeAt(0) - 65 ] = color
|
||||||
|
})
|
||||||
|
|
||||||
|
var ansi_fg = [
|
||||||
|
97, // white
|
||||||
|
30, // black
|
||||||
|
34, // dark blue
|
||||||
|
32, // green
|
||||||
|
91, // light red
|
||||||
|
31, // dark red
|
||||||
|
35, // purple
|
||||||
|
33, // "dark yellow" (orange?)
|
||||||
|
93, // "light yellow"
|
||||||
|
92, // light green
|
||||||
|
36, // cyan (teal?)
|
||||||
|
96, // light cyan
|
||||||
|
94, // light blue
|
||||||
|
95, // light magenta
|
||||||
|
90, // dark gray
|
||||||
|
37, // light gray
|
||||||
|
]
|
||||||
|
|
||||||
|
var ansi_bg = [
|
||||||
|
107, // white
|
||||||
|
40, // black
|
||||||
|
44, // dark blue
|
||||||
|
42, // green
|
||||||
|
101, // light red
|
||||||
|
41, // dark red
|
||||||
|
45, // purple
|
||||||
|
43, // yellow (orange)
|
||||||
|
103, // light yellow
|
||||||
|
102, // light green
|
||||||
|
46, // cyan (teal?)
|
||||||
|
106, // light cyan
|
||||||
|
104, // light blue
|
||||||
|
105, // light magenta
|
||||||
|
100, // dark gray
|
||||||
|
47, // light gray
|
||||||
|
]
|
10
js/dither.js
Normal file
10
js/dither.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
var dither = {
|
||||||
|
aa: '▓▒░ ',
|
||||||
|
a: '▓',
|
||||||
|
b: '▒',
|
||||||
|
c: '░',
|
||||||
|
d: ' ',
|
||||||
|
p: function(n){
|
||||||
|
return dither.aa[Math.floor(Math.abs(n) % 4)]
|
||||||
|
}
|
||||||
|
}
|
221
js/draw.js
Normal file
221
js/draw.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
|
||||||
|
var draw = (function(){
|
||||||
|
|
||||||
|
var last_point = [0,0]
|
||||||
|
|
||||||
|
function down (e, lex, point) {
|
||||||
|
var w = canvas.w, h = canvas.h
|
||||||
|
erasing = (e.which == "3" || e.ctrlKey)
|
||||||
|
changed = true
|
||||||
|
if (e.shiftKey) {
|
||||||
|
line (lex, last_point, point, erasing)
|
||||||
|
if (mirror_x) {
|
||||||
|
line(lex, [w-last_point[0], last_point[1]], [w-point[0], point[1]], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_y) {
|
||||||
|
line(lex, [last_point[0], h-last_point[1]], [point[0], h-point[1]], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_x && mirror_y) {
|
||||||
|
line(lex, [w-last_point[0], h-last_point[1]], [w-point[0], h-point[1]], erasing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stamp (canvas, brush, point[0], point[1], erasing)
|
||||||
|
if (mirror_x) {
|
||||||
|
stamp (canvas, brush, w-point[0], point[1], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_y) {
|
||||||
|
stamp (canvas, brush, point[0], h-point[1], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_x && mirror_y) {
|
||||||
|
stamp (canvas, brush, w-point[0], h-point[1], erasing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_point[0] = point[0]
|
||||||
|
last_point[1] = point[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_last_point (e, point) {
|
||||||
|
last_point[0] = point[0]
|
||||||
|
last_point[1] = point[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
function move (e, lex, point) {
|
||||||
|
var w = canvas.w, h = canvas.h
|
||||||
|
line(lex, last_point, point, erasing)
|
||||||
|
if (mirror_x) {
|
||||||
|
line(lex, [w-last_point[0], last_point[1]], [w-point[0], point[1]], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_y) {
|
||||||
|
line(lex, [last_point[0], h-last_point[1]], [point[0], h-point[1]], erasing)
|
||||||
|
}
|
||||||
|
if (mirror_x && mirror_y) {
|
||||||
|
line(lex, [w-last_point[0], h-last_point[1]], [w-point[0], h-point[1]], erasing)
|
||||||
|
}
|
||||||
|
|
||||||
|
last_point[0] = point[0]
|
||||||
|
last_point[1] = point[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
function move_toroidal (e, lex, point) {
|
||||||
|
var w = canvas.w, h = canvas.h
|
||||||
|
var src_x_quantile = quantile( last_point[0], w )
|
||||||
|
var src_y_quantile = quantile( last_point[1], h )
|
||||||
|
var dst_x_quantile = quantile( point[0], w )
|
||||||
|
var dst_y_quantile = quantile( point[1], h )
|
||||||
|
var src_x_mod = mod( last_point[0], w )
|
||||||
|
var src_y_mod = mod( last_point[1], h )
|
||||||
|
var dst_x_mod = mod( point[0], w )
|
||||||
|
var dst_y_mod = mod( point[1], h )
|
||||||
|
// if we've moved across the edge of the board, draw two lines
|
||||||
|
if (src_x_quantile != dst_x_quantile || src_y_quantile != dst_y_quantile) {
|
||||||
|
var xa, ya
|
||||||
|
if (src_x_quantile < dst_x_quantile) {
|
||||||
|
xa = [
|
||||||
|
[src_x_mod, dst_x_mod + w],
|
||||||
|
[src_x_mod-w, dst_x_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else if (src_x_quantile == dst_x_quantile) {
|
||||||
|
xa = [
|
||||||
|
[src_x_mod, dst_x_mod],
|
||||||
|
[src_x_mod, dst_x_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xa = [
|
||||||
|
[src_x_mod, dst_x_mod-w],
|
||||||
|
[src_x_mod+w, dst_x_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_y_quantile < dst_y_quantile) {
|
||||||
|
ya = [
|
||||||
|
[src_y_mod, dst_y_mod + h],
|
||||||
|
[src_y_mod-h, dst_y_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else if (src_y_quantile == dst_y_quantile) {
|
||||||
|
ya = [
|
||||||
|
[src_y_mod, dst_y_mod],
|
||||||
|
[src_y_mod, dst_y_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ya = [
|
||||||
|
[src_y_mod, dst_y_mod-h],
|
||||||
|
[src_y_mod+h, dst_y_mod],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
line(lex, [ xa[0][0], ya[0][0] ], [ xa[0][1], ya[0][1] ], erasing)
|
||||||
|
line(lex, [ xa[1][0], ya[1][0] ], [ xa[1][1], ya[1][1] ], erasing)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var x_a = mod( last_point[0], w )
|
||||||
|
var y_a = mod( last_point[1], h )
|
||||||
|
var x_b = mod( point[0], w )
|
||||||
|
var y_b = mod( point[1], h )
|
||||||
|
var last_point_mod = [x_b, y_b], point_mod = [x_a, y_a]
|
||||||
|
line(lex, last_point_mod, point_mod, erasing)
|
||||||
|
// if (mirror_x) {
|
||||||
|
// line(lex, [w-last_point_mod[0], last_point_mod[1]], [w-point_mod[0], point_mod[1]], erasing)
|
||||||
|
// }
|
||||||
|
// if (mirror_y) {
|
||||||
|
// line(lex, [last_point_mod[0], h-last_point_mod[1]], [point_mod[0], h-point_mod[1]], erasing)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
last_point[0] = point[0]
|
||||||
|
last_point[1] = point[1]
|
||||||
|
// y = point.y
|
||||||
|
}
|
||||||
|
|
||||||
|
function point (lex, x, y, erasing) {
|
||||||
|
stamp (canvas, brush, x, y, erasing)
|
||||||
|
}
|
||||||
|
|
||||||
|
function line (lex, a, b, erasing) {
|
||||||
|
var len = dist(a[0], a[1], b[0], b[1])
|
||||||
|
var bw = 1
|
||||||
|
var x, y, i;
|
||||||
|
for (var i = 0; i <= len; i += bw) {
|
||||||
|
x = lerp(i / len, a[0], b[0])
|
||||||
|
y = lerp(i / len, a[1], b[1])
|
||||||
|
stamp (canvas, brush, x, y, erasing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stamp (canvas, brush, x, y, erasing) {
|
||||||
|
var hh = brush.w/2|0
|
||||||
|
brush.forEach(function(lex, s, t){
|
||||||
|
s = round( s + x-hh )
|
||||||
|
t = round( t + y-hh )
|
||||||
|
if (s >= 0 && s < canvas.w && t >= 0 && t < canvas.h) {
|
||||||
|
if (lex.opacity === 0 && lex.char === ' ') return;
|
||||||
|
var aa = canvas.aa[t][s]
|
||||||
|
undo.save_lex(s, t, aa)
|
||||||
|
if (erasing) {
|
||||||
|
aa.erase(lex)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
aa.stamp(lex, brush)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function fill (lex, x, y) {
|
||||||
|
var q = [ [x,y] ]
|
||||||
|
var aa = canvas.aa
|
||||||
|
var target = aa[y][x].clone()
|
||||||
|
var n, w = 0, e = 0, j = 0
|
||||||
|
var kk = 0
|
||||||
|
// gets into a weird infinite loop if we don't break here.. :\
|
||||||
|
if (target.eq(lex)) { return }
|
||||||
|
LOOP: while (q.length) {
|
||||||
|
n = q.shift()
|
||||||
|
if (aa[n[1]][n[0]].ne(target)) {
|
||||||
|
continue LOOP
|
||||||
|
}
|
||||||
|
w = e = n[0]
|
||||||
|
j = n[1]
|
||||||
|
WEST: while (w > 0) {
|
||||||
|
if (aa[j][w-1].eq(target)) {
|
||||||
|
w = w-1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break WEST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EAST: while (e < canvas.w-1) {
|
||||||
|
if (aa[j][e+1].eq(target)) {
|
||||||
|
e = e+1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break EAST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = w; i <= e; i++) {
|
||||||
|
undo.save_lex(i, j, aa[j][i])
|
||||||
|
aa[j][i].assign(lex)
|
||||||
|
if (j > 0 && aa[j-1][i].eq(target)) {
|
||||||
|
q.push([ i, j-1 ])
|
||||||
|
}
|
||||||
|
if (j < canvas.h-1 && aa[j+1][i].eq(target)) {
|
||||||
|
q.push([ i, j+1 ])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var draw = {}
|
||||||
|
draw.down = down
|
||||||
|
draw.set_last_point = set_last_point
|
||||||
|
draw.move = move
|
||||||
|
draw.move_toroidal = move_toroidal
|
||||||
|
draw.stamp = stamp
|
||||||
|
draw.line = line
|
||||||
|
draw.point = point
|
||||||
|
draw.fill = fill
|
||||||
|
return draw
|
||||||
|
|
||||||
|
})()
|
138
js/lex.js
Normal file
138
js/lex.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
function Lex (x,y) {
|
||||||
|
if (typeof x == "number") {
|
||||||
|
this.y = y
|
||||||
|
this.x = x
|
||||||
|
this.span = document.createElement("span")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.span = x
|
||||||
|
}
|
||||||
|
this.fg = colors.white
|
||||||
|
this.bg = colors.black
|
||||||
|
this.char = " "
|
||||||
|
this.opacity = 1
|
||||||
|
this.focused = false
|
||||||
|
}
|
||||||
|
Lex.prototype.build = function(){
|
||||||
|
if (isNaN(this.bg) || this.bg == Infinity || this.bg == -Infinity) this.bg = colors.black
|
||||||
|
if (isNaN(this.fg) || this.fg == Infinity || this.fg == -Infinity) this.fg = colors.black
|
||||||
|
this.span.className = this.css()
|
||||||
|
this.span.innerHTML = this.html()
|
||||||
|
}
|
||||||
|
Lex.prototype.css = function(){
|
||||||
|
return (
|
||||||
|
this.focused ?
|
||||||
|
"focused " : ""
|
||||||
|
) + (
|
||||||
|
this.opacity === 0 ?
|
||||||
|
"transparent f" + color_alphabet[modi(this.fg,16)] :
|
||||||
|
"f" + color_alphabet[modi(this.fg,16)] + " b" + color_alphabet[modi(this.bg,16)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Lex.prototype.html = function(){
|
||||||
|
return this.char == " " ? " " : this.char || " "
|
||||||
|
}
|
||||||
|
Lex.prototype.read = function(){
|
||||||
|
this.char = this.span.innerHTML
|
||||||
|
return this.char
|
||||||
|
}
|
||||||
|
Lex.prototype.ascii = function(){
|
||||||
|
return this.char || " "
|
||||||
|
}
|
||||||
|
Lex.prototype.sanitize = function(){
|
||||||
|
switch (this.char) {
|
||||||
|
// case "%": return "%"
|
||||||
|
case undefined:
|
||||||
|
case "": return " "
|
||||||
|
default: return this.char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fgOnly = false
|
||||||
|
Lex.prototype.mirc = function(){
|
||||||
|
var char = this.char || " "
|
||||||
|
if (fgOnly) {
|
||||||
|
return "\x03" + (this.fg&15) + char
|
||||||
|
}
|
||||||
|
if ((this.bg&15) < 10 && ! isNaN(parseInt(char))) {
|
||||||
|
return "\x03" + (this.fg&15) + ",0" + (this.bg&15) + char
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "\x03" + (this.fg&15) + "," + (this.bg&15) + char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lex.prototype.ansi = function(){
|
||||||
|
var fg = ansi_fg[ this.fg&15 ]
|
||||||
|
var bg = ansi_bg[ this.bg&15 ]
|
||||||
|
var c = this.sanitize()
|
||||||
|
if (c == "\\") c = "\\\\"
|
||||||
|
if (c == '"') c = '\\"'
|
||||||
|
return "\\e[" + fg + ";" + bg + "m" + c
|
||||||
|
}
|
||||||
|
Lex.prototype.assign = function (lex){
|
||||||
|
this.fg = lex.fg
|
||||||
|
this.bg = lex.bg
|
||||||
|
this.char = lex.char
|
||||||
|
this.opacity = lex.opacity
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
|
Lex.prototype.stamp = function (lex, brush){
|
||||||
|
if (brush.draw_fg) this.fg = lex.fg
|
||||||
|
if (brush.draw_bg && lex.opacity > 0) this.bg = lex.bg
|
||||||
|
if (brush.draw_char) this.char = lex.char
|
||||||
|
this.opacity = 1
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
|
Lex.prototype.clone = function () {
|
||||||
|
var lex = new Lex (0,0)
|
||||||
|
lex.assign(this)
|
||||||
|
return lex
|
||||||
|
}
|
||||||
|
Lex.prototype.erase = function (){
|
||||||
|
this.fg = fillColor
|
||||||
|
this.bg = fillColor
|
||||||
|
this.char = " "
|
||||||
|
this.opacity = 1
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
|
Lex.prototype.eq = function(lex){
|
||||||
|
return lex && this.fg == lex.fg && this.bg == lex.bg && this.char == lex.char
|
||||||
|
}
|
||||||
|
Lex.prototype.eqColor = function(lex){
|
||||||
|
return lex && this.fg == lex.fg && this.bg == lex.bg
|
||||||
|
}
|
||||||
|
Lex.prototype.ne = function(lex){
|
||||||
|
return ! this.eq(lex)
|
||||||
|
}
|
||||||
|
Lex.prototype.clear = function(){
|
||||||
|
this.bg = colors.black
|
||||||
|
this.fg = 0
|
||||||
|
this.char = " "
|
||||||
|
this.opacity = 0
|
||||||
|
this.build()
|
||||||
|
}
|
||||||
|
Lex.prototype.isClear = function(){
|
||||||
|
return this.bg == 1 && this.fg == 0 && this.char == " "
|
||||||
|
}
|
||||||
|
Lex.prototype.focus = function(){
|
||||||
|
if (focused) focused.blur()
|
||||||
|
this.span.classList.add('focused')
|
||||||
|
this.focused = true
|
||||||
|
focused = this
|
||||||
|
}
|
||||||
|
Lex.prototype.blur = function(){
|
||||||
|
focused = null
|
||||||
|
this.span && this.span.classList.remove('focused')
|
||||||
|
this.focused = false
|
||||||
|
this.onBlur && this.onBlur()
|
||||||
|
}
|
||||||
|
Lex.prototype.demolish = function(){
|
||||||
|
if (this.span.parentNode) { this.span.parentNode.removeChild(this.span) }
|
||||||
|
this.span = null
|
||||||
|
}
|
||||||
|
Lex.prototype.key = function(char, keyCode) {
|
||||||
|
if (! char) { return }
|
||||||
|
this.char = char
|
||||||
|
this.fg = brush.fg
|
||||||
|
this.build()
|
||||||
|
return true
|
||||||
|
}
|
321
js/matrix.js
Normal file
321
js/matrix.js
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
function Matrix (w,h,f){
|
||||||
|
this.x = 0
|
||||||
|
this.y = 0
|
||||||
|
this.w = w
|
||||||
|
this.h = h
|
||||||
|
this.f = f
|
||||||
|
this.focus_x = 0
|
||||||
|
this.focus_y = 0
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
Matrix.prototype.initialize = function(f){
|
||||||
|
var w = this.w || 1, h = this.h || 1, f = f || this.f
|
||||||
|
var aa = new Array (h)
|
||||||
|
for (var y = 0; y < h; y++) {
|
||||||
|
aa[y] = new Array (w)
|
||||||
|
for (var x = 0; x < w; x++) {
|
||||||
|
aa[y][x] = f(x,y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.aa = aa
|
||||||
|
}
|
||||||
|
Matrix.prototype.rebuild = function (){
|
||||||
|
this.demolish()
|
||||||
|
this.initialize()
|
||||||
|
this.append()
|
||||||
|
this.bind()
|
||||||
|
this.generate && this.generate()
|
||||||
|
this.focus_clamp()
|
||||||
|
check_if_lost_focus()
|
||||||
|
}
|
||||||
|
Matrix.prototype.clone = function () {
|
||||||
|
var base = this
|
||||||
|
var clone = new Matrix(this.w, this.h, function(x,y){
|
||||||
|
return base.getCell(x,y).clone()
|
||||||
|
})
|
||||||
|
clone.f = this.f
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
Matrix.prototype.assign = function (mat) {
|
||||||
|
var base = this
|
||||||
|
this.demolish()
|
||||||
|
this.w = mat.w
|
||||||
|
this.h = mat.h
|
||||||
|
// this.f = function(){}
|
||||||
|
this.initialize(function(x,y){
|
||||||
|
var el = mat.getCell(x,y).clone()
|
||||||
|
el.build()
|
||||||
|
return el
|
||||||
|
})
|
||||||
|
this.append()
|
||||||
|
this.bind()
|
||||||
|
check_if_lost_focus()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix.prototype.bind = function () {}
|
||||||
|
Matrix.prototype.demolish = function (){
|
||||||
|
this.forEach(function(lex){
|
||||||
|
lex.demolish()
|
||||||
|
})
|
||||||
|
while (this.rapper && this.rapper.firstChild) {
|
||||||
|
this.rapper.removeChild(this.rapper.firstChild);
|
||||||
|
}
|
||||||
|
this.aa.forEach(function(row){
|
||||||
|
row.length = 0
|
||||||
|
})
|
||||||
|
this.aa.length = 0
|
||||||
|
}
|
||||||
|
Matrix.prototype.forEach = function(f){
|
||||||
|
this.aa.forEach(function(row, y){
|
||||||
|
row.forEach(function(lex, x){
|
||||||
|
f(lex, x, y)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Matrix.prototype.focus_clamp = function(){
|
||||||
|
this.focus_x = clamp(this.focus_x, 0, this.w - 1)
|
||||||
|
this.focus_y = clamp(this.focus_y, 0, this.h - 1)
|
||||||
|
}
|
||||||
|
Matrix.prototype.focus_add = function(x, y){
|
||||||
|
this.focus(this.focus_x + x, this.focus_y + y)
|
||||||
|
}
|
||||||
|
Matrix.prototype.focus = function(x, y){
|
||||||
|
if (x === undefined) x = this.focus_x
|
||||||
|
if (y === undefined) y = this.focus_y
|
||||||
|
x = mod(x, this.w)
|
||||||
|
y = mod(y, this.h)
|
||||||
|
this.focus_x = x
|
||||||
|
this.focus_y = y
|
||||||
|
|
||||||
|
//focused_input = this
|
||||||
|
this.aa[y][x].focus()
|
||||||
|
}
|
||||||
|
Matrix.prototype.focusLex = function(y,x){
|
||||||
|
if (x < 0) {
|
||||||
|
y -= 1
|
||||||
|
}
|
||||||
|
if (x > this.aa[0].length) {
|
||||||
|
y += 1
|
||||||
|
}
|
||||||
|
this.aa[mod(y,this.h)][mod(x,this.w)].focus()
|
||||||
|
}
|
||||||
|
Matrix.prototype.clear = function(){
|
||||||
|
this.forEach(function(lex,x,y){ lex.clear() })
|
||||||
|
}
|
||||||
|
Matrix.prototype.erase = function(){
|
||||||
|
this.forEach(function(lex,x,y){ lex.erase() })
|
||||||
|
}
|
||||||
|
Matrix.prototype.fill = function(lex){
|
||||||
|
this.fg = lex.fg
|
||||||
|
this.bg = lex.bg
|
||||||
|
this.char = lex.char
|
||||||
|
this.opacity = lex.opacity
|
||||||
|
this.forEach(function(el,x,y){
|
||||||
|
el.assign(lex)
|
||||||
|
el.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix.prototype.build = function(){
|
||||||
|
this.forEach(function(lex,x,y){
|
||||||
|
lex.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Matrix.prototype.append = function(rapper){
|
||||||
|
rapper = this.rapper = rapper || this.rapper
|
||||||
|
if (! this.rapper) return
|
||||||
|
this.aa.forEach(function(row, y){
|
||||||
|
var div = document.createElement("div")
|
||||||
|
row.forEach(function(lex, x) {
|
||||||
|
div.appendChild(lex.span)
|
||||||
|
})
|
||||||
|
rapper.appendChild( div )
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Matrix.prototype.region = function(w,h,x,y) {
|
||||||
|
w = w || 1
|
||||||
|
h = h || 1
|
||||||
|
x = x || 0
|
||||||
|
y = y || 0
|
||||||
|
var parent = this
|
||||||
|
var mat = new Matrix(w, h, function(x,y){
|
||||||
|
return parent.aa[y][x]
|
||||||
|
})
|
||||||
|
mat.f = this.f
|
||||||
|
return mat
|
||||||
|
}
|
||||||
|
Matrix.prototype.setCell = function(lex,x,y){
|
||||||
|
this.aa[y] && this.aa[y][x] && this.aa[y][x].assign(lex)
|
||||||
|
}
|
||||||
|
Matrix.prototype.getCell = function(x,y){
|
||||||
|
if (this.aa[y] && this.aa[y][x]) return this.aa[y][x]
|
||||||
|
else return null
|
||||||
|
}
|
||||||
|
Matrix.prototype.get = function(x,y){
|
||||||
|
y = floor(mod(y || 0, this.h))
|
||||||
|
x = floor(mod(x || 0, this.w))
|
||||||
|
if (this.aa[y] && this.aa[y][x]) return this.aa[y][x]
|
||||||
|
else return null
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix.prototype.resize = function(w,h){
|
||||||
|
w = w || canvas.w
|
||||||
|
h = h || canvas.h
|
||||||
|
var div, row, lex
|
||||||
|
var f = this.f, old_h = this.aa.length, old_w = this.aa[0].length
|
||||||
|
var rapper = this.rapper
|
||||||
|
w = max(w, 1)
|
||||||
|
h = max(h, 1)
|
||||||
|
if (h < old_h) {
|
||||||
|
for (var y = old_h; y > h; y--) {
|
||||||
|
row = this.aa.pop()
|
||||||
|
div = row[0].span.parentNode
|
||||||
|
row.forEach(function(lex, x){
|
||||||
|
lex.demolish()
|
||||||
|
})
|
||||||
|
div.parentNode.removeChild(div)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (h > old_h) {
|
||||||
|
for (var y = old_h; y < h; y++) {
|
||||||
|
div = document.createElement("div")
|
||||||
|
rapper.appendChild( div )
|
||||||
|
this.aa[y] = new Array (w)
|
||||||
|
for (var x = 0; x < w; x++) {
|
||||||
|
lex = this.aa[y][x] = f(x,y)
|
||||||
|
div.appendChild(lex.span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w < old_w) {
|
||||||
|
this.aa.forEach(function(row, y){
|
||||||
|
while (row.length > w) {
|
||||||
|
lex = row.pop()
|
||||||
|
lex.demolish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (w > old_w) {
|
||||||
|
this.aa.forEach(function(row, y){
|
||||||
|
div = row[0].span.parentNode
|
||||||
|
for (var x = row.length; x < w; x++) {
|
||||||
|
lex = row[x] = f(x,y)
|
||||||
|
div.appendChild(lex.span)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.w = w
|
||||||
|
this.h = h
|
||||||
|
this.bind && this.bind()
|
||||||
|
this.focus_clamp()
|
||||||
|
if (this.rapper && this.rapper.parentNode != document.body) {
|
||||||
|
this.resize_rapper()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Matrix.prototype.resize_rapper = function(){
|
||||||
|
var cell = canvas.aa[0][0].span
|
||||||
|
var cw = cell.offsetWidth
|
||||||
|
var ch = cell.offsetHeight
|
||||||
|
// if (canvas.grid) { ch++ }
|
||||||
|
var width = cw * this.aa[0].length
|
||||||
|
var height = ch * this.aa.length
|
||||||
|
if (canvas.grid) { width++; height++ }
|
||||||
|
if (this.rotated) {
|
||||||
|
this.rapper.parentNode.classList.add("rotated")
|
||||||
|
this.rapper.parentNode.style.height = (width) + "px"
|
||||||
|
this.rapper.parentNode.style.width = (height) + "px"
|
||||||
|
this.rapper.style.top = (width/2) + "px"
|
||||||
|
// this.rapper.style.left = ((canvas_rapper.offsetHeight+20)/2) + "px"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.rapper.parentNode.classList.remove("rotated")
|
||||||
|
this.rapper.parentNode.style.height = ""
|
||||||
|
this.rapper.style.width =
|
||||||
|
this.rapper.parentNode.style.width = (width) + "px"
|
||||||
|
this.rapper.style.top = ""
|
||||||
|
// canvas_rapper.style.left = "auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Matrix.prototype.ascii = function () {
|
||||||
|
var lines = this.aa.map(function(row, y){
|
||||||
|
var last, line = ""
|
||||||
|
row.forEach(function(lex, x) {
|
||||||
|
line += lex.ascii()
|
||||||
|
})
|
||||||
|
return line // .replace(/\s+$/,"")
|
||||||
|
})
|
||||||
|
var txt = lines.join("\n")
|
||||||
|
return txt
|
||||||
|
}
|
||||||
|
Matrix.prototype.ansi = function (opts) {
|
||||||
|
var lines = this.aa.map(function(row, y){
|
||||||
|
var last, line = ""
|
||||||
|
row.forEach(function(lex, x) {
|
||||||
|
if (lex.eqColor(last)) {
|
||||||
|
line += lex.sanitize()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line += lex.ansi()
|
||||||
|
last = lex
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return line
|
||||||
|
})
|
||||||
|
var txt = lines.filter(function(line){ return line.length > 0 }).join('\\e[0m\\n') + "\\e[0m"
|
||||||
|
return 'echo -e "' + txt + '"'
|
||||||
|
}
|
||||||
|
Matrix.prototype.mirc = function (opts) {
|
||||||
|
var cutoff = false
|
||||||
|
var lines = this.aa.map(function(row, y){
|
||||||
|
var last, line = ""
|
||||||
|
row.forEach(function(lex, x) {
|
||||||
|
if (lex.eqColor(last)) {
|
||||||
|
line += lex.sanitize()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line += lex.mirc()
|
||||||
|
last = lex
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (opts && opts.cutoff && line.length > opts.cutoff) {
|
||||||
|
cutoff = true
|
||||||
|
return line.substr(0, opts.cutoff)
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
})
|
||||||
|
|
||||||
|
var txt = lines.filter(function(line){ return line.length > 0 }).join('\n')
|
||||||
|
|
||||||
|
if (cutoff) {
|
||||||
|
txt = new String(txt)
|
||||||
|
txt.cutoff = true
|
||||||
|
}
|
||||||
|
return txt
|
||||||
|
}
|
||||||
|
Matrix.prototype.irssi = function(opts){
|
||||||
|
var mirc = this.mirc(opts)
|
||||||
|
var txt = mirc
|
||||||
|
// .replace(/\%/g, '%%')
|
||||||
|
.replace(/\\/g, '\\x5C')
|
||||||
|
.replace(/\"/g, '\\\"')
|
||||||
|
// .replace(/\'/g, '\\\'')
|
||||||
|
.replace(/\`/g, '\\\`')
|
||||||
|
.replace(/\$/g, '\\$')
|
||||||
|
// .replace(/\n\s+/g, '\n')
|
||||||
|
// .replace(/\s+$/g, '\n')
|
||||||
|
// .replace(/^\n+/, '')
|
||||||
|
.replace(/\n/g, '\\n')
|
||||||
|
.replace(/\x02/g, '\\x02')
|
||||||
|
.replace(/\x03/g, '\\x03')
|
||||||
|
|
||||||
|
txt = unicode.escapeToEscapedBytes(txt)
|
||||||
|
txt = '/exec -out printf "%b" "' + txt + '"\n'
|
||||||
|
if (mirc.cutoff){
|
||||||
|
txt = new String(txt)
|
||||||
|
txt.cutoff = true
|
||||||
|
}
|
||||||
|
return txt
|
||||||
|
}
|
226
js/png.js
Normal file
226
js/png.js
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
var PNG = (function(){
|
||||||
|
|
||||||
|
var crc32 = function(u8){
|
||||||
|
var table = new Uint32Array([
|
||||||
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||||
|
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||||
|
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||||
|
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||||
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||||
|
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||||
|
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||||
|
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||||
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||||
|
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||||
|
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||||
|
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||||
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||||
|
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||||
|
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||||
|
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||||
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||||
|
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||||
|
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||||
|
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||||
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||||
|
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||||
|
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||||
|
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||||
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||||
|
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||||
|
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||||
|
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||||
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||||
|
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||||
|
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||||
|
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||||
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||||
|
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||||
|
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||||
|
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||||
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||||
|
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||||
|
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||||
|
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||||
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||||
|
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||||
|
])
|
||||||
|
|
||||||
|
var crc = 0 ^ (-1)
|
||||||
|
|
||||||
|
for(var i = 0; i < u8.length; i++){
|
||||||
|
crc = (crc >>> 8) ^ table[(crc ^ u8[i]) & 0xFF]
|
||||||
|
}
|
||||||
|
|
||||||
|
//return (crc ^ (-1)) // signed
|
||||||
|
return (crc ^ (-1)) >>> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var signature = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10])
|
||||||
|
var te, td
|
||||||
|
|
||||||
|
// decodes chunks in png
|
||||||
|
// see http://www.w3.org/TR/PNG/#5Chunk-layout
|
||||||
|
// returns something like
|
||||||
|
// [{length: Number,
|
||||||
|
// type: String[4],
|
||||||
|
// crc: Number,
|
||||||
|
// data: Uint8Array[] // optional
|
||||||
|
// }, ...]
|
||||||
|
var decode = function(buf, err){
|
||||||
|
var u8a = new Uint8Array(buf)
|
||||||
|
var dv = new DataView(buf)
|
||||||
|
td = td || new TextDecoder('utf-8')
|
||||||
|
err = err || function(msg){ throw new Error(msg) }
|
||||||
|
|
||||||
|
var out = []
|
||||||
|
var pos = 0
|
||||||
|
|
||||||
|
if (u8a.length < signature.length) return err("not a valid png")
|
||||||
|
for (var i=0; i<signature.length; i++){
|
||||||
|
if (signature[i] !== u8a[i]) return err("not a valid png")
|
||||||
|
pos += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var done = false
|
||||||
|
while (!done){
|
||||||
|
var chunk = {}
|
||||||
|
|
||||||
|
if (pos + 4 > u8a.length) return err("unexpected end of file")
|
||||||
|
chunk.length = dv.getInt32(pos, false)
|
||||||
|
pos += 4
|
||||||
|
|
||||||
|
if (pos + 4 > u8a.length) return err("unexpected end of file")
|
||||||
|
chunk.type = td.decode(new DataView(buf, pos, 4))
|
||||||
|
pos += 4
|
||||||
|
|
||||||
|
if (chunk.length){
|
||||||
|
if (pos + chunk.length > u8a.length) return err('unexpected end of file')
|
||||||
|
chunk.data = new Uint8Array(buf, pos, chunk.length)
|
||||||
|
pos += chunk.length
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos + 4 > u8a.length) return err("unexpected end of file")
|
||||||
|
//chunk.crc = new Uint8Array(buf, pos, 4)
|
||||||
|
chunk.crc = dv.getUint32(pos, false)
|
||||||
|
pos += 4
|
||||||
|
|
||||||
|
|
||||||
|
out.push(chunk)
|
||||||
|
//done = true
|
||||||
|
//console.log(pos.length, u8a.length)
|
||||||
|
if (pos === u8a.length) done = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
var encode = function(chunks){
|
||||||
|
te = te || new TextEncoder('utf-8')
|
||||||
|
|
||||||
|
var size = 8 // inital png signature
|
||||||
|
for (var i=0, c; c=chunks[i]; i++){
|
||||||
|
size += 4 // length
|
||||||
|
size += 4 // type
|
||||||
|
size += c.length // data
|
||||||
|
size += 4 // crc32
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = new ArrayBuffer(size)
|
||||||
|
var u8 = new Uint8Array(buf)
|
||||||
|
var dv = new DataView(buf)
|
||||||
|
var pos = 0
|
||||||
|
|
||||||
|
u8.set(signature, 0)
|
||||||
|
pos += 8
|
||||||
|
|
||||||
|
for (var i=0, c; c=chunks[i]; i++){
|
||||||
|
dv.setInt32(pos, c.length, false) // length
|
||||||
|
pos += 4
|
||||||
|
var chunk_type_u8 = te.encode(c.type) // type
|
||||||
|
u8.set(chunk_type_u8, pos)
|
||||||
|
pos += 4
|
||||||
|
if (c.length){
|
||||||
|
u8.set(c.data, pos) // data
|
||||||
|
pos += c.length
|
||||||
|
}
|
||||||
|
//u8.set(c.crc, pos) // crc32
|
||||||
|
dv.setUint32(pos, c.crc, false) // crc32
|
||||||
|
pos += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
return u8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var make_itxt_chunk = function(keyword, txt){
|
||||||
|
te = te || new TextEncoder('utf-8')
|
||||||
|
var keyword_u8 = te.encode(keyword)
|
||||||
|
var txt_u8 = te.encode(txt)
|
||||||
|
var header_u8 = new Uint8Array(keyword_u8.length + 5)
|
||||||
|
header_u8.set(keyword_u8, 0)
|
||||||
|
// header has keyword, then a null byte and some additional fields
|
||||||
|
// see http://www.w3.org/TR/PNG/#11iTXt
|
||||||
|
var chunk = {type: 'iTXt'}
|
||||||
|
chunk.length = header_u8.length + txt_u8.length
|
||||||
|
var u8 = new Uint8Array(4 + chunk.length)
|
||||||
|
// put type and data on the same u8 array so we can calculate crc
|
||||||
|
u8.set(te.encode(chunk.type), 0)
|
||||||
|
u8.set(header_u8, 4)
|
||||||
|
u8.set(txt_u8, header_u8.length + 4)
|
||||||
|
chunk.crc = crc32(u8)
|
||||||
|
chunk.data = new Uint8Array(u8.buffer, 4)
|
||||||
|
return chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
var read_cstring = function(u8, pos){
|
||||||
|
var str = ""
|
||||||
|
while (pos < u8.length){
|
||||||
|
if (u8[pos] === 0) return str
|
||||||
|
str += String.fromCharCode(u8[pos])
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
var decode_itxt_chunk = function(chunk){
|
||||||
|
td = td || new TextDecoder('utf-8')
|
||||||
|
var data = {}
|
||||||
|
var pos = 0
|
||||||
|
data.keyword = read_cstring(chunk.data, 0)
|
||||||
|
pos += data.keyword.length + 1
|
||||||
|
data.compression = chunk.data[pos]
|
||||||
|
pos += 1
|
||||||
|
data.compression_method = chunk.data[pos]
|
||||||
|
pos += 1
|
||||||
|
data.language = read_cstring(chunk.data, pos)
|
||||||
|
pos += data.language.length + 1
|
||||||
|
data.translated_keyword = read_cstring(chunk.data, pos)
|
||||||
|
pos += data.translated_keyword.length + 1
|
||||||
|
var data_u8 = chunk.data.subarray(pos)
|
||||||
|
data.data = td.decode(data_u8)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
var canvas_to_blob_with_colorcode = function(canvas, cc){
|
||||||
|
var u8 = dataUriToUint8Array(canvas.toDataURL())
|
||||||
|
var chunks = decode(u8.buffer)
|
||||||
|
var itxt_chunk = make_itxt_chunk('colorcode', cc)
|
||||||
|
// assume we wanna insert the chunk very last, just in front of the end
|
||||||
|
chunks.splice(chunks.length - 1, 0, itxt_chunk)
|
||||||
|
var blob = new Blob([encode(chunks)], {type: 'image/png'})
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
|
||||||
|
var exports = {}
|
||||||
|
exports.crc32 = crc32
|
||||||
|
exports.decode = decode
|
||||||
|
exports.encode = encode
|
||||||
|
exports.make_itxt_chunk = make_itxt_chunk
|
||||||
|
exports.decode_itxt_chunk = decode_itxt_chunk
|
||||||
|
exports.canvas_to_blob_with_colorcode = canvas_to_blob_with_colorcode
|
||||||
|
return exports
|
||||||
|
|
||||||
|
})()
|
58
js/shader.js
Normal file
58
js/shader.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
var shader = (function(){
|
||||||
|
var fn_str, fn, lex
|
||||||
|
var exports = {}
|
||||||
|
var animating = false
|
||||||
|
|
||||||
|
exports.init = function(){
|
||||||
|
lex = new Lex (0, 0)
|
||||||
|
exports.build(demo_shader.innerHTML)
|
||||||
|
}
|
||||||
|
exports.build = function (fn_str){
|
||||||
|
try {
|
||||||
|
new_fn = new Function('lex', 'x', 'y', 'w', 'h', 't', fn_str)
|
||||||
|
new_fn(lex, 0, 0, 1, 1, 0)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
throw 'Shader execution error'
|
||||||
|
}
|
||||||
|
exports.fn = fn = new_fn
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
exports.run = function(canvas){
|
||||||
|
var t = +new Date
|
||||||
|
shader.canvas = shader.canvas || canvas
|
||||||
|
var w = shader.canvas.w, h = shader.canvas.h
|
||||||
|
shader.canvas.forEach(function(lex, x, y){
|
||||||
|
fn(lex, x, y, w, h, t)
|
||||||
|
lex.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
exports.toggle = function(state){
|
||||||
|
animating = typeof state == "boolean" ? state : ! animating
|
||||||
|
shader_fps_el.classList.toggle('hidden')
|
||||||
|
return animating
|
||||||
|
}
|
||||||
|
exports.pause = function(){
|
||||||
|
animating = false
|
||||||
|
shader_fps_el.classList.add('hidden')
|
||||||
|
shader.fps_time = 0
|
||||||
|
}
|
||||||
|
exports.play = function(){
|
||||||
|
animating = true
|
||||||
|
shader_fps_el.classList.remove('hidden')
|
||||||
|
}
|
||||||
|
exports.animate = function (t){
|
||||||
|
requestAnimationFrame(exports.animate)
|
||||||
|
if (! animating) { return }
|
||||||
|
if (shader.fps_time){
|
||||||
|
var ms = Date.now() - shader.fps_time
|
||||||
|
fps = 1000 / ms
|
||||||
|
shader_fps_el.innerHTML = (fps | 0) + ' fps'
|
||||||
|
}
|
||||||
|
shader.fps_time = Date.now()
|
||||||
|
exports.run(canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
return exports
|
||||||
|
|
||||||
|
})()
|
170
js/tool.js
Normal file
170
js/tool.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
var Tool = Model({
|
||||||
|
init: function (el) {
|
||||||
|
this.el = el
|
||||||
|
this.lex = new Lex (el)
|
||||||
|
this.name = el.innerHTML
|
||||||
|
},
|
||||||
|
bind: function(){
|
||||||
|
var tool = this
|
||||||
|
tool.el.addEventListener('mousedown', function(e){
|
||||||
|
tool.focus()
|
||||||
|
})
|
||||||
|
tool.el.addEventListener('contextmenu', function(e){
|
||||||
|
tool.context(e)
|
||||||
|
})
|
||||||
|
if (tool.memorable) {
|
||||||
|
// console.log(tool.name, localStorage.getItem("ascii.tools." + tool.name) )
|
||||||
|
tool.use( localStorage.getItem("ascii.tools." + tool.name) == "true" )
|
||||||
|
}
|
||||||
|
},
|
||||||
|
use: function(){},
|
||||||
|
context: function(e){},
|
||||||
|
done: function(){},
|
||||||
|
focus: function(){
|
||||||
|
// focused && focused.blur()
|
||||||
|
current_tool && current_tool.blur()
|
||||||
|
current_tool = this
|
||||||
|
this.el.classList.add('focused')
|
||||||
|
this.use()
|
||||||
|
if (this.name != 'shader' && is_desktop) { cursor_input.focus() }
|
||||||
|
},
|
||||||
|
blur: function(){
|
||||||
|
current_tool = null
|
||||||
|
this.el.classList.remove('focused')
|
||||||
|
this.done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var FileTool = Tool.extend({
|
||||||
|
focus: function(){
|
||||||
|
if (current_filetool === this) {
|
||||||
|
this.blur()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
current_filetool && current_filetool.blur()
|
||||||
|
current_filetool = this
|
||||||
|
this.el.classList.add('focused')
|
||||||
|
this.use()
|
||||||
|
if (this.name != 'shader' && is_desktop) { cursor_input.focus() }
|
||||||
|
},
|
||||||
|
blur: function(){
|
||||||
|
current_filetool = null
|
||||||
|
this.el.classList.remove('focused')
|
||||||
|
this.done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var RadioItem = Tool.extend({
|
||||||
|
init: function(group, el){
|
||||||
|
this.group = group
|
||||||
|
this.el = el
|
||||||
|
},
|
||||||
|
focus: function(){
|
||||||
|
this.el.classList.add('focused')
|
||||||
|
},
|
||||||
|
blur: function(){
|
||||||
|
this.el.classList.remove('focused')
|
||||||
|
},
|
||||||
|
bind: function(){
|
||||||
|
var control = this
|
||||||
|
this.el.addEventListener('mousedown', function(){
|
||||||
|
control.group.use(control)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var RadioGroup = Tool.extend({
|
||||||
|
init: function(el){
|
||||||
|
this.el = el
|
||||||
|
this.controls = {}
|
||||||
|
var names = el.innerHTML.split(' ')
|
||||||
|
el.innerHTML = ''
|
||||||
|
var group = this
|
||||||
|
names.forEach(function(value){
|
||||||
|
var el = document.createElement('span')
|
||||||
|
el.classList.add('radio','tool')
|
||||||
|
var control = new RadioItem(group, el)
|
||||||
|
if (value.substr(0,1) === '*') {
|
||||||
|
control.value = value = value.substr(1)
|
||||||
|
group.use(control)
|
||||||
|
}
|
||||||
|
control.value = el.innerHTML = value
|
||||||
|
group.controls[value] = control
|
||||||
|
group.el.appendChild(el)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
use: function(control){
|
||||||
|
if (typeof control === 'string') {
|
||||||
|
control = this.controls[control]
|
||||||
|
}
|
||||||
|
this.selected_control && this.selected_control.blur()
|
||||||
|
this.value = control.value
|
||||||
|
this.selected_control = control
|
||||||
|
control.focus()
|
||||||
|
control.use()
|
||||||
|
if (this.memorable){
|
||||||
|
localStorage.setItem("ascii.tools." + this.name, this.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bind: function(){
|
||||||
|
var tool = this
|
||||||
|
for (var n in this.controls){
|
||||||
|
this.controls[n].bind()
|
||||||
|
}
|
||||||
|
if (tool.memorable) {
|
||||||
|
var value = localStorage.getItem("ascii.tools." + tool.name)
|
||||||
|
if (value) tool.use(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var Checkbox = Tool.extend({
|
||||||
|
init: function (el){
|
||||||
|
this.__init(el)
|
||||||
|
var name = this.name.replace(/^[x_] /,"")
|
||||||
|
var state = localStorage.getItem("ascii.tools." + name) == "true" || this.name[0] == "x"
|
||||||
|
this.name = name
|
||||||
|
this.update(state)
|
||||||
|
},
|
||||||
|
update: function(state){
|
||||||
|
if (state) this.el.innerHTML = "x " + this.name
|
||||||
|
else this.el.innerHTML = "_ " + this.name
|
||||||
|
if (this.memorable) { localStorage.setItem("ascii.tools." + this.name, !! state) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var BlurredCheckbox = Checkbox.extend({
|
||||||
|
focus: function(){
|
||||||
|
this.use()
|
||||||
|
},
|
||||||
|
blur: function(){
|
||||||
|
this.el.classList.remove('focused')
|
||||||
|
this.done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var BlurredTool = Tool.extend({
|
||||||
|
focus: function(){
|
||||||
|
this.use()
|
||||||
|
},
|
||||||
|
blur: function(){
|
||||||
|
this.el.classList.remove('focused')
|
||||||
|
this.done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var HiddenCheckbox = BlurredCheckbox.extend({
|
||||||
|
on: "o",
|
||||||
|
off: ".",
|
||||||
|
init: function (el){
|
||||||
|
this.el = el
|
||||||
|
this.lex = new Lex (el)
|
||||||
|
this.name = this.el.id
|
||||||
|
var state = localStorage.getItem("ascii.tools." + name) == "true" || this.el.innerHTML[0] == this.on
|
||||||
|
this.update(state)
|
||||||
|
},
|
||||||
|
update: function(state){
|
||||||
|
this.el.innerHTML = state ? this.on : this.off
|
||||||
|
if (this.memorable) { localStorage.setItem("ascii.tools." + this.name, !! state) }
|
||||||
|
}
|
||||||
|
})
|
108
js/ui/brush.js
Normal file
108
js/ui/brush.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
var brush = (function(){
|
||||||
|
|
||||||
|
var brush = new Matrix (5, 5, function(x,y){
|
||||||
|
var lex = new Lex (x,y)
|
||||||
|
lex.build()
|
||||||
|
return lex
|
||||||
|
})
|
||||||
|
|
||||||
|
brush.modified = false
|
||||||
|
|
||||||
|
brush.mask = blit.circle
|
||||||
|
|
||||||
|
brush.generate = function(){
|
||||||
|
brush.fill(brush)
|
||||||
|
brush.mask(brush)
|
||||||
|
}
|
||||||
|
|
||||||
|
brush.bind = function(){
|
||||||
|
|
||||||
|
var last_point = [0,0]
|
||||||
|
var dragging = false
|
||||||
|
var erasing = false
|
||||||
|
|
||||||
|
brush.forEach(function(lex, x, y){
|
||||||
|
|
||||||
|
if (lex.bound) return
|
||||||
|
lex.bound = true
|
||||||
|
|
||||||
|
var point = [x,y]
|
||||||
|
lex.span.addEventListener('contextmenu', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
lex.span.addEventListener('mousedown', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas = brush
|
||||||
|
brush.modified = true
|
||||||
|
dragging = true
|
||||||
|
erasing = (e.which == "3" || e.ctrlKey)
|
||||||
|
if (erasing) {
|
||||||
|
lex.clear()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fillColor = brush.bg
|
||||||
|
lex.assign(brush)
|
||||||
|
}
|
||||||
|
brush.focus(x, y)
|
||||||
|
})
|
||||||
|
lex.span.addEventListener('mousemove', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
if (! dragging) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
erasing = (e.which == "3" || e.ctrlKey)
|
||||||
|
if (erasing) {
|
||||||
|
lex.clear()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lex.assign(brush)
|
||||||
|
}
|
||||||
|
brush.focus(x, y)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
window.addEventListener('mouseup', function(e){
|
||||||
|
dragging = erasing = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
brush.resize = function(w, h){
|
||||||
|
w = this.w = clamp(w, this.min, this.max)
|
||||||
|
h = this.h = clamp(h, this.min, this.max)
|
||||||
|
brush.rebuild()
|
||||||
|
controls.brush_w.char = "" + w
|
||||||
|
controls.brush_w.build()
|
||||||
|
controls.brush_h.char = "" + h
|
||||||
|
controls.brush_h.build()
|
||||||
|
}
|
||||||
|
brush.size_add = function(w, h){
|
||||||
|
brush.resize(brush.w + w, brush.h + h)
|
||||||
|
}
|
||||||
|
brush.expand = function(i){
|
||||||
|
brush.size_add(i, i)
|
||||||
|
}
|
||||||
|
brush.contract = function(i){
|
||||||
|
brush.size_add(-i, -i)
|
||||||
|
}
|
||||||
|
|
||||||
|
brush.load = function(lex){
|
||||||
|
brush.char = lex.char
|
||||||
|
brush.fg = lex.fg
|
||||||
|
brush.bg = lex.bg
|
||||||
|
brush.opacity = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
brush.min = 1
|
||||||
|
brush.max = 100
|
||||||
|
|
||||||
|
brush.char = " "
|
||||||
|
brush.fg = 0
|
||||||
|
brush.bg = 1
|
||||||
|
brush.opacity = 1
|
||||||
|
|
||||||
|
brush.draw_fg = true
|
||||||
|
brush.draw_bg = true
|
||||||
|
brush.draw_char = true
|
||||||
|
|
||||||
|
return brush
|
||||||
|
|
||||||
|
})()
|
144
js/ui/canvas.js
Normal file
144
js/ui/canvas.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
var canvas = current_canvas = (function(){
|
||||||
|
|
||||||
|
var cols = 100
|
||||||
|
var rows = 30
|
||||||
|
|
||||||
|
var canvas = new Matrix (cols, rows, function(x,y){
|
||||||
|
var lex = new Lex (x,y)
|
||||||
|
lex.build()
|
||||||
|
return lex
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas.bind = function(){
|
||||||
|
|
||||||
|
canvas.forEach(function(lex, x, y){
|
||||||
|
|
||||||
|
if (lex.bound) return
|
||||||
|
lex.bound = true
|
||||||
|
var point = [x,y]
|
||||||
|
lex.span.addEventListener('contextmenu', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
lex.span.addEventListener('mousedown', function(e){
|
||||||
|
if (is_mobile) return
|
||||||
|
e.preventDefault()
|
||||||
|
dragging = true
|
||||||
|
current_canvas = canvas
|
||||||
|
if (e.altKey) {
|
||||||
|
if (e.shiftKey) {
|
||||||
|
blit.copy_from(canvas, brush, floor(x-brush.w/2), floor(y-brush.h/2))
|
||||||
|
brush.mask(brush)
|
||||||
|
draw.set_last_point(e, point)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
brush.load(lex)
|
||||||
|
brush.generate()
|
||||||
|
dragging = false
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (drawing) {
|
||||||
|
undo.new()
|
||||||
|
draw.down(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (selecting) {
|
||||||
|
selection.down(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (transforming) {
|
||||||
|
transform.down(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (filling) {
|
||||||
|
undo.new()
|
||||||
|
draw.fill(brush, x, y)
|
||||||
|
}
|
||||||
|
canvas.focus(x, y)
|
||||||
|
})
|
||||||
|
|
||||||
|
lex.span.addEventListener("mousemove", function(e){
|
||||||
|
mouse.x = x
|
||||||
|
mouse.y = y
|
||||||
|
if (is_mobile) return
|
||||||
|
if (! dragging) return
|
||||||
|
if (drawing) {
|
||||||
|
draw.move(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (selecting) {
|
||||||
|
selection.move(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (transforming) {
|
||||||
|
transform.move(e, lex, point)
|
||||||
|
}
|
||||||
|
canvas.focus(x, y)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
if (is_mobile) {
|
||||||
|
canvas.rapper.addEventListener('touchstart', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
var x, y, point, lex
|
||||||
|
x = (e.touches[0].pageX - canvas.rapper.offsetTop) / canvas.aa[0][0].span.offsetWidth
|
||||||
|
y = (e.touches[0].pageY - canvas.rapper.offsetTop) / canvas.aa[0][0].span.offsetHeight
|
||||||
|
x = ~~clamp(x, 0, canvas.aa[0].length-1)
|
||||||
|
y = ~~clamp(y, 0, canvas.aa.length-1)
|
||||||
|
point = [x,y]
|
||||||
|
lex = canvas.aa[y][x]
|
||||||
|
dragging = true
|
||||||
|
if (drawing) {
|
||||||
|
undo.new()
|
||||||
|
draw.down(e, lex, point)
|
||||||
|
}
|
||||||
|
else if (filling) {
|
||||||
|
undo.new()
|
||||||
|
draw.fill(brush, x, y)
|
||||||
|
}
|
||||||
|
canvas.focus(x, y)
|
||||||
|
})
|
||||||
|
canvas.rapper.addEventListener("touchmove", function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
var x, y, point, lex
|
||||||
|
x = (e.touches[0].pageX - canvas.rapper.offsetTop) / canvas.aa[0][0].span.offsetWidth
|
||||||
|
y = (e.touches[0].pageY - canvas.rapper.offsetTop) / canvas.aa[0][0].span.offsetHeight
|
||||||
|
x = ~~clamp(x, 0, canvas.aa[0].length-1)
|
||||||
|
y = ~~clamp(y, 0, canvas.aa.length-1)
|
||||||
|
point = [x,y]
|
||||||
|
lex = canvas.aa[y][x]
|
||||||
|
if (! dragging) return
|
||||||
|
shader_el.innerHTML = point.join(",")
|
||||||
|
if (drawing) {
|
||||||
|
draw.move(e, lex, point)
|
||||||
|
}
|
||||||
|
canvas.focus(x, y)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.min = 1
|
||||||
|
canvas.max = 999
|
||||||
|
|
||||||
|
// canvas.resize(1, 1, true) // wont create undo state
|
||||||
|
canvas.resize = function(w, h, no_undo){
|
||||||
|
var old_w = this.w, old_h = this.h
|
||||||
|
w = this.w = clamp(w, this.min, this.max)
|
||||||
|
h = this.h = clamp(h, this.min, this.max)
|
||||||
|
if (old_w === w && old_h === h) return;
|
||||||
|
|
||||||
|
if (!no_undo){
|
||||||
|
undo.new()
|
||||||
|
undo.save_resize(w, h, old_w, old_h)
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.__proto__.resize.call(canvas, w, h)
|
||||||
|
controls.canvas_w.char = "" + w
|
||||||
|
controls.canvas_w.build()
|
||||||
|
controls.canvas_h.char = "" + h
|
||||||
|
controls.canvas_h.build()
|
||||||
|
}
|
||||||
|
canvas.size_add = function(w, h){
|
||||||
|
canvas.resize(canvas.w + w, canvas.h + h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas
|
||||||
|
|
||||||
|
})()
|
374
js/ui/controls.js
vendored
Normal file
374
js/ui/controls.js
vendored
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
var controls = (function(){
|
||||||
|
|
||||||
|
var controls = {}
|
||||||
|
|
||||||
|
controls.cross = new Tool (cross_el)
|
||||||
|
controls.cross.use = function(){
|
||||||
|
if (brush.mask == blit.cross) {
|
||||||
|
controls.cross.el.innerHTML = "ssoɹɔ"
|
||||||
|
brush.mask = blit.inverted_cross
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
controls.cross.el.innerHTML = "cross"
|
||||||
|
brush.mask = blit.cross
|
||||||
|
}
|
||||||
|
brush.generate()
|
||||||
|
drawing = true
|
||||||
|
brush.modified = false
|
||||||
|
}
|
||||||
|
controls.cross.done = function(){
|
||||||
|
controls.cross.el.innerHTML = "cross"
|
||||||
|
drawing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.circle = new Tool (circle_el)
|
||||||
|
controls.circle.use = function(){
|
||||||
|
brush.mask = blit.circle
|
||||||
|
brush.generate()
|
||||||
|
drawing = true
|
||||||
|
brush.modified = false
|
||||||
|
}
|
||||||
|
controls.circle.done = function(){
|
||||||
|
drawing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.square = new Tool (square_el)
|
||||||
|
controls.square.use = function(){
|
||||||
|
brush.mask = blit.square
|
||||||
|
brush.generate()
|
||||||
|
brush.modified = false
|
||||||
|
drawing = true
|
||||||
|
}
|
||||||
|
controls.square.done = function(){
|
||||||
|
drawing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.text = new Tool (text_el)
|
||||||
|
controls.text.use = function(){
|
||||||
|
current_filetool && current_filetool.blur()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.select = new Tool (select_el)
|
||||||
|
controls.select.use = function(){
|
||||||
|
selection.show()
|
||||||
|
}
|
||||||
|
controls.select.done = function(){
|
||||||
|
selection.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.rotate = new Tool (rotate_el)
|
||||||
|
controls.rotate.use = function(){
|
||||||
|
transform.set_mode('rotate')
|
||||||
|
}
|
||||||
|
controls.rotate.done = function(){
|
||||||
|
transform.done()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.scale = new Tool (scale_el)
|
||||||
|
controls.scale.use = function(){
|
||||||
|
transform.set_mode('scale')
|
||||||
|
}
|
||||||
|
controls.scale.done = function(){
|
||||||
|
transform.done()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.slice = new Tool (slice_el)
|
||||||
|
controls.slice.use = function(){
|
||||||
|
transform.set_mode('slice')
|
||||||
|
}
|
||||||
|
controls.slice.done = function(){
|
||||||
|
transform.done()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.translate = new Tool (translate_el)
|
||||||
|
controls.translate.use = function(){
|
||||||
|
transform.set_mode('translate')
|
||||||
|
}
|
||||||
|
controls.translate.done = function(){
|
||||||
|
transform.done()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.fill = new Tool (fill_el)
|
||||||
|
controls.fill.use = function(){
|
||||||
|
filling = true
|
||||||
|
document.body.classList.add("bucket")
|
||||||
|
}
|
||||||
|
controls.fill.done = function(){
|
||||||
|
filling = false
|
||||||
|
document.body.classList.remove("bucket")
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.undo = new BlurredTool (undo_el)
|
||||||
|
controls.undo.use = function(){
|
||||||
|
undo.undo()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.redo = new BlurredTool (redo_el)
|
||||||
|
controls.redo.use = function(){
|
||||||
|
undo.redo()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.clear = new BlurredTool (clear_el)
|
||||||
|
controls.clear.use = function(){
|
||||||
|
undo.new()
|
||||||
|
undo.save_rect(0, 0, canvas.w, canvas.h)
|
||||||
|
canvas.erase()
|
||||||
|
current_filetool && current_filetool.blur()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.webcam = new FileTool (webcam_el)
|
||||||
|
controls.webcam.load = function(){
|
||||||
|
this.loaded = true
|
||||||
|
webcam_close.addEventListener("click", function(){ controls.webcam.blur() })
|
||||||
|
window.addEventListener("message", function(e){
|
||||||
|
if (e.origin !== window.location.origin) return
|
||||||
|
controls.webcam.blur()
|
||||||
|
controls.circle.focus()
|
||||||
|
import_textarea.value = e.data
|
||||||
|
clipboard.import_colorcode()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
controls.webcam.use = function(){
|
||||||
|
if (! this.loaded) {
|
||||||
|
this.load()
|
||||||
|
}
|
||||||
|
webcam_iframe.src = "webcam.html"
|
||||||
|
webcam_rapper.style.display = "block"
|
||||||
|
}
|
||||||
|
controls.webcam.done = function(){
|
||||||
|
webcam_iframe.src = ""
|
||||||
|
webcam_rapper.style.display = "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.grid = new BlurredCheckbox (grid_el)
|
||||||
|
controls.grid.memorable = true
|
||||||
|
controls.grid.use = function(state){
|
||||||
|
state = typeof state == "boolean" ? state : ! document.body.classList.contains("grid")
|
||||||
|
document.body.classList[ state ? "add" : "remove" ]('grid')
|
||||||
|
letters.grid = palette.grid = canvas.grid = state
|
||||||
|
canvas.resize_rapper()
|
||||||
|
palette.resize_rapper()
|
||||||
|
letters.resize_rapper()
|
||||||
|
if (! selection.hidden) selection.reposition()
|
||||||
|
this.update( state )
|
||||||
|
}
|
||||||
|
ClipboardTool = FileTool.extend({
|
||||||
|
blur: function(){
|
||||||
|
this.__blur()
|
||||||
|
clipboard.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
controls.save = new ClipboardTool (save_el)
|
||||||
|
controls.save.use = function(){
|
||||||
|
changed && clipboard.upload_png()
|
||||||
|
clipboard.show()
|
||||||
|
clipboard.export_mode()
|
||||||
|
}
|
||||||
|
controls.send_to_irc = new ClipboardTool (send_to_irc_el)
|
||||||
|
controls.send_to_irc.use = function(){
|
||||||
|
changed && clipboard.upload_png()
|
||||||
|
clipboard.show()
|
||||||
|
clipboard.export_mode()
|
||||||
|
alert('your ascii art is now on display on the IRC channel inside the panke.gallery!')
|
||||||
|
}
|
||||||
|
controls.load = new ClipboardTool (load_el)
|
||||||
|
controls.load.use = function(){
|
||||||
|
// console.log("use")
|
||||||
|
clipboard.show()
|
||||||
|
clipboard.import_mode()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.save_format = new RadioGroup(format_el)
|
||||||
|
controls.save_format.name = 'save_format'
|
||||||
|
controls.save_format.memorable = true
|
||||||
|
var cs = controls.save_format.controls
|
||||||
|
cs.mirc.use = cs.irssi.use = cs.ascii.use = function(){
|
||||||
|
clipboard.export_data()
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
var ShaderTool = FileTool.extend({
|
||||||
|
active: false,
|
||||||
|
use: function(state){
|
||||||
|
this.active = typeof state == "boolean" ? state : ! this.active
|
||||||
|
if (this.active) {
|
||||||
|
shader_rapper.style.display = "block"
|
||||||
|
shader_textarea.focus()
|
||||||
|
} else {
|
||||||
|
shader_rapper.style.display = "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
done: function(){
|
||||||
|
this.use(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
controls.shader = new ShaderTool (shader_el)
|
||||||
|
shader_textarea.value = shader_textarea.value || demo_shader.innerHTML
|
||||||
|
shader_textarea.addEventListener("input", function(){
|
||||||
|
var fn = shader.build(shader_textarea.value)
|
||||||
|
fn && shader.run(canvas)
|
||||||
|
})
|
||||||
|
controls.animate = new BlurredCheckbox (animate_checkbox)
|
||||||
|
controls.animate.use = function(state){
|
||||||
|
var state = shader.toggle()
|
||||||
|
this.update(state)
|
||||||
|
// controls.shader.focus()
|
||||||
|
controls.shader.use(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.shader_target = new RadioGroup(shader_target_el)
|
||||||
|
var cs = controls.shader_target.controls
|
||||||
|
cs.canvas.use = function(){ shader.canvas = canvas }
|
||||||
|
cs.brush.use = function(){ shader.canvas = brush }
|
||||||
|
cs.selection.use = function(){ shader.canvas = selection.canvas }
|
||||||
|
|
||||||
|
controls.experimental_palette = new HiddenCheckbox (experimental_palette_toggle)
|
||||||
|
controls.experimental_palette.memorable = true
|
||||||
|
controls.experimental_palette.use = function(state){
|
||||||
|
var state = palette.experimental(state)
|
||||||
|
this.update(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.advanced = new BlurredCheckbox (advanced_checkbox)
|
||||||
|
controls.advanced.memorable = true
|
||||||
|
controls.advanced.use = function(state){
|
||||||
|
console.log(state)
|
||||||
|
state = typeof state == "boolean" ? state : ! document.body.classList.contains('panke')
|
||||||
|
if (state)
|
||||||
|
document.body.classList.add('panke')
|
||||||
|
else
|
||||||
|
document.body.classList.remove('panke')
|
||||||
|
this.update(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
controls.nopaint = new HiddenCheckbox (nopaint_toggle)
|
||||||
|
controls.nopaint.memorable = true
|
||||||
|
controls.nopaint.on = "N"
|
||||||
|
controls.nopaint.use = function(state){
|
||||||
|
var state = nopaint.toggle(state)
|
||||||
|
this.update(state)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
controls.fg = new BlurredCheckbox (fg_checkbox)
|
||||||
|
controls.fg.use = function(state){
|
||||||
|
brush.draw_fg = state || ! brush.draw_fg
|
||||||
|
this.update(brush.draw_fg)
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.bg = new BlurredCheckbox (bg_checkbox)
|
||||||
|
controls.bg.use = function(state){
|
||||||
|
brush.draw_bg = state || ! brush.draw_bg
|
||||||
|
this.update(brush.draw_bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.char = new BlurredCheckbox (char_checkbox)
|
||||||
|
controls.char.use = function(state){
|
||||||
|
brush.draw_char = state || ! brush.draw_char
|
||||||
|
this.update(brush.draw_char)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// controls.turn = new BlurredCheckbox (turn_checkbox)
|
||||||
|
// controls.turn.memorable = true
|
||||||
|
// controls.turn.use = function(state){
|
||||||
|
// canvas.rotated = typeof state == "boolean" ? state : ! canvas.rotated
|
||||||
|
// canvas.resize_rapper()
|
||||||
|
// this.update(canvas.rotated)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// controls.pixels = new BlurredCheckbox (pixels_checkbox)
|
||||||
|
// controls.pixels.memorable = true
|
||||||
|
// controls.pixels.use = function(state){
|
||||||
|
// canvas.pixels = typeof state == "boolean" ? state : ! canvas.pixels
|
||||||
|
// document.body.classList.toggle("pixels", canvas.pixels)
|
||||||
|
// this.update(canvas.pixels)
|
||||||
|
// }
|
||||||
|
|
||||||
|
controls.mirror_x = new BlurredCheckbox (mirror_x_checkbox)
|
||||||
|
controls.mirror_x.use = function(state){
|
||||||
|
window.mirror_x = typeof state == "boolean" ? state : ! window.mirror_x
|
||||||
|
this.update(window.mirror_x)
|
||||||
|
}
|
||||||
|
controls.mirror_y = new BlurredCheckbox (mirror_y_checkbox)
|
||||||
|
controls.mirror_y.use = function(state){
|
||||||
|
window.mirror_y = typeof state == "boolean" ? state : ! window.mirror_y
|
||||||
|
this.update(window.mirror_y)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
controls.vertical = new BlurredCheckbox (vertical_checkbox)
|
||||||
|
controls.vertical.memorable = true
|
||||||
|
controls.vertical.use = function(state){
|
||||||
|
canvas.vertical = typeof state == "boolean" ? state : ! canvas.vertical
|
||||||
|
controls.vertical.refresh()
|
||||||
|
}
|
||||||
|
controls.vertical.refresh = function(){
|
||||||
|
if (canvas.vertical) {
|
||||||
|
document.body.classList.add("vertical")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.body.classList.remove("vertical")
|
||||||
|
}
|
||||||
|
palette.repaint()
|
||||||
|
letters.repaint()
|
||||||
|
this.update(canvas.vertical)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
controls.brush_w = new Lex (brush_w_el)
|
||||||
|
controls.brush_h = new Lex (brush_h_el)
|
||||||
|
controls.canvas_w = new Lex (canvas_w_el)
|
||||||
|
controls.canvas_h = new Lex (canvas_h_el)
|
||||||
|
|
||||||
|
// bind
|
||||||
|
|
||||||
|
controls.bind = function(){
|
||||||
|
|
||||||
|
for (var n in controls){
|
||||||
|
var control = controls[n]
|
||||||
|
if (typeof control === 'object' && 'bind' in control){
|
||||||
|
control.bind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[
|
||||||
|
controls.brush_w,
|
||||||
|
controls.brush_h,
|
||||||
|
controls.canvas_w,
|
||||||
|
controls.canvas_h
|
||||||
|
].forEach(function(lex){
|
||||||
|
lex.span.addEventListener('mousedown', function(e){
|
||||||
|
lex.focus()
|
||||||
|
if (is_mobile) cursor_input.focus()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
controls.brush_w.key = keys.single_numeral_key(controls.brush_w, function(w){ brush.resize(w, brush.h) })
|
||||||
|
controls.brush_w.raw_key = keys.arrow_key(function(w){ brush.size_add(w, 0) })
|
||||||
|
|
||||||
|
controls.brush_h.key = keys.single_numeral_key(controls.brush_h, function(h){ brush.resize(brush.w, h) })
|
||||||
|
controls.brush_h.raw_key = keys.arrow_key(function(h){ brush.size_add(0, h) })
|
||||||
|
|
||||||
|
controls.canvas_w.key = keys.multi_numeral_key(controls.canvas_w, 3)
|
||||||
|
controls.canvas_w.onBlur = keys.multi_numeral_blur(controls.canvas_w, function(w){ canvas.resize(w, canvas.h) })
|
||||||
|
controls.canvas_w.raw_key = keys.arrow_key(function(w){ canvas.size_add(w, 0) })
|
||||||
|
|
||||||
|
controls.canvas_h.key = keys.multi_numeral_key(controls.canvas_h, 3)
|
||||||
|
controls.canvas_h.onBlur = keys.multi_numeral_blur(controls.canvas_h, function(h){ canvas.resize(canvas.w, h) })
|
||||||
|
controls.canvas_h.raw_key = keys.arrow_key(function(h){ canvas.size_add(0, h) })
|
||||||
|
|
||||||
|
add_custom_el.addEventListener("click", function(){
|
||||||
|
custom.clone()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return controls
|
||||||
|
})()
|
24
js/ui/custom.js
Normal file
24
js/ui/custom.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
var custom = (function(){
|
||||||
|
|
||||||
|
var exports = {}
|
||||||
|
|
||||||
|
exports.clone = function (){
|
||||||
|
var new_brush = brush.clone()
|
||||||
|
var rapper = document.createElement("div")
|
||||||
|
rapper.className = "custom"
|
||||||
|
new_brush.append(rapper)
|
||||||
|
custom_rapper.appendChild(rapper)
|
||||||
|
// store in localstorage?
|
||||||
|
rapper.addEventListener("click", function(){
|
||||||
|
// load this brush
|
||||||
|
exports.load(new_brush)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.load = function(new_brush){
|
||||||
|
brush.assign( new_brush )
|
||||||
|
}
|
||||||
|
|
||||||
|
return exports
|
||||||
|
|
||||||
|
})()
|
132
js/ui/goodies.js
Normal file
132
js/ui/goodies.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
var goodies = (function(){
|
||||||
|
var goodies = {}
|
||||||
|
|
||||||
|
goodies.build = () => {
|
||||||
|
Object.keys(goodies.list).map(() => {
|
||||||
|
goodies_rapper.appendChild(tool_canvas.el)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
goodies.list = {}
|
||||||
|
|
||||||
|
goodies.list.choppy = {
|
||||||
|
mode: 'brush',
|
||||||
|
fn: `var char = choice(" abcdef ")
|
||||||
|
lex.bg = +choice("0124")
|
||||||
|
lex.fg = +choice("01234")
|
||||||
|
lex.char = char
|
||||||
|
lex.opacity = char == " " ? 0 : 1`,
|
||||||
|
}
|
||||||
|
|
||||||
|
goodies.list.foggy = {
|
||||||
|
mode: 'brush',
|
||||||
|
fn: `var char = choice(" abcdef ")
|
||||||
|
lex.bg = choice([14,15])
|
||||||
|
lex.fg = choice("367")
|
||||||
|
lex.char = char
|
||||||
|
lex.opacity = char == " " ? 0 : 1`,
|
||||||
|
}
|
||||||
|
// goodies.list.name = {
|
||||||
|
// fn: ``,
|
||||||
|
// }
|
||||||
|
// goodies.list.name = {
|
||||||
|
// fn: ``,
|
||||||
|
// }
|
||||||
|
// goodies.list.name = {
|
||||||
|
// fn: ``,
|
||||||
|
// }
|
||||||
|
// goodies.list.name = {
|
||||||
|
// fn: ``,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// >> mirror brush (up-down)
|
||||||
|
|
||||||
|
// NOTE: Animate this on the canvas, then draw:
|
||||||
|
|
||||||
|
// if (x > h/2) {
|
||||||
|
// lex.assign( canvas.aa[h-y][x] )
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> rainbow stardust brush
|
||||||
|
|
||||||
|
// Uncheck BG and animate this to brush:
|
||||||
|
|
||||||
|
// lex.fg = hue(t)
|
||||||
|
// lex.char = choice(" ,'.,.','****** ")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> noise brushes, works on a black background:
|
||||||
|
|
||||||
|
// lex.bg = max(5, yellow(randint(t)))
|
||||||
|
// lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> simple rainbow:
|
||||||
|
|
||||||
|
// if (lex.bg != 1) lex.bg = randint(t)
|
||||||
|
// lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> self-erasing:
|
||||||
|
|
||||||
|
// if (lex.bg != 1) lex.bg = yellow(randint(t))
|
||||||
|
// lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> cycling rainbow brush
|
||||||
|
|
||||||
|
// if (lex.bg != 1) lex.bg = hue( all_color_hue_order.indexOf( color_names[ lex.bg ] ) + 1 )
|
||||||
|
// lex.opacity = lex.bg == colors.black ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> "stars" brush.. set your brush to paint just the character "#"
|
||||||
|
|
||||||
|
// if (lex.char == "#") {
|
||||||
|
// lex.fg = hue(randint(15))
|
||||||
|
// lex.char = random() > 0.1 ? " " : "+@*.,\"+'*-"[randint(10)]
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> use fg char to mask mask what you're drawing on the bg
|
||||||
|
|
||||||
|
// if (lex.char != "/") { lex.bg = 1 }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> sharded glitch brush
|
||||||
|
|
||||||
|
// Example: http://asdf.us/z/kksnvs.png
|
||||||
|
|
||||||
|
// Use on a brush:
|
||||||
|
|
||||||
|
// lex.bg = t/y/x
|
||||||
|
// lex.opacity = lex.bg % 1 ? 0 : 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// >> incremental brush
|
||||||
|
|
||||||
|
// Set your brush to be the ^ character, square, about 10x10
|
||||||
|
// Draw "char" only
|
||||||
|
// Then animate this shader on the canvas:
|
||||||
|
|
||||||
|
// if (lex.char=="^") {
|
||||||
|
// lex.bg += 1
|
||||||
|
// lex.char = " "
|
||||||
|
// }
|
||||||
|
// lex.bg += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return goodies
|
||||||
|
})
|
240
js/ui/keys.js
Normal file
240
js/ui/keys.js
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
var keys = (function(){
|
||||||
|
|
||||||
|
var keys = {}
|
||||||
|
keys.bind = function(){
|
||||||
|
cursor_input.addEventListener('keydown', function(e){
|
||||||
|
|
||||||
|
// console.log("keycode:", e.keyCode)
|
||||||
|
if (e.altKey) {
|
||||||
|
document.body.classList.add("dropper")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 27: // esc
|
||||||
|
if (!selection.hidden && current_canvas === canvas){
|
||||||
|
selection.hide()
|
||||||
|
selection.show()
|
||||||
|
} else if (focused){
|
||||||
|
focused.blur()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.focused && focused.raw_key) {
|
||||||
|
focused.raw_key(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 219: // [
|
||||||
|
if (current_tool.name != "text") {
|
||||||
|
e.preventDefault()
|
||||||
|
brush.contract(1)
|
||||||
|
brush.modified = false
|
||||||
|
check_if_lost_focus()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 221: // ]
|
||||||
|
if (current_tool.name != "text") {
|
||||||
|
e.preventDefault()
|
||||||
|
brush.expand(1)
|
||||||
|
brush.modified = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 8: // backspace
|
||||||
|
e.preventDefault()
|
||||||
|
if (current_canvas === canvas)
|
||||||
|
undo.new()
|
||||||
|
current_canvas.focus_add(-1, 0)
|
||||||
|
if (current_canvas === canvas)
|
||||||
|
undo.save_focused_lex()
|
||||||
|
focused.char = " "
|
||||||
|
focused.build()
|
||||||
|
return
|
||||||
|
case 13: // return
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas.focusLex(focused.y, focused.x+1)
|
||||||
|
return
|
||||||
|
case 38: // up
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas.focus_add(0, -1)
|
||||||
|
break
|
||||||
|
case 40: // down
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas.focus_add(0, 1)
|
||||||
|
break
|
||||||
|
case 37: // left
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas.focus_add(-1, 0)
|
||||||
|
break
|
||||||
|
case 39: // right
|
||||||
|
e.preventDefault()
|
||||||
|
current_canvas.focus_add(1, 0)
|
||||||
|
break
|
||||||
|
// use typical windows and os x shortcuts
|
||||||
|
// undo: ctrl-z or cmd-z
|
||||||
|
// redo: ctrl-y or shift-cmd-z
|
||||||
|
case 89: // y
|
||||||
|
if (!e.ctrlKey && !e.metaKey) break;
|
||||||
|
e.preventDefault();
|
||||||
|
undo.redo();
|
||||||
|
break
|
||||||
|
case 90: // z
|
||||||
|
if (!e.ctrlKey && !e.metaKey) break;
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.shiftKey)
|
||||||
|
undo.redo();
|
||||||
|
else
|
||||||
|
undo.undo();
|
||||||
|
break
|
||||||
|
// default:
|
||||||
|
// if (focused) { focused.key(undefined, e.keyCode) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
cursor_input.addEventListener('input', function(e){
|
||||||
|
/*
|
||||||
|
if (! e.metaKey && ! e.ctrlKey && ! e.altKey) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (current_tool.name == "shader") {
|
||||||
|
cursor_input.value = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var char = cursor_input.value
|
||||||
|
cursor_input.value = ""
|
||||||
|
|
||||||
|
// console.log("input:", char)
|
||||||
|
|
||||||
|
if (current_tool.name != "text" && ! brush.modified) {
|
||||||
|
brush.char = char
|
||||||
|
if (char == " ") {
|
||||||
|
brush.bg = brush.fg
|
||||||
|
}
|
||||||
|
else if (brush.bg != fillColor) {
|
||||||
|
brush.fg = brush.bg
|
||||||
|
brush.bg = fillColor
|
||||||
|
}
|
||||||
|
brush.rebuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focused && char) {
|
||||||
|
var y = focused.y, x = focused.x
|
||||||
|
if (current_canvas === canvas){
|
||||||
|
undo.new()
|
||||||
|
undo.save_focused_lex()
|
||||||
|
}
|
||||||
|
var moving = focused.key(char, e.keyCode)
|
||||||
|
if ( ! moving || ! ('y' in focused && 'x' in focused) ) { return }
|
||||||
|
current_canvas.focus_add(1, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
cursor_input.addEventListener("keyup", function(e){
|
||||||
|
if (! e.altKey) {
|
||||||
|
document.body.classList.remove("dropper")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.int_key = function (f) {
|
||||||
|
return function (key, keyCode) {
|
||||||
|
var n = parseInt(key)
|
||||||
|
! isNaN(n) && f(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.arrow_key = function (fn) {
|
||||||
|
return function (e){
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 38: // up
|
||||||
|
e.preventDefault()
|
||||||
|
fn(1)
|
||||||
|
break
|
||||||
|
case 40: // down
|
||||||
|
e.preventDefault()
|
||||||
|
fn(-1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keys.left_right_key = function (fn) {
|
||||||
|
return function (e){
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 39: // right
|
||||||
|
e.preventDefault()
|
||||||
|
fn(1)
|
||||||
|
break
|
||||||
|
case 38: // up
|
||||||
|
case 40: // down
|
||||||
|
e.preventDefault()
|
||||||
|
fn(0)
|
||||||
|
break
|
||||||
|
case 37: // left
|
||||||
|
e.preventDefault()
|
||||||
|
fn(-1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.single_numeral_key = function (lex, fn) {
|
||||||
|
return keys.int_key(function(n, keyCode){
|
||||||
|
if (n == 0) n = 10
|
||||||
|
lex.blur()
|
||||||
|
fn(n)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
keys.multi_numeral_key = function (lex, digits){
|
||||||
|
return keys.int_key(function(n, keyCode){
|
||||||
|
lex.read()
|
||||||
|
if (lex.char.length < digits) {
|
||||||
|
n = parseInt(lex.char) * 10 + n
|
||||||
|
}
|
||||||
|
lex.char = ""+n
|
||||||
|
lex.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
keys.multi_numeral_blur = function (lex, fn){
|
||||||
|
return function(){
|
||||||
|
var n = parseInt(lex.char)
|
||||||
|
if (isNaN(n)) return
|
||||||
|
fn(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function cancelZoom() {
|
||||||
|
// var d = document,
|
||||||
|
// viewport,
|
||||||
|
// content,
|
||||||
|
// maxScale = ',maximum-scale=',
|
||||||
|
// maxScaleRegex = /,*maximum\-scale\=\d*\.*\d*/;
|
||||||
|
|
||||||
|
// // this should be a focusable DOM Element
|
||||||
|
// if (!this.addEventListener || !d.querySelector) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// viewport = d.querySelector('meta[name="viewport"]');
|
||||||
|
// content = viewport.content;
|
||||||
|
|
||||||
|
// function changeViewport(event) {
|
||||||
|
// // http://nerd.vasilis.nl/prevent-ios-from-zooming-onfocus/
|
||||||
|
// viewport.content = content + (event.type == 'blur' ? (content.match(maxScaleRegex, '') ? '' : maxScale + 10) : maxScale + 1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // We could use DOMFocusIn here, but it's deprecated.
|
||||||
|
// this.addEventListener('focus', changeViewport, true);
|
||||||
|
// this.addEventListener('blur', changeViewport, false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// cancelZoom.bind(cursor_input)();
|
||||||
|
|
||||||
|
return keys
|
||||||
|
})()
|
||||||
|
|
||||||
|
function check_if_lost_focus() {
|
||||||
|
if (! window.focused || ! window.focused.span)
|
||||||
|
window.focused = canvas.aa[0][0]
|
||||||
|
}
|
89
js/ui/letters.js
Normal file
89
js/ui/letters.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
var letters = (function(){
|
||||||
|
|
||||||
|
var last_charset = ""
|
||||||
|
var charset_index = 0
|
||||||
|
var charsets = [
|
||||||
|
'Basic Latin',
|
||||||
|
'Latin-1 Supplement',
|
||||||
|
'Box Drawing',
|
||||||
|
'Block Elements',
|
||||||
|
]
|
||||||
|
|
||||||
|
var letters = new Matrix (1, 1, function(x,y){
|
||||||
|
var lex = new Lex (x,y)
|
||||||
|
return lex
|
||||||
|
})
|
||||||
|
|
||||||
|
letters.charset = ""
|
||||||
|
|
||||||
|
letters.repaint = function(charset){
|
||||||
|
letters.charset = charset = charset || last_charset
|
||||||
|
last_charset = charset
|
||||||
|
var chars = unicode.block(charset, 32)
|
||||||
|
if (chars[0] != " ") chars.unshift(" ")
|
||||||
|
if (canvas.vertical) {
|
||||||
|
letters.resize( Math.ceil( chars.length / 16 ), 16 )
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
letters.resize( 32, Math.ceil( chars.length / 32 ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
letters.forEach(function(lex,x,y){
|
||||||
|
if (canvas.vertical) { x=x^y;y=x^y;x=x^y }
|
||||||
|
var char = chars[i++]
|
||||||
|
if (palette.chars.indexOf(brush.char) > 1) {
|
||||||
|
lex.bg = brush.fg
|
||||||
|
lex.fg = brush.bg
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lex.bg = colors.black
|
||||||
|
lex.fg = brush.fg == fillColor ? colors.black : brush.fg
|
||||||
|
}
|
||||||
|
lex.char = char
|
||||||
|
lex.opacity = 1
|
||||||
|
lex.build()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
letters.bind = function(){
|
||||||
|
letters.forEach(function(lex,x,y){
|
||||||
|
if (lex.bound) return
|
||||||
|
lex.bound = true
|
||||||
|
|
||||||
|
lex.span.addEventListener('mousedown', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
if (e.shiftKey) {
|
||||||
|
charset_index = (charset_index+1) % charsets.length
|
||||||
|
letters.repaint(charsets[charset_index])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (e.ctrlKey || e.which == 3) {
|
||||||
|
brush.char = lex.char
|
||||||
|
brush.bg = brush.fg
|
||||||
|
brush.fg = fillColor
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
brush.char = lex.char
|
||||||
|
if (lex.char == " ") {
|
||||||
|
brush.bg = brush.fg
|
||||||
|
}
|
||||||
|
else if (brush.bg != fillColor) {
|
||||||
|
brush.fg = brush.bg
|
||||||
|
brush.bg = fillColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! brush.modified) {
|
||||||
|
brush.generate()
|
||||||
|
}
|
||||||
|
palette.repaint()
|
||||||
|
})
|
||||||
|
lex.span.addEventListener('contextmenu', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return letters
|
||||||
|
})()
|
896
js/ui/nopaint.js
Normal file
896
js/ui/nopaint.js
Normal file
@ -0,0 +1,896 @@
|
|||||||
|
var nopaint = (function(){
|
||||||
|
|
||||||
|
controls.no = new Tool (nopaint_no_el)
|
||||||
|
controls.no.use = function(state){
|
||||||
|
undo.undo()
|
||||||
|
controls.paint.focus()
|
||||||
|
}
|
||||||
|
controls.no.context = function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
nopaint.turbo()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.paint = new Tool (nopaint_paint_el)
|
||||||
|
controls.paint.use = function(state){
|
||||||
|
nopaint.paint()
|
||||||
|
nopaint_pause_el.classList.toggle("hidden", false)
|
||||||
|
focused = controls.paint.lex
|
||||||
|
}
|
||||||
|
controls.paint.context = function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
nopaint.autoplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
controls.nopaint_pause = new Tool (nopaint_pause_el)
|
||||||
|
controls.nopaint_pause.use = function(state){
|
||||||
|
// nopaint.pause()
|
||||||
|
nopaint.autoplay(false)
|
||||||
|
nopaint_pause_el.classList.toggle("hidden", true)
|
||||||
|
focused = canvas.aa[0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// use own stepwise clock to drive tweens
|
||||||
|
oktween.raf = function(){}
|
||||||
|
|
||||||
|
var nopaint = {}
|
||||||
|
nopaint.debug = true
|
||||||
|
nopaint.delay = nopaint.normal_delay = 100
|
||||||
|
nopaint.turbo_delay = 0
|
||||||
|
nopaint.tool = null
|
||||||
|
nopaint.tools = {}
|
||||||
|
nopaint.keys = []
|
||||||
|
nopaint.weights = []
|
||||||
|
nopaint.step = 0
|
||||||
|
nopaint.time = 0
|
||||||
|
nopaint.timeout = false
|
||||||
|
nopaint.toggle = function(state){
|
||||||
|
var state = typeof state == "boolean" ? state : nopaint_rapper.classList.contains("hidden")
|
||||||
|
nopaint_rapper.classList.toggle("hidden", ! state)
|
||||||
|
nopaint_pause_el.classList.toggle("hidden", true)
|
||||||
|
document.body.classList.toggle("nopaint", state)
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
nopaint.no = function(){
|
||||||
|
undo.undo()
|
||||||
|
nopaint.paint()
|
||||||
|
}
|
||||||
|
nopaint.raw_key = controls.paint.lex.raw_key = keys.left_right_key(function(n){
|
||||||
|
if (! nopaint.timeout) return
|
||||||
|
if (n < 0) nopaint.no()
|
||||||
|
else if (n > 0) nopaint.paint()
|
||||||
|
else nopaint.pause()
|
||||||
|
})
|
||||||
|
nopaint.pause = nopaint.blur = function(){
|
||||||
|
clearTimeout(nopaint.timeout)
|
||||||
|
nopaint.timeout = 0
|
||||||
|
nopaint.step = 0
|
||||||
|
}
|
||||||
|
nopaint.paint = function(){
|
||||||
|
var state = undo.new()
|
||||||
|
delete state.focus
|
||||||
|
nopaint.pause()
|
||||||
|
nopaint.switch_tool()
|
||||||
|
nopaint.go()
|
||||||
|
}
|
||||||
|
nopaint.go = function(){
|
||||||
|
nopaint.timeout = setTimeout(nopaint.go, nopaint.delay)
|
||||||
|
oktween.update(nopaint.time)
|
||||||
|
nopaint.tool.paint( nopaint.step )
|
||||||
|
nopaint.time += 1
|
||||||
|
nopaint.step += 1
|
||||||
|
}
|
||||||
|
nopaint.switch_tool = function(){
|
||||||
|
last_tool = nopaint.tool
|
||||||
|
last_tool && last_tool.finish()
|
||||||
|
nopaint.tool = nopaint.get_random_tool( last_tool )
|
||||||
|
nopaint.tool.start( last_tool )
|
||||||
|
nopaint.debug && console.log("> %s", nopaint.tool.type)
|
||||||
|
}
|
||||||
|
nopaint.add_tool = function(fn){
|
||||||
|
nopaint.tools[fn.type] = fn
|
||||||
|
}
|
||||||
|
nopaint.disable_all_tools = function(){
|
||||||
|
Object.keys(nopaint.tools).forEach(function(key){
|
||||||
|
nopaint.tools[key].disabled = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
nopaint.enable_tools = function(keys){
|
||||||
|
keys.forEach(function(key){
|
||||||
|
if (nopaint.tools[key]) nopaint.tools[key].disabled = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
nopaint.get_random_tool = function( last_tool ){
|
||||||
|
var n = rand( nopaint.sum )
|
||||||
|
for (var i = 0, _len = nopaint.weights.length; i < _len; i++) {
|
||||||
|
if (n < nopaint.weights[i] && (! last_tool || nopaint.keys[i] !== last_tool.key)) {
|
||||||
|
return nopaint.tools[ nopaint.keys[i] ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nopaint.tools[ choice(nopaint.keys) ]
|
||||||
|
}
|
||||||
|
nopaint.regenerate_weights = function(){
|
||||||
|
nopaint.sum = 0
|
||||||
|
nopaint.weights = []
|
||||||
|
nopaint.keys = Object.keys( nopaint.tools ).sort(function(a,b){
|
||||||
|
return nopaint.tools[b].opt.weight-nopaint.tools[a].opt.weight
|
||||||
|
}).filter(function(key){
|
||||||
|
return ! nopaint.tools[key].disabled
|
||||||
|
})
|
||||||
|
nopaint.keys.forEach(function(key){
|
||||||
|
nopaint.sum += nopaint.tools[key].opt.weight
|
||||||
|
nopaint.weights.push( nopaint.sum )
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
nopaint.is_turbo = false
|
||||||
|
nopaint.turbo = function(state){
|
||||||
|
nopaint.is_turbo = typeof state == "boolean" ? state : ! nopaint.is_turbo
|
||||||
|
nopaint.delay = nopaint.is_turbo ? nopaint.turbo_delay : nopaint.normal_delay
|
||||||
|
if (nopaint.is_turbo) {
|
||||||
|
nopaint_no_el.classList.add("locked")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nopaint_no_el.classList.remove("locked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nopaint.is_autoplay = false
|
||||||
|
nopaint.autoplay = function(state){
|
||||||
|
nopaint.is_autoplay = typeof state == "boolean" ? state : ! nopaint.is_autoplay
|
||||||
|
if (nopaint.is_autoplay) {
|
||||||
|
nopaint_paint_el.classList.add("locked")
|
||||||
|
if (! nopaint.player) {
|
||||||
|
nopaint.player = new RandomPlayer ()
|
||||||
|
}
|
||||||
|
if (! nopaint.timeout) nopaint.paint()
|
||||||
|
nopaint.player.play()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nopaint_paint_el.classList.remove("locked")
|
||||||
|
nopaint.pause()
|
||||||
|
nopaint.player && nopaint.player.pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var NopaintPlayer = Model({
|
||||||
|
type: "player",
|
||||||
|
upload_png: false,
|
||||||
|
upload_interval: 100,
|
||||||
|
step: 0,
|
||||||
|
timeout: null,
|
||||||
|
delay: function(){
|
||||||
|
return nopaint.is_turbo ? randrange(150, 300) : randrange(400, 800)
|
||||||
|
},
|
||||||
|
reset: function(){
|
||||||
|
this.no_count = 0
|
||||||
|
this.paint_count = 0
|
||||||
|
},
|
||||||
|
pause: function(){
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
this.timeout = 0
|
||||||
|
},
|
||||||
|
play: function(){
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
var delay = this.delay()
|
||||||
|
this.timeout = setTimeout(this.play.bind(this), delay)
|
||||||
|
this.check_fitness()
|
||||||
|
this.step += 1
|
||||||
|
},
|
||||||
|
check_fitness: function(){
|
||||||
|
switch (this.fitness()) {
|
||||||
|
case "no":
|
||||||
|
nopaint.no_count += 1
|
||||||
|
nopaint.since_last_no = 0
|
||||||
|
nopaint.since_last_paint += 1
|
||||||
|
nopaint.no()
|
||||||
|
break
|
||||||
|
case "paint":
|
||||||
|
nopaint.paint_count += 1
|
||||||
|
nopaint.since_last_no += 1
|
||||||
|
nopaint.since_last_paint = 0
|
||||||
|
nopaint.paint()
|
||||||
|
break
|
||||||
|
case "screenshot":
|
||||||
|
if (this.save_as_png) break
|
||||||
|
console.log("uploading...")
|
||||||
|
setTimeout(clipboard.upload_png, 0)
|
||||||
|
// fall thru
|
||||||
|
default:
|
||||||
|
nopaint.since_last_no += 1
|
||||||
|
nopaint.since_last_paint += 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fitness: function(){},
|
||||||
|
})
|
||||||
|
|
||||||
|
var RandomPlayer = NopaintPlayer.extend({
|
||||||
|
type: "random_player",
|
||||||
|
upload_png: false,
|
||||||
|
fitness: function(){
|
||||||
|
var no_prob = random()
|
||||||
|
var paint_prob = 1 - no_prob
|
||||||
|
if (paint_prob < 0.3) {
|
||||||
|
return "paint"
|
||||||
|
}
|
||||||
|
else if (no_prob < 0.5) {
|
||||||
|
return "no"
|
||||||
|
}
|
||||||
|
else if ( this.paint_count > 100 && (this.step % 100) == 99 ) {
|
||||||
|
return "screenshot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var StylePlayer = NopaintPlayer.extend({
|
||||||
|
type: "style_player",
|
||||||
|
upload_png: false,
|
||||||
|
fitness: function(){
|
||||||
|
var no_prob = random()
|
||||||
|
var paint_prob = 1 - no_prob
|
||||||
|
var np, pp
|
||||||
|
var steps = this.since_last_paint
|
||||||
|
|
||||||
|
if (nopaint.tool.is_brush) {
|
||||||
|
if (nopaint.tool.is_clone) {
|
||||||
|
if (steps < randrange(3,8)) return
|
||||||
|
np = 0.3
|
||||||
|
pp = 0.4
|
||||||
|
}
|
||||||
|
else if (nopaint.tool.is_erase) {
|
||||||
|
if (steps < randrange(2,6)) return
|
||||||
|
np = 0.3
|
||||||
|
pp = 0.4
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (steps < randrange(2,4)) return
|
||||||
|
np = 0.1
|
||||||
|
pp = 0.3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nopaint.tool.is_shader) {
|
||||||
|
switch (nopaint.tool.name) {
|
||||||
|
case "rotate":
|
||||||
|
case "scale":
|
||||||
|
if (steps < randrange(2,4)) return
|
||||||
|
np = 0.1
|
||||||
|
pp = 0.2
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
np = 0.2
|
||||||
|
pp = 0.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nopaint.tool.is_fill) {
|
||||||
|
np = 0.4
|
||||||
|
pp = 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (steps > 10) {
|
||||||
|
np *= 0.7
|
||||||
|
pp *= 1.5
|
||||||
|
|
||||||
|
if (nopaint.is_turbo) {
|
||||||
|
np *= 1.2
|
||||||
|
pp *= 1.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paint_prob < np) {
|
||||||
|
return "paint"
|
||||||
|
}
|
||||||
|
else if (no_prob < np) {
|
||||||
|
return "no"
|
||||||
|
}
|
||||||
|
else if ( this.paint_count > 100 && (this.step % 100) == 99 ) {
|
||||||
|
return "screenshot"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Base models for brushes */
|
||||||
|
|
||||||
|
var NopaintTool = Model({
|
||||||
|
type: "none",
|
||||||
|
init: function(opt){
|
||||||
|
this.opt = opt || {}
|
||||||
|
},
|
||||||
|
start: function(){},
|
||||||
|
paint: function(t){},
|
||||||
|
update: function(t){},
|
||||||
|
finish: function(){},
|
||||||
|
})
|
||||||
|
|
||||||
|
var NopaintBrush = NopaintTool.extend({
|
||||||
|
type: "brush",
|
||||||
|
is_brush: true,
|
||||||
|
init: function(opt){
|
||||||
|
this.opt = opt || {}
|
||||||
|
this.opt.max_radius = this.opt.max_radius || 10
|
||||||
|
this.p = {x: randint(canvas.w), y: randint(canvas.h)}
|
||||||
|
this.fg = 0
|
||||||
|
this.bg = 1
|
||||||
|
this.char = " "
|
||||||
|
this.tweens = []
|
||||||
|
},
|
||||||
|
|
||||||
|
start: function(last_brush){
|
||||||
|
this.set_brush_mask()
|
||||||
|
this.toggle_channels()
|
||||||
|
this.reset( last_brush )
|
||||||
|
this.regenerate()
|
||||||
|
draw.down({}, null, [this.p.x, this.p.y])
|
||||||
|
},
|
||||||
|
|
||||||
|
paint: function(t){
|
||||||
|
this.update(t)
|
||||||
|
draw.move_toroidal({}, null, [this.p.x, this.p.y])
|
||||||
|
},
|
||||||
|
|
||||||
|
finish: function(){
|
||||||
|
this.tweens.forEach(function(t){ t.cancel() })
|
||||||
|
this.tweens = []
|
||||||
|
},
|
||||||
|
|
||||||
|
reorient: function(last_brush){
|
||||||
|
var a = {}, b
|
||||||
|
|
||||||
|
if (last_brush) {
|
||||||
|
this.p.x = a.x = randint(canvas.w)
|
||||||
|
this.p.y = a.y = randint(canvas.h)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a.x = this.p.x
|
||||||
|
a.y = this.p.y
|
||||||
|
}
|
||||||
|
|
||||||
|
b = this.get_next_point()
|
||||||
|
|
||||||
|
var tween = oktween.add({
|
||||||
|
obj: this.p,
|
||||||
|
from: a,
|
||||||
|
to: b,
|
||||||
|
duration: b.duration,
|
||||||
|
easing: b.easing,
|
||||||
|
update: b.update,
|
||||||
|
finished: function(){
|
||||||
|
this.iterate()
|
||||||
|
this.regenerate()
|
||||||
|
}.bind(this)
|
||||||
|
})
|
||||||
|
this.tweens.push(tween)
|
||||||
|
},
|
||||||
|
|
||||||
|
get_next_point: function(){
|
||||||
|
var radius = randrange(2, this.opt.max_radius)
|
||||||
|
var b = {}
|
||||||
|
b.duration = randrange(1, 7)
|
||||||
|
b.easing = choice(easings)
|
||||||
|
b.x = this.p.x + randrange(-radius, radius)
|
||||||
|
b.y = this.p.y + randrange(-radius, radius)
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
|
||||||
|
set_brush_mask: function(){
|
||||||
|
var r = Math.random()
|
||||||
|
if (r < 0.2) {
|
||||||
|
brush.mask = blit.square
|
||||||
|
}
|
||||||
|
else if (r < 0.6) {
|
||||||
|
brush.mask = blit.circle
|
||||||
|
}
|
||||||
|
else if (r < 0.9) {
|
||||||
|
brush.mask = blit.cross
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
brush.mask = blit.inverted_cross
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle_channels: function(){
|
||||||
|
if (Math.random() < 0.001) { controls.bg.use(false) }
|
||||||
|
else if (! brush.draw_bg && Math.random() < 0.25) { controls.bg.use(true) }
|
||||||
|
|
||||||
|
if (Math.random() < 0.1) { controls.fg.use(false) }
|
||||||
|
else if (! brush.draw_fg && Math.random() < 0.5) { controls.fg.use(true) }
|
||||||
|
|
||||||
|
if (Math.random() < 0.02) { controls.char.use(false) }
|
||||||
|
else if (! brush.draw_char && Math.random() < 0.2) { controls.char.use(true) }
|
||||||
|
},
|
||||||
|
|
||||||
|
iterate: function( last_brush ){
|
||||||
|
this.reorient( last_brush )
|
||||||
|
},
|
||||||
|
|
||||||
|
regenerate: function(){
|
||||||
|
brush.load( this )
|
||||||
|
brush.generate()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var easings = "linear circ_out circ_in circ_in_out quad_in quad_out quad_in_out".split(" ")
|
||||||
|
|
||||||
|
/* Standard brushes */
|
||||||
|
|
||||||
|
var SolidBrush = NopaintBrush.extend({
|
||||||
|
type: "solid",
|
||||||
|
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = this.bg = randint(16)
|
||||||
|
this.char = " "
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function(m,n){
|
||||||
|
m = m || 3
|
||||||
|
n = n || 0
|
||||||
|
var bw = xrandrange(5, 0, m) + n
|
||||||
|
brush.resize( round(bw * randrange(0.9, 1.8)) || 1, round(bw) || 1 )
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function( last_brush ){
|
||||||
|
this.opt.max_radius = randrange(5,20)
|
||||||
|
this.resize()
|
||||||
|
this.reorient( last_brush )
|
||||||
|
this.recolor( last_brush )
|
||||||
|
this.regenerate()
|
||||||
|
},
|
||||||
|
|
||||||
|
iterate: function( last_brush ){
|
||||||
|
this.resize()
|
||||||
|
this.reorient( last_brush )
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var EraseBrush = SolidBrush.extend({
|
||||||
|
type: "erase",
|
||||||
|
reset: function( last_brush ){
|
||||||
|
this.opt.max_radius = randrange(8, 20)
|
||||||
|
this.reorient( last_brush )
|
||||||
|
this.bg = random() < 0.2 ? colors.white : colors.black
|
||||||
|
this.char = " "
|
||||||
|
brush.load( this )
|
||||||
|
this.resize(3,2)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var ShadowBrush = NopaintBrush.extend({
|
||||||
|
type: "shadow",
|
||||||
|
pairs: [
|
||||||
|
[ colors.yellow, colors.orange ],
|
||||||
|
[ colors.orange, colors.darkred ],
|
||||||
|
[ colors.red, colors.darkred ],
|
||||||
|
[ colors.lime, colors.green ],
|
||||||
|
[ colors.cyan, colors.teal ],
|
||||||
|
[ colors.cyan, colors.blue ],
|
||||||
|
[ colors.blue, colors.darkblue ],
|
||||||
|
[ colors.magenta, colors.purple ],
|
||||||
|
[ colors.lightgray, colors.darkgray ],
|
||||||
|
[ colors.darkgray, colors.black ],
|
||||||
|
[ colors.white, colors.lightgray ],
|
||||||
|
[ colors.white, colors.black ],
|
||||||
|
],
|
||||||
|
shapes: [
|
||||||
|
[[0],[1]],
|
||||||
|
[[0,0],[1,1]],
|
||||||
|
[[1,0,0],[1,1,1]],
|
||||||
|
[[0,0,1],[1,1,1]],
|
||||||
|
[[0,0,0],[1,1,1]],
|
||||||
|
[[0,0,0,0],[1,1,1,1]],
|
||||||
|
[[1,0,0,0],[null,1,1,1]],
|
||||||
|
[[0,0,0,1],[1,1,1,null]],
|
||||||
|
[[0,0],[1,0],[1,1]],
|
||||||
|
[[0,0],[0,1],[1,1]],
|
||||||
|
],
|
||||||
|
reset: function( last_brush ){
|
||||||
|
var pair = choice(this.pairs)
|
||||||
|
var shape = choice(this.shapes)
|
||||||
|
this.reorient( last_brush )
|
||||||
|
brush.char = " "
|
||||||
|
brush.resize(shape[0].length, shape.length)
|
||||||
|
brush.generate()
|
||||||
|
brush.rebuild()
|
||||||
|
brush.forEach(function(lex,x,y){
|
||||||
|
if (shape[y][x] == null) {
|
||||||
|
lex.opacity = 0
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lex.fg = lex.bg = pair[ shape[y][x] ]
|
||||||
|
lex.opacity = 1
|
||||||
|
}
|
||||||
|
lex.build()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
regenerate: function(){},
|
||||||
|
})
|
||||||
|
|
||||||
|
var RandomBrush = SolidBrush.extend({
|
||||||
|
type: "random",
|
||||||
|
iterate: function( last_brush ){
|
||||||
|
this.reorient( last_brush )
|
||||||
|
this.recolor( last_brush )
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var HueBrush = SolidBrush.extend({
|
||||||
|
type: "hue",
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = this.bg = rand_hue()
|
||||||
|
this.char = " "
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var GrayBrush = SolidBrush.extend({
|
||||||
|
type: "gray",
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = this.bg = rand_gray()
|
||||||
|
this.char = " "
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var LetterBrush = SolidBrush.extend({
|
||||||
|
type: "letter",
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = rand_hue()
|
||||||
|
this.bg = rand_hue()
|
||||||
|
this.char = choice( unicode.block(letters.charset, 32) )
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var RandomLetterBrush = LetterBrush.extend({
|
||||||
|
type: "random-letter",
|
||||||
|
iterate: function(){
|
||||||
|
if (Math.random() < 0.01) {
|
||||||
|
this.fg += 1
|
||||||
|
}
|
||||||
|
if (Math.random() < 0.05) {
|
||||||
|
var n = this.fg
|
||||||
|
this.fg = this.bg
|
||||||
|
this.bg = n
|
||||||
|
}
|
||||||
|
if (Math.random() < 0.7) {
|
||||||
|
this.char = choice( unicode.block(letters.charset, 32) )
|
||||||
|
}
|
||||||
|
this.regenerate()
|
||||||
|
this.__iterate()
|
||||||
|
},
|
||||||
|
update: function(){
|
||||||
|
if (Math.random() < 0.3) {
|
||||||
|
this.char = choice( unicode.block(letters.charset, 32) )
|
||||||
|
}
|
||||||
|
this.regenerate()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var CloneBrush = SolidBrush.extend({
|
||||||
|
type: "clone",
|
||||||
|
|
||||||
|
is_clone: true,
|
||||||
|
|
||||||
|
reset: function( last_brush ){
|
||||||
|
this.opt.max_radius = randrange(5, 20)
|
||||||
|
this.reorient( last_brush )
|
||||||
|
this.resize(4,2)
|
||||||
|
this.clone_random_region()
|
||||||
|
},
|
||||||
|
|
||||||
|
clone_random_region: function(x, y){
|
||||||
|
var x = randrange(0, canvas.w - brush.w)
|
||||||
|
var y = randrange(0, canvas.h - brush.h)
|
||||||
|
this.clone_region(x, y)
|
||||||
|
},
|
||||||
|
|
||||||
|
clone_region: function(x, y){
|
||||||
|
blit.copy_toroidal_from(canvas, brush, round(x-brush.w/2), round(y-brush.h/2))
|
||||||
|
brush.mask(brush)
|
||||||
|
},
|
||||||
|
|
||||||
|
iterate: function( last_brush ){
|
||||||
|
this.reorient( last_brush )
|
||||||
|
},
|
||||||
|
|
||||||
|
regenerate: function(){},
|
||||||
|
})
|
||||||
|
|
||||||
|
var SmearBrush = CloneBrush.extend({
|
||||||
|
type: "smear",
|
||||||
|
|
||||||
|
update: function(){
|
||||||
|
var r = random()
|
||||||
|
var jitter_x = randnullsign() * xrand(2, 2)
|
||||||
|
var jitter_y = randnullsign() * xrand(2, 2)
|
||||||
|
this.clone_region( this.p.x + jitter_x, this.p.y + jitter_y )
|
||||||
|
},
|
||||||
|
|
||||||
|
iterate: function( last_brush ){
|
||||||
|
this.resize(4, 2)
|
||||||
|
this.update()
|
||||||
|
this.reorient( last_brush )
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var StarsTool = NopaintBrush.extend({
|
||||||
|
type: "stars",
|
||||||
|
chars: "....,,'''*",
|
||||||
|
|
||||||
|
start: function(last_brush){
|
||||||
|
this.reorient( last_brush )
|
||||||
|
},
|
||||||
|
|
||||||
|
paint: function(t){
|
||||||
|
if (Math.random() < 0.5) {
|
||||||
|
var lex = canvas.get(this.p.x, this.p.y)
|
||||||
|
undo.save_lex(lex.x, lex.y, lex)
|
||||||
|
lex.fg = rand_hue()
|
||||||
|
// lex.bg = colors.black
|
||||||
|
lex.char = choice(this.chars)
|
||||||
|
lex.build()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Fill tool */
|
||||||
|
|
||||||
|
var FillTool = NopaintTool.extend({
|
||||||
|
type: "fill",
|
||||||
|
rate: 25,
|
||||||
|
is_fill: true,
|
||||||
|
start: function(){
|
||||||
|
this.fill()
|
||||||
|
},
|
||||||
|
paint: function(t){
|
||||||
|
if ((t % this.rate) == this.rate-1) {
|
||||||
|
this.fill()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = this.bg = randint(16)
|
||||||
|
this.char = " "
|
||||||
|
this.opacity = 1
|
||||||
|
},
|
||||||
|
fill: function(){
|
||||||
|
var x = randint(canvas.w)
|
||||||
|
var y = randint(canvas.h)
|
||||||
|
this.recolor()
|
||||||
|
draw.fill(this, x, y)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var FillLetterTool = FillTool.extend({
|
||||||
|
type: "fill-letter",
|
||||||
|
rate: 25,
|
||||||
|
recolor: function(){
|
||||||
|
this.fg = randint(16)
|
||||||
|
this.bg = randint(16)
|
||||||
|
this.char = choice( unicode.block(letters.charset, 32) )
|
||||||
|
this.opacity = 1
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Shader Tools */
|
||||||
|
|
||||||
|
var ShaderTool = NopaintTool.extend({
|
||||||
|
type: "shader",
|
||||||
|
speed: 3,
|
||||||
|
is_shader: true,
|
||||||
|
is_recursive: false,
|
||||||
|
start: function(){
|
||||||
|
undo.save_rect(0, 0, canvas.w, canvas.h)
|
||||||
|
this.canvas = canvas.clone()
|
||||||
|
},
|
||||||
|
paint: function(t){
|
||||||
|
if ((t % this.speed) == 0) {
|
||||||
|
var w = canvas.w
|
||||||
|
var h = canvas.h
|
||||||
|
var lex
|
||||||
|
if (this.is_recursive) {
|
||||||
|
this.canvas.assign(canvas)
|
||||||
|
}
|
||||||
|
this.before_shade()
|
||||||
|
for (var x = 0; x < w; x++) {
|
||||||
|
for (var y = 0; y < h; y++) {
|
||||||
|
lex = canvas.get(x, y)
|
||||||
|
if (! this.shade( this.canvas, canvas, lex, x, y, w, h )) {
|
||||||
|
lex.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
before_shade: function(){},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){},
|
||||||
|
finish: function(){
|
||||||
|
this.canvas.demolish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var ColorizeTool = ShaderTool.extend({
|
||||||
|
type: "colorize",
|
||||||
|
fns: [mirc_color_reverse,hue,inv_hue,gray,fire,red,yellow,green,blue,purple,dark_gray],
|
||||||
|
speed: 5,
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
this.i = randint(this.fns.length)
|
||||||
|
},
|
||||||
|
before_shade: function(){
|
||||||
|
this.i = (this.i + 1) % this.fns.length
|
||||||
|
this.fn = this.fns[this.i]
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
lex.bg = this.fn( lex.bg )
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var TranslateTool = ShaderTool.extend({
|
||||||
|
type: "translate",
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
speed: 3,
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
this.dx = randint(3)-1
|
||||||
|
this.dy = randint(3)-1
|
||||||
|
this.x = this.y = 0
|
||||||
|
if (! this.dx && ! this.dy) {
|
||||||
|
this.dx = 1
|
||||||
|
this.dy = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
before_shade: function(){
|
||||||
|
this.x += this.dx
|
||||||
|
this.y += this.dy
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
var copy = src.get(x+this.x, y+this.y)
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var SliceTool = ShaderTool.extend({
|
||||||
|
type: "slice",
|
||||||
|
dx: 0,
|
||||||
|
dy: 0,
|
||||||
|
speed: 1,
|
||||||
|
is_recursive: true,
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
this.is_y = Math.random() > 0.3
|
||||||
|
this.limit = this.is_y ? canvas.h : canvas.w
|
||||||
|
this.position = randint(this.limit)
|
||||||
|
this.direction = 1
|
||||||
|
},
|
||||||
|
before_shade: function(){
|
||||||
|
if (Math.random() < 0.6) {
|
||||||
|
this.position = mod(this.position + 1, this.limit)
|
||||||
|
}
|
||||||
|
if (Math.random() > 0.8) {
|
||||||
|
this.direction = randsign()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
if (this.is_y) {
|
||||||
|
if (y >= this.position) {
|
||||||
|
var copy = src.get(x + this.direction, y)
|
||||||
|
lex.assign(copy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (x >= this.position) {
|
||||||
|
var copy = src.get(x, y + this.direction)
|
||||||
|
lex.assign(copy)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var ScaleTool = ShaderTool.extend({
|
||||||
|
type: "scale",
|
||||||
|
scale: 1,
|
||||||
|
dscale: 0,
|
||||||
|
speed: 3,
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
var sign = randsign()
|
||||||
|
this.x_scale = 1
|
||||||
|
this.y_scale = 1
|
||||||
|
this.dx_scale = randsign() * randrange(0.0005, 0.01)
|
||||||
|
var r = Math.random()
|
||||||
|
if (r < 0.333) {
|
||||||
|
this.dy_scale = this.dx_scale * randrange(0.85, 1.25)
|
||||||
|
}
|
||||||
|
else if (r < 0.666) {
|
||||||
|
this.dy_scale = this.dx_scale
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.dy_scale = randsign() * randrange(0.0005, 0.01)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
before_shade: function(){
|
||||||
|
this.x_scale += this.dx_scale
|
||||||
|
this.y_scale += this.dy_scale
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
x = (x/w) * 2 - 1
|
||||||
|
y = (y/h) * 2 - 1
|
||||||
|
x *= this.x_scale
|
||||||
|
y *= this.y_scale
|
||||||
|
x = (x + 1) / 2 * w
|
||||||
|
y = (y + 1) / 2 * h
|
||||||
|
var copy = src.get(x, y)
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var RotateTool = ShaderTool.extend({
|
||||||
|
type: "rotate",
|
||||||
|
theta: 0,
|
||||||
|
d_theta: 0,
|
||||||
|
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
var sign = randsign()
|
||||||
|
this.theta = 0
|
||||||
|
this.d_theta = randsign() * randrange(0.001, 0.05)
|
||||||
|
},
|
||||||
|
before_shade: function(){
|
||||||
|
this.theta += this.d_theta
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
x = (x/w) * 2 - 1
|
||||||
|
y = (y/h) * 2 - 1
|
||||||
|
var ca = cos(this.theta)
|
||||||
|
var sa = sin(this.theta)
|
||||||
|
var a = x * ca - y * sa
|
||||||
|
var b = x * sa + y * ca
|
||||||
|
x = (a + 1) / 2 * w
|
||||||
|
y = (b + 1) / 2 * h
|
||||||
|
var copy = src.get(x, y)
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
var CycleTool = ShaderTool.extend({
|
||||||
|
type: "cycle",
|
||||||
|
n: 0,
|
||||||
|
speed: 5,
|
||||||
|
is_recursive: true,
|
||||||
|
start: function(){
|
||||||
|
this.__start()
|
||||||
|
this.n = randsign()
|
||||||
|
if (random() < 0.2) this.n *= randint(15)
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y){
|
||||||
|
lex.bg += this.n
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
nopaint.add_tool( new SolidBrush({ weight: 5 }) )
|
||||||
|
nopaint.add_tool( new ShadowBrush({ weight: 10 }) )
|
||||||
|
nopaint.add_tool( new EraseBrush({ weight: 5 }) )
|
||||||
|
nopaint.add_tool( new RandomBrush({ weight: 4 }) )
|
||||||
|
nopaint.add_tool( new HueBrush({ weight: 5 }) )
|
||||||
|
nopaint.add_tool( new GrayBrush({ weight: 5 }) )
|
||||||
|
nopaint.add_tool( new LetterBrush({ weight: 2 }) )
|
||||||
|
nopaint.add_tool( new RandomLetterBrush({ weight: 12 }) )
|
||||||
|
nopaint.add_tool( new CloneBrush({ weight: 8 }) )
|
||||||
|
nopaint.add_tool( new SmearBrush({ weight: 10 }) )
|
||||||
|
nopaint.add_tool( new FillTool({ weight: 3 }) )
|
||||||
|
nopaint.add_tool( new FillLetterTool({ weight: 6 }) )
|
||||||
|
nopaint.add_tool( new StarsTool({ weight: 2 }) )
|
||||||
|
nopaint.add_tool( new TranslateTool({ weight: 4 }) )
|
||||||
|
nopaint.add_tool( new CycleTool({ weight: 1 }) )
|
||||||
|
nopaint.add_tool( new ScaleTool({ weight: 3 }) )
|
||||||
|
nopaint.add_tool( new RotateTool({ weight: 3 }) )
|
||||||
|
nopaint.add_tool( new SliceTool({ weight: 4 }) )
|
||||||
|
nopaint.add_tool( new ColorizeTool({ weight: 1 }) )
|
||||||
|
nopaint.regenerate_weights()
|
||||||
|
|
||||||
|
nopaint.toggle(true)
|
||||||
|
|
||||||
|
nopaint.player = new StylePlayer ()
|
||||||
|
|
||||||
|
return nopaint
|
||||||
|
})()
|
106
js/ui/palette.js
Normal file
106
js/ui/palette.js
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
var palette = (function(){
|
||||||
|
|
||||||
|
var palette = new Matrix (32, 2, function(x,y){
|
||||||
|
var lex = new Lex (x,y)
|
||||||
|
return lex
|
||||||
|
})
|
||||||
|
|
||||||
|
var palette_index = localStorage.getItem("ascii.palette") || 1
|
||||||
|
var palette_list = [all_hue, all_inv_hue, mirc_color, mirc_color_reverse]
|
||||||
|
var palette_fn = palette_list[palette_index]
|
||||||
|
palette.chars = " " + dither.a + dither.b + dither.c
|
||||||
|
|
||||||
|
palette.repaint = function(){
|
||||||
|
var xw = use_experimental_palette ? 5 : 2
|
||||||
|
if (canvas.vertical) {
|
||||||
|
palette.resize( xw, 16 )
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
palette.resize( 32, xw )
|
||||||
|
}
|
||||||
|
|
||||||
|
palette.forEach(function(lex,x,y){
|
||||||
|
if (canvas.vertical) { x=x^y;y=x^y;x=x^y;x*=2 }
|
||||||
|
if (y < 2) {
|
||||||
|
lex.bg = palette_fn(x>>1)
|
||||||
|
lex.fg = palette_fn(x>>1)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lex.bg = fillColor
|
||||||
|
lex.fg = palette_fn(x>>1)
|
||||||
|
}
|
||||||
|
lex.char = palette.chars[y]
|
||||||
|
lex.opacity = 1
|
||||||
|
lex.build()
|
||||||
|
if (lex.char == "_") lex.char = " "
|
||||||
|
})
|
||||||
|
}
|
||||||
|
palette.repaint()
|
||||||
|
var use_experimental_palette = false
|
||||||
|
palette.experimental = function(state){
|
||||||
|
use_experimental_palette = typeof state == "boolean" ? state : ! use_experimental_palette
|
||||||
|
use_experimental_palette ? palette.resize(32, 5) : palette.resize(32, 2)
|
||||||
|
palette.repaint()
|
||||||
|
return use_experimental_palette
|
||||||
|
}
|
||||||
|
|
||||||
|
palette.bind = function(){
|
||||||
|
palette.forEach(function(lex, x, y){
|
||||||
|
if (lex.bound) return
|
||||||
|
lex.bound = true
|
||||||
|
|
||||||
|
lex.span.addEventListener('mousedown', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
if (e.shiftKey) {
|
||||||
|
palette_index = (palette_index+1) % palette_list.length
|
||||||
|
localStorage.setItem("ascii.palette", palette_index)
|
||||||
|
palette_fn = palette_list[palette_index]
|
||||||
|
palette.repaint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (e.ctrlKey || e.which == 3) return
|
||||||
|
if (brush.char == " " && lex.char == " ") {
|
||||||
|
brush.fg = lex.fg
|
||||||
|
brush.bg = lex.bg
|
||||||
|
brush.char = lex.char
|
||||||
|
}
|
||||||
|
else if (lex.char != " ") {
|
||||||
|
brush.fg = lex.bg
|
||||||
|
brush.bg = lex.fg
|
||||||
|
brush.char = lex.char
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
brush.fg = lex.bg
|
||||||
|
brush.bg = fillColor
|
||||||
|
// brush.char = lex.char
|
||||||
|
}
|
||||||
|
brush.opacity = lex.opacity
|
||||||
|
if (! brush.modified) {
|
||||||
|
brush.generate()
|
||||||
|
}
|
||||||
|
if (filling || e.ctrlKey) {
|
||||||
|
fillColor = lex.bg
|
||||||
|
}
|
||||||
|
letters.repaint()
|
||||||
|
})
|
||||||
|
|
||||||
|
lex.span.addEventListener('contextmenu', function(e){
|
||||||
|
e.preventDefault()
|
||||||
|
fillColor = y ? lex.fg : lex.bg
|
||||||
|
palette.repaint()
|
||||||
|
brush.fg = lex.fg
|
||||||
|
brush.char = lex.char
|
||||||
|
brush.opacity = lex.opacity
|
||||||
|
brush.generate()
|
||||||
|
brush_rapper.style.borderColor = css_reverse_lookup[fillColor]
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
brush_rapper.style.borderColor = css_reverse_lookup[fillColor]
|
||||||
|
|
||||||
|
return palette
|
||||||
|
|
||||||
|
})()
|
159
js/ui/selection.js
Normal file
159
js/ui/selection.js
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
var selection = (function(){
|
||||||
|
|
||||||
|
var creating = false, moving = false, copying = false
|
||||||
|
|
||||||
|
var selection_canvas = new Matrix (1, 1, function(x,y){
|
||||||
|
var lex = new Lex (x,y)
|
||||||
|
lex.build()
|
||||||
|
return lex
|
||||||
|
})
|
||||||
|
|
||||||
|
var selector_el = document.createElement("div")
|
||||||
|
selector_el.className = "selector_el"
|
||||||
|
selection_canvas.append(selector_el)
|
||||||
|
document.body.appendChild(selector_el)
|
||||||
|
|
||||||
|
// in selection mode..
|
||||||
|
// - we start by clicking the canvas. this positions the selection, and copies
|
||||||
|
// the character
|
||||||
|
// - then we drag down and to the right. this resizes the selection and pushes new
|
||||||
|
// rows and columns. each of these copies the character underneath.
|
||||||
|
// - on mouseup, the selection is locked. then..
|
||||||
|
// - drag the selection to move it -- this "cuts" it and leaves a blank space on the canvas.
|
||||||
|
// - shift-drag the selection to copy it
|
||||||
|
|
||||||
|
var a = [0, 0]
|
||||||
|
var b = [0, 0]
|
||||||
|
var c = [0, 0]
|
||||||
|
var d = [0, 0]
|
||||||
|
|
||||||
|
function reset () {
|
||||||
|
a[0] = a[1] = b[0] = b[1] = 0
|
||||||
|
}
|
||||||
|
function left (a,b) { return min(a[0],b[0]) }
|
||||||
|
function top (a,b) { return min(a[1],b[1]) }
|
||||||
|
function right (a,b) { return max(a[0],b[0]) }
|
||||||
|
function bottom (a,b) { return max(a[1],b[1]) }
|
||||||
|
function width (a,b) { return abs(a[0]-b[0])+1 }
|
||||||
|
function height (a,b) { return abs(a[1]-b[1])+1 }
|
||||||
|
function mag_x (a,b) { return a[0]-b[0] }
|
||||||
|
function mag_y (a,b) { return a[1]-b[1] }
|
||||||
|
function orient (a,b) {
|
||||||
|
var l = left(a,b), m = top(a,b), n = right(a,b), o = bottom(a,b)
|
||||||
|
a[0] = l ; a[1] = m ; b[0] = n ; b[1] = o
|
||||||
|
}
|
||||||
|
|
||||||
|
function contains (a,b,point) {
|
||||||
|
var contains_x = a[0] <= point[0] && point[0] <= b[0]
|
||||||
|
var contains_y = a[1] <= point[1] && point[1] <= b[1]
|
||||||
|
return (contains_x && contains_y)
|
||||||
|
}
|
||||||
|
function reposition (aa, bb) {
|
||||||
|
aa = aa || a
|
||||||
|
bb = bb || b
|
||||||
|
var cell = canvas.aa[top(aa, bb)][left(aa, bb)].span
|
||||||
|
var cell_left = cell.offsetLeft
|
||||||
|
var cell_top = cell.offsetTop
|
||||||
|
var cell_width = cell.offsetWidth
|
||||||
|
var cell_height = cell.offsetHeight
|
||||||
|
|
||||||
|
var w = width(aa, bb)
|
||||||
|
var h = height(aa, bb)
|
||||||
|
|
||||||
|
selector_el.style.top = (cell_top-1) + "px"
|
||||||
|
selector_el.style.left = (cell_left-1) + "px"
|
||||||
|
selector_el.style.width = (cell_width*w+1) + "px"
|
||||||
|
selector_el.style.height = (cell_height*h+1) + "px"
|
||||||
|
}
|
||||||
|
function down (e, lex, point){
|
||||||
|
if ( ! contains(a,b,point) ) {
|
||||||
|
copying = false
|
||||||
|
moving = false
|
||||||
|
creating = true
|
||||||
|
a[0] = point[0]
|
||||||
|
a[1] = point[1]
|
||||||
|
b[0] = point[0]
|
||||||
|
b[1] = point[1]
|
||||||
|
reposition(a,b)
|
||||||
|
selection.hidden = false
|
||||||
|
selector_el.classList.add("creating")
|
||||||
|
} else {
|
||||||
|
copying = false
|
||||||
|
moving = true
|
||||||
|
creating = false
|
||||||
|
c[0] = point[0]
|
||||||
|
c[1] = point[1]
|
||||||
|
d[0] = point[0]
|
||||||
|
d[1] = point[1]
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
selector_el.classList.remove("dragging")
|
||||||
|
}
|
||||||
|
function move (e, lex, point){
|
||||||
|
if (creating) {
|
||||||
|
b[0] = point[0]
|
||||||
|
b[1] = point[1]
|
||||||
|
reposition(a,b)
|
||||||
|
}
|
||||||
|
else if (moving) {
|
||||||
|
d[0] = point[0]
|
||||||
|
d[1] = point[1]
|
||||||
|
var dx = - clamp( mag_x(c,d), b[0] - canvas.w + 1, a[0] )
|
||||||
|
var dy = - clamp( mag_y(c,d), b[1] - canvas.h + 1, a[1] )
|
||||||
|
reposition( [ a[0] + dx, a[1] + dy ], [ b[0] + dx, b[1] + dy ])
|
||||||
|
}
|
||||||
|
else if (copying) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function up (e) {
|
||||||
|
if (creating) {
|
||||||
|
orient(a,b)
|
||||||
|
selection_canvas.resize(width(a,b), height(a,b))
|
||||||
|
reposition(a,b)
|
||||||
|
blit.copy_from( canvas, selection_canvas, a[0], a[1] )
|
||||||
|
selection_canvas.build()
|
||||||
|
selector_el.classList.remove("creating")
|
||||||
|
}
|
||||||
|
if (moving) {
|
||||||
|
var dx = - clamp( mag_x(c,d), b[0] - canvas.w + 1, a[0] )
|
||||||
|
var dy = - clamp( mag_y(c,d), b[1] - canvas.h + 1, a[1] )
|
||||||
|
a[0] += dx
|
||||||
|
a[1] += dy
|
||||||
|
b[0] += dx
|
||||||
|
b[1] += dy
|
||||||
|
undo.new()
|
||||||
|
undo.save_rect(a[0], a[1], b[0] - a[0] + 1, b[1] - a[1] + 1)
|
||||||
|
blit.copy_to( canvas, selection_canvas, a[0], a[1] )
|
||||||
|
}
|
||||||
|
if (copying) {
|
||||||
|
}
|
||||||
|
creating = moving = copying = false
|
||||||
|
selector_el.classList.remove("dragging")
|
||||||
|
}
|
||||||
|
|
||||||
|
function show () {
|
||||||
|
selecting = true
|
||||||
|
}
|
||||||
|
function hide () {
|
||||||
|
reset()
|
||||||
|
selector_el.style.top = "-9999px"
|
||||||
|
selector_el.style.left = "-9999px"
|
||||||
|
selector_el.style.width = "0px"
|
||||||
|
selector_el.style.height = "0px"
|
||||||
|
creating = moving = copying = false
|
||||||
|
selection.hidden = true
|
||||||
|
selecting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
var selection = {}
|
||||||
|
selection.reposition = reposition
|
||||||
|
selection.down = down
|
||||||
|
selection.move = move
|
||||||
|
selection.up = up
|
||||||
|
selection.canvas = selection_canvas
|
||||||
|
selection.show = show
|
||||||
|
selection.hide = hide
|
||||||
|
selection.hidden = true
|
||||||
|
return selection
|
||||||
|
|
||||||
|
})()
|
176
js/ui/transform.js
Normal file
176
js/ui/transform.js
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
var transform = (function(){
|
||||||
|
|
||||||
|
var p = [0,0], q = [0,0]
|
||||||
|
var mode
|
||||||
|
var copy
|
||||||
|
|
||||||
|
function down (e, lex, point){
|
||||||
|
p[0] = point[0]
|
||||||
|
p[1] = point[1]
|
||||||
|
q[0] = e.pageX
|
||||||
|
q[1] = e.pageY
|
||||||
|
undo.new()
|
||||||
|
undo.save_rect(0, 0, canvas.w, canvas.h)
|
||||||
|
copy = canvas.clone()
|
||||||
|
mode.init(e)
|
||||||
|
}
|
||||||
|
function move (e, lex, point){
|
||||||
|
var pdx = point[0] - p[0]
|
||||||
|
var pdy = point[1] - p[1]
|
||||||
|
var dx = e.pageX - q[0]
|
||||||
|
var dy = e.pageY - q[1]
|
||||||
|
var w = canvas.w
|
||||||
|
var h = canvas.h
|
||||||
|
mode.before(dx, dy, pdx, pdy, point)
|
||||||
|
for (var x = 0; x < w; x++) {
|
||||||
|
for (var y = 0; y < h; y++) {
|
||||||
|
lex = canvas.get(x, y)
|
||||||
|
if (! mode.shade( copy, canvas, lex, x, y, w, h )) {
|
||||||
|
lex.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function up (e){
|
||||||
|
}
|
||||||
|
|
||||||
|
var modes = {
|
||||||
|
|
||||||
|
rotate: {
|
||||||
|
init: function(e){
|
||||||
|
mode.theta = 0
|
||||||
|
},
|
||||||
|
before: function(dx, dy){
|
||||||
|
var radius = dist(0, 0, dx, dy)
|
||||||
|
if (radius < 10) return
|
||||||
|
mode.theta = angle(0, 0, dx, -dy)
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
x = (x/w) * 2 - 1
|
||||||
|
y = (y/h) * 2 - 1
|
||||||
|
var ca = cos(mode.theta)
|
||||||
|
var sa = sin(mode.theta)
|
||||||
|
var a = x * ca - y * sa
|
||||||
|
var b = x * sa + y * ca
|
||||||
|
x = (a + 1) / 2 * w
|
||||||
|
y = (b + 1) / 2 * h
|
||||||
|
var copy = src.get(x, y)
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
scale: {
|
||||||
|
init: function(e){
|
||||||
|
mode.independent = e.shiftKey || e.altKey || e.metaKey
|
||||||
|
mode.x_scale = mode.y_scale = 0
|
||||||
|
},
|
||||||
|
before: function(dx, dy, pdx, pdy){
|
||||||
|
if (mode.independent) {
|
||||||
|
mode.x_scale = Math.pow(2, -pdx / (canvas.w / 8))
|
||||||
|
mode.y_scale = Math.pow(2, -pdy / (canvas.h / 8))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mode.x_scale = mode.y_scale = Math.pow(2, -pdx / (canvas.w / 8))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
x = ((x-p[0])/w) * 2 - 1
|
||||||
|
y = ((y-p[1])/h) * 2 - 1
|
||||||
|
x *= mode.x_scale
|
||||||
|
y *= mode.y_scale
|
||||||
|
x = (x + 1) / 2 * w
|
||||||
|
y = (y + 1) / 2 * h
|
||||||
|
var copy = src.get(x+p[0], y+p[1])
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
translate: {
|
||||||
|
init: function(e){
|
||||||
|
mode.dx = mode.dy = 0
|
||||||
|
},
|
||||||
|
before: function(dx, dy, pdx, pdy){
|
||||||
|
mode.dx = -pdx
|
||||||
|
mode.dy = -pdy
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
var copy = src.get(x+mode.dx, y+mode.dy)
|
||||||
|
lex.assign(copy)
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
slice: {
|
||||||
|
init: function(e){
|
||||||
|
mode.is_y = ! (e.altKey || e.metaKey)
|
||||||
|
mode.reverse = !! (e.shiftKey)
|
||||||
|
mode.position = 0
|
||||||
|
mode.direction = 0
|
||||||
|
mode.last_dd = -1
|
||||||
|
},
|
||||||
|
before: function(dx, dy, pdx, pdy, point){
|
||||||
|
var new_position = mode.is_y ? point[1] : point[0]
|
||||||
|
var dd = mode.is_y ? pdx : pdy
|
||||||
|
|
||||||
|
if (mode.position !== new_position) {
|
||||||
|
mode.position = new_position
|
||||||
|
mode.direction = 0
|
||||||
|
}
|
||||||
|
if (mode.last_dd !== -1) {
|
||||||
|
mode.direction = mode.last_dd - dd
|
||||||
|
}
|
||||||
|
console.log(mode.position)
|
||||||
|
mode.last_dd = dd
|
||||||
|
copy.assign(canvas)
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
if (mode.is_y) {
|
||||||
|
if (y >= mode.position || (mode.reverse && mode.position >= y)) {
|
||||||
|
var copy = src.get(x + mode.direction, y)
|
||||||
|
lex.assign(copy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (x >= mode.position || (mode.reverse && mode.position >= x)) {
|
||||||
|
var copy = src.get(x, y + mode.direction)
|
||||||
|
lex.assign(copy)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
mode: {
|
||||||
|
init: function(e){
|
||||||
|
},
|
||||||
|
before: function(dx, dy, pdx, pdy){
|
||||||
|
},
|
||||||
|
shade: function(src, dest, lex, x, y, w, h){
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mode(m){
|
||||||
|
if (m in modes) {
|
||||||
|
mode = modes[m]
|
||||||
|
transforming = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function done(){
|
||||||
|
transforming = false
|
||||||
|
copy && copy.demolish()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
down: down,
|
||||||
|
move: move,
|
||||||
|
up: up,
|
||||||
|
set_mode: set_mode,
|
||||||
|
modes: modes,
|
||||||
|
done: done,
|
||||||
|
}
|
||||||
|
|
||||||
|
})()
|
227
js/undo.js
Normal file
227
js/undo.js
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
var undo = (function(){
|
||||||
|
|
||||||
|
var max_states = 200;
|
||||||
|
|
||||||
|
// undotimetotal = 0;
|
||||||
|
|
||||||
|
var stack = {undo: [], redo: []};
|
||||||
|
var current_undo = null;
|
||||||
|
var dom = {undo: undo_el, redo: redo_el};
|
||||||
|
dom.undo.is_visible = dom.redo.is_visible = false
|
||||||
|
|
||||||
|
var LexState = function(lex){
|
||||||
|
this.fg = lex.fg;
|
||||||
|
this.bg = lex.bg;
|
||||||
|
this.char = lex.char;
|
||||||
|
this.opacity = lex.opacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
var update_dom_visibility = function(type){
|
||||||
|
var el = dom[type]
|
||||||
|
if (el.is_visible){
|
||||||
|
if (stack[type].length === 0) {
|
||||||
|
el.classList.add('hidden')
|
||||||
|
el.is_visible = false
|
||||||
|
}
|
||||||
|
} else if (stack[type].length > 0){
|
||||||
|
el.classList.remove('hidden')
|
||||||
|
el.is_visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var update_dom = function(){
|
||||||
|
update_dom_visibility('undo')
|
||||||
|
update_dom_visibility('redo')
|
||||||
|
}
|
||||||
|
|
||||||
|
// state is an undo or redo state that might contain these props
|
||||||
|
// { lexs: {'0,0': LexState, ...}, // for sparse lex changes (eg brush, fill)
|
||||||
|
// focus: {x:, y: },
|
||||||
|
// size: {w:, h: },
|
||||||
|
// rects: [{x:, y:, w:, h:, lexs: [LexState, ...]}, ...]
|
||||||
|
// }
|
||||||
|
var new_state = function(){
|
||||||
|
var state = {lexs:{}};
|
||||||
|
save_focus(canvas.focus_x, canvas.focus_y, state)
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
var new_redo = function(){
|
||||||
|
return new_state()
|
||||||
|
}
|
||||||
|
var new_undo = function(){
|
||||||
|
current_undo = new_state()
|
||||||
|
stack.redo = []
|
||||||
|
stack.undo.push(current_undo)
|
||||||
|
if (stack.undo.length > max_states) stack.undo.shift();
|
||||||
|
update_dom()
|
||||||
|
return current_undo
|
||||||
|
}
|
||||||
|
|
||||||
|
var save_focus = function(x, y, state){
|
||||||
|
state = state || current_undo
|
||||||
|
state.focus = {x:x, y:y}
|
||||||
|
}
|
||||||
|
var save_size = function(w, h, state){
|
||||||
|
state = state || current_undo
|
||||||
|
state.size = {w:w, h:h};
|
||||||
|
}
|
||||||
|
// the reason for stringifying the x y coords is so that each
|
||||||
|
// coordinate is saved only once in an undo state.
|
||||||
|
// otherwise there would be problems with, eg, a brush stroke
|
||||||
|
// that passed over the same grid cell twice.
|
||||||
|
var save_lex = function(x, y, lex, state){
|
||||||
|
// var start = Date.now()
|
||||||
|
state = state || current_undo
|
||||||
|
var lexs = state.lexs;
|
||||||
|
var xy = x + "," + y;
|
||||||
|
if (xy in lexs) return;
|
||||||
|
lexs[xy] = new LexState(lex)
|
||||||
|
// undotimetotal += Date.now() - start
|
||||||
|
}
|
||||||
|
var save_focused_lex = function(state){
|
||||||
|
state = state || current_undo
|
||||||
|
var x = canvas.focus_x
|
||||||
|
var y = canvas.focus_y
|
||||||
|
save_lex(x, y, canvas.aa[y][x], state)
|
||||||
|
}
|
||||||
|
var save_rect = function(xpos, ypos, w, h, state){
|
||||||
|
if (w === 0 || h === 0) return;
|
||||||
|
state = state || current_undo;
|
||||||
|
state.rects = state.rects || []
|
||||||
|
var aa = canvas.aa;
|
||||||
|
var rect = {x: xpos, y: ypos, w: w, h: h, lexs: []}
|
||||||
|
var lexs = rect.lexs
|
||||||
|
var xlen = xpos + w
|
||||||
|
var ylen = ypos + h
|
||||||
|
for (var y = ypos; y < ylen; y++){
|
||||||
|
var aay = aa[y]
|
||||||
|
for (var x = xpos; x < xlen; x++){
|
||||||
|
lexs.push(new LexState(aay[x]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.rects.push(rect)
|
||||||
|
}
|
||||||
|
var save_resize = function(w, h, old_w, old_h, state){
|
||||||
|
state = state || current_undo
|
||||||
|
save_size(old_w, old_h, state)
|
||||||
|
if (old_w > w){
|
||||||
|
// .---XX
|
||||||
|
// | XX
|
||||||
|
// |___XX
|
||||||
|
save_rect(w, 0, old_w - w, old_h, state)
|
||||||
|
if (old_h > h){
|
||||||
|
// .----.
|
||||||
|
// | |
|
||||||
|
// XXXX_|
|
||||||
|
save_rect(0, h, w, old_h - h, state)
|
||||||
|
}
|
||||||
|
} else if (old_h > h){
|
||||||
|
// .----.
|
||||||
|
// | |
|
||||||
|
// XXXXXX
|
||||||
|
save_rect(0, h, old_w, old_h - h, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var restore_state = function(state){
|
||||||
|
// all redo states will have a cached undo state on them
|
||||||
|
// an undo state might have a cached redo state
|
||||||
|
// if it doesn't have one, generate one
|
||||||
|
var make_redo = ! ('redo' in state || 'undo' in state);
|
||||||
|
var aa = canvas.aa
|
||||||
|
var lex, lexs;
|
||||||
|
|
||||||
|
if (make_redo){
|
||||||
|
state.redo = new_redo()
|
||||||
|
|
||||||
|
// copy saved rects that intersect with current canvas size
|
||||||
|
// important to do this before resizing canvas
|
||||||
|
if ('rects' in state){
|
||||||
|
for (var ri=0, rect; rect=state.rects[ri]; ri++){
|
||||||
|
if (rect.x >= canvas.w ||
|
||||||
|
rect.y >= canvas.h) continue;
|
||||||
|
var w = Math.min(rect.w, canvas.w - rect.x)
|
||||||
|
var h = Math.min(rect.h, canvas.h - rect.y)
|
||||||
|
save_rect(rect.x, rect.y, w, h, state.redo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('size' in state){
|
||||||
|
save_resize(state.size.w, state.size.h, canvas.w, canvas.h, state.redo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('size' in state){
|
||||||
|
canvas.resize(state.size.w, state.size.h, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('rects' in state){
|
||||||
|
for (var ri=0, rect; rect=state.rects[ri]; ri++){
|
||||||
|
lexs = rect.lexs
|
||||||
|
for (var li=0; lex=lexs[li]; li++){
|
||||||
|
var x = (li % rect.w) + rect.x
|
||||||
|
var y = ((li / rect.w)|0) + rect.y
|
||||||
|
aa[y][x].assign(lex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lexs = state.lexs
|
||||||
|
for (var key in lexs){
|
||||||
|
var xy = key.split(',');
|
||||||
|
lex = aa[xy[1]][xy[0]]
|
||||||
|
if (make_redo)
|
||||||
|
save_lex(xy[0], xy[1], lex, state.redo)
|
||||||
|
lex.assign(lexs[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('focus' in state){
|
||||||
|
canvas.focus_x = state.focus.x
|
||||||
|
canvas.focus_y = state.focus.y
|
||||||
|
if (current_canvas === canvas){
|
||||||
|
canvas.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var undo = function(){
|
||||||
|
var state = stack.undo.pop();
|
||||||
|
if (!state) return;
|
||||||
|
|
||||||
|
restore_state(state)
|
||||||
|
|
||||||
|
// now take the applied undo state and store it on the redo state
|
||||||
|
// and push the redo state to the redo stack
|
||||||
|
state.redo.undo = state
|
||||||
|
stack.redo.push(state.redo)
|
||||||
|
delete state.redo
|
||||||
|
|
||||||
|
update_dom()
|
||||||
|
}
|
||||||
|
|
||||||
|
var redo = function(){
|
||||||
|
var state = stack.redo.pop();
|
||||||
|
if (!state) return;
|
||||||
|
|
||||||
|
restore_state(state)
|
||||||
|
|
||||||
|
state.undo.redo = state
|
||||||
|
stack.undo.push(state.undo)
|
||||||
|
delete state.undo
|
||||||
|
|
||||||
|
update_dom()
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
stack: stack,
|
||||||
|
new: new_undo,
|
||||||
|
// new_redo: new_redo,
|
||||||
|
save_focus: save_focus,
|
||||||
|
save_size: save_size,
|
||||||
|
save_lex: save_lex,
|
||||||
|
save_focused_lex: save_focused_lex,
|
||||||
|
save_rect: save_rect,
|
||||||
|
save_resize: save_resize,
|
||||||
|
undo: undo,
|
||||||
|
redo: redo
|
||||||
|
}
|
||||||
|
|
||||||
|
})()
|
543
js/unicode.js
Normal file
543
js/unicode.js
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
var unicode = (function(){
|
||||||
|
var UNICODE_BLOCK_LIST = [
|
||||||
|
0x0020, 0x007F, "Basic Latin",
|
||||||
|
0x0080, 0x00FF, "Latin-1 Supplement",
|
||||||
|
0x0100, 0x017F, "Latin Extended-A",
|
||||||
|
0x0180, 0x024F, "Latin Extended-B",
|
||||||
|
0x0250, 0x02AF, "IPA Extensions",
|
||||||
|
0x02B0, 0x02FF, "Spacing Modifier Letters",
|
||||||
|
0x0300, 0x036F, "Combining Diacritical Marks",
|
||||||
|
0x0370, 0x03FF, "Greek and Coptic",
|
||||||
|
0x0400, 0x04FF, "Cyrillic",
|
||||||
|
0x0500, 0x052F, "Cyrillic Supplement",
|
||||||
|
0x0530, 0x058F, "Armenian",
|
||||||
|
0x0590, 0x05FF, "Hebrew",
|
||||||
|
0x0600, 0x06FF, "Arabic",
|
||||||
|
0x0700, 0x074F, "Syriac",
|
||||||
|
0x0750, 0x077F, "Arabic Supplement",
|
||||||
|
0x0780, 0x07BF, "Thaana",
|
||||||
|
0x07C0, 0x07FF, "NKo",
|
||||||
|
0x0800, 0x083F, "Samaritan",
|
||||||
|
0x0840, 0x085F, "Mandaic",
|
||||||
|
0x08A0, 0x08FF, "Arabic Extended-A",
|
||||||
|
0x0900, 0x097F, "Devanagari",
|
||||||
|
0x0980, 0x09FF, "Bengali",
|
||||||
|
0x0A00, 0x0A7F, "Gurmukhi",
|
||||||
|
0x0A80, 0x0AFF, "Gujarati",
|
||||||
|
0x0B00, 0x0B7F, "Oriya",
|
||||||
|
0x0B80, 0x0BFF, "Tamil",
|
||||||
|
0x0C00, 0x0C7F, "Telugu",
|
||||||
|
0x0C80, 0x0CFF, "Kannada",
|
||||||
|
0x0D00, 0x0D7F, "Malayalam",
|
||||||
|
0x0D80, 0x0DFF, "Sinhala",
|
||||||
|
0x0E00, 0x0E7F, "Thai",
|
||||||
|
0x0E80, 0x0EFF, "Lao",
|
||||||
|
0x0F00, 0x0FFF, "Tibetan",
|
||||||
|
0x1000, 0x109F, "Myanmar",
|
||||||
|
0x10A0, 0x10FF, "Georgian",
|
||||||
|
0x1100, 0x11FF, "Hangul Jamo",
|
||||||
|
0x1200, 0x137F, "Ethiopic",
|
||||||
|
0x1380, 0x139F, "Ethiopic Supplement",
|
||||||
|
0x13A0, 0x13FF, "Cherokee",
|
||||||
|
0x1400, 0x167F, "Unified Canadian Aboriginal Syllabics",
|
||||||
|
0x1680, 0x169F, "Ogham",
|
||||||
|
0x16A0, 0x16FF, "Runic",
|
||||||
|
0x1700, 0x171F, "Tagalog",
|
||||||
|
0x1720, 0x173F, "Hanunoo",
|
||||||
|
0x1740, 0x175F, "Buhid",
|
||||||
|
0x1760, 0x177F, "Tagbanwa",
|
||||||
|
0x1780, 0x17FF, "Khmer",
|
||||||
|
0x1800, 0x18AF, "Mongolian",
|
||||||
|
0x18B0, 0x18FF, "Unified Canadian Aboriginal Syllabics Extended",
|
||||||
|
0x1900, 0x194F, "Limbu",
|
||||||
|
0x1950, 0x197F, "Tai Le",
|
||||||
|
0x1980, 0x19DF, "New Tai Lue",
|
||||||
|
0x19E0, 0x19FF, "Khmer Symbols",
|
||||||
|
0x1A00, 0x1A1F, "Buginese",
|
||||||
|
0x1A20, 0x1AAF, "Tai Tham",
|
||||||
|
0x1AB0, 0x1AFF, "Combining Diacritical Marks Extended",
|
||||||
|
0x1B00, 0x1B7F, "Balinese",
|
||||||
|
0x1B80, 0x1BBF, "Sundanese",
|
||||||
|
0x1BC0, 0x1BFF, "Batak",
|
||||||
|
0x1C00, 0x1C4F, "Lepcha",
|
||||||
|
0x1C50, 0x1C7F, "Ol Chiki",
|
||||||
|
0x1CC0, 0x1CCF, "Sundanese Supplement",
|
||||||
|
0x1CD0, 0x1CFF, "Vedic Extensions",
|
||||||
|
0x1D00, 0x1D7F, "Phonetic Extensions",
|
||||||
|
0x1D80, 0x1DBF, "Phonetic Extensions Supplement",
|
||||||
|
0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement",
|
||||||
|
0x1E00, 0x1EFF, "Latin Extended Additional",
|
||||||
|
0x1F00, 0x1FFF, "Greek Extended",
|
||||||
|
0x2000, 0x206F, "General Punctuation",
|
||||||
|
0x2070, 0x209F, "Superscripts and Subscripts",
|
||||||
|
0x20A0, 0x20CF, "Currency Symbols",
|
||||||
|
0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols",
|
||||||
|
0x2100, 0x214F, "Letterlike Symbols",
|
||||||
|
0x2150, 0x218F, "Number Forms",
|
||||||
|
0x2190, 0x21FF, "Arrows",
|
||||||
|
0x2200, 0x22FF, "Mathematical Operators",
|
||||||
|
0x2300, 0x23FF, "Miscellaneous Technical",
|
||||||
|
0x2400, 0x243F, "Control Pictures",
|
||||||
|
0x2440, 0x245F, "Optical Character Recognition",
|
||||||
|
0x2460, 0x24FF, "Enclosed Alphanumerics",
|
||||||
|
0x2500, 0x257F, "Box Drawing",
|
||||||
|
0x2580, 0x259F, "Block Elements",
|
||||||
|
0x25A0, 0x25FF, "Geometric Shapes",
|
||||||
|
0x2600, 0x26FF, "Miscellaneous Symbols",
|
||||||
|
0x2700, 0x27BF, "Dingbats",
|
||||||
|
0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A",
|
||||||
|
0x27F0, 0x27FF, "Supplemental Arrows-A",
|
||||||
|
0x2800, 0x28FF, "Braille Patterns",
|
||||||
|
0x2900, 0x297F, "Supplemental Arrows-B",
|
||||||
|
0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B",
|
||||||
|
0x2A00, 0x2AFF, "Supplemental Mathematical Operators",
|
||||||
|
0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows",
|
||||||
|
0x2C00, 0x2C5F, "Glagolitic",
|
||||||
|
0x2C60, 0x2C7F, "Latin Extended-C",
|
||||||
|
0x2C80, 0x2CFF, "Coptic",
|
||||||
|
0x2D00, 0x2D2F, "Georgian Supplement",
|
||||||
|
0x2D30, 0x2D7F, "Tifinagh",
|
||||||
|
0x2D80, 0x2DDF, "Ethiopic Extended",
|
||||||
|
0x2DE0, 0x2DFF, "Cyrillic Extended-A",
|
||||||
|
0x2E00, 0x2E7F, "Supplemental Punctuation",
|
||||||
|
0x2E80, 0x2EFF, "CJK Radicals Supplement",
|
||||||
|
0x2F00, 0x2FDF, "Kangxi Radicals",
|
||||||
|
0x2FF0, 0x2FFF, "Ideographic Description Characters",
|
||||||
|
0x3000, 0x303F, "CJK Symbols and Punctuation",
|
||||||
|
0x3040, 0x309F, "Hiragana",
|
||||||
|
0x30A0, 0x30FF, "Katakana",
|
||||||
|
0x3100, 0x312F, "Bopomofo",
|
||||||
|
0x3130, 0x318F, "Hangul Compatibility Jamo",
|
||||||
|
0x3190, 0x319F, "Kanbun",
|
||||||
|
0x31A0, 0x31BF, "Bopomofo Extended",
|
||||||
|
0x31C0, 0x31EF, "CJK Strokes",
|
||||||
|
0x31F0, 0x31FF, "Katakana Phonetic Extensions",
|
||||||
|
0x3200, 0x32FF, "Enclosed CJK Letters and Months",
|
||||||
|
0x3300, 0x33FF, "CJK Compatibility",
|
||||||
|
0x3400, 0x4DBF, "CJK Unified Ideographs Extension A",
|
||||||
|
0x4DC0, 0x4DFF, "Yijing Hexagram Symbols",
|
||||||
|
0x4E00, 0x9FFF, "CJK Unified Ideographs",
|
||||||
|
0xA000, 0xA48F, "Yi Syllables",
|
||||||
|
0xA490, 0xA4CF, "Yi Radicals",
|
||||||
|
0xA4D0, 0xA4FF, "Lisu",
|
||||||
|
0xA500, 0xA63F, "Vai",
|
||||||
|
0xA640, 0xA69F, "Cyrillic Extended-B",
|
||||||
|
0xA6A0, 0xA6FF, "Bamum",
|
||||||
|
0xA700, 0xA71F, "Modifier Tone Letters",
|
||||||
|
0xA720, 0xA7FF, "Latin Extended-D",
|
||||||
|
0xA800, 0xA82F, "Syloti Nagri",
|
||||||
|
0xA830, 0xA83F, "Common Indic Number Forms",
|
||||||
|
0xA840, 0xA87F, "Phags-pa",
|
||||||
|
0xA880, 0xA8DF, "Saurashtra",
|
||||||
|
0xA8E0, 0xA8FF, "Devanagari Extended",
|
||||||
|
0xA900, 0xA92F, "Kayah Li",
|
||||||
|
0xA930, 0xA95F, "Rejang",
|
||||||
|
0xA960, 0xA97F, "Hangul Jamo Extended-A",
|
||||||
|
0xA980, 0xA9DF, "Javanese",
|
||||||
|
0xA9E0, 0xA9FF, "Myanmar Extended-B",
|
||||||
|
0xAA00, 0xAA5F, "Cham",
|
||||||
|
0xAA60, 0xAA7F, "Myanmar Extended-A",
|
||||||
|
0xAA80, 0xAADF, "Tai Viet",
|
||||||
|
0xAAE0, 0xAAFF, "Meetei Mayek Extensions",
|
||||||
|
0xAB00, 0xAB2F, "Ethiopic Extended-A",
|
||||||
|
0xAB30, 0xAB6F, "Latin Extended-E",
|
||||||
|
0xABC0, 0xABFF, "Meetei Mayek",
|
||||||
|
0xAC00, 0xD7AF, "Hangul Syllables",
|
||||||
|
0xD7B0, 0xD7FF, "Hangul Jamo Extended-B",
|
||||||
|
0xD800, 0xDB7F, "High Surrogates",
|
||||||
|
0xDB80, 0xDBFF, "High Private Use Surrogates",
|
||||||
|
0xDC00, 0xDFFF, "Low Surrogates",
|
||||||
|
0xE000, 0xF8FF, "Private Use Area",
|
||||||
|
0xF900, 0xFAFF, "CJK Compatibility Ideographs",
|
||||||
|
0xFB00, 0xFB4F, "Alphabetic Presentation Forms",
|
||||||
|
0xFB50, 0xFDFF, "Arabic Presentation Forms-A",
|
||||||
|
0xFE00, 0xFE0F, "Variation Selectors",
|
||||||
|
0xFE10, 0xFE1F, "Vertical Forms",
|
||||||
|
0xFE20, 0xFE2F, "Combining Half Marks",
|
||||||
|
0xFE30, 0xFE4F, "CJK Compatibility Forms",
|
||||||
|
0xFE50, 0xFE6F, "Small Form Variants",
|
||||||
|
0xFE70, 0xFEFF, "Arabic Presentation Forms-B",
|
||||||
|
0xFF00, 0xFFEF, "Halfwidth and Fullwidth Forms",
|
||||||
|
0xFFF0, 0xFFFF, "Specials",
|
||||||
|
0x10000, 0x1007F, "Linear B Syllabary",
|
||||||
|
0x10080, 0x100FF, "Linear B Ideograms",
|
||||||
|
0x10100, 0x1013F, "Aegean Numbers",
|
||||||
|
0x10140, 0x1018F, "Ancient Greek Numbers",
|
||||||
|
0x10190, 0x101CF, "Ancient Symbols",
|
||||||
|
0x101D0, 0x101FF, "Phaistos Disc",
|
||||||
|
0x10280, 0x1029F, "Lycian",
|
||||||
|
0x102A0, 0x102DF, "Carian",
|
||||||
|
0x102E0, 0x102FF, "Coptic Epact Numbers",
|
||||||
|
0x10300, 0x1032F, "Old Italic",
|
||||||
|
0x10330, 0x1034F, "Gothic",
|
||||||
|
0x10350, 0x1037F, "Old Permic",
|
||||||
|
0x10380, 0x1039F, "Ugaritic",
|
||||||
|
0x103A0, 0x103DF, "Old Persian",
|
||||||
|
0x10400, 0x1044F, "Deseret",
|
||||||
|
0x10450, 0x1047F, "Shavian",
|
||||||
|
0x10480, 0x104AF, "Osmanya",
|
||||||
|
0x10500, 0x1052F, "Elbasan",
|
||||||
|
0x10530, 0x1056F, "Caucasian Albanian",
|
||||||
|
0x10600, 0x1077F, "Linear A",
|
||||||
|
0x10800, 0x1083F, "Cypriot Syllabary",
|
||||||
|
0x10840, 0x1085F, "Imperial Aramaic",
|
||||||
|
0x10860, 0x1087F, "Palmyrene",
|
||||||
|
0x10880, 0x108AF, "Nabataean",
|
||||||
|
0x10900, 0x1091F, "Phoenician",
|
||||||
|
0x10920, 0x1093F, "Lydian",
|
||||||
|
0x10980, 0x1099F, "Meroitic Hieroglyphs",
|
||||||
|
0x109A0, 0x109FF, "Meroitic Cursive",
|
||||||
|
0x10A00, 0x10A5F, "Kharoshthi",
|
||||||
|
0x10A60, 0x10A7F, "Old South Arabian",
|
||||||
|
0x10A80, 0x10A9F, "Old North Arabian",
|
||||||
|
0x10AC0, 0x10AFF, "Manichaean",
|
||||||
|
0x10B00, 0x10B3F, "Avestan",
|
||||||
|
0x10B40, 0x10B5F, "Inscriptional Parthian",
|
||||||
|
0x10B60, 0x10B7F, "Inscriptional Pahlavi",
|
||||||
|
0x10B80, 0x10BAF, "Psalter Pahlavi",
|
||||||
|
0x10C00, 0x10C4F, "Old Turkic",
|
||||||
|
0x10E60, 0x10E7F, "Rumi Numeral Symbols",
|
||||||
|
0x11000, 0x1107F, "Brahmi",
|
||||||
|
0x11080, 0x110CF, "Kaithi",
|
||||||
|
0x110D0, 0x110FF, "Sora Sompeng",
|
||||||
|
0x11100, 0x1114F, "Chakma",
|
||||||
|
0x11150, 0x1117F, "Mahajani",
|
||||||
|
0x11180, 0x111DF, "Sharada",
|
||||||
|
0x111E0, 0x111FF, "Sinhala Archaic Numbers",
|
||||||
|
0x11200, 0x1124F, "Khojki",
|
||||||
|
0x112B0, 0x112FF, "Khudawadi",
|
||||||
|
0x11300, 0x1137F, "Grantha",
|
||||||
|
0x11480, 0x114DF, "Tirhuta",
|
||||||
|
0x11580, 0x115FF, "Siddham",
|
||||||
|
0x11600, 0x1165F, "Modi",
|
||||||
|
0x11680, 0x116CF, "Takri",
|
||||||
|
0x118A0, 0x118FF, "Warang Citi",
|
||||||
|
0x11AC0, 0x11AFF, "Pau Cin Hau",
|
||||||
|
0x12000, 0x123FF, "Cuneiform",
|
||||||
|
0x12400, 0x1247F, "Cuneiform Numbers and Punctuation",
|
||||||
|
0x13000, 0x1342F, "Egyptian Hieroglyphs",
|
||||||
|
0x16800, 0x16A3F, "Bamum Supplement",
|
||||||
|
0x16A40, 0x16A6F, "Mro",
|
||||||
|
0x16AD0, 0x16AFF, "Bassa Vah",
|
||||||
|
0x16B00, 0x16B8F, "Pahawh Hmong",
|
||||||
|
0x16F00, 0x16F9F, "Miao",
|
||||||
|
0x1B000, 0x1B0FF, "Kana Supplement",
|
||||||
|
0x1BC00, 0x1BC9F, "Duployan",
|
||||||
|
0x1BCA0, 0x1BCAF, "Shorthand Format Controls",
|
||||||
|
0x1D000, 0x1D0FF, "Byzantine Musical Symbols",
|
||||||
|
0x1D100, 0x1D1FF, "Musical Symbols",
|
||||||
|
0x1D200, 0x1D24F, "Ancient Greek Musical Notation",
|
||||||
|
0x1D300, 0x1D35F, "Tai Xuan Jing Symbols",
|
||||||
|
0x1D360, 0x1D37F, "Counting Rod Numerals",
|
||||||
|
0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols",
|
||||||
|
0x1E800, 0x1E8DF, "Mende Kikakui",
|
||||||
|
0x1EE00, 0x1EEFF, "Arabic Mathematical Alphabetic Symbols",
|
||||||
|
0x1F000, 0x1F02F, "Mahjong Tiles",
|
||||||
|
0x1F030, 0x1F09F, "Domino Tiles",
|
||||||
|
0x1F0A0, 0x1F0FF, "Playing Cards",
|
||||||
|
0x1F100, 0x1F1FF, "Enclosed Alphanumeric Supplement",
|
||||||
|
0x1F200, 0x1F2FF, "Enclosed Ideographic Supplement",
|
||||||
|
0x1F300, 0x1F5FF, "Miscellaneous Symbols and Pictographs",
|
||||||
|
0x1F600, 0x1F64F, "Emoticons",
|
||||||
|
0x1F650, 0x1F67F, "Ornamental Dingbats",
|
||||||
|
0x1F680, 0x1F6FF, "Transport and Map Symbols",
|
||||||
|
0x1F700, 0x1F77F, "Alchemical Symbols",
|
||||||
|
0x1F780, 0x1F7FF, "Geometric Shapes Extended",
|
||||||
|
0x1F800, 0x1F8FF, "Supplemental Arrows-C",
|
||||||
|
0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B",
|
||||||
|
0x2A700, 0x2B73F, "CJK Unified Ideographs Extension C",
|
||||||
|
0x2B740, 0x2B81F, "CJK Unified Ideographs Extension D",
|
||||||
|
0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement",
|
||||||
|
0xE0000, 0xE007F, "Tags",
|
||||||
|
0xE0100, 0xE01EF, "Variation Selectors Supplement",
|
||||||
|
0xF0000, 0xFFFFF, "Supplementary Private Use Area-A",
|
||||||
|
0x100000, 0x10FFFF, "Supplementary Private Use Area-B",
|
||||||
|
]
|
||||||
|
var UNICODE_BLOCK_COUNT = UNICODE_BLOCK_LIST.length / 3
|
||||||
|
var UNICODE_LOOKUP = {}
|
||||||
|
for (var i = 0, len = UNICODE_BLOCK_LIST.length; i < len; i += 3) {
|
||||||
|
UNICODE_LOOKUP[ UNICODE_BLOCK_LIST[i+2] ] = [ UNICODE_BLOCK_LIST[i], UNICODE_BLOCK_LIST[i+1] ]
|
||||||
|
}
|
||||||
|
|
||||||
|
function index (j) {
|
||||||
|
return [ UNICODE_BLOCK_LIST[j*3], UNICODE_BLOCK_LIST[j*3+1], UNICODE_BLOCK_LIST[j*3+2], [] ]
|
||||||
|
}
|
||||||
|
function range(m,n){
|
||||||
|
if (m > n) return []
|
||||||
|
var a = new Array (n-m)
|
||||||
|
for (var i = 0, j = m; j <= n; i++, j++) {
|
||||||
|
a[i] = j
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
function paginate (a, n){
|
||||||
|
var aa = [], ai, i = 0
|
||||||
|
while (i < 100) {
|
||||||
|
ai = a.slice(i * n, (i+1) * n)
|
||||||
|
if (! ai.length) break
|
||||||
|
aa.push(ai)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return aa
|
||||||
|
}
|
||||||
|
function block (name, n){
|
||||||
|
var b = UNICODE_LOOKUP[name]
|
||||||
|
if (! b) return ""
|
||||||
|
return range.apply(null, b).map(function(n){ return String.fromCharCode(n) })
|
||||||
|
}
|
||||||
|
function entities (a) {
|
||||||
|
return a.map(function(k){ return "&#" + k.join(";&#") + ";" }).join("<br>")
|
||||||
|
}
|
||||||
|
function findGroups (chars){
|
||||||
|
var groups = [], row, list
|
||||||
|
for (var i = 0, j = -1, next = -1, len = chars.length; i < len; i++) {
|
||||||
|
if (chars[i] < next) {
|
||||||
|
list.push(chars[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
j += 1
|
||||||
|
next = UNICODE_BLOCK_LIST[(j+1)*3]
|
||||||
|
} while (chars[i] > next)
|
||||||
|
row = index(j)
|
||||||
|
list = row[3]
|
||||||
|
groups.push( row )
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodes unicode characters as escaped utf16 - \xFFFF
|
||||||
|
// encodes ONLY non-ascii characters
|
||||||
|
function escapeToUtf16 (txt) {
|
||||||
|
var escaped_txt = "", kode
|
||||||
|
for (var i = 0; i < txt.length; i++) {
|
||||||
|
kode = txt.charCodeAt(i)
|
||||||
|
if (kode > 0x7f) {
|
||||||
|
kode = kode.toString(16)
|
||||||
|
switch (kode.length) {
|
||||||
|
case 2:
|
||||||
|
kode = "0" + kode
|
||||||
|
case 3:
|
||||||
|
kode = "0" + kode
|
||||||
|
}
|
||||||
|
escaped_txt += "\\u" + kode
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
escaped_txt += txt[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return escaped_txt
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodes unicode characters as escaped bytes - \xFF
|
||||||
|
// encodes ONLY non-ascii characters
|
||||||
|
function escapeToEscapedBytes (txt) {
|
||||||
|
var escaped_txt = "", kode, utf8_bytes
|
||||||
|
for (var i = 0; i < txt.length; i++) {
|
||||||
|
kode = txt.charCodeAt(i)
|
||||||
|
if (kode > 0x7f) {
|
||||||
|
utf8_bytes = convertUnicodeCodePointToUtf8Bytes(kode)
|
||||||
|
escaped_txt += convertBytesToEscapedString(utf8_bytes, 16)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
escaped_txt += txt[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return escaped_txt
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodes unicode characters as escaped bytes - \xFF
|
||||||
|
// encodes an ENTIRE string
|
||||||
|
function escapeAllToEscapedBytes(str, base) {
|
||||||
|
var unicode_codes = convertStringToUnicodeCodePoints(str);
|
||||||
|
var data_bytes = convertUnicodeCodePointsToBytes(unicode_codes);
|
||||||
|
return convertBytesToEscapedString(data_bytes, 16);
|
||||||
|
}
|
||||||
|
// [ 0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84 ] => '\xE3\x81\x82\xE3\x81\x84'
|
||||||
|
// [ 0343, 0201, 0202, 0343, 0201, 0204 ] => '\343\201\202\343\201\204'
|
||||||
|
function convertBytesToEscapedString(data_bytes, base) {
|
||||||
|
var escaped = '';
|
||||||
|
for (var i = 0; i < data_bytes.length; ++i) {
|
||||||
|
var prefix = (base == 16 ? "\\x" : "\\");
|
||||||
|
var num_digits = base == 16 ? 2 : 3;
|
||||||
|
var escaped_byte = prefix + formatNumber(data_bytes[i], base, num_digits)
|
||||||
|
escaped += escaped_byte;
|
||||||
|
}
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
// [ 0x3042, 0x3044 ] => [ 0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84 ]
|
||||||
|
function convertUnicodeCodePointsToBytes(unicode_codes) {
|
||||||
|
var utf8_bytes = [];
|
||||||
|
for (var i = 0; i < unicode_codes.length; ++i) {
|
||||||
|
var bytes = convertUnicodeCodePointToUtf8Bytes(unicode_codes[i]);
|
||||||
|
utf8_bytes = utf8_bytes.concat(bytes);
|
||||||
|
}
|
||||||
|
return utf8_bytes;
|
||||||
|
}
|
||||||
|
// 0x3042 => [ 0xE3, 0x81, 0x82 ]
|
||||||
|
function convertUnicodeCodePointToUtf8Bytes(unicode_code) {
|
||||||
|
var utf8_bytes = [];
|
||||||
|
if (unicode_code < 0x80) { // 1-byte
|
||||||
|
utf8_bytes.push(unicode_code);
|
||||||
|
} else if (unicode_code < (1 << 11)) { // 2-byte
|
||||||
|
utf8_bytes.push((unicode_code >>> 6) | 0xC0);
|
||||||
|
utf8_bytes.push((unicode_code & 0x3F) | 0x80);
|
||||||
|
} else if (unicode_code < (1 << 16)) { // 3-byte
|
||||||
|
utf8_bytes.push((unicode_code >>> 12) | 0xE0);
|
||||||
|
utf8_bytes.push(((unicode_code >> 6) & 0x3f) | 0x80);
|
||||||
|
utf8_bytes.push((unicode_code & 0x3F) | 0x80);
|
||||||
|
} else if (unicode_code < (1 << 21)) { // 4-byte
|
||||||
|
utf8_bytes.push((unicode_code >>> 18) | 0xF0);
|
||||||
|
utf8_bytes.push(((unicode_code >> 12) & 0x3F) | 0x80);
|
||||||
|
utf8_bytes.push(((unicode_code >> 6) & 0x3F) | 0x80);
|
||||||
|
utf8_bytes.push((unicode_code & 0x3F) | 0x80);
|
||||||
|
}
|
||||||
|
return utf8_bytes;
|
||||||
|
}
|
||||||
|
// "ã‚ã„" => [ 0x3042, 0x3044 ]
|
||||||
|
function convertStringToUnicodeCodePoints(str) {
|
||||||
|
var surrogate_1st = 0;
|
||||||
|
var unicode_codes = [];
|
||||||
|
for (var i = 0; i < str.length; ++i) {
|
||||||
|
var utf16_code = str.charCodeAt(i);
|
||||||
|
if (surrogate_1st != 0) {
|
||||||
|
if (utf16_code >= 0xDC00 && utf16_code <= 0xDFFF) {
|
||||||
|
var surrogate_2nd = utf16_code;
|
||||||
|
var unicode_code = (surrogate_1st - 0xD800) * (1 << 10) + (1 << 16) +
|
||||||
|
(surrogate_2nd - 0xDC00);
|
||||||
|
unicode_codes.push(unicode_code);
|
||||||
|
} else {
|
||||||
|
// Malformed surrogate pair ignored.
|
||||||
|
}
|
||||||
|
surrogate_1st = 0;
|
||||||
|
} else if (utf16_code >= 0xD800 && utf16_code <= 0xDBFF) {
|
||||||
|
surrogate_1st = utf16_code;
|
||||||
|
} else {
|
||||||
|
unicode_codes.push(utf16_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unicode_codes;
|
||||||
|
}
|
||||||
|
// 0xff => "ff"
|
||||||
|
// 0xff => "377"
|
||||||
|
function formatNumber(number, base, num_digits) {
|
||||||
|
var str = number.toString(base).toUpperCase();
|
||||||
|
for (var i = str.length; i < num_digits; ++i) {
|
||||||
|
str = "0" + str;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert \xFF\xFF\xFF to unicode
|
||||||
|
function unescapeFromEscapedBytes (str) {
|
||||||
|
var data_bytes = convertEscapedBytesToBytes(str);
|
||||||
|
var unicode_codes = convertUtf8BytesToUnicodeCodePoints(data_bytes);
|
||||||
|
return convertUnicodeCodePointsToString(unicode_codes);
|
||||||
|
}
|
||||||
|
// r'\xE3\x81\x82\xE3\x81\x84' => [ 0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84 ]
|
||||||
|
// r'\343\201\202\343\201\204' => [ 0343, 0201, 0202, 0343, 0201, 0204 ]
|
||||||
|
function convertEscapedBytesToBytes(str) {
|
||||||
|
var parts = str.split("\\x");
|
||||||
|
parts.shift(); // Trim the first element.
|
||||||
|
var codes = [];
|
||||||
|
var max = Math.pow(2, 8);
|
||||||
|
for (var i = 0; i < parts.length; ++i) {
|
||||||
|
var code = parseInt(parts[i], 16);
|
||||||
|
if (code >= 0 && code < max) {
|
||||||
|
codes.push(code);
|
||||||
|
} else {
|
||||||
|
// Malformed code ignored.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return codes;
|
||||||
|
}
|
||||||
|
// [ 0xE3, 0x81, 0x82, 0xE3, 0x81, 0x84 ] => [ 0x3042, 0x3044 ]
|
||||||
|
function convertUtf8BytesToUnicodeCodePoints(utf8_bytes) {
|
||||||
|
var unicode_codes = [];
|
||||||
|
var unicode_code = 0;
|
||||||
|
var num_followed = 0;
|
||||||
|
for (var i = 0; i < utf8_bytes.length; ++i) {
|
||||||
|
var utf8_byte = utf8_bytes[i];
|
||||||
|
if (utf8_byte >= 0x100) {
|
||||||
|
// Malformed utf8 byte ignored.
|
||||||
|
} else if ((utf8_byte & 0xC0) == 0x80) {
|
||||||
|
if (num_followed > 0) {
|
||||||
|
unicode_code = (unicode_code << 6) | (utf8_byte & 0x3f);
|
||||||
|
num_followed -= 1;
|
||||||
|
} else {
|
||||||
|
// Malformed UTF-8 sequence ignored.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (num_followed == 0) {
|
||||||
|
unicode_codes.push(unicode_code);
|
||||||
|
} else {
|
||||||
|
// Malformed UTF-8 sequence ignored.
|
||||||
|
}
|
||||||
|
if (utf8_byte < 0x80){ // 1-byte
|
||||||
|
unicode_code = utf8_byte;
|
||||||
|
num_followed = 0;
|
||||||
|
} else if ((utf8_byte & 0xE0) == 0xC0) { // 2-byte
|
||||||
|
unicode_code = utf8_byte & 0x1f;
|
||||||
|
num_followed = 1;
|
||||||
|
} else if ((utf8_byte & 0xF0) == 0xE0) { // 3-byte
|
||||||
|
unicode_code = utf8_byte & 0x0f;
|
||||||
|
num_followed = 2;
|
||||||
|
} else if ((utf8_byte & 0xF8) == 0xF0) { // 4-byte
|
||||||
|
unicode_code = utf8_byte & 0x07;
|
||||||
|
num_followed = 3;
|
||||||
|
} else {
|
||||||
|
// Malformed UTF-8 sequence ignored.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_followed == 0) {
|
||||||
|
unicode_codes.push(unicode_code);
|
||||||
|
} else {
|
||||||
|
// Malformed UTF-8 sequence ignored.
|
||||||
|
}
|
||||||
|
unicode_codes.shift(); // Trim the first element.
|
||||||
|
return unicode_codes;
|
||||||
|
}
|
||||||
|
// [ 0x3042, 0x3044 ] => [ 0x3042, 0x3044 ]
|
||||||
|
// [ 0xD840, 0xDC0B ] => [ 0x2000B ] // A surrogate pair.
|
||||||
|
function convertUnicodeCodePointsToUtf16Codes(unicode_codes) {
|
||||||
|
var utf16_codes = [];
|
||||||
|
for (var i = 0; i < unicode_codes.length; ++i) {
|
||||||
|
var unicode_code = unicode_codes[i];
|
||||||
|
if (unicode_code < (1 << 16)) {
|
||||||
|
utf16_codes.push(unicode_code);
|
||||||
|
} else {
|
||||||
|
var first = ((unicode_code - (1 << 16)) / (1 << 10)) + 0xD800;
|
||||||
|
var second = (unicode_code % (1 << 10)) + 0xDC00;
|
||||||
|
utf16_codes.push(first)
|
||||||
|
utf16_codes.push(second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utf16_codes;
|
||||||
|
}
|
||||||
|
// [ 0x3042, 0x3044 ] => "ã‚ã„"
|
||||||
|
function convertUnicodeCodePointsToString(unicode_codes) {
|
||||||
|
var utf16_codes = convertUnicodeCodePointsToUtf16Codes(unicode_codes);
|
||||||
|
return convertUtf16CodesToString(utf16_codes);
|
||||||
|
}
|
||||||
|
// [ 0x3042, 0x3044 ] => "ã‚ã„"
|
||||||
|
function convertUtf16CodesToString(utf16_codes) {
|
||||||
|
var unescaped = '';
|
||||||
|
for (var i = 0; i < utf16_codes.length; ++i) {
|
||||||
|
unescaped += String.fromCharCode(utf16_codes[i]);
|
||||||
|
}
|
||||||
|
return unescaped;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
raw: UNICODE_BLOCK_LIST,
|
||||||
|
lookup: UNICODE_LOOKUP,
|
||||||
|
index: index,
|
||||||
|
range: range,
|
||||||
|
block: block,
|
||||||
|
findGroups: findGroups,
|
||||||
|
paginate: paginate,
|
||||||
|
escapeToEscapedBytes: escapeToEscapedBytes,
|
||||||
|
unescapeFromEscapedBytes: unescapeFromEscapedBytes,
|
||||||
|
}
|
||||||
|
})()
|
83
js/upload.js
Normal file
83
js/upload.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
var upload = (function(){
|
||||||
|
var el = document.getElementById("upload_input")
|
||||||
|
var button = document.getElementById("upload_button")
|
||||||
|
var uploading = false
|
||||||
|
|
||||||
|
function upload(blob, filename, tag, ascii){
|
||||||
|
if (uploading) return
|
||||||
|
filename = filename || get_filename()
|
||||||
|
tag = tag || "shader"
|
||||||
|
|
||||||
|
button.innerHTML = "uploading..."
|
||||||
|
button.className = "uploading"
|
||||||
|
|
||||||
|
uploading = true
|
||||||
|
|
||||||
|
uploadImage({
|
||||||
|
blob: blob,
|
||||||
|
ascii: ascii,
|
||||||
|
filename: filename,
|
||||||
|
username: user.username,
|
||||||
|
tag: tag,
|
||||||
|
success: function(data){
|
||||||
|
|
||||||
|
// data.url
|
||||||
|
// data.filesize
|
||||||
|
// data.success
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
el.style.display = "block"
|
||||||
|
el.value = data.url
|
||||||
|
el.focus()
|
||||||
|
setCaretToPos(el, 0)
|
||||||
|
button.innerHTML = "upload"
|
||||||
|
button.className = ""
|
||||||
|
uploading = false
|
||||||
|
},
|
||||||
|
error: function(data){
|
||||||
|
console.log(data)
|
||||||
|
console.log("error uploading: " + data.error)
|
||||||
|
button.innerHTML = "upload"
|
||||||
|
button.className = ""
|
||||||
|
uploading = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadImage(opt){
|
||||||
|
if (! opt.blob || ! opt.filename) return;
|
||||||
|
|
||||||
|
opt.username = opt.username || "";
|
||||||
|
opt.success = opt.success || noop;
|
||||||
|
opt.error = opt.error || noop;
|
||||||
|
|
||||||
|
var form = new FormData();
|
||||||
|
|
||||||
|
form.append("username", opt.username);
|
||||||
|
form.append("filename", opt.filename);
|
||||||
|
form.append("qqfile", opt.blob);
|
||||||
|
form.append("tag", opt.tag);
|
||||||
|
if (opt.ascii) {
|
||||||
|
form.append("ascii", opt.ascii);
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.open("POST", "/cgi-bin/im/shader/upload");
|
||||||
|
req.onload = function(event) {
|
||||||
|
if (req.status == 200) {
|
||||||
|
var res = JSON.parse(req.responseText);
|
||||||
|
if (res.success) {
|
||||||
|
opt.success(res);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
opt.error(res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opt.error({ success: false, error: req.status });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
req.send(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
return upload
|
||||||
|
})()
|
67
js/user.js
Normal file
67
js/user.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
var user = (function(){
|
||||||
|
|
||||||
|
var user = {}
|
||||||
|
var el = document.getElementById("username_input")
|
||||||
|
|
||||||
|
user.init = function(){
|
||||||
|
user.load()
|
||||||
|
user.bind()
|
||||||
|
}
|
||||||
|
user.bind = function(){
|
||||||
|
el.addEventListener("input", user.save)
|
||||||
|
}
|
||||||
|
user.load = function(){
|
||||||
|
user.username = user.getCookie()
|
||||||
|
if (! user.username) {
|
||||||
|
user.username = '00' + randint(9876876)
|
||||||
|
user.setCookie(user.username)
|
||||||
|
}
|
||||||
|
if (!user.username.match(/^00/)) {
|
||||||
|
el.value = user.username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.prefs = new function(){}
|
||||||
|
user.prefs.get = function (key){
|
||||||
|
return localStorage.getItem("im.prefs." + key)
|
||||||
|
}
|
||||||
|
user.prefs.set = function (key,value){
|
||||||
|
return localStorage.setItem("im.prefs." + key, value)
|
||||||
|
}
|
||||||
|
user.sanitize = function(){
|
||||||
|
return el.value.replace(/[^-_ a-zA-Z0-9]/g,"")
|
||||||
|
}
|
||||||
|
user.getCookie = function () {
|
||||||
|
var username = localStorage.getItem("im.name") || "";
|
||||||
|
if (document.cookie && ! username.length) {
|
||||||
|
var cookies = document.cookie.split(";")
|
||||||
|
for (i in cookies) {
|
||||||
|
var cookie = cookies[i].split("=")
|
||||||
|
if (cookie[0].indexOf("imname") !== -1) {
|
||||||
|
if (cookie[1] !== 'false' && cookie[1] !== 'undefined' && cookie[1].length) {
|
||||||
|
return cookie[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return username
|
||||||
|
}
|
||||||
|
var timeout
|
||||||
|
user.save = function(){
|
||||||
|
clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(function(){
|
||||||
|
var username = user.sanitize()
|
||||||
|
if (username != user.username) user.setCookie(username);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
user.setCookie = function(username){
|
||||||
|
if (!user.username.match(/^00/)) {
|
||||||
|
console.log("setting to " + username)
|
||||||
|
}
|
||||||
|
document.cookie = "imname="+username+";path=/;domain=.asdf.us;max-age=1086400"
|
||||||
|
localStorage.setItem("im.name", username);
|
||||||
|
}
|
||||||
|
|
||||||
|
user.init()
|
||||||
|
|
||||||
|
return user
|
||||||
|
})()
|
199
js/util.js
Normal file
199
js/util.js
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
if (window.$) {
|
||||||
|
$.fn.int = function(){ return parseInt($(this).val(),10) }
|
||||||
|
$.fn.float = function(){ return parseFloat($(this).val()) }
|
||||||
|
$.fn.string = function(){ return trim($(this).val()) }
|
||||||
|
$.fn.enable = function() { return $(this).attr("disabled",null) }
|
||||||
|
$.fn.disable = function() { return $(this).attr("disabled","disabled") }
|
||||||
|
}
|
||||||
|
|
||||||
|
function noop(){}
|
||||||
|
function trim(s){ return s.replace(/^\s+/,"").replace(/\s+$/,"") }
|
||||||
|
|
||||||
|
var E = Math.E
|
||||||
|
var PI = Math.PI
|
||||||
|
var PHI = (1+Math.sqrt(5))/2
|
||||||
|
var TWO_PI = PI*2
|
||||||
|
var LN10 = Math.LN10
|
||||||
|
function clamp(n,a,b){ return n<a?a:n<b?n:b }
|
||||||
|
function norm(n,a,b){ return (n-a) / (b-a) }
|
||||||
|
function lerp(n,a,b){ return (b-a)*n+a }
|
||||||
|
function mix(n,a,b){ return a*(1-n)+b*n }
|
||||||
|
function ceil(n){ return Math.ceil(n) }
|
||||||
|
function floor(n){ return Math.floor(n) }
|
||||||
|
function round(n){ return Math.round(n) }
|
||||||
|
function max(a,b){ return Math.max(a,b) }
|
||||||
|
function min(a,b){ return Math.min(a,b) }
|
||||||
|
function abs(n){ return Math.abs(n) }
|
||||||
|
function sign(n){ return Math.abs(n)/n }
|
||||||
|
function pow(n,b) { return Math.pow(n,b) }
|
||||||
|
function exp(n) { return Math.exp(n) }
|
||||||
|
function log(n){ return Math.log(n) }
|
||||||
|
function ln(n){ return Math.log(n)/LN10 }
|
||||||
|
function sqrt(n) { return Math.sqrt(n) }
|
||||||
|
function cos(n){ return Math.cos(n) }
|
||||||
|
function sin(n){ return Math.sin(n) }
|
||||||
|
function tan(n){ return Math.tan(n) }
|
||||||
|
function acos(n){ return Math.cos(n) }
|
||||||
|
function asin(n){ return Math.sin(n) }
|
||||||
|
function atan(n){ return Math.atan(n) }
|
||||||
|
function atan2(a,b){ return Math.atan2(a,b) }
|
||||||
|
function sec(n){ return 1/cos(n) }
|
||||||
|
function csc(n){ return 1/sin(n) }
|
||||||
|
function cot(n){ return 1/tan(n) }
|
||||||
|
function cosp(n){ return (1+Math.cos(n))/2 } // cos^2
|
||||||
|
function sinp(n){ return (1+Math.sin(n))/2 }
|
||||||
|
function random(){ return Math.random() }
|
||||||
|
function rand(n){ return (Math.random()*n) }
|
||||||
|
function randint(n){ return rand(n)|0 }
|
||||||
|
function randrange(a,b){ return a + rand(b-a) }
|
||||||
|
function randsign(){ return random() >= 0.5 ? -1 : 1 }
|
||||||
|
function randnullsign(){ var r = random(); return r < 0.333 ? -1 : r < 0.666 ? 0 : 1 }
|
||||||
|
|
||||||
|
function xrandom(exp){ return Math.pow(Math.random(), exp) }
|
||||||
|
function xrand(exp,n){ return (xrandom(exp)*n) }
|
||||||
|
function xrandint(exp,n){ return rand(exp,n)|0 }
|
||||||
|
function xrandrange(exp,a,b){ return a + xrand(exp,b-a) }
|
||||||
|
|
||||||
|
function choice(a){ return a[randint(a.length)] }
|
||||||
|
function deg(n){ return n*180/PI }
|
||||||
|
function rad(n){ return n*PI/180 }
|
||||||
|
function xor(a,b){ a=!!a; b=!!b; return (a||b) && !(a&&b) }
|
||||||
|
function mod(n,m){ n = n % m; return n < 0 ? (m + n) : n }
|
||||||
|
function modi(n,m){ return floor(mod(n,m)) }
|
||||||
|
function dist(x0,y0,x1,y1){ return sqrt(pow(x1-x0,2)+pow(y1-y0,2)) }
|
||||||
|
function angle(x0,y0,x1,y1){ return atan2(y1-y0,x1-x0) }
|
||||||
|
function avg(m,n,a){ return (m*(a-1)+n)/a }
|
||||||
|
function quantize(a,b){ return floor(a/b)*b }
|
||||||
|
function quantile(a,b){ return floor(a/b) }
|
||||||
|
|
||||||
|
function pixel(x,y){ return 4*(mod(y,actual_h)*actual_w+mod(x,actual_w)) }
|
||||||
|
function rgbpixel(d,x,y){
|
||||||
|
var p = pixel(~~x,~~y)
|
||||||
|
r = d[p]
|
||||||
|
g = d[p+1]
|
||||||
|
b = d[p+2]
|
||||||
|
a = d[p+3]
|
||||||
|
}
|
||||||
|
function fit(d,x,y){ rgbpixel(d,x*actual_w/w,y*actual_h/h) }
|
||||||
|
|
||||||
|
function step(a, b){
|
||||||
|
return (b >= a) + 0
|
||||||
|
// ^^ bool -> int
|
||||||
|
}
|
||||||
|
|
||||||
|
function julestep (a,b,n) {
|
||||||
|
return clamp(norm(n,a,b), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hermite curve apparently
|
||||||
|
function smoothstep(min,max,n){
|
||||||
|
var t = clamp((n - min) / (max - min), 0.0, 1.0);
|
||||||
|
return t * t * (3.0 - 2.0 * t)
|
||||||
|
}
|
||||||
|
|
||||||
|
function toArray(a){ return Array.prototype.slice.call(a) }
|
||||||
|
function shuffle(a){
|
||||||
|
for (var i = a.length; i > 0; i--){
|
||||||
|
var r = randint(i)
|
||||||
|
var swap = a[i-1]
|
||||||
|
a[i-1] = a[r]
|
||||||
|
a[r] = swap
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
function reverse(a){
|
||||||
|
var reversed = []
|
||||||
|
for (var i = 0, _len = a.length-1; i <= _len; i++){
|
||||||
|
reversed[i] = a[_len-i]
|
||||||
|
}
|
||||||
|
return reversed
|
||||||
|
}
|
||||||
|
function deinterlace(a){
|
||||||
|
var odd = [], even = []
|
||||||
|
for (var i = 0, _len = a.length; i < _len; i++) {
|
||||||
|
if (i % 2) even.push(a[i])
|
||||||
|
else odd.push(a[i])
|
||||||
|
}
|
||||||
|
return [even, odd]
|
||||||
|
}
|
||||||
|
function weave(a){
|
||||||
|
var aa = deinterlace(a)
|
||||||
|
var b = []
|
||||||
|
aa[0].forEach(function(el){ b.push(el) })
|
||||||
|
reverse(aa[1]).forEach(function(el){ b.push(el) })
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
function cssRule (selector, declaration) {
|
||||||
|
var x = document.styleSheets, y = x.length-1;
|
||||||
|
x[y].insertRule(selector+"{"+declaration+"}", x[y].cssRules.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// easing functions
|
||||||
|
function circular (t) { return Math.sqrt( 1 - ( --t * t ) ) }
|
||||||
|
function quadratic (t) { return t * ( 2 - t ) }
|
||||||
|
function back (t) {
|
||||||
|
var b = 4;
|
||||||
|
return ( t = t - 1 ) * t * ( ( b + 1 ) * t + b ) + 1;
|
||||||
|
}
|
||||||
|
function bounce (t) {
|
||||||
|
if (t >= 1) return 1;
|
||||||
|
if ( ( t /= 1 ) < ( 1 / 2.75 ) ) {
|
||||||
|
return 7.5625 * t * t;
|
||||||
|
} else if ( t < ( 2 / 2.75 ) ) {
|
||||||
|
return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75;
|
||||||
|
} else if ( t < ( 2.5 / 2.75 ) ) {
|
||||||
|
return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375;
|
||||||
|
} else {
|
||||||
|
return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function elastic (t) {
|
||||||
|
var f = 0.22,
|
||||||
|
e = 0.4;
|
||||||
|
|
||||||
|
if ( t === 0 ) { return 0; }
|
||||||
|
if ( t == 1 ) { return 1; }
|
||||||
|
|
||||||
|
return ( e * Math.pow( 2, - 10 * t ) * Math.sin( ( t - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Model=function a(b,c,d,e){function f(){var a=this,f={};a.on=function(a,b){(f[a]||
|
||||||
|
(f[a]=[])).push(b)},a.trigger=function(a,b){for(var c=f[a],d=0;c&&d<c.length;)c
|
||||||
|
[d++](b)},a.off=function(a,b){for(d=f[a]||[];b&&(c=d.indexOf(b))>-1;)d.splice(c
|
||||||
|
,1);f[a]=b?d:[]};for(c in b)d=b[c],a[c]=typeof d=="function"?function(){return(
|
||||||
|
d=this.apply(a,arguments))===e?a:d}.bind(d):d;a.init&&a.init.apply(a,arguments)
|
||||||
|
}return f.extend=function(f){d={};for(c in b)d[c]=b[c];for(c in f)d[c]=f[c],b[c
|
||||||
|
]!==e&&(d["__"+c]=b[c]);return a(d)},f},typeof module=="object"&&(module.exports
|
||||||
|
=Model); // c-{{{-<
|
||||||
|
|
||||||
|
function defaults (dest, src) {
|
||||||
|
dest = dest || {}
|
||||||
|
for (var i in src) {
|
||||||
|
dest[i] = typeof dest[i] == 'undefined' ? src[i] : dest[i]
|
||||||
|
}
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectionRange(input, selectionStart, selectionEnd) {
|
||||||
|
if (input.setSelectionRange) {
|
||||||
|
input.focus();
|
||||||
|
input.setSelectionRange(selectionStart, selectionEnd);
|
||||||
|
}
|
||||||
|
else if (input.createTextRange) {
|
||||||
|
var range = input.createTextRange();
|
||||||
|
range.collapse(true);
|
||||||
|
range.moveEnd('character', selectionEnd);
|
||||||
|
range.moveStart('character', selectionStart);
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function setCaretToPos(input, pos) {
|
||||||
|
setSelectionRange(input, pos, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Naive useragent detection pattern
|
||||||
|
var is_iphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))
|
||||||
|
var is_ipad = (navigator.userAgent.match(/iPad/i))
|
||||||
|
var is_android = (navigator.userAgent.match(/Android/i))
|
||||||
|
var is_mobile = is_iphone || is_ipad || is_android
|
||||||
|
var is_desktop = ! is_mobile;
|
232
js/vendor/FileSaver.js
vendored
Normal file
232
js/vendor/FileSaver.js
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/* FileSaver.js
|
||||||
|
* A saveAs() FileSaver implementation.
|
||||||
|
* 2013-10-21
|
||||||
|
*
|
||||||
|
* By Eli Grey, http://eligrey.com
|
||||||
|
* License: X11/MIT
|
||||||
|
* See LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*global self */
|
||||||
|
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
|
||||||
|
plusplus: true */
|
||||||
|
|
||||||
|
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
|
||||||
|
|
||||||
|
var saveAs = saveAs
|
||||||
|
|| (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
|
||||||
|
|| (function(view) {
|
||||||
|
"use strict";
|
||||||
|
var
|
||||||
|
doc = view.document
|
||||||
|
// only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
|
||||||
|
, get_URL = function() {
|
||||||
|
return view.URL || view.webkitURL || view;
|
||||||
|
}
|
||||||
|
, URL = view.URL || view.webkitURL || view
|
||||||
|
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
|
||||||
|
, can_use_save_link = !view.externalHost && "download" in save_link
|
||||||
|
, click = function(node) {
|
||||||
|
var event = doc.createEvent("MouseEvents");
|
||||||
|
event.initMouseEvent(
|
||||||
|
"click", true, false, view, 0, 0, 0, 0, 0
|
||||||
|
, false, false, false, false, 0, null
|
||||||
|
);
|
||||||
|
node.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
, webkit_req_fs = view.webkitRequestFileSystem
|
||||||
|
, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
|
||||||
|
, throw_outside = function (ex) {
|
||||||
|
(view.setImmediate || view.setTimeout)(function() {
|
||||||
|
throw ex;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
, force_saveable_type = "application/octet-stream"
|
||||||
|
, fs_min_size = 0
|
||||||
|
, deletion_queue = []
|
||||||
|
, process_deletion_queue = function() {
|
||||||
|
var i = deletion_queue.length;
|
||||||
|
while (i--) {
|
||||||
|
var file = deletion_queue[i];
|
||||||
|
if (typeof file === "string") { // file is an object URL
|
||||||
|
URL.revokeObjectURL(file);
|
||||||
|
} else { // file is a File
|
||||||
|
file.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deletion_queue.length = 0; // clear queue
|
||||||
|
}
|
||||||
|
, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, FileSaver = function(blob, name) {
|
||||||
|
// First try a.download, then web filesystem, then object URLs
|
||||||
|
var
|
||||||
|
filesaver = this
|
||||||
|
, type = blob.type
|
||||||
|
, blob_changed = false
|
||||||
|
, object_url
|
||||||
|
, target_view
|
||||||
|
, get_object_url = function() {
|
||||||
|
var object_url = get_URL().createObjectURL(blob);
|
||||||
|
deletion_queue.push(object_url);
|
||||||
|
return 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() {
|
||||||
|
// don't create more object URLs than needed
|
||||||
|
if (blob_changed || !object_url) {
|
||||||
|
object_url = get_object_url(blob);
|
||||||
|
}
|
||||||
|
if (target_view) {
|
||||||
|
target_view.location.href = object_url;
|
||||||
|
} else {
|
||||||
|
window.open(object_url, "_blank");
|
||||||
|
}
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch_all();
|
||||||
|
}
|
||||||
|
, abortable = function(func) {
|
||||||
|
return function() {
|
||||||
|
if (filesaver.readyState !== filesaver.DONE) {
|
||||||
|
return func.apply(this, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
, create_if_not_found = {create: true, exclusive: false}
|
||||||
|
, slice
|
||||||
|
;
|
||||||
|
filesaver.readyState = filesaver.INIT;
|
||||||
|
if (!name) {
|
||||||
|
name = "download";
|
||||||
|
}
|
||||||
|
if (can_use_save_link) {
|
||||||
|
object_url = get_object_url(blob);
|
||||||
|
// FF for Android has a nasty garbage collection mechanism
|
||||||
|
// that turns all objects that are not pure javascript into 'deadObject'
|
||||||
|
// this means `doc` and `save_link` are unusable and need to be recreated
|
||||||
|
// `view` is usable though:
|
||||||
|
doc = view.document;
|
||||||
|
save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
|
||||||
|
save_link.href = object_url;
|
||||||
|
save_link.download = name;
|
||||||
|
var event = doc.createEvent("MouseEvents");
|
||||||
|
event.initMouseEvent(
|
||||||
|
"click", true, false, view, 0, 0, 0, 0, 0
|
||||||
|
, false, false, false, false, 0, null
|
||||||
|
);
|
||||||
|
save_link.dispatchEvent(event);
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Object and web filesystem URLs have a problem saving in Google Chrome when
|
||||||
|
// viewed in a tab, so I force save with application/octet-stream
|
||||||
|
// http://code.google.com/p/chromium/issues/detail?id=91158
|
||||||
|
if (view.chrome && type && type !== force_saveable_type) {
|
||||||
|
slice = blob.slice || blob.webkitSlice;
|
||||||
|
blob = slice.call(blob, 0, blob.size, force_saveable_type);
|
||||||
|
blob_changed = true;
|
||||||
|
}
|
||||||
|
// Since I can't be sure that the guessed media type will trigger a download
|
||||||
|
// in WebKit, I append .download to the filename.
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=65440
|
||||||
|
if (webkit_req_fs && name !== "download") {
|
||||||
|
name += ".download";
|
||||||
|
}
|
||||||
|
if (type === force_saveable_type || webkit_req_fs) {
|
||||||
|
target_view = view;
|
||||||
|
}
|
||||||
|
if (!req_fs) {
|
||||||
|
fs_error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs_min_size += blob.size;
|
||||||
|
req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
|
||||||
|
fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
|
||||||
|
var save = function() {
|
||||||
|
dir.getFile(name, create_if_not_found, abortable(function(file) {
|
||||||
|
file.createWriter(abortable(function(writer) {
|
||||||
|
writer.onwriteend = function(event) {
|
||||||
|
target_view.location.href = file.toURL();
|
||||||
|
deletion_queue.push(file);
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch(filesaver, "writeend", event);
|
||||||
|
};
|
||||||
|
writer.onerror = function() {
|
||||||
|
var error = writer.error;
|
||||||
|
if (error.code !== error.ABORT_ERR) {
|
||||||
|
fs_error();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"writestart progress write abort".split(" ").forEach(function(event) {
|
||||||
|
writer["on" + event] = filesaver["on" + event];
|
||||||
|
});
|
||||||
|
writer.write(blob);
|
||||||
|
filesaver.abort = function() {
|
||||||
|
writer.abort();
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
};
|
||||||
|
filesaver.readyState = filesaver.WRITING;
|
||||||
|
}), fs_error);
|
||||||
|
}), fs_error);
|
||||||
|
};
|
||||||
|
dir.getFile(name, {create: false}, abortable(function(file) {
|
||||||
|
// delete file if it already exists
|
||||||
|
file.remove();
|
||||||
|
save();
|
||||||
|
}), abortable(function(ex) {
|
||||||
|
if (ex.code === ex.NOT_FOUND_ERR) {
|
||||||
|
save();
|
||||||
|
} else {
|
||||||
|
fs_error();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}), fs_error);
|
||||||
|
}), fs_error);
|
||||||
|
}
|
||||||
|
, FS_proto = FileSaver.prototype
|
||||||
|
, saveAs = function(blob, name) {
|
||||||
|
return new FileSaver(blob, name);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
FS_proto.abort = function() {
|
||||||
|
var filesaver = this;
|
||||||
|
filesaver.readyState = filesaver.DONE;
|
||||||
|
dispatch(filesaver, "abort");
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
|
||||||
|
view.addEventListener("unload", process_deletion_queue, false);
|
||||||
|
return saveAs;
|
||||||
|
}(this.self || this.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 = saveAs;
|
551
js/vendor/colorcode.js
vendored
Normal file
551
js/vendor/colorcode.js
vendored
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.colorcode=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||||
|
var colorcode = {};
|
||||||
|
module.exports = colorcode;
|
||||||
|
colorcode.to_json = require('./src/to_json');
|
||||||
|
colorcode.from_json = require('./src/from_json');
|
||||||
|
colorcode.style = require('./src/style');
|
||||||
|
colorcode.to_canvas = require('./src/canvas');
|
||||||
|
colorcode.color = require('./src/color');
|
||||||
|
colorcode.font = require('./src/font');
|
||||||
|
|
||||||
|
},{"./src/canvas":2,"./src/color":3,"./src/font":4,"./src/from_json":8,"./src/style":9,"./src/to_json":10}],2:[function(require,module,exports){
|
||||||
|
var to_json = require('./to_json');
|
||||||
|
var fontload = require('./font').load;
|
||||||
|
var style = require('./style');
|
||||||
|
var color = require('./color');
|
||||||
|
|
||||||
|
// node-canvas
|
||||||
|
var Canvas = require('canvas');
|
||||||
|
if (typeof Image === "undefined") Image = Canvas.Image;
|
||||||
|
|
||||||
|
var make_canvas = function(){
|
||||||
|
if (typeof document === "undefined" && typeof Canvas !== "undefined")
|
||||||
|
return new Canvas();
|
||||||
|
else
|
||||||
|
return document.createElement("canvas");
|
||||||
|
}
|
||||||
|
|
||||||
|
var canvas_tmp;
|
||||||
|
|
||||||
|
var render_colorcode = function(json, canvas, font, opts){
|
||||||
|
|
||||||
|
var cw = font.char_w
|
||||||
|
, ch = font.char_h
|
||||||
|
, ctx = canvas.getContext('2d')
|
||||||
|
, canvas_tmp = canvas_tmp || make_canvas()
|
||||||
|
, ctx_tmp = canvas_tmp.getContext("2d")
|
||||||
|
|
||||||
|
var palette = color.palettes[opts.palette || style.palette];
|
||||||
|
var bg = opts.bg || style.bg;
|
||||||
|
|
||||||
|
canvas_tmp.width = cw;
|
||||||
|
canvas_tmp.height = ch;
|
||||||
|
|
||||||
|
canvas.width = json.w * cw;
|
||||||
|
canvas.height = json.h * ch;
|
||||||
|
|
||||||
|
// pre fill entire canvas with bg color
|
||||||
|
// is this a good optimization?
|
||||||
|
if (bg === color.transparent_index){
|
||||||
|
// already cleared when resized above
|
||||||
|
// canvas.clearRect(0,0, canvas.width,canvas.height);
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = palette[bg];
|
||||||
|
ctx.fillRect(0,0, canvas.width,canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var l=0; l<json.lines.length; l++){
|
||||||
|
var line = json.lines[l];
|
||||||
|
for (var c=0; c<line.length; c++){
|
||||||
|
var char = line[c];
|
||||||
|
var x = c * cw
|
||||||
|
var y = l * ch
|
||||||
|
|
||||||
|
// draw bg for this char if not already filled
|
||||||
|
if (char.bg !== bg) {
|
||||||
|
if (char.bg === color.transparent_index) {
|
||||||
|
ctx.clearRect(x, y, cw, ch)
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = palette[char.bg]
|
||||||
|
ctx.fillRect(x, y, cw, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.is_char_blank(char.value)) continue;
|
||||||
|
|
||||||
|
// draw char in fg
|
||||||
|
var fg = palette[char.fg]
|
||||||
|
if (fg !== color.transparent){
|
||||||
|
ctx_tmp.globalCompositeOperation = 'source-over'
|
||||||
|
ctx_tmp.fillStyle = fg
|
||||||
|
ctx_tmp.fillRect(0,0,cw,ch)
|
||||||
|
ctx_tmp.globalCompositeOperation = 'destination-in'
|
||||||
|
font.render_char(font, char.value, ctx_tmp, 0, 0, char)
|
||||||
|
ctx.drawImage(canvas_tmp, x, y)
|
||||||
|
} else { // transparent foreground punches out bg
|
||||||
|
ctx.globalCompositeOperation = 'destination-out'
|
||||||
|
font.render_char(font, char.value, ctx, x, y, char)
|
||||||
|
ctx.globalCompositeOperation = 'source-over'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.done) opts.done(canvas)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var to_canvas = function(string_or_json, opts){
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
if (typeof string_or_json === 'string')
|
||||||
|
string_or_json = to_json(string_or_json, opts);
|
||||||
|
|
||||||
|
var canvas = opts.canvas || make_canvas();
|
||||||
|
var font_name = opts.font || style.font;
|
||||||
|
|
||||||
|
fontload(font_name, function(font){
|
||||||
|
render_colorcode(string_or_json, canvas, font, opts)
|
||||||
|
});
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = to_canvas;
|
||||||
|
|
||||||
|
},{"./color":3,"./font":4,"./style":9,"./to_json":10,"canvas":11}],3:[function(require,module,exports){
|
||||||
|
var style = require('./style');
|
||||||
|
|
||||||
|
var color = {};
|
||||||
|
module.exports = color;
|
||||||
|
|
||||||
|
style.palette = 'mirc';
|
||||||
|
|
||||||
|
color.transparent_index = 99;
|
||||||
|
color.transparent = 'rgba(0,0,0,0)';
|
||||||
|
var ps = color.palettes = {};
|
||||||
|
|
||||||
|
ps.mirc = [
|
||||||
|
'rgb(255,255,255)'
|
||||||
|
,'rgb(0,0,0)'
|
||||||
|
,'rgb(0,0,127)'
|
||||||
|
,'rgb(0,147,0)'
|
||||||
|
,'rgb(255,0,0)'
|
||||||
|
,'rgb(127,0,0)'
|
||||||
|
,'rgb(156,0,156)'
|
||||||
|
,'rgb(252,127,0)'
|
||||||
|
,'rgb(255,255,0)'
|
||||||
|
,'rgb(0,252,0)'
|
||||||
|
,'rgb(0,147,147)'
|
||||||
|
,'rgb(0,255,255)'
|
||||||
|
,'rgb(0,0,252)'
|
||||||
|
,'rgb(255,0,255)'
|
||||||
|
,'rgb(127,127,127)'
|
||||||
|
,'rgb(210,210,210)'
|
||||||
|
];
|
||||||
|
|
||||||
|
ps.winxp = [
|
||||||
|
'rgb(255,255,255)'
|
||||||
|
,'rgb(0,0,0)'
|
||||||
|
,'rgb(0,0,128)'
|
||||||
|
,'rgb(0,128,0)'
|
||||||
|
,'rgb(255,0,0)'
|
||||||
|
,'rgb(128,0,0)'
|
||||||
|
,'rgb(128,0,128)'
|
||||||
|
,'rgb(255,128,0)'
|
||||||
|
,'rgb(255,255,0)'
|
||||||
|
,'rgb(0,255,0)'
|
||||||
|
,'rgb(0,128,128)'
|
||||||
|
,'rgb(0,255,255)'
|
||||||
|
,'rgb(0,0,255)'
|
||||||
|
,'rgb(255,0,255)'
|
||||||
|
,'rgb(128,128,128)'
|
||||||
|
,'rgb(192,192,192)'
|
||||||
|
];
|
||||||
|
|
||||||
|
ps.vga = [
|
||||||
|
'rgb(255,255,255)'
|
||||||
|
,'rgb(0,0,0)'
|
||||||
|
,'rgb(0,0,170)'
|
||||||
|
,'rgb(0,170,0)'
|
||||||
|
,'rgb(255,85,85)'
|
||||||
|
,'rgb(170,0,0)'
|
||||||
|
,'rgb(170,0,170)'
|
||||||
|
,'rgb(170,85,0)'
|
||||||
|
,'rgb(255,255,85)'
|
||||||
|
,'rgb(85,255,85)'
|
||||||
|
,'rgb(0,170,170)'
|
||||||
|
,'rgb(85,255,255)'
|
||||||
|
,'rgb(85,85,255)'
|
||||||
|
,'rgb(255,85,255)'
|
||||||
|
,'rgb(85,85,85)'
|
||||||
|
,'rgb(170,170,170)'
|
||||||
|
];
|
||||||
|
|
||||||
|
ps.c64 = [
|
||||||
|
'rgb(255,255,255)'
|
||||||
|
,'rgb(0,0,0)'
|
||||||
|
,'rgb(69,32,170)'
|
||||||
|
,'rgb(101,170,69)'
|
||||||
|
,'rgb(138,101,32)'
|
||||||
|
,'rgb(138,69,32)'
|
||||||
|
,'rgb(138,69,170)'
|
||||||
|
,'rgb(101,69,0)'
|
||||||
|
,'rgb(207,207,101)'
|
||||||
|
,'rgb(170,239,138)'
|
||||||
|
,'rgb(138,138,138)'
|
||||||
|
,'rgb(101,170,207)'
|
||||||
|
,'rgb(138,101,223)'
|
||||||
|
,'rgb(207,138,101)'
|
||||||
|
,'rgb(69,69,69)'
|
||||||
|
,'rgb(170,170,170)'
|
||||||
|
];
|
||||||
|
|
||||||
|
ps.appleii = [
|
||||||
|
'rgb(255,255,255)'
|
||||||
|
,'rgb(0,0,0)'
|
||||||
|
,'rgb(64,53,121)'
|
||||||
|
,'rgb(64,75,7)'
|
||||||
|
,'rgb(191,180,248)'
|
||||||
|
,'rgb(109,41,64)'
|
||||||
|
,'rgb(218,60,241)'
|
||||||
|
,'rgb(218,104,15)'
|
||||||
|
,'rgb(191,202,134)'
|
||||||
|
,'rgb(38,195,16)'
|
||||||
|
,'rgb(19,87,64)'
|
||||||
|
,'rgb(146,214,191)'
|
||||||
|
,'rgb(37,151,240)'
|
||||||
|
,'rgb(236,168,191)'
|
||||||
|
,'rgb(128,128,128)'
|
||||||
|
,'rgb(128,128,128)'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
},{"./style":9}],4:[function(require,module,exports){
|
||||||
|
var __dirname="/src";var style = require('./style');
|
||||||
|
// node-canvas
|
||||||
|
var Canvas = require('canvas');
|
||||||
|
if (typeof Image === "undefined") Image = Canvas.Image;
|
||||||
|
|
||||||
|
var font = {};
|
||||||
|
module.exports = font;
|
||||||
|
|
||||||
|
// hack for loading fonts in node... todo, fix this
|
||||||
|
font.img_path = "";
|
||||||
|
if (typeof document === "undefined") font.img_path = __dirname + "/../examples/web/"
|
||||||
|
|
||||||
|
|
||||||
|
font.list = {};
|
||||||
|
|
||||||
|
var fsexps = require('./font/fixedsys');
|
||||||
|
var cp437s = require('./font/cp437');
|
||||||
|
for (f in fsexps) font.list[fsexps[f].name] = fsexps[f];
|
||||||
|
for (f in cp437s) font.list[cp437s[f].name] = cp437s[f];
|
||||||
|
|
||||||
|
style.font = 'fixedsys_8x16';
|
||||||
|
|
||||||
|
var err_font_load = function(){
|
||||||
|
console.log("couldn't load font")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
font.load = function(font_name, callback_fn){
|
||||||
|
if (!(font_name in font.list)) { return;} // todo error
|
||||||
|
|
||||||
|
var f = font.list[font_name]
|
||||||
|
|
||||||
|
if (f.loaded) {
|
||||||
|
callback_fn(f);
|
||||||
|
} else {
|
||||||
|
f.sheet = new Image();
|
||||||
|
f.sheet.crossOrigin = 'anonymous'
|
||||||
|
// node-canvas doesn't have addEventListener :(
|
||||||
|
f.sheet.onload = function(){
|
||||||
|
f.loaded = true
|
||||||
|
callback_fn(f);
|
||||||
|
}
|
||||||
|
f.sheet.src = font.img_path + f.sheet_url
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},{"./font/cp437":5,"./font/fixedsys":6,"./style":9,"canvas":11}],5:[function(require,module,exports){
|
||||||
|
var cp437s = [[8,8],[8,12],[8,14],[8,16],[10,10],[10,16],[12,12],[16,16]]
|
||||||
|
var fonts = {};
|
||||||
|
module.exports = fonts;
|
||||||
|
|
||||||
|
// utf8 -> cp437 function by sheetjs
|
||||||
|
// edited from https://github.com/SheetJS/js-codepage/blob/master/bits/437.js
|
||||||
|
var cp437 = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d[i]] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })();
|
||||||
|
|
||||||
|
var render_char = function(font, char_value, ctx, ctx_x, ctx_y){
|
||||||
|
char_value = cp437.enc[String.fromCharCode(char_value)] | 0;
|
||||||
|
var sheet_x = (char_value % font.sheet_w_in_chars) * font.char_w
|
||||||
|
var sheet_y = ((char_value / font.sheet_w_in_chars) |0) * font.char_h
|
||||||
|
ctx.drawImage(font.sheet,
|
||||||
|
sheet_x|0, sheet_y|0, font.char_w, font.char_h,
|
||||||
|
ctx_x|0, ctx_y|0, font.char_w, font.char_h)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0, wh; wh=cp437s[i]; i++){
|
||||||
|
var font = {};
|
||||||
|
font.is_char_blank = require('../fontutil').is_char_blank;
|
||||||
|
font.render_char = render_char;
|
||||||
|
font.name = 'cp437_' + wh[0] + 'x' + wh[1];
|
||||||
|
font.sheet_url = './img/' + font.name + '.png'
|
||||||
|
font.sheet_w_in_chars = 16;
|
||||||
|
font.char_w = wh[0]
|
||||||
|
font.char_h = wh[1]
|
||||||
|
fonts[font.name] = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// window.cp437 = cp437;
|
||||||
|
|
||||||
|
},{"../fontutil":7}],6:[function(require,module,exports){
|
||||||
|
var fsexps = [[8,16,0],[8,15,1],[8,8,5]]
|
||||||
|
var fonts = {};
|
||||||
|
module.exports = fonts;
|
||||||
|
|
||||||
|
var render_char = function(font, char_value, ctx, ctx_x, ctx_y, char){
|
||||||
|
var sheet_x = 0, sheet_y = 3;
|
||||||
|
if (char_value >= 0x20 && char_value <= 0x7e){ // ascii
|
||||||
|
sheet_x = (char_value - 0x20) * font.char_w_sheet
|
||||||
|
if (char.i){ // italic
|
||||||
|
sheet_y = 1 * font.char_h_sheet + 3
|
||||||
|
}
|
||||||
|
} else if (char_value >= 0x80 && char_value <= 0xff){ // latin-1
|
||||||
|
sheet_x = (char_value - 0x80) * font.char_w_sheet;
|
||||||
|
sheet_y = 2 * font.char_h_sheet + 3
|
||||||
|
} else if (char_value >= 0x0100 && char_value <= 0x017f){ // latin a
|
||||||
|
sheet_x = (char_value - 0x0100) * font.char_w_sheet;
|
||||||
|
sheet_y = 3 * font.char_h_sheet + 3
|
||||||
|
} else if (char_value >= 0x0180 && char_value <= 0x024f){ // latin b
|
||||||
|
sheet_x = (char_value - 0x0180) * font.char_w_sheet;
|
||||||
|
sheet_y = 4 * font.char_h_sheet + 3
|
||||||
|
} else if (char_value >= 0x2500 && char_value <= 0x25ff){ // geom
|
||||||
|
sheet_x = (char_value - 0x2500) * font.char_w_sheet;
|
||||||
|
sheet_y = 5 * font.char_h_sheet + 3
|
||||||
|
} else if (char_value >= 0x2600 && char_value <= 0x26ff){ // emoji
|
||||||
|
sheet_x = (char_value - 0x2600) * font.char_w_sheet;
|
||||||
|
sheet_y = 6 * font.char_h_sheet + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// var sheet_x = (char_value % font.sheet_w_in_chars) * font.char_w
|
||||||
|
// var sheet_y = ((char_value / font.sheet_w_in_chars) |0) * font.char_h + 3
|
||||||
|
ctx.drawImage(font.sheet,
|
||||||
|
sheet_x|0, (sheet_y|0) + font.y_adj, font.char_w, font.char_h,
|
||||||
|
ctx_x|0, ctx_y|0, font.char_w, font.char_h)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i=0, wh; wh=fsexps[i]; i++){
|
||||||
|
var font = {
|
||||||
|
name: 'fixedsys_' + wh[0] + 'x' + wh[1],
|
||||||
|
sheet_url: './img/fsex-simple.png',
|
||||||
|
sheet_w_in_chars: 128,
|
||||||
|
char_w_sheet: 8,
|
||||||
|
char_h_sheet: 16,
|
||||||
|
char_w: wh[0],
|
||||||
|
char_h: wh[1],
|
||||||
|
y_adj: wh[2],
|
||||||
|
is_char_blank: require('../fontutil').is_char_blank,
|
||||||
|
render_char: render_char
|
||||||
|
}
|
||||||
|
fonts[font.name] = font
|
||||||
|
}
|
||||||
|
},{"../fontutil":7}],7:[function(require,module,exports){
|
||||||
|
var util = {};
|
||||||
|
module.exports = util;
|
||||||
|
|
||||||
|
util.is_char_blank = function(char_value){
|
||||||
|
if (char_value === 32) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
util.render_char = function(font, char_value, ctx, ctx_x, ctx_y){
|
||||||
|
var sheet_x = (char_value % font.sheet_w_in_chars) * font.char_w
|
||||||
|
var sheet_y = ((char_value / font.sheet_w_in_chars) |0) * font.char_h
|
||||||
|
ctx.drawImage(font.sheet,
|
||||||
|
sheet_x|0, sheet_y|0, font.char_w, font.char_h,
|
||||||
|
ctx_x|0, ctx_y|0, font.char_w, font.char_h)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
},{}],8:[function(require,module,exports){
|
||||||
|
var char_color = '\x03';
|
||||||
|
|
||||||
|
var make_colorcode_fgbg = function(fg, bg){
|
||||||
|
// pad numbers: this prevents irc parsing confusion
|
||||||
|
// when the character after the colorcode is a number
|
||||||
|
if (fg < 10) fg = "0" + fg;
|
||||||
|
if (bg < 10) bg = "0" + bg;
|
||||||
|
return char_color + fg + "," + bg
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorcode_from_json = function(json, opts){
|
||||||
|
var out = "";
|
||||||
|
for (var li=0, line; line=json.lines[li]; li++){
|
||||||
|
for (var ci=0, char; char=line[ci]; ci++){
|
||||||
|
out += make_colorcode_fgbg(char.fg, char.bg)
|
||||||
|
out += String.fromCharCode(char.value)
|
||||||
|
}
|
||||||
|
out += "\n";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = colorcode_from_json;
|
||||||
|
|
||||||
|
},{}],9:[function(require,module,exports){
|
||||||
|
// default settings for fonts, colors, etc
|
||||||
|
var style = {};
|
||||||
|
module.exports = style;
|
||||||
|
|
||||||
|
},{}],10:[function(require,module,exports){
|
||||||
|
var char_color = '\x03';
|
||||||
|
var regexp_color = /(^[\d]{1,2})?(?:,([\d]{1,2}))?/;
|
||||||
|
|
||||||
|
var style_chars = {
|
||||||
|
'\x02': 'bold',
|
||||||
|
'\x1d': 'italic',
|
||||||
|
'\x1f': 'underline',
|
||||||
|
'\x0f': 'reset',
|
||||||
|
'\x16': 'inverse'
|
||||||
|
};
|
||||||
|
|
||||||
|
var Style = function(style){
|
||||||
|
this.b = style.b;
|
||||||
|
this.i = style.i;
|
||||||
|
this.u = style.u;
|
||||||
|
this.fg = style.fg;
|
||||||
|
this.bg = style.bg;
|
||||||
|
};
|
||||||
|
|
||||||
|
var style_fns = {};
|
||||||
|
|
||||||
|
style_fns.bold = function(style){ style.b = !style.b };
|
||||||
|
|
||||||
|
style_fns.italic = function(style){ style.i = !style.i };
|
||||||
|
|
||||||
|
style_fns.underline = function(style){ style.u = !style.u };
|
||||||
|
|
||||||
|
style_fns.inverse = function(style){
|
||||||
|
var tmp = style.fg;
|
||||||
|
style.fg = style.bg;
|
||||||
|
style.bg = tmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
style_fns.reset = function(style, base_style){
|
||||||
|
style.b = base_style.b;
|
||||||
|
style.i = base_style.i;
|
||||||
|
style.u = base_style.u;
|
||||||
|
style.fg = base_style.fg;
|
||||||
|
style.bg = base_style.bg;
|
||||||
|
};
|
||||||
|
|
||||||
|
var colorcode_to_json = function(string, opts){
|
||||||
|
// looks like its already converted
|
||||||
|
if (typeof string === 'object' &&
|
||||||
|
'lines' in string &&
|
||||||
|
'w' in string &&
|
||||||
|
'h' in string)
|
||||||
|
return string;
|
||||||
|
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
var d = colorcode_to_json.defaults;
|
||||||
|
|
||||||
|
var base_style = {
|
||||||
|
b: "b" in opts ? opts.b : d.b,
|
||||||
|
i: "i" in opts ? opts.i : d.i,
|
||||||
|
u: "u" in opts ? opts.u : d.u,
|
||||||
|
fg: "fg" in opts ? opts.fg : d.fg,
|
||||||
|
bg: "bg" in opts ? opts.bg : d.bg
|
||||||
|
};
|
||||||
|
|
||||||
|
var lines_in = string.split(/\r?\n/);
|
||||||
|
var lines_out = [];
|
||||||
|
var w = 0, h = 0;
|
||||||
|
|
||||||
|
for (var i=0; i<lines_in.length; i++){
|
||||||
|
var line = lines_in[i];
|
||||||
|
if (line.length === 0) continue; // skip blank lines
|
||||||
|
var json_line = line_to_json(line, base_style);
|
||||||
|
if (w < json_line.length) w = json_line.length;
|
||||||
|
lines_out.push(json_line);
|
||||||
|
h++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {w:w, h:h, lines:lines_out};
|
||||||
|
};
|
||||||
|
|
||||||
|
colorcode_to_json.defaults = {
|
||||||
|
b: false
|
||||||
|
, i: false
|
||||||
|
, u: false
|
||||||
|
, fg: 1
|
||||||
|
, bg: 99
|
||||||
|
};
|
||||||
|
|
||||||
|
var line_to_json = function(line, base_style){
|
||||||
|
var out = [];
|
||||||
|
var pos = -1;
|
||||||
|
var len = line.length -1;
|
||||||
|
var char;
|
||||||
|
var style = new Style(base_style);
|
||||||
|
|
||||||
|
while (pos < len){ pos++;
|
||||||
|
|
||||||
|
char = line[pos];
|
||||||
|
|
||||||
|
// next char is a styling char
|
||||||
|
if (char in style_chars){
|
||||||
|
style_fns[style_chars[char]](style, base_style);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// next char is a color styling char, with possible color nums after
|
||||||
|
if (char === char_color){
|
||||||
|
var matches = line.substr(pos+1,5).match(regexp_color);
|
||||||
|
|
||||||
|
// \x03 without color code is a soft style reset
|
||||||
|
if (matches[1] === undefined && matches[2] === undefined) {
|
||||||
|
style.fg = base_style.fg;
|
||||||
|
style.bg = base_style.bg;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches[1] !== undefined)
|
||||||
|
style.fg = Number(matches[1]);
|
||||||
|
|
||||||
|
if (matches[2] !== undefined)
|
||||||
|
style.bg = Number(matches[2]);
|
||||||
|
|
||||||
|
pos += matches[0].length;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, next char is treated as normal content
|
||||||
|
var data = new Style(style);
|
||||||
|
//data.value = char;
|
||||||
|
data.value = char.charCodeAt(0);
|
||||||
|
|
||||||
|
out.push(data);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = colorcode_to_json;
|
||||||
|
|
||||||
|
},{}],11:[function(require,module,exports){
|
||||||
|
|
||||||
|
},{}]},{},[1])
|
||||||
|
(1)
|
||||||
|
});
|
58
js/vendor/dataUriToBlob.js
vendored
Normal file
58
js/vendor/dataUriToBlob.js
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
var dataUriToUint8Array = function(uri){
|
||||||
|
var data = uri.split(',')[1];
|
||||||
|
var bytes = atob(data);
|
||||||
|
var buf = new ArrayBuffer(bytes.length);
|
||||||
|
var u8 = new Uint8Array(buf);
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
u8[i] = bytes.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return u8
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dataUriToBlob = (function(){
|
||||||
|
/**
|
||||||
|
* Blob constructor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Blob = window.Blob;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ArrayBufferView support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var hasArrayBufferView = new Blob([new Uint8Array(100)]).size == 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a `Blob` for the given data `uri`.
|
||||||
|
*
|
||||||
|
* @param {String} uri
|
||||||
|
* @return {Blob}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
var dataUriToBlob = function(uri){
|
||||||
|
var data = uri.split(',')[1];
|
||||||
|
var bytes = atob(data);
|
||||||
|
var buf = new ArrayBuffer(bytes.length);
|
||||||
|
var arr = new Uint8Array(buf);
|
||||||
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
|
arr[i] = bytes.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasArrayBufferView) arr = buf;
|
||||||
|
var blob = new Blob([arr], { type: mime(uri) });
|
||||||
|
blob.slice = blob.slice || blob.webkitSlice;
|
||||||
|
return blob;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data uri mime type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function mime(uri) {
|
||||||
|
return uri.split(';')[0].slice(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataUriToBlob;
|
||||||
|
|
||||||
|
})()
|
167
js/vendor/oktween.js
vendored
Normal file
167
js/vendor/oktween.js
vendored
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
oktween.add({
|
||||||
|
obj: el.style,
|
||||||
|
units: "px",
|
||||||
|
from: { left: 0 },
|
||||||
|
to: { left: 100 },
|
||||||
|
duration: 1000,
|
||||||
|
easing: oktween.easing.circ_out,
|
||||||
|
update: function(obj){
|
||||||
|
console.log(obj.left)
|
||||||
|
}
|
||||||
|
finished: function(){
|
||||||
|
console.log("done")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
var oktween = (function(){
|
||||||
|
var oktween = {}
|
||||||
|
var tweens = oktween.tweens = []
|
||||||
|
var last_t = 0
|
||||||
|
var id = 0
|
||||||
|
oktween.speed = 1
|
||||||
|
oktween.raf = requestAnimationFrame
|
||||||
|
oktween.add = function(tween){
|
||||||
|
tween.id = id++
|
||||||
|
tween.obj = tween.obj || {}
|
||||||
|
if (tween.easing) {
|
||||||
|
if (typeof tween.easing == "string") {
|
||||||
|
tween.easing = oktween.easing[tween.easing]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tween.easing = oktween.easing.linear
|
||||||
|
}
|
||||||
|
if (! ('from' in tween) && ! ('to' in tween)) {
|
||||||
|
tween.keys = []
|
||||||
|
}
|
||||||
|
else if (! ('from' in tween) ) {
|
||||||
|
tween.from = {}
|
||||||
|
tween.keys = Object.keys(tween.to)
|
||||||
|
tween.keys.forEach(function(prop){
|
||||||
|
tween.from[prop] = parseFloat(tween.obj[prop])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tween.keys = Object.keys(tween.from)
|
||||||
|
}
|
||||||
|
tween.delay = tween.delay || 0
|
||||||
|
tween.start = last_t + tween.delay
|
||||||
|
tween.done = false
|
||||||
|
tween.after = tween.after || []
|
||||||
|
tween.then = function(fn){ tween.after.push(fn); return tween }
|
||||||
|
tween.cancel = function(){
|
||||||
|
var index = tweens.indexOf(tween)
|
||||||
|
if (index != -1) tweens.splice(index, 1)
|
||||||
|
tween.obj = null
|
||||||
|
tween.after = null
|
||||||
|
tween.done = null
|
||||||
|
}
|
||||||
|
tween.tick = 0
|
||||||
|
tween.skip = tween.skip || 1
|
||||||
|
tween.dt = 0
|
||||||
|
tweens.push(tween)
|
||||||
|
return tween
|
||||||
|
}
|
||||||
|
oktween.update = function(t) {
|
||||||
|
oktween.raf(oktween.update)
|
||||||
|
last_t = t * oktween.speed
|
||||||
|
if (tweens.length == 0) return
|
||||||
|
var done = false
|
||||||
|
tweens.forEach(function(tween, i){
|
||||||
|
var dt = Math.min(1.0, (t - tween.start) / tween.duration)
|
||||||
|
tween.tick++
|
||||||
|
if (dt < 0 || (dt < 1 && (tween.tick % tween.skip != 0))) return
|
||||||
|
var ddt = tween.dt = tween.easing(dt)
|
||||||
|
tween.keys.forEach(function(prop){
|
||||||
|
val = lerp( ddt, tween.from[prop], tween.to[prop] )
|
||||||
|
if (tween.round) val = Math.round(val)
|
||||||
|
if (tween.units) val = (Math.round(val)) + tween.units
|
||||||
|
tween.obj[prop] = val
|
||||||
|
})
|
||||||
|
tween.update && tween.update(tween.obj, dt)
|
||||||
|
if (dt == 1) {
|
||||||
|
tween.finished && tween.finished(tween)
|
||||||
|
if (tween.after.length) {
|
||||||
|
var twn = tween.after.shift()
|
||||||
|
twn.obj = twn.obj || tween.obj
|
||||||
|
twn.after = tween.after
|
||||||
|
oktween.add(twn)
|
||||||
|
}
|
||||||
|
if (tween.loop) {
|
||||||
|
tween.start = t + tween.delay
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
done = tween.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (done) {
|
||||||
|
tweens = tweens.filter(function(tween){ return ! tween.done })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function lerp(n,a,b){ return (b-a)*n+a }
|
||||||
|
|
||||||
|
// requestAnimationFrame(oktween.update)
|
||||||
|
|
||||||
|
oktween.easing = {
|
||||||
|
linear: function(t){
|
||||||
|
return t
|
||||||
|
},
|
||||||
|
circ_out: function(t) {
|
||||||
|
return Math.sqrt(1 - (t = t - 1) * t)
|
||||||
|
},
|
||||||
|
circ_in: function(t){
|
||||||
|
return -(Math.sqrt(1 - (t * t)) - 1)
|
||||||
|
},
|
||||||
|
circ_in_out: function(t) {
|
||||||
|
return ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1)
|
||||||
|
},
|
||||||
|
quad_in: function(n){
|
||||||
|
return Math.pow(n, 2)
|
||||||
|
},
|
||||||
|
quad_out: function(n){
|
||||||
|
return n * (n - 2) * -1
|
||||||
|
},
|
||||||
|
quad_in_out: function(n){
|
||||||
|
n = n * 2
|
||||||
|
if(n < 1){ return Math.pow(n, 2) / 2 }
|
||||||
|
return -1 * ((--n) * (n - 2) - 1) / 2
|
||||||
|
},
|
||||||
|
cubic_bezier: function (mX1, mY1, mX2, mY2) {
|
||||||
|
function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
|
||||||
|
function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
|
||||||
|
function C(aA1) { return 3.0 * aA1; }
|
||||||
|
|
||||||
|
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
||||||
|
function CalcBezier(aT, aA1, aA2) {
|
||||||
|
return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
|
||||||
|
function GetSlope(aT, aA1, aA2) {
|
||||||
|
return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetTForX(aX) {
|
||||||
|
// Newton raphson iteration
|
||||||
|
var aGuessT = aX;
|
||||||
|
for (var i = 0; i < 10; ++i) {
|
||||||
|
var currentSlope = GetSlope(aGuessT, mX1, mX2);
|
||||||
|
if (currentSlope == 0.0) return aGuessT;
|
||||||
|
var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
|
||||||
|
aGuessT -= currentX / currentSlope;
|
||||||
|
}
|
||||||
|
return aGuessT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(aX) {
|
||||||
|
if (mX1 == mY1 && mX2 == mY2) return aX; // linear
|
||||||
|
return CalcBezier(aX, mY1, mY2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oktween
|
||||||
|
})()
|
141
js/vendor/text-encoder-lite.js
vendored
Normal file
141
js/vendor/text-encoder-lite.js
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// taken from https://github.com/coolaj86/TextEncoderLite/blob/master/index.js
|
||||||
|
// added polyfill at bottom
|
||||||
|
|
||||||
|
function TextEncoderLite() {
|
||||||
|
}
|
||||||
|
function TextDecoderLite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Taken from https://github.com/feross/buffer/blob/master/index.js
|
||||||
|
// Thanks Feross et al! :-)
|
||||||
|
|
||||||
|
function utf8ToBytes (string, units) {
|
||||||
|
units = units || Infinity
|
||||||
|
var codePoint
|
||||||
|
var length = string.length
|
||||||
|
var leadSurrogate = null
|
||||||
|
var bytes = []
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
for (; i < length; i++) {
|
||||||
|
codePoint = string.charCodeAt(i)
|
||||||
|
|
||||||
|
// is surrogate component
|
||||||
|
if (codePoint > 0xD7FF && codePoint < 0xE000) {
|
||||||
|
// last char was a lead
|
||||||
|
if (leadSurrogate) {
|
||||||
|
// 2 leads in a row
|
||||||
|
if (codePoint < 0xDC00) {
|
||||||
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||||
|
leadSurrogate = codePoint
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
// valid surrogate pair
|
||||||
|
codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000
|
||||||
|
leadSurrogate = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no lead yet
|
||||||
|
|
||||||
|
if (codePoint > 0xDBFF) {
|
||||||
|
// unexpected trail
|
||||||
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||||
|
continue
|
||||||
|
} else if (i + 1 === length) {
|
||||||
|
// unpaired lead
|
||||||
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
// valid lead
|
||||||
|
leadSurrogate = codePoint
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (leadSurrogate) {
|
||||||
|
// valid bmp char, but last char was a lead
|
||||||
|
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||||||
|
leadSurrogate = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode utf8
|
||||||
|
if (codePoint < 0x80) {
|
||||||
|
if ((units -= 1) < 0) break
|
||||||
|
bytes.push(codePoint)
|
||||||
|
} else if (codePoint < 0x800) {
|
||||||
|
if ((units -= 2) < 0) break
|
||||||
|
bytes.push(
|
||||||
|
codePoint >> 0x6 | 0xC0,
|
||||||
|
codePoint & 0x3F | 0x80
|
||||||
|
)
|
||||||
|
} else if (codePoint < 0x10000) {
|
||||||
|
if ((units -= 3) < 0) break
|
||||||
|
bytes.push(
|
||||||
|
codePoint >> 0xC | 0xE0,
|
||||||
|
codePoint >> 0x6 & 0x3F | 0x80,
|
||||||
|
codePoint & 0x3F | 0x80
|
||||||
|
)
|
||||||
|
} else if (codePoint < 0x200000) {
|
||||||
|
if ((units -= 4) < 0) break
|
||||||
|
bytes.push(
|
||||||
|
codePoint >> 0x12 | 0xF0,
|
||||||
|
codePoint >> 0xC & 0x3F | 0x80,
|
||||||
|
codePoint >> 0x6 & 0x3F | 0x80,
|
||||||
|
codePoint & 0x3F | 0x80
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid code point')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
function utf8Slice (buf, start, end) {
|
||||||
|
var res = ''
|
||||||
|
var tmp = ''
|
||||||
|
end = Math.min(buf.length, end || Infinity)
|
||||||
|
start = start || 0;
|
||||||
|
|
||||||
|
for (var i = start; i < end; i++) {
|
||||||
|
if (buf[i] <= 0x7F) {
|
||||||
|
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
|
||||||
|
tmp = ''
|
||||||
|
} else {
|
||||||
|
tmp += '%' + buf[i].toString(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res + decodeUtf8Char(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeUtf8Char (str) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(str)
|
||||||
|
} catch (err) {
|
||||||
|
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEncoderLite.prototype.encode = function (str) {
|
||||||
|
var result;
|
||||||
|
|
||||||
|
if ('undefined' === typeof Uint8Array) {
|
||||||
|
result = utf8ToBytes(str);
|
||||||
|
} else {
|
||||||
|
result = new Uint8Array(utf8ToBytes(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
TextDecoderLite.prototype.decode = function (bytes) {
|
||||||
|
return utf8Slice(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
if (typeof TextEncoder === 'undefined') TextEncoder = TextEncoderLite
|
||||||
|
if (typeof TextDecoder === 'undefined') TextDecoder = TextDecoderLite
|
Loading…
Reference in New Issue
Block a user