Latest local changes for branching (2).

This commit is contained in:
BKcore
2013-03-16 16:11:34 +01:00
parent 28046f4a66
commit 451e9464a3
95 changed files with 5281 additions and 62 deletions
+4
View File
@@ -0,0 +1,4 @@
AddType application/x-web-app-manifest+json .webapp
ExpiresByType application/x-web-app-manifest+json "access"
AddType text/cache-manifest .appcache
ExpiresByType text/cache-manifest "access"
+10 -10
View File
@@ -12,8 +12,8 @@ bkcore.hexgl.Gameplay = function(opts)
{
var self = this;
this.startDelay = 1000;
this.countDownDelay = 1500;
this.startDelay = opts.hud == null ? 0 : 1000;
this.countDownDelay = opts.hud == null ? 1000 : 1500;
this.active = false;
this.timer = new bkcore.Timer();
@@ -107,7 +107,7 @@ bkcore.hexgl.Gameplay.prototype.simu = function()
{
this.lapTimes = [92300, 91250, 90365];
this.finishTime = this.lapTimes[0]+this.lapTimes[1]+this.lapTimes[2];
this.hud != null && this.hud.display("Finish");
if(this.hud != null) this.hud.display("Finish");
this.step = 100;
this.result = this.results.FINISH;
this.shipControls.active = false;
@@ -128,7 +128,7 @@ bkcore.hexgl.Gameplay.prototype.start = function(opts)
if(this.mode == 'replay')
{
this.cameraControls.mode = this.cameraControls.modes.ORBIT;
this.hud != null && this.hud.messageOnly = true;
if(this.hud != null) this.hud.messageOnly = true;
try {
var d = localStorage['race-'+this.track.name+'-replay'];
@@ -166,12 +166,12 @@ bkcore.hexgl.Gameplay.prototype.end = function(result)
if(result == this.results.FINISH)
{
this.hud != null && this.hud.display("Finish");
if(this.hud != null) this.hud.display("Finish");
this.step = 100;
}
else if(result == this.results.DESTROYED)
{
this.hud != null && this.hud.display("Destroyed");
if(this.hud != null) this.hud.display("Destroyed");
this.step = 100;
}
}
@@ -184,22 +184,22 @@ bkcore.hexgl.Gameplay.prototype.update = function()
if(this.step == 0 && this.timer.time.elapsed >= this.countDownDelay+this.startDelay)
{
this.hud != null && this.hud.display("3");
if(this.hud != null) this.hud.display("3");
this.step = 1;
}
else if(this.step == 1 && this.timer.time.elapsed >= 2*this.countDownDelay+this.startDelay)
{
this.hud != null && this.hud.display("2");
if(this.hud != null) this.hud.display("2");
this.step = 2;
}
else if(this.step == 2 && this.timer.time.elapsed >= 3*this.countDownDelay+this.startDelay)
{
this.hud != null && this.hud.display("1");
if(this.hud != null) this.hud.display("1");
this.step = 3;
}
else if(this.step == 3 && this.timer.time.elapsed >= 4*this.countDownDelay+this.startDelay)
{
this.hud != null && this.hud.display("Go", 0.5);
if(this.hud != null) this.hud.display("Go", 0.5);
this.step = 4;
this.timer.start();
+50 -21
View File
@@ -19,6 +19,7 @@ bkcore.hexgl.HexGL = function(opts)
this.a = window.location.href;
this.mobile = opts.mobile == undefined ? false : opts.mobile;
this.active = true;
this.displayHUD = opts.hud == undefined ? true : opts.hud;
this.width = opts.width == undefined ? window.innerWidth : opts.width;
@@ -34,6 +35,8 @@ bkcore.hexgl.HexGL = function(opts)
this.mode = opts.mode == undefined ? 'timeattack' : opts.mode;
this.controlType = opts.controlType == undefined ? 1 : opts.controlType;
if(this.half)
{
this.width /= 2;
@@ -56,6 +59,10 @@ bkcore.hexgl.HexGL = function(opts)
this.containers.main = opts.container == undefined ? document.body : opts.container;
this.containers.overlay = opts.overlay == undefined ? document.body : opts.overlay;
this.gameover = opts.gameover == undefined ? null : opts.gameover;
this.godmode = opts.godmode == undefined ? false : opts.godmode;
this.hud = null;
this.gameplay = null;
@@ -86,7 +93,7 @@ bkcore.hexgl.HexGL.prototype.start = function()
function raf()
{
requestAnimationFrame( raf );
if(self && self.active) requestAnimationFrame( raf );
self.update();
}
@@ -104,7 +111,8 @@ bkcore.hexgl.HexGL.prototype.reset = function()
bkcore.hexgl.HexGL.prototype.restart = function()
{
this.document.getElementById('finish').style.display = 'none';
try{ this.document.getElementById('finish').style.display = 'none'; }
catch(e){};
this.reset();
}
@@ -122,16 +130,16 @@ bkcore.hexgl.HexGL.prototype.init = function()
{
this.initHUD();
this.track.buildMaterials(this.quality);
this.track.buildMaterials(this.quality, this.mobile);
this.track.buildScenes(this, this.quality);
this.track.buildScenes(this, this.quality, this.mobile);
this.initGameComposer();
}
bkcore.hexgl.HexGL.prototype.load = function(opts)
{
this.track.load(opts, this.quality);
this.track.load(opts, this.quality, this.mobile);
}
bkcore.hexgl.HexGL.prototype.initGameplay = function()
@@ -156,6 +164,23 @@ bkcore.hexgl.HexGL.prototype.initGameplay = function()
bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
{
this.active = false;
var tf = bkcore.Timer.msToTimeString(f);
var tl = [
bkcore.Timer.msToTimeString(l[0]),
bkcore.Timer.msToTimeString(l[1]),
bkcore.Timer.msToTimeString(l[2])
];
if(this.mobile)
{
this.gameover.style.display = "block";
this.gameover.innerHTML = tf.m + "'" + tf.s + "''" + tf.ms;
this.containers.main.style.display = "none";
return;
}
var t = this.track;
var dc = this.document.getElementById("finish");
var ds = this.document.getElementById("finish-state");
@@ -171,12 +196,6 @@ bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
var sl = this.document.getElementById("lowfps-msg");
var d = this.difficulty == 0 ? 'casual' : 'hard';
var ts = this.hud.timeSeparators;
var tf = bkcore.Timer.msToTimeString(f);
var tl = [
bkcore.Timer.msToTimeString(l[0]),
bkcore.Timer.msToTimeString(l[1]),
bkcore.Timer.msToTimeString(l[2])
];
if(this.gameplay.result == this.gameplay.results.FINISH)
{
@@ -252,12 +271,15 @@ bkcore.hexgl.HexGL.prototype.initRenderer = function()
clearColor: 0x000000
});
renderer.physicallyBasedShading = true;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
if(this.quality > 0 && !this.mobile)
{
renderer.physicallyBasedShading = true;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
}
renderer.autoClear = false;
renderer.sortObjects = false;
@@ -297,7 +319,8 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
this.composers.game = new THREE.EffectComposer( this.renderer, renderTarget );
var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
effectScreen.renderToScreen = true;
var effectVignette = new THREE.ShaderPass( THREE.ShaderExtras[ "vignette" ] );
var effectHex = new THREE.ShaderPass( bkcore.threejs.Shaders[ "hexvignette" ] );
@@ -312,7 +335,7 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
this.composers.game.addPass( renderSky );
this.composers.game.addPass( renderModel );
if(this.quality > 0)
if(this.quality > 0 && !this.mobile)
{
var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height );
@@ -321,7 +344,7 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
this.extras.fxaa = effectFXAA;
}
if(this.quality > 1)
if(this.quality > 1 && !this.mobile)
{
var effectBloom = new THREE.BloomPass( 0.8, 25, 4 , 256);
@@ -330,7 +353,10 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
this.extras.bloom = effectBloom;
}
this.composers.game.addPass( effectHex );
if(!this.mobile || this.quality > 0)
this.composers.game.addPass( effectHex );
else
this.composers.game.addPass( effectScreen );
}
@@ -343,7 +369,7 @@ bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, ma
mesh.position.set( x, y, z );
parent.add(mesh);
if(this.quality > 0)
if(this.quality > 0 && !this.mobile)
{
mesh.castShadow = true;
mesh.receiveShadow = true;
@@ -393,4 +419,7 @@ bkcore.hexgl.HexGL.prototype.tweakShipControls = function()
c.driftLerp = 0.3;
c.angularLerp = 0.4;
}
if(this.godmode)
c.shieldDamage = 0.0;
}
+73 -10
View File
@@ -15,6 +15,7 @@ bkcore.hexgl.ShipControls = function(ctx)
this.active = true;
this.destroyed = false;
this.falling = false;
this.dom = domElement;
this.mesh = null;
@@ -96,6 +97,8 @@ bkcore.hexgl.ShipControls = function(ctx)
this.repulsionAmount = 0.0;
this.repulsionForce = new THREE.Vector3();
this.fallVector = new THREE.Vector3(0,-20,0);
this.resetPos = null;
this.resetRot = null;
@@ -115,16 +118,40 @@ bkcore.hexgl.ShipControls = function(ctx)
right: false
};
this.touchController = bkcore.TouchController.isTouchable() ? new bkcore.TouchController(
domElement, ctx.width/2,
function(state, touch, event){
if(event.touches.length <= 1)
self.key.forward = false;
else
self.key.forward = true;
console.log(event.touches.length);
console.log(self.key.forward);
}) : null;
this.touchController = null;
this.orientationController = null;
if(ctx.controlType == 1 && bkcore.controllers.TouchController.isCompatible())
{
this.touchController = new bkcore.controllers.TouchController(
domElement, ctx.width/2,
function(state, touch, event){
if(event.touches.length >= 4)
window.location.reload(false);
else if(event.touches.length == 3)
ctx.restart();
else if(event.touches.length <= 1)
self.key.forward = false;
else
self.key.forward = true;
});
}
else if(ctx.controlType == 2 && bkcore.controllers.OrientationController.isCompatible())
{
this.orientationController = new bkcore.controllers.OrientationController(
domElement, true,
function(state, touch, event){
console.log(event.touches.length);
if(event.touches.length >= 4)
window.location.reload(false);
else if(event.touches.length == 3)
ctx.restart();
else if(event.touches.length < 1)
self.key.forward = false;
else
self.key.forward = true;
});
}
function onKeyDown(event)
{
@@ -212,8 +239,28 @@ bkcore.hexgl.ShipControls.prototype.destroy = function()
this.collision.right = false;
}
bkcore.hexgl.ShipControls.prototype.fall = function()
{
this.active = false;
this.collision.front = false;
this.collision.left = false;
this.collision.right = false;
this.falling = true;
_this = this;
setTimeout(function(){
_this.destroyed = true;
}, 1500);
}
bkcore.hexgl.ShipControls.prototype.update = function(dt)
{
if(this.falling)
{
this.mesh.position.addSelf(this.fallVector);
return;
}
if(!this.active) return;
this.rotation.y = 0;
@@ -229,6 +276,11 @@ bkcore.hexgl.ShipControls.prototype.update = function(dt)
angularAmount -= this.touchController.stickVector.x/100 * this.angularSpeed * dt;
rollAmount += this.touchController.stickVector.x/100 * this.rollAngle;
}
if(this.orientationController != null)
{
angularAmount += this.orientationController.beta/45 * this.angularSpeed * dt;
rollAmount -= this.orientationController.beta/45 * this.rollAngle;
}
if(this.key.forward)
this.speed += this.thrust * dt;
@@ -478,6 +530,17 @@ bkcore.hexgl.ShipControls.prototype.collisionCheck = function(dt)
this.speed = 0;
}
// DIRTY GAMEOVER
if(rCol < 128 && lCol < 128)
{
var fCol = this.collisionMap.getPixel(Math.round(pos.x+2), Math.round(pos.z+2)).r;
if(fCol < 128)
{
console.log('GAMEOVER');
this.fall();
}
}
this.speed *= this.collisionSpeedDecrease;
this.speed *= (1-this.collisionSpeedDecreaseCoef*(1-collision.r/255));
this.boost = 0;
+7 -7
View File
@@ -37,11 +37,11 @@ bkcore.hexgl.tracks.Cityscape = {
analyser: null,
pixelRatio: 2048.0 / 6000.0,
load: function(opts, quality)
load: function(opts, quality, mobile)
{
this.lib = new bkcore.threejs.Loader(opts);
if(quality < 1) // LOW
if((quality < 1 && !mobile) || quality < 2) // LOW
{
this.lib.load({
textures: {
@@ -137,9 +137,9 @@ bkcore.hexgl.tracks.Cityscape = {
}
},
buildMaterials: function(quality)
buildMaterials: function(quality, mobile)
{
if(this.quality < 1) // LOW
if((quality < 1 && !mobile) || quality < 2) // LOW
{
this.materials.track = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.diffuse"),
@@ -268,7 +268,7 @@ bkcore.hexgl.tracks.Cityscape = {
}
},
buildScenes: function(ctx, quality)
buildScenes: function(ctx, quality, mobile)
{
// IMPORTANT
this.analyser = this.lib.get("analysers", "track.cityscape.collision");
@@ -311,7 +311,7 @@ bkcore.hexgl.tracks.Cityscape = {
sun.position.set( -4000, 1200, 1800 );
sun.lookAt(new THREE.Vector3());
if(quality > 0)
if(quality > 0 && !mobile)
{
sun.castShadow = true;
sun.shadowCameraNear = 50;
@@ -371,7 +371,7 @@ bkcore.hexgl.tracks.Cityscape = {
boosterLight: boosterLight,
useParticles: false
};
if(quality > 0)
if(quality > 0 && !mobile)
{
fxParams.textureCloud = this.lib.get("textures", "cloud");
fxParams.textureSpark = this.lib.get("textures", "spark");
+74
View File
@@ -0,0 +1,74 @@
CACHE MANIFEST
# v1.0.1-ffos-201302192207
# HexGL by Thibaut Despoulain (BKcore.com)
index.html
css/BebasNeue-webfont.eot
css/BebasNeue-webfont.ttf
css/fonts.css
css/mobile-controls-2.jpg
css/mobile-over.jpg
css/BebasNeue-webfont.svg
css/BebasNeue-webfont.woff
css/mobile-controls-1.jpg
css/mobile.jpg
css/touchcontroller.css
libs/Three.dev.js
libs/ShaderExtras.js
libs/postprocessing/EffectComposer.js
libs/postprocessing/RenderPass.js
libs/postprocessing/BloomPass.js
libs/postprocessing/ShaderPass.js
libs/postprocessing/MaskPass.js
libs/Detector.js
libs/Stats.js
libs/DAT.GUI.min.js
bkcore.coffee/controllers/TouchController.js
bkcore.coffee/controllers/OrientationController.js
bkcore/Timer.js
bkcore/ImageData.js
bkcore/Utils.js
bkcore/threejs/RenderManager.js
bkcore/threejs/Shaders.js
bkcore/threejs/Particles.js
bkcore/threejs/Loader.js
bkcore/hexgl/HUD.js
bkcore/hexgl/RaceData.js
bkcore/hexgl/ShipControls.js
bkcore/hexgl/ShipEffects.js
bkcore/hexgl/CameraChase.js
bkcore/hexgl/Gameplay.js
bkcore/hexgl/tracks/Cityscape.js
bkcore/hexgl/HexGL.js
geometries/bonus/base/base.js
geometries/booster/booster.js
geometries/ships/feisar/feisar.js
geometries/tracks/cityscape/scrapers1.js
geometries/tracks/cityscape/scrapers2.js
geometries/tracks/cityscape/startbanner.js
geometries/tracks/cityscape/start.js
geometries/tracks/cityscape/track.js
geometries/tracks/cityscape/bonus/speed.js
textures/tracks/cityscape/collision.png
textures/tracks/cityscape/diffuse.jpg
textures/tracks/cityscape/height.png
textures/tracks/cityscape/start/diffuse.jpg
textures/tracks/cityscape/start/start.jpg
textures/tracks/cityscape/scrapers2/diffuse.jpg
textures/tracks/cityscape/scrapers1/diffuse.jpg
textures/skybox/dawnclouds/nx.jpg
textures/skybox/dawnclouds/ny.jpg
textures/skybox/dawnclouds/nz.jpg
textures/skybox/dawnclouds/px.jpg
textures/skybox/dawnclouds/pz.jpg
textures/skybox/dawnclouds/py.jpg
textures/ships/feisar/diffuse.jpg
textures/ships/feisar/booster/booster.png
textures/ships/feisar/booster/boostersprite.jpg
textures/bonus/base/diffuse.jpg
textures/particles/cloud.png
textures/particles/damage.png
textures/particles/spark.png
textures/hud/hud-bg.png
textures/hud/hex.jpg
textures/hud/hud-fg-speed.png
textures/hud/hud-fg-shield.png
Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

+117
View File
@@ -0,0 +1,117 @@
<!doctype html>
<html lang="en" manifest="cache.appcache">
<head>
<title>HexGL dev page</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="css/fonts.css" type="text/css" charset="utf-8">
<style>
body {
background:#ccc;
padding:0;
margin:0;
overflow:hidden;
font-family:georgia;
text-align:center;
color: #666;
}
h1 {color: #666 ; }
a { color:skyblue }
canvas { pointer-events:none; }
#overlay{
position: absolute;
z-index: 9999;
top: 0;
left: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="overlay"></div>
<div id="main"></div>
<script src="libs/Three.dev.js"></script>
<script src="libs/ShaderExtras.js"></script>
<script src="libs/postprocessing/EffectComposer.js"></script>
<script src="libs/postprocessing/RenderPass.js"></script>
<script src="libs/postprocessing/BloomPass.js"></script>
<script src="libs/postprocessing/ShaderPass.js"></script>
<script src="libs/postprocessing/MaskPass.js"></script>
<script src="libs/Detector.js"></script>
<script src="libs/Stats.js"></script>
<script src="libs/DAT.GUI.min.js"></script>
<script src="bkcore.coffee/controllers/TouchController.js"></script>
<script src="bkcore.coffee/controllers/OrientationController.js"></script>
<script src="bkcore/Timer.js"></script>
<script src="bkcore/ImageData.js"></script>
<script src="bkcore/Utils.js"></script>
<script src="bkcore/threejs/RenderManager.js"></script>
<script src="bkcore/threejs/Shaders.js"></script>
<script src="bkcore/threejs/Particles.js"></script>
<script src="bkcore/threejs/Loader.js"></script>
<script src="bkcore/hexgl/HUD.js"></script>
<script src="bkcore/hexgl/RaceData.js"></script>
<script src="bkcore/hexgl/ShipControls.js"></script>
<script src="bkcore/hexgl/ShipEffects.js"></script>
<script src="bkcore/hexgl/CameraChase.js"></script>
<script src="bkcore/hexgl/Gameplay.js"></script>
<script src="bkcore/hexgl/tracks/Cityscape.js"></script>
<script src="bkcore/hexgl/HexGL.js"></script>
<script>
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var container, hudcontainer;
var hexGL;
function init() {
hudcontainer = document.getElementById("overlay");
container = document.getElementById("main");
hexGL = new bkcore.hexgl.HexGL({
document: document,
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
container: container,
overlay: overlay,
quality: bkcore.Utils.getURLParameter('quality'),
difficulty: bkcore.Utils.getURLParameter('difficulty'),
half: bkcore.Utils.getURLParameter('half'),
mode: bkcore.Utils.getURLParameter('mode'),
track: 'Cityscape'
});
hexGL.load({
onLoad: function(){
console.log("ALL LOADED.");
hexGL.init();
hexGL.start();
},
onError: function(s){
console.log("ERROR ON "+s+".");
},
onProgress: function(p, t, n)
{
console.log("LOADED "+t+" : "+n+" ( "+p.loaded+" / "+p.total+" ).");
}
});
}
init();
</script>
</body>
</html>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

+205 -14
View File
@@ -1,13 +1,21 @@
<!doctype html>
<html lang="en">
<html lang="en" manifest="cache.appcache">
<head>
<title>HexGL dev page</title>
<title>HexGL</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="css/fonts.css" type="text/css" charset="utf-8">
<link rel="icon" href="/icon_256.png" type="image/png">
<link rel="shortcut icon" href="/icon_256.png" type="image/png">
<style>
html { background: #000000; }
body {
background:#ccc;
background: url('css/mobile.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
-o-background-size: cover;
background-size: cover;
padding:0;
margin:0;
overflow:hidden;
@@ -17,18 +25,125 @@
}
h1 {color: #666 ; }
a { color:skyblue }
canvas { pointer-events:none; }
#overlay{
/*canvas { pointer-events:none; }*/
html, body, #main, #titles, #controls, #over, #loading, canvas { width: 100%; height: 100%;}
#overlay, #titles, #controls-1, #controls-2, #over, #loading {
position: absolute;
z-index: 9999;
z-index: 1000;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
#titles{
z-index: 1001;
}
#controls-1{
z-index: 1002;
background: url('css/mobile-controls-1.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
-o-background-size: cover;
background-size: cover;
display: none;
}
#controls-2{
z-index: 1003;
background: url('css/mobile-controls-2.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
-o-background-size: cover;
background-size: cover;
display: none;
}
#over{
z-index: 1004;
background: url('css/mobile-over.jpg') no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
-o-background-size: cover;
background-size: cover;
display: none;
}
#loading{
display: none;
color: #fff;
}
#loading div{
position: absolute;
bottom: 20px;
right: 20px;
text-align: right;
font-size: 3em;
font-weight: bold;
font-family: arial, sans-serif;
}
#titles-logo{
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 40%;
text-align: center;
font-size: 4em;
font-weight: bold;
font-family: arial, sans-serif;
text-decoration: none;
color: #444444;
text-indent: -99999px;
}
#titles-logo div{
display: block;
top: 50%;
position: absolute;
margin-top: -40px;
line-height: 80px;
width: 100%;
text-align: center;
}
#titles-buttons{
position: absolute;
left: 60%;
width: 40%;
height: 100%;
border: none;
border-collapse: collapse;
}
#titles-button tr td{
}
.titles-button{
vertical-align: middle;
text-align: center;
font-size: 2em;
font-weight: bold;
font-family: arial, sans-serif;
text-decoration: none;
color: #ffffff;
cursor: pointer;
}
.titles-button:active, .titles-button:focus{
color: skyblue;
}
</style>
<link rel="stylesheet" href="css/touchcontroller.css" type="text/css" charset="utf-8">
</head>
<body>
<div id="titles">
<div id="titles-logo"><div>HexGL</div></div>
<table id="titles-buttons">
<tr><td class="titles-button" id="s-quality" onclick="rollQuality();">QUALITY: SD</td></tr>
<tr><td class="titles-button" id="s-controls" onclick="rollControls();">CONTROLS: TOUCH</td></tr>
<tr><td class="titles-button" onclick="init();">START</td></tr>
</table>
</div>
<div id="controls-1" onclick="start();"></div>
<div id="controls-2" onclick="start();"></div>
<div id="over" onclick="restart();"></div>
<div id="loading"><div>Loading...</div></div>
<div id="overlay"></div>
<div id="main"></div>
@@ -43,6 +158,9 @@
<script src="libs/Stats.js"></script>
<script src="libs/DAT.GUI.min.js"></script>
<script src="bkcore.coffee/controllers/TouchController.js"></script>
<script src="bkcore.coffee/controllers/OrientationController.js"></script>
<script src="bkcore/Timer.js"></script>
<script src="bkcore/ImageData.js"></script>
<script src="bkcore/Utils.js"></script>
@@ -64,6 +182,32 @@
<script src="bkcore/hexgl/HexGL.js"></script>
<script>
try {
var request = navigator.mozApps.getSelf();
request.onsuccess = function() {
if (request.result) {
// we're installed
} else {
// not installed
var conf = confirm('Would you like to install HexGL as an app?');
if(conf)
{
var irequest = navigator.mozApps.install("http://ffos.hexgl.bkcore.com/package.webapp");
irequest.onsuccess = function() {
alert('HexGL is now installed. Please launch the app from the homescreen to cache assets.');
};
irequest.onerror = function(e) {
alert('Error: '+irequest.error.name);
};
}
}
};
request.onerror = function() {
console.warn('Error checking installation status: ' + this.error.message);
};
}catch(e){
//TODO
}
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
@@ -72,9 +216,52 @@
var hexGL;
var q = 0, qmax = 2, c = 1, cmax = 2;
var sq = ['SD', 'HD', 'ULTRA'];
var sc = ['NONE', 'TOUCH', 'MOTION'];
var titles = document.getElementById("titles")
var hudcontainer = document.getElementById("overlay");
var gameover = document.getElementById("over");
var controls1 = document.getElementById("controls-1");
var controls2 = document.getElementById("controls-2");
var squality = document.getElementById("s-quality");
var scontrols = document.getElementById("s-controls");
var loading = document.getElementById("loading");
var container = document.getElementById("main");
function rollQuality() {
q++;
if(q > qmax) q = 0;
squality.innerHTML = "QUALITY: " + sq[q];
}
function rollControls() {
c++;
if(c > cmax) c = 1;
scontrols.innerHTML = "CONTROLS: " + sc[c];
}
function init() {
hudcontainer = document.getElementById("overlay");
container = document.getElementById("main");
titles.style.display = "none";
this['controls'+c].style.display = "block";
}
function restart() {
/*titles.style.display = "block";
gameover.style.display = "none";*/
location.reload(false);
}
function start() {
controls1.style.display = "none";
controls2.style.display = "none";
container.style.display = "block";
loading.style.display = "block";
quality = q < 2 ? 0 : 1;
half = q < 1;
hexGL = new bkcore.hexgl.HexGL({
document: document,
@@ -82,17 +269,21 @@
height: SCREEN_HEIGHT,
container: container,
overlay: overlay,
quality: bkcore.Utils.getURLParameter('quality'),
difficulty: bkcore.Utils.getURLParameter('difficulty'),
half: bkcore.Utils.getURLParameter('half'),
mode: bkcore.Utils.getURLParameter('mode'),
track: 'Cityscape'
gameover: gameover,
quality: quality,
track: 'Cityscape',
hud: false,
half: half,
mobile: true,
controlType: c,
godmode: true
});
hexGL.load({
onLoad: function(){
console.log("ALL LOADED.");
hexGL.init();
loading.style.display = "none";
hexGL.start();
},
onError: function(s){
@@ -105,7 +296,7 @@
});
}
init();
//init();
</script>
+717
View File
File diff suppressed because one or more lines are too long
+212
View File
@@ -0,0 +1,212 @@
var pgli = pgli || {};
pgli.App = gamecore.Base.extend("App",
{ // static
},
{ // instance
project: null,
moduleList: null,
editor: null,
diagram: null,
preview: null,
nodeCount: 0,
console: null,
debug: 2, // 0:none, 1:inapp, 2:console, 3:both
init: function(domDiagram, domModuleList, domEditor, domPreview)
{
var self = this;
this.moduleList = new pgli.ui.ModuleList(domModuleList);
this.editor = ace.edit(domEditor);
this.editor.setFontSize("16px");
this.editor.setTheme("ace/theme/monokai");
this.editor.getSession().setMode("ace/mode/json");
this.diagram = new pgli.diagram.Diagram(domDiagram, 30);
this.preview = new pgli.render.CanvasRenderer(domPreview);
this.console = $('#console-text');
this.bindEvents();
pgli.lang.Parser.debug = self.debug;
window.trace = function(args)
{
if(!self.debug) return;
for(var i=0, len=arguments.length; i<len; ++i)
{
if(self.debug < 2) console.log(arguments[i]);
if(self.debug == 1 || self.debug == 3) return;
self.console.append(arguments[i].toString()+"\n");
self.console.scrollTop(
self.console[0].scrollHeight - self.console.height()
);
};
}
window.clearTrace = function()
{
self.console.text("");
}
},
bindEvents: function()
{
var self = this;
$(window).on('resize', function(){ return self.resize.call(self); });
$(document).bind('keydown', function(e){ return self.onKeyDown.call(self,e); });
$('#modules').on('drop', function(e) { return self.onDropEvent.call(self,e); });
//window.addEventListener("drop",function(e){ return self.onDropEvent.call(self,e); }) ;
},
bindProject: function(project)
{
this.nodeCount = 0;
this.project = project;
this.project.setAppInstance(this);
this.moduleList.bindProject(project);
this.preview.bindProject(project);
this.draw();
},
draw: function()
{
this.moduleList != undefined && this.moduleList.draw();
//this.preview.draw();
},
showInEditor: function(module)
{
this.project.setActiveFile(module);
this.editor.getSession().setValue(this.project.files.get(module));
},
getEditorContent: function()
{
return this.editor.getSession().getValue();
},
addDiagramNode: function(key, module)
{
this.diagram.addNode(new pgli.diagram.Node(key, module, 50 + 160 * this.nodeCount++, 50));
},
resize: function()
{
this.diagram.resize();
this.preview.resize();
},
saveModule: function()
{
for(var i=0; i<this.project.keys.length;i++)
{
var name = this.project.keys[i]
var fileToSave = this.project.getModule(name);
var jsonData = {file :'files/'+name ,obj: fileToSave};
$.ajax({
url:"/",
type:"POST",
data: JSON.stringify(jsonData),
contentType: "application/json; charset=utf-8",
dataType: "text",
success:function(a)
{
console.log("AJAX POST OK: ", a);
},
error: function(a)
{
console.log("AJAX POST ERROR: ", a);
}
});
console.log("STARTED AJAX REQUEST");
}
},
onKeyDown: function(e)
{
if(e.keyCode==117)
{
this.updateDiagram();
e.preventDefault();
return false;
}
else if(e.keyCode==118)
{
this.preview.draw();
e.preventDefault();
return false;
}
else if(e.keyCode==119)
{
this.saveModule();
e.preventDefault();
return false;
}
},
updateDiagram:function()
{
this.project.rememberActiveFile();
for(var i = 0, len = this.project.keys.length; i<len; i++)
{
var object = pgli.lang.Parser.parseModule(this.project.files.get(this.project.keys[i]));
this.project.modules.put(this.project.keys[i], object);
this.diagram.getNode(this.project.keys[i]).module = object;
//this.getNode.updateModule()...
}
this.diagram.draw();
},
onDropEvent: function(e)
{
trace("#Parsing dropped file(s)...");
e.preventDefault();
var self = this;
var length = e.originalEvent.dataTransfer.files.length;
for (var i = 0; i < length; i++)
{
var file = e.originalEvent.dataTransfer.files[i];
console.log(file);
fileName = file.name;
if(i == 0 && this.project == null)
{
var path = window.prompt("Please prove project's root path (with trailing slash).", "../files/");
trace("#Opening new project from ["+fileName+"]...");
this.bindProject(new pgli.Project(path+fileName, function(){
self.draw();
self.showInEditor(self.project.root);
}));
}
else
this.project.loadFile(self.project.path+fileName,fileName,true,true);
}
this.draw();
return false;
}
});
+389
View File
@@ -0,0 +1,389 @@
var pgli = pgli || {};
pgli.render = pgli.render || {};
pgli.render.CanvasRenderer = gamecore.Base.extend('CanvasRenderer',
{ // static
SCOPE_KEYWORDS: {
'use': 0,
'repeat': 1,
'comment': 2
},
SCOPE_XFORMS: {
'x': 1,
'y': 2,
'width': 3,
'height': 4,
'scale': 0
},
REPEAT_TYPES: {
'none': 'no-repeat',
'x': 'repeat-x',
'y': 'repeat-y',
'xy': 'repeat'
}
},
{ // instance
dom: null,
container: null,
canvas: null,
context: null,
width: 1024,
height: 768,
project: null,
xform: [],
xseek: -1,
scope: [],
sseek: -1,
resources: {
images: []
},
variables: null,
/**
* Bind a new renderer to given canvas
* @param jQuery.DOMElement domElement [description]
* @param Integer width [description]
* @param Integer height [description]
*/
init: function(domElement)
{
this.dom = domElement;
this.container = $('#'+this.dom);
this.canvas = document.createElement("Canvas");
this.container.append(this.canvas);
this.resize();
this.variables = new gamecore.Hashtable();
},
draw: function()
{
clearTrace();
if(!this.project)
{
trace("#Render failed: No project loaded");
return;
}
trace("#Starting renderer...");
this.context.clearRect(0, 0, this.width, this.height);
var ratio = this.getRenderRatio();
var root = this.project.getRootModule();
var w = root.width*ratio;
var h = root.height*ratio;
var x = Math.round((this.width - w)/2);
var y = Math.round((this.height - h)/2);
this.sreset();
this.xreset(ratio, x, y, w, h);
this.walkModule(root);
},
walkModule: function(module)
{
if(!module) return;
trace("#Render: "+module.name);
if("params" in module) for(p in module.params)
this.sset(p, module.params[p]);
if("vars" in module)
this.actionVars(module.vars);
if("fill" in module)
this.actionFill(module.fill);
if("layers" in module) for(var i=0, len=module.layers.length; i<len; ++i)
{
var layer = module.layers[i];
if("use" in layer)
{
if("repeat" in layer)
{
var iterator;
try {
iterator = pgli.lang.Parser.parseRepeat(layer.repeat, this.sget());
trace("# Found repeat layer ["+iterator.varname+" from "+iterator.start+" to "+iterator.end+"]");
} catch(e) {
trace("(!) Syntax error in repeat expression ["+layer.repeat+"]");
continue;
}
while(iterator.loop())
{
this.sset(iterator.varname, iterator.step);
this.walkLayer(layer);
iterator.next();
}
}
else
{
this.walkLayer(layer);
}
}
}
},
walkLayer: function(layer)
{
var static = pgli.render.CanvasRenderer;
this.xpush();
this.spush();
for(k in layer)
{
if(k in static.SCOPE_KEYWORDS)
continue;
else if(k in static.SCOPE_XFORMS)
{
var val = pgli.lang.Parser.parseExpression(layer[k], this.sget(), this.xget());
if(typeof(val) == "number")
{
val = Number(val)*this.xgetr();
}
else
{
var p = val.search("%");
if(p > 0)
val = (Number(val.substr(O, p))/100)*this.xget()[static.SCOPE_XFORMS[k]];
else continue;
}
if(k == "x" || k == "y")
{
val += this.xget()[static.SCOPE_XFORMS[k]];
}
this.xset(static.SCOPE_XFORMS[k], val);
}
else
this.sset(k, pgli.lang.Parser.parseExpression(layer[k], this.sget()), this.xget());
}
this.walkModule(this.project.getModule(layer.use));
this.spop();
this.xpop();
},
actionVars: function(opts)
{
var static = pgli.render.CanvasRenderer;
for(k in opts)
{
if(k in static.SCOPE_KEYWORDS || k in static.SCOPE_XFORMS)
continue;
else
this.sset(k, pgli.lang.Parser.parseExpression(opts[k], this.sget(), this.xget()));
}
},
actionFill: function(opts)
{
var static = pgli.render.CanvasRenderer;
if(opts.type == "image")
{
//trace("# Fill(image)...")
var image = this.loadImage(
pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget())
);
if("repeat" in opts && opts.repeat in static.REPEAT_TYPES)
{
var pattern = this.context.createPattern(image, static.REPEAT_TYPES[opts.repeat]);
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
this.context.fillStyle = pattern;
this.context.fill();
//pattern = null;
}
else
{
this.context.drawImage(image, this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
}
}
else if(opts.type == "color")
{
//trace("# Fill(color)...")
this.context.beginPath();
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
this.context.fillStyle = pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget());
this.context.fill();
}
else if(opts.type == "line")
{
//trace("# Fill(line)...")
this.context.beginPath();
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
this.context.lineWidth = 1;
this.context.strokeStyle = pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget());
this.context.stroke();
}
},
loadImage: function(url)
{
var self = this;
if(url in this.resources.images)
{
return this.resources.images[url];
}
else
{
trace("/!\\ Image is loading, will redraw onload.");
var img = new Image();
img.onload = function(){
trace("#Image loaded, redrawing...");
self.draw();
};
img.src = url;
this.resources.images[url] = img;
return img;
}
},
spush: function()
{
this.scope.push(this.cloneScope(this.sget()));
this.sseek++;
},
spop: function()
{
this.sseek--;
return this.scope.pop();
},
sreset: function()
{
this.scope = [{}];
this.sseek = 0;
},
sget: function()
{
return this.scope[this.sseek];
},
sset: function(key, value)
{
this.scope[this.sseek][key] = value;
},
xpush: function(ratio, x, y, h, w)
{
if(ratio == undefined)
if(this.xseek == -1)
this.xform.push([1.0, 0, 0, this.width, this.height]);
else
this.xform.push(this.xget().slice(0))
else
this.xform.push([ratio, x, y, h, w]);
this.xseek++;
},
xpop: function()
{
this.xseek--;
return this.xform.pop();
},
xget: function()
{
return this.xform[this.xseek];
},
xset: function(key, value)
{
this.xform[this.xseek][key] = value;
},
xreset: function(ratio, x, y, h, w)
{
this.xseek = -1;
this.xform = [];
this.xpush(ratio, x, y, h, w);
},
xgetr: function()
{
return this.xform[this.xseek][0];
},
xgetx: function()
{
return this.xform[this.xseek][1];
},
xgety: function()
{
return this.xform[this.xseek][2];
},
xgetw: function()
{
return this.xform[this.xseek][3];
},
xgeth: function()
{
return this.xform[this.xseek][4];
},
cloneScope: (function()
{
return function (obj) { Clone.prototype=obj; return new Clone() };
function Clone(){}
}()),
bindProject: function(project)
{
this.project = project;
},
resize: function()
{
var w = this.container.width();
var h = this.container.height();
var size = 0.9*Math.min(w, h);
this.width = size;
this.height = size;
var $canvas = $(this.canvas);
$canvas.width(size);
$canvas.height(size);
this.canvas.width = size;
this.canvas.height = size;
$canvas.css('marginTop', this.container.height() / 2 - size / 2);
$canvas.css('marginLeft', this.container.width() / 2 - size / 2);
this.context = this.canvas.getContext("2d");
/*var ctx = this.canvas.getContext("2d");
ctx.clearRect(0, 0, size, size);
ctx.canvas.width = ctx.canvas.height = size;
ctx.font = 'bold 40px Arial';
ctx.textAlign = 'center';
ctx.fillStyle = '#444';
ctx.fillText("Preview", size/2, size/2);*/
},
getRenderRatio: function()
{
var root = this.project.getRootModule();
if(!root) return;
return Math.min(this.width/root.width, this.height/root.height);
}
});
+148
View File
@@ -0,0 +1,148 @@
var pgli = pgli || {};
pgli.diagram = pgli.diagram || {};
pgli.diagram.Diagram = gamecore.Base.extend('Diagram',
{ // static
},
{ // instance
dom: null,
container: null,
width: 1024,
height: 768,
timer: null,
redrawDelay: 1000/30,
stage: null,
layers: {
background: null,
nodes: null,
links: null
},
background: null,
links: null,
project: null,
nodes: [],
/**
* Bind a new renderer to given canvas
* @param HTMLElement domContainer [description]
* @param Integer width [description]
* @param Integer height [description]
* @param Integer autoRedraw If defined, sets redraw rate to given FPS
*/
init: function(domContainer, autoRedraw)
{
var self = this;
this.dom = domContainer;
this.container = $('#'+domContainer);
this.width = this.container.width();
this.height = this.container.height();
this.stage = new Kinetic.Stage({
container: this.dom,
width: this.width,
height: this.height
});
this.layers.background = new Kinetic.Layer();
this.layers.nodes = new Kinetic.Layer();
this.layers.links = new Kinetic.Layer();
this.background = new Kinetic.Rect({
width: this.width,
height: this.height,
fill: "#272822"
});
this.layers.background.add(this.background);
this.links = new pgli.diagram.Links(this);
this.layers.links.add(this.links.shape);
this.stage.add(this.layers.background);
this.stage.add(this.layers.nodes);
this.stage.add(this.layers.links);
// Stage drag hack to trigger only on background drag
var self = this;
this.background.on("mousedown", function(){
self.stage.setDraggable(true);
self.stage.on("dragmove", function(){
self.layers.background.setX(-this.getX());
self.layers.background.setY(-this.getY());
});
self.stage.on("dragend", function(){
this.off("dragend");
this.off("dragmove");
this.setDraggable(false);
});
});
if(autoRedraw != undefined && autoRedraw != false && autoRedraw > 0)
{
this.redrawDelay = 1000 / autoRedraw;
this.timer = new bkcore.Timer();
this.timer.start();
this.autoRedraw(true);
}
},
addNode: function(node)
{
this.nodes.push(node);
this.layers.nodes.add(node.shape);
this.layers.nodes.draw();
},
getNode: function(nodeKey)
{
var i = 0, len = this.nodes.length;
while(i < len)
{
if(this.nodes[i].key == nodeKey)
return this.nodes[i];
i++;
}
console.warn("Error in Diagram: Unable to find node["+nodeKey+"]");
return false;
},
draw: function()
{
this.layers.background.draw();
this.layers.nodes.draw();
this.layers.links.draw();
},
autoRedraw: function(keep)
{
var self = this;
if(this.timer.update() > this.redrawDelay)
{
this.timer.start();
this.draw();
}
if(keep)
requestAnimFrame(function(){
self.autoRedraw(true);
});
},
resize: function()
{
this.width = this.container.width();
this.height = this.container.height();
this.stage.setSize(this.width, this.height);
this.background.setSize(this.width, this.height);
this.draw();
}
});
+92
View File
@@ -0,0 +1,92 @@
var pgli = pgli || {};
pgli.lang = pgli.lang || {};
pgli.lang.Iterator = gamecore.Base.extend('Iterator',
// Static
{
MAX_ITERATIONS: 1000,
COMPARATORS: {
"<": 0,
">": 1,
"<=": 2,
">=": 3
},
genComparatorMethod: function(type)
{
switch(type)
{
case 0:
return function(a, b){ return a < b };
case 1:
return function(a, b){ return a > b };
case 2:
return function(a, b){ return a <= b };
case 3:
return function(a, b){ return a >= b };
default:
return function(a, b){ return false };
}
},
genStepMethod: function(type, scope, attr)
{
switch(type)
{
case 1:
case 3:
return function(){ return --scope[attr] };
case 0:
case 2:
default:
return function(){ return ++scope[attr] };
}
}
},
// Instance
{
varname: "i",
start: 0,
end: 1,
comparator: 0,
compMethod: null,
stepMethod: null,
step: 0,
iter: 0,
init: function(name, start, comparator, end)
{
var static = pgli.lang.Iterator;
if(comparator in static.COMPARATORS)
this.comparator = static.COMPARATORS[comparator];
else
this.comparator = static.COMPARATORS["<"];
this.start = start;
this.end = end;
this.step = start;
this.varname = name;
this.compMethod = static.genComparatorMethod(this.comparator);
this.stepMethod = static.genStepMethod(this.comparator, this, "step");
},
loop: function()
{
return (this.iter < pgli.lang.Iterator.MAX_ITERATIONS && this.compMethod(this.step, this.end));
},
next: function()
{
++this.iter;
return this.stepMethod();
},
toString: function()
{
return "Iterator("+this.varname+") "+this.start+" - "+this.step+" - "+this.end;
}
});
+56
View File
@@ -0,0 +1,56 @@
var pgli = pgli || {};
pgli.diagram = pgli.diagram || {};
pgli.diagram.Links = gamecore.Base.extend('Links',
{ // static
bezierOffset: 50
},
{ // instance
diagram: null,
shape: null,
init: function(diagram)
{
var static = pgli.diagram.Links;
var self = this;
this.diagram = diagram;
this.shape = new Kinetic.Shape({
drawFunc: function(ctx){
ctx.beginPath();
for(var i = 0, len = self.diagram.nodes.length; i < len; i++)
{
var node = self.diagram.nodes[i];
if(! ("layers" in node.module)) continue;
for(var j = 0, _len = node.module.layers.length; j < _len; j++)
{
if(! ("use" in node.module.layers[j])) continue;
var start = node.getLayerSlot(j);
var tNode = self.diagram.getNode(node.module.layers[j].use);
if(!tNode) continue;
var end = tNode.getSlot();
ctx.moveTo(start[0], start[1]);
ctx.bezierCurveTo(
start[0]+static.bezierOffset, start[1],
end[0]-static.bezierOffset, end[1],
end[0], end[1]);
}
}
this.stroke(ctx);
},
x: 0,
y: 0,
stroke: "#999",
strokeWidth: 3,
lineCap: "round"
});
}
});
+47
View File
@@ -0,0 +1,47 @@
var pgli = pgli || {};
pgli.ui = pgli.ui || {};
pgli.ui.ModuleList = gamecore.Base.extend('ModuleList',
{ // static
tplModuleItem: "<li data-path='$path'>$name</li>",
tplModuleList: "<ul data-path='$path'>$list</ul>"
},
{ // instance
project: null,
container: null,
init: function(domContainer)
{
this.container = $('#'+domContainer);
this.container.on("click", "li", {object: this}, this.onModuleClick);
},
bindProject: function(project)
{
this.project = project;
},
draw: function()
{
var static = pgli.ui.ModuleList;
var modules = "";
var module = null;
if(!this.project.isEmpty()) for(var i = 0, len = this.project.getModulesCount(); i < len; ++i)
{
key = this.project.getModuleKey(i);
module = this.project.getModule(key);
modules += static.tplModuleItem.replace("$path", key).replace("$name", key);
}
this.container.html(static.tplModuleList.replace("$list", modules));
},
onModuleClick: function(event)
{
event.data.object.project.rememberActiveFile();
event.data.object.project.getAppInstance().showInEditor($(this).attr("data-path"));
event.data.object.container.find('li').removeClass('active');
$(this).addClass('active');
}
});
+122
View File
@@ -0,0 +1,122 @@
var pgli = pgli || {};
pgli.diagram = pgli.diagram || {};
pgli.diagram.Node = gamecore.Base.extend('Node',
{ // static
layersWidth: 20,
layersMargin: 20,
layersHeight: 16,
headerHeight: 40,
slotX: 10,
slotY: 14,
slotRadius: 6
},
{ // instance
module: null,
key: null,
shape: null,
background: null,
name: null,
layers: null,
slot: null,
sockets: [],
width: 150,
height: 200,
init: function(key, module, x, y)
{
var static = pgli.diagram.Node;
this.key = key;
this.module = module;
this.shape = new Kinetic.Group({
x: x == undefined ? 0 : x,
y: y == undefined ? 0 : y,
draggable: true
});
var layerCount = (module.layers != undefined ? module.layers.length : 0) + 1;
this.height = static.headerHeight + layerCount * static.layersHeight;
this.background = new Kinetic.Rect({
x: 0,
y: 0,
width: this.width,
height: this.height,
fill: "#222",
stroke: "#000",
strokeWidth: 0.5,
shadow: {
color: "black",
blur: 6,
offset: [0, 0],
opacity: 0.5
}
});
this.layers = new Kinetic.Shape({
drawFunc: function(ctx){
ctx.beginPath();
for(var i=0, len = this.attrs.count; i < len; ++i)
ctx.arc(10, 10+i*static.layersHeight, static.slotRadius, 0, Math.PI*2, true);
ctx.closePath();
this.fill(ctx);
},
x: this.width-static.layersWidth,
y: static.layersMargin,
count: layerCount,
fill: "#111"
});
this.slot = new Kinetic.Circle({
x: static.slotX,
y: static.slotY,
radius: static.slotRadius,
fill: "#111"
});
this.name = new Kinetic.Text({
x: 20,
y: 6,
text: module.name,
fontSize: 13,
fontFamily: "Ubuntu Mono",
textFill: "#aaa"
});
this.shape.on('mousedown', function(){
this.moveToTop();
});
this.shape.add(this.background);
this.shape.add(this.name);
this.shape.add(this.layers);
this.shape.add(this.slot);
},
updateLayers: function()
{
var layerCount = (module.layers != undefined ? module.layers.length : 0) + 1;
this.layers.attrs.count = layerCount;
},
getSlot: function()
{
var static = pgli.diagram.Node;
return [this.shape.getX()+static.slotX,
this.shape.getY()+static.slotY];
},
getLayerSlot: function(index)
{
var static = pgli.diagram.Node;
return [this.shape.getX()+this.width-static.layersWidth/2,
this.shape.getY()+10+index*static.layersHeight+static.layersMargin];
}
});
+140
View File
@@ -0,0 +1,140 @@
var pgli = pgli || {};
pgli.lang = pgli.lang || {};
pgli.lang.Parser = gamecore.Base.extend('Parser',
{
xStruct: {
"scale": 0,
"x": 1,
"y": 2,
"width": 3,
"height": 4
},
patternVar:/\@(\w+)/g,
patternMethod: /\#(\w+)(\(([^\)]+)\))/g,
debug: 1,
parseExpression: function(string, scope, xform)
{
static = pgli.lang.Parser;
var self = this;
var orig = string;
var s = (scope !== null && typeof(scope) !== "undefined")
var x = (xform !== null && typeof(xform) !== "undefined" && xform.length > 0)
if(typeof(string) != "string")
return string;
if(scope != undefined)
{
string = string.replace(this.patternVar,function(match,varName)
{
if(x && varName in static.xStruct)
return xform[static.xStruct[varName]];
else if(s && varName in scope)
return scope[varName]
else
return 0
});
}
string = string.replace(this.patternMethod,function(match,methodName,a,params)
{
if(self.debug < 2) console.log(arguments);
return self.execFunction(methodName, params);
});
if(self.debug < 2) console.log("#Parsed expr: '"+string+"' from '"+orig+"'");
try {
return eval(string);
} catch (e) {
return string;
}
},
parseRepeat: function(string, scope)
{
var items = string.split(" ");
if(items.length != 4)
throw "Syntax error in repeat expression";
if(self.debug < 2) console.warn(items[0].substr(1))
if(self.debug < 2) console.warn(Number(this.parseExpression(items[1], scope)))
if(self.debug < 2) console.warn(items[2])
if(self.debug < 2) console.warn(Number(this.parseExpression(items[3], scope)))
return new pgli.lang.Iterator(
items[0].substr(1),
Number(this.parseExpression(items[1], scope)),
items[2],
Number(this.parseExpression(items[3], scope))
);
},
parseModule: function(string)
{
try
{
return JSON.parse(string);
}
catch(e)
{
trace("(!) Syntax error in module.");
return {error:"unable to parse module"};
}
},
execFunction: function(methodName, params)
{
var hasP = params != undefined;
var p = hasP ? params.replace(" ", "").split(',') : [];
if(methodName == "random")
{
var r = Math.random();
if(hasP && p.length == 2) try
{
var min = eval(p[0]);
var max = eval(p[1]);
r = Math.round(r * (max-min) + min);
} catch(e) {
console.warn('Bad method format: '+methodName+' / '+params);
return 0;
}
return r;
}
else if(methodName == "mod")
{
if(hasP && p.length == 2) try
{
var base = eval(p[0]);
var div = eval(p[1]);
if(div == 0) throw "Divide by 0";
return Math.floor(base/div);
} catch(e) {
console.warn('Bad method format: '+methodName+' / '+params);
}
return 0;
}
else
{
console.warn("Unsupported method : "+methodName);
return 0;
}
}
},
{
});
+162
View File
@@ -0,0 +1,162 @@
var pgli = pgli || {};
pgli.Project = gamecore.Base.extend('Project',
{
patternRoot: /\/([a-z]+\.pmod)/ig,
patternPath: /([a-z\/]+\/)[a-z]+\.pmod/ig
},
{
appInstance: null,
modules: null,
activeFile: null,
files:null,
keys :[],
name: "default",
path: "/files/",
root: "default.pmod",
diagram: null,
loadingQueue: [],
onLoad: function() { console.log("Project loaded."); },
init : function(projectFile, onLoad)
{
this.onLoad = onLoad;
this.modules = new gamecore.Hashtable();
this.files = new gamecore.Hashtable();
this.path = pgli.Project.patternPath.exec(projectFile)[1];
this.root = pgli.Project.patternRoot.exec(projectFile)[1];
var self = this;
this.loadFile(projectFile,this.root,true,true);
},
loadFile: function(path,name,doDependencies,doDiagram)
{
trace("#Loading ["+name+"].");
var self = this;
var request = $.ajax({
url: path,
type: 'get',
dataType: "text",
})
.success(function(data)
{
self.files.put(name, data);
self.keys.push(name);
var object = pgli.lang.Parser.parseModule(data);
self.modules.put(name, object);
if(doDependencies == true)
self.loadDependencies(object);
if(doDiagram == true)
self.getAppInstance().addDiagramNode(name, object);
trace("#["+name+"] loaded");
self.onLoad();
})
.error(function()
{
throw "Unable to load file: " + path;
});
},
loadDependencies: function(object)
{
if(!("layers" in object))
return;
var layers = object.layers;
var self = this;
for (var i=0, len = layers.length; i<len ; i++)
{
if(!("use" in layers[i]) )
continue;
var layerName = layers[i].use;
trace("#Found dependency ["+layerName+"]");
(function(name,self)
{
self.loadFile(self.path+name,name,true,true);
})(layerName,self);
}
},
getModulesCount: function()
{
return this.keys.length;
},
getModule: function(key)
{
return this.modules.get(key);
},
getFile: function(key)
{
return this.files.get(key);
},
getModuleKey: function(index)
{
return this.keys[index];
},
getRootModule: function()
{
return this.modules.get(this.root);
},
isEmpty: function()
{
return (this.keys.length <= 0);
},
setAppInstance: function(app)
{
this.appInstance = app;
},
getAppInstance: function()
{
return this.appInstance;
},
setActiveFile: function(key)
{
this.activeFile = key;
},
rememberActiveFile: function()
{
if(!this.activeFile) return;
this.files.put(this.activeFile, this.getAppInstance().getEditorContent());
}
/*updateDiagram: function()
{
},
render: function(canvasRenderer)
{
//canvasRenderer.Render(modules, root, new Hashtable());
}*/
});
+166
View File
@@ -0,0 +1,166 @@
/*!
* @class bkcore.Timer
*
* new Date().getTime() wrapper to use as timers.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/**
* RAF shim
*/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
/*!
* @package bkcore
*/
var bkcore = bkcore || {};
/*!
* Creates a new timer, inactive by default.
* Call Timer.start() to activate.
*/
bkcore.Timer = function()
{
this.time = {
start: 0,
current: 0,
previous: 0,
elapsed: 0,
delta: 0
}
this.active = false;
}
/*!
* Starts/restarts the timer.
*/
bkcore.Timer.prototype.start = function()
{
var now = new Date().getTime();
this.time.start = now;
this.time.current = now;
this.time.previous = now;
this.time.elapsed = 0;
this.time.delta = 0;
this.active = true;
}
/*!
* Restarts timer, returning last ms tick
*/
bkcore.Timer.prototype.restart = function()
{
var now = new Date().getTime();
var e = now - this.time.start;
this.time.start = now;
this.time.current = now;
this.time.previous = now;
this.time.elapsed = 0;
this.time.delta = 0;
this.active = true;
return e;
}
/*!
* Pauses(true)/Unpauses(false) the timer.
*
* @param bool Do pause
*/
bkcore.Timer.prototype.pause = function(bool)
{
this.active = !bool;
}
/*!
* Update method to be called inside a RAF loop
*/
bkcore.Timer.prototype.update = function()
{
if(!this.active) return;
var now = new Date().getTime();
this.time.current = now;
this.time.elapsed = this.time.current - this.time.start;
this.time.delta = now - this.time.previous;
this.time.previous = now;
return this.time.elapsed;
}
/*!
* Returns elapsed milliseconds
*/
bkcore.Timer.prototype.getElapsed = function()
{
return this.time.elapsed;
}
/*!
* Returns a formatted version of the current elapsed time using msToTime().
*
*
*/
bkcore.Timer.prototype.getElapsedTime = function()
{
return bkcore.Timer.msToTime(this.time.elapsed);
}
/*!
* Formats a millisecond integer into a h/m/s/ms object
*
* @param x int In milliseconds
* @return Object{h,m,s,ms}
*/
bkcore.Timer.msToTime = function(t)
{
var ms, s, m, h;
ms = t%1000;
s = Math.floor((t/1000)%60);
m = Math.floor((t/60000)%60);
h = Math.floor((t/3600000));
return {h:h, m:m, s:s, ms:ms};
}
/*!
* Formats a millisecond integer into a h/m/s/ms object with prefix zeros
*
* @param x int In milliseconds
* @return Object<string>{h,m,s,ms}
*/
bkcore.Timer.msToTimeString = function(t)
{
var ms, s, m, h;
ms = t%1000;
if(ms < 10) ms = "00"+ms;
else if(ms < 100) ms = "0"+ms;
s = Math.floor((t/1000)%60);
if(s < 10) s = "0"+s;
m = Math.floor((t/60000)%60);
h = Math.floor((t/3600000));
return {h:h, m:m, s:s, ms:ms};
}
File diff suppressed because one or more lines are too long
+989
View File
@@ -0,0 +1,989 @@
/**
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
* class.js
* Classes and objects
*/
/**
* @Class
* A modified version of class.js to cater to static inheritance and deep object cloning
* Based almost completely on class.js (Javascript MVC -- Justin Meyer, Brian Moschel, Michael Mayer and others)
* (http://javascriptmvc.com/contribute.html)
* Some portions adapted from Prototype JavaScript framework, version 1.6.0.1 (c) 2005-2007 Sam Stephenson
* <p>
* Class system for javascript
* <p>
* <code>
* var Fighter = gamecore.Base.extend('Fighter',
* {
* // static (this is inherited as well)
* firingSpeed: 1000
* },
* {
* // instance
*
* hp: 0,
* lastFireTime: 0,
*
* init: function(hp)
* {
* this.hp = hp;
* },
*
* fire: function()
* {
* this._super(); // super methods!
*
* // do firing!
* }
* });
*
* var gunship = new Fighter(100);
* </code>
*
* Introspection:
* <code>
* gamecore.Base.extend(Fighter.Gunship);
* Fighter.Gunship.shortName; // Gunship
* Fighter.Gunship.fullName; // Fighter.Gunship
* Fighter.Gunship.namespace; // Fighter
* </code>
* <p>
* Setup method will be called prior to any init -- nice if you want to do things without needing the
* users to call _super in the init, as well as for normalizing parameters.
* <code>
* setup: function()
* {
* this.objectId = this.Class.totalObjects++;
* this.uniqueId = this.Class.fullName + ':' + this.objectId;
* }
* </code>
*/
// compatible with jquery classing
(function ($)
{
var regs = {
undHash: /_|-/,
colons: /::/,
words: /([A-Z]+)([A-Z][a-z])/g,
lowUp: /([a-z\d])([A-Z])/g,
dash: /([a-z\d])([A-Z])/g,
replacer: /\{([^\}]+)\}/g,
dot: /\./
},
getNext = function (current, nextPart, add)
{
return current[nextPart] || ( add && (current[nextPart] = {}) );
},
isContainer = function (current)
{
var type = typeof current;
return type && ( type == 'function' || type == 'object' );
},
getObject = function (objectName, roots, add)
{
var parts = objectName ? objectName.split(regs.dot) : [],
length = parts.length,
currents = $.isArray(roots) ? roots : [roots || window],
current,
ret,
i,
c = 0,
type;
if (length == 0)
{
return currents[0];
}
while (current = currents[c++])
{
for (i = 0; i < length - 1 && isContainer(current); i++)
{
current = getNext(current, parts[i], add);
}
if (isContainer(current))
{
ret = getNext(current, parts[i], add);
if (ret !== undefined)
{
if (add === false)
{
delete current[parts[i]];
}
return ret;
}
}
}
},
/**
* @class jQuery.String
*
* A collection of useful string helpers.
*
*/
str = $.String = $.extend($.String || {}, {
/**
* @function
* Gets an object from a string.
* @param {String} name the name of the object to look for
* @param {Array} [roots] an array of root objects to look for the name
* @param {Boolean} [add] true to add missing objects to
* the path. false to remove found properties. undefined to
* not modify the root object
*/
getObject: getObject,
/**
* Capitalizes a string
* @param {String} s the string.
* @return {String} a string with the first character capitalized.
*/
capitalize: function (s, cache)
{
return s.charAt(0).toUpperCase() + s.substr(1);
},
/**
* Capitalizes a string from something undercored. Examples:
* @codestart
* jQuery.String.camelize("one_two") //-> "oneTwo"
* "three-four".camelize() //-> threeFour
* @codeend
* @param {String} s
* @return {String} a the camelized string
*/
camelize: function (s)
{
s = str.classize(s);
return s.charAt(0).toLowerCase() + s.substr(1);
},
/**
* Like camelize, but the first part is also capitalized
* @param {String} s
* @return {String} the classized string
*/
classize: function (s, join)
{
var parts = s.split(regs.undHash),
i = 0;
for (; i < parts.length; i++)
{
parts[i] = str.capitalize(parts[i]);
}
return parts.join(join || '');
},
/**
* Like [jQuery.String.classize|classize], but a space separates each 'word'
* @codestart
* jQuery.String.niceName("one_two") //-> "One Two"
* @codeend
* @param {String} s
* @return {String} the niceName
*/
niceName: function (s)
{
return str.classize(s, ' ');
},
/**
* Underscores a string.
* @codestart
* jQuery.String.underscore("OneTwo") //-> "one_two"
* @codeend
* @param {String} s
* @return {String} the underscored string
*/
underscore: function (s)
{
return s.replace(regs.colons, '/').replace(regs.words, '$1_$2').replace(regs.lowUp, '$1_$2').replace(regs.dash, '_').toLowerCase();
},
/**
* Returns a string with {param} replaced values from data.
*
* $.String.sub("foo {bar}",{bar: "far"})
* //-> "foo far"
*
* @param {String} s The string to replace
* @param {Object} data The data to be used to look for properties. If it's an array, multiple
* objects can be used.
* @param {Boolean} [remove] if a match is found, remove the property from the object
*/
sub: function (s, data, remove)
{
var obs = [];
obs.push(s.replace(regs.replacer, function (whole, inside)
{
//convert inside to type
var ob = getObject(inside, data, typeof remove == 'boolean' ? !remove : remove),
type = typeof ob;
if ((type === 'object' || type === 'function') && type !== null)
{
obs.push(ob);
return "";
} else
{
return "" + ob;
}
}));
return obs.length <= 1 ? obs[0] : obs;
}
});
})(jQuery);
(function ($)
{
// if we are initializing a new class
var initializing = false,
makeArray = $.makeArray,
isFunction = $.isFunction,
isArray = $.isArray,
extend = $.extend,
/**
*
*/
cloneObject = function(object)
{
if (!object || typeof(object) != 'object')
return object;
// special case handling of array (deep copy them)
if (object instanceof Array)
{
var clone = [];
for (var c = 0; c < object.length; c++)
clone[c] = cloneObject(object[c]);
return clone;
}
else // otherwise, it's a normal object, clone it's properties
{
var cloneObj = {};
for (var prop in object)
cloneObj[prop] = cloneObject(object[prop]);
return cloneObj;
}
},
concatArgs = function (arr, args)
{
return arr.concat(makeArray(args));
},
// tests if we can get super in .toString()
fnTest = /xyz/.test(function ()
{
xyz;
}) ? /\b_super\b/ : /.*/,
// overwrites an object with methods, sets up _super
// newProps - new properties
// oldProps - where the old properties might be
// addTo - what we are adding to
inheritProps = function (newProps, oldProps, addTo)
{
addTo = addTo || newProps
for (var name in newProps)
{
// Check if we're overwriting an existing function
addTo[name] = isFunction(newProps[name]) &&
isFunction(oldProps[name]) &&
fnTest.test(newProps[name]) ? (function (name, fn)
{
return function ()
{
var tmp = this._super, ret;
// Add a new ._super() method that is the same method but on the super-class
this._super = oldProps[name];
// The method only need to be bound temporarily, so we remove it when we're done executing
ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, newProps[name]) : newProps[name];
}
},
/**
* @class jQuery.Class
* @plugin jquery/class
* @tag core
* @download dist/jquery/jquery.class.js
* @test jquery/class/qunit.html
*
* Class provides simulated inheritance in JavaScript. Use clss to bridge the gap between
* jQuery's functional programming style and Object Oriented Programming. It
* is based off John Resig's [http://ejohn.org/blog/simple-javascript-inheritance/|Simple Class]
* Inheritance library. Besides prototypal inheritance, it includes a few important features:
*
* - Static inheritance
* - Introspection
* - Namespaces
* - Setup and initialization methods
* - Easy callback function creation
*
*
* ## Static v. Prototype
*
* Before learning about Class, it's important to
* understand the difference between
* a class's __static__ and __prototype__ properties.
*
* //STATIC
* MyClass.staticProperty //shared property
*
* //PROTOTYPE
* myclass = new MyClass()
* myclass.prototypeMethod() //instance method
*
* A static (or class) property is on the Class constructor
* function itself
* and can be thought of being shared by all instances of the
* Class. Prototype propertes are available only on instances of the Class.
*
* ## A Basic Class
*
* The following creates a Monster class with a
* name (for introspection), static, and prototype members.
* Every time a monster instance is created, the static
* count is incremented.
*
* @codestart
* $.Class.extend('Monster',
* /* @static *|
* {
* count: 0
* },
* /* @prototype *|
* {
* init: function( name ) {
*
* // saves name on the monster instance
* this.name = name;
*
* // sets the health
* this.health = 10;
*
* // increments count
* this.Class.count++;
* },
* eat: function( smallChildren ){
* this.health += smallChildren;
* },
* fight: function() {
* this.health -= 2;
* }
* });
*
* hydra = new Monster('hydra');
*
* dragon = new Monster('dragon');
*
* hydra.name // -> hydra
* Monster.count // -> 2
* Monster.shortName // -> 'Monster'
*
* hydra.eat(2); // health = 12
*
* dragon.fight(); // health = 8
*
* @codeend
*
*
* Notice that the prototype <b>init</b> function is called when a new instance of Monster is created.
*
*
* ## Inheritance
*
* When a class is extended, all static and prototype properties are available on the new class.
* If you overwrite a function, you can call the base class's function by calling
* <code>this._super</code>. Lets create a SeaMonster class. SeaMonsters are less
* efficient at eating small children, but more powerful fighters.
*
*
* Monster.extend("SeaMonster",{
* eat: function( smallChildren ) {
* this._super(smallChildren / 2);
* },
* fight: function() {
* this.health -= 1;
* }
* });
*
* lockNess = new SeaMonster('Lock Ness');
* lockNess.eat(4); //health = 12
* lockNess.fight(); //health = 11
*
* ### Static property inheritance
*
* You can also inherit static properties in the same way:
*
* $.Class.extend("First",
* {
* staticMethod: function() { return 1;}
* },{})
*
* First.extend("Second",{
* staticMethod: function() { return this._super()+1;}
* },{})
*
* Second.staticMethod() // -> 2
*
* ## Namespaces
*
* Namespaces are a good idea! We encourage you to namespace all of your code.
* It makes it possible to drop your code into another app without problems.
* Making a namespaced class is easy:
*
* @codestart
* $.Class.extend("MyNamespace.MyClass",{},{});
*
* new MyNamespace.MyClass()
* @codeend
* <h2 id='introspection'>Introspection</h2>
* Often, it's nice to create classes whose name helps determine functionality. Ruby on
* Rails's [http://api.rubyonrails.org/classes/ActiveRecord/Base.html|ActiveRecord] ORM class
* is a great example of this. Unfortunately, JavaScript doesn't have a way of determining
* an object's name, so the developer must provide a name. Class fixes this by taking a String name for the class.
* @codestart
* $.Class.extend("MyOrg.MyClass",{},{})
* MyOrg.MyClass.shortName //-> 'MyClass'
* MyOrg.MyClass.fullName //-> 'MyOrg.MyClass'
* @codeend
* The fullName (with namespaces) and the shortName (without namespaces) are added to the Class's
* static properties.
*
*
* <h2>Setup and initialization methods</h2>
* <p>
* Class provides static and prototype initialization functions.
* These come in two flavors - setup and init.
* Setup is called before init and
* can be used to 'normalize' init's arguments.
* </p>
* <div class='whisper'>PRO TIP: Typically, you don't need setup methods in your classes. Use Init instead.
* Reserve setup methods for when you need to do complex pre-processing of your class before init is called.
*
* </div>
* @codestart
* $.Class.extend("MyClass",
* {
* setup: function() {} //static setup
* init: function() {} //static constructor
* },
* {
* setup: function() {} //prototype setup
* init: function() {} //prototype constructor
* })
* @codeend
*
* <h3>Setup</h3>
* <p>Setup functions are called before init functions. Static setup functions are passed
* the base class followed by arguments passed to the extend function.
* Prototype static functions are passed the Class constructor function arguments.</p>
* <p>If a setup function returns an array, that array will be used as the arguments
* for the following init method. This provides setup functions the ability to normalize
* arguments passed to the init constructors. They are also excellent places
* to put setup code you want to almost always run.</p>
* <p>
* The following is similar to how [jQuery.Controller.prototype.setup]
* makes sure init is always called with a jQuery element and merged options
* even if it is passed a raw
* HTMLElement and no second parameter.
* </p>
* @codestart
* $.Class.extend("jQuery.Controller",{
* ...
* },{
* setup: function( el, options ) {
* ...
* return [$(el),
* $.extend(true,
* this.Class.defaults,
* options || {} ) ]
* }
* })
* @codeend
* Typically, you won't need to make or overwrite setup functions.
* <h3>Init</h3>
*
* <p>Init functions are called after setup functions.
* Typically, they receive the same arguments
* as their preceding setup function. The Foo class's <code>init</code> method
* gets called in the following example:
* </p>
* @codestart
* $.Class.Extend("Foo", {
* init: function( arg1, arg2, arg3 ) {
* this.sum = arg1+arg2+arg3;
* }
* })
* var foo = new Foo(1,2,3);
* foo.sum //-> 6
* @codeend
* <h2>Callbacks</h2>
* <p>Similar to jQuery's proxy method, Class provides a
* [jQuery.Class.static.callback callback]
* function that returns a callback to a method that will always
* have
* <code>this</code> set to the class or instance of the class.
* </p>
* The following example uses this.callback to make sure
* <code>this.name</code> is available in <code>show</code>.
* @codestart
* $.Class.extend("Todo",{
* init: function( name ) { this.name = name }
* get: function() {
* $.get("/stuff",this.callback('show'))
* },
* show: function( txt ) {
* alert(this.name+txt)
* }
* })
* new Todo("Trash").get()
* @codeend
* <p>Callback is available as a static and prototype method.</p>
*
* <h2>Typing<h2>
* Classes are automatically populating with three type related components:
*
* _types: a variable that contains an array of types of this class (extends history)
* _fullTypeName: a string representation of the extends hierarchy
* isA(string): a function you can call which will return true if the class is of a given type string.
* <p>
* Example:
* <p>
* Animal.extend('Tiger', {}, {});
* Tiger._types; // ['Animal', 'Tiger']
* Tiger._fullTypeName; // 'Animal | Tiger |"
* Tiger.isA('Animal'); // true
* </p>
* @constructor Creating a new instance of an object that has extended jQuery.Class
* calls the init prototype function and returns a new instance of the class.
*
*/
clss = $.Class = function ()
{
if (arguments.length)
{
return clss.extend.apply(clss, arguments);
}
};
/* @Static*/
extend(clss, {
/**
* @function callback
* Returns a callback function for a function on this Class.
* The callback function ensures that 'this' is set appropriately.
* @codestart
* $.Class.extend("MyClass",{
* getData: function() {
* this.showing = null;
* $.get("data.json",this.callback('gotData'),'json')
* },
* gotData: function( data ) {
* this.showing = data;
* }
* },{});
* MyClass.showData();
* @codeend
* <h2>Currying Arguments</h2>
* Additional arguments to callback will fill in arguments on the returning function.
* @codestart
* $.Class.extend("MyClass",{
* getData: function( <b>callback</b> ) {
* $.get("data.json",this.callback('process',<b>callback</b>),'json');
* },
* process: function( <b>callback</b>, jsonData ) { //callback is added as first argument
* jsonData.processed = true;
* callback(jsonData);
* }
* },{});
* MyClass.getData(showDataFunc)
* @codeend
* <h2>Nesting Functions</h2>
* Callback can take an array of functions to call as the first argument. When the returned callback function
* is called each function in the array is passed the return value of the prior function. This is often used
* to eliminate currying initial arguments.
* @codestart
* $.Class.extend("MyClass",{
* getData: function( callback ) {
* //calls process, then callback with value from process
* $.get("data.json",this.callback(['process2',callback]),'json')
* },
* process2: function( type,jsonData ) {
* jsonData.processed = true;
* return [jsonData];
* }
* },{});
* MyClass.getData(showDataFunc);
* @codeend
* @param {String|Array} fname If a string, it represents the function to be called.
* If it is an array, it will call each function in order and pass the return value of the prior function to the
* next function.
* @return {Function} the callback function.
*/
callback: function (funcs)
{
//args that should be curried
var args = makeArray(arguments),
self;
funcs = args.shift();
if (!isArray(funcs))
{
funcs = [funcs];
}
self = this;
return function class_cb()
{
var cur = concatArgs(args, arguments),
isString,
length = funcs.length,
f = 0,
func;
for (; f < length; f++)
{
func = funcs[f];
if (!func)
continue;
isString = typeof func == "string";
if (isString && self._set_called)
self.called = func;
cur = (isString ? self[func] : func).apply(self, cur || []);
if (f < length - 1)
cur = !isArray(cur) || cur._use_call ? [cur] : cur
}
return cur;
}
},
/**
* @function getObject
* Gets an object from a String.
* If the object or namespaces the string represent do not
* exist it will create them.
* @codestart
* Foo = {Bar: {Zar: {"Ted"}}}
* $.Class.getobject("Foo.Bar.Zar") //-> "Ted"
* @codeend
* @param {String} objectName the object you want to get
* @param {Object} [current=window] the object you want to look in.
* @return {Object} the object you are looking for.
*/
getObject: $.String.getObject,
/**
* @function newInstance
* Creates a new instance of the class. This method is useful for creating new instances
* with arbitrary parameters.
* <h3>Example</h3>
* @codestart
* $.Class.extend("MyClass",{},{})
* var mc = MyClass.newInstance.apply(null, new Array(parseInt(Math.random()*10,10))
* @codeend
* @return {class} instance of the class
*/
newInstance: function ()
{
var inst = this.rawInstance();
var args;
if (inst.setup)
args = inst.setup.apply(inst, arguments);
// Added by martin@playcraftlabs.com -- fix for deep cloning of properties
for (var prop in inst.__proto__)
inst[prop] = cloneObject(inst[prop]);
if (inst.init)
inst.init.apply(inst, isArray(args) ? args : arguments);
return inst;
},
/**
* Setup gets called on the inherting class with the base class followed by the
* inheriting class's raw properties.
*
* Setup will deeply extend a static defaults property on the base class with
* properties on the base class. For example:
*
* $.Class("MyBase",{
* defaults : {
* foo: 'bar'
* }
* },{})
*
* MyBase("Inheriting",{
* defaults : {
* newProp : 'newVal'
* }
* },{}
*
* Inheriting.defaults -> {foo: 'bar', 'newProp': 'newVal'}
*
* @param {Object} baseClass the base class that is being inherited from
* @param {String} fullName the name of the new class
* @param {Object} staticProps the static properties of the new class
* @param {Object} protoProps the prototype properties of the new class
*/
setup: function (baseClass, fullName)
{
this.defaults = extend(true, {}, baseClass.defaults, this.defaults);
if (this._types == undefined) this._types = [];
this._types.push(this.fullName);
if (this._fullTypeName == undefined) this._fullTypeName = '|';
this._fullTypeName += this.fullName + '|';
return arguments;
},
rawInstance: function ()
{
initializing = true;
var inst = new this();
initializing = false;
return inst;
},
/**
* Extends a class with new static and prototype functions. There are a variety of ways
* to use extend:
* @codestart
* //with className, static and prototype functions
* $.Class.extend('Task',{ STATIC },{ PROTOTYPE })
* //with just classname and prototype functions
* $.Class.extend('Task',{ PROTOTYPE })
* //With just a className
* $.Class.extend('Task')
* @codeend
* @param {String} [fullName] the classes name (used for classes w/ introspection)
* @param {Object} [klass] the new classes static/class functions
* @param {Object} [proto] the new classes prototype functions
* @return {jQuery.Class} returns the new class
*/
extend: function (fullName, klass, proto)
{
// figure out what was passed
if (typeof fullName != 'string')
{
proto = klass;
klass = fullName;
fullName = null;
}
if (!proto)
{
proto = klass;
klass = null;
}
proto = proto || {};
var _super_class = this,
_super = this.prototype,
name, shortName, namespace, prototype;
// append the isA function
this.isA = function(typeName)
{
return this._fullTypeName.indexOf('|'+typeName+'|') != -1;
};
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
inheritProps(proto, _super, prototype);
// The dummy class constructor
function Class()
{
// All construction is actually done in the init method
if (initializing) return;
if (this.constructor !== Class && arguments.length)
{ //we are being called w/o new
return arguments.callee.extend.apply(arguments.callee, arguments)
} else
{ //we are being called w/ new
// copy objects
return this.Class.newInstance.apply(this.Class, arguments)
}
}
// Copy old stuff onto class
for (name in this)
if (this.hasOwnProperty(name))
Class[name] = cloneObject(this[name]);
// copy new props on class
inheritProps(klass, this, Class);
// do namespace stuff
if (fullName)
{
var parts = fullName.split(/\./);
var shortName = parts.pop();
// Martin Wells (playcraft): bug fix. Don't add a namespace object if the class name
// has no namespace elements (i.e. it's just "MyClass", not "MyProject.MyClass")
if (parts.length > 0)
{
current = clss.getObject(parts.join('.'), window, true),
namespace = current;
}
current[shortName] = Class;
}
// set things that can't be overwritten
extend(Class, {
prototype: prototype,
namespace: namespace,
shortName: shortName,
constructor: Class,
fullName: fullName
});
//make sure our prototype looks nice
Class.prototype.Class = Class.prototype.constructor = Class;
/**
* @attribute fullName
* The full name of the class, including namespace, provided for introspection purposes.
* @codestart
* $.Class.extend("MyOrg.MyClass",{},{})
* MyOrg.MyClass.shortName //-> 'MyClass'
* MyOrg.MyClass.fullName //-> 'MyOrg.MyClass'
* @codeend
*/
var args = Class.setup.apply(Class, concatArgs([_super_class], arguments));
if (Class.init)
{
Class.init.apply(Class, args || []);
}
/* @Prototype*/
return Class;
/**
* @function setup
* If a setup method is provided, it is called when a new
* instances is created. It gets passed the same arguments that
* were given to the Class constructor function (<code> new Class( arguments ... )</code>).
*
* $.Class("MyClass",
* {
* setup: function( val ) {
* this.val = val;
* }
* })
* var mc = new MyClass("Check Check")
* mc.val //-> 'Check Check'
*
* Setup is called before [jQuery.Class.prototype.init init]. If setup
* return an array, those arguments will be used for init.
*
* $.Class("jQuery.Controller",{
* setup : function(htmlElement, rawOptions){
* return [$(htmlElement),
* $.extend({}, this.Class.defaults, rawOptions )]
* }
* })
*
* <div class='whisper'>PRO TIP:
* Setup functions are used to normalize constructor arguments and provide a place for
* setup code that extending classes don't have to remember to call _super to
* run.
* </div>
*
* Setup is not defined on $.Class itself, so calling super in inherting classes
* will break. Don't do the following:
*
* $.Class("Thing",{
* setup : function(){
* this._super(); // breaks!
* }
* })
*
* @return {Array|undefined} If an array is return, [jQuery.Class.prototype.init] is
* called with those arguments; otherwise, the original arguments are used.
*/
//break up
/**
* @function init
* If an <code>init</code> method is provided, it gets called when a new instance
* is created. Init gets called after [jQuery.Class.prototype.setup setup], typically with the
* same arguments passed to the Class
* constructor: (<code> new Class( arguments ... )</code>).
*
* $.Class("MyClass",
* {
* init: function( val ) {
* this.val = val;
* }
* })
* var mc = new MyClass(1)
* mc.val //-> 1
*
* [jQuery.Class.prototype.setup Setup] is able to modify the arguments passed to init. Read
* about it there.
*
*/
//Breaks up code
/**
* @attribute Class
* References the static properties of the instance's class.
* <h3>Quick Example</h3>
* @codestart
* // a class with a static classProperty property
* $.Class.extend("MyClass", {classProperty : true}, {});
*
* // a new instance of myClass
* var mc1 = new MyClass();
*
* //
* mc1.Class.classProperty = false;
*
* // creates a new MyClass
* var mc2 = new mc.Class();
* @codeend
* Getting static properties via the Class property, such as it's
* [jQuery.Class.static.fullName fullName] is very common.
*/
}
})
clss.prototype.
/**
* @function callback
* Returns a callback function. This does the same thing as and is described better in [jQuery.Class.static.callback].
* The only difference is this callback works
* on a instance instead of a class.
* @param {String|Array} fname If a string, it represents the function to be called.
* If it is an array, it will call each function in order and pass the return value of the prior function to the
* next function.
* @return {Function} the callback function
*/
callback = clss.callback;
})(jQuery);
+16
View File
@@ -0,0 +1,16 @@
.ace_gutter {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ace_sb {
overflow-y: hidden !important;
}
#editor {
background: #272822;
}
+24
View File
@@ -0,0 +1,24 @@
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 700;
src: local('Ubuntu Mono Bold'), local('UbuntuMono-Bold'), url(bold.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 400;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url(normal.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu Mono';
font-style: italic;
font-weight: 700;
src: local('Ubuntu Mono Bold Italic'), local('UbuntuMono-BoldItalic'), url(bolditalic.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu Mono';
font-style: italic;
font-weight: 400;
src: local('Ubuntu Mono Italic'), local('UbuntuMono-Italic'), url(italic.woff) format('woff');
}
+133
View File
@@ -0,0 +1,133 @@
/**
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
* gamecore.js
* Namespace wrappers and the base class
*/
window.gamecore = {};
gamecore.Class = $.Class;
/**
* @class gamecore.Base
* A base class providing logging, object counting and unique object id's
* Examples:
*
* Unique ID and total objects:
* <code>
* var Fighter = gamecore.Base.extend('Fighter', {}, {});
* var fighter1 = new Fighter();
* var fighter2 = new Fighter();
* fighter1.uniqueId; // -> 'Fighter:0'
* fighter2.uniqueId; // -> 'Fighter:1'
* Fighter.totalObjects; // -> 2
* </code>
*
* Logging: (log, info, warn, error, debug)
* <code>
* fighter1.warn('oops'); // == console.log('Fighter:0 [WARN] oops');
*/
gamecore.Base = gamecore.Class('gamecore.Base',
///
/// STATIC
///
{
totalObjects: 0,
WARN: 'WARN',
DEBUG: 'DEBUG',
ERROR: 'ERROR',
INFO: 'INFO',
log: function(id, type, message)
{
var idString = '';
if (id) idString = ':'+id;
console.log(this.fullName + idString + ' [' + type + '] ' + message);
},
warn: function (message)
{
this.log(null, this.WARN, message);
},
debug: function (message)
{
this.log(null, this.DEBUG, message);
},
error: function (message)
{
this.log(null, this.ERROR, message);
},
info: function (message)
{
this.log(null, this.INFO, message);
},
assert: function(msg, condition)
{
if (!condition)
throw msg;
}
},
///
/// INSTANCE
///
{
objectId: 0,
uniqueId: null,
init: function()
{
},
setup: function()
{
this.objectId = this.Class.totalObjects++;
this.uniqueId = this.Class.fullName + ':' + this.objectId;
},
/**
* @returns {String} A system-wide unique Id for this object instance
*/
getUniqueId: function()
{
// if you see a null error here, then likely you have forgotten to call
// this._super in a subclassed init method.
return this.uniqueId;
},
/**
* @returns {String} A hash matching this object. Override this to implement different
* kinds of object hashing in derived classes.
*/
hashCode: function()
{
return this.getUniqueId();
},
warn: function (message)
{
this.Class.log(this.objectId, this.Class.WARN, message);
},
debug: function (message)
{
this.Class.log(this.objectId, this.Class.DEBUG, message);
},
error: function (message)
{
this.Class.log(this.objectId, this.Class.ERROR, message);
},
info: function (message)
{
this.Class.log(this.objectId, this.Class.INFO, message);
},
toString: function()
{
return this.Class.fullName + ' [id: ' + this.objectId + ']';
}
});
+41
View File
@@ -0,0 +1,41 @@
/**
* A map of linked lists mapped by a string value
*/
gamecore.HashList = gamecore.Base.extend('gamecore.HashList',
{},
{
hashtable: null,
init: function()
{
this.hashtable = new gamecore.Hashtable();
},
add: function(key, object)
{
// find the list associated with this key and add the object to it
var list = this.hashtable.get(key);
if (list == null)
{
// no list associated with this key yet, so let's make one
list = new pc.LinkedList();
this.hashtable.put(key, list);
}
list.add(object);
},
remove: function(key, object)
{
var list = this.hashtable.get(key);
if (list == null) throw "No list for a key in hashlist when removing";
list.remove(object);
},
get: function(key)
{
return this.hashtable.get(key);
}
});
+468
View File
@@ -0,0 +1,468 @@
/**
* Copyright 2010 Tim Down.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Tim Down <tim@timdown.co.uk>
* Version: 2.1
* Build date: 21 March 2010
* Website: http://www.timdown.co.uk/jshashtable
*
* (Slight mod to add to gamecore namespace -- martin@playcraftlabs.com)
*/
/**
* jshashtable
*
* jshashtable is a JavaScript implementation of a hash table. It creates a single constructor function called Hashtable
* in the global scope.
* Example:
* <code>
* var map = new gamecore.Hashtable();
* map.put('test1', obj);
* var obj = map.get('test1');
* </code>
*/
gamecore.Hashtable = (function ()
{
var FUNCTION = "function";
var arrayRemoveAt = (typeof Array.prototype.splice == FUNCTION) ?
function (arr, idx)
{
arr.splice(idx, 1);
} :
function (arr, idx)
{
var itemsAfterDeleted, i, len;
if (idx === arr.length - 1)
{
arr.length = idx;
} else
{
itemsAfterDeleted = arr.slice(idx + 1);
arr.length = idx;
for (i = 0, len = itemsAfterDeleted.length; i < len; ++i)
{
arr[idx + i] = itemsAfterDeleted[i];
}
}
};
function hashObject(obj)
{
var hashCode;
if (typeof obj == "string")
{
return obj;
} else if (typeof obj.hashCode == FUNCTION)
{
// Check the hashCode method really has returned a string
hashCode = obj.hashCode();
return (typeof hashCode == "string") ? hashCode : hashObject(hashCode);
} else if (typeof obj.toString == FUNCTION)
{
return obj.toString();
} else
{
try
{
return String(obj);
}
catch (ex)
{
// For host objects (such as ActiveObjects in IE) that have no toString() method and throw an error when
// passed to String()
return Object.prototype.toString.call(obj);
}
}
}
function equals_fixedValueHasEquals(fixedValue, variableValue)
{
return fixedValue.equals(variableValue);
}
function equals_fixedValueNoEquals(fixedValue, variableValue)
{
return (typeof variableValue.equals == FUNCTION) ?
variableValue.equals(fixedValue) : (fixedValue === variableValue);
}
function createKeyValCheck(kvStr)
{
return function (kv)
{
if (kv === null)
{
throw new Error("null is not a valid " + kvStr);
} else if (typeof kv == "undefined")
{
throw new Error(kvStr + " must not be undefined");
}
};
}
var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value");
/*----------------------------------------------------------------------------------------------------------------*/
function Bucket(hash, firstKey, firstValue, equalityFunction)
{
this[0] = hash;
this.entries = [];
this.addEntry(firstKey, firstValue);
if (equalityFunction !== null)
{
this.getEqualityFunction = function ()
{
return equalityFunction;
};
}
}
var EXISTENCE = 0, ENTRY = 1, ENTRY_INDEX_AND_VALUE = 2;
function createBucketSearcher(mode)
{
return function (key)
{
var i = this.entries.length, entry, equals = this.getEqualityFunction(key);
while (i--)
{
entry = this.entries[i];
if (equals(key, entry[0]))
{
switch (mode)
{
case EXISTENCE:
return true;
case ENTRY:
return entry;
case ENTRY_INDEX_AND_VALUE:
return [ i, entry[1] ];
}
}
}
return false;
};
}
function createBucketLister(entryProperty)
{
return function (aggregatedArr)
{
var startIndex = aggregatedArr.length;
for (var i = 0, len = this.entries.length; i < len; ++i)
{
aggregatedArr[startIndex + i] = this.entries[i][entryProperty];
}
};
}
Bucket.prototype = {
getEqualityFunction:function (searchValue)
{
return (typeof searchValue.equals == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
},
getEntryForKey:createBucketSearcher(ENTRY),
getEntryAndIndexForKey:createBucketSearcher(ENTRY_INDEX_AND_VALUE),
removeEntryForKey:function (key)
{
var result = this.getEntryAndIndexForKey(key);
if (result)
{
arrayRemoveAt(this.entries, result[0]);
return result[1];
}
return null;
},
addEntry:function (key, value)
{
this.entries[this.entries.length] = [key, value];
},
keys:createBucketLister(0),
values:createBucketLister(1),
getEntries:function (entries)
{
var startIndex = entries.length;
for (var i = 0, len = this.entries.length; i < len; ++i)
{
// Clone the entry stored in the bucket before adding to array
entries[startIndex + i] = this.entries[i].slice(0);
}
},
containsKey:createBucketSearcher(EXISTENCE),
containsValue:function (value)
{
var i = this.entries.length;
while (i--)
{
if (value === this.entries[i][1])
{
return true;
}
}
return false;
}
};
/*----------------------------------------------------------------------------------------------------------------*/
// Supporting functions for searching hashtable buckets
function searchBuckets(buckets, hash)
{
var i = buckets.length, bucket;
while (i--)
{
bucket = buckets[i];
if (hash === bucket[0])
{
return i;
}
}
return null;
}
function getBucketForHash(bucketsByHash, hash)
{
var bucket = bucketsByHash[hash];
// Check that this is a genuine bucket and not something inherited from the bucketsByHash's prototype
return ( bucket && (bucket instanceof Bucket) ) ? bucket : null;
}
/*----------------------------------------------------------------------------------------------------------------*/
function Hashtable(hashingFunctionParam, equalityFunctionParam)
{
var that = this;
var buckets = [];
var bucketsByHash = {};
var hashingFunction = (typeof hashingFunctionParam == FUNCTION) ? hashingFunctionParam : hashObject;
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
this.put = function (key, value)
{
checkKey(key);
checkValue(value);
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
// Check if a bucket exists for the bucket key
bucket = getBucketForHash(bucketsByHash, hash);
if (bucket)
{
// Check this bucket to see if it already contains this key
bucketEntry = bucket.getEntryForKey(key);
if (bucketEntry)
{
// This bucket entry is the current mapping of key to value, so replace old value and we're done.
oldValue = bucketEntry[1];
bucketEntry[1] = value;
} else
{
// The bucket does not contain an entry for this key, so add one
bucket.addEntry(key, value);
}
} else
{
// No bucket exists for the key, so create one and put our key/value mapping in
bucket = new Bucket(hash, key, value, equalityFunction);
buckets[buckets.length] = bucket;
bucketsByHash[hash] = bucket;
}
return oldValue;
};
this.get = function (key)
{
checkKey(key);
var hash = hashingFunction(key);
// Check if a bucket exists for the bucket key
var bucket = getBucketForHash(bucketsByHash, hash);
if (bucket)
{
// Check this bucket to see if it contains this key
var bucketEntry = bucket.getEntryForKey(key);
if (bucketEntry)
{
// This bucket entry is the current mapping of key to value, so return the value.
return bucketEntry[1];
}
}
return null;
};
this.containsKey = function (key)
{
checkKey(key);
var bucketKey = hashingFunction(key);
// Check if a bucket exists for the bucket key
var bucket = getBucketForHash(bucketsByHash, bucketKey);
return bucket ? bucket.containsKey(key) : false;
};
this.containsValue = function (value)
{
checkValue(value);
var i = buckets.length;
while (i--)
{
if (buckets[i].containsValue(value))
{
return true;
}
}
return false;
};
this.clear = function ()
{
buckets.length = 0;
bucketsByHash = {};
};
this.isEmpty = function ()
{
return !buckets.length;
};
var createBucketAggregator = function (bucketFuncName)
{
return function ()
{
var aggregated = [], i = buckets.length;
while (i--)
{
buckets[i][bucketFuncName](aggregated);
}
return aggregated;
};
};
this.keys = createBucketAggregator("keys");
this.values = createBucketAggregator("values");
this.entries = createBucketAggregator("getEntries");
this.remove = function (key)
{
checkKey(key);
var hash = hashingFunction(key), bucketIndex, oldValue = null;
// Check if a bucket exists for the bucket key
var bucket = getBucketForHash(bucketsByHash, hash);
if (bucket)
{
// Remove entry from this bucket for this key
oldValue = bucket.removeEntryForKey(key);
if (oldValue !== null)
{
// Entry was removed, so check if bucket is empty
if (!bucket.entries.length)
{
// Bucket is empty, so remove it from the bucket collections
bucketIndex = searchBuckets(buckets, hash);
arrayRemoveAt(buckets, bucketIndex);
delete bucketsByHash[hash];
}
}
}
return oldValue;
};
this.size = function ()
{
var total = 0, i = buckets.length;
while (i--)
{
total += buckets[i].entries.length;
}
return total;
};
this.each = function (callback)
{
var entries = that.entries(), i = entries.length, entry;
while (i--)
{
entry = entries[i];
callback(entry[0], entry[1]);
}
};
this.putAll = function (hashtable, conflictCallback)
{
var entries = hashtable.entries();
var entry, key, value, thisValue, i = entries.length;
var hasConflictCallback = (typeof conflictCallback == FUNCTION);
while (i--)
{
entry = entries[i];
key = entry[0];
value = entry[1];
// Check for a conflict. The default behaviour is to overwrite the value for an existing key
if (hasConflictCallback && (thisValue = that.get(key)))
{
value = conflictCallback(key, thisValue, value);
}
that.put(key, value);
}
};
this.clone = function ()
{
var clone = new Hashtable(hashingFunctionParam, equalityFunctionParam);
clone.putAll(that);
return clone;
};
/**
* Added by martin@playcratlabs.com to support debug dumping of hash arrays
*/
this.toString = function ()
{
var result = '';
var keys = this.keys();
for (var i = 0; i < keys.length; i++)
{
var obj = this.get(keys[i]);
result += keys[i].toString() + ' = ' + obj.toString() + '\n';
}
return result;
}
}
return Hashtable;
})();
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+204
View File
@@ -0,0 +1,204 @@
body {
overflow: hidden;
font-family: "Ubuntu sans", Arial, sans-serif;
font-size: 14px;
color: #ddd;
line-height: 1em;
background: #1e1e1e;
}
#panel-center {
margin: 0;
position: absolute;
z-index: 20;
top: 0;
bottom: 0;
left: 200px;
right: 400px;
}
#panel-left {
margin: 0;
position: absolute;
z-index: 10;
top: 0;
bottom: 0;
left: 0;
width: 200px;
background: #191919;
}
#panel-right {
margin: 0;
position: absolute;
z-index: 30;
top: 0;
bottom: 0;
right: 0;
width: 400px;
background: #191919;
}
#editor {
margin: 0;
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
z-index: 100;
}
#diagram {
margin: 0;
position: absolute;
bottom: 0;
top: 50%;
left: 0;
right: 0;
z-index: 200;
}
#editor-separator, #preview-separator {
margin: 0;
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 3px;
z-index: 300;
background: #191919;
border-top: 1px solid #292929;
border-bottom: 1px solid #292929;
}
#preview-separator {
z-index: 400;
left: 3px;
}
#left-separator {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 3px;
z-index: 300;
background: #191919;
}
#right-separator {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 3px;
z-index: 300;
background: #191919;
}
#preview {
margin: 0;
position: absolute;
top: 0;
bottom: 50%;
left: 3px;
width: 396px;
background: #1e1e1e;
border-left: 1px solid #292929;
z-index: 210;
}
#console {
margin: 0;
position: absolute;
bottom: 0;
top: 50%;
left: 0;
left: 3px;
width: 396px;
z-index: 220;
background: #1e1e1e;
border-left: 1px solid #292929;
}
#console-text {
background: transparent;
border: none;
width: 100%;
height: 100%;
color: #666;
text-shadow: 0px 1px 1px #000000;
filter: dropshadow(color=#000000, offx=0, offy=1);
padding: 6px;
outline: none;
overflow: hidden;
scroll: none;
}
#preview canvas {
background: #161616;
}
#modules {
margin: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 196px;
font-size: 13px;
background: #1e1e1e;
border-right: 1px solid #292929;
}
#modules ul {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
list-style: none;
margin: 10px 0;
padding: 0;
}
#modules li {
list-style: none;
line-height: 2.0em;
padding: 0 20px;
background: #1e1e1e;
cursor: pointer;
text-shadow: 0px 1px 1px #000000;
filter: dropshadow(color=#000000, offx=0, offy=1);
}
#modules li:hover {
background: #434343; /* Old browsers */
background: -moz-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#888), color-stop(4%,#4e4e4e), color-stop(96%,#434343), color-stop(100%,#1e1e1e)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* IE10+ */
background: linear-gradient(to bottom, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* W3C */
}
#modules li.active {
background: #292929;
}
#render
{
position: absolute;
z-index: 9999999;
}
File diff suppressed because one or more lines are too long
+542
View File
@@ -0,0 +1,542 @@
/**
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
* pool.js
*/
/**
* @class gamecore.Pool
* Easy (high-performance) object pooling
*
* A pool of objects for use in situations where you want to minimize object life cycling (and
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
* collection for small numbers of objects.
* <p>
* This class maintains mutual an array of objects which are free. If you wish to maintain a list of both
* free and used then see the gamecore.DualPool.
* <p>
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
* <p>
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
* You need to "acquire" one and then reset its state, usually via a static create factory method.
* <p>
* Example:
* <code>
* Point = gamecore.Pooled('Point',
* {
* // Static constructor
* create:function (x, y)
* {
* var n = this._super();
* n.x = x;
* n.y = y;
* return n;
* }
* },
* {
* x:0, y:0, // instance
*
* init: function(x, y)
* {
* this.x = x;
* this.y = y;
* }
* }
* </code>
* To then access the object from the pool, use create, instead of new. Then release it.
* <code>
* var p = Point.create(100, 100);
* // ... do something
* p.release();
* </code>
*
*/
gamecore.Pool = gamecore.Base.extend('gamecore.Pool',
{
INITIAL_POOL_SIZE:1,
pools:new gamecore.Hashtable(), // all your pools belong to us
totalPooled:0,
totalUsed:0,
/**
* Acquire an object from a pool based on the class[name]. Typically this method is
* automatically called from
* @param classType Class of object to create
*/
acquire:function (classType)
{
var pool = this.getPool(classType);
if (pool == undefined || pool == null)
{
// create a pool for this type of class
//this.info('Constructing a new pool for ' + classType.fullName + ' objects.');
pool = new gamecore.Pool(classType, this.INITIAL_POOL_SIZE);
this.pools.put(classType.fullName, pool);
}
return pool.acquire();
},
/**
* Releases an object back into it's corresponding object pool
* @param pooledObj Object to return to the pool
*/
release:function (pooledObj)
{
var pool = this.pools.get(pooledObj.Class.fullName);
if (pool == undefined)
throw "Oops, trying to release an object of type " + pooledObj.Class.fullName +
" but no pool exists. Did you new an object instead of using create.";
pool.release(pooledObj);
},
/**
* Returns the pool associated with the given classType, or null if no pool currently exists
*/
getPool:function (classType)
{
return this.pools.get(classType.fullName);
},
getStats:function ()
{
var s = '';
var keys = this.pools.keys();
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
var pool = this.pools.get(key);
s += key + ': ' + pool.getStats() + '\n';
}
return s;
}
},
{
freeList:null,
expansion: 1,
traces: null,
/**
* Constructs a pool using a base of objects passed in as an array.
* @param classType Class name of the type of objects in the pool
* @param initial Starting number of objects in the pool
*/
init:function (classType, initial)
{
this._super();
this.classType = classType;
this.freeList = [];
// instantiate the initial objects for the pool
this.expand(initial);
},
startTracing:function ()
{
if (this.tracing) return;
this.tracing = true;
if (this.traces)
this.traces.clear();
else
this.traces = new gamecore.Hashtable();
},
stopTracing:function ()
{
this.tracing = false;
},
/**
* Expand the pool of objects by constructing a bunch of new ones. The pool will
* automatically expand itself by 10% each time it runs out of space, so generally you
* shouldn't need to use this.
* @param howMany Number of new objects you want to add
*/
expand:function (howMany)
{
gamecore.Pool.totalPooled += howMany;
//debug: if you want to track expansion
//this.debug('expanding ' + this.classType.fullName + ' by ' + howMany + ' total=' + gamecore.Pool.totalPooled);
for (var i = 0; i < howMany; i++)
this.freeList.push(new this.classType());
},
getFreeCount: function()
{
return this.freeList.length;
},
/**
* Returns the next free object by moving it from the free pool to the used
* one. If no free objects are available it returns the oldest from the used
* pool.
* access to the object
*/
acquire:function ()
{
// check if we have anymore to give out
if (this.freeList.length <= 0)
{
// create some more space (expand by 20%, minimum 1)
this.expansion = Math.round(this.expansion*1.2)+1;
this.expand(this.expansion);
}
if (this.tracing)
{
var stack = printStackTrace();
var pos = stack.length - 1;
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
pos--;
var count = this.traces.get(stack[pos]);
if (count == null)
this.traces.put(stack[pos], { value:1 });
else
count.value++;
}
return this.freeList.pop();
},
/**
* Releases an object by moving it from the used list back to the free list.
* @param obj {pc.Base} The obj to release back into the pool
*/
release:function (obj)
{
this.freeList.push(obj);
},
getStats:function ()
{
var s = this.Class.fullName + ' stats: ' + this.freeList.length + ' free.\n';
if (this.tracing)
{
s += 'TRACING\n';
var traceKeys = this.traces.keys();
for (var k in traceKeys)
s += traceKeys[k] + ' (' + this.traces.get(traceKeys[k]).value + ')\n';
}
return s;
},
dump:function (msg)
{
this.info('================== ' + msg + ' ===================');
this.info('FREE');
this.freeList.dump();
},
/**
* Returns the number of objects in the pool
*/
size:function ()
{
return this.freeList.length;
},
/**
* Returns the LinkedList of currently free objects in the pool
*/
getFreeList:function ()
{
return this.freeList;
}
});
/**
* @class gamecore.DualPool
* Easy (high-performance) object pooling
*
* A pool of objects for use in situations where you want to minimize object life cycling (and
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
* collection for small numbers of objects.
* <p>
* This class maintains mutual set of doubly-linked lists in order to differentiate between
* objects that are in use and those that are unallocated from the pool. This allows for much
* faster cycling of only the in-use objects.
* <p>
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
* <p>
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
* You need to "acquire" one and then reset its state, usually via a static create factory method.
* <p>
* Example:
* <code>
* Point = gamecore.Pooled('Point',
* {
* // Static constructor
* create:function (x, y)
* {
* var n = this._super();
* n.x = x;
* n.y = y;
* return n;
* }
* },
* {
* x:0, y:0, // instance
*
* init: function(x, y)
* {
* this.x = x;
* this.y = y;
* }
* }
* </code>
* To then access the object from the pool, use create, instead of new. Then release it.
* <code>
* var p = Point.create(100, 100);
* // ... do something
* p.release();
* </code>
*
*/
gamecore.DualPool = gamecore.Pool.extend('gamecore.DualPool',
{
acquire:function (classType)
{
var pool = this.getPool(classType);
if (pool == undefined || pool == null)
{
pool = new gamecore.DualPool(classType, this.INITIAL_POOL_SIZE);
this.pools.put(classType.fullName, pool);
}
return pool.acquire();
},
getStats:function ()
{
var s = '';
var keys = this.pools.keys();
for (var i = 0; i < keys.length; i++)
{
var key = keys[i];
var pool = this.pools.get(key);
s += key + ' (free: ' + pool.freeList.length() + ' used: ' + pool.usedList.length() + ')\n';
}
return s;
}
},
///
/// INSTANCE
///
{
freeList:null,
usedList:null,
/**
* Constructs a pool using a base of objects passed in as an array.
* @param classType Class name of the type of objects in the pool
* @param initial Starting number of objects in the pool
*/
init:function (classType, initial)
{
this.classType = classType;
this.usedList = new gamecore.LinkedList();
this.freeList = new gamecore.LinkedList();
// instantiate the initial objects for the pool
this.expand(initial);
},
/**
* Expand the pool of objects by constructing a bunch of new ones. The pool will
* automatically expand itself by 10% each time it runs out of space, so generally you
* shouldn't need to use this.
* @param howMany Number of new objects you want to add
*/
expand:function (howMany)
{
// this.info('Expanding ' + this.classType.fullName + ' pool from ' + this.size() +
// ' to ' + (this.size() + howMany) + ' objects');
gamecore.Pool.totalPooled += howMany;
for (var i = 0; i < howMany; i++)
this.freeList.add(new this.classType());
},
/**
* Returns the next free object by moving it from the free pool to the used
* one. If no free objects are available it returns the oldest from the used
* pool.
* access to the object
*/
returnObj:null,
acquire:function ()
{
// check if we have anymore to give out
if (this.freeList.first == null)
// create some more space (expand by 20%, minimum 1)
this.expand(Math.round(this.size() / 5) + 1);
this.returnObj = this.freeList.first.obj;
this.freeList.remove(this.returnObj);
this.returnObj.destroyed = false;
this.usedList.add(this.returnObj);
if (this.tracing)
{
var stack = printStackTrace();
var pos = stack.length - 1;
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
pos--;
var count = this.traces.get(stack[pos]);
if (count == null)
this.traces.put(stack[pos], { value:1 });
else
count.value++;
}
return this.returnObj;
},
/**
* Releases an object by moving it from the used list back to the free list.
* @param obj {pc.Base} The obj to release back into the pool
*/
release:function (obj)
{
this.freeList.add(obj);
this.usedList.remove(obj);
},
dump:function (msg)
{
this.info('================== ' + msg + ' ===================');
this.info('FREE');
this.freeList.dump();
this.info('USED');
this.usedList.dump();
},
/**
* Returns the number of objects in the pool
*/
size:function ()
{
return this.freeList.count + this.usedList.count;
},
/**
* Returns the LinkedList of current used objects in the pool
* @return {*}
*/
getUsedList:function ()
{
return this.usedList;
}
});
/**
* @class gamecore.Pooled
* Used as a base class for objects which are life cycle managed in an object pool.
*/
gamecore.Pooled = gamecore.Base('gamecore.Pooled',
///
/// STATICS
///
{
/**
* Static factory method for creating a new object based on its class. This method
* should be called using this._super from the Class.create that derives from this.
* @returns An object from the pool
*/
create:function ()
{
return gamecore.Pool.acquire(this);
},
getPool:function ()
{
return gamecore.Pool.getPool(this);
}
},
///
/// INSTANCE
///
{
destroyed:false,
init:function ()
{
this._super();
},
release:function ()
{
this.onRelease();
gamecore.Pool.release(this);
},
onRelease:function ()
{
}
});
/**
* @class gamecore.DualPooled
* Used as a base class for objects which are life cycle managed in an object pool (the DualPool edition)
*/
gamecore.DualPooled = gamecore.Base('gamecore.DualPooled',
///
/// STATICS
///
{
/**
* Static factory method for creating a new object based on its class. This method
* should be called using this._super from the Class.create that derives from this.
* @returns An object from the pool
*/
create:function ()
{
return gamecore.DualPool.acquire(this);
},
getPool:function ()
{
return gamecore.DualPool.getPool(this);
}
},
///
/// INSTANCE
///
{
destroyed:false,
init:function ()
{
this._super();
},
release:function ()
{
this.onRelease();
gamecore.DualPool.release(this);
},
onRelease:function ()
{
}
});
+1
View File
@@ -0,0 +1 @@
ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(a,b,c){b.isDark=!0,b.cssClass="ace-monokai",b.cssText=".ace-monokai .ace_editor { border: 2px solid rgb(159, 159, 159)}.ace-monokai .ace_editor.ace_focus { border: 2px solid #327fbd}.ace-monokai .ace_gutter { background: #2f3129; color: #f1f1f1}.ace-monokai .ace_print_margin { width: 1px; background: #555651}.ace-monokai .ace_scroller { background-color: #272822}.ace-monokai .ace_text-layer { color: #F8F8F2}.ace-monokai .ace_cursor { border-left: 2px solid #F8F8F0}.ace-monokai .ace_cursor.ace_overwrite { border-left: 0px; border-bottom: 1px solid #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection { background: #49483E}.ace-monokai.multiselect .ace_selection.start { box-shadow: 0 0 3px 0px #272822; border-radius: 2px}.ace-monokai .ace_marker-layer .ace_step { background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket { margin: -1px 0 0 -1px; border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active_line { background: #202020}.ace-monokai .ace_gutter_active_line { background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected_word { border: 1px solid #49483E}.ace-monokai .ace_invisible { color: #49483E}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta,.ace-monokai .ace_storage { color: #F92672}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other { color: #AE81FF}.ace-monokai .ace_invalid { color: #F8F8F0; background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated { color: #F8F8F0; background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function { color: #66D9EF}.ace-monokai .ace_fold { background-color: #A6E22E; border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type { font-style: italic; color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable { color: #A6E22E}.ace-monokai .ace_variable.ace_parameter { font-style: italic; color: #FD971F}.ace-monokai .ace_string { color: #E6DB74}.ace-monokai .ace_comment { color: #75715E}.ace-monokai .ace_markup.ace_underline { text-decoration: underline}.ace-monokai .ace_indent-guide { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQ11D6z7Bq1ar/ABCKBG6g04U2AAAAAElFTkSuQmCC) right repeat-y}";var d=a("../lib/dom");d.importCssString(b.cssText,b.cssClass)})
+18
View File
@@ -0,0 +1,18 @@
{
"name": "HexGL",
"description": "HexGL v1.0.1-ffos",
"launch_path": "/index.html",
"icons": {
"32": "/icon_32.png",
"64": "/icon_64.png",
"128": "/icon_128.png",
"256": "/icon_256.png"
},
"developer": {
"name": "Thibaut Despoulain (BKcore)",
"url": "http://bkcore.com"
},
"installs_allowed_from": ["*"],
"default_locale": "en",
"orientation": ["landscape"]
}
+10
View File
@@ -0,0 +1,10 @@
{
"name": "HexGL",
"description": "HexGL v1.0.1-ffos",
"package_path" : "package.zip",
"version": "1",
"developer": {
"name": "Thibaut Despoulain (BKcore)",
"url": "http://bkcore.com"
}
}
BIN
View File
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 64 KiB