├── .babelrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── blacktie ├── css │ └── black-tie.min.css └── fonts │ ├── bold │ ├── BlackTie-Bold-webfont.eot │ ├── BlackTie-Bold-webfont.svg │ ├── BlackTie-Bold-webfont.ttf │ ├── BlackTie-Bold-webfont.woff │ └── BlackTie-Bold-webfont.woff2 │ ├── brands │ ├── FontAwesomeBrands-Regular-webfont.eot │ ├── FontAwesomeBrands-Regular-webfont.svg │ ├── FontAwesomeBrands-Regular-webfont.ttf │ ├── FontAwesomeBrands-Regular-webfont.woff │ └── FontAwesomeBrands-Regular-webfont.woff2 │ ├── light │ ├── BlackTie-Light-webfont.eot │ ├── BlackTie-Light-webfont.svg │ ├── BlackTie-Light-webfont.ttf │ ├── BlackTie-Light-webfont.woff │ └── BlackTie-Light-webfont.woff2 │ ├── medium │ ├── BlackTie-Medium-webfont.eot │ ├── BlackTie-Medium-webfont.svg │ ├── BlackTie-Medium-webfont.ttf │ ├── BlackTie-Medium-webfont.woff │ └── BlackTie-Medium-webfont.woff2 │ └── solid │ ├── BlackTie-Solid-webfont.eot │ ├── BlackTie-Solid-webfont.svg │ ├── BlackTie-Solid-webfont.ttf │ ├── BlackTie-Solid-webfont.woff │ └── BlackTie-Solid-webfont.woff2 ├── index.html ├── lib ├── ace │ ├── ace.js │ ├── mode-glsl.js │ ├── snippets │ │ └── glsl.js │ └── theme-twilight.js ├── editor │ └── gk-inspector.js ├── exporter │ └── exporter-obj.js ├── fabricate.js ├── gk-acewrap.js ├── gk-component.js ├── gk-core.js ├── gk-fixedshader.js ├── gk-framework.js ├── gk-gameobject.js ├── gk-glwrap.js ├── gk-logger.js ├── gk-mouseorbit.js ├── gk-renderer.js ├── gk-resmgr.js ├── gk-respanel.js ├── gk-scenemgr.js ├── gk-timer.js ├── loader │ ├── loader-fbx.js │ └── loader-osgjs.js └── util │ └── gl-matrix-extension.js ├── main.js ├── package.json ├── renderer.js ├── res ├── mesh │ ├── box100.osgjs │ ├── box100.osgjs.bin │ ├── head.fbx │ ├── lucyh.fbx │ ├── quad2.osgjs │ ├── quad2.osgjs.bin │ ├── venusl.c4d │ └── venusl.fbx ├── shader │ ├── base_fs.glsl │ └── base_vs.glsl └── texture │ ├── ground.jpg │ ├── leaf.png │ ├── matcap.jpg │ ├── plaster.jpg │ └── white.jpg ├── screenshot.png ├── style.css └── test ├── loader-osgjs.js ├── package-build.js └── pkg-postprocess.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react" 5 | ], 6 | 7 | "plugins": [ 8 | "transform-object-rest-spread" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | bundle.js 5 | .idea 6 | *.log 7 | *.c4d 8 | res/package 9 | res/source 10 | electron-shadermonki* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.9.1" 4 | before_install: 5 | - npm install npm@latest -g 6 | install: 7 | - npm install 8 | - npm install browserify 9 | script: 10 | - npm run build-js 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 gameKnife 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | electron-shadermonki 2 | --- 3 | 4 | [![Build Status](https://travis-ci.org/gameknife/electron-shadermonki.svg?branch=master)](https://travis-ci.org/gameknife/electron-shadermonki) 5 | 6 | ![ss](screenshot.png) 7 | 8 | a research [rendermonkey](http://developer.amd.com/tools-and-sdks/archive/games-cgi/rendermonkey-toolsuite/) like app based on [electron](https://github.com/electron/electron) 9 | 10 | ### Startup 11 | 12 | * install [node.js](https://nodejs.org) 13 | * update [npm](https://www.npmjs.com) to latest 14 | ``` 15 | npm install npm@latest -g 16 | ``` 17 | * install [cnpm](https://npm.taobao.org/) if ur under gfw 18 | ``` 19 | npm install -g cnpm --registry=https://registry.npm.taobao.org 20 | ``` 21 | * install dependency 22 | ``` 23 | cnpm install 24 | ``` 25 | * start running 26 | ``` 27 | npm start 28 | ``` 29 | 30 | ### Usage 31 | 32 | * edit vs & fs shader file 33 | * press Ctrl + S || Command + S to save change, preview will change at realtime. 34 | 35 | ### Future Task 36 | 37 | 1. binary fbx mesh loader 38 | 1. ~~resource management~~ 39 | 1. ~~unity3d like gameobject & component system~~ 40 | 1. ~~osgjs mesh loader~~ 41 | 1. ~~obj format exporter~~ 42 | 1. ~~gl-matrix-integrate~~ 43 | 1. ~~real-time shadow~~ 44 | 1. lightmap support 45 | 1. deferred shading chain & ssao 46 | 1. progressive rendering 47 | 1. normalmap support 48 | 49 | ### Thanks to 50 | 51 | * [ACE](https://github.com/ajaxorg/ace) 52 | * [glcubic.js](https://github.com/doxas/glcubic.js) 53 | * [three.js](https://github.com/mrdoob/three.js) 54 | -------------------------------------------------------------------------------- /blacktie/css/black-tie.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * The Black Tie Font is commercial software. Please do not distribute. 3 | */ 4 | /* FONT PATH 5 | * -------------------------- */ 6 | @font-face { 7 | font-family: 'Black Tie'; 8 | src: url('../fonts/solid/BlackTie-Solid-webfont.eot?v=1.0.0'); 9 | src: url('../fonts/solid/BlackTie-Solid-webfont.eot?#iefix&v=1.0.0') format('embedded-opentype'), url('../fonts/solid/BlackTie-Solid-webfont.woff2?v=1.0.0') format('woff2'), url('../fonts/solid/BlackTie-Solid-webfont.woff?v=1.0.0') format('woff'), url('../fonts/solid/BlackTie-Solid-webfont.ttf?v=1.0.0') format('truetype'), url('../fonts/solid/BlackTie-Solid-webfont.svg?v=1.0.0#black_tiesolid') format('svg'); 10 | font-weight: 900; 11 | font-style: normal; 12 | } 13 | @font-face { 14 | font-family: 'Black Tie'; 15 | src: url('../fonts/bold/BlackTie-Bold-webfont.eot?v=1.0.0'); 16 | src: url('../fonts/bold/BlackTie-Bold-webfont.eot?#iefix&v=1.0.0') format('embedded-opentype'), url('../fonts/bold/BlackTie-Bold-webfont.woff2?v=1.0.0') format('woff2'), url('../fonts/bold/BlackTie-Bold-webfont.woff?v=1.0.0') format('woff'), url('../fonts/bold/BlackTie-Bold-webfont.ttf?v=1.0.0') format('truetype'), url('../fonts/bold/BlackTie-Bold-webfont.svg?v=1.0.0#black_tiebold') format('svg'); 17 | font-weight: 700; 18 | font-style: normal; 19 | } 20 | @font-face { 21 | font-family: 'Black Tie'; 22 | src: url('../fonts/medium/BlackTie-Medium-webfont.eot?v=1.0.0'); 23 | src: url('../fonts/medium/BlackTie-Medium-webfont.eot?#iefix&v=1.0.0') format('embedded-opentype'), url('../fonts/medium/BlackTie-Medium-webfont.woff2?v=1.0.0') format('woff2'), url('../fonts/medium/BlackTie-Medium-webfont.woff?v=1.0.0') format('woff'), url('../fonts/medium/BlackTie-Medium-webfont.ttf?v=1.0.0') format('truetype'), url('../fonts/medium/BlackTie-Medium-webfont.svg?v=1.0.0#black_tiemedium') format('svg'); 24 | font-weight: 400; 25 | font-style: normal; 26 | } 27 | @font-face { 28 | font-family: 'Black Tie'; 29 | src: url('../fonts/light/BlackTie-Light-webfont.eot?v=1.0.0'); 30 | src: url('../fonts/light/BlackTie-Light-webfont.eot?#iefix&v=1.0.0') format('embedded-opentype'), url('../fonts/light/BlackTie-Light-webfont.woff2?v=1.0.0') format('woff2'), url('../fonts/light/BlackTie-Light-webfont.woff?v=1.0.0') format('woff'), url('../fonts/light/BlackTie-Light-webfont.ttf?v=1.0.0') format('truetype'), url('../fonts/light/BlackTie-Light-webfont.svg?v=1.0.0#black_tielight') format('svg'); 31 | font-weight: 200; 32 | font-style: normal; 33 | } 34 | @font-face { 35 | font-family: 'Font Awesome Brands'; 36 | src: url('../fonts/brands/FontAwesomeBrands-Regular-webfont.eot?v=1.0.0'); 37 | src: url('../fonts/brands/FontAwesomeBrands-Regular-webfont.eot?#iefix&v=1.0.0') format('embedded-opentype'), url('../fonts/brands/FontAwesomeBrands-Regular-webfont.woff2?v=1.0.0') format('woff2'), url('../fonts/brands/FontAwesomeBrands-Regular-webfont.woff?v=1.0.0') format('woff'), url('../fonts/brands/FontAwesomeBrands-Regular-webfont.ttf?v=1.0.0') format('truetype'), url('../fonts/brands/FontAwesomeBrands-Regular-webfont.svg?v=1.0.0#font_awesome_brandsregular') format('svg'); 38 | font-weight: normal; 39 | font-style: normal; 40 | } 41 | .bts, 42 | .btb, 43 | .btm, 44 | .btl, 45 | .fab { 46 | display: inline-block; 47 | font: normal normal normal 14px/1 "Black Tie"; 48 | font-size: inherit; 49 | vertical-align: -14.28571429%; 50 | text-rendering: auto; 51 | -webkit-font-smoothing: antialiased; 52 | -moz-osx-font-smoothing: grayscale; 53 | transform: translate(0, 0); 54 | } 55 | .bts { 56 | font-weight: 900; 57 | } 58 | .btb { 59 | font-weight: 700; 60 | } 61 | .btl { 62 | font-weight: 200; 63 | } 64 | .fab { 65 | font-family: "Font Awesome Brands"; 66 | } 67 | /* makes the font 25% smaller relative to the icon container */ 68 | .bt-sm { 69 | font-size: .7em; 70 | vertical-align: baseline; 71 | } 72 | /* makes the font 33% larger relative to the icon container */ 73 | .bt-lg { 74 | font-size: 1.33333333em; 75 | line-height: 0.75em; 76 | } 77 | .bt-2x { 78 | font-size: 2em; 79 | } 80 | .bt-3x { 81 | font-size: 3em; 82 | } 83 | .bt-4x { 84 | font-size: 4em; 85 | } 86 | .bt-5x { 87 | font-size: 5em; 88 | } 89 | .bt-lg, 90 | .bt-2x, 91 | .bt-3x, 92 | .bt-4x, 93 | .bt-5x { 94 | vertical-align: -30%; 95 | } 96 | .bt-fw { 97 | width: 1.28571429em; 98 | text-align: center; 99 | } 100 | .bt-ul { 101 | padding-left: 0; 102 | margin-left: 2.14285714em; 103 | list-style-type: none; 104 | } 105 | .bt-ul > li { 106 | position: relative; 107 | } 108 | .bt-li { 109 | position: absolute; 110 | left: -2.14285714em; 111 | width: 2.14285714em; 112 | top: 0.14285714em; 113 | text-align: center; 114 | } 115 | .bt-li.bt-lg { 116 | left: -2em; 117 | } 118 | .bt-border { 119 | padding: .2em; 120 | border: solid 0.08em #eeeeee; 121 | border-radius: .1em; 122 | } 123 | .pull-right { 124 | float: right; 125 | } 126 | .pull-left { 127 | float: left; 128 | } 129 | .bts.pull-left, 130 | .btb.pull-left, 131 | .btm.pull-left, 132 | .btl.pull-left, 133 | .fab.pull-left { 134 | margin-right: .3em; 135 | } 136 | .bts.pull-right, 137 | .btb.pull-right, 138 | .btm.pull-right, 139 | .btl.pull-right, 140 | .fab.pull-right { 141 | margin-left: .3em; 142 | } 143 | .bt-spin { 144 | -webkit-animation: bt-spin 2s infinite linear; 145 | animation: bt-spin 2s infinite linear; 146 | } 147 | .bt-pulse { 148 | -webkit-animation: bt-spin 1s infinite steps(8); 149 | animation: bt-spin 1s infinite steps(8); 150 | } 151 | @-webkit-keyframes bt-spin { 152 | 0% { 153 | -webkit-transform: rotate(0deg); 154 | transform: rotate(0deg); 155 | } 156 | 100% { 157 | -webkit-transform: rotate(359deg); 158 | transform: rotate(359deg); 159 | } 160 | } 161 | @keyframes bt-spin { 162 | 0% { 163 | -webkit-transform: rotate(0deg); 164 | transform: rotate(0deg); 165 | } 166 | 100% { 167 | -webkit-transform: rotate(359deg); 168 | transform: rotate(359deg); 169 | } 170 | } 171 | .bt-rotate-90 { 172 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); 173 | -webkit-transform: rotate(90deg); 174 | -ms-transform: rotate(90deg); 175 | transform: rotate(90deg); 176 | } 177 | .bt-rotate-180 { 178 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); 179 | -webkit-transform: rotate(180deg); 180 | -ms-transform: rotate(180deg); 181 | transform: rotate(180deg); 182 | } 183 | .bt-rotate-270 { 184 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); 185 | -webkit-transform: rotate(270deg); 186 | -ms-transform: rotate(270deg); 187 | transform: rotate(270deg); 188 | } 189 | .bt-flip-horizontal { 190 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); 191 | -webkit-transform: scale(-1, 1); 192 | -ms-transform: scale(-1, 1); 193 | transform: scale(-1, 1); 194 | } 195 | .bt-flip-vertical { 196 | filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); 197 | -webkit-transform: scale(1, -1); 198 | -ms-transform: scale(1, -1); 199 | transform: scale(1, -1); 200 | } 201 | :root .bt-rotate-90, 202 | :root .bt-rotate-180, 203 | :root .bt-rotate-270, 204 | :root .bt-flip-horizontal, 205 | :root .bt-flip-vertical { 206 | filter: none; 207 | } 208 | .bt-stack { 209 | position: relative; 210 | display: inline-block; 211 | width: 1.28571429em; 212 | height: 1em; 213 | line-height: 1em; 214 | vertical-align: baseline; 215 | } 216 | .bt-stack-sm { 217 | position: absolute; 218 | top: 0; 219 | left: 0; 220 | line-height: inherit; 221 | font-size: .5em; 222 | } 223 | .bt-stack-1x, 224 | .bt-stack-sm { 225 | display: inline-block; 226 | width: 100%; 227 | text-align: center; 228 | } 229 | .bt-inverse { 230 | color: #ffffff; 231 | } 232 | /* Black Tie uses the Unicode Private Use Area (PUA) to ensure screen 233 | readers do not read off random characters that represent icons */ 234 | .bt-bars:before { 235 | content: "\f000"; 236 | } 237 | .bt-envelope:before { 238 | content: "\f001"; 239 | } 240 | .bt-search:before { 241 | content: "\f002"; 242 | } 243 | .bt-search-plus:before { 244 | content: "\f003"; 245 | } 246 | .bt-search-minus:before { 247 | content: "\f004"; 248 | } 249 | .bt-phone:before { 250 | content: "\f005"; 251 | } 252 | .bt-comment:before { 253 | content: "\f007"; 254 | } 255 | .bt-commenting:before { 256 | content: "\f008"; 257 | } 258 | .bt-comments:before { 259 | content: "\f009"; 260 | } 261 | .bt-rss:before { 262 | content: "\f00a"; 263 | } 264 | .bt-times:before { 265 | content: "\f00c"; 266 | } 267 | .bt-times-circle:before { 268 | content: "\f00d"; 269 | } 270 | .bt-clock:before { 271 | content: "\f00e"; 272 | } 273 | .bt-star:before { 274 | content: "\f010"; 275 | } 276 | .bt-star-half:before { 277 | content: "\f011"; 278 | } 279 | .bt-check:before { 280 | content: "\f012"; 281 | } 282 | .bt-check-circle:before { 283 | content: "\f013"; 284 | } 285 | .bt-check-square:before { 286 | content: "\f014"; 287 | } 288 | .bt-th:before { 289 | content: "\f015"; 290 | } 291 | .bt-th-large:before { 292 | content: "\f016"; 293 | } 294 | .bt-heart:before { 295 | content: "\f017"; 296 | } 297 | .bt-heart-half:before { 298 | content: "\f018"; 299 | } 300 | .bt-calendar:before { 301 | content: "\f019"; 302 | } 303 | .bt-shopping-cart:before { 304 | content: "\f01a"; 305 | } 306 | .bt-plus:before { 307 | content: "\f01b"; 308 | } 309 | .bt-plus-circle:before { 310 | content: "\f01c"; 311 | } 312 | .bt-plus-square:before { 313 | content: "\f01d"; 314 | } 315 | .bt-pen:before { 316 | content: "\f01e"; 317 | } 318 | .bt-minus:before { 319 | content: "\f021"; 320 | } 321 | .bt-minus-circle:before { 322 | content: "\f022"; 323 | } 324 | .bt-minus-square:before { 325 | content: "\f023"; 326 | } 327 | .bt-pencil:before { 328 | content: "\f024"; 329 | } 330 | .bt-edit:before { 331 | content: "\f025"; 332 | } 333 | .bt-thumbs-up:before { 334 | content: "\f026"; 335 | } 336 | .bt-thumbs-down:before { 337 | content: "\f027"; 338 | } 339 | .bt-gear:before { 340 | content: "\f028"; 341 | } 342 | .bt-trash:before { 343 | content: "\f029"; 344 | } 345 | .bt-file:before { 346 | content: "\f02a"; 347 | } 348 | .bt-info-circle:before { 349 | content: "\f02b"; 350 | } 351 | .bt-label:before { 352 | content: "\f02c"; 353 | } 354 | .bt-rocket:before { 355 | content: "\f02d"; 356 | } 357 | .bt-book:before { 358 | content: "\f02e"; 359 | } 360 | .bt-book-open:before { 361 | content: "\f02f"; 362 | } 363 | .bt-notebook:before { 364 | content: "\f030"; 365 | } 366 | .bt-camera:before { 367 | content: "\f031"; 368 | } 369 | .bt-folder:before { 370 | content: "\f032"; 371 | } 372 | .bt-quote-left:before { 373 | content: "\f036"; 374 | } 375 | .bt-quote-right:before { 376 | content: "\f037"; 377 | } 378 | .bt-eye:before { 379 | content: "\f038"; 380 | } 381 | .bt-lock:before { 382 | content: "\f039"; 383 | } 384 | .bt-lock-open:before { 385 | content: "\f03a"; 386 | } 387 | .bt-gift:before { 388 | content: "\f03b"; 389 | } 390 | .bt-spinner-clock:before { 391 | content: "\f03c"; 392 | } 393 | .bt-spinner:before { 394 | content: "\f03d"; 395 | } 396 | .bt-wrench:before { 397 | content: "\f03e"; 398 | } 399 | .bt-cloud:before { 400 | content: "\f040"; 401 | } 402 | .bt-cloud-upload:before { 403 | content: "\f041"; 404 | } 405 | .bt-cloud-download:before { 406 | content: "\f042"; 407 | } 408 | .bt-sync:before { 409 | content: "\f043"; 410 | } 411 | .bt-question-circle:before { 412 | content: "\f044"; 413 | } 414 | .bt-share:before { 415 | content: "\f045"; 416 | } 417 | .bt-briefcase:before { 418 | content: "\f046"; 419 | } 420 | .bt-money:before { 421 | content: "\f047"; 422 | } 423 | .bt-megaphone:before { 424 | content: "\f048"; 425 | } 426 | .bt-sign-in:before { 427 | content: "\f049"; 428 | } 429 | .bt-sign-out:before { 430 | content: "\f04a"; 431 | } 432 | .bt-film:before { 433 | content: "\f04b"; 434 | } 435 | .bt-trophy:before { 436 | content: "\f04c"; 437 | } 438 | .bt-code:before { 439 | content: "\f04d"; 440 | } 441 | .bt-light-bulb:before { 442 | content: "\f04e"; 443 | } 444 | .bt-print:before { 445 | content: "\f050"; 446 | } 447 | .bt-fax:before { 448 | content: "\f051"; 449 | } 450 | .bt-video:before { 451 | content: "\f052"; 452 | } 453 | .bt-signal:before { 454 | content: "\f053"; 455 | } 456 | .bt-sitemap:before { 457 | content: "\f054"; 458 | } 459 | .bt-upload:before { 460 | content: "\f055"; 461 | } 462 | .bt-download:before { 463 | content: "\f056"; 464 | } 465 | .bt-key:before { 466 | content: "\f057"; 467 | } 468 | .bt-mug:before { 469 | content: "\f058"; 470 | } 471 | .bt-bookmark:before { 472 | content: "\f059"; 473 | } 474 | .bt-flag:before { 475 | content: "\f05a"; 476 | } 477 | .bt-external-link:before { 478 | content: "\f05b"; 479 | } 480 | .bt-smile:before { 481 | content: "\f05c"; 482 | } 483 | .bt-frown:before { 484 | content: "\f05d"; 485 | } 486 | .bt-meh:before { 487 | content: "\f05e"; 488 | } 489 | .bt-magic:before { 490 | content: "\f060"; 491 | } 492 | .bt-bolt:before { 493 | content: "\f061"; 494 | } 495 | .bt-exclamation-triangle:before { 496 | content: "\f062"; 497 | } 498 | .bt-exclamation-circle:before { 499 | content: "\f063"; 500 | } 501 | .bt-flask:before { 502 | content: "\f064"; 503 | } 504 | .bt-music:before { 505 | content: "\f065"; 506 | } 507 | .bt-push-pin:before { 508 | content: "\f066"; 509 | } 510 | .bt-shield:before { 511 | content: "\f067"; 512 | } 513 | .bt-sort:before { 514 | content: "\f068"; 515 | } 516 | .bt-reply:before { 517 | content: "\f069"; 518 | } 519 | .bt-forward:before { 520 | content: "\f06a"; 521 | } 522 | .bt-reply-all:before { 523 | content: "\f06b"; 524 | } 525 | .bt-forward-all:before { 526 | content: "\f06c"; 527 | } 528 | .bt-bell:before { 529 | content: "\f06d"; 530 | } 531 | .bt-bell-off:before { 532 | content: "\f06e"; 533 | } 534 | .bt-ban:before { 535 | content: "\f070"; 536 | } 537 | .bt-database:before { 538 | content: "\f071"; 539 | } 540 | .bt-hard-drive:before { 541 | content: "\f072"; 542 | } 543 | .bt-merge:before { 544 | content: "\f073"; 545 | } 546 | .bt-fork:before { 547 | content: "\f074"; 548 | } 549 | .bt-wifi:before { 550 | content: "\f075"; 551 | } 552 | .bt-paper-plane:before { 553 | content: "\f076"; 554 | } 555 | .bt-inbox:before { 556 | content: "\f077"; 557 | } 558 | .bt-fire:before { 559 | content: "\f078"; 560 | } 561 | .bt-play:before { 562 | content: "\f079"; 563 | } 564 | .bt-pause:before { 565 | content: "\f07a"; 566 | } 567 | .bt-stop:before { 568 | content: "\f08b"; 569 | } 570 | .bt-play-circle:before { 571 | content: "\f07b"; 572 | } 573 | .bt-next:before { 574 | content: "\f07c"; 575 | } 576 | .bt-previous:before { 577 | content: "\f07d"; 578 | } 579 | .bt-repeat:before { 580 | content: "\f07e"; 581 | } 582 | .bt-fast-forward:before { 583 | content: "\f080"; 584 | } 585 | .bt-fast-reverse:before { 586 | content: "\f081"; 587 | } 588 | .bt-volume:before { 589 | content: "\f082"; 590 | } 591 | .bt-volume-off:before { 592 | content: "\f083"; 593 | } 594 | .bt-volume-up:before { 595 | content: "\f084"; 596 | } 597 | .bt-volume-down:before { 598 | content: "\f085"; 599 | } 600 | .bt-maximize:before { 601 | content: "\f086"; 602 | } 603 | .bt-minimize:before { 604 | content: "\f087"; 605 | } 606 | .bt-closed-captions:before { 607 | content: "\f088"; 608 | } 609 | .bt-shuffle:before { 610 | content: "\f089"; 611 | } 612 | .bt-triangle:before { 613 | content: "\f08a"; 614 | } 615 | .bt-square:before { 616 | content: "\f08b"; 617 | } 618 | .bt-circle:before { 619 | content: "\f08c"; 620 | } 621 | .bt-hexagon:before { 622 | content: "\f08d"; 623 | } 624 | .bt-octagon:before { 625 | content: "\f08e"; 626 | } 627 | .bt-angle-up:before { 628 | content: "\f090"; 629 | } 630 | .bt-angle-down:before { 631 | content: "\f091"; 632 | } 633 | .bt-angle-left:before { 634 | content: "\f092"; 635 | } 636 | .bt-angle-right:before { 637 | content: "\f093"; 638 | } 639 | .bt-angles-up:before { 640 | content: "\f094"; 641 | } 642 | .bt-angles-down:before { 643 | content: "\f095"; 644 | } 645 | .bt-angles-left:before { 646 | content: "\f096"; 647 | } 648 | .bt-angles-right:before { 649 | content: "\f097"; 650 | } 651 | .bt-arrow-up:before { 652 | content: "\f098"; 653 | } 654 | .bt-arrow-down:before { 655 | content: "\f099"; 656 | } 657 | .bt-arrow-left:before { 658 | content: "\f09a"; 659 | } 660 | .bt-arrow-right:before { 661 | content: "\f09b"; 662 | } 663 | .bt-bar-chart:before { 664 | content: "\f09c"; 665 | } 666 | .bt-pie-chart:before { 667 | content: "\f09d"; 668 | } 669 | .bt-circle-arrow-up:before { 670 | content: "\f0a0"; 671 | } 672 | .bt-circle-arrow-down:before { 673 | content: "\f0a1"; 674 | } 675 | .bt-circle-arrow-left:before { 676 | content: "\f0a2"; 677 | } 678 | .bt-circle-arrow-right:before { 679 | content: "\f0a3"; 680 | } 681 | .bt-caret-up:before { 682 | content: "\f0a4"; 683 | } 684 | .bt-caret-down:before { 685 | content: "\f0a5"; 686 | } 687 | .bt-caret-left:before { 688 | content: "\f0a6"; 689 | } 690 | .bt-caret-right:before { 691 | content: "\f0a7"; 692 | } 693 | .bt-long-arrow-up:before { 694 | content: "\f0a8"; 695 | } 696 | .bt-long-arrow-down:before { 697 | content: "\f0a9"; 698 | } 699 | .bt-long-arrow-left:before { 700 | content: "\f0aa"; 701 | } 702 | .bt-long-arrow-right:before { 703 | content: "\f0ab"; 704 | } 705 | .bt-Bold:before { 706 | content: "\f0ac"; 707 | } 708 | .bt-italic:before { 709 | content: "\f0ad"; 710 | } 711 | .bt-underline:before { 712 | content: "\f0ae"; 713 | } 714 | .bt-link:before { 715 | content: "\f0b0"; 716 | } 717 | .bt-paper-clip:before { 718 | content: "\f0b1"; 719 | } 720 | .bt-align-left:before { 721 | content: "\f0b2"; 722 | } 723 | .bt-align-center:before { 724 | content: "\f0b3"; 725 | } 726 | .bt-align-right:before { 727 | content: "\f0b4"; 728 | } 729 | .bt-align-justify:before { 730 | content: "\f0b5"; 731 | } 732 | .bt-cut:before { 733 | content: "\f0b6"; 734 | } 735 | .bt-copy:before { 736 | content: "\f0b7"; 737 | } 738 | .bt-paste:before { 739 | content: "\f0b8"; 740 | } 741 | .bt-photo:before { 742 | content: "\f0b9"; 743 | } 744 | .bt-table:before { 745 | content: "\f0ba"; 746 | } 747 | .bt-ulist:before { 748 | content: "\f0bb"; 749 | } 750 | .bt-olist:before { 751 | content: "\f0bc"; 752 | } 753 | .bt-indent:before { 754 | content: "\f0bd"; 755 | } 756 | .bt-outdent:before { 757 | content: "\f0be"; 758 | } 759 | .bt-undo:before { 760 | content: "\f0c0"; 761 | } 762 | .bt-redo:before { 763 | content: "\f0c1"; 764 | } 765 | .bt-sup:before { 766 | content: "\f0c2"; 767 | } 768 | .bt-sub:before { 769 | content: "\f0c3"; 770 | } 771 | .bt-text-size:before { 772 | content: "\f0c4"; 773 | } 774 | .bt-text-color:before { 775 | content: "\f0c5"; 776 | } 777 | .bt-remove-formatting:before { 778 | content: "\f0c6"; 779 | } 780 | .bt-blockquote:before { 781 | content: "\f036"; 782 | } 783 | .bt-globe:before { 784 | content: "\f0c7"; 785 | } 786 | .bt-map:before { 787 | content: "\f0c8"; 788 | } 789 | .bt-map-arrow:before { 790 | content: "\f0c9"; 791 | } 792 | .bt-map-marker:before { 793 | content: "\f0ca"; 794 | } 795 | .bt-map-pin:before { 796 | content: "\f0cb"; 797 | } 798 | .bt-home:before { 799 | content: "\f0cc"; 800 | } 801 | .bt-building:before { 802 | content: "\f0cd"; 803 | } 804 | .bt-industry:before { 805 | content: "\f0ce"; 806 | } 807 | .bt-desktop:before { 808 | content: "\f0d0"; 809 | } 810 | .bt-laptop:before { 811 | content: "\f0d1"; 812 | } 813 | .bt-tablet:before { 814 | content: "\f0d2"; 815 | } 816 | .bt-mobile:before { 817 | content: "\f0d3"; 818 | } 819 | .bt-tv:before { 820 | content: "\f0d4"; 821 | } 822 | .bt-radio-checked:before { 823 | content: "\f0d5"; 824 | } 825 | .bt-radio-unchecked:before { 826 | content: "\f08c"; 827 | } 828 | .bt-checkbox-checked:before { 829 | content: "\f014"; 830 | } 831 | .bt-checkbox-unchecked:before { 832 | content: "\f08b"; 833 | } 834 | .bt-checkbox-intermediate:before { 835 | content: "\f023"; 836 | } 837 | .bt-user:before { 838 | content: "\f0d6"; 839 | } 840 | .bt-user-male:before { 841 | content: "\f0d6"; 842 | } 843 | .bt-user-female:before { 844 | content: "\f0d7"; 845 | } 846 | .bt-crown:before { 847 | content: "\f0d8"; 848 | } 849 | .bt-credit-card:before { 850 | content: "\f0d9"; 851 | } 852 | .bt-strikethrough:before { 853 | content: "\f0da"; 854 | } 855 | .bt-eject:before { 856 | content: "\f0db"; 857 | } 858 | .bt-ellipsis-h:before { 859 | content: "\f0dc"; 860 | } 861 | .bt-ellipsis-v:before { 862 | content: "\f0dd"; 863 | } 864 | .fab-facebook:before { 865 | content: "\f000"; 866 | } 867 | .fab-facebook-alt:before { 868 | content: "\f001"; 869 | } 870 | .fab-twitter:before { 871 | content: "\f002"; 872 | } 873 | .fab-linkedin:before { 874 | content: "\f003"; 875 | } 876 | .fab-linkedin-alt:before { 877 | content: "\f004"; 878 | } 879 | .fab-instagram:before { 880 | content: "\f005"; 881 | } 882 | .fab-github:before { 883 | content: "\f006"; 884 | } 885 | .fab-github-alt:before { 886 | content: "\f007"; 887 | } 888 | .fab-googleplus:before { 889 | content: "\f008"; 890 | } 891 | .fab-googleplus-alt:before { 892 | content: "\f009"; 893 | } 894 | .fab-pinterest:before { 895 | content: "\f00a"; 896 | } 897 | .fab-pinterest-alt:before { 898 | content: "\f00b"; 899 | } 900 | .fab-tumblr:before { 901 | content: "\f00c"; 902 | } 903 | .fab-tumblr-alt:before { 904 | content: "\f00d"; 905 | } 906 | .fab-bitcoin:before { 907 | content: "\f010"; 908 | } 909 | .fab-bitcoin-alt:before { 910 | content: "\f011"; 911 | } 912 | .fab-dropbox:before { 913 | content: "\f012"; 914 | } 915 | .fab-stackexchange:before { 916 | content: "\f013"; 917 | } 918 | .fab-stackoverflow:before { 919 | content: "\f014"; 920 | } 921 | .fab-flickr:before { 922 | content: "\f015"; 923 | } 924 | .fab-flickr-alt:before { 925 | content: "\f016"; 926 | } 927 | .fab-bitbucket:before { 928 | content: "\f017"; 929 | } 930 | .fab-html5:before { 931 | content: "\f018"; 932 | } 933 | .fab-css3:before { 934 | content: "\f019"; 935 | } 936 | .fab-apple:before { 937 | content: "\f01a"; 938 | } 939 | .fab-windows:before { 940 | content: "\f01b"; 941 | } 942 | .fab-android:before { 943 | content: "\f01c"; 944 | } 945 | .fab-linux:before { 946 | content: "\f01d"; 947 | } 948 | .fab-dribbble:before { 949 | content: "\f01e"; 950 | } 951 | .fab-youtube:before { 952 | content: "\f021"; 953 | } 954 | .fab-skype:before { 955 | content: "\f022"; 956 | } 957 | .fab-foursquare:before { 958 | content: "\f023"; 959 | } 960 | .fab-trello:before { 961 | content: "\f024"; 962 | } 963 | .fab-maxcdn:before { 964 | content: "\f025"; 965 | } 966 | .fab-gittip:before, 967 | .fab-gratipay:before { 968 | content: "\f026"; 969 | } 970 | .fab-vimeo:before { 971 | content: "\f027"; 972 | } 973 | .fab-vimeo-alt:before { 974 | content: "\f028"; 975 | } 976 | .fab-slack:before { 977 | content: "\f029"; 978 | } 979 | .fab-wordpress:before { 980 | content: "\f02a"; 981 | } 982 | .fab-wordpress-alt:before { 983 | content: "\f02b"; 984 | } 985 | .fab-openid:before { 986 | content: "\f02c"; 987 | } 988 | .fab-yahoo:before { 989 | content: "\f02d"; 990 | } 991 | .fab-yahoo-alt:before { 992 | content: "\f02e"; 993 | } 994 | .fab-reddit:before { 995 | content: "\f02f"; 996 | } 997 | .fab-google:before { 998 | content: "\f030"; 999 | } 1000 | .fab-google-alt:before { 1001 | content: "\f031"; 1002 | } 1003 | .fab-stumbleupon:before { 1004 | content: "\f032"; 1005 | } 1006 | .fab-stumbleupon-alt:before { 1007 | content: "\f033"; 1008 | } 1009 | .fab-delicious:before { 1010 | content: "\f034"; 1011 | } 1012 | .fab-digg:before { 1013 | content: "\f035"; 1014 | } 1015 | .fab-piedpiper:before { 1016 | content: "\f036"; 1017 | } 1018 | .fab-piedpiper-alt:before { 1019 | content: "\f037"; 1020 | } 1021 | .fab-drupal:before { 1022 | content: "\f038"; 1023 | } 1024 | .fab-joomla:before { 1025 | content: "\f039"; 1026 | } 1027 | .fab-behance:before { 1028 | content: "\f03a"; 1029 | } 1030 | .fab-steam:before { 1031 | content: "\f03b"; 1032 | } 1033 | .fab-steam-alt:before { 1034 | content: "\f03c"; 1035 | } 1036 | .fab-spotify:before { 1037 | content: "\f03d"; 1038 | } 1039 | .fab-deviantart:before { 1040 | content: "\f03e"; 1041 | } 1042 | .fab-soundcloud:before { 1043 | content: "\f040"; 1044 | } 1045 | .fab-vine:before { 1046 | content: "\f041"; 1047 | } 1048 | .fab-codepen:before { 1049 | content: "\f042"; 1050 | } 1051 | .fab-jsfiddle:before { 1052 | content: "\f043"; 1053 | } 1054 | .fab-rebel:before { 1055 | content: "\f044"; 1056 | } 1057 | .fab-empire:before { 1058 | content: "\f045"; 1059 | } 1060 | .fab-git:before { 1061 | content: "\f046"; 1062 | } 1063 | .fab-hackernews:before { 1064 | content: "\f047"; 1065 | } 1066 | .fab-hackernews-alt:before { 1067 | content: "\f048"; 1068 | } 1069 | .fab-slideshare:before { 1070 | content: "\f049"; 1071 | } 1072 | .fab-twitch:before { 1073 | content: "\f04a"; 1074 | } 1075 | .fab-yelp:before { 1076 | content: "\f04b"; 1077 | } 1078 | .fab-paypal:before { 1079 | content: "\f04c"; 1080 | } 1081 | .fab-google-wallet:before { 1082 | content: "\f04d"; 1083 | } 1084 | .fab-angellist:before { 1085 | content: "\f04e"; 1086 | } 1087 | .fab-cc-visa:before { 1088 | content: "\f050"; 1089 | } 1090 | .fab-cc-mastercard:before { 1091 | content: "\f051"; 1092 | } 1093 | .fab-cc-discover:before { 1094 | content: "\f052"; 1095 | } 1096 | .fab-cc-amex:before { 1097 | content: "\f053"; 1098 | } 1099 | .fab-cc-paypal:before { 1100 | content: "\f054"; 1101 | } 1102 | .fab-cc-stripe:before { 1103 | content: "\f055"; 1104 | } 1105 | .fab-lastfm:before { 1106 | content: "\f056"; 1107 | } 1108 | .fab-whatsapp:before { 1109 | content: "\f057"; 1110 | } 1111 | .fab-medium:before { 1112 | content: "\f058"; 1113 | } 1114 | .fab-meanpath:before { 1115 | content: "\f059"; 1116 | } 1117 | .fab-meanpath-alt:before { 1118 | content: "\f05a"; 1119 | } 1120 | .fab-pagelines:before { 1121 | content: "\f05b"; 1122 | } 1123 | .fab-ioxhost:before { 1124 | content: "\f060"; 1125 | } 1126 | .fab-buysellads:before { 1127 | content: "\f061"; 1128 | } 1129 | .fab-buysellads-alt:before { 1130 | content: "\f062"; 1131 | } 1132 | .fab-connectdevelop:before { 1133 | content: "\f063"; 1134 | } 1135 | .fab-dashcube:before { 1136 | content: "\f064"; 1137 | } 1138 | .fab-forumbee:before { 1139 | content: "\f065"; 1140 | } 1141 | .fab-leanpub:before { 1142 | content: "\f066"; 1143 | } 1144 | .fab-sellsy:before { 1145 | content: "\f067"; 1146 | } 1147 | .fab-shirtsinbulk:before { 1148 | content: "\f068"; 1149 | } 1150 | .fab-simplybuilt:before { 1151 | content: "\f069"; 1152 | } 1153 | .fab-skyatlas:before { 1154 | content: "\f06a"; 1155 | } 1156 | .fab-viacoin:before { 1157 | content: "\f06b"; 1158 | } 1159 | .fab-codiepie:before { 1160 | content: "\f06c"; 1161 | } 1162 | .fab-queue:before { 1163 | content: "\f06d"; 1164 | } 1165 | .fab-queue-alt:before { 1166 | content: "\f06e"; 1167 | } 1168 | .fab-fonticons:before { 1169 | content: "\f070"; 1170 | } 1171 | .fab-fonticons-alt:before { 1172 | content: "\f071"; 1173 | } 1174 | .fab-blacktie:before { 1175 | content: "\f072"; 1176 | } 1177 | .fab-blacktie-alt:before { 1178 | content: "\f073"; 1179 | } 1180 | .fab-xing:before { 1181 | content: "\f090"; 1182 | } 1183 | .fab-vk:before { 1184 | content: "\f091"; 1185 | } 1186 | .fab-weibo:before { 1187 | content: "\f092"; 1188 | } 1189 | .fab-renren:before { 1190 | content: "\f093"; 1191 | } 1192 | .fab-tencent-weibo:before { 1193 | content: "\f094"; 1194 | } 1195 | .fab-qq:before { 1196 | content: "\f095"; 1197 | } 1198 | .fab-wechat:before, 1199 | .fab-weixin:before { 1200 | content: "\f096"; 1201 | } 1202 | -------------------------------------------------------------------------------- /blacktie/fonts/bold/BlackTie-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/bold/BlackTie-Bold-webfont.eot -------------------------------------------------------------------------------- /blacktie/fonts/bold/BlackTie-Bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/bold/BlackTie-Bold-webfont.ttf -------------------------------------------------------------------------------- /blacktie/fonts/bold/BlackTie-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/bold/BlackTie-Bold-webfont.woff -------------------------------------------------------------------------------- /blacktie/fonts/bold/BlackTie-Bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/bold/BlackTie-Bold-webfont.woff2 -------------------------------------------------------------------------------- /blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.eot -------------------------------------------------------------------------------- /blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.ttf -------------------------------------------------------------------------------- /blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.woff -------------------------------------------------------------------------------- /blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/brands/FontAwesomeBrands-Regular-webfont.woff2 -------------------------------------------------------------------------------- /blacktie/fonts/light/BlackTie-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/light/BlackTie-Light-webfont.eot -------------------------------------------------------------------------------- /blacktie/fonts/light/BlackTie-Light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/light/BlackTie-Light-webfont.ttf -------------------------------------------------------------------------------- /blacktie/fonts/light/BlackTie-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/light/BlackTie-Light-webfont.woff -------------------------------------------------------------------------------- /blacktie/fonts/light/BlackTie-Light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/light/BlackTie-Light-webfont.woff2 -------------------------------------------------------------------------------- /blacktie/fonts/medium/BlackTie-Medium-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/medium/BlackTie-Medium-webfont.eot -------------------------------------------------------------------------------- /blacktie/fonts/medium/BlackTie-Medium-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/medium/BlackTie-Medium-webfont.ttf -------------------------------------------------------------------------------- /blacktie/fonts/medium/BlackTie-Medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/medium/BlackTie-Medium-webfont.woff -------------------------------------------------------------------------------- /blacktie/fonts/medium/BlackTie-Medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/medium/BlackTie-Medium-webfont.woff2 -------------------------------------------------------------------------------- /blacktie/fonts/solid/BlackTie-Solid-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/solid/BlackTie-Solid-webfont.eot -------------------------------------------------------------------------------- /blacktie/fonts/solid/BlackTie-Solid-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/solid/BlackTie-Solid-webfont.ttf -------------------------------------------------------------------------------- /blacktie/fonts/solid/BlackTie-Solid-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/solid/BlackTie-Solid-webfont.woff -------------------------------------------------------------------------------- /blacktie/fonts/solid/BlackTie-Solid-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/blacktie/fonts/solid/BlackTie-Solid-webfont.woff2 -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | shadermonk! 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | 21 | 22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 | Real-time Preview 30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 | 38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 | 46 |
47 |
48 |
49 |
50 | Console 51 |
52 |
53 |
54 |
55 |
56 | 57 |
58 |
59 | Components 60 |
61 |
62 |
63 | Mesh-Filter 64 |
65 | RenderingMesh 66 |
67 |
68 | Drag mesh here! 69 |
70 |
71 | 72 |
73 | Material 74 |
75 | _MainTex 76 |
77 |
78 | Drag texture here! 79 |
80 |
81 | 82 |
83 | Export 84 |
85 | to .obj 86 |
87 |
88 | Export 89 |
90 | 91 |
92 |
93 |
94 | 95 | 96 | 113 | 114 | 115 | 116 |
117 |
118 | Resources 119 |
120 |
121 |
122 | 123 |
124 | 125 |
126 | 127 |
128 |
129 | ready. 130 |
131 | 132 |
133 | 134 |
135 | 136 |
137 | 138 | 139 | 140 | 144 | 145 | -------------------------------------------------------------------------------- /lib/ace/mode-glsl.js: -------------------------------------------------------------------------------- 1 | define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | var oop = require("../lib/oop"); 5 | var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; 6 | 7 | var DocCommentHighlightRules = function() { 8 | this.$rules = { 9 | "start" : [ { 10 | token : "comment.doc.tag", 11 | regex : "@[\\w\\d_]+" // TODO: fix email addresses 12 | }, 13 | DocCommentHighlightRules.getTagRule(), 14 | { 15 | defaultToken : "comment.doc", 16 | caseInsensitive: true 17 | }] 18 | }; 19 | }; 20 | 21 | oop.inherits(DocCommentHighlightRules, TextHighlightRules); 22 | 23 | DocCommentHighlightRules.getTagRule = function(start) { 24 | return { 25 | token : "comment.doc.tag.storage.type", 26 | regex : "\\b(?:TODO|FIXME|XXX|HACK)\\b" 27 | }; 28 | } 29 | 30 | DocCommentHighlightRules.getStartRule = function(start) { 31 | return { 32 | token : "comment.doc", // doc comment 33 | regex : "\\/\\*(?=\\*)", 34 | next : start 35 | }; 36 | }; 37 | 38 | DocCommentHighlightRules.getEndRule = function (start) { 39 | return { 40 | token : "comment.doc", // closing comment 41 | regex : "\\*\\/", 42 | next : start 43 | }; 44 | }; 45 | 46 | 47 | exports.DocCommentHighlightRules = DocCommentHighlightRules; 48 | 49 | }); 50 | 51 | define("ace/mode/c_cpp_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"], function(require, exports, module) { 52 | "use strict"; 53 | 54 | var oop = require("../lib/oop"); 55 | var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; 56 | var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; 57 | var cFunctions = exports.cFunctions = "\\b(?:hypot(?:f|l)?|s(?:scanf|ystem|nprintf|ca(?:nf|lb(?:n(?:f|l)?|ln(?:f|l)?))|i(?:n(?:h(?:f|l)?|f|l)?|gn(?:al|bit))|tr(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?)|error|pbrk|ftime|len|rchr|xfrm)|printf|et(?:jmp|vbuf|locale|buf)|qrt(?:f|l)?|w(?:scanf|printf)|rand)|n(?:e(?:arbyint(?:f|l)?|xt(?:toward(?:f|l)?|after(?:f|l)?))|an(?:f|l)?)|c(?:s(?:in(?:h(?:f|l)?|f|l)?|qrt(?:f|l)?)|cos(?:h(?:f)?|f|l)?|imag(?:f|l)?|t(?:ime|an(?:h(?:f|l)?|f|l)?)|o(?:s(?:h(?:f|l)?|f|l)?|nj(?:f|l)?|pysign(?:f|l)?)|p(?:ow(?:f|l)?|roj(?:f|l)?)|e(?:il(?:f|l)?|xp(?:f|l)?)|l(?:o(?:ck|g(?:f|l)?)|earerr)|a(?:sin(?:h(?:f|l)?|f|l)?|cos(?:h(?:f|l)?|f|l)?|tan(?:h(?:f|l)?|f|l)?|lloc|rg(?:f|l)?|bs(?:f|l)?)|real(?:f|l)?|brt(?:f|l)?)|t(?:ime|o(?:upper|lower)|an(?:h(?:f|l)?|f|l)?|runc(?:f|l)?|gamma(?:f|l)?|mp(?:nam|file))|i(?:s(?:space|n(?:ormal|an)|cntrl|inf|digit|u(?:nordered|pper)|p(?:unct|rint)|finite|w(?:space|c(?:ntrl|type)|digit|upper|p(?:unct|rint)|lower|al(?:num|pha)|graph|xdigit|blank)|l(?:ower|ess(?:equal|greater)?)|al(?:num|pha)|gr(?:eater(?:equal)?|aph)|xdigit|blank)|logb(?:f|l)?|max(?:div|abs))|di(?:v|fftime)|_Exit|unget(?:c|wc)|p(?:ow(?:f|l)?|ut(?:s|c(?:har)?|wc(?:har)?)|error|rintf)|e(?:rf(?:c(?:f|l)?|f|l)?|x(?:it|p(?:2(?:f|l)?|f|l|m1(?:f|l)?)?))|v(?:s(?:scanf|nprintf|canf|printf|w(?:scanf|printf))|printf|f(?:scanf|printf|w(?:scanf|printf))|w(?:scanf|printf)|a_(?:start|copy|end|arg))|qsort|f(?:s(?:canf|e(?:tpos|ek))|close|tell|open|dim(?:f|l)?|p(?:classify|ut(?:s|c|w(?:s|c))|rintf)|e(?:holdexcept|set(?:e(?:nv|xceptflag)|round)|clearexcept|testexcept|of|updateenv|r(?:aiseexcept|ror)|get(?:e(?:nv|xceptflag)|round))|flush|w(?:scanf|ide|printf|rite)|loor(?:f|l)?|abs(?:f|l)?|get(?:s|c|pos|w(?:s|c))|re(?:open|e|ad|xp(?:f|l)?)|m(?:in(?:f|l)?|od(?:f|l)?|a(?:f|l|x(?:f|l)?)?))|l(?:d(?:iv|exp(?:f|l)?)|o(?:ngjmp|cal(?:time|econv)|g(?:1(?:p(?:f|l)?|0(?:f|l)?)|2(?:f|l)?|f|l|b(?:f|l)?)?)|abs|l(?:div|abs|r(?:int(?:f|l)?|ound(?:f|l)?))|r(?:int(?:f|l)?|ound(?:f|l)?)|gamma(?:f|l)?)|w(?:scanf|c(?:s(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?|mbs)|pbrk|ftime|len|r(?:chr|tombs)|xfrm)|to(?:b|mb)|rtomb)|printf|mem(?:set|c(?:hr|py|mp)|move))|a(?:s(?:sert|ctime|in(?:h(?:f|l)?|f|l)?)|cos(?:h(?:f|l)?|f|l)?|t(?:o(?:i|f|l(?:l)?)|exit|an(?:h(?:f|l)?|2(?:f|l)?|f|l)?)|b(?:s|ort))|g(?:et(?:s|c(?:har)?|env|wc(?:har)?)|mtime)|r(?:int(?:f|l)?|ound(?:f|l)?|e(?:name|alloc|wind|m(?:ove|quo(?:f|l)?|ainder(?:f|l)?))|a(?:nd|ise))|b(?:search|towc)|m(?:odf(?:f|l)?|em(?:set|c(?:hr|py|mp)|move)|ktime|alloc|b(?:s(?:init|towcs|rtowcs)|towc|len|r(?:towc|len))))\\b" 58 | 59 | var c_cppHighlightRules = function() { 60 | 61 | var keywordControls = ( 62 | "break|case|continue|default|do|else|for|goto|if|_Pragma|" + 63 | "return|switch|while|catch|operator|try|throw|using" 64 | ); 65 | 66 | var storageType = ( 67 | "asm|__asm__|auto|bool|_Bool|char|_Complex|double|enum|float|" + 68 | "_Imaginary|int|long|short|signed|struct|typedef|union|unsigned|void|" + 69 | "class|wchar_t|template|char16_t|char32_t" 70 | ); 71 | 72 | var storageModifiers = ( 73 | "const|extern|register|restrict|static|volatile|inline|private|" + 74 | "protected|public|friend|explicit|virtual|export|mutable|typename|" + 75 | "constexpr|new|delete|alignas|alignof|decltype|noexcept|thread_local" 76 | ); 77 | 78 | var keywordOperators = ( 79 | "and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq" + 80 | "const_cast|dynamic_cast|reinterpret_cast|static_cast|sizeof|namespace" 81 | ); 82 | 83 | var builtinConstants = ( 84 | "NULL|true|false|TRUE|FALSE|nullptr" 85 | ); 86 | 87 | var keywordMapper = this.$keywords = this.createKeywordMapper({ 88 | "keyword.control" : keywordControls, 89 | "storage.type" : storageType, 90 | "storage.modifier" : storageModifiers, 91 | "keyword.operator" : keywordOperators, 92 | "variable.language": "this", 93 | "constant.language": builtinConstants 94 | }, "identifier"); 95 | 96 | var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*\\b"; 97 | var escapeRe = /\\(?:['"?\\abfnrtv]|[0-7]{1,3}|x[a-fA-F\d]{2}|u[a-fA-F\d]{4}U[a-fA-F\d]{8}|.)/.source; 98 | 99 | this.$rules = { 100 | "start" : [ 101 | { 102 | token : "comment", 103 | regex : "//$", 104 | next : "start" 105 | }, { 106 | token : "comment", 107 | regex : "//", 108 | next : "singleLineComment" 109 | }, 110 | DocCommentHighlightRules.getStartRule("doc-start"), 111 | { 112 | token : "comment", // multi line comment 113 | regex : "\\/\\*", 114 | next : "comment" 115 | }, { 116 | token : "string", // character 117 | regex : "'(?:" + escapeRe + "|.)?'" 118 | }, { 119 | token : "string.start", 120 | regex : '"', 121 | stateName: "qqstring", 122 | next: [ 123 | { token: "string", regex: /\\\s*$/, next: "qqstring" }, 124 | { token: "constant.language.escape", regex: escapeRe }, 125 | { token: "constant.language.escape", regex: /%[^'"\\]/ }, 126 | { token: "string.end", regex: '"|$', next: "start" }, 127 | { defaultToken: "string"} 128 | ] 129 | }, { 130 | token : "string.start", 131 | regex : 'R"\\(', 132 | stateName: "rawString", 133 | next: [ 134 | { token: "string.end", regex: '\\)"', next: "start" }, 135 | { defaultToken: "string"} 136 | ] 137 | }, { 138 | token : "constant.numeric", // hex 139 | regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" 140 | }, { 141 | token : "constant.numeric", // float 142 | regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" 143 | }, { 144 | token : "keyword", // pre-compiler directives 145 | regex : "#\\s*(?:include|import|pragma|line|define|undef)\\b", 146 | next : "directive" 147 | }, { 148 | token : "keyword", // special case pre-compiler directive 149 | regex : "#\\s*(?:endif|if|ifdef|else|elif|ifndef)\\b" 150 | }, { 151 | token : "support.function.C99.c", 152 | regex : cFunctions 153 | }, { 154 | token : keywordMapper, 155 | regex : "[a-zA-Z_$][a-zA-Z0-9_$]*" 156 | }, { 157 | token : "keyword.operator", 158 | regex : /--|\+\+|<<=|>>=|>>>=|<>|&&|\|\||\?:|[*%\/+\-&\^|~!<>=]=?/ 159 | }, { 160 | token : "punctuation.operator", 161 | regex : "\\?|\\:|\\,|\\;|\\." 162 | }, { 163 | token : "paren.lparen", 164 | regex : "[[({]" 165 | }, { 166 | token : "paren.rparen", 167 | regex : "[\\])}]" 168 | }, { 169 | token : "text", 170 | regex : "\\s+" 171 | } 172 | ], 173 | "comment" : [ 174 | { 175 | token : "comment", // closing comment 176 | regex : ".*?\\*\\/", 177 | next : "start" 178 | }, { 179 | token : "comment", // comment spanning whole line 180 | regex : ".+" 181 | } 182 | ], 183 | "singleLineComment" : [ 184 | { 185 | token : "comment", 186 | regex : /\\$/, 187 | next : "singleLineComment" 188 | }, { 189 | token : "comment", 190 | regex : /$/, 191 | next : "start" 192 | }, { 193 | defaultToken: "comment" 194 | } 195 | ], 196 | "directive" : [ 197 | { 198 | token : "constant.other.multiline", 199 | regex : /\\/ 200 | }, 201 | { 202 | token : "constant.other.multiline", 203 | regex : /.*\\/ 204 | }, 205 | { 206 | token : "constant.other", 207 | regex : "\\s*<.+?>", 208 | next : "start" 209 | }, 210 | { 211 | token : "constant.other", // single line 212 | regex : '\\s*["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]', 213 | next : "start" 214 | }, 215 | { 216 | token : "constant.other", // single line 217 | regex : "\\s*['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']", 218 | next : "start" 219 | }, 220 | { 221 | token : "constant.other", 222 | regex : /[^\\\/]+/, 223 | next : "start" 224 | } 225 | ] 226 | }; 227 | 228 | this.embedRules(DocCommentHighlightRules, "doc-", 229 | [ DocCommentHighlightRules.getEndRule("start") ]); 230 | this.normalizeRules(); 231 | }; 232 | 233 | oop.inherits(c_cppHighlightRules, TextHighlightRules); 234 | 235 | exports.c_cppHighlightRules = c_cppHighlightRules; 236 | }); 237 | 238 | define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) { 239 | "use strict"; 240 | 241 | var Range = require("../range").Range; 242 | 243 | var MatchingBraceOutdent = function() {}; 244 | 245 | (function() { 246 | 247 | this.checkOutdent = function(line, input) { 248 | if (! /^\s+$/.test(line)) 249 | return false; 250 | 251 | return /^\s*\}/.test(input); 252 | }; 253 | 254 | this.autoOutdent = function(doc, row) { 255 | var line = doc.getLine(row); 256 | var match = line.match(/^(\s*\})/); 257 | 258 | if (!match) return 0; 259 | 260 | var column = match[1].length; 261 | var openBracePos = doc.findMatchingBracket({row: row, column: column}); 262 | 263 | if (!openBracePos || openBracePos.row == row) return 0; 264 | 265 | var indent = this.$getIndent(doc.getLine(openBracePos.row)); 266 | doc.replace(new Range(row, 0, row, column-1), indent); 267 | }; 268 | 269 | this.$getIndent = function(line) { 270 | return line.match(/^\s*/)[0]; 271 | }; 272 | 273 | }).call(MatchingBraceOutdent.prototype); 274 | 275 | exports.MatchingBraceOutdent = MatchingBraceOutdent; 276 | }); 277 | 278 | define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"], function(require, exports, module) { 279 | "use strict"; 280 | 281 | var oop = require("../../lib/oop"); 282 | var Range = require("../../range").Range; 283 | var BaseFoldMode = require("./fold_mode").FoldMode; 284 | 285 | var FoldMode = exports.FoldMode = function(commentRegex) { 286 | if (commentRegex) { 287 | this.foldingStartMarker = new RegExp( 288 | this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start) 289 | ); 290 | this.foldingStopMarker = new RegExp( 291 | this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end) 292 | ); 293 | } 294 | }; 295 | oop.inherits(FoldMode, BaseFoldMode); 296 | 297 | (function() { 298 | 299 | this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/; 300 | this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; 301 | this.singleLineBlockCommentRe= /^\s*(\/\*).*\*\/\s*$/; 302 | this.tripleStarBlockCommentRe = /^\s*(\/\*\*\*).*\*\/\s*$/; 303 | this.startRegionRe = /^\s*(\/\*|\/\/)#?region\b/; 304 | this._getFoldWidgetBase = this.getFoldWidget; 305 | this.getFoldWidget = function(session, foldStyle, row) { 306 | var line = session.getLine(row); 307 | 308 | if (this.singleLineBlockCommentRe.test(line)) { 309 | if (!this.startRegionRe.test(line) && !this.tripleStarBlockCommentRe.test(line)) 310 | return ""; 311 | } 312 | 313 | var fw = this._getFoldWidgetBase(session, foldStyle, row); 314 | 315 | if (!fw && this.startRegionRe.test(line)) 316 | return "start"; // lineCommentRegionStart 317 | 318 | return fw; 319 | }; 320 | 321 | this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) { 322 | var line = session.getLine(row); 323 | 324 | if (this.startRegionRe.test(line)) 325 | return this.getCommentRegionBlock(session, line, row); 326 | 327 | var match = line.match(this.foldingStartMarker); 328 | if (match) { 329 | var i = match.index; 330 | 331 | if (match[1]) 332 | return this.openingBracketBlock(session, match[1], row, i); 333 | 334 | var range = session.getCommentFoldRange(row, i + match[0].length, 1); 335 | 336 | if (range && !range.isMultiLine()) { 337 | if (forceMultiline) { 338 | range = this.getSectionRange(session, row); 339 | } else if (foldStyle != "all") 340 | range = null; 341 | } 342 | 343 | return range; 344 | } 345 | 346 | if (foldStyle === "markbegin") 347 | return; 348 | 349 | var match = line.match(this.foldingStopMarker); 350 | if (match) { 351 | var i = match.index + match[0].length; 352 | 353 | if (match[1]) 354 | return this.closingBracketBlock(session, match[1], row, i); 355 | 356 | return session.getCommentFoldRange(row, i, -1); 357 | } 358 | }; 359 | 360 | this.getSectionRange = function(session, row) { 361 | var line = session.getLine(row); 362 | var startIndent = line.search(/\S/); 363 | var startRow = row; 364 | var startColumn = line.length; 365 | row = row + 1; 366 | var endRow = row; 367 | var maxRow = session.getLength(); 368 | while (++row < maxRow) { 369 | line = session.getLine(row); 370 | var indent = line.search(/\S/); 371 | if (indent === -1) 372 | continue; 373 | if (startIndent > indent) 374 | break; 375 | var subRange = this.getFoldWidgetRange(session, "all", row); 376 | 377 | if (subRange) { 378 | if (subRange.start.row <= startRow) { 379 | break; 380 | } else if (subRange.isMultiLine()) { 381 | row = subRange.end.row; 382 | } else if (startIndent == indent) { 383 | break; 384 | } 385 | } 386 | endRow = row; 387 | } 388 | 389 | return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); 390 | }; 391 | this.getCommentRegionBlock = function(session, line, row) { 392 | var startColumn = line.search(/\s*$/); 393 | var maxRow = session.getLength(); 394 | var startRow = row; 395 | 396 | var re = /^\s*(?:\/\*|\/\/|--)#?(end)?region\b/; 397 | var depth = 1; 398 | while (++row < maxRow) { 399 | line = session.getLine(row); 400 | var m = re.exec(line); 401 | if (!m) continue; 402 | if (m[1]) depth--; 403 | else depth++; 404 | 405 | if (!depth) break; 406 | } 407 | 408 | var endRow = row; 409 | if (endRow > startRow) { 410 | return new Range(startRow, startColumn, endRow, line.length); 411 | } 412 | }; 413 | 414 | }).call(FoldMode.prototype); 415 | 416 | }); 417 | 418 | define("ace/mode/c_cpp",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/c_cpp_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"], function(require, exports, module) { 419 | "use strict"; 420 | 421 | var oop = require("../lib/oop"); 422 | var TextMode = require("./text").Mode; 423 | var c_cppHighlightRules = require("./c_cpp_highlight_rules").c_cppHighlightRules; 424 | var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; 425 | var Range = require("../range").Range; 426 | var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; 427 | var CStyleFoldMode = require("./folding/cstyle").FoldMode; 428 | 429 | var Mode = function() { 430 | this.HighlightRules = c_cppHighlightRules; 431 | 432 | this.$outdent = new MatchingBraceOutdent(); 433 | this.$behaviour = new CstyleBehaviour(); 434 | 435 | this.foldingRules = new CStyleFoldMode(); 436 | }; 437 | oop.inherits(Mode, TextMode); 438 | 439 | (function() { 440 | 441 | this.lineCommentStart = "//"; 442 | this.blockComment = {start: "/*", end: "*/"}; 443 | 444 | this.getNextLineIndent = function(state, line, tab) { 445 | var indent = this.$getIndent(line); 446 | 447 | var tokenizedLine = this.getTokenizer().getLineTokens(line, state); 448 | var tokens = tokenizedLine.tokens; 449 | var endState = tokenizedLine.state; 450 | 451 | if (tokens.length && tokens[tokens.length-1].type == "comment") { 452 | return indent; 453 | } 454 | 455 | if (state == "start") { 456 | var match = line.match(/^.*[\{\(\[]\s*$/); 457 | if (match) { 458 | indent += tab; 459 | } 460 | } else if (state == "doc-start") { 461 | if (endState == "start") { 462 | return ""; 463 | } 464 | var match = line.match(/^\s*(\/?)\*/); 465 | if (match) { 466 | if (match[1]) { 467 | indent += " "; 468 | } 469 | indent += "* "; 470 | } 471 | } 472 | 473 | return indent; 474 | }; 475 | 476 | this.checkOutdent = function(state, line, input) { 477 | return this.$outdent.checkOutdent(line, input); 478 | }; 479 | 480 | this.autoOutdent = function(state, doc, row) { 481 | this.$outdent.autoOutdent(doc, row); 482 | }; 483 | 484 | this.$id = "ace/mode/c_cpp"; 485 | }).call(Mode.prototype); 486 | 487 | exports.Mode = Mode; 488 | }); 489 | 490 | define("ace/mode/glsl_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/c_cpp_highlight_rules"], function(require, exports, module) { 491 | "use strict"; 492 | 493 | var oop = require("../lib/oop"); 494 | var c_cppHighlightRules = require("./c_cpp_highlight_rules").c_cppHighlightRules; 495 | 496 | var glslHighlightRules = function() { 497 | 498 | var keywords = ( 499 | "attribute|const|uniform|varying|break|continue|do|for|while|" + 500 | "if|else|in|out|inout|float|int|void|bool|true|false|" + 501 | "lowp|mediump|highp|precision|invariant|discard|return|mat2|mat3|" + 502 | "mat4|vec2|vec3|vec4|ivec2|ivec3|ivec4|bvec2|bvec3|bvec4|sampler2D|" + 503 | "samplerCube|struct" 504 | ); 505 | 506 | var buildinConstants = ( 507 | "radians|degrees|sin|cos|tan|asin|acos|atan|pow|" + 508 | "exp|log|exp2|log2|sqrt|inversesqrt|abs|sign|floor|ceil|fract|mod|" + 509 | "min|max|clamp|mix|step|smoothstep|length|distance|dot|cross|" + 510 | "normalize|faceforward|reflect|refract|matrixCompMult|lessThan|" + 511 | "lessThanEqual|greaterThan|greaterThanEqual|equal|notEqual|any|all|" + 512 | "not|dFdx|dFdy|fwidth|texture2D|texture2DProj|texture2DLod|" + 513 | "texture2DProjLod|textureCube|textureCubeLod|" + 514 | "gl_MaxVertexAttribs|gl_MaxVertexUniformVectors|gl_MaxVaryingVectors|" + 515 | "gl_MaxVertexTextureImageUnits|gl_MaxCombinedTextureImageUnits|" + 516 | "gl_MaxTextureImageUnits|gl_MaxFragmentUniformVectors|gl_MaxDrawBuffers|" + 517 | "gl_DepthRangeParameters|gl_DepthRange|" + 518 | "gl_Position|gl_PointSize|" + 519 | "gl_FragCoord|gl_FrontFacing|gl_PointCoord|gl_FragColor|gl_FragData" 520 | ); 521 | 522 | var keywordMapper = this.createKeywordMapper({ 523 | "variable.language": "this", 524 | "keyword": keywords, 525 | "constant.language": buildinConstants 526 | }, "identifier"); 527 | 528 | this.$rules = new c_cppHighlightRules().$rules; 529 | this.$rules.start.forEach(function(rule) { 530 | if (typeof rule.token == "function") 531 | rule.token = keywordMapper; 532 | }) 533 | }; 534 | 535 | oop.inherits(glslHighlightRules, c_cppHighlightRules); 536 | 537 | exports.glslHighlightRules = glslHighlightRules; 538 | }); 539 | 540 | define("ace/mode/glsl",["require","exports","module","ace/lib/oop","ace/mode/c_cpp","ace/mode/glsl_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"], function(require, exports, module) { 541 | "use strict"; 542 | 543 | var oop = require("../lib/oop"); 544 | var CMode = require("./c_cpp").Mode; 545 | var glslHighlightRules = require("./glsl_highlight_rules").glslHighlightRules; 546 | var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; 547 | var Range = require("../range").Range; 548 | var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; 549 | var CStyleFoldMode = require("./folding/cstyle").FoldMode; 550 | 551 | var Mode = function() { 552 | this.HighlightRules = glslHighlightRules; 553 | 554 | this.$outdent = new MatchingBraceOutdent(); 555 | this.$behaviour = new CstyleBehaviour(); 556 | this.foldingRules = new CStyleFoldMode(); 557 | }; 558 | oop.inherits(Mode, CMode); 559 | 560 | (function() { 561 | this.$id = "ace/mode/glsl"; 562 | }).call(Mode.prototype); 563 | 564 | exports.Mode = Mode; 565 | }); 566 | -------------------------------------------------------------------------------- /lib/ace/snippets/glsl.js: -------------------------------------------------------------------------------- 1 | define("ace/snippets/glsl",["require","exports","module"], function(require, exports, module) { 2 | "use strict"; 3 | 4 | exports.snippetText =undefined; 5 | exports.scope = "glsl"; 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /lib/ace/theme-twilight.js: -------------------------------------------------------------------------------- 1 | define("ace/theme/twilight",["require","exports","module","ace/lib/dom"], function(require, exports, module) { 2 | 3 | exports.isDark = true; 4 | exports.cssClass = "ace-twilight"; 5 | exports.cssText = ".ace-twilight .ace_gutter {\ 6 | background: #232323;\ 7 | color: #E2E2E2\ 8 | }\ 9 | .ace-twilight .ace_print-margin {\ 10 | width: 1px;\ 11 | background: #232323\ 12 | }\ 13 | .ace-twilight {\ 14 | background-color: #141414;\ 15 | color: #F8F8F8\ 16 | }\ 17 | .ace-twilight .ace_cursor {\ 18 | color: #A7A7A7\ 19 | }\ 20 | .ace-twilight .ace_marker-layer .ace_selection {\ 21 | background: rgba(221, 240, 255, 0.20)\ 22 | }\ 23 | .ace-twilight.ace_multiselect .ace_selection.ace_start {\ 24 | box-shadow: 0 0 3px 0px #141414;\ 25 | }\ 26 | .ace-twilight .ace_marker-layer .ace_step {\ 27 | background: rgb(102, 82, 0)\ 28 | }\ 29 | .ace-twilight .ace_marker-layer .ace_bracket {\ 30 | margin: -1px 0 0 -1px;\ 31 | border: 1px solid rgba(255, 255, 255, 0.25)\ 32 | }\ 33 | .ace-twilight .ace_marker-layer .ace_active-line {\ 34 | background: rgba(255, 255, 255, 0.031)\ 35 | }\ 36 | .ace-twilight .ace_gutter-active-line {\ 37 | background-color: rgba(255, 255, 255, 0.031)\ 38 | }\ 39 | .ace-twilight .ace_marker-layer .ace_selected-word {\ 40 | border: 1px solid rgba(221, 240, 255, 0.20)\ 41 | }\ 42 | .ace-twilight .ace_invisible {\ 43 | color: rgba(255, 255, 255, 0.25)\ 44 | }\ 45 | .ace-twilight .ace_keyword,\ 46 | .ace-twilight .ace_meta {\ 47 | color: #CDA869\ 48 | }\ 49 | .ace-twilight .ace_constant,\ 50 | .ace-twilight .ace_constant.ace_character,\ 51 | .ace-twilight .ace_constant.ace_character.ace_escape,\ 52 | .ace-twilight .ace_constant.ace_other,\ 53 | .ace-twilight .ace_heading,\ 54 | .ace-twilight .ace_markup.ace_heading,\ 55 | .ace-twilight .ace_support.ace_constant {\ 56 | color: #CF6A4C\ 57 | }\ 58 | .ace-twilight .ace_invalid.ace_illegal {\ 59 | color: #F8F8F8;\ 60 | background-color: rgba(86, 45, 86, 0.75)\ 61 | }\ 62 | .ace-twilight .ace_invalid.ace_deprecated {\ 63 | text-decoration: underline;\ 64 | font-style: italic;\ 65 | color: #D2A8A1\ 66 | }\ 67 | .ace-twilight .ace_support {\ 68 | color: #9B859D\ 69 | }\ 70 | .ace-twilight .ace_fold {\ 71 | background-color: #AC885B;\ 72 | border-color: #F8F8F8\ 73 | }\ 74 | .ace-twilight .ace_support.ace_function {\ 75 | color: #DAD085\ 76 | }\ 77 | .ace-twilight .ace_list,\ 78 | .ace-twilight .ace_markup.ace_list,\ 79 | .ace-twilight .ace_storage {\ 80 | color: #F9EE98\ 81 | }\ 82 | .ace-twilight .ace_entity.ace_name.ace_function,\ 83 | .ace-twilight .ace_meta.ace_tag,\ 84 | .ace-twilight .ace_variable {\ 85 | color: #AC885B\ 86 | }\ 87 | .ace-twilight .ace_string {\ 88 | color: #8F9D6A\ 89 | }\ 90 | .ace-twilight .ace_string.ace_regexp {\ 91 | color: #E9C062\ 92 | }\ 93 | .ace-twilight .ace_comment {\ 94 | font-style: italic;\ 95 | color: #82a463\ 96 | }\ 97 | .ace-twilight .ace_variable {\ 98 | color: #7587A6\ 99 | }\ 100 | .ace-twilight .ace_xml-pe {\ 101 | color: #494949\ 102 | }\ 103 | .ace-twilight .ace_indent-guide {\ 104 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWMQERFpYLC1tf0PAAgOAnPnhxyiAAAAAElFTkSuQmCC) right repeat-y\ 105 | }"; 106 | 107 | var dom = require("../lib/dom"); 108 | dom.importCssString(exports.cssText, exports.cssClass); 109 | }); 110 | -------------------------------------------------------------------------------- /lib/editor/gk-inspector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/13. 3 | */ 4 | class Inspector { 5 | 6 | constructor() { 7 | 8 | } 9 | 10 | get Selection() { 11 | 12 | } 13 | set Selection( value ) { 14 | 15 | } 16 | 17 | updatePanel() { 18 | 19 | } 20 | 21 | } 22 | 23 | module.exports = Inspector; -------------------------------------------------------------------------------- /lib/exporter/exporter-obj.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/12/15. 3 | */ 4 | const Component = require('../gk-component.js'); 5 | const math = require('gl-matrix'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | 9 | var exporter_obj = exporter_obj || {}; 10 | module.exports = exporter_obj; 11 | 12 | exporter_obj.normalizeName = function(str) { 13 | 14 | let ret = str.replace(/ /g, "_"); 15 | ret = ret.replace(/#/g, "_"); 16 | return ret; 17 | 18 | } 19 | 20 | exporter_obj.exportNode = function( rootGameObject, base_path ) 21 | { 22 | // make root transform to root 23 | if( !(rootGameObject instanceof Component.Transform ) ) 24 | { 25 | console.info('export error, root node must be Component.Transform'); 26 | return; 27 | } 28 | 29 | let orgParent = rootGameObject.parent; 30 | rootGameObject.parent = null; 31 | 32 | // goThrough each MeshFilter, export into obj 33 | let mfs = rootGameObject.getComponent( Component.MeshFilter ); 34 | 35 | let headerPart = 'mtllib ./exported.mtl\r'; 36 | 37 | let vertexPart = ''; 38 | let normalPart = ''; 39 | let texcoordPart = ''; 40 | 41 | let mtlFileContent = ''; 42 | 43 | let facePart = ''; 44 | let totalVertexPassed = 1; 45 | let totalObjectPassed = 0; 46 | 47 | let materialNames = []; 48 | 49 | mfs.forEach( meshFilter => { 50 | if( meshFilter.mesh ) 51 | { 52 | facePart += 'o Geometry' + totalObjectPassed + '\r'; 53 | let mr = meshFilter.host.components.get(Component.MeshRenderer); 54 | if( mr ) 55 | { 56 | facePart += 'usemtl ' + exporter_obj.normalizeName(mr.material.name) + '\r'; 57 | 58 | // write mat file here 59 | if(materialNames.indexOf( exporter_obj.normalizeName(mr.material.name) ) === -1) 60 | { 61 | mtlFileContent += '\r'; 62 | mtlFileContent += 'newmtl ' + exporter_obj.normalizeName(mr.material.name) + '\r'; 63 | mtlFileContent += 'Kd 1.00000000000000 1.00000000000000 1.00000000000000\r'; 64 | mtlFileContent += 'map_Kd ' + path.basename( mr.material.mainTex.filetoken )+ '\r'; 65 | mtlFileContent += 'Ks 1.00000000000000 1.00000000000000 1.00000000000000\r'; 66 | mtlFileContent += 'Ns 100\rillum 7\r'; 67 | 68 | materialNames.push( exporter_obj.normalizeName(mr.material.name) ); 69 | } 70 | 71 | } 72 | 73 | let vbo = meshFilter.mesh.vboForReadback; 74 | let size = meshFilter.mesh.vertexSize / 4; 75 | 76 | let vertCount = vbo.length / size ; 77 | //console.log(vbo.length + ' / ' + size); 78 | 79 | for( let i=0; i < vertCount; ++i) { 80 | 81 | let position = math.vec3.fromValues(meshFilter.mesh.vboForReadback[i * size + 0], meshFilter.mesh.vboForReadback[i * size + 1],meshFilter.mesh.vboForReadback[i * size + 2]); 82 | let normal = math.vec3.fromValues(meshFilter.mesh.vboForReadback[i * size + 3], meshFilter.mesh.vboForReadback[i * size + 4],meshFilter.mesh.vboForReadback[i * size + 5]); 83 | let texcoord = math.vec2.fromValues(meshFilter.mesh.vboForReadback[i * size + 6], meshFilter.mesh.vboForReadback[i * size + 7]); 84 | 85 | let mtx = meshFilter.host.transform.localToWorldMatrix; 86 | 87 | math.vec3.transformMat4( position, position, mtx); 88 | math.vec3.normalize(normal,normal); 89 | let alignNormal = math.vec4.fromValues( normal[0], normal[1], normal[2], 0 ); 90 | math.vec4.transformMat4( alignNormal, alignNormal, mtx); 91 | normal = math.vec3.clone( alignNormal ); 92 | math.vec3.normalize(normal,normal); 93 | 94 | let vertexstring = 'v ' + position[0] 95 | + ' ' + position[1] 96 | + ' ' + position[2] 97 | + '\r'; 98 | let normalstring = 'vn ' + normal[0] 99 | + ' ' + normal[1] 100 | + ' ' + normal[2] 101 | + '\r'; 102 | let texcoordstring = 'vt ' + texcoord[0] 103 | + ' ' + (1.0 - texcoord[1]) 104 | + '\r'; 105 | 106 | vertexPart += vertexstring; 107 | normalPart += normalstring; 108 | texcoordPart += texcoordstring; 109 | 110 | //console.info( vertexstring + normalstring + texcoordstring ); 111 | } 112 | 113 | 114 | // idx process 115 | let tristrip = meshFilter.mesh.tristripForReadback; 116 | let trilist = meshFilter.mesh.trilistForReadback; 117 | 118 | if(tristrip) 119 | { 120 | for( let i=0, len = tristrip.length - 2; i < len; ++i) 121 | { 122 | let v0 = tristrip[i] + totalVertexPassed; 123 | let v1 = tristrip[i+1] + totalVertexPassed; 124 | let v2 = tristrip[i+2] + totalVertexPassed; 125 | 126 | if(v0 != v1 && v0 != v2 && v1 != v2) 127 | { 128 | let faceString = 'f '; 129 | if( i % 2 === 0 ) { 130 | faceString = 'f ' + v0 + '/' + v0 + '/' + v0 + ' ' 131 | + v1 + '/' + v1 + '/' + v1 + ' ' 132 | + v2 + '/' + v2 + '/' + v2 + '\r'; 133 | } 134 | else { 135 | faceString = 'f ' + v0 + '/' + v0 + '/' + v0 + ' ' 136 | + v2 + '/' + v2 + '/' + v2 + ' ' 137 | + v1 + '/' + v1 + '/' + v1 + '\r'; 138 | } 139 | 140 | facePart += faceString; 141 | } 142 | } 143 | } 144 | 145 | if(trilist) 146 | { 147 | for( let i=0, len = trilist.length / 3; i < len; ++i) 148 | { 149 | let v0 = trilist[i * 3] + totalVertexPassed; 150 | let v1 = trilist[i * 3 + 1] + totalVertexPassed; 151 | let v2 = trilist[i * 3 + 2] + totalVertexPassed; 152 | 153 | if(v0 != v1 && v0 != v2 && v1 != v2) 154 | { 155 | let faceString = 'f ' + v0 + '/' + v0 + '/' + v0 + ' ' 156 | + v1 + '/' + v1 + '/' + v1 + ' ' 157 | + v2 + '/' + v2 + '/' + v2 + '\r'; 158 | 159 | facePart += faceString; 160 | } 161 | } 162 | } 163 | 164 | totalVertexPassed += vertCount; 165 | totalObjectPassed++; 166 | 167 | } 168 | }) 169 | 170 | fs.writeFile(path.join(base_path, 'res', "exported.obj"), headerPart + vertexPart + normalPart + texcoordPart + facePart ,function(err){ 171 | if(!err) 172 | console.log("obj writed!"); 173 | }); 174 | 175 | fs.writeFile(path.join(base_path, 'res', 'exported.mtl'), mtlFileContent ,function(err){ 176 | if(!err) 177 | console.log("obj writed!"); 178 | }); 179 | 180 | rootGameObject.parent = orgParent; 181 | } -------------------------------------------------------------------------------- /lib/fabricate.js: -------------------------------------------------------------------------------- 1 | function Fabricate(prefab) { 2 | if(!prefab) { 3 | throw new Error("No prefab passed to Fabricate."); 4 | } 5 | const host = Object.create(prefab); 6 | host.components = new Map(); 7 | if(prefab.components) { 8 | prefab.components.forEach(component => { 9 | let componentInst; 10 | if(component.prototype && component.prototype.constructor) { 11 | componentInst = new component(); 12 | } else { 13 | componentInst = Object.create(component); 14 | } 15 | componentInst.host = host; 16 | host.components.set(component, componentInst); 17 | }); 18 | } 19 | return host; 20 | } 21 | 22 | //export default Fabricate; 23 | module.exports = Fabricate; -------------------------------------------------------------------------------- /lib/gk-acewrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/18. 3 | */ 4 | const fs = require('fs-promise'); 5 | const Promise = require("bluebird"); 6 | const path = require("path"); 7 | 8 | class AceEditorWindow { 9 | constructor( elementId ) 10 | { 11 | this.elementToken = elementId; 12 | 13 | { 14 | let container = document.getElementById(this.elementToken); 15 | let title = container.previousElementSibling; 16 | if(title === null) 17 | { 18 | title = container.nextElementSibling; 19 | } 20 | if(title !== null) 21 | { 22 | this.elementTitle = title; 23 | } 24 | } 25 | 26 | this.editor = ace.edit(elementId); 27 | this.editor.setTheme('ace/theme/twilight'); 28 | let GLSLMode = ace.require("ace/mode/glsl").Mode; 29 | this.editor.session.setMode(new GLSLMode()); 30 | this.callback = null; 31 | this.autoUpdate = true; 32 | 33 | this.editingFiletoken = ""; 34 | 35 | let ref = this; 36 | 37 | 38 | this.loadCoroutine = Promise.coroutine(function* (url) { 39 | let source = yield fs.readFile(url); 40 | if (source === null) { 41 | console.warn('error : ' + err); 42 | return; 43 | } 44 | let text = source.toString(); 45 | ref.editor.setValue(text); 46 | ref.editor.clearSelection(); 47 | 48 | ref.elementTitle.textContent = path.basename(url); 49 | 50 | }); 51 | 52 | this.saveCoroutine = Promise.coroutine(function* (url) { 53 | yield fs.writeFile(url, ref.editor.getValue()); 54 | }); 55 | 56 | // intereaction intialize 57 | 58 | // change 59 | 60 | this.editor.getSession().on('change', function(e) { 61 | let text = ref.editor.getValue(); 62 | if(ref.callback != null) 63 | { 64 | ref.callback(text); 65 | } 66 | ref.elementTitle.className = 'title-bar-modify'; 67 | }); 68 | 69 | this.editor.commands.addCommand({ 70 | name: 'save to', 71 | bindKey: {win: 'Ctrl-S', mac: 'Command-S'}, 72 | exec: function(editor) { 73 | ref.saveFile(); 74 | }, 75 | readOnly: true // false if this command should not apply in readOnly mode 76 | }); 77 | 78 | 79 | // drop 80 | let holder = document.getElementById(elementId); 81 | holder.ondrop = function( ev ) { 82 | 83 | ev.preventDefault(); 84 | var filetoken = ev.dataTransfer.getData("restoken"); 85 | 86 | let type = 0; 87 | let resobj = resMgr.gResmgr.get_res(filetoken); 88 | if( resobj !== null ) 89 | { 90 | type = resobj.get_type(); 91 | 92 | if(type === resMgr.RESTYPE.TEXT) 93 | { 94 | // save and load 95 | 96 | // save 97 | ref.saveFile(); 98 | 99 | // load coroutine 100 | ref.loadFile(resobj.filetoken); 101 | } 102 | } 103 | } 104 | 105 | holder.ondragover = function (ev) { 106 | ev.preventDefault(); 107 | } 108 | } 109 | 110 | loadFile(filetoken) 111 | { 112 | this.editingFiletoken = filetoken; 113 | this.loadCoroutine(this.editingFiletoken); 114 | } 115 | 116 | saveFile() { 117 | this.saveCoroutine(this.editingFiletoken); 118 | this.elementTitle.className = 'title-bar-saved'; 119 | }; 120 | 121 | 122 | autoUpdate( isAuto ) 123 | { 124 | 125 | } 126 | 127 | setChangeCallback( callbackfun ) 128 | { 129 | this.callback = callbackfun; 130 | } 131 | } 132 | 133 | module.exports = { AceEditorWindow }; -------------------------------------------------------------------------------- /lib/gk-component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/18. 3 | */ 4 | const math = require("gl-matrix"); 5 | const mathext = require('./util/gl-matrix-extension.js'); 6 | const gkCore = window.gkCore; 7 | 8 | class Component { 9 | constructor() { 10 | this._host = null; 11 | } 12 | 13 | get host() 14 | { 15 | return this._host; 16 | } 17 | 18 | set host( target ) 19 | { 20 | this._host = target; 21 | this.onStart(); 22 | } 23 | 24 | onStart() { 25 | 26 | } 27 | 28 | onUpdate() { 29 | //console.info( this ); 30 | } 31 | 32 | onRender() { 33 | 34 | } 35 | } 36 | 37 | class Transform extends Component { 38 | constructor() { 39 | super(); 40 | 41 | this._position = math.vec3.fromValues(0,0,0); 42 | this._rotation = math.quat.identity(math.quat.create()); 43 | this._scale = math.vec3.fromValues(1,1,1); 44 | 45 | this._dirty = true; 46 | 47 | this._localToWorldMatrx = math.mat4.identity(math.mat4.create()); 48 | 49 | 50 | this._parent = null; 51 | this.children = new Set(); 52 | 53 | 54 | this._worldposition = math.vec3.create(); 55 | this._worldrotation = math.quat.create(); 56 | } 57 | 58 | _markDirty() 59 | { 60 | this._dirtyComp = true; 61 | this._dirty = true; 62 | 63 | // all children mark dirty 64 | this.children.forEach( child => { 65 | child._markDirty(); 66 | } ); 67 | } 68 | 69 | get parent() 70 | { 71 | return this._parent; 72 | } 73 | 74 | set parent( target ) 75 | { 76 | // detach 77 | 78 | if(this._parent !== null) { 79 | this._parent._removeChild(this); 80 | } 81 | 82 | this._parent = target; 83 | 84 | if( target instanceof Transform) 85 | { 86 | // attach 87 | this._parent._addChild(this); 88 | } 89 | 90 | this._markDirty(); 91 | 92 | } 93 | 94 | _addChild( target ) 95 | { 96 | this.children.add( target ); 97 | } 98 | 99 | _removeChild( target ) 100 | { 101 | if(this.children.has( target )) { 102 | this.children.delete(target); 103 | } 104 | } 105 | 106 | CheckCompDirty() { 107 | if (this._dirtyComp === true) { 108 | if(this._parent !== null) 109 | { 110 | this._worldposition = math.vec3.add(math.vec3.create(), this._parent.position, math.vec3.transformQuat( 111 | math.vec3.create(), this.localPosition, this._parent.rotation)); 112 | 113 | this._worldrotation = math.quat.mul(math.quat.create(), this._parent.rotation, this.localRotation); 114 | } 115 | else 116 | { 117 | this._worldposition = this.localPosition; 118 | this._worldrotation = this.localRotation; 119 | } 120 | this._dirtyComp = false; 121 | } 122 | } 123 | 124 | get position() { 125 | if( this._parent === null ) 126 | { 127 | return this._position; 128 | } 129 | this.CheckCompDirty(); 130 | return this._worldposition; 131 | } 132 | 133 | get rotation() { 134 | if( this._parent === null ) 135 | { 136 | return this._rotation; 137 | } 138 | this.CheckCompDirty(); 139 | return this._worldrotation; 140 | } 141 | 142 | set position(value) { 143 | this._worldposition = value; 144 | if( this._parent !== null) 145 | { 146 | let distance = math.vec3.sub(math.vec3.create(), this._worldposition, this._parent.position); 147 | let invRotParent = math.quat.invert( math.quat.create(), this._parent.rotation ); 148 | this.localPosition = math.vec3.transformQuat( math.vec3.create(), distance, invRotParent ); 149 | } 150 | else 151 | { 152 | this.localPosition = this._worldposition; 153 | } 154 | } 155 | 156 | set rotation(value) { 157 | this._worldrotation = value; 158 | if( this._parent !== null) { 159 | let invRotParent = math.quat.invert(math.quat.create(), this._parent.rotation); 160 | this.localRotation = math.quat.mul(math.quat.create(), invRotParent, this._worldrotation); 161 | } 162 | else 163 | { 164 | this.localRotation = this._worldrotation; 165 | } 166 | } 167 | 168 | // native propery setter/getter 169 | get localPosition() { 170 | return this._position; 171 | } 172 | set localPosition(value) { 173 | this._markDirty(); 174 | this._position = value; 175 | } 176 | 177 | get localRotation() { 178 | return this._rotation; 179 | } 180 | set localRotation(value) { 181 | this._markDirty(); 182 | this._rotation = value; 183 | } 184 | 185 | get localScale() { 186 | return this._scale; 187 | } 188 | set localScale(value) { 189 | this._markDirty(); 190 | this._scale = value; 191 | } 192 | 193 | // matrix access 194 | get localToWorldMatrix() { 195 | if(this._dirty) 196 | { 197 | this._dirty = false; 198 | 199 | let childmatrix = math.mat4.fromRotationTranslationScale(math.mat4.create(), this._rotation, this._position, this._scale ); 200 | 201 | if(this._parent !== null) 202 | { 203 | this._localToWorldMatrx = math.mat4.mul( this._localToWorldMatrx, this._parent.localToWorldMatrix, childmatrix ); 204 | } 205 | else 206 | { 207 | this._localToWorldMatrx = childmatrix; 208 | } 209 | } 210 | return this._localToWorldMatrx; 211 | } 212 | 213 | get forward() { 214 | // TODO 215 | return math.vec3.transformQuat(math.vec3.create(), math.vec3.fromValues(0,0,1), this.rotation ); 216 | } 217 | 218 | get up() { 219 | // TODO 220 | return math.vec3.transformQuat(math.vec3.create(), math.vec3.fromValues(0,1,0), this.rotation ); 221 | } 222 | 223 | get left() { 224 | // TODO 225 | return math.vec3.transformQuat(math.vec3.create(), math.vec3.fromValues(1,0,0), this.rotation ); 226 | } 227 | 228 | // other method 229 | lookAt( target ) { 230 | 231 | // rebuild the quat axes with forward and up 232 | let forward = math.vec3.sub(math.vec3.create(), target, this.position); 233 | forward = math.vec3.normalize(forward, forward); 234 | 235 | let up = math.vec3.fromValues(0,1,0); 236 | 237 | let left = math.vec3.cross(math.vec3.create(), up, forward ); 238 | left = math.vec3.normalize(left,left); 239 | 240 | up = math.vec3.cross(math.vec3.create(), forward, left ); 241 | up = math.vec3.normalize(up, up); 242 | 243 | let matr = math.mat3.create(); 244 | matr[0] = -left[0]; 245 | matr[1] = -left[1]; 246 | matr[2] = -left[2]; 247 | 248 | matr[3] = up[0]; 249 | matr[4] = up[1]; 250 | matr[5] = up[2]; 251 | 252 | matr[6] = -forward[0]; 253 | matr[7] = -forward[1]; 254 | matr[8] = -forward[2]; 255 | 256 | this.rotation = math.quat.fromMat3(math.quat.create(), matr); 257 | } 258 | 259 | /** 260 | * Transforms in localspace 261 | * 262 | * @param {vec3} vector 263 | */ 264 | translateLocal( vec ) { 265 | let trans = math.vec3.transformQuat( math.vec3.create(), vec, this.localRotation ); 266 | this.localPosition = math.vec3.add( this.localPosition, this.localPosition, trans ); 267 | } 268 | 269 | /** 270 | * Transforms in worldspace 271 | * 272 | * @param {vec3} vector 273 | */ 274 | translateWorld( vec ) { 275 | let trans = math.vec3.transformQuat( math.vec3.create(), vec, this.rotation ); 276 | this.position = math.vec3.add( math.vec3.create(), this.position, trans ); 277 | } 278 | 279 | getComponent( comp ) { 280 | let returnArray = []; 281 | 282 | let component = this.host.components.get( comp ); 283 | if(component) 284 | { 285 | returnArray.push(component); 286 | } 287 | 288 | this.children.forEach( child => { 289 | returnArray = returnArray.concat( child.getComponent( comp ) ); 290 | }); 291 | 292 | return returnArray; 293 | } 294 | 295 | onStart() { 296 | this.host.transform = this; 297 | } 298 | } 299 | 300 | class MeshFilter extends Component { 301 | constructor() { 302 | super(); 303 | this._mesh = null; 304 | 305 | this._aabb = mathext.aabb.create(); 306 | } 307 | 308 | set mesh(value) { 309 | this._mesh = value; 310 | 311 | // for each vertice in mesh 312 | // compare with _lbb & _rtf 313 | let vbo = this._mesh.vboForReadback; 314 | let size = this._mesh.vertexSize / 4; 315 | 316 | let vertCount = vbo.length / size ; 317 | //console.log(vbo.length + ' / ' + size); 318 | 319 | for( let i=0; i < vertCount; ++i) { 320 | let position = math.vec3.fromValues(this._mesh.vboForReadback[i * size + 0], this._mesh.vboForReadback[i * size + 1], this._mesh.vboForReadback[i * size + 2]); 321 | 322 | mathext.aabb.addPoint( this._aabb, position); 323 | } 324 | // complete 325 | } 326 | 327 | get mesh() { 328 | return this._mesh; 329 | } 330 | } 331 | 332 | class MeshRenderer extends Component { 333 | constructor() { 334 | super(); 335 | this.material = null; 336 | } 337 | 338 | get bounds() { 339 | 340 | let mf = this.host.components.get(MeshFilter); 341 | 342 | // transform mesh bounds to world, 343 | let tmpaabb = mathext.aabb.create(); 344 | mathext.aabb.mergeOBB( tmpaabb, mf._aabb, this.host.transform.localToWorldMatrix ); 345 | 346 | // return the new bounds 347 | return tmpaabb; 348 | } 349 | } 350 | 351 | class Camera extends Component { 352 | constructor() { 353 | super(); 354 | } 355 | 356 | onUpdate() { 357 | super.onUpdate(); 358 | } 359 | 360 | onRender() { 361 | // prepare render queue 362 | let queue = gkCore.renderer.getOrCreateRenderQueue(0); 363 | 364 | // send per queue parameter set to queue 365 | queue.setupCamera( this ); 366 | 367 | // push target mr to renderqueue 368 | let mrs = gkCore.sceneMgr.getMeshRenderers(); 369 | mrs.forEach( mr => { 370 | // doing culling here 371 | queue.addRenderer( mr ); 372 | }); 373 | } 374 | } 375 | 376 | class Light extends Component { 377 | constructor() { 378 | super(); 379 | 380 | this.intensity = 1.0; 381 | } 382 | 383 | onUpdate() { 384 | super.onUpdate(); 385 | } 386 | 387 | onRender() { 388 | // TODO: add to everyqueue 389 | // prepare render queue 390 | let queue = gkCore.renderer.getOrCreateRenderQueue(0); 391 | 392 | // send per queue parameter set to queue 393 | queue.setupLight( this ); 394 | } 395 | } 396 | 397 | module.exports = {Component, Transform, MeshFilter, MeshRenderer, Camera, Light}; 398 | 399 | -------------------------------------------------------------------------------- /lib/gk-core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/5. 3 | */ 4 | window.gkCore = exports; 5 | 6 | exports.Component = require('./gk-component.js'); 7 | exports.GameObject = require('./gk-gameobject.js'); 8 | const Renderer = require('./gk-renderer.js'); 9 | exports.renderer = new Renderer(); 10 | const SceneMgr = require('./gk-scenemgr.js'); 11 | exports.sceneMgr = new SceneMgr(); 12 | exports.math = require('gl-matrix'); 13 | exports.mouse = require("./gk-mouseorbit.js"); 14 | const BaseResMgr = require("./gk-resmgr").BaseResMgr; 15 | exports.resMgr = new BaseResMgr(); 16 | exports.mathext = require("./util/gl-matrix-extension.js"); -------------------------------------------------------------------------------- /lib/gk-fixedshader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/1. 3 | */ 4 | 5 | var quadvsp = "attribute vec3 position;\ 6 | varying vec2 vTexCoord;\ 7 | void main(){\ 8 | vTexCoord = ((position + 1.0) * 0.5).xy;\ 9 | gl_Position = vec4(position, 1.0);\ 10 | }\ 11 | "; 12 | 13 | var noisefsp = "precision mediump float;\ 14 | uniform sampler2D texture;\ 15 | varying vec2 vTexCoord;\ 16 | uniform float _TIME;\ 17 | float snoise(vec2 co){\ 18 | return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\ 19 | }\ 20 | void main(){\ 21 | float noise = fract(_TIME);\ 22 | vec4 samplerColor = vec4(0.3,0.3,0.3,1.0);\ 23 | float vignette = 1.0 - length((vTexCoord.xy - vec2(0.5,0.5)) * vec2(1.5, 1.5));\ 24 | samplerColor *= vignette;\ 25 | samplerColor += snoise(vTexCoord.xy + vec2(noise,noise)) * 0.04;\ 26 | gl_FragColor = samplerColor;\ 27 | }\ 28 | "; 29 | 30 | var quadfsp = "precision highp float;\ 31 | uniform sampler2D texture;\ 32 | varying vec2 vTexCoord;\ 33 | float DecodeFloatRGBA(vec4 enc){\ 34 | vec4 kDecodeDot = vec4(1.0,1.0/255.0,1.0/65025.0,1.0/160581375.0);\ 35 | return dot(enc, kDecodeDot);\ 36 | }\ 37 | void main(){\ 38 | vec4 samplerColor = texture2D(texture, vTexCoord.xy);\ 39 | gl_FragColor = samplerColor;\ 40 | }\ 41 | "; 42 | 43 | var shadowvsp = "attribute vec2 texcoord;\ 44 | attribute vec3 normal;\ 45 | attribute vec3 position;\ 46 | uniform mat4 _MVP;\ 47 | uniform mat4 _M2W;\ 48 | \ 49 | varying vec2 vTexCoord;\ 50 | varying vec2 zOffset;\ 51 | \ 52 | void main(){\ 53 | vTexCoord = texcoord;\ 54 | gl_Position = _MVP * vec4(position, 1.0);\ 55 | zOffset = gl_Position.zw;\ 56 | }"; 57 | var shadowfsp = "precision highp float;\ 58 | uniform sampler2D _MainTex;\ 59 | uniform sampler2D _AlphaTex;\ 60 | varying vec2 vTexCoord;\ 61 | varying vec2 zOffset;\ 62 | \ 63 | \ 64 | float frac(float t)\ 65 | {\ 66 | return t - floor(t);\ 67 | }\ 68 | vec4 frac(vec4 t)\ 69 | {\ 70 | return t - floor(t);\ 71 | }\ 72 | vec4 EncodeFloatRGBA( float v )\ 73 | {\ 74 | vec4 kEncodeMul = vec4(1.0, 255.0, 65025.0, 160581375.0);\ 75 | float kEncodeBit = 1.0/255.0;\ 76 | vec4 enc = kEncodeMul * vec4(v,v,v,v);\ 77 | enc = frac(enc);\ 78 | enc -= enc.yzww * kEncodeBit;\ 79 | return enc;\ 80 | }\ 81 | void main(){\ 82 | vec4 encoded = EncodeFloatRGBA(zOffset.x / zOffset.y);\ 83 | vec4 samplerColor = texture2D(_MainTex, vTexCoord.xy);\ 84 | vec4 alphaSamplerColor = texture2D(_AlphaTex, vTexCoord.xy);\ 85 | if(samplerColor.a < 0.05) discard;\ 86 | gl_FragColor = encoded;\ 87 | }"; 88 | 89 | var simpleshadowvsp = "attribute vec2 texcoord;\ 90 | attribute vec3 normal;\ 91 | attribute vec3 position;\ 92 | uniform mat4 _MVP;\ 93 | uniform mat4 _M2W;\ 94 | \ 95 | varying vec2 vTexCoord;\ 96 | \ 97 | void main(){\ 98 | vTexCoord = texcoord;\ 99 | gl_Position = _MVP * vec4(position, 1.0);\ 100 | }"; 101 | var simpleshadowfsp = "precision highp float;\ 102 | uniform sampler2D _MainTex;\ 103 | uniform sampler2D _AlphaTex;\ 104 | varying vec2 vTexCoord;\ 105 | void main(){\ 106 | vec4 alphaSamplerColor = texture2D(_AlphaTex, vTexCoord.xy);\ 107 | if(alphaSamplerColor.a < 0.05) discard;\ 108 | gl_FragColor = vec4(1.0,1.0,1.0,1.0);\ 109 | }"; 110 | 111 | var simplezpassvsp = "attribute vec2 texcoord;\ 112 | attribute vec3 normal;\ 113 | attribute vec3 position;\ 114 | uniform mat4 _MVP;\ 115 | uniform mat4 _M2W;\ 116 | uniform mat4 _MV;\ 117 | \ 118 | varying vec2 vTexCoord;\ 119 | varying vec4 vNormal;\ 120 | \ 121 | void main(){\ 122 | vTexCoord = texcoord;\ 123 | vNormal = _MV * vec4(normal, 0.0);\ 124 | gl_Position = _MVP * vec4(position, 1.0);\ 125 | }"; 126 | var simplezpassfsp = "precision highp float;\ 127 | uniform sampler2D _MainTex;\ 128 | uniform sampler2D _AlphaTex;\ 129 | varying vec2 vTexCoord;\ 130 | varying vec4 vNormal;\ 131 | void main(){\ 132 | vec4 alphaSamplerColor = texture2D(_AlphaTex, vTexCoord.xy);\ 133 | if(alphaSamplerColor.a < 0.05) discard;\ 134 | gl_FragColor = vec4(vNormal.xyz * 0.5 + 0.5,1.0);\ 135 | }"; 136 | 137 | var ssaovsp = "attribute vec3 position;\ 138 | varying vec2 vTexCoord;\ 139 | void main(){\ 140 | vTexCoord = ((position + 1.0) * 0.5).xy;\ 141 | gl_Position = vec4(position, 1.0);\ 142 | }\ 143 | "; 144 | 145 | var ssaofsp = "precision mediump float;\ 146 | uniform sampler2D _GlobalNormalMap;\ 147 | uniform sampler2D _GlobalDepthMap;\ 148 | uniform float _TIME;\ 149 | varying vec2 vTexCoord;\ 150 | const vec2 sobel1 = vec2(0,-1);\ 151 | const vec2 sobel2 = vec2(-1.41,1.41);\ 152 | const vec2 sobel3 = vec2(1.41,1.41);\ 153 | const vec2 sobel4 = vec2(0,1);\ 154 | const vec2 sobel5 = vec2(1.41,-1.41);\ 155 | const vec2 sobel6 = vec2(-1.41,-1.41);\ 156 | float DecodeFloatRGBA(vec4 enc){\ 157 | vec4 kDecodeDot = vec4(1.0,1.0/255.0,1.0/65025.0,1.0/160581375.0);\ 158 | return dot(enc, kDecodeDot);\ 159 | }\ 160 | float snoise(vec2 co){\ 161 | return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\ 162 | }\ 163 | float CalcAccumNormal(){\ 164 | vec3 acc1 = vec3(0,0,0);\ 165 | float noise = fract(_TIME);\ 166 | float noiseMap = snoise(vTexCoord.xy + vec2(noise,noise)) * 1.0;\ 167 | vec2 normal = vec2(noiseMap, 1.0 - noiseMap);\ 168 | normal = normalize(normal);\ 169 | vec2 s1 = reflect(normal, sobel1);\ 170 | vec2 s2 = reflect(normal, sobel2);\ 171 | vec2 s3 = reflect(normal, sobel3);\ 172 | vec2 s4 = reflect(normal, sobel4);\ 173 | vec2 s5 = reflect(normal, sobel5);\ 174 | vec2 s6 = reflect(normal, sobel6);\ 175 | \ 176 | acc1.x = dot(vec3(s1,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s1 * -0.003).xyz * 2.0 - 1.0);\ 177 | acc1.y = dot(vec3(s2,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s2 * -0.003).xyz * 2.0 - 1.0);\ 178 | acc1.z = dot(vec3(s3,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s3 * -0.003).xyz * 2.0 - 1.0);\ 179 | acc1 = vec3(1,1,1) - min(acc1, vec3(1,1,1));\ 180 | \ 181 | vec3 acc2 = vec3(0,0,0);\ 182 | acc2.x = dot(vec3(s4,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s4 * -0.006).xyz * 2.0 - 1.0);\ 183 | acc2.y = dot(vec3(s5,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s5 * -0.006).xyz * 2.0 - 1.0);\ 184 | acc2.z = dot(vec3(s6,0.0), texture2D(_GlobalNormalMap, vTexCoord.xy + s6 * -0.006).xyz * 2.0 - 1.0);\ 185 | acc2 = vec3(1,1,1) - min(acc2, vec3(1,1,1));\ 186 | \ 187 | return dot(acc1, vec3(0.15,0.15,0.15)) + dot(acc2, vec3(0.15,0.15,0.15));\ 188 | }\ 189 | void main(){\ 190 | float samplerColor = CalcAccumNormal();\ 191 | gl_FragColor = vec4(samplerColor, samplerColor, samplerColor, 1.0);\ 192 | }\ 193 | "; 194 | 195 | module.exports = { quadvsp, noisefsp, quadfsp, 196 | shadowvsp, shadowfsp, 197 | simpleshadowvsp, simpleshadowfsp, 198 | simplezpassvsp, simplezpassfsp, 199 | ssaovsp, ssaofsp}; -------------------------------------------------------------------------------- /lib/gk-framework.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/1. 3 | */ 4 | 'use strict'; 5 | const gTimer = require("./gk-timer.js"); 6 | const Fabricate = require("./fabricate.js"); 7 | 8 | const gkCore = require("./gk-core.js"); 9 | const acEditor = require('./gk-acewrap'); 10 | const glw = require("./gk-glwrap"); 11 | 12 | class Framework 13 | { 14 | constructor() { 15 | 16 | } 17 | 18 | init() { 19 | 20 | } 21 | 22 | update() { 23 | 24 | } 25 | 26 | destroy() { 27 | 28 | } 29 | } 30 | 31 | class ShaderMonkiFramework extends Framework 32 | { 33 | constructor() { 34 | super(); 35 | 36 | this.renderer = null; 37 | this.sceneMgr = null; 38 | 39 | this.mainCamera = null; 40 | 41 | 42 | this.modelrotation = 0; 43 | this.camerarotationx = 0; 44 | this.camerarotationy = 0; 45 | 46 | this.camerapanx = 0; 47 | this.camerapany = 0; 48 | 49 | this.autoRotate = false; 50 | 51 | this.vsp_source = null; 52 | this.fsp_source = null; 53 | 54 | this.holderGameObject = null; 55 | 56 | this.cameraCenter = gkCore.math.vec3.create(); 57 | this.cameraRadius = 500.0; 58 | } 59 | 60 | init() { 61 | gTimer.init(); 62 | 63 | this.renderer = gkCore.renderer; 64 | this.renderer.init(); 65 | 66 | this.sceneMgr = gkCore.sceneMgr; 67 | this.sceneMgr.init(); 68 | 69 | this.mainCamera = Fabricate(gkCore.GameObject.Camera); 70 | this.mainCamera.transform.parent = this.sceneMgr.getSceneRoot().transform; 71 | 72 | // temporary camera transform setting 73 | this.mainCamera.transform.position = gkCore.math.vec3.fromValues(0,15,50); 74 | this.mainCamera.transform.lookAt( gkCore.math.vec3.fromValues(0,0,0) ); 75 | 76 | this.mainLight = Fabricate(gkCore.GameObject.Light); 77 | this.mainLight.transform.position = gkCore.math.vec3.fromValues(-1000,1500,1000); 78 | this.mainLight.transform.lookAt( gkCore.math.vec3.fromValues(0,0,0) ); 79 | this.mainLight.transform.parent = this.sceneMgr.getSceneRoot().transform; 80 | 81 | // create editor 82 | let refthis = this; 83 | 84 | let vseditor = new acEditor.AceEditorWindow("vs-editor-panel"); 85 | vseditor.setChangeCallback( function(str) { 86 | refthis.vsp_source = str; 87 | refthis.updateShader(); 88 | } ) 89 | 90 | let fseditor = new acEditor.AceEditorWindow("fs-editor-panel"); 91 | fseditor.setChangeCallback( function(str) { 92 | refthis.fsp_source = str; 93 | refthis.updateShader(); 94 | } ); 95 | 96 | // default assets loading 97 | vseditor.loadFile('res/shader/base_vs.glsl'); 98 | fseditor.loadFile('res/shader/base_fs.glsl'); 99 | 100 | } 101 | 102 | update() { 103 | gTimer.update(); 104 | 105 | // update mouse 106 | let relDelta = gkCore.mouse.frameUpdate(); 107 | 108 | if(gkCore.mouse.moveType === gkCore.mouse.HOLDLEFT) 109 | { 110 | this.camerarotationy -= relDelta.y * 0.005; 111 | this.camerarotationx -= relDelta.x * 0.005; 112 | } 113 | else if(gkCore.mouse.moveType === gkCore.mouse.HOLDMIDDLE) 114 | { 115 | this.camerapany += relDelta.y * (0.002 * this.cameraRadius); 116 | this.camerapanx -= relDelta.x * (0.002 * this.cameraRadius); 117 | } 118 | 119 | this.cameraRadius *= (1.0 - relDelta.z * 0.25); 120 | 121 | let rot = gkCore.math.quat.create(); 122 | gkCore.math.quat.rotateY(rot, rot, this.camerarotationx); 123 | gkCore.math.quat.rotateX(rot, rot, this.camerarotationy); 124 | this.mainCamera.transform.rotation = rot; 125 | this.mainCamera.transform.position = this.cameraCenter; 126 | this.mainCamera.transform.translateLocal(gkCore.math.vec3.fromValues(this.camerapanx,this.camerapany,0)); 127 | this.mainCamera.transform.translateLocal(gkCore.math.vec3.fromValues(0,0,this.cameraRadius)); 128 | 129 | this.sceneMgr.update(); 130 | this.renderer.render(); 131 | } 132 | 133 | destory() { 134 | 135 | } 136 | 137 | updateShader() { 138 | if(this.vsp_source !== null && this.fsp_source !== null && this.vsp_source !== "" && this.fsp_source !== "") { 139 | let program = glw.createProgramObject(this.vsp_source, this.fsp_source); 140 | this.renderer.overrideProgram = program; 141 | } 142 | } 143 | 144 | bindShowObj( gameObject) { 145 | 146 | // load a mesh into gameobject struct 147 | if(this.holderGameObject !== null) 148 | { 149 | this.holderGameObject.transform.parent = null; 150 | } 151 | // bind it to scene root 152 | gameObject.transform.parent = gkCore.sceneMgr.getSceneRoot().transform; 153 | this.holderGameObject = gameObject; 154 | 155 | // camera target reset 156 | let mrs = gameObject.transform.getComponent( gkCore.Component.MeshRenderer ); 157 | let aabbTotal = gkCore.mathext.aabb.create(); 158 | mrs.forEach( meshRenderer => { 159 | let aabb = meshRenderer.bounds; 160 | gkCore.mathext.aabb.mergeAABB(aabbTotal, aabb); 161 | }); 162 | 163 | this.cameraCenter = gkCore.mathext.aabb.center(gkCore.math.vec3.create(), aabbTotal); 164 | this.cameraRadius = gkCore.mathext.aabb.radius(aabbTotal) * 1.5; 165 | this.camerapanx = 0; 166 | this.camerapany = 0; 167 | 168 | //console.info(aabbTotal); 169 | if( isNaN( this.cameraCenter[0] )) 170 | { 171 | this.cameraCenter = gkCore.math.vec3.create(); 172 | this.cameraRadius = 100.0; 173 | } 174 | 175 | console.info(this.cameraCenter); 176 | console.log(this.cameraRadius); 177 | } 178 | } 179 | 180 | module.exports = ShaderMonkiFramework; -------------------------------------------------------------------------------- /lib/gk-gameobject.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/18. 3 | */ 4 | const Component = require('./gk-component.js'); 5 | 6 | const Base = { 7 | name: "GameObject", 8 | transform: null, 9 | components: [Component.Transform] 10 | } 11 | 12 | const Camera = { 13 | name: "Camera", 14 | transform: null, 15 | components: [Component.Transform, Component.Camera] 16 | } 17 | 18 | const StaticMesh = { 19 | name: "StaticMesh", 20 | transform: null, 21 | components: [Component.Transform, Component.MeshFilter, Component.MeshRenderer] 22 | } 23 | 24 | const Light = { 25 | name: "Light", 26 | transform: null, 27 | components: [Component.Transform, Component.Light] 28 | } 29 | 30 | module.exports = {Base, Camera, StaticMesh, Light}; -------------------------------------------------------------------------------- /lib/gk-glwrap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const logger = require('./gk-logger.js'); 3 | const math = require('gl-matrix'); 4 | 5 | var glw = glw || {}; 6 | module.exports = glw; 7 | 8 | // const 9 | glw.VERSION = '0.1'; 10 | glw.PI2 = 6.28318530717958647692528676655900576; 11 | glw.PI = 3.14159265358979323846264338327950288; 12 | glw.PIH = 1.57079632679489661923132169163975144; 13 | glw.PIH2 = 0.78539816339744830961566084581987572; 14 | 15 | glw.VERTEX_LAYOUT_P = 0; 16 | glw.VERTEX_LAYOUT_N = 1; 17 | glw.VERTEX_LAYOUT_T0 = 2; 18 | glw.VERTEX_LAYOUT_T1 = 3; 19 | glw.VERTEX_LAYOUT_C = 4; 20 | 21 | // global member 22 | glw.ready = false; 23 | glw.canvas = null; 24 | glw.gl = null; 25 | glw.curr_program = null; 26 | glw.nullTexture = null; 27 | glw.glext_depth_texture = false; 28 | 29 | // public interface 30 | 31 | // initialize webgl 32 | glw.initGL = function(canvasId, options){ 33 | this.ready = false; 34 | this.canvas = null; 35 | this.gl = null; 36 | 37 | if(Object.prototype.toString.call(canvasId) === '[object String]'){ 38 | this.canvas = document.getElementById(canvasId); 39 | }else{ 40 | if(Object.prototype.toString.call(canvasId) === '[object HTMLCanvasElement]'){ 41 | this.canvas = canvasId; 42 | } 43 | } 44 | 45 | var opt = options || {}; 46 | if(this.canvas == null){return false;} 47 | this.gl = this.canvas.getContext('webgl', opt) 48 | || this.canvas.getContext('experimental-webgl', opt); 49 | 50 | if(this.gl != null){ 51 | this.ready = true; 52 | } 53 | 54 | let checkerData = new Uint8Array(16); 55 | checkerData[0] = 0; 56 | checkerData[1] = 0; 57 | checkerData[2] = 0; 58 | checkerData[3] = 0; 59 | 60 | glw.nullTexture = glw._create_procedural_texture(2,2,checkerData); 61 | let ext = this.gl.getExtension("WEBGL_depth_texture"); 62 | glw.glext_depth_texture = (ext !== undefined); 63 | 64 | return this.ready; 65 | }; 66 | 67 | // glclear 68 | glw.clear = function(color, depth, stencil){ 69 | var gl = this.gl; 70 | var flg = gl.COLOR_BUFFER_BIT; 71 | gl.clearColor(color[0], color[1], color[2], color[3]); 72 | if(depth != null){ 73 | gl.clearDepth(depth); 74 | flg = flg | gl.DEPTH_BUFFER_BIT; 75 | } 76 | if(stencil != null){ 77 | gl.clearStencil(stencil); 78 | flg = flg | gl.STENCIL_BUFFER_BIT; 79 | } 80 | gl.clear(flg); 81 | }; 82 | 83 | // glviewport 84 | glw.viewport = function(x, y, width, height){ 85 | var X = x || 0; 86 | var Y = y || 0; 87 | var w = width || window.innerWidth; 88 | var h = height || window.innerHeight; 89 | this.gl.viewport(X, Y, w, h); 90 | }; 91 | 92 | glw.set_uniform1f = function(name, fvalue) 93 | { 94 | if(this.curr_program != null) { 95 | var loc = this.gl.getUniformLocation(this.curr_program, name); 96 | if (loc != -1) { 97 | this.gl.uniform1f(loc, fvalue); 98 | } 99 | } 100 | }; 101 | 102 | glw.set_uniform4f = function (name, fvalue) 103 | { 104 | if(this.curr_program != null) 105 | { 106 | var loc = this.gl.getUniformLocation(this.curr_program, name); 107 | if (loc != -1) { 108 | this.gl.uniform4f(loc, fvalue[0], fvalue[1], fvalue[2], fvalue[3]); 109 | } 110 | } 111 | }; 112 | 113 | glw.set_uniform4x4fv = function(name, fvalue) 114 | { 115 | if(this.curr_program != null) { 116 | var loc = this.gl.getUniformLocation(this.curr_program, name); 117 | if (loc != -1) { 118 | this.gl.uniformMatrix4fv(loc, false, fvalue); 119 | } 120 | } 121 | }; 122 | 123 | 124 | glw.bind_texture = function( texobj, unit ) 125 | { 126 | let targetTO = texobj; 127 | if(texobj === null) { 128 | targetTO = glw.nullTexture; 129 | } 130 | 131 | if(this.curr_program != null) 132 | { 133 | var loc = this.gl.getUniformLocation(this.curr_program, '_MainTex'); 134 | if (loc != -1) { 135 | this.gl.uniform1i(loc, 0); 136 | } 137 | loc = this.gl.getUniformLocation(this.curr_program, '_AlphaTex'); 138 | if (loc != -1) { 139 | this.gl.uniform1i(loc, 1); 140 | } 141 | loc = this.gl.getUniformLocation(this.curr_program, '_GlobalNormalMap'); 142 | if (loc != -1) { 143 | this.gl.uniform1i(loc, 5); 144 | } 145 | loc = this.gl.getUniformLocation(this.curr_program, '_GlobalOccMap'); 146 | if (loc != -1) { 147 | this.gl.uniform1i(loc, 5); 148 | } 149 | loc = this.gl.getUniformLocation(this.curr_program, '_GlobalDepthMap'); 150 | if (loc != -1) { 151 | this.gl.uniform1i(loc, 6); 152 | } 153 | loc = this.gl.getUniformLocation(this.curr_program, '_GlobalShadowMap'); 154 | if (loc != -1) { 155 | this.gl.uniform1i(loc, 7); 156 | } 157 | 158 | 159 | } 160 | 161 | { 162 | this.gl.activeTexture(33984 + unit); 163 | this.gl.bindTexture(this.gl.TEXTURE_2D, targetTO); 164 | } 165 | }; 166 | 167 | /// mesh obj 168 | glw.meshObject = function(webglContext){ 169 | this.gl = webglContext; 170 | }; 171 | 172 | // construct 173 | glw.createMeshObject = function ( res, vertexLayout ) { 174 | 175 | var newObj = new meshObject(this.gl); 176 | 177 | // res comes single one 178 | let vertexStream = res.vbo; 179 | let indexStream_list = res.ibo.trilist; 180 | let indexStream_strip = res.ibo.tristrip; 181 | 182 | newObj.vboForReadback = vertexStream; 183 | newObj.trilistForReadback = indexStream_list; 184 | newObj.tristripForReadback = indexStream_strip; 185 | 186 | newObj.vbo = glw._create_vbo(vertexStream); 187 | if(indexStream_list) 188 | { 189 | newObj.trilist = glw._create_ibo(indexStream_list); 190 | newObj.indexSize_list = indexStream_list.length; 191 | } 192 | else 193 | { 194 | newObj.indexSize_list = 0; 195 | } 196 | if(indexStream_strip) 197 | { 198 | newObj.tristrip = glw._create_ibo(indexStream_strip); 199 | newObj.indexSize_strip = indexStream_strip.length; 200 | } 201 | else 202 | { 203 | newObj.indexSize_strip = 0; 204 | } 205 | 206 | var size = 0; 207 | if(vertexLayout.indexOf(glw.VERTEX_LAYOUT_P) !== -1 ) 208 | { 209 | size += 3 * 4; 210 | } 211 | 212 | if(vertexLayout.indexOf(glw.VERTEX_LAYOUT_N) !== -1 ) 213 | { 214 | size += 3 * 4; 215 | } 216 | 217 | if(vertexLayout.indexOf(glw.VERTEX_LAYOUT_T0) !== -1 ) 218 | { 219 | size += 2 * 4; 220 | } 221 | newObj.vertexSize = size; 222 | newObj.vertexLayout = vertexLayout; 223 | 224 | // calc bbox 225 | // for( let i=0, len = vertexStream.length / size; i < len; ++i) 226 | // { 227 | // let vertexPos = math.vec3.fromValues( vertexStream[i * size + 0], vertexStream[i * size + 1], vertexStream[i * size + 2]); 228 | // math.vec3.min( newObj.lbb, newObj.lbb, vertexPos ); 229 | // math.vec3.max( newObj.rtf, newObj.rtf, vertexPos ); 230 | // } 231 | 232 | return newObj; 233 | }; 234 | 235 | class meshObject { 236 | 237 | constructor( glcontext ) { 238 | this.gl = glcontext; 239 | this.vbo = null; 240 | this.tristrip = null; 241 | this.trilist = null; 242 | this.vertexSize = null; 243 | this.vertexLayout = null; 244 | this.indexSize_list = 0; 245 | this.indexSize_strip = 0; 246 | this.lbb = math.vec3.fromValues(999999,999999,999999); 247 | this.rtf = math.vec3.fromValues(-999999,-999999,-999999); 248 | 249 | this.vboForReadback = null; 250 | this.trilistForReadback = null; 251 | this.tristripForReadback = null; 252 | } 253 | 254 | bind() { 255 | var offset = 0; 256 | 257 | if(this.vertexLayout.indexOf(glw.VERTEX_LAYOUT_P) !== -1 ) 258 | { 259 | var location = this.gl.getAttribLocation(glw.curr_program, "position"); 260 | if(location !== -1) 261 | { 262 | this.gl.enableVertexAttribArray(location); 263 | this.gl.vertexAttribPointer(location,3,this.gl.FLOAT,false,this.vertexSize,offset); 264 | } 265 | offset += 3 * 4; 266 | } 267 | 268 | if(this.vertexLayout.indexOf(glw.VERTEX_LAYOUT_N) !== -1 ) 269 | { 270 | var location = this.gl.getAttribLocation(glw.curr_program, "normal"); 271 | if(location !== -1) { 272 | this.gl.enableVertexAttribArray(location); 273 | this.gl.vertexAttribPointer(location, 3, this.gl.FLOAT, false, this.vertexSize, offset); 274 | } 275 | offset += 3 * 4; 276 | } 277 | 278 | if(this.vertexLayout.indexOf(glw.VERTEX_LAYOUT_T0) !== -1 ) 279 | { 280 | var location = this.gl.getAttribLocation(glw.curr_program, "texcoord"); 281 | if(location !== -1) { 282 | this.gl.enableVertexAttribArray(location); 283 | this.gl.vertexAttribPointer(location,2,this.gl.FLOAT,false,this.vertexSize,offset); 284 | } 285 | offset += 2 * 4; 286 | } 287 | 288 | 289 | } 290 | 291 | draw() { 292 | 293 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vbo); 294 | this.bind(); 295 | 296 | if(this.indexSize_list > 0) 297 | { 298 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.trilist); 299 | glw._draw_elements(this.gl.TRIANGLES, this.indexSize_list); 300 | } 301 | if(this.indexSize_strip > 0) 302 | { 303 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.tristrip); 304 | glw._draw_elements(this.gl.TRIANGLE_STRIP, this.indexSize_strip); 305 | } 306 | 307 | } 308 | 309 | } 310 | // mesh obj 311 | 312 | /// material obj 313 | glw.createMaterialObject = function () { 314 | return new materialObject(); 315 | }; 316 | class materialObject 317 | { 318 | constructor() { 319 | this.mainTex = null; 320 | this.lightMapTex = null; 321 | this.name = 'default'; 322 | } 323 | 324 | bind() { 325 | 326 | } 327 | } 328 | 329 | /// program obj 330 | glw.createProgramObject = function (vsSource, psSource) { 331 | 332 | var newObj = new programObject(this.gl); 333 | newObj.glprogram = newObj.create(vsSource, psSource); 334 | if(newObj.glprogram === null) 335 | { 336 | return null; 337 | } 338 | // analyze uniforms from vs & fs source 339 | newObj.loc[0] = this.gl.getAttribLocation(newObj.glprogram, "position"); 340 | newObj.loc[1] = this.gl.getAttribLocation(newObj.glprogram, "normal"); 341 | newObj.loc[2] = this.gl.getAttribLocation(newObj.glprogram, "texcoord"); 342 | 343 | return newObj; 344 | }; 345 | 346 | class programObject 347 | { 348 | constructor(glContext) { 349 | this.gl = glContext; 350 | this.glprogram = null; 351 | this.loc = {}; 352 | } 353 | 354 | create(vsSource, fsSource) { 355 | var prg = null; 356 | var vs = glw._create_shader_from_source(vsSource, this.gl.VERTEX_SHADER); 357 | var fs = glw._create_shader_from_source(fsSource, this.gl.FRAGMENT_SHADER); 358 | prg = glw._create_program(vs, fs); 359 | return prg; 360 | }; 361 | 362 | set_uniform( uniform_name, uniform_value ) 363 | { 364 | 365 | }; 366 | 367 | use() 368 | { 369 | glw._use_program( this.glprogram ); 370 | }; 371 | } 372 | // program obj 373 | 374 | 375 | 376 | /// internal interface 377 | 378 | // create shader 379 | glw._create_shader_from_source = function(source, type){ 380 | var shader, msg; 381 | switch(type){ 382 | case this.gl.VERTEX_SHADER: 383 | shader = this.gl.createShader(this.gl.VERTEX_SHADER); 384 | break; 385 | case this.gl.FRAGMENT_SHADER: 386 | shader = this.gl.createShader(this.gl.FRAGMENT_SHADER); 387 | break; 388 | default : 389 | return; 390 | } 391 | this.gl.shaderSource(shader, source); 392 | this.gl.compileShader(shader); 393 | if(this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)){ 394 | return shader; 395 | }else{ 396 | msg = this.gl.getShaderInfoLog(shader); 397 | // directly print to console 398 | logger.error(msg); 399 | console.warn('compile failed of shader: ' + msg); 400 | return null; 401 | } 402 | }; 403 | 404 | // create program 405 | glw._create_program = function(vs, fs){ 406 | 407 | if(vs == null || fs == null) 408 | { 409 | return null; 410 | } 411 | 412 | var program = this.gl.createProgram(); 413 | this.gl.attachShader(program, vs); 414 | this.gl.attachShader(program, fs); 415 | this.gl.linkProgram(program); 416 | if(this.gl.getProgramParameter(program, this.gl.LINK_STATUS)){ 417 | this.gl.useProgram(program); 418 | return program; 419 | }else{ 420 | var msg = this.gl.getProgramInfoLog(program); 421 | logger.error(msg); 422 | console.warn('link program failed: ' + msg); 423 | return null; 424 | } 425 | }; 426 | 427 | // use program 428 | glw._use_program = function(prg){ 429 | this.gl.useProgram(prg); 430 | this.curr_program = prg; 431 | }; 432 | 433 | 434 | // gen & bind vbo data 435 | // TODO: managed later 436 | glw._create_vbo = function(data){ 437 | if(data == null){return;} 438 | var vbo = this.gl.createBuffer(); 439 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vbo); 440 | this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(data), this.gl.STATIC_DRAW); 441 | this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null); 442 | return vbo; 443 | }; 444 | 445 | // gen & bind ibo data 446 | // TODO: managed later 447 | glw._create_ibo = function(data){ 448 | 449 | if(data == null){return;} 450 | 451 | var ibo = this.gl.createBuffer(); 452 | 453 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, ibo); 454 | this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Int16Array(data), this.gl.STATIC_DRAW); 455 | this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null); 456 | 457 | return ibo; 458 | }; 459 | 460 | // gen & bind texture 461 | glw._create_procedural_texture = function(width, height, data){ 462 | 463 | let gl = this.gl; 464 | let fTexture = gl.createTexture(); 465 | 466 | gl.bindTexture(gl.TEXTURE_2D, fTexture); 467 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); 468 | 469 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 470 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 471 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 472 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 473 | 474 | return fTexture; 475 | }; 476 | 477 | 478 | glw._create_bind_texture = function(data){ 479 | 480 | let gl = this.gl; 481 | let buffer = gl.createTexture(); 482 | 483 | gl.bindTexture(gl.TEXTURE_2D, buffer); 484 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data); 485 | 486 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 487 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 488 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); 489 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); 490 | gl.bindTexture(gl.TEXTURE_2D, null); 491 | 492 | return buffer; 493 | }; 494 | 495 | // fbo 496 | glw._create_framebuffer = function(width, height){ 497 | 498 | // check & prepare 499 | if(width == null || height == null){return;} 500 | var gl = this.gl; 501 | 502 | // create fbo 503 | var frameBuffer = gl.createFramebuffer(); 504 | gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); 505 | 506 | let depthComponent = null; 507 | 508 | if(glw.glext_depth_texture) 509 | { 510 | //console.info("bind depth texture"); 511 | var fTexture = gl.createTexture(); 512 | gl.bindTexture(gl.TEXTURE_2D, fTexture); 513 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, width, height, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null); 514 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 515 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 516 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 517 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 518 | gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, fTexture, 0); 519 | 520 | depthComponent = fTexture; 521 | } 522 | else 523 | { 524 | // depth by renderbuffer, compitable with all 525 | var depthRenderBuffer = gl.createRenderbuffer(); 526 | gl.bindRenderbuffer(gl.RENDERBUFFER, depthRenderBuffer); 527 | gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height); 528 | gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRenderBuffer); 529 | 530 | depthComponent = depthRenderBuffer; 531 | } 532 | 533 | 534 | 535 | 536 | 537 | // color by render textrue 538 | var fTexture = gl.createTexture(); 539 | gl.bindTexture(gl.TEXTURE_2D, fTexture); 540 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 541 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 542 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 543 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 544 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 545 | gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fTexture, 0); 546 | 547 | // clear state 548 | gl.bindTexture(gl.TEXTURE_2D, null); 549 | gl.bindRenderbuffer(gl.RENDERBUFFER, null); 550 | gl.bindFramebuffer(gl.FRAMEBUFFER, null); 551 | 552 | return {framebuffer: frameBuffer, depthRenderbuffer: depthComponent, rendertexture: fTexture}; 553 | }; 554 | 555 | // dp 556 | glw._draw_arrays = function(primitive, vertexCount){ 557 | this.gl.drawArrays(primitive, 0, vertexCount); 558 | }; 559 | 560 | // dip 561 | glw._draw_elements = function(primitive, indexLength){ 562 | this.gl.drawElements(primitive, indexLength, this.gl.UNSIGNED_SHORT, 0); 563 | }; 564 | -------------------------------------------------------------------------------- /lib/gk-logger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/11/11. 3 | */ 4 | class logger { 5 | 6 | static get LOGTYPE_INFO() { 7 | return 0; 8 | } 9 | static get LOGTYPE_WARN() { 10 | return 1; 11 | } 12 | static get LOGTYPE_ERRO() { 13 | return 2; 14 | } 15 | 16 | static init(console) { 17 | logger.console = console; 18 | logger.logcache = new Array(); 19 | }; 20 | 21 | static info(logstr) { 22 | logger.logcache.unshift([logger.LOGTYPE_INFO, logstr]); 23 | logger.refreshLog(); 24 | }; 25 | 26 | static warn(logstr) { 27 | logger.logcache.unshift([logger.LOGTYPE_WARN, logstr]); 28 | logger.refreshLog(); 29 | }; 30 | 31 | static error(logstr) { 32 | logger.logcache.unshift([logger.LOGTYPE_ERRO, logstr]); 33 | logger.refreshLog(); 34 | }; 35 | 36 | static refreshLog() { 37 | while (logger.console.firstChild) { 38 | logger.console.removeChild(logger.console.firstChild); 39 | } 40 | 41 | if (logger.logcache.length > 50) { 42 | var deleteCount = logger.logcache.length - 50; 43 | logger.logcache.splice(50, deleteCount); 44 | } 45 | 46 | var count = 0; 47 | logger.logcache.forEach(function (line) { 48 | var log_line = document.createElement('div'); 49 | if (count++ % 2 === 0) { 50 | log_line.className = 'log-line-s'; 51 | } 52 | else { 53 | log_line.className = 'log-line-d'; 54 | } 55 | 56 | var infotype = line[0]; 57 | var log_icon = document.createElement('i'); 58 | 59 | switch (infotype) { 60 | case logger.LOGTYPE_INFO: 61 | log_icon.className = 'btm bt-info-circle'; 62 | log_line.style.color = '#fff'; 63 | break; 64 | case logger.LOGTYPE_WARN: 65 | log_icon.className = 'bts bt-exclamation-triangle'; 66 | log_line.style.color = '#ff3'; 67 | break; 68 | case logger.LOGTYPE_ERRO: 69 | log_icon.className = 'bts bt-ban'; 70 | log_line.style.color = '#f33'; 71 | break; 72 | } 73 | 74 | log_line.appendChild(log_icon); 75 | 76 | var log_text = document.createTextNode(' ' + line[1]); 77 | log_line.appendChild(log_text); 78 | 79 | logger.console.appendChild(log_line); 80 | }); 81 | 82 | }; 83 | } 84 | 85 | module.exports = logger; 86 | 87 | -------------------------------------------------------------------------------- /lib/gk-mouseorbit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 12/11/2016. 3 | */ 4 | 'use strict' 5 | var mouseorbit = mouseorbit || {}; 6 | 7 | module.exports = mouseorbit; 8 | 9 | mouseorbit.HOLDLEFT = 1; 10 | mouseorbit.HOLDMIDDLE = 2; 11 | mouseorbit.HOLDRIGHT = 3; 12 | mouseorbit.HOLDFREE = 0; 13 | 14 | mouseorbit.frame = null; 15 | mouseorbit.startPT = null; 16 | mouseorbit.movePT = null; 17 | mouseorbit.delta = { x: 0, y: 0}; 18 | 19 | mouseorbit.deltaLast = { x: 0, y: 0, z: 0}; 20 | 21 | mouseorbit.wheelStatus = 0; 22 | mouseorbit._wheelStatus = 0; 23 | 24 | mouseorbit.moveType = 0; 25 | 26 | mouseorbit.frameUpdate = function() 27 | { 28 | let relativeDelta = { x: mouseorbit.delta.x - mouseorbit.deltaLast.x, y : mouseorbit.delta.y - mouseorbit.deltaLast.y, z: mouseorbit.wheelStatus }; 29 | mouseorbit.deltaLast = mouseorbit.delta; 30 | mouseorbit.wheelStatus = 0; 31 | return relativeDelta; 32 | } 33 | 34 | mouseorbit.updateDelta = function() 35 | { 36 | mouseorbit.delta = { x: mouseorbit.movePT.x - mouseorbit.startPT.x, y: mouseorbit.movePT.y - mouseorbit.startPT.y}; 37 | } 38 | 39 | mouseorbit.onMouseDown = function( event ) 40 | { 41 | event.preventDefault(); 42 | 43 | mouseorbit.startPT = { x: event.clientX, y: event.clientY}; 44 | 45 | if ('which' in event) { 46 | switch (event.which) { 47 | case 1: 48 | mouseorbit.moveType = mouseorbit.HOLDLEFT; 49 | break; 50 | case 2: 51 | mouseorbit.moveType = mouseorbit.HOLDMIDDLE; 52 | break; 53 | case 3: 54 | mouseorbit.moveType = mouseorbit.HOLDRIGHT; 55 | break; 56 | } 57 | } 58 | 59 | mouseorbit.frame.addEventListener( 'mousemove', mouseorbit.onMouseMove, false ); 60 | mouseorbit.frame.addEventListener( 'mouseup', mouseorbit.onMouseUp, false ); 61 | 62 | mouseorbit.delta = { x: 0, y: 0}; 63 | mouseorbit.deltaLast = { x: 0, y: 0}; 64 | } 65 | 66 | mouseorbit.onMouseMove = function( event ) 67 | { 68 | mouseorbit.frame.style.setProperty( 'cursor', 'move' ); 69 | 70 | event.preventDefault(); 71 | 72 | mouseorbit.movePT = { x: event.clientX, y: event.clientY}; 73 | 74 | mouseorbit.updateDelta(); 75 | } 76 | 77 | mouseorbit.onMouseUp = function( event ) 78 | { 79 | mouseorbit.frame.style.setProperty( 'cursor', 'pointer' ); 80 | 81 | mouseorbit.moveType = mouseorbit.HOLDFREE; 82 | 83 | mouseorbit.frame.removeEventListener( 'mousemove', mouseorbit.onMouseMove, false); 84 | mouseorbit.frame.removeEventListener( 'mouseup', mouseorbit.onMouseUp, false); 85 | } 86 | 87 | mouseorbit.onMouseWheel = function( event ) { 88 | 89 | var value = event.wheelDelta || -event.detail; 90 | var delta = Math.max(-1, Math.min(1, value)); 91 | mouseorbit.wheelStatus = delta; 92 | } 93 | 94 | mouseorbit.init = function( frame ) 95 | { 96 | mouseorbit.frame = frame; 97 | mouseorbit.frame.addEventListener( 'mousedown', mouseorbit.onMouseDown, false ); 98 | mouseorbit.frame.addEventListener( 'mousewheel', mouseorbit.onMouseWheel, false ); 99 | } -------------------------------------------------------------------------------- /lib/gk-renderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/1. 3 | */ 4 | const glw = require("./gk-glwrap"); 5 | const fixedshader = require("./gk-fixedshader"); 6 | const resMgr = require("./gk-resmgr"); 7 | const math = require("gl-matrix"); 8 | const gTimer = require("./gk-timer"); 9 | const mouse = require("./gk-mouseorbit"); 10 | 11 | 12 | const GameObject = require("./gk-gameobject.js"); 13 | const Component = require("./gk-component.js"); 14 | 15 | class RenderQueue { 16 | constructor( _depth ) { 17 | this.depth = _depth; 18 | this.meshRenderers = []; 19 | 20 | // per queue uniform unit: { KEY: "_MVP", VALUE: mat4 / vec4 / etc } 21 | this.uniformPerQueue = new Map(); 22 | 23 | this.camera = null; 24 | this.light = null; 25 | } 26 | 27 | setupCamera( cam ) { 28 | 29 | this.camera = cam; 30 | 31 | } 32 | 33 | setupLight( light ) { 34 | 35 | this.light = light; 36 | } 37 | 38 | clear() { 39 | this.meshRenderers = []; 40 | } 41 | 42 | addRenderer( mr ) { 43 | this.meshRenderers.push(mr); 44 | } 45 | 46 | sort() { 47 | // sort by material 48 | } 49 | 50 | prepare( rendererInst ) 51 | { 52 | // prepare cam 53 | { 54 | let camts = this.camera.host.transform; 55 | 56 | let cameraPosition = camts.position; 57 | let cameraUpDirection = camts.up; 58 | let cameraForwardDirection = math.vec3.negate(math.vec3.create(), camts.forward); 59 | let centerPoint = math.vec3.add( math.vec3.create(), cameraPosition, cameraForwardDirection ); 60 | 61 | let aspect = rendererInst.currentRenderTarget.width / rendererInst.currentRenderTarget.height; 62 | 63 | let projMatrix = math.mat4.perspective(math.mat4.create(), 45, aspect, 0.5, 5000.0); 64 | let viewMatrix = math.mat4.lookAt(math.mat4.create(), cameraPosition, centerPoint, cameraUpDirection); 65 | let vpMatrix = math.mat4.multiply(math.mat4.create(), projMatrix, viewMatrix); 66 | 67 | this.uniformPerQueue.set("_PROJ", projMatrix ); 68 | this.uniformPerQueue.set("_VIEW", viewMatrix ); 69 | this.uniformPerQueue.set("_VIEWPROJ", vpMatrix ); 70 | } 71 | 72 | // prepare light 73 | { 74 | let lightDir = this.light.host.transform.forward; 75 | this.uniformPerQueue.set("_LIGHTDIR", lightDir); 76 | 77 | let camts = this.light.host.transform; 78 | 79 | let cameraPosition = camts.position; 80 | let cameraUpDirection = camts.up; 81 | let cameraForwardDirection = math.vec3.negate(math.vec3.create(), camts.forward); 82 | let centerPoint = math.vec3.add( math.vec3.create(), cameraPosition, cameraForwardDirection ); 83 | 84 | let projMatrix = math.mat4.ortho(math.mat4.create(), -150, 150, -150, 150, 500, 3000); 85 | let viewMatrix = math.mat4.lookAt(math.mat4.create(), cameraPosition, centerPoint, cameraUpDirection); 86 | let vpMatrix = math.mat4.multiply(math.mat4.create(), projMatrix, viewMatrix); 87 | 88 | this.uniformPerQueue.set("_LIGHTPROJ", projMatrix ); 89 | this.uniformPerQueue.set("_LIGHTVIEW", viewMatrix ); 90 | this.uniformPerQueue.set("_LIGHTVIEWPROJ", vpMatrix ); 91 | 92 | let vMatrixOfCam = this.uniformPerQueue.get("_VIEW"); 93 | let cam2lightMtx = math.mat4.invert(math.mat4.create(), vMatrixOfCam); 94 | 95 | math.mat4.multiply(cam2lightMtx, vpMatrix, cam2lightMtx); 96 | 97 | this.uniformPerQueue.set("_CAM2LIGHTVIEWPROJ", cam2lightMtx ); 98 | } 99 | 100 | } 101 | 102 | // func: param0 - renderer 103 | traverse( func, additionParam ) { 104 | 105 | for( let i=0, len = this.meshRenderers.length; i < len; ++i) 106 | { 107 | func( this.meshRenderers[i], this, additionParam ); 108 | } 109 | } 110 | } 111 | 112 | // singleton 113 | let instance = null; 114 | 115 | class Renderer { 116 | constructor() { 117 | if(!instance){ 118 | instance = this; 119 | 120 | this.bgMesh = null; 121 | this.bgProgram = null; 122 | this.noiseProgram = null; 123 | this.shadowmapProgram = null; 124 | this.zpassProgram = null; 125 | 126 | this.ssaoProgram = null; 127 | 128 | this.simBackBuffer = null; 129 | this.shadowMapBuffer = null; 130 | this.zpassFrameBuffer = null; 131 | 132 | this.overrideProgram = null; 133 | 134 | this.renderQueues = new Map(); 135 | 136 | this.currentRenderTarget = null; 137 | } 138 | 139 | return instance; 140 | } 141 | 142 | init() { 143 | 144 | // initialize quad 145 | const quadPosition = [ 146 | -1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 147 | 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 148 | -1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 149 | 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 150 | ]; 151 | const quadIndex = [ 152 | 0, 1, 2, 2, 1, 3 153 | ]; 154 | let res = null; 155 | let ibo = {}; 156 | ibo.trilist = quadIndex; 157 | res = {vbo: quadPosition, ibo: ibo }; 158 | this.bgMesh = glw.createMeshObject(res, [glw.VERTEX_LAYOUT_P, glw.VERTEX_LAYOUT_T0, glw.VERTEX_LAYOUT_N]); 159 | 160 | // initialize shader 161 | this.bgProgram = glw.createProgramObject(fixedshader.quadvsp, fixedshader.quadfsp); 162 | this.noiseProgram = glw.createProgramObject(fixedshader.quadvsp, fixedshader.noisefsp); 163 | 164 | if( glw.glext_depth_texture ) 165 | { 166 | this.shadowmapProgram = glw.createProgramObject(fixedshader.simpleshadowvsp, fixedshader.simpleshadowfsp); 167 | } 168 | else 169 | { 170 | this.shadowmapProgram = glw.createProgramObject(fixedshader.shadowvsp, fixedshader.shadowfsp); 171 | } 172 | 173 | this.zpassProgram = glw.createProgramObject(fixedshader.simplezpassvsp, fixedshader.simplezpassfsp); 174 | 175 | this.ssaoProgram = glw.createProgramObject(fixedshader.ssaovsp, fixedshader.ssaofsp); 176 | 177 | // initialize render texture 178 | this.shadowMapBuffer = resMgr.gResmgr.create_render_texture(1024,1024); 179 | this.shadowMapBuffer.load(); 180 | 181 | this.resize(1024, 1024); 182 | 183 | } 184 | 185 | resize( width, height ) 186 | { 187 | this.simBackBuffer = resMgr.gResmgr.create_render_texture(width * 2, height * 2); 188 | this.simBackBuffer.load(); 189 | 190 | this.zpassFrameBuffer = resMgr.gResmgr.create_render_texture(width * 2, height * 2); 191 | this.zpassFrameBuffer.load(); 192 | 193 | this.occlusionFrameBuffer = resMgr.gResmgr.create_render_texture(width * 2, height * 2); 194 | this.occlusionFrameBuffer.load(); 195 | } 196 | 197 | pushRenderTarget( renderTexture ) 198 | { 199 | this.currentRenderTarget = renderTexture; 200 | glw.gl.bindFramebuffer(glw.gl.FRAMEBUFFER, renderTexture.fbo); 201 | glw.viewport(0, 0,renderTexture.width, renderTexture.height); 202 | } 203 | 204 | popRenderTarget() 205 | { 206 | 207 | } 208 | 209 | render() { 210 | 211 | // render queue sorting 212 | for (let queue of this.renderQueues.values()) { 213 | queue.sort(); 214 | } 215 | 216 | /////////////////// 217 | // shadow map gen 218 | this.pushRenderTarget(this.shadowMapBuffer); 219 | // clear with a grey color 220 | glw.clear([1, 1, 1, 1], 1.0); 221 | 222 | // set z enable 223 | glw.gl.enable(glw.gl.DEPTH_TEST); 224 | glw.gl.depthFunc(glw.gl.LEQUAL); 225 | glw.gl.disable(glw.gl.CULL_FACE); 226 | 227 | this.shadowmapProgram.use(); 228 | 229 | for (let queue of this.renderQueues.values()) { 230 | queue.traverse( this.renderSingleRendererShadowmp ); 231 | } 232 | 233 | 234 | /////////////////// 235 | // zpass 236 | this.pushRenderTarget(this.zpassFrameBuffer); 237 | // clear with a normal color 238 | glw.clear([0.5, 0.5, 1.0, 1.0], 1.0); 239 | 240 | // set z enable 241 | glw.gl.enable(glw.gl.DEPTH_TEST); 242 | glw.gl.depthFunc(glw.gl.LEQUAL); 243 | glw.gl.disable(glw.gl.CULL_FACE); 244 | 245 | // for every render queue 246 | if(this.zpassProgram != null) 247 | { 248 | this.zpassProgram.use(); 249 | } 250 | 251 | for (let queue of this.renderQueues.values()) { 252 | 253 | queue.prepare( this ); 254 | // setup queue basic parameter 255 | queue.traverse( this.renderSingleRenderer ); 256 | } 257 | 258 | /////////////////// 259 | // occlusion pass 260 | 261 | // ssao 262 | this.pushRenderTarget(this.occlusionFrameBuffer); 263 | // clear with white color 264 | glw.clear([1.0, 1.0, 1.0, 1.0], 1.0); 265 | if(this.ssaoProgram != null) { 266 | this.ssaoProgram.use(); 267 | glw.bind_texture( this.zpassFrameBuffer.gltextureobject, 5 ); 268 | glw.bind_texture( this.zpassFrameBuffer.depth, 6 ); 269 | } 270 | this.bgMesh.draw(); 271 | 272 | /////////////////// 273 | // general shading pass 274 | 275 | // bind general draw ssaa fbo 276 | this.pushRenderTarget(this.simBackBuffer); 277 | // clear with a grey color 278 | glw.clear([0.15, 0.15, 0.15, 1.0], 1.0); 279 | 280 | // set z enable 281 | glw.gl.enable(glw.gl.DEPTH_TEST); 282 | glw.gl.depthFunc(glw.gl.LEQUAL); 283 | glw.gl.disable(glw.gl.CULL_FACE); 284 | 285 | // render the noising background 286 | this.noiseProgram.use(); 287 | glw.set_uniform1f("_TIME", gTimer.runTime * 0.001); 288 | this.bgMesh.draw(); 289 | 290 | // main render process 291 | 292 | // for every render queue 293 | if(this.overrideProgram != null) 294 | { 295 | this.overrideProgram.use(); 296 | } 297 | 298 | for (let queue of this.renderQueues.values()) { 299 | 300 | queue.prepare( this ); 301 | // setup queue basic parameter 302 | queue.traverse( this.renderSingleRenderer ); 303 | } 304 | 305 | // bind backbuffer, resolve ssaa 306 | glw.gl.bindFramebuffer(glw.gl.FRAMEBUFFER, null ); 307 | 308 | // clear with a grey color 309 | glw.clear([0.15, 0.15, 0.15, 1.0], 1.0); 310 | glw.viewport(0, 0, glw.canvas.width, glw.canvas.height); 311 | 312 | this.bgProgram.use(); 313 | glw.set_uniform1f("_TIME", gTimer.runTime * 0.001); 314 | 315 | // bind the draw buffer 316 | glw.bind_texture( this.simBackBuffer.gltextureobject, 0 ); 317 | 318 | // bind the zpass buffer 319 | //glw.bind_texture( this.occlusionFrameBuffer.gltextureobject, 0); 320 | 321 | this.bgMesh.draw(); 322 | 323 | 324 | 325 | 326 | // render queue clear 327 | for (let queue of this.renderQueues.values()) { 328 | queue.clear(); 329 | } 330 | } 331 | 332 | destroy() { 333 | 334 | } 335 | 336 | getOrCreateRenderQueue( depth ) { 337 | if( !this.renderQueues.has( depth ) ) 338 | { 339 | this.renderQueues.set( depth, new RenderQueue( depth )); 340 | } 341 | 342 | return this.renderQueues.get( depth ); 343 | } 344 | 345 | renderSingleRendererShadowmp( renderer, queue ) { 346 | if( renderer instanceof Component.MeshRenderer ) 347 | { 348 | // grab matrix 349 | let vpMatrix = queue.uniformPerQueue.get("_LIGHTVIEWPROJ"); 350 | 351 | //renderer.host.transform._localToWorldMatrx; 352 | let mMatrix = renderer.host.transform.localToWorldMatrix; 353 | 354 | // set material 355 | let mat = renderer.material; 356 | 357 | glw.bind_texture( mat.mainTex.gltextureobject, 0 ); 358 | glw.bind_texture( mat.opacityMapTex.gltextureobject, 1 ); 359 | 360 | glw.set_uniform4x4fv("_MVP", math.mat4.mul(math.mat4.create(), vpMatrix, mMatrix)); 361 | glw.set_uniform4x4fv("_M2W", mMatrix); 362 | 363 | // extract meshfilter 364 | let mf = renderer.host.components.get(Component.MeshFilter); 365 | 366 | // render 367 | if( mf.mesh !== null ) { 368 | //console.info(mf.mesh); 369 | mf.mesh.draw(); 370 | } 371 | } 372 | } 373 | 374 | renderSingleRenderer( renderer, queue ) { 375 | if( renderer instanceof Component.MeshRenderer ) 376 | { 377 | // grab matrix 378 | let vpMatrix = queue.uniformPerQueue.get("_VIEWPROJ"); 379 | let vMatrix = queue.uniformPerQueue.get("_VIEW"); 380 | let vpMatrix_Light = queue.uniformPerQueue.get("_CAM2LIGHTVIEWPROJ"); 381 | 382 | //renderer.host.transform._localToWorldMatrx; 383 | let mMatrix = renderer.host.transform.localToWorldMatrix; 384 | 385 | // set material 386 | let mat = renderer.material; 387 | 388 | let lightDir = queue.uniformPerQueue.get("_LIGHTDIR"); 389 | if(lightDir) 390 | { 391 | lightDir[3] = 0; 392 | glw.set_uniform4f("_LIGHTDIR", lightDir); 393 | } 394 | 395 | glw.bind_texture( mat.mainTex.gltextureobject, 0 ); 396 | glw.bind_texture( mat.opacityMapTex.gltextureobject, 1 ); 397 | 398 | glw.bind_texture( instance.zpassFrameBuffer.gltextureobject, 5 ); 399 | if(glw.glext_depth_texture) 400 | { 401 | glw.bind_texture( instance.zpassFrameBuffer.depth, 6 ); 402 | } 403 | else 404 | { 405 | //glw.bind_texture( instance.shadowMapBuffer.gltextureobject, 6 ); 406 | } 407 | 408 | if(glw.glext_depth_texture) 409 | { 410 | glw.bind_texture( instance.shadowMapBuffer.depth, 7 ); 411 | } 412 | else 413 | { 414 | glw.bind_texture( instance.shadowMapBuffer.gltextureobject, 7 ); 415 | } 416 | 417 | glw.set_uniform4x4fv("_MVP", math.mat4.mul(math.mat4.create(), vpMatrix, mMatrix)); 418 | glw.set_uniform4x4fv("_MV", math.mat4.mul(math.mat4.create(), vMatrix, mMatrix)); 419 | glw.set_uniform4x4fv("_M2W", mMatrix); 420 | 421 | glw.set_uniform4x4fv("_MVP_LIGHT",vpMatrix_Light); 422 | 423 | // extract meshfilter 424 | let mf = renderer.host.components.get(Component.MeshFilter); 425 | 426 | // render 427 | if( mf.mesh !== null ) { 428 | //console.info(mf.mesh); 429 | mf.mesh.draw(); 430 | } 431 | } 432 | } 433 | } 434 | 435 | module.exports = Renderer; -------------------------------------------------------------------------------- /lib/gk-resmgr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 14/11/2016. 3 | */ 4 | const logger = require('./gk-logger.js'); 5 | const path = require('path'); 6 | const loader_fbx = require('./loader/loader-fbx.js'); 7 | const loader_osgjs = require('./loader/loader-osgjs.js'); 8 | const glw = require('./gk-glwrap.js'); 9 | const Fabricate = require('./fabricate'); 10 | const GameObject = require('./gk-gameobject'); 11 | const Component = require('./gk-component'); 12 | const math = require('gl-matrix'); 13 | 14 | // type define 15 | var RESTYPE = RESTYPE || {}; 16 | RESTYPE.INVALID = 0; 17 | RESTYPE.MESH = 1; 18 | RESTYPE.TEXTURE = 2; 19 | RESTYPE.TEXT = 3; 20 | RESTYPE.MATERIAL = 4; 21 | 22 | // base class obj 23 | class BaseResObj { 24 | constructor(token) { 25 | this.filetoken = token; 26 | this.loaded = false; 27 | this.type = RESTYPE.INVALID; 28 | this.dynamic = false; 29 | } 30 | 31 | get_type() { 32 | return this.type; 33 | } 34 | 35 | load(callback) { 36 | if( !this.loaded ) 37 | { 38 | this.loadimpl(callback); 39 | } 40 | this.loaded = true; 41 | } 42 | 43 | unload() { 44 | if(this.loaded) 45 | { 46 | this.unloadimpl(); 47 | } 48 | this.loaded = false; 49 | } 50 | } 51 | 52 | class MaterialResObj extends BaseResObj { 53 | 54 | } 55 | 56 | class MeshResObj extends BaseResObj { 57 | constructor(token) { 58 | super(token); 59 | this.type = RESTYPE.MESH; 60 | this.glmeshobject = null; 61 | this.gameObject = null; 62 | } 63 | 64 | loadimpl(callback) { 65 | // load fbx tmp 66 | let ref = this; 67 | 68 | let timestamp = Date.now(); 69 | 70 | 71 | let ext = getFileExtension(this.filetoken); 72 | this.gameObject = Fabricate(GameObject.Base); 73 | 74 | switch (ext) 75 | { 76 | case 'fbx': 77 | 78 | loader_fbx.load( gResmgr, this.filetoken, function(res) { 79 | res.transform.parent = ref.gameObject.transform; 80 | let timeelapsed = Date.now() - timestamp; 81 | logger.info('Mesh ' + ref.filetoken + ' loaded in ' + timeelapsed + 'ms.'); 82 | } ); 83 | 84 | break; 85 | case 'osgjs': 86 | 87 | loader_osgjs.load( gResmgr, this.filetoken, function(res) { 88 | res.transform.parent = ref.gameObject.transform; 89 | let timeelapsed = Date.now() - timestamp; 90 | logger.info('Mesh ' + ref.filetoken + ' loaded in ' + timeelapsed + 'ms.'); 91 | 92 | if(callback) { 93 | callback(); 94 | } 95 | } ); 96 | 97 | break; 98 | } 99 | 100 | 101 | } 102 | 103 | unloadimpl() { 104 | // release 105 | } 106 | } 107 | 108 | class TextureResObj extends BaseResObj { 109 | constructor(token) { 110 | super(token); 111 | this.type = RESTYPE.TEXTURE; 112 | this.gltextureobject = null; 113 | this.width = 0; 114 | this.height = 0; 115 | } 116 | 117 | loadimpl(callback) { 118 | 119 | let ref = this; 120 | 121 | let img = new Image(); 122 | this.image = img; 123 | let timestamp = Date.now(); 124 | 125 | img.onload = function () { 126 | ref.gltextureobject = glw._create_bind_texture(img); 127 | let timeelapsed = Date.now() - timestamp; 128 | logger.info('Texture ' + ref.filetoken + ' loaded in ' + timeelapsed + 'ms.'); 129 | 130 | this.width = img.width; 131 | this.height = img.height; 132 | }; 133 | 134 | // trigger loading 135 | img.src = this.filetoken; 136 | } 137 | 138 | unloadimpl() { 139 | // TODO 140 | } 141 | } 142 | 143 | class RenderTextureResObj extends TextureResObj { 144 | constructor(_width, _height) { 145 | 146 | let token = "dyn_" + gResmgr.dynamicTokenId; 147 | gResmgr.dynamicTokenId++; 148 | 149 | super(token); 150 | this.dynamic = true; 151 | this.width = _width; 152 | this.height = _height; 153 | 154 | this.fbo = null; 155 | this.depth = null; 156 | } 157 | 158 | loadimpl(callback) { 159 | let ret = glw._create_framebuffer(this.width, this.height); 160 | if(ret !== null) 161 | { 162 | this.gltextureobject = ret.rendertexture; 163 | this.fbo = ret.framebuffer; 164 | this.depth = ret.depthRenderbuffer; 165 | } 166 | 167 | } 168 | 169 | unloadimpl() { 170 | // TODO 171 | } 172 | } 173 | 174 | class TextResObj extends BaseResObj { 175 | constructor(token) { 176 | super(token); 177 | this.type = RESTYPE.TEXT; 178 | } 179 | 180 | loadimpl(callback) { 181 | 182 | } 183 | 184 | unloadimpl() { 185 | 186 | } 187 | } 188 | 189 | function getFileExtension(filename) { 190 | return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined; 191 | } 192 | 193 | let instance = null; 194 | 195 | class BaseResMgr { 196 | 197 | constructor() { 198 | if(!instance) { 199 | instance = this; 200 | 201 | this.resrefs = new Map(); 202 | this.dynamicTokenId = 0; 203 | } 204 | 205 | return instance; 206 | } 207 | 208 | add_res(token) { 209 | 210 | if (this.resrefs.has(token)) { 211 | logger.error('Duplicate res added: ' + token); 212 | return; 213 | } 214 | 215 | let retRes = this.create_res_type_by_token(token); 216 | if (retRes !== null) { 217 | this.resrefs.set(token, retRes); 218 | } 219 | 220 | return retRes; 221 | } 222 | 223 | get_res(token) { 224 | token = path.normalize(token); 225 | return this.resrefs.get(token); 226 | } 227 | 228 | create_render_texture( _width, _height ) { 229 | let retRes = new RenderTextureResObj(_width, _height); 230 | if (retRes !== null) { 231 | this.resrefs.set(retRes.filetoken, retRes); 232 | } 233 | return retRes; 234 | } 235 | 236 | create_dyn_res_by_type(type) { 237 | switch (type) { 238 | case RESTYPE.MESH: 239 | return new MeshResObj(token); 240 | break; 241 | case RESTYPE.TEXTURE: 242 | return new TextureResObj(token); 243 | break; 244 | } 245 | return null; 246 | } 247 | 248 | create_res_type_by_token(token) { 249 | 250 | let ext = getFileExtension(token); 251 | 252 | if (ext !== undefined) { 253 | ext = ext.toLowerCase(); 254 | switch (ext) { 255 | case 'fbx': 256 | case 'osgjs': 257 | return new MeshResObj(token); 258 | break; 259 | case 'jpg': 260 | case 'jpeg': 261 | case 'png': 262 | return new TextureResObj(token); 263 | break; 264 | case 'glsl': 265 | case 'js': 266 | return new TextResObj(token); 267 | break; 268 | } 269 | } 270 | 271 | return null; 272 | } 273 | } 274 | 275 | const gResmgr = new BaseResMgr(); 276 | 277 | module.exports = {RESTYPE, BaseResMgr, BaseResObj, gResmgr}; -------------------------------------------------------------------------------- /lib/gk-respanel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/15. 3 | */ 4 | const resMgr = require('./gk-resmgr.js'); 5 | const fs = require('fs-extra'); 6 | const path = require('path'); 7 | const logger = require('./gk-logger.js'); 8 | 9 | var respanel = respanel || {}; 10 | 11 | module.exports = respanel; 12 | 13 | 14 | respanel.resFolderStruct = { '_folded' : false, '_name': 'root', '_child' : {} }; 15 | respanel.resContainer = null; 16 | respanel.basedir = null; 17 | respanel.curr_selection = null; 18 | 19 | respanel.init = function(container, basedir) 20 | { 21 | respanel.resContainer = container; 22 | respanel.basedir = basedir; 23 | } 24 | 25 | respanel.rescan_resources = function () { 26 | 27 | let filelist = fs.walkSync(respanel.basedir + '/res/'); 28 | filelist.forEach( item => { 29 | 30 | item = path.normalize(item); 31 | let filename = path.basename( item ); 32 | let dirname = path.dirname(item); 33 | let relpath = path.relative( respanel.basedir, dirname ); 34 | let token = path.normalize( relpath + path.sep + filename ); 35 | 36 | resMgr.gResmgr.add_res(token); 37 | }); 38 | 39 | } 40 | 41 | respanel.reconstruct_filetree = function () { 42 | 43 | // rebuild filetree with root 44 | respanel.resFolderStruct = { '_folded' : false, '_name': 'root', '_child' : {} }; 45 | 46 | // build the folder struct 47 | resMgr.gResmgr.resrefs.forEach( item => { 48 | 49 | let folders = item.filetoken.split(path.sep); 50 | 51 | let currFolderLevel = respanel.resFolderStruct; 52 | 53 | // go check the folder links, choose the last 54 | for( let i=0; i < folders.length; ++i) 55 | { 56 | if( i === folders.length - 1) 57 | { 58 | // leaf 59 | currFolderLevel._child[folders[i]] = item; 60 | break; 61 | } 62 | 63 | if( folders[i] in currFolderLevel._child ) 64 | { 65 | currFolderLevel = currFolderLevel._child[folders[i]]; 66 | } 67 | else 68 | { 69 | currFolderLevel._child[folders[i]] = { '_folded' : true, '_child' : {} }; 70 | currFolderLevel._child[folders[i]]._name = folders[i]; 71 | 72 | currFolderLevel = currFolderLevel._child[folders[i]]; 73 | } 74 | } 75 | }); 76 | 77 | } 78 | 79 | respanel.refresh = function () { 80 | let timestamp = Date.now(); 81 | respanel.clean_folder(respanel.resContainer); 82 | respanel.list_folder(respanel.resFolderStruct, 1); 83 | let timeelapsed = Date.now() - timestamp; 84 | 85 | //logger.info('respanel refresh take ' + timeelapsed + 'ms.'); 86 | } 87 | 88 | //console.info(resFolderStruct); 89 | // dispatch res to resouce 90 | 91 | respanel.create_res_showobj = function(depth, filetoken, type, thumbMode = true) { 92 | 93 | var obj_container = document.createElement('div'); 94 | // indent 95 | obj_container.style.padding = '0px ' + depth + 'px'; 96 | 97 | // create inside button 98 | var obj_button = document.createElement('button'); 99 | obj_button.className = 'obj-line'; 100 | obj_button.id = 'btn-' + filetoken; 101 | 102 | // create icon 103 | var log_icon = null; 104 | 105 | switch (type) { 106 | case resMgr.RESTYPE.MESH: 107 | log_icon = document.createElement('i'); 108 | log_icon.className = 'btm bt-database'; 109 | break; 110 | case resMgr.RESTYPE.TEXTURE: 111 | 112 | // load resmgt 113 | let res = resMgr.gResmgr.get_res(filetoken); 114 | if(res !== null && !res.dynamic) 115 | { 116 | log_icon = document.createElement('img'); 117 | log_icon.src = res.filetoken; 118 | if(thumbMode) 119 | { 120 | log_icon.width = '13'; 121 | log_icon.height = '13'; 122 | } 123 | else 124 | { 125 | log_icon.width = '48'; 126 | log_icon.height = '48'; 127 | } 128 | 129 | } 130 | else 131 | { 132 | log_icon = document.createElement('i'); 133 | log_icon.className = 'bts bt-photo'; 134 | } 135 | break; 136 | default: 137 | log_icon = document.createElement('i'); 138 | log_icon.className = 'btm bt-file'; 139 | break; 140 | } 141 | log_icon.style.color = '#8af'; 142 | 143 | // create name text 144 | var log_text = document.createTextNode(' ' + filetoken.split(path.sep).pop()); 145 | 146 | // compose 147 | obj_button.appendChild(log_icon); 148 | if(thumbMode) 149 | { 150 | obj_button.appendChild(log_text); 151 | } 152 | obj_container.appendChild(obj_button); 153 | 154 | // return 155 | return {obj_container: obj_container, obj_button: obj_button, obj_icon: log_icon}; 156 | } 157 | 158 | respanel.list_folder = function (folderStruct, depth) { 159 | 160 | for (let element in folderStruct._child) { 161 | 162 | let folder = folderStruct._child[element]; 163 | if(folder === undefined) 164 | { 165 | break; 166 | } 167 | 168 | 169 | 170 | if (folder instanceof resMgr.BaseResObj) 171 | { 172 | // create obj button 173 | let filetoken = folder.filetoken; 174 | let type = folder.get_type(); 175 | let __ret = respanel.create_res_showobj(depth, filetoken, type); 176 | let obj_container = __ret.obj_container; 177 | let obj_button = __ret.obj_button; 178 | let obj_icon = __ret.obj_icon; 179 | 180 | if(folder.loaded) 181 | { 182 | obj_icon.style.color = '#7f7'; 183 | } 184 | 185 | // selection status 186 | if (respanel.curr_selection === folder) { 187 | obj_button.className = 'obj-line-checked'; 188 | } 189 | 190 | // click selection change 191 | obj_button.onclick = function () { 192 | respanel.curr_selection = folder; 193 | respanel.refresh(); 194 | } 195 | 196 | // drag status 197 | obj_button.draggable = true; 198 | obj_button.ondragstart = function (ev) { 199 | ev.dataTransfer.setData("restoken", filetoken); 200 | } 201 | 202 | // db click 203 | obj_button.ondblclick = function () { 204 | //window.parent.renderer.updateMesh(folder.filetoken); 205 | } 206 | 207 | // append 208 | respanel.resContainer.appendChild(obj_container); 209 | } 210 | else 211 | { 212 | var obj_container = document.createElement('div'); 213 | obj_container.style.padding = '0px ' + depth + 'px'; 214 | 215 | var obj_button = document.createElement('button'); 216 | obj_button.id = 'folder-' + folder._name; 217 | obj_button.className = 'obj-line'; 218 | 219 | obj_button.onclick = function () { 220 | folder._folded = !folder._folded; 221 | respanel.refresh(); 222 | } 223 | 224 | var log_icon = document.createElement('i'); 225 | if (folder._folded) { 226 | log_icon.className = 'bts bt-folder'; 227 | } else { 228 | log_icon.className = 'btm bt-folder'; 229 | } 230 | log_icon.style.color = '#8af'; 231 | var log_text = document.createTextNode(' ' + folder._name); 232 | 233 | // compose 234 | obj_button.appendChild(log_icon); 235 | obj_button.appendChild(log_text); 236 | obj_container.appendChild(obj_button); 237 | 238 | respanel.resContainer.appendChild(obj_container); 239 | 240 | if (folder._folded) { 241 | 242 | } 243 | else 244 | { 245 | //console.info(folder); 246 | respanel.list_folder(folder, depth + 10); 247 | } 248 | } 249 | 250 | 251 | //var log_icon = document.createElement('i'); 252 | 253 | } 254 | ; 255 | } 256 | 257 | respanel.clean_folder = function(resContainer) { 258 | while (resContainer.firstChild) { 259 | resContainer.removeChild(resContainer.firstChild); 260 | } 261 | } 262 | 263 | 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /lib/gk-scenemgr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/12/1. 3 | */ 4 | const Fabricate = require("./fabricate.js"); 5 | const GameObject = require("./gk-gameobject.js"); 6 | const Component = require("./gk-component.js"); 7 | 8 | let instance = null; 9 | 10 | class SceneMgr { 11 | constructor() { 12 | if(!instance) { 13 | instance = this; 14 | 15 | this.root = null; 16 | this.meshRenderers = []; 17 | } 18 | 19 | return instance; 20 | } 21 | 22 | init() { 23 | this.root = Fabricate(GameObject.Base); 24 | } 25 | 26 | update() { 27 | 28 | // update 29 | this.traverseNode( this.root, this.updateComonents ); 30 | 31 | // collect mr 32 | this.meshRenderers = []; 33 | this.traverseNode( this.root, this.collectRenderer ); 34 | 35 | // onRender -> Camera Component 36 | this.traverseNode( this.root, this.renderComonents ); 37 | } 38 | 39 | getSceneRoot() { 40 | return this.root; 41 | } 42 | 43 | getMeshRenderers() { 44 | return this.meshRenderers; 45 | } 46 | 47 | traverseNode(node, nodeProcess ) { 48 | 49 | nodeProcess( node ); 50 | 51 | let transform = node.components.get(Component.Transform); 52 | if( transform ) 53 | { 54 | let refthis = this; 55 | transform.children.forEach( child => { 56 | refthis.traverseNode( child.host, nodeProcess ); 57 | }); 58 | } 59 | } 60 | 61 | updateComonents( node ) { 62 | if( node.components ) 63 | { 64 | for (let comp of node.components.values()) { 65 | if( comp instanceof Component.Component ) 66 | { 67 | comp.onUpdate(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | renderComonents( node ) { 74 | if( node.components ) 75 | { 76 | for (let comp of node.components.values()) { 77 | if( comp instanceof Component.Component ) 78 | { 79 | comp.onRender(); 80 | } 81 | } 82 | } 83 | } 84 | 85 | collectRenderer( node ) { 86 | if( node.components ) 87 | { 88 | let mr = node.components.get(Component.MeshRenderer); 89 | 90 | if( mr !== undefined ) 91 | { 92 | instance.meshRenderers.push(mr); 93 | } 94 | } 95 | } 96 | 97 | 98 | } 99 | 100 | module.exports = SceneMgr; -------------------------------------------------------------------------------- /lib/gk-timer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/12/1. 3 | */ 4 | class GKTimer { 5 | constructor() { 6 | this.startUpTimer = 0.0; 7 | this.runTime = 0.0; 8 | this.lastFrameTime = 0.0; 9 | this.deltaTime = 0.0; 10 | } 11 | 12 | init() { 13 | this.startUpTimer = Date.now(); 14 | this.lastFrameTime = this.startUpTimer; 15 | } 16 | 17 | update() { 18 | this.runTime = Date.now() - this.startUpTimer; 19 | this.deltaTime = this.runTime - this.lastFrameTime; 20 | this.lastFrameTime = this.runTime; 21 | } 22 | } 23 | 24 | const gTimer = new GKTimer(); 25 | 26 | module.exports = gTimer; -------------------------------------------------------------------------------- /lib/util/gl-matrix-extension.js: -------------------------------------------------------------------------------- 1 | const math = require('gl-matrix'); 2 | 3 | var aabb = {}; 4 | 5 | aabb.create = function () { 6 | 7 | var out = {}; 8 | 9 | out.lbb = math.vec3.fromValues(9999999,9999999,9999999); 10 | out.rtf = math.vec3.fromValues(-9999999,-9999999,-9999999); 11 | 12 | return out; 13 | } 14 | 15 | aabb.addPoint = function ( out, _vertex ) { 16 | out.lbb = math.vec3.min(out.lbb, out.lbb, _vertex); 17 | out.rtf = math.vec3.max(out.rtf, out.rtf, _vertex); 18 | return out; 19 | } 20 | 21 | aabb.mergeAABB = function ( out, _aabb ) { 22 | aabb.addPoint( out, _aabb.lbb ); 23 | aabb.addPoint( out, _aabb.rtf ); 24 | 25 | return out; 26 | } 27 | 28 | aabb.mergeOBB = function ( out, _aabb, obj2worldMatrix ) { 29 | // extract to 8 point 30 | let lbb = math.vec3.clone(_aabb.lbb); 31 | let rtf = math.vec3.clone(_aabb.rtf); 32 | let ltb = math.vec3.fromValues( lbb[0], rtf[1], lbb[2] ); 33 | let ltf = math.vec3.fromValues( lbb[0], rtf[1], rtf[2] ); 34 | let lbf = math.vec3.fromValues( lbb[0], lbb[1], rtf[2] ); 35 | 36 | let rbb = math.vec3.fromValues( rtf[0], lbb[1], lbb[2] ); 37 | let rbf = math.vec3.fromValues( rtf[0], lbb[1], rtf[2] ); 38 | let rtb = math.vec3.fromValues( rtf[0], rtf[1], lbb[2] ); 39 | 40 | math.vec3.transformMat4(lbb, lbb, obj2worldMatrix); 41 | math.vec3.transformMat4(rtf, rtf, obj2worldMatrix); 42 | math.vec3.transformMat4(ltb, ltb, obj2worldMatrix); 43 | math.vec3.transformMat4(ltf, ltf, obj2worldMatrix); 44 | math.vec3.transformMat4(lbf, lbf, obj2worldMatrix); 45 | math.vec3.transformMat4(rbb, rbb, obj2worldMatrix); 46 | math.vec3.transformMat4(rbf, rbf, obj2worldMatrix); 47 | math.vec3.transformMat4(rtb, rtb, obj2worldMatrix); 48 | 49 | aabb.addPoint( out, lbb ); 50 | aabb.addPoint( out, rtf ); 51 | aabb.addPoint( out, ltb ); 52 | aabb.addPoint( out, ltf ); 53 | aabb.addPoint( out, lbf ); 54 | aabb.addPoint( out, rbb ); 55 | aabb.addPoint( out, rbf ); 56 | aabb.addPoint( out, rtb ); 57 | 58 | return out; 59 | } 60 | 61 | aabb.center = function (out, src) { 62 | math.vec3.add(out, src.lbb, src.rtf); 63 | math.vec3.scale(out, out, 0.5); 64 | return out; 65 | } 66 | 67 | aabb.radius = function (src) { 68 | let distance = math.vec3.sub( math.vec3.create(), src.lbb, src.rtf); 69 | return math.vec3.length(distance) * 0.5; 70 | } 71 | 72 | 73 | exports.aabb = aabb; -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | // Module to control application life. 3 | const app = electron.app 4 | // Module to create native browser window. 5 | const BrowserWindow = electron.BrowserWindow 6 | 7 | const path = require('path') 8 | const url = require('url') 9 | 10 | // Keep a global reference of the window object, if you don't, the window will 11 | // be closed automatically when the JavaScript object is garbage collected. 12 | let mainWindow 13 | 14 | function createWindow () { 15 | // Create the browser window. 16 | 17 | const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize 18 | 19 | mainWindow = new BrowserWindow({width: width, height: height}) 20 | 21 | // and load the index.html of the app. 22 | mainWindow.loadURL(url.format({ 23 | pathname: path.join(__dirname, 'index.html'), 24 | protocol: 'file:', 25 | slashes: true 26 | })) 27 | 28 | // Open the DevTools. 29 | mainWindow.webContents.openDevTools() 30 | 31 | // Emitted when the window is closed. 32 | mainWindow.on('closed', function () { 33 | // Dereference the window object, usually you would store windows 34 | // in an array if your app supports multi windows, this is the time 35 | // when you should delete the corresponding element. 36 | mainWindow = null 37 | }) 38 | } 39 | 40 | // This method will be called when Electron has finished 41 | // initialization and is ready to create browser windows. 42 | // Some APIs can only be used after this event occurs. 43 | app.on('ready', createWindow) 44 | 45 | // Quit when all windows are closed. 46 | app.on('window-all-closed', function () { 47 | // On OS X it is common for applications and their menu bar 48 | // to stay active until the user quits explicitly with Cmd + Q 49 | //if (process.platform !== 'darwin') { 50 | app.quit() 51 | //} 52 | }) 53 | 54 | app.on('activate', function () { 55 | // On OS X it's common to re-create a window in the app when the 56 | // dock icon is clicked and there are no other windows open. 57 | if (mainWindow === null) { 58 | createWindow() 59 | } 60 | }) 61 | 62 | // In this file you can include the rest of your app's specific main process 63 | // code. You can also put them in separate files and require them here. 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-shadermonki", 3 | "version": "1.0.0", 4 | "description": "A research Electron app", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron .", 8 | "pack": "electron-packager . --arch=all", 9 | "watch-js": "watchify main.js -o bundle.js -dv", 10 | "build-js": "browserify main.js > bundle.js", 11 | "test": "tape test/loader-osgjs.js", 12 | "pkg-postprocess": "tape test/pkg-postprocess.js", 13 | "package-build": "tape test/package-build.js" 14 | }, 15 | "repository": "https://github.com/gameknife/electron-shadermonki", 16 | "keywords": [ 17 | "Electron", 18 | "Shader" 19 | ], 20 | "author": "gameKnife", 21 | "license": "MIT", 22 | "devDependencies": { 23 | "electron": "^1.4.1", 24 | "electron-packager": "^8.2.0", 25 | "browserify": "^13.1.1", 26 | "watchify": "^3.7.0", 27 | "tape": "~2.3.2" 28 | }, 29 | 30 | "build": { 31 | "appId": "gameknife.shadermonki", 32 | "mac": { 33 | "category": "gameknife.app.category.utils" 34 | }, 35 | "win": { 36 | "iconUrl": "(windows-only) https link to icon" 37 | } 38 | }, 39 | "dependencies": { 40 | "fs-extra": "^1.0.0", 41 | "bluebird": "^3.4.6", 42 | "fs-promise": "^1.0.0", 43 | "gl-matrix": "2.3.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /renderer.js: -------------------------------------------------------------------------------- 1 | // This file is required by the index.html file and will 2 | // be executed in the renderer process for that window. 3 | // All of the Node.js APIs are available in this process. 4 | 'use strict'; 5 | 6 | const gkCore = require('./lib/gk-core'); 7 | 8 | const logger = require('./lib/gk-logger'); 9 | const glw = require('./lib/gk-glwrap'); 10 | const mouse = require('./lib/gk-mouseorbit'); 11 | const resMgr = require('./lib/gk-resmgr'); 12 | const resPanel = require('./lib/gk-respanel'); 13 | const Framework = require('./lib/gk-framework'); 14 | const path = require('path'); 15 | 16 | // initial 17 | window.onload = function(){ 18 | // init logger 19 | logger.init(bid('console-log-container')); 20 | logger.info('shadermonki started.'); 21 | 22 | // initialize rendering 23 | var canvas = bid('canvas'); 24 | glw.initGL(canvas); 25 | 26 | switch_sceneview(false); 27 | 28 | if(!glw.ready){console.log('initialize error'); return;} 29 | 30 | // initialize mouse orbit 31 | mouse.init(canvas); 32 | 33 | // filter it and put it into resource manager 34 | resPanel.init(bid('res-container'), __dirname); 35 | resPanel.rescan_resources(); 36 | resPanel.reconstruct_filetree(); 37 | resPanel.refresh(); 38 | 39 | // temporary feature 40 | let holder = bid('mesh-holder'); 41 | let current_proj = ''; 42 | 43 | holder.ondrop = function( ev ) { 44 | 45 | ev.preventDefault(); 46 | var filetoken = ev.dataTransfer.getData("restoken"); 47 | 48 | let type = 0; 49 | let resobj = resMgr.gResmgr.get_res(filetoken); 50 | if( resobj !== null ) 51 | { 52 | current_proj = path.dirname(filetoken) + '/'; 53 | 54 | type = resobj.get_type(); 55 | 56 | if(type === resMgr.RESTYPE.MESH) 57 | { 58 | //create a mesh element 59 | let _ret = resPanel.create_res_showobj(0, filetoken, type); 60 | 61 | resPanel.clean_folder(this); 62 | this.appendChild(_ret.obj_container); 63 | 64 | // load mesh here 65 | if(!resobj.loaded) 66 | { 67 | resobj.load( onFinish => { 68 | framework.bindShowObj( resobj.gameObject ); 69 | } ); 70 | } 71 | else 72 | { 73 | framework.bindShowObj( resobj.gameObject ); 74 | } 75 | 76 | resPanel.refresh(); 77 | 78 | 79 | } 80 | 81 | } 82 | 83 | } 84 | 85 | holder.ondragover = function (ev) { 86 | ev.preventDefault(); 87 | } 88 | 89 | let imgholder = bid('image-holder'); 90 | imgholder.ondrop = function( ev ) { 91 | 92 | ev.preventDefault(); 93 | var filetoken = ev.dataTransfer.getData("restoken"); 94 | 95 | let type = 0; 96 | let resobj = resMgr.gResmgr.get_res(filetoken); 97 | if( resobj !== null ) 98 | { 99 | type = resobj.get_type(); 100 | 101 | if(type === resMgr.RESTYPE.TEXTURE) 102 | { 103 | //create a mesh element 104 | let _ret = resPanel.create_res_showobj(0, filetoken, type, false); 105 | 106 | resPanel.clean_folder(this); 107 | this.appendChild(_ret.obj_container); 108 | 109 | // load mesh here 110 | resobj.load(); 111 | resPanel.refresh(); 112 | //window.parent.renderer.updateTexure(resobj); 113 | } 114 | 115 | } 116 | 117 | } 118 | 119 | imgholder.ondragover = function (ev) { 120 | ev.preventDefault(); 121 | } 122 | 123 | // framework start 124 | window.framework = new Framework(); 125 | window.framework.init(); 126 | 127 | 128 | 129 | // start and loop 130 | this.running = true; 131 | refresh_playbtn('btn_play', 'btn_play', window.running); 132 | 133 | 134 | // create render loop 135 | render_loop(); 136 | function render_loop() 137 | { 138 | if(window.running) { 139 | window.framework.update(); 140 | } 141 | requestAnimationFrame(render_loop); 142 | } 143 | 144 | // btn control 145 | { 146 | var playBtn = bid('btn_play'); 147 | playBtn.onclick = function () { 148 | window.running = !window.running; 149 | refresh_playbtn('btn_play', 'btn_play', window.running); 150 | } 151 | } 152 | 153 | { 154 | // btn control 155 | let playBtn = bid('btn_auto_rotate'); 156 | playBtn.onclick = function () { 157 | //refresh_playbtn('btn_auto_rotate', 'btn_square', renderer.autoRotate); 158 | } 159 | } 160 | 161 | this.fullscreen = false; 162 | { 163 | // btn control 164 | let targetBtn = bid('btn_next'); 165 | targetBtn.onclick = function () { 166 | window.fullscreen = !window.fullscreen; 167 | switch_sceneview(window.fullscreen); 168 | } 169 | } 170 | 171 | }; 172 | 173 | function refresh_playbtn( element_id, element_class, swt ) { 174 | var element = bid(element_id); 175 | if ( swt ) { 176 | element.className = element_class + '_on'; 177 | } 178 | else { 179 | element.className = element_class; 180 | } 181 | } 182 | 183 | function switch_sceneview( fsmode ) { 184 | 185 | var canvas_fsholder = bid('fullscreen'); 186 | var canvas = bid('canvas'); 187 | var canvas_defaultHolder = bid('sceneview'); 188 | 189 | //canvas_fsholder.style.visibility = 'hidden'; 190 | //canvas_fsholder.appendChild(canvas); 191 | //canvas_defaultHolder.appendChild(canvas); 192 | 193 | if( fsmode ) { 194 | canvas_fsholder.style.visibility = 'visible'; 195 | canvas_fsholder.appendChild(canvas); 196 | canvas.width = window.innerWidth; 197 | canvas.height = window.innerHeight; 198 | 199 | if( window.framework != undefined ) { 200 | window.framework.renderer.resize( window.innerWidth, window.innerHeight ); 201 | } 202 | } 203 | else { 204 | canvas_fsholder.style.visibility = 'hidden'; 205 | canvas_defaultHolder.appendChild(canvas); 206 | canvas.width = 512; 207 | canvas.height =512; 208 | 209 | if( window.framework != undefined ) { 210 | window.framework.renderer.resize(512, 512); 211 | } 212 | } 213 | } 214 | 215 | function bid(id){return document.getElementById(id);} 216 | 217 | -------------------------------------------------------------------------------- /res/mesh/box100.osgjs: -------------------------------------------------------------------------------- 1 | { 2 | "Generator": "OpenSceneGraph 3.5.4", 3 | "Version": 9, 4 | "osg.Node": { 5 | "Children": [ { 6 | "osg.MatrixTransform": { 7 | "UniqueID": 0, 8 | "Name": "c30296831dfb46218b3eee3b15b9c5ca.fbx", 9 | "Children": [ { 10 | "osg.MatrixTransform": { 11 | "UniqueID": 2, 12 | "Name": "RootNode", 13 | "Children": [ { 14 | "osg.MatrixTransform": { 15 | "UniqueID": 5, 16 | "Name": "Cube", 17 | "Children": [ { 18 | "osg.Node": { 19 | "UniqueID": 6, 20 | "Name": "Cube", 21 | "Children": [ { 22 | "osg.Geometry": { 23 | "UniqueID": 7, 24 | "Name": "Cube__0", 25 | "PrimitiveSetList": [ { 26 | "DrawElementsUInt": { 27 | "UniqueID": 13, 28 | "Indices": { 29 | "UniqueID": 14, 30 | "Array": { 31 | "Uint32Array": { 32 | "File": "model_file.bin.gz", 33 | "Size": 15, 34 | "Offset": 0, 35 | "Encoding": "varint" 36 | } 37 | }, 38 | "ItemSize": 1, 39 | "Type": "ELEMENT_ARRAY_BUFFER" 40 | }, 41 | "Mode": "TRIANGLE_STRIP" 42 | } 43 | } ], 44 | "UserDataContainer": { 45 | "UniqueID": 8, 46 | "Values": [ { 47 | "Name": "attributes", 48 | "Value": "55" 49 | }, 50 | { 51 | "Name": "vertex_bits", 52 | "Value": "8" 53 | }, 54 | { 55 | "Name": "vertex_mode", 56 | "Value": "3" 57 | }, 58 | { 59 | "Name": "uv_0_bits", 60 | "Value": "8" 61 | }, 62 | { 63 | "Name": "uv_0_mode", 64 | "Value": "3" 65 | }, 66 | { 67 | "Name": "epsilon", 68 | "Value": "0.25" 69 | }, 70 | { 71 | "Name": "nphi", 72 | "Value": "720" 73 | }, 74 | { 75 | "Name": "triangle_mode", 76 | "Value": "7" 77 | }, 78 | { 79 | "Name": "vtx_bbl_x", 80 | "Value": "-100" 81 | }, 82 | { 83 | "Name": "vtx_bbl_y", 84 | "Value": "-100" 85 | }, 86 | { 87 | "Name": "vtx_bbl_z", 88 | "Value": "-100" 89 | }, 90 | { 91 | "Name": "vtx_h_x", 92 | "Value": "1.5748" 93 | }, 94 | { 95 | "Name": "vtx_h_y", 96 | "Value": "1.5748" 97 | }, 98 | { 99 | "Name": "vtx_h_z", 100 | "Value": "1.5748" 101 | }, 102 | { 103 | "Name": "uv_0_bbl_x", 104 | "Value": "0" 105 | }, 106 | { 107 | "Name": "uv_0_bbl_y", 108 | "Value": "0" 109 | }, 110 | { 111 | "Name": "uv_0_h_x", 112 | "Value": "0.00787402" 113 | }, 114 | { 115 | "Name": "uv_0_h_y", 116 | "Value": "0.00787402" 117 | } ] 118 | }, 119 | "VertexAttributeList": { 120 | "Normal": { 121 | "UniqueID": 10, 122 | "Array": { 123 | "Uint32Array": { 124 | "File": "model_file.bin.gz", 125 | "Size": 24, 126 | "Offset": 20, 127 | "Encoding": "varint" 128 | } 129 | }, 130 | "ItemSize": 2, 131 | "Type": "ARRAY_BUFFER" 132 | }, 133 | "Tangent": { 134 | "UniqueID": 12, 135 | "Array": { 136 | "Uint32Array": { 137 | "File": "model_file.bin.gz", 138 | "Size": 24, 139 | "Offset": 100, 140 | "Encoding": "varint" 141 | } 142 | }, 143 | "ItemSize": 2, 144 | "Type": "ARRAY_BUFFER" 145 | }, 146 | "TexCoord0": { 147 | "UniqueID": 11, 148 | "Array": { 149 | "Int32Array": { 150 | "File": "model_file.bin.gz", 151 | "Size": 24, 152 | "Offset": 172, 153 | "Encoding": "varint" 154 | } 155 | }, 156 | "ItemSize": 2, 157 | "Type": "ARRAY_BUFFER" 158 | }, 159 | "Vertex": { 160 | "UniqueID": 9, 161 | "Array": { 162 | "Int32Array": { 163 | "File": "model_file.bin.gz", 164 | "Size": 24, 165 | "Offset": 252, 166 | "Encoding": "varint" 167 | } 168 | }, 169 | "ItemSize": 3, 170 | "Type": "ARRAY_BUFFER" 171 | } 172 | } 173 | } 174 | }, 175 | { 176 | "osg.Geometry": { 177 | "UniqueID": 15, 178 | "Name": "Cube__0", 179 | "PrimitiveSetList": [ { 180 | "DrawElementsUByte": { 181 | "UniqueID": 17, 182 | "Indices": { 183 | "UniqueID": 18, 184 | "Array": { 185 | "Uint8Array": { 186 | "File": "model_file_wireframe.bin.gz", 187 | "Size": 48, 188 | "Offset": 0 189 | } 190 | }, 191 | "ItemSize": 1, 192 | "Type": "ELEMENT_ARRAY_BUFFER" 193 | }, 194 | "Mode": "LINES" 195 | } 196 | } ], 197 | "UserDataContainer": { 198 | "UniqueID": 16, 199 | "Values": [ { 200 | "Name": "wireframe", 201 | "Value": "1" 202 | }, 203 | { 204 | "Name": "attributes", 205 | "Value": "1" 206 | } ] 207 | }, 208 | "VertexAttributeList": { 209 | "Vertex": { 210 | "UniqueID": 9 211 | } 212 | } 213 | } 214 | } ] 215 | } 216 | } ], 217 | "Matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] 218 | } 219 | } ], 220 | "Matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ], 221 | "StateSet": { 222 | "osg.StateSet": { 223 | "UniqueID": 3, 224 | "UserDataContainer": { 225 | "UniqueID": 4, 226 | "Values": [ { 227 | "Name": "UniqueID", 228 | "Value": "1" 229 | } ] 230 | } 231 | } 232 | } 233 | } 234 | } ], 235 | "Matrix": [ 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 ], 236 | "UserDataContainer": { 237 | "UniqueID": 1, 238 | "Values": [ { 239 | "Name": "source", 240 | "Value": "fbx" 241 | }, 242 | { 243 | "Name": "authoring_tool", 244 | "Value": "CINEMA 4D R17" 245 | } ] 246 | } 247 | } 248 | } ] 249 | } 250 | } -------------------------------------------------------------------------------- /res/mesh/box100.osgjs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/mesh/box100.osgjs.bin -------------------------------------------------------------------------------- /res/mesh/quad2.osgjs: -------------------------------------------------------------------------------- 1 | { 2 | "Generator": "OpenSceneGraph 3.5.4", 3 | "Version": 9, 4 | "osg.Node": { 5 | "Children": [ { 6 | "osg.MatrixTransform": { 7 | "UniqueID": 0, 8 | "Name": "fc2211c8bdc74a278e8b80ce09b87a00.fbx", 9 | "Children": [ { 10 | "osg.MatrixTransform": { 11 | "UniqueID": 2, 12 | "Name": "RootNode", 13 | "Children": [ { 14 | "osg.MatrixTransform": { 15 | "UniqueID": 5, 16 | "Name": "Plane_2", 17 | "Children": [ { 18 | "osg.Node": { 19 | "UniqueID": 6, 20 | "Name": "Plane_2", 21 | "Children": [ { 22 | "osg.Geometry": { 23 | "UniqueID": 7, 24 | "Name": "Plane_2__0", 25 | "PrimitiveSetList": [ { 26 | "DrawElementsUByte": { 27 | "UniqueID": 13, 28 | "Indices": { 29 | "UniqueID": 14, 30 | "Array": { 31 | "Uint8Array": { 32 | "File": "model_file.bin.gz", 33 | "Size": 6, 34 | "Offset": 0 35 | } 36 | }, 37 | "ItemSize": 1, 38 | "Type": "ELEMENT_ARRAY_BUFFER" 39 | }, 40 | "Mode": "TRIANGLE_STRIP" 41 | } 42 | } ], 43 | "UserDataContainer": { 44 | "UniqueID": 8, 45 | "Values": [ { 46 | "Name": "attributes", 47 | "Value": "55" 48 | }, 49 | { 50 | "Name": "vertex_bits", 51 | "Value": "8" 52 | }, 53 | { 54 | "Name": "vertex_mode", 55 | "Value": "3" 56 | }, 57 | { 58 | "Name": "uv_0_bits", 59 | "Value": "8" 60 | }, 61 | { 62 | "Name": "uv_0_mode", 63 | "Value": "3" 64 | }, 65 | { 66 | "Name": "epsilon", 67 | "Value": "0.25" 68 | }, 69 | { 70 | "Name": "nphi", 71 | "Value": "720" 72 | }, 73 | { 74 | "Name": "triangle_mode", 75 | "Value": "7" 76 | }, 77 | { 78 | "Name": "vtx_bbl_x", 79 | "Value": "-200" 80 | }, 81 | { 82 | "Name": "vtx_bbl_y", 83 | "Value": "0" 84 | }, 85 | { 86 | "Name": "vtx_bbl_z", 87 | "Value": "-200" 88 | }, 89 | { 90 | "Name": "vtx_h_x", 91 | "Value": "3.14961" 92 | }, 93 | { 94 | "Name": "vtx_h_y", 95 | "Value": "7.87402e-08" 96 | }, 97 | { 98 | "Name": "vtx_h_z", 99 | "Value": "7.08661" 100 | }, 101 | { 102 | "Name": "uv_0_bbl_x", 103 | "Value": "0" 104 | }, 105 | { 106 | "Name": "uv_0_bbl_y", 107 | "Value": "0" 108 | }, 109 | { 110 | "Name": "uv_0_h_x", 111 | "Value": "0.00787402" 112 | }, 113 | { 114 | "Name": "uv_0_h_y", 115 | "Value": "0.00787402" 116 | } ] 117 | }, 118 | "VertexAttributeList": { 119 | "Normal": { 120 | "UniqueID": 10, 121 | "Array": { 122 | "Uint32Array": { 123 | "File": "model_file.bin.gz", 124 | "Size": 8, 125 | "Offset": 8, 126 | "Encoding": "varint" 127 | } 128 | }, 129 | "ItemSize": 2, 130 | "Type": "ARRAY_BUFFER" 131 | }, 132 | "Tangent": { 133 | "UniqueID": 12, 134 | "Array": { 135 | "Uint32Array": { 136 | "File": "model_file.bin.gz", 137 | "Size": 8, 138 | "Offset": 40, 139 | "Encoding": "varint" 140 | } 141 | }, 142 | "ItemSize": 2, 143 | "Type": "ARRAY_BUFFER" 144 | }, 145 | "TexCoord0": { 146 | "UniqueID": 11, 147 | "Array": { 148 | "Int32Array": { 149 | "File": "model_file.bin.gz", 150 | "Size": 8, 151 | "Offset": 64, 152 | "Encoding": "varint" 153 | } 154 | }, 155 | "ItemSize": 2, 156 | "Type": "ARRAY_BUFFER" 157 | }, 158 | "Vertex": { 159 | "UniqueID": 9, 160 | "Array": { 161 | "Int32Array": { 162 | "File": "model_file.bin.gz", 163 | "Size": 8, 164 | "Offset": 88, 165 | "Encoding": "varint" 166 | } 167 | }, 168 | "ItemSize": 3, 169 | "Type": "ARRAY_BUFFER" 170 | } 171 | } 172 | } 173 | }, 174 | { 175 | "osg.Geometry": { 176 | "UniqueID": 15, 177 | "Name": "Plane_2__0", 178 | "PrimitiveSetList": [ { 179 | "DrawElementsUByte": { 180 | "UniqueID": 17, 181 | "Indices": { 182 | "UniqueID": 18, 183 | "Array": { 184 | "Uint8Array": { 185 | "File": "model_file_wireframe.bin.gz", 186 | "Size": 16, 187 | "Offset": 0 188 | } 189 | }, 190 | "ItemSize": 1, 191 | "Type": "ELEMENT_ARRAY_BUFFER" 192 | }, 193 | "Mode": "LINES" 194 | } 195 | } ], 196 | "UserDataContainer": { 197 | "UniqueID": 16, 198 | "Values": [ { 199 | "Name": "wireframe", 200 | "Value": "1" 201 | }, 202 | { 203 | "Name": "attributes", 204 | "Value": "1" 205 | } ] 206 | }, 207 | "VertexAttributeList": { 208 | "Vertex": { 209 | "UniqueID": 9 210 | } 211 | } 212 | } 213 | } ] 214 | } 215 | } ], 216 | "Matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -500, 1 ] 217 | } 218 | } ], 219 | "Matrix": [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ], 220 | "StateSet": { 221 | "osg.StateSet": { 222 | "UniqueID": 3, 223 | "UserDataContainer": { 224 | "UniqueID": 4, 225 | "Values": [ { 226 | "Name": "UniqueID", 227 | "Value": "1" 228 | } ] 229 | } 230 | } 231 | } 232 | } 233 | } ], 234 | "Matrix": [ 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1 ], 235 | "UserDataContainer": { 236 | "UniqueID": 1, 237 | "Values": [ { 238 | "Name": "source", 239 | "Value": "fbx" 240 | }, 241 | { 242 | "Name": "authoring_tool", 243 | "Value": "CINEMA 4D R17" 244 | } ] 245 | } 246 | } 247 | } ] 248 | } 249 | } -------------------------------------------------------------------------------- /res/mesh/quad2.osgjs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/mesh/quad2.osgjs.bin -------------------------------------------------------------------------------- /res/mesh/venusl.c4d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/mesh/venusl.c4d -------------------------------------------------------------------------------- /res/shader/base_fs.glsl: -------------------------------------------------------------------------------- 1 | /* 2 | _MainTex ('Main Texture', 2D) = 'white' 3 | _AlphaTex ('Alpha Texture', 2D) = 'white' 4 | */ 5 | precision mediump float; 6 | uniform sampler2D _MainTex; 7 | uniform sampler2D _AlphaTex; 8 | uniform sampler2D _GlobalOccMap; 9 | uniform sampler2D _GlobalDepthMap; 10 | uniform sampler2D _GlobalShadowMap; 11 | varying vec2 vTexCoord; 12 | varying vec3 vNormal; 13 | varying vec4 vLightHPos; 14 | varying vec4 vHpos; 15 | 16 | uniform float _TIME; 17 | uniform vec4 _LIGHTDIR; 18 | 19 | #define BIA 0.0003 20 | #define SHADOWMAP_SIZE (1.0 / 1024.0) 21 | 22 | float DecodeFloatRGBA(vec4 enc){ 23 | vec4 kDecodeDot = vec4(1.0,1.0/255.0,1.0/65025.0,1.0/160581375.0); 24 | return dot(enc, kDecodeDot); 25 | } 26 | float frac(float t) 27 | { 28 | return t - floor(t); 29 | } 30 | 31 | float snoise(vec2 co){ 32 | return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); 33 | } 34 | 35 | float sampleShadow(vec3 light_hpos) 36 | { 37 | float noise = fract(_TIME); 38 | float noiseMap = snoise(vTexCoord.xy + vec2(noise,noise)) * 1.0; 39 | vec2 normal = vec2(noiseMap, 1.0 - noiseMap); 40 | //normal = normalize(normal); 41 | vec4 shadow4; 42 | 43 | shadow4.x = sign(texture2D(_GlobalShadowMap, light_hpos.xy * 0.5 44 | + vec2(0.5,0.5) 45 | + reflect( normal, vec2(1,0)) 46 | * SHADOWMAP_SIZE).r - (light_hpos.z * 0.5 + 0.5) + BIA); 47 | 48 | shadow4.y = sign(texture2D(_GlobalShadowMap, light_hpos.xy * 0.5 49 | + vec2(0.5,0.5) 50 | + reflect( normal, vec2(-1,0)) 51 | * SHADOWMAP_SIZE).r - (light_hpos.z * 0.5 + 0.5) + BIA); 52 | shadow4.z = sign(texture2D(_GlobalShadowMap, light_hpos.xy * 0.5 53 | + vec2(0.5,0.5) 54 | + reflect( normal, vec2(0,1)) 55 | * SHADOWMAP_SIZE).r - (light_hpos.z * 0.5 + 0.5) + BIA); 56 | shadow4.w = sign(texture2D(_GlobalShadowMap, light_hpos.xy * 0.5 57 | + vec2(0.5,0.5) 58 | + reflect( normal, vec2(0,-1)) 59 | * SHADOWMAP_SIZE).r - (light_hpos.z * 0.5 + 0.5) + BIA); 60 | 61 | return max(0.0, dot(shadow4, vec4(0.25)) ); 62 | } 63 | void main(){ 64 | 65 | // shadow 66 | vec3 light_hpos = vLightHPos.xyz / vLightHPos.w; 67 | float shadow = sampleShadow(light_hpos); 68 | 69 | // occlusion 70 | vec2 hposuv = vHpos.xy / vHpos.w; 71 | float occ = texture2D(_GlobalOccMap, hposuv).x; 72 | 73 | vec4 samplerColor1 = vec4(frac(vTexCoord.x + _TIME),frac(vTexCoord.y + _TIME),0,1); 74 | vec4 samplerColor2 = vec4(vNormal * vec3(0.5,0.5,0.5) + vec3(0.5,0.5,0.5),1); 75 | float ndotl = max(0.0, dot(_LIGHTDIR.xyz, vNormal)); 76 | vec4 samplerColor = texture2D(_MainTex, vTexCoord.xy); 77 | vec4 alphaSamplerColor = texture2D(_AlphaTex, vTexCoord.xy); 78 | samplerColor *= samplerColor; 79 | samplerColor.a *= alphaSamplerColor.r * alphaSamplerColor.a; 80 | if(samplerColor.a < 0.05) discard; 81 | samplerColor = samplerColor * (ndotl * shadow + vec4(0.2,0.3,0.7,1.0) * (vNormal.y * 0.4 + 0.6)) * occ; 82 | //samplerColor.rgb = vec3(occ,occ,occ); 83 | samplerColor.a = 1.0; 84 | //gl_FragColor = vec4(depthA,depthA,depthA,1.0); 85 | gl_FragColor = sqrt(samplerColor); 86 | } 87 | -------------------------------------------------------------------------------- /res/shader/base_vs.glsl: -------------------------------------------------------------------------------- 1 | attribute vec2 texcoord; 2 | attribute vec3 normal; 3 | attribute vec3 position; 4 | uniform mat4 _MVP; 5 | uniform mat4 _MV; 6 | uniform mat4 _M2W; 7 | uniform mat4 _MVP_LIGHT; 8 | 9 | varying vec2 vTexCoord; 10 | varying vec3 vNormal; 11 | varying vec4 vLightHPos; 12 | varying vec4 vHpos; 13 | 14 | void main() 15 | { 16 | vTexCoord = (position * 0.075).xy; 17 | vTexCoord = texcoord; 18 | vNormal = (_M2W * vec4(normal, 0.0)).xyz; 19 | vLightHPos = _MV * vec4(position, 1.0); 20 | vLightHPos = _MVP_LIGHT * vLightHPos; 21 | 22 | /*gl_Position = vec4(position, 1.0);*/ 23 | gl_Position = _MVP * vec4(position, 1.0); 24 | 25 | vHpos = gl_Position; 26 | vHpos.xy *= -1.0; 27 | vHpos.xyz = (vHpos.w - vHpos.xyz) * 0.5; 28 | } -------------------------------------------------------------------------------- /res/texture/ground.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/texture/ground.jpg -------------------------------------------------------------------------------- /res/texture/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/texture/leaf.png -------------------------------------------------------------------------------- /res/texture/matcap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/texture/matcap.jpg -------------------------------------------------------------------------------- /res/texture/plaster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/texture/plaster.jpg -------------------------------------------------------------------------------- /res/texture/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/res/texture/white.jpg -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gameknife/electron-shadermonki/a6780567960fc0d0d6a523e8fab951cef1eef72a/screenshot.png -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | * { 4 | margin: 0px; 5 | padding: 0px; 6 | } 7 | 8 | html, body { 9 | font-family: 'arial','sans-serif','Monaco',monospace; 10 | width: 100%; 11 | height: 100%; 12 | min-width: 1024px; 13 | overflow: hidden; 14 | } 15 | 16 | #toolbar { 17 | background-color: #222; 18 | width: 100%; 19 | height: 36px; 20 | position: absolute; 21 | z-index: 10; 22 | box-shadow: 0 1px 2px rgba(0,0,0,.85),inset 0 1px 0 rgba(255,255,255,.15) 23 | } 24 | #toolbar .grp_control { 25 | width: 154px; 26 | margin: 0 auto; 27 | } 28 | 29 | .btn_wide { 30 | 31 | margin: 5px 10px; 32 | line-height: 28px; 33 | border: 1px solid #333; 34 | border-radius: 4px; 35 | 36 | box-shadow: 0 1px 2px rgba(0,0,0,.05),inset 0 1px 1px rgba(255,255,255,.25); 37 | color: #fff; 38 | font-size: 10px; 39 | text-align: center; 40 | outline: 0; 41 | cursor: pointer; 42 | -webkit-transition: all .2s ease-in-out; 43 | transition: all .2s ease-in-out; 44 | 45 | background: #444; 46 | background: -webkit-linear-gradient(top,#444,#333); 47 | background: linear-gradient(to bottom,#444,#333); 48 | } 49 | 50 | .btn_play, .btn_play_on, .btn_square, .btn_square_on { 51 | 52 | line-height: 28px; 53 | margin-top: 4px; 54 | border: 1px solid #333; 55 | border-radius: 4px; 56 | 57 | box-shadow: 0 1px 2px rgba(0,0,0,.05),inset 0 1px 1px rgba(255,255,255,.25); 58 | color: #fff; 59 | font-size: 10px; 60 | text-align: center; 61 | outline: 0; 62 | cursor: pointer; 63 | -webkit-transition: all .2s ease-in-out; 64 | transition: all .2s ease-in-out; 65 | 66 | background: #444; 67 | background: -webkit-linear-gradient(top,#444,#333); 68 | background: linear-gradient(to bottom,#444,#333); 69 | } 70 | 71 | .btn_square, .btn_square_on { 72 | width: 28px; 73 | height: 28px; 74 | font-size: 12px; 75 | } 76 | 77 | .btn_play, .btn_play_on { 78 | width: 48px; 79 | height: 28px; 80 | } 81 | 82 | .btn_play_on, .btn_square_on { 83 | background: #47c; 84 | background: -webkit-linear-gradient(top,#47c,#46a); 85 | background: linear-gradient(to bottom,#47c,#46a); 86 | } 87 | 88 | .btn_play:hover, .btn_square:hover { 89 | color: #47c; 90 | background: -webkit-linear-gradient(top,#333,#444); 91 | background: linear-gradient(to bottom,#333,#444); 92 | } 93 | 94 | .btn_play_on:hover, .btn_square_on:hover { 95 | color: #222; 96 | background: -webkit-linear-gradient(top,#46a,#47c); 97 | background: linear-gradient(to bottom,#46a,#47c); 98 | } 99 | 100 | #mainframe { 101 | background-color: #333; 102 | width: 100%; 103 | top: 36px; 104 | bottom: 20px; 105 | position: absolute; 106 | 107 | display: flex; 108 | flex-direction: row; 109 | } 110 | 111 | #status_bar { 112 | border: 1px solid #111; 113 | background-color: #222; 114 | width: 100%; 115 | margin-top: 20px; 116 | bottom: 0; 117 | position: absolute; 118 | 119 | z-index: -10; 120 | } 121 | 122 | #status_bar .status-content { 123 | color: #ccc; 124 | font-size: 13px; 125 | margin: 2px 0; 126 | } 127 | 128 | #left { 129 | background-color: #333; 130 | width: 512px; 131 | 132 | display: flex; 133 | flex-direction: column; 134 | } 135 | 136 | #left .canvas-frame { 137 | height: 536px; 138 | position: relative; 139 | } 140 | 141 | #left .canvas-ctlbtn { 142 | position: absolute; 143 | top: 20px; 144 | width: 512px; 145 | height: 30px; 146 | } 147 | 148 | #left .canvas-ctlbtn-cgrp { 149 | position: relative; 150 | top: -512px; 151 | width: 100px; 152 | margin: 0 auto; 153 | } 154 | 155 | #left .canvas-ctlbtn-rgrp { 156 | position: relative; 157 | top: -340px; 158 | left: 480px; 159 | width: 34px; 160 | height: 120px; 161 | } 162 | 163 | #left .console-frame { 164 | flex: 1; 165 | 166 | display: flex; 167 | flex-direction: column; 168 | } 169 | 170 | .obj-container { 171 | flex: 1; 172 | background-color: #333; 173 | overflow:scroll; 174 | } 175 | 176 | .obj-container::-webkit-scrollbar { 177 | width: 12px; 178 | } 179 | 180 | .obj-container::-webkit-scrollbar-track { 181 | border-radius: 1px; 182 | border: 1px #111; 183 | background-color: #222; 184 | } 185 | 186 | .obj-container::-webkit-scrollbar-thumb { 187 | border-radius: 1px; 188 | border: 1px #222; 189 | background-color: #111; 190 | } 191 | 192 | .obj-container::-webkit-scrollbar-corner { 193 | border-radius: 1px; 194 | border: 1px #111; 195 | background-color: #222; 196 | } 197 | 198 | .obj-line, .obj-line-checked { 199 | line-height: 16px; 200 | padding: 2px 10px; 201 | border: hidden; 202 | 203 | color: #aaa; 204 | font-size: 14px; 205 | text-align: center; 206 | outline: 0; 207 | cursor: pointer; 208 | 209 | -webkit-transition: all .1s ease-in-out; 210 | transition: all .1s ease-in-out; 211 | 212 | background: #333; 213 | 214 | white-space: nowrap; 215 | } 216 | 217 | .obj-line-checked { 218 | color: #fff; 219 | background: #47c; 220 | } 221 | .obj-line:hover { 222 | color: #fff; 223 | } 224 | 225 | #left .log-line-s { 226 | padding: 2px 10px; 227 | background-color: #2a2a2a; 228 | color: #fff; 229 | font-size: 12px; 230 | } 231 | 232 | #left .log-line-d { 233 | padding: 2px 10px; 234 | background-color: #222; 235 | color: #fff; 236 | font-size: 12px; 237 | } 238 | 239 | #parameter-bar { 240 | height: 100%; 241 | width: 200px; 242 | display: flex; 243 | flex-direction: column; 244 | } 245 | 246 | #right { 247 | height: 100%; 248 | flex: 2; 249 | display: flex; 250 | flex-direction: column; 251 | } 252 | 253 | #project-bar { 254 | height: 100%; 255 | width: 200px; 256 | display: flex; 257 | flex-direction: column; 258 | } 259 | 260 | .resobj-contain { 261 | padding: 2px 10px; 262 | } 263 | 264 | #right .editor-frame { 265 | background-color: #333; 266 | font-size: 14px; 267 | box-shadow: 0 1px 2px rgba(0,0,0,.85),inset 0 1px 0 rgba(255,255,255,.15); 268 | flex: 1; 269 | display: flex; 270 | flex-direction: column; 271 | /*display: none;*/ 272 | } 273 | 274 | #right .editor { 275 | font-family: 'consolas', 'Menlo', monospace; 276 | color: #fff; 277 | background-color: #333; 278 | font-size: 12px; 279 | line-height: 1.25; 280 | flex: 1; 281 | /*display: none;*/ 282 | } 283 | 284 | .title-bar, .title-bar-modify, .title-bar-saved { 285 | padding: 4px 10px; 286 | background-color: #444; 287 | color: #fff; 288 | font-weight: bold; 289 | font-size: 12px; 290 | } 291 | 292 | .title-bar-modify { 293 | background-color: #a43; 294 | } 295 | 296 | .title-bar-saved { 297 | background-color: #4a3; 298 | } 299 | 300 | .parameter-group { 301 | margin: 10px 2px; 302 | padding: 2px 2px; 303 | color: #777; 304 | font-size: 12px; 305 | box-shadow: 0 4px 2px rgba(0,0,0,.15); 306 | background: #373737; 307 | border: 1px dotted #777; 308 | } 309 | 310 | .droped-title { 311 | margin: 0px 0px; 312 | padding: 2px 5px; 313 | color: #47c; 314 | font-size: 12px; 315 | font-weight: bold; 316 | background: linear-gradient(to right,#222,#2a2a2a); 317 | } 318 | 319 | .droped-container { 320 | 321 | padding: 10px 5px; 322 | margin: 2px 10px 2px 10px; 323 | min-height: 20px; 324 | border: 1px dotted #777; 325 | border-radius: 2px; 326 | 327 | box-shadow: inset -4px -4px rgba(0,0,0,.05),inset 0 4px 2px rgba(0,0,0,.05); 328 | color: #fff; 329 | font-size: 12px; 330 | text-align: center; 331 | outline: 0; 332 | cursor: pointer; 333 | -webkit-transition: all .2s ease-in-out; 334 | transition: all .2s ease-in-out; 335 | 336 | background: #333; 337 | } 338 | 339 | .dotted-container { 340 | 341 | padding: 10px 60px; 342 | margin: 2px 10px 2px 10px; 343 | min-height: 20px; 344 | border: 1px dotted #777; 345 | border-radius: 2px; 346 | 347 | box-shadow: inset -4px -4px rgba(0,0,0,.05),inset 0 4px 2px rgba(0,0,0,.05); 348 | color: #fff; 349 | font-size: 12px; 350 | text-align: center; 351 | outline: 0; 352 | cursor: pointer; 353 | -webkit-transition: all .2s ease-in-out; 354 | transition: all .2s ease-in-out; 355 | 356 | background: #333; 357 | } 358 | 359 | .interactive-frame { 360 | cursor: pointer; 361 | } 362 | 363 | #fullscreen { 364 | position: absolute; 365 | top: 35px; 366 | bottom: 0px; 367 | left: 0px; 368 | right: 0px; 369 | z-index: 10; 370 | background: #333; 371 | color: #fff; 372 | display: inherit; 373 | } -------------------------------------------------------------------------------- /test/loader-osgjs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/20. 3 | */ 4 | var test = require('tape'); 5 | var loader_osgjs = require('../lib/loader/loader-osgjs.js'); 6 | 7 | test('loader-osgjs', function (t) { 8 | t.plan(1); 9 | 10 | loader_osgjs.load( "./res/package/blacksmith/model.osgjs", "./res/package/blacksmith/model.osgjs.bin", function(res) { 11 | //t.message( res ); 12 | } ); 13 | 14 | t.equal(1, 1); 15 | }); -------------------------------------------------------------------------------- /test/package-build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by gameKnife on 2016/11/26. 3 | */ 4 | var test = require('tape'); 5 | var fs = require('fs-extra'); 6 | var path = require('path'); 7 | var http = require('http'); 8 | var https = require('https'); 9 | var zlib = require('zlib'); 10 | test('package-build', function (t) { 11 | t.plan(1); 12 | 13 | console.info('shader monki package builder v0.1'); 14 | 15 | let packageWaitForBuild = []; 16 | 17 | let filelist = fs.walkSync('res/package/'); 18 | filelist.forEach( item => { 19 | 20 | item = path.normalize(item); 21 | let filename = path.basename( item ); 22 | let dirname = path.dirname(item); 23 | let relpath = path.relative( 'res/package/', dirname ); 24 | let extname = path.extname(item); 25 | let purefilename = path.basename( item, extname ); 26 | if(extname == '.spkg') 27 | { 28 | let pkgDir = path.join( dirname , purefilename); 29 | 30 | try { 31 | console.info('spkg found: ' + pkgDir); 32 | fs.accessSync(pkgDir, fs.F_OK); 33 | 34 | // TODO to remove 35 | packageWaitForBuild.push(item); 36 | } catch (e) { 37 | // It isn't accessible 38 | 39 | // push it & mkdir 40 | try { 41 | fs.mkdirSync(pkgDir); 42 | packageWaitForBuild.push(item); 43 | } 44 | catch (e){ 45 | console.error('spkg dir create failed!!!'); 46 | } 47 | } 48 | 49 | 50 | } 51 | }); 52 | 53 | //console.info(packageWaitForBuild); 54 | 55 | packageWaitForBuild.forEach( spkgpath => { 56 | try { 57 | 58 | let buffer = fs.readFileSync(spkgpath); 59 | let text = buffer.toString(); 60 | let pkgJSON = JSON.parse(text); 61 | //console.info(pkgJSON); 62 | 63 | let extname = path.extname(spkgpath); 64 | let purefilename = path.basename( spkgpath, extname ); 65 | let dirname = path.dirname(spkgpath); 66 | let pkgDir = path.join( dirname , purefilename); 67 | ParsePkg(pkgJSON, pkgDir); 68 | 69 | } catch (e) { 70 | 71 | } 72 | 73 | } ); 74 | 75 | t.equal(1, 1); 76 | }); 77 | 78 | function DownloadFile(dir, osgfile, downloadfile) { 79 | 80 | let absDir = path.join(dir, downloadfile); 81 | try { 82 | fs.accessSync(absDir, fs.F_OK); 83 | } catch (e) { 84 | var file = fs.createWriteStream(absDir); 85 | var request = https.get(osgfile, function (response) { 86 | 87 | switch (response.headers['content-encoding']) { 88 | // or, just use zlib.createUnzip() to handle both cases 89 | case 'gzip': 90 | response.pipe(zlib.createGunzip()).pipe(file); 91 | break; 92 | case 'deflate': 93 | response.pipe(zlib.createInflate()).pipe(file); 94 | break; 95 | default: 96 | response.pipe(file); 97 | break; 98 | } 99 | 100 | var len = parseInt(response.headers['content-length'], 10); 101 | var body = ""; 102 | var cur = 0; 103 | var total = len / 1048576; //1048576 - bytes in 1Megabyte 104 | 105 | response.on("data", function(chunk) { 106 | body += chunk; 107 | cur += chunk.length; 108 | 109 | let outData = "Downloading " + downloadfile + ' - ' + (100.0 * cur / len).toFixed(2) + "% "; 110 | console.log(outData); 111 | }); 112 | 113 | response.on("end", function() { 114 | 115 | }); 116 | }); 117 | } 118 | } 119 | function ParsePkg( pkgObject, dir ){ 120 | //console.info(pkgObject); 121 | console.info('pkg building...\nwork dir: ' + dir); 122 | 123 | // mesh files 124 | let osgfile = pkgObject.files[0].osgjsUrl; 125 | let osgModelfile = osgfile.replace('file.osgjs.gz', 'model_file.bin.gz'); 126 | DownloadFile(dir, osgfile, 'model.osgjs'); 127 | DownloadFile(dir, osgModelfile, 'model.osgjs.bin'); 128 | 129 | // material files 130 | let options = pkgObject.options; 131 | let materials = options.materials; 132 | 133 | for( let mat in materials ) 134 | { 135 | let matnode = materials[mat]; 136 | 137 | let mattext = JSON.stringify(matnode); 138 | var file = fs.createWriteStream(path.join(dir, matnode.name + '.mat')); 139 | file.write(mattext); 140 | file.close(); 141 | 142 | 143 | // download all textures 144 | for( let channel in matnode.channels) 145 | { 146 | //console.info(matnode); 147 | let channelnode = matnode.channels[channel]; 148 | if( channelnode.texture ) 149 | { 150 | let image = channelnode.texture.image; 151 | let name = image.name; 152 | let images = image.images; 153 | 154 | let toplodurl = ''; 155 | let maxWidth = 0; 156 | for( let i=0; i < images.length; ++i) 157 | { 158 | let currImage = images[i]; 159 | if( currImage.width > maxWidth ) 160 | { 161 | maxWidth = currImage.width; 162 | toplodurl = currImage.url; 163 | } 164 | } 165 | let ext = path.extname(toplodurl); 166 | DownloadFile( dir, toplodurl, name + ext ); 167 | 168 | } 169 | } 170 | } 171 | 172 | } 173 | 174 | -------------------------------------------------------------------------------- /test/pkg-postprocess.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by kaimingyi on 2016/11/20. 3 | */ 4 | var test = require('tape'); 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | 8 | test('loader-osgjs', function (t) { 9 | t.plan(1); 10 | 11 | let basepath = 'res/package/game/'; 12 | 13 | fs.readFile(basepath + 'list.txt', 'utf-8', function(err, data) { 14 | if(err) 15 | { 16 | 17 | } 18 | else 19 | { 20 | let text = data.toString(); 21 | 22 | let imgs = text.split('\r\n'); 23 | imgs.forEach(img => { 24 | 25 | let side = img.split('#'); 26 | let orgfile = path.basename(side[0]); 27 | let newfile = side[1]; 28 | console.info(basepath + orgfile + ' : ' + basepath + newfile); 29 | if(orgfile && newfile) 30 | { 31 | //console.info(basepath + orgfile + ' : ' + basepath + newfile); 32 | //if(fs.existsSync(basepath + orgfile) ) 33 | { 34 | fs.rename( basepath + orgfile, basepath + newfile ); 35 | } 36 | } 37 | }); 38 | 39 | //if(fs.existsSync(basepath + 'file.osgjs.gz') ) 40 | { 41 | fs.rename( basepath + 'file.osgjs.gz', basepath + 'model.osgjs' ); 42 | fs.rename( basepath + 'model_file.bin.gz', basepath + 'model.osgjs.bin' ); 43 | } 44 | 45 | } 46 | }); 47 | 48 | 49 | t.equal(1, 1); 50 | }); --------------------------------------------------------------------------------