├── texture
├── ring.png
├── sky.jpg
├── wall.png
├── sonic.jpg
├── sonic.png
├── spring.jpg
├── wall2.png
├── monitor.png
├── wall-ghost.png
├── monitor-display.jpg
├── monitor-display.png
├── monitor-specular.png
└── water-shield-icon.png
├── js
├── Engine.js
├── Sky.js
├── Spring.js
├── json.addons.js
├── InputController.js
├── Ring.js
├── console.js
├── main.js
├── ResourceManager.js
├── WorldEngine.js
├── Player.js
└── GraphicsEngine.js
├── index.html
├── css
└── style.css
├── shader
├── depth.jsonshader
├── sphere.jsonshader
├── metal.jsonshader
├── sonic.jsonshader
├── sky.jsonshader
├── monitor.jsonshader
├── glow.jsonshader
└── default.jsonshader
├── README.md
├── LICENSE
├── tools
└── md3tojson3d.c
├── lib
├── sylvester.addons.js
└── sylvester.js
├── level
└── lvl0.jsonlevel
└── mesh
├── sky.jsonmesh
└── spinball.jsonmesh
/texture/ring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/ring.png
--------------------------------------------------------------------------------
/texture/sky.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/sky.jpg
--------------------------------------------------------------------------------
/texture/wall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/wall.png
--------------------------------------------------------------------------------
/texture/sonic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/sonic.jpg
--------------------------------------------------------------------------------
/texture/sonic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/sonic.png
--------------------------------------------------------------------------------
/texture/spring.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/spring.jpg
--------------------------------------------------------------------------------
/texture/wall2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/wall2.png
--------------------------------------------------------------------------------
/texture/monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/monitor.png
--------------------------------------------------------------------------------
/texture/wall-ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/wall-ghost.png
--------------------------------------------------------------------------------
/texture/monitor-display.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/monitor-display.jpg
--------------------------------------------------------------------------------
/texture/monitor-display.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/monitor-display.png
--------------------------------------------------------------------------------
/texture/monitor-specular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/monitor-specular.png
--------------------------------------------------------------------------------
/texture/water-shield-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coreh-deprecated/WebSonic/HEAD/texture/water-shield-icon.png
--------------------------------------------------------------------------------
/js/Engine.js:
--------------------------------------------------------------------------------
1 | var Engine = function(canvas) {
2 | var engine = {}
3 | engine.gfx = GraphicsEngine(engine, canvas);
4 | engine.resources = ResourceManager(engine);
5 | engine.world = WorldEngine(engine);
6 | engine.input = InputController(engine);
7 | return engine;
8 | }
--------------------------------------------------------------------------------
/js/Sky.js:
--------------------------------------------------------------------------------
1 | var Sky = function(engine, camera) {
2 | var sky = new engine.world.MeshEntity(engine.resources.get("mesh/sky.jsonmesh"));
3 | sky.layer = -99;
4 |
5 | sky.scale($V([20,2,20]));
6 | sky.castsShadows = false;
7 |
8 | sky.update = function(timeDelta) {
9 | sky.position(camera.position());
10 | }
11 |
12 | return sky;
13 | }
--------------------------------------------------------------------------------
/js/Spring.js:
--------------------------------------------------------------------------------
1 | var Spring = function(engine, player) {
2 | var spring = engine.world.MeshEntity(engine.resources.get("mesh/spring.jsonmesh"));
3 | var deformation = 0.0;
4 |
5 | spring.update = function(timeDelta) {
6 | if (player.position().subtract(spring.position()).modulus() < 32 && player.position().elements[1] > spring.position().elements[1]) {
7 | var oldSpeed = player.speed();
8 | player.speed($V([oldSpeed.elements[0], 12 * 60, oldSpeed.elements[2]]));
9 | player.state(player.STATE_SPRING);
10 | deformation = 0.5;
11 | }
12 | if (deformation > 0) {
13 | spring.frame = 1;
14 | } else {
15 | spring.frame = 0;
16 | }
17 | deformation -= timeDelta;
18 | }
19 |
20 | return spring;
21 | }
--------------------------------------------------------------------------------
/js/json.addons.js:
--------------------------------------------------------------------------------
1 | JSON.forgivingParse = function(data) {
2 | var dataTokens = data.split("\"");
3 | var insideString = false;
4 | for (var i in dataTokens) {
5 | if (insideString) {
6 | // escape control characters
7 | dataTokens[i] = dataTokens[i].replace(/[\t]/g, "\\t");
8 | dataTokens[i] = dataTokens[i].replace(/[\r]+/g, "\\r");
9 | dataTokens[i] = dataTokens[i].replace(/[\n]+/g, "\\n");
10 | } else {
11 | // strip comments
12 | dataTokens[i] = dataTokens[i].replace(/\*.*?\*/g, "");
13 | dataTokens[i] = dataTokens[i].replace(/\/\/.*?(\n|\r|\r\n)/g, "");
14 |
15 | // strip additional commas
16 | dataTokens[i] = dataTokens[i].replace(/,\s*\]/g, "]");
17 | dataTokens[i] = dataTokens[i].replace(/,\s*\}/g, "}");
18 | }
19 | insideString = !insideString
20 | if (!insideString && dataTokens[i][dataTokens[i].length - 1] == "\\") {
21 | insideString = true;
22 | }
23 | }
24 | return JSON.parse(dataTokens.join("\""));
25 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebSonic
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | Score0
28 | Time0:00
29 | Rings0
30 |
31 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | overflow: hidden;
4 | background: #000;
5 | color: white;
6 | font-family: monospace;
7 | }
8 |
9 | #console {
10 | position: absolute;
11 | left: 0;
12 | top: 0;
13 | right: 0;
14 | bottom: 0;
15 | overflow: hidden;
16 | }
17 |
18 | #console > div {
19 | background: rgba(127,127,127, 0.1);
20 | }
21 |
22 | #console > div > div {
23 | padding: 4px;
24 | color: rgba(255,255,255,0.3);
25 | -moz-border-radius: 2px;
26 | -webkit-border-radius: 2px;
27 | border-radius: 2px;
28 | font-size: 12px;
29 | }
30 |
31 | #console .warning {
32 | color: rgba(255,200,0,1.0);
33 | background: rgba(255,255,0,0.1);
34 | text-shadow: 0px 1px 2px black;
35 | }
36 |
37 | #console .error {
38 | background: rgba(255,0,0,0.5);
39 | color: white;
40 | text-shadow: 0px 1px 2px black;
41 | }
42 |
43 | #console .info {
44 | color: white;
45 | text-shadow: 0px 1px 2px black;
46 | }
47 |
48 | canvas {
49 | -webkit-transform: scale(1.0,1.0);
50 | }
51 |
52 | #hud {
53 | position: absolute;
54 | top: 0;
55 | left: 0;
56 | font-family: Helvetica, Arial, sans-serif;
57 | font-weight: bold;
58 | padding: 0.5em;
59 | text-transform: uppercase;
60 | text-shadow: 0 1px 1px black;
61 | font-size: 30px;
62 | }
63 |
64 | #hud strong {
65 | color: #ee0;
66 | width: 4em;
67 | position: relative;
68 | display: inline-block;
69 | }
70 |
71 | #hud span {
72 | width: 4em;
73 | display: inline-block;
74 | text-align: right;
75 | }
--------------------------------------------------------------------------------
/js/InputController.js:
--------------------------------------------------------------------------------
1 | var InputController = function(engine){
2 | var input = {};
3 | var keysHeld = {};
4 | var keysPressed = {};
5 | $(window).keydown(function(e){
6 | if (!e.ctrlKey && !e.metaKey) {
7 | // For keysPressed, we need to check if the key was already held,
8 | // because chrome sends keyDown events of auto-repeated keys
9 | if (keysHeld[e.which] != true) {
10 | keysPressed[e.which] = true;
11 | }
12 | keysHeld[e.which] = true;
13 | e.preventDefault();
14 | e.stopPropagation();
15 | }
16 | });
17 | $(window).keyup(function(e){
18 | keysHeld[e.which] = false;
19 | if (!e.ctrlKey && !e.metaKey) {
20 | e.preventDefault();
21 | e.stopPropagation();
22 | }
23 | });
24 | $(window).keypress(function(e){
25 | if (!e.ctrlKey && !e.metaKey) {
26 | e.preventDefault();
27 | e.stopPropagation();
28 | }
29 | });
30 |
31 | input.pressedUp = function() { return input.pressed(38); }
32 | input.pressedDown = function() { return input.pressed(40); }
33 | input.pressedLeft = function() { return input.pressed(37); }
34 | input.pressedRight = function() { return input.pressed(39); }
35 |
36 | input.pressed = function(keycode) {
37 | return keysPressed[keycode] == true;
38 | }
39 |
40 | input.held = function(keycode) {
41 | return keysHeld[keycode] == true;
42 | }
43 |
44 | input.heldUp = function() { return input.held(38); }
45 | input.heldDown = function() { return input.held(40); }
46 | input.heldLeft = function() { return input.held(37); }
47 | input.heldRight = function() { return input.held(39); }
48 |
49 | input.resetPressed = function() {
50 | keysPressed = {};
51 | }
52 | return input;
53 | }
--------------------------------------------------------------------------------
/shader/depth.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_modelView",
3 | "u_projection" ],
4 | "attributes": ["a_position"],
5 | "vertexShader": "
6 | #ifdef GL_ES
7 | precision highp float;
8 | #endif
9 |
10 | attribute vec3 a_position;
11 | attribute vec3 a_normal;
12 | attribute vec2 a_texCoords;
13 |
14 | uniform mat4 u_cameraView;
15 | uniform mat4 u_modelView;
16 | uniform mat4 u_projection;
17 | uniform mat4 u_normalCameraView;
18 | uniform mat4 u_normalModelView;
19 |
20 | uniform sampler2D u_diffuseMap;
21 |
22 | varying vec2 v_texCoords;
23 | varying vec3 v_normal;
24 | varying vec4 v_globalPosition;
25 | varying vec4 v_localPosition;
26 |
27 | void main(void) {
28 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
29 | v_localPosition = u_cameraView * v_globalPosition;
30 | gl_Position = u_projection * v_localPosition;
31 | }
32 | ",
33 | "fragmentShader": "
34 | #ifdef GL_ES
35 | precision highp float;
36 | #endif
37 |
38 | varying vec3 v_normal;
39 | varying vec4 v_globalPosition;
40 | varying vec4 v_localPosition;
41 | varying vec2 v_texCoords;
42 |
43 | uniform sampler2D u_levelShadowMap;
44 | uniform sampler2D u_diffuseMap;
45 | uniform sampler2D u_ghostMap;
46 | uniform vec3 u_levelSize;
47 | uniform vec3 u_lightDirection;
48 | uniform vec4 u_lightColor;
49 | uniform vec4 u_ambientLightColor;
50 | uniform vec3 u_playerPosition;
51 | uniform mat4 u_cameraView;
52 | uniform mat4 u_modelView;
53 | uniform mat4 u_normalCameraView;
54 | uniform float u_time;
55 |
56 | void main(void) {
57 | gl_FragColor = vec4(-v_localPosition.z/1000.0, -v_localPosition.z/1000.0, -v_localPosition.z/1000.0, 1.0);
58 | gl_FragColor = vec4(1.0 -gl_FragColor.rgb, 1.0);
59 | }
60 | "
61 | }
--------------------------------------------------------------------------------
/js/Ring.js:
--------------------------------------------------------------------------------
1 | var Ring = function(engine, player, level) {
2 | var ring = new engine.world.MeshEntity(engine.resources.get("mesh/ring.jsonmesh"));
3 | var speed = $V([0,0,0]);
4 | // var speed = $V([(Math.random()-0.5)*10,Math.random()-0.5,(Math.random()-0.5)*10]);
5 | var time = 0;
6 | var grv = 0.09375 * 60.0 * 60.0
7 | var i = Math.floor(Math.random() * 5);
8 | var creationTime = engine.world.time();
9 |
10 | ring.speed = function(newSpeed) {
11 | if (newSpeed) {
12 | speed = newSpeed;
13 | }
14 | return speed;
15 | }
16 |
17 | ring.update = function(timeDelta) {
18 | time+= timeDelta;
19 | // ring.rotation(ring.rotation().x(Matrix.RotationY(1.875 * Math.PI * timeDelta).ensure4x4()));
20 | speed = speed.add($V([0,-grv*timeDelta,0]));
21 | ring.position(ring.position().add(speed.x(timeDelta)));
22 | i++;
23 | if (i == 5) {
24 | i = 0;
25 | var intersect = level.rayIntersect(ring.position(), speed.toUnitVector(), 16, 0);
26 | if (isFinite(intersect.distance) && intersect.normal.dot(speed) <= 0) {
27 | ring.position(ring.position().subtract(speed.toUnitVector().x(16-intersect.distance)));
28 | var length = intersect.normal.dot(speed);
29 | speed = speed.subtract(intersect.normal.x(length*2));
30 | speed.elements[1] *= 0.75;
31 | }
32 | }
33 | if (engine.world.time() > creationTime + 4.26) {
34 | engine.world.remove(ring);
35 | }
36 |
37 | }
38 | ring.isStatic = true;
39 | var superRender = ring.render;
40 | ring.render = function(renderParams) {
41 | // ring.rotation(Matrix.RotationY(1.875 * Math.PI * renderParams.uniforms[0].u_time).ensure4x4());
42 | // if (engine.world.time() < creationTime + 3) {
43 | superRender(renderParams);
44 | // } else {
45 | // if (Math.floor(engine.world.time() * 20) % 2 == 0)
46 | // superRender(renderParams);
47 | // }
48 | }
49 |
50 | return ring;
51 | }
--------------------------------------------------------------------------------
/js/console.js:
--------------------------------------------------------------------------------
1 | //if (!window.console) {
2 | window.console = {};
3 | window.console.initialTime = (new Date()).getTime();
4 | window.console.log = function(message){
5 | //return;
6 | var div = document.createElement("div");
7 | div.innerHTML = " [ " + (((new Date()).getTime() - window.console.initialTime) / 1000).toFixed(4) + "s ] " + message;
8 | $("#log")[0].appendChild(div);
9 | $("#console").attr({ scrollTop: $("#console").attr("scrollHeight") }, 3000);
10 | setTimeout(function(){
11 | $(div).fadeOut(1000,function(){
12 | div.parentNode.removeChild(div);
13 | });
14 | }, 2000);
15 | }
16 | window.console.warn = function(message){
17 | var div = document.createElement("div");
18 | div.innerHTML = " [ " + (((new Date()).getTime() - window.console.initialTime) / 1000).toFixed(4) + "s ] Warning: " + message;
19 | div.className = "warning";
20 | $("#log")[0].appendChild(div);
21 | $("#console").attr({ scrollTop: $("#console").attr("scrollHeight") }, 3000);
22 | setTimeout(function(){
23 | $(div).fadeOut(1000,function(){
24 | div.parentNode.removeChild(div);
25 | });
26 | }, 2000);
27 | }
28 | window.console.error = function(message){
29 | var div = document.createElement("div");
30 | div.innerHTML = "Error: " + message;
31 | div.className = "error";
32 | $("#log")[0].appendChild(div);
33 | $("#console").attr({ scrollTop: $("#console").attr("scrollHeight") }, 3000);
34 | }
35 | window.console.info = function(message){
36 | var div = document.createElement("div");
37 | div.innerHTML = message;
38 | div.className = "info";
39 | $("#info")[0].appendChild(div);
40 | $("#console").attr({ scrollTop: $("#console").attr("scrollHeight") }, 3000);
41 | setTimeout(function(){
42 | $(div).fadeOut(2000,function(){
43 | div.parentNode.removeChild(div);
44 | });
45 | }, 10000);
46 | }
47 | //}
--------------------------------------------------------------------------------
/shader/sphere.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_normalCameraView",
3 | "u_modelView",
4 | "u_normalModelView",
5 | "u_projection",
6 | "u_diffuseMap",
7 | "u_lightDirection",
8 | "u_lightColor",
9 | "u_ambientLightColor",
10 | ],
11 | "attributes": ["a_position", "a_normal", "a_texCoords"],
12 | "vertexShader": "
13 | #ifdef GL_ES
14 | precision highp float;
15 | #endif
16 |
17 | attribute vec3 a_position;
18 | attribute vec3 a_normal;
19 | attribute vec2 a_texCoords;
20 |
21 | uniform mat4 u_cameraView;
22 | uniform mat4 u_modelView;
23 | uniform mat4 u_projection;
24 | uniform mat4 u_normalCameraView;
25 | uniform mat4 u_normalModelView;
26 |
27 | uniform sampler2D u_diffuseMap;
28 |
29 | varying vec2 v_texCoords;
30 | varying vec3 v_normal;
31 | varying vec4 v_globalPosition;
32 | varying vec4 v_localPosition;
33 |
34 | void main(void) {
35 | v_texCoords = a_texCoords;
36 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
37 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
38 | v_localPosition = u_cameraView * v_globalPosition;
39 | gl_Position = u_projection * v_localPosition;
40 | }
41 | ",
42 | "fragmentShader": "
43 | #ifdef GL_ES
44 | precision highp float;
45 | #endif
46 |
47 | varying vec3 v_normal;
48 | varying vec4 v_globalPosition;
49 | varying vec4 v_localPosition;
50 | varying vec2 v_texCoords;
51 |
52 | uniform sampler2D u_diffuseMap;
53 | uniform vec3 u_lightDirection;
54 | uniform vec4 u_lightColor;
55 | uniform vec4 u_ambientLightColor;
56 | uniform vec3 u_playerPosition;
57 | uniform mat4 u_cameraView;
58 | uniform mat4 u_modelView;
59 | uniform mat4 u_normalCameraView;
60 | uniform float u_time;
61 |
62 | void main(void) {
63 | vec3 normal = normalize(v_normal);
64 | float product = dot(normal, (u_normalCameraView * vec4(u_lightDirection, 0.0)).xyz);
65 | gl_FragColor = u_ambientLightColor + u_lightColor * (max(0.0, product) * 3.0) / 3.0;
66 | gl_FragColor *= texture2D(u_diffuseMap, vec2( v_texCoords.x, v_texCoords.y));
67 | float dotp = dot(reflect((u_normalCameraView * vec4(u_lightDirection,0.0)).xyz, (vec4(-normal,0.0)).xyz), (vec4(0.0, 0.0, -1.0, 0.0)).xyz);
68 | gl_FragColor += pow(dotp, 30.0) * u_lightColor;
69 | // gl_FragColor += texture2D(u_diffuseMap, (normal.xy + 1.0) / 2.0) * pow(length(normal.xy), 10.0);
70 | //gl_FragColor = vec4(v_worldPosition.y / 256.0, 1.0, 1.0, 1.0);
71 | // gl_FragColor += pow(length(normal.xy), 22.0) * vec4(1.0,1.0,1.0,1.0) * (1.0) * gl_FragColor;
72 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
73 | }
74 | "
75 | }
--------------------------------------------------------------------------------
/shader/metal.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_modelView",
3 | "u_normalCameraView",
4 | "u_normalModelView",
5 | "u_projection",
6 | "u_diffuseMap",
7 | ],
8 | "attributes": ["a_position", "a_normal"],
9 | "vertexShader": "
10 | #ifdef GL_ES
11 | precision highp float;
12 | #endif
13 |
14 | attribute vec3 a_position;
15 | attribute vec3 a_normal;
16 | attribute vec2 a_texCoords;
17 |
18 | uniform mat4 u_cameraView;
19 | uniform mat4 u_modelView;
20 | uniform mat4 u_projection;
21 | uniform mat4 u_normalCameraView;
22 | uniform mat4 u_normalModelView;
23 |
24 | uniform sampler2D u_diffuseMap;
25 |
26 | varying vec2 v_texCoords;
27 | varying vec3 v_normal;
28 | varying vec4 v_globalPosition;
29 | varying vec4 v_localPosition;
30 |
31 | void main(void) {
32 | v_texCoords = a_texCoords;
33 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
34 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
35 | v_localPosition = u_cameraView * v_globalPosition;
36 | gl_Position = u_projection * v_localPosition;
37 | }
38 | ",
39 | "fragmentShader": "
40 | #ifdef GL_ES
41 | precision highp float;
42 | #endif
43 |
44 | varying vec3 v_normal;
45 | varying vec4 v_globalPosition;
46 | varying vec4 v_localPosition;
47 | varying vec2 v_texCoords;
48 |
49 | uniform sampler2D u_diffuseMap;
50 | uniform vec3 u_lightDirection;
51 | uniform vec4 u_lightColor;
52 | uniform vec4 u_ambientLightColor;
53 | uniform vec3 u_playerPosition;
54 | uniform mat4 u_cameraView;
55 | uniform mat4 u_modelView;
56 | uniform mat4 u_normalCameraView;
57 | uniform float u_time;
58 |
59 | void main(void) {
60 | vec3 normal = normalize(v_normal);
61 | // float product = dot(normal, (u_normalCameraView * vec4(u_lightDirection, 0.0)).xyz);
62 | // gl_FragColor = u_ambientLightColor + u_lightColor * (max(0.0, product) * 3.0) / 3.0;
63 | if (normal.z > 0.0) {
64 | gl_FragColor = texture2D(u_diffuseMap, vec2(normal.x,-normal.y)/2.0 + (1.0/2.0));
65 | } else {
66 | vec2 nn = normalize(normal.xy);
67 | gl_FragColor = texture2D(u_diffuseMap, vec2(nn.x,-nn.y)/2.0 + (1.0/2.0));
68 | }
69 |
70 | // gl_FragColor = vec4(1.0,1.0,1.0,1.0);
71 | // float dotp = dot(reflect((u_normalCameraView * vec4(u_lightDirection,0.0)).xyz, (vec4(-normal,0.0)).xyz), (vec4(0.0, 0.0, -1.0, 0.0)).xyz);
72 | // gl_FragColor += pow(dotp, 30.0) * u_lightColor;
73 | // gl_FragColor += texture2D(u_diffuseMap, (normal.xy + 1.0) / 2.0) * pow(length(normal.xy), 10.0);
74 | // gl_FragColor = vec4(v_worldPosition.y / 256.0, 1.0, 1.0, 1.0);
75 | // gl_FragColor += pow(length(normal.xy), 22.0) * vec4(1.0,1.0,1.0,1.0) * (1.0) * gl_FragColor;
76 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
77 | }
78 | "
79 | }
--------------------------------------------------------------------------------
/shader/sonic.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_normalCameraView",
3 | "u_modelView",
4 | "u_normalModelView",
5 | "u_projection",
6 | "u_diffuseMap",
7 | "u_lightDirection",
8 | "u_lightColor",
9 | "u_ambientLightColor",
10 | "u_levelSize",
11 | "u_levelShadowMap"
12 | ],
13 | "attributes": ["a_position", "a_normal", "a_texCoords"],
14 | "vertexShader": "
15 | #ifdef GL_ES
16 | precision highp float;
17 | #endif
18 |
19 | attribute vec3 a_position;
20 | attribute vec3 a_normal;
21 | attribute vec2 a_texCoords;
22 |
23 | uniform mat4 u_cameraView;
24 | uniform mat4 u_modelView;
25 | uniform mat4 u_projection;
26 | uniform mat4 u_normalCameraView;
27 | uniform mat4 u_normalModelView;
28 |
29 | uniform sampler2D u_diffuseMap;
30 |
31 | varying vec2 v_texCoords;
32 | varying vec3 v_normal;
33 | varying vec4 v_globalPosition;
34 | varying vec4 v_localPosition;
35 |
36 | void main(void) {
37 | v_texCoords = a_texCoords;
38 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
39 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
40 | v_localPosition = u_cameraView * v_globalPosition;
41 | gl_Position = u_projection * v_localPosition;
42 | }
43 | ",
44 | "fragmentShader": "
45 | #ifdef GL_ES
46 | precision highp float;
47 | #endif
48 |
49 | varying vec3 v_normal;
50 | varying vec4 v_globalPosition;
51 | varying vec4 v_localPosition;
52 | varying vec2 v_texCoords;
53 |
54 | uniform sampler2D u_diffuseMap;
55 | uniform sampler2D u_levelShadowMap;
56 | uniform vec3 u_levelSize;
57 | uniform vec3 u_lightDirection;
58 | uniform vec4 u_lightColor;
59 | uniform vec4 u_ambientLightColor;
60 | uniform vec3 u_playerPosition;
61 | uniform mat4 u_cameraView;
62 | uniform mat4 u_modelView;
63 | uniform mat4 u_normalCameraView;
64 | uniform float u_time;
65 |
66 | void main(void) {
67 | vec3 normal = normalize(v_normal);
68 | float product = dot(normal, (u_normalCameraView * vec4(u_lightDirection, 0.0)).xyz);
69 | float shadowSourceHeight = texture2D(u_levelShadowMap, vec2((v_globalPosition.x)/ u_levelSize.x, (v_globalPosition.z) / u_levelSize.z)).r;
70 | float shadowCoefficient = max(1.0/10.0,min(1.0,(v_globalPosition.y - shadowSourceHeight * u_levelSize.y) / 20.0 + 1.0));
71 | product *= shadowCoefficient;
72 | gl_FragColor = u_ambientLightColor + u_lightColor * (max(0.0, product) * 3.0) / 3.0;
73 | gl_FragColor *= texture2D(u_diffuseMap, vec2( v_texCoords.x, v_texCoords.y));
74 | float dotp = dot(reflect((u_normalCameraView * vec4(u_lightDirection,0.0)).xyz, (vec4(-normal,0.0)).xyz), (vec4(0.0, 0.0, -1.0, 0.0)).xyz);
75 | gl_FragColor += pow(max(dotp, 0.0), 30.0) * u_lightColor / 5.0 * shadowCoefficient;
76 | // gl_FragColor += texture2D(u_diffuseMap, (normal.xy + 1.0) / 2.0) * pow(length(normal.xy), 10.0);
77 | //gl_FragColor = vec4(v_worldPosition.y / 256.0, 1.0, 1.0, 1.0);
78 | gl_FragColor += pow(length(normal.xy), 10.0) * u_lightColor * (1.0 - product) * gl_FragColor;
79 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
80 | }
81 | "
82 | }
--------------------------------------------------------------------------------
/shader/sky.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_modelView",
3 | "u_normalModelView",
4 | "u_projection",
5 | "u_cloudMap",
6 | "u_time"
7 | ],
8 | "attributes": ["a_position", "a_normal", "a_texCoords"],
9 | "vertexShader": "
10 | #ifdef GL_ES
11 | precision highp float;
12 | #endif
13 |
14 | attribute vec3 a_position;
15 | attribute vec3 a_normal;
16 | attribute vec2 a_texCoords;
17 |
18 | uniform mat4 u_cameraView;
19 | uniform mat4 u_modelView;
20 | uniform mat4 u_projection;
21 | uniform mat4 u_normalCameraView;
22 | uniform mat4 u_normalModelView;
23 |
24 | uniform sampler2D u_diffuseMap;
25 |
26 | varying vec2 v_texCoords;
27 | varying vec3 v_normal;
28 | varying vec4 v_globalPosition;
29 | varying vec4 v_localPosition;
30 | varying vec4 v_originalPosition;
31 |
32 | void main(void) {
33 | v_texCoords = a_texCoords;
34 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
35 | v_originalPosition = vec4(a_position, 1.0);
36 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
37 | v_localPosition = u_cameraView * v_globalPosition;
38 | gl_Position = u_projection * v_localPosition;
39 | }
40 | ",
41 | "fragmentShader": "
42 | #ifdef GL_ES
43 | precision highp float;
44 | #endif
45 |
46 | varying vec3 v_normal;
47 | varying vec4 v_globalPosition;
48 | varying vec4 v_localPosition;
49 | varying vec2 v_texCoords;
50 | varying vec4 v_originalPosition;
51 |
52 | uniform sampler2D u_cloudMap;
53 | uniform mat4 u_cameraView;
54 | uniform mat4 u_modelView;
55 | uniform mat4 u_normalCameraView;
56 | uniform float u_time;
57 |
58 | void main(void) {
59 | vec3 normal = normalize(v_normal);
60 | float t_time = u_time * 3.0;
61 | gl_FragColor = texture2D(u_cloudMap, v_originalPosition.xz / 10.0 + vec2(t_time/100.0, t_time/10.0) + vec2(cos(v_originalPosition.x/5.0+v_originalPosition.z/5.0+t_time/50.0),sin(v_originalPosition.x/5.0+v_originalPosition.z/5.0+t_time/100.0))/8.0);
62 | gl_FragColor *= texture2D(u_cloudMap, v_originalPosition.xz / 15.0 + vec2(t_time/20.0, t_time/40.0) + vec2(cos(v_originalPosition.x/2.0+v_originalPosition.z/3.0+t_time/20.0+1.0),sin(v_originalPosition.x/3.0+v_originalPosition.z/2.0+t_time/50.0+1.0))/12.0);
63 | gl_FragColor *= texture2D(u_cloudMap, v_originalPosition.xz / 20.0 + vec2(t_time/80.0, t_time/70.0) + vec2(cos(v_originalPosition.x/8.0+v_originalPosition.z/4.0+t_time/100.0+2.0),sin(v_originalPosition.x/4.0+v_originalPosition.z/8.0+t_time/20.0+2.0))/20.0);
64 | gl_FragColor *= texture2D(u_cloudMap, v_originalPosition.xz / 50.0 + vec2(t_time/40.0, t_time/20.0));
65 | gl_FragColor *= abs(v_originalPosition.y/10.0);
66 | gl_FragColor = min(max(gl_FragColor, 1.0/5.0), 3.0/4.0) - 1.0/5.0;
67 | gl_FragColor += 1.0/abs(v_originalPosition.y/5.0);
68 | gl_FragColor *= 10.0/13.0;
69 | gl_FragColor += vec4(1.0/5.0,1.0/3.0,4.0/5.0,0.0);
70 | // gl_FragColor += vec4(3.0/5.0,1.0/3.0,1.0/10.0,0.0);
71 | gl_FragColor += vec4(3.0/50.0,1.0/30.0,1.0/10.0,0.0) * 2.0;
72 | gl_FragColor = min(gl_FragColor, 1.0);
73 | // if (v_originalPosition.y < 0.0) {
74 | // gl_FragColor *= vec4(10.0,10.0,10.0,1.0) / abs(v_originalPosition.y);
75 | // }
76 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
77 | }
78 | "
79 | }
--------------------------------------------------------------------------------
/shader/monitor.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_normalCameraView",
3 | "u_modelView",
4 | "u_normalModelView",
5 | "u_projection",
6 | "u_diffuseMap",
7 | "u_displayMap",
8 | "u_displayImageMap",
9 | "u_specularMap",
10 | "u_lightDirection",
11 | "u_lightColor",
12 | "u_ambientLightColor",
13 | "u_time",
14 | "u_levelShadowMap",
15 | "u_levelSize"
16 | ],
17 | "attributes": ["a_position", "a_normal", "a_texCoords"],
18 | "vertexShader": "
19 | #ifdef GL_ES
20 | precision highp float;
21 | #endif
22 |
23 | attribute vec3 a_position;
24 | attribute vec3 a_normal;
25 | attribute vec2 a_texCoords;
26 |
27 | uniform mat4 u_cameraView;
28 | uniform mat4 u_modelView;
29 | uniform mat4 u_projection;
30 | uniform mat4 u_normalCameraView;
31 | uniform mat4 u_normalModelView;
32 |
33 | uniform sampler2D u_diffuseMap;
34 |
35 | varying vec2 v_texCoords;
36 | varying vec3 v_normal;
37 | varying vec4 v_globalPosition;
38 | varying vec4 v_localPosition;
39 |
40 | void main(void) {
41 | v_texCoords = a_texCoords;
42 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
43 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
44 | v_localPosition = u_cameraView * v_globalPosition;
45 | gl_Position = u_projection * v_localPosition;
46 | }
47 | ",
48 | "fragmentShader": "
49 | #ifdef GL_ES
50 | precision highp float;
51 | #endif
52 |
53 | varying vec3 v_normal;
54 | varying vec4 v_globalPosition;
55 | varying vec4 v_localPosition;
56 | varying vec2 v_texCoords;
57 |
58 | uniform sampler2D u_diffuseMap;
59 | uniform sampler2D u_specularMap;
60 | uniform sampler2D u_displayMap;
61 | uniform sampler2D u_displayImageMap;
62 | uniform sampler2D u_levelShadowMap;
63 | uniform vec3 u_levelSize;
64 | uniform vec3 u_lightDirection;
65 | uniform vec4 u_lightColor;
66 | uniform vec4 u_ambientLightColor;
67 | uniform vec3 u_playerPosition;
68 | uniform mat4 u_cameraView;
69 | uniform mat4 u_modelView;
70 | uniform mat4 u_normalCameraView;
71 | uniform float u_time;
72 |
73 | void main(void) {
74 | vec3 normal = normalize(v_normal);
75 | float product = dot(normal, (u_normalCameraView * vec4(u_lightDirection, 0.0)).xyz);
76 | float shadowSourceHeight = texture2D(u_levelShadowMap, vec2((v_globalPosition.x)/ u_levelSize.x, (v_globalPosition.z) / u_levelSize.z)).r;
77 | float shadowCoefficient = max(0.0,min(1.0,(v_globalPosition.y - shadowSourceHeight * u_levelSize.y) / 20.0 + 1.0));
78 | product *= shadowCoefficient;
79 | gl_FragColor = u_ambientLightColor + u_lightColor * max(0.0, product);
80 | gl_FragColor *= texture2D(u_diffuseMap, v_texCoords);
81 | // gl_FragColor = vec4(0.0,0.0,0.0,1.0);
82 | float dotp = dot(reflect((u_normalCameraView * vec4(u_lightDirection,0.0)).xyz, (vec4(-normal,0.0)).xyz), (vec4(0.0, 0.0, -1.0, 0.0)).xyz);
83 | gl_FragColor += pow(max(0.0, dotp), 100.0 * texture2D(u_specularMap, v_texCoords).r) * texture2D(u_specularMap, v_texCoords) * 10.0 * shadowCoefficient;
84 | vec4 imgPosition = texture2D(u_displayMap, v_texCoords);
85 | float interf = (cos(imgPosition.g + u_time * 2.0) - 29.0/30.0) * 30.0;
86 | vec4 imgColor = imgPosition.b * texture2D(u_displayImageMap, imgPosition.rg + vec2((1.0 - max(0.0,interf)) + sin(u_time / 2.0) * cos(u_time * 12.0 + imgPosition.g * 20.0) / 40.0 + sin(u_time / 2.0) / 32.0, sin(u_time / 2.0) / 16.0));
87 | if (interf > 0.0) {
88 | float gray = (imgColor.r + imgColor.g + imgColor.b) / 3.0;
89 | imgColor = vec4(gray,gray,gray, 1.0) * (2.0 - interf);
90 | }
91 | gl_FragColor += imgColor;
92 | // gl_FragColor += texture2D(u_diffuseMap, (normal.xy + 1.0) / 2.0) * pow(length(normal.xy), 10.0);
93 | //gl_FragColor = vec4(v_worldPosition.y / 256.0, 1.0, 1.0, 1.0);
94 | // gl_FragColor += pow(length(normal.xy), 22.0) * vec4(1.0,1.0,1.0,1.0) * (1.0) * gl_FragColor;
95 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
96 | }
97 | "
98 | }
--------------------------------------------------------------------------------
/shader/glow.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_image" ],
2 | "attributes": ["a_position", "a_texCoords" ],
3 | "vertexShader": "
4 | #ifdef GL_ES
5 | precision highp float;
6 | #endif
7 |
8 | uniform sampler2D u_image;
9 |
10 | attribute vec3 a_position;
11 | attribute vec2 a_texCoords;
12 |
13 | varying vec2 v_texCoords;
14 |
15 | void main(void) {
16 | gl_Position = vec4(a_position, 1.0);
17 | v_texCoords = a_texCoords;
18 | }
19 | ",
20 | "fragmentShader": "
21 | #ifdef GL_ES
22 | precision highp float;
23 | #endif
24 |
25 | uniform sampler2D u_image;
26 |
27 | varying vec2 v_texCoords;
28 |
29 | void main(void) {
30 | const float frac = 600.0;
31 | const float frac2 = 450.0;
32 | // float x = 0.5;
33 | float i = 0.0;
34 | vec4 sumGlow = vec4(0.0,0.0,0.0,0.0);
35 | vec4 maxGlow = vec4(0.0,0.0,0.0,0.0);
36 | for(float x = 0.5; x < 10.0; x+=3.0/10.0) {
37 | /* vec4 thisGlow = (texture2D(u_image, v_texCoords + vec2(x/frac,x/frac)) +
38 | texture2D(u_image, v_texCoords + vec2(-x/frac,x/frac)) +
39 | texture2D(u_image, v_texCoords + vec2(x/frac,-x/frac)) +
40 | texture2D(u_image, v_texCoords + vec2(-x/frac,-x/frac)) +
41 | texture2D(u_image, v_texCoords + vec2(0.0,-x/frac2)) +
42 | texture2D(u_image, v_texCoords + vec2(-x/frac2,0.0)) +
43 | texture2D(u_image, v_texCoords + vec2(0.0, x/frac2)) +
44 | texture2D(u_image, v_texCoords + vec2(x/frac2, 0.0))) * (10.0-x);// * (1.0 + vec4(cos(x), sin(x), cos(x+2.0), 1.0)/5.0); */
45 | vec4 thisGlow = vec4(0.0,0.0,0.0,0.0);
46 | vec4 c;
47 | float len;
48 | c = texture2D(u_image, v_texCoords + vec2(x/frac,x/frac));
49 | len = length(c.xyz);
50 | if (length(c.xyz) > 1.0) {
51 | thisGlow += c - c/len;
52 | }
53 | c = texture2D(u_image, v_texCoords + vec2(-x/frac,x/frac));
54 | len = length(c.xyz);
55 | if (length(c.xyz) > 1.0) {
56 | thisGlow += c - c/len;
57 | }
58 | c = texture2D(u_image, v_texCoords + vec2(x/frac,-x/frac));
59 | len = length(c.xyz);
60 | if (length(c.xyz) > 1.0) {
61 | thisGlow += c - c/len;
62 | }
63 | c = texture2D(u_image, v_texCoords + vec2(-x/frac,-x/frac));
64 | len = length(c.xyz);
65 | if (length(c.xyz) > 1.0) {
66 | thisGlow += c - c/len;
67 | }
68 | /* c = texture2D(u_image, v_texCoords + vec2(x/frac2,0.0));
69 | if (length(c.xyz) > 1.0) {
70 | thisGlow += c - normalize(c);
71 | }
72 | c = texture2D(u_image, v_texCoords + vec2(-x/frac2,0.0));
73 | if (length(c.xyz) > 1.0) {
74 | thisGlow += c - normalize(c);
75 | }
76 | c = texture2D(u_image, v_texCoords + vec2(0.0,x/frac2));
77 | if (length(c.xyz) > 1.0) {
78 | thisGlow += c - normalize(c);
79 | }
80 | c = texture2D(u_image, v_texCoords + vec2(0.0,-x/frac2));
81 | if (length(c.xyz) > 1.0) {
82 | thisGlow += c - normalize(c);
83 | }*/
84 | thisGlow *= (10.0-x);
85 | maxGlow = max(maxGlow, thisGlow);
86 | sumGlow += thisGlow;
87 | // x += 3.0/1.0;
88 | i += (10.0-x) * 3.0/1.0;//* (1.0 + vec4(cos(x), sin(x), cos(x+2.0), 1.0)/5.0);
89 | }
90 | sumGlow /= 2.0 * i;
91 | maxGlow /= 2.0 * (i / 4.0);
92 |
93 | float len = length(maxGlow.rgb);
94 | // float lengthPow = min(len, 10.0/10.0) / 5.0;
95 | // glow = glow * pow(lengthPow, 2.0);
96 | vec4 glow;
97 | if (length(sumGlow.rgb) > 0.0) {
98 | glow = vec4(normalize(sumGlow.rgb), 1.0);
99 | } else {
100 | glow = sumGlow;
101 | }
102 | // len = pow(max(len, 0.0), 1.0);
103 | glow = glow * len;
104 |
105 | /* vec4 color = vec4(texture2D(u_image, v_texCoords * vec2(101.0/100.0, 100.0/100.0) + vec2(0.0,0.0)).r,
106 | texture2D(u_image, v_texCoords * vec2(100.0/100.0, 101.0/100.0) + vec2(0.0,0.0)).g,
107 | texture2D(u_image, v_texCoords * vec2(99.0/100.0, 100.0/100.0) + vec2(0.0,0.0)).b,
108 | 1.0);*/
109 | vec4 color = texture2D(u_image, v_texCoords + vec2(0.0,0.0));
110 |
111 | gl_FragColor = color + glow;
112 |
113 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
114 | }
115 | "
116 | }
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | window.onload = function(){
2 | var canvas = $("#c")[0];
3 | var engine = Engine(canvas);
4 |
5 | /* var pitch = 0.0;
6 | var yaw = 0.0;
7 | var holding = false;
8 | var oldX, oldY, oldPitch, oldYaw;
9 | var alpha = 0.0;
10 | window.addEventListener("mouseup", function(e){
11 | holding = false;
12 | }, false);
13 | window.addEventListener("mousedown", function(e){
14 | oldX = e.clientX;
15 | oldY = e.clientY;
16 | oldYaw = yaw;
17 | oldPitch = pitch;
18 | holding = true;
19 | e.preventDefault();
20 | e.stopPropagation();
21 | }, false);
22 | window.addEventListener("mousemove", function(e){
23 | if (holding) {
24 | pitch = oldPitch + (e.clientY - oldY) * 0.01;
25 | yaw = oldYaw + (e.clientX - oldX) * 0.01;
26 | }
27 | }, false);*/
28 | engine.resources.load("mesh/sky.jsonmesh");
29 | engine.resources.load("mesh/monitor.jsonmesh");
30 | engine.resources.load("mesh/spinball.jsonmesh")
31 | engine.resources.load("mesh/sonic.jsonmesh");
32 | engine.resources.load("mesh/spring.jsonmesh");
33 | engine.resources.load("mesh/ring.jsonmesh");
34 | engine.resources.load("level/lvl0.jsonlevel");
35 | engine.resources.load("shader/depth.jsonshader");
36 | engine.resources.load("shader/glow.jsonshader");
37 | var interval = setInterval(
38 | function () {
39 | // try {
40 | if (engine.resources.totalPending() == 0) {
41 | var camera = engine.world.Camera();
42 | camera.rotation(Matrix.RotationX(-1/4*Math.PI).ensure4x4());
43 | engine.world.add(camera);
44 | camera.position($V([128,512,512]));
45 | var level = engine.world.LevelEntity(engine.resources.get("level/lvl0.jsonlevel"));
46 | engine.world.add(level);
47 | var sky = new Sky(engine, camera);
48 | engine.world.add(sky);
49 | /* for (var c = 0; c<32; c++) {
50 | var ring = Ring(engine, player, level);
51 | ring.position($V([1536/2, 64, 64]));
52 | // mesh.scale($V([0.3,0.3,0.3]));
53 | engine.world.add(ring);
54 | }*/
55 |
56 |
57 |
58 |
59 | var player = Player(engine, camera, level);
60 | player.position($V([1536/2,128/2,128/2]));
61 | engine.world.add(player);
62 | engine.world.add(new Spring(engine, player));
63 |
64 | clearInterval(interval);
65 | var alpha = 0.0;
66 | var updateFunc;
67 | interval = requestAnimationFrame( updateFunc = function () {
68 | alpha += 0.1;
69 | if ($(window).width() != canvas.width || $(window).height() != canvas.height) {
70 | canvas.width = $(window).width();
71 | canvas.height = $(window).height();
72 | engine.gfx.gl.viewport(0,0,canvas.width, canvas.height);
73 | }
74 |
75 | /* //alpha+= 0.1;
76 | // for (var c = 0; c < 10; c++) {
77 | //engine.resources.get("mesh/lvl0.jsonmesh").render(Matrix.Perspective(45, canvas.width/canvas.height, 1, 1000), Matrix.Translation($V([0,0,-50])).x(Matrix.RotationY(yaw+alpha *0.1).ensure4x4()).x(Matrix.RotationX(pitch).ensure4x4()).x(Matrix.Translation($V([0,-10,0]))).x($V([256.0,256.0,256.0,1.0]).toDiagonalMatrix()), 0, [{ u_lightColor: $V([1.0,1.0,1.0,1.0]), u_lightDirection: $V([Math.sin(alpha* 0.01), Math.cos(alpha * 0.01), 0]) }, {u_ambientLightColor: $V([0.0,0.2,0.1,1.0])}]);
78 | engine.resources.get("level/lvl0.jsonlevel").render(Matrix.Perspective(45, canvas.width/canvas.height, 1, 10000).x(Matrix.RotationX(pitch).ensure4x4()).x(Matrix.RotationY(yaw).ensure4x4()).x(Matrix.Translation($V([-128,-128,-128]))), [{ u_lightColor: $V([1.0,1.0,1.0,1.0]), u_lightDirection: $V([Math.sin(alpha* 0.1), Math.cos(alpha * 0.1), 0]) }, {u_ambientLightColor: $V([0.0,0.2,0.1,1.0])}]);
79 | // }*/
80 | //camera.position($V([0, 0, -10]));
81 |
82 | try {
83 | alpha += 0.001;
84 | //camera.rotation(Matrix.RotationX(0.0).ensure4x4().x(Matrix.RotationY(0.1).ensure4x4()).x(camera.rotation()))
85 | engine.world.update();
86 | engine.world.render();
87 | var seconds = engine.world.time();
88 | $("#time")[0].innerHTML = Math.floor(seconds / 60) + ":" + ((Math.floor(seconds) % 60 < 10)?"0":"") + Math.floor(seconds) % 60;
89 | requestAnimationFrame(updateFunc);
90 | } catch(e) {
91 | console.error(e.message + e.stack);
92 | //clearInterval(interval);
93 | }
94 | });
95 | }
96 | /* } catch (e) {
97 | console.error(e.message);
98 | clearInterval(interval);
99 | }*/
100 | }, 1000/60.0);
101 | }
--------------------------------------------------------------------------------
/js/ResourceManager.js:
--------------------------------------------------------------------------------
1 | var ResourceManager = function(engine){
2 | var resourceManager = {};
3 | var loadedResources = {};
4 | var totalPending = 0;
5 |
6 | resourceManager.load = function(path) {
7 | if (loadedResources[path] !== undefined) {
8 | // resource already loaded or loading
9 | return;
10 | }
11 |
12 | console.log("Requesting remote resource file: " + path);
13 |
14 | var extension = path.split(".")[1];
15 | switch(extension) {
16 | case "bmp": // I don't think we'll be using BMP, but who knows?
17 | case "gif":
18 | case "png":
19 | case "jpeg":
20 | case "jpg":
21 | var image = document.createElement("img");
22 | image.onload = function() {
23 | var texture = engine.gfx.gl.createTexture();
24 | engine.gfx.gl.bindTexture( engine.gfx.gl.TEXTURE_2D, texture);
25 | engine.gfx.gl.texImage2D( engine.gfx.gl.TEXTURE_2D, 0, engine.gfx.gl.RGBA, engine.gfx.gl.RGBA, engine.gfx.gl.UNSIGNED_BYTE, image);
26 | engine.gfx.gl.texParameteri( engine.gfx.gl.TEXTURE_2D, engine.gfx.gl.TEXTURE_MAG_FILTER, engine.gfx.gl.LINEAR);
27 | engine.gfx.gl.texParameteri( engine.gfx.gl.TEXTURE_2D, engine.gfx.gl.TEXTURE_MIN_FILTER, engine.gfx.gl.LINEAR);
28 | engine.gfx.gl.generateMipmap(engine.gfx.gl.TEXTURE_2D);
29 | // if (Math.floor((Math.log(image.width) / Math.log( 2 ))) != (Math.log(image.width) / Math.log( 2 ))) {
30 | // console.warn("Texture " + path + " is not square and/or doesn't have power of two dimensions.");
31 | // }
32 | loadedResources[path] = texture;
33 | totalPending--;
34 | console.log("Resource loaded: " + path);
35 | };
36 | totalPending++;
37 | image.src = path;
38 | break;
39 | case "jsonmesh":
40 | totalPending++;
41 | $.ajax({ url: path, dataType: "text", success: function(data) {
42 | console.log("Resource loaded: " + path);
43 | try {
44 | data = JSON.parse(data);
45 | } catch (e) {
46 | try {
47 | data = JSON.forgivingParse(data);
48 | console.warn("Falling back to non-standard JSON parsing. (Have you escaped all control characters and removed all comments?)");
49 | } catch (e) {
50 | console.error("Malformed JSON.");
51 | throw e;
52 | }
53 | }
54 | try {
55 | var mesh = new engine.gfx.Mesh(data);
56 | loadedResources[path] = mesh;
57 | totalPending--;
58 | } catch (e) {
59 | console.error(e.message + e.stack)
60 | throw e;
61 | }
62 | } });
63 | break;
64 | case "jsonshader":
65 | totalPending++;
66 | $.ajax({ url: path, dataType: "text", success: function(data) {
67 | console.log("Resource loaded: " + path);
68 | try {
69 | data = JSON.parse(data);
70 | } catch (e) {
71 | try {
72 | data = JSON.forgivingParse(data);
73 | console.warn("Falling back to non-standard JSON parsing. (Have you escaped all control characters and removed all comments?)");
74 | } catch (e) {
75 | console.error("Malformed JSON.");
76 | throw e;
77 | }
78 | }
79 | try {
80 | var shader = new engine.gfx.Shader(data, path);
81 | loadedResources[path] = shader;
82 | totalPending--;
83 | } catch (e) {
84 | console.error(e.message + e.stack)
85 | throw e;
86 | }
87 | } });
88 | break;
89 | case "jsonlevel":
90 | totalPending++;
91 | $.ajax({ url: path, dataType: "text", success: function(data) {
92 | console.log("Resource loaded: " + path);
93 | try {
94 | data = JSON.parse(data);
95 | } catch (e) {
96 | try {
97 | data = JSON.forgivingParse(data);
98 | console.warn("Falling back to non-standard JSON parsing. (Have you escaped all control characters and comments?)");
99 | } catch (e) {
100 | console.error("Malformed JSON.");
101 | throw e;
102 | }
103 | }
104 | try {
105 | var level = new engine.gfx.Level(data, path);
106 | loadedResources[path] = level;
107 | totalPending--;
108 | } catch (e) {
109 | console.error(e.message + e.stack)
110 | throw e;
111 | }
112 | } });
113 | break;
114 | }
115 | loadedResources[path] = null;
116 | }
117 |
118 | resourceManager.hasLoaded = function(path) {
119 | if (loadedResources[path]) {
120 | return true;
121 | }
122 | return false;
123 | }
124 |
125 | resourceManager.get = function(path) {
126 | var resource = loadedResources[path];
127 | if (resource === undefined) {
128 | throw new Error("Tried to use a resource that hasn't been requested: " + path);
129 | } else if (resource === null) {
130 | throw new Error("Tried to use a resource that hasn't finished loading: " + path);
131 | }
132 | return resource;
133 | }
134 |
135 | resourceManager.totalPending = function() {
136 | return totalPending;
137 | }
138 |
139 | return resourceManager;
140 | }
--------------------------------------------------------------------------------
/shader/default.jsonshader:
--------------------------------------------------------------------------------
1 | {"uniforms": [ "u_cameraView",
2 | "u_normalCameraView",
3 | "u_modelView",
4 | "u_normalModelView",
5 | "u_projection",
6 | "u_diffuseMap",
7 | "u_ghostMap",
8 | "u_lightDirection",
9 | "u_lightColor",
10 | "u_ambientLightColor",
11 | "u_levelShadowMap",
12 | "u_time",
13 | "u_levelSize",
14 | "u_dynamicShadowMap",
15 | "u_dynamicShadowMapPosition"],
16 | "attributes": ["a_position", "a_normal", "a_texCoords"],
17 | "vertexShader": "
18 | #ifdef GL_ES
19 | precision highp float;
20 | #endif
21 |
22 | attribute vec3 a_position;
23 | attribute vec3 a_normal;
24 | attribute vec2 a_texCoords;
25 |
26 | uniform mat4 u_cameraView;
27 | uniform mat4 u_modelView;
28 | uniform mat4 u_projection;
29 | uniform mat4 u_normalCameraView;
30 | uniform mat4 u_normalModelView;
31 |
32 | uniform sampler2D u_diffuseMap;
33 |
34 | varying vec2 v_texCoords;
35 | varying vec3 v_normal;
36 | varying vec4 v_globalPosition;
37 | varying vec4 v_localPosition;
38 |
39 | void main(void) {
40 | v_texCoords = a_texCoords;
41 | v_normal = (u_normalCameraView * (u_normalModelView * vec4(a_normal, 0.0))).xyz;
42 | v_globalPosition = u_modelView * vec4(a_position, 1.0);
43 | v_localPosition = u_cameraView * v_globalPosition;
44 | gl_Position = u_projection * v_localPosition;
45 | // float distortion = (pow(v_localPosition.x, 2.0) + pow(v_localPosition.y, 2.0))/ 2000.0;
46 | // gl_Position += vec4(-(distortion) * normalize(gl_Position.xy),sqrt(distortion),0.0);
47 | }
48 | ",
49 | "fragmentShader": "
50 | #ifdef GL_ES
51 | precision highp float;
52 | #endif
53 |
54 | varying vec3 v_normal;
55 | varying vec4 v_globalPosition;
56 | varying vec4 v_localPosition;
57 | varying vec2 v_texCoords;
58 |
59 | uniform sampler2D u_levelShadowMap;
60 | uniform sampler2D u_diffuseMap;
61 | uniform sampler2D u_ghostMap;
62 | uniform sampler2D u_dynamicShadowMap;
63 | uniform vec3 u_dynamicShadowMapPosition;
64 | uniform vec3 u_levelSize;
65 | uniform vec3 u_lightDirection;
66 | uniform vec4 u_lightColor;
67 | uniform vec4 u_ambientLightColor;
68 | uniform vec3 u_playerPosition;
69 | uniform mat4 u_cameraView;
70 | uniform mat4 u_modelView;
71 | uniform mat4 u_normalCameraView;
72 | uniform float u_time;
73 |
74 | void main(void) {
75 | float z = - pow(v_localPosition.x * v_localPosition.x * 5.0 / 10.0 + v_localPosition.y * v_localPosition.y * 4.0, 1.0/2.0) * 6.0 / 10.0 + v_localPosition.z * 1.0 + v_localPosition.y * 12.0/10.0 + cos(v_localPosition.y/6.0 + u_time * 6.0) * 2.0 + sin(v_localPosition.x/6.0 + u_time * 6.0) * 2.0;
76 | if (z > -280.0) {
77 | if (z > -270.0) {
78 | vec4 textureColor = texture2D(u_ghostMap, v_texCoords);//*/vec2(v_texCoords.x + sin(v_localPosition.x*12.0 + u_time * 3.0) / 100.0, v_texCoords.y + cos(v_localPosition.y*12.0 + u_time * 3.0) / 100.0));
79 | if (textureColor.a > 20.0/100.0) {
80 | gl_FragColor = vec4(textureColor.a,textureColor.a, textureColor.a,1.0);
81 | } else {
82 | discard;
83 | }
84 | }
85 | else {
86 | if (z < -278.0) { //mod(z, 7.0) < 6.0) {
87 | gl_FragColor = vec4(1.0,1.0,1.0,1.0);
88 | } else {
89 | discard;
90 | }
91 | }
92 | } else {
93 | vec3 normal = normalize(v_normal);
94 | float product = dot(normal, (u_normalCameraView * vec4(u_lightDirection, 0.0)).xyz);
95 | float shadowSourceHeight = texture2D(u_levelShadowMap, vec2((v_globalPosition.x)/ u_levelSize.x, (v_globalPosition.z) / u_levelSize.z)).r;
96 | float dynamicShadowHeight = texture2D(u_dynamicShadowMap, vec2(0.0, 1.0) + vec2(1.0,-1.0) * (v_globalPosition.xz - u_dynamicShadowMapPosition.xz + 170.0)/350.0).r / 1000.0 / u_levelSize.y;
97 | if (dynamicShadowHeight > 0.0)
98 | shadowSourceHeight = max(dynamicShadowHeight + u_dynamicShadowMapPosition.y / u_levelSize.y, shadowSourceHeight);
99 | float shadowCoefficient = max(0.0,min(1.0,(v_globalPosition.y - shadowSourceHeight * u_levelSize.y) / 10.0 + 1.0));
100 | product *= shadowCoefficient;
101 | gl_FragColor = u_ambientLightColor + u_lightColor * max(0.0, product);
102 | // gl_FragColor += pow(length(normal.xy), 9.0) * vec4(0.1,0.0,0.0,1.0) * 1.0;
103 | gl_FragColor *= texture2D(u_diffuseMap, v_texCoords);
104 | //// gl_FragColor += texture2D(u_dynamicShadowMap, (v_globalPosition.xz - u_dynamicShadowMapPosition.xz)/100.0);
105 | // gl_FragColor.r = shadowSourceHeight;
106 | product = dot(reflect((u_normalCameraView * vec4(u_lightDirection,0.0)).xyz, (vec4(-normal,0.0)).xyz), (vec4(0.0, 0.0, -1.0, 0.0)).xyz);
107 | gl_FragColor += pow(max(0.0, product), 30.0) * u_lightColor * shadowCoefficient;
108 | // gl_FragColor += texture2D(u_diffuseMap, (normal.xy + 1.0) / 2.0) * pow(length(normal.xy), 10.0);
109 | //gl_FragColor = vec4(v_worldPosition.y / 256.0, 1.0, 1.0, 1.0);
110 | float fog = pow(v_localPosition.z / 1700.0, 2.0);
111 | gl_FragColor *= (1.0 - fog);
112 | gl_FragColor += fog * u_ambientLightColor + pow(1.0 - length(normal.xy), 25.0) * 3.0/10.0;
113 | gl_FragColor = vec4(gl_FragColor.rgb, 1.0);
114 | }
115 | }
116 | "
117 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | WebSonic Engine - WebGL Sonic the Hedgehog Game Engine
2 | ======================================================
3 |
4 | This is a Sonic engine I showcased on Sonic Retro last year. (2010)
5 |
6 | It's written on JavaScript, and makes use of the WebGL canvas API of HTML5 to
7 | draw its graphics.
8 |
9 | To play it, you'll need a modern browser with WebGL support (Firefox 4.0 and
10 | Chrome 10.0 are good enough) and a semi-decent graphics card. Just fire up
11 | `index.html` and you're ready to go.
12 |
13 | Keep in mind that to run it locally in Chrome, without a Web server, you'll
14 | need to launch the browser with the `--allow-file-access-from-files` command
15 | line flag.
16 |
17 | Introduction
18 | ------------
19 |
20 | I was planning on a bigger release for this project, with finished levels and
21 | gameplay, but couldn't get it done due to time constraints. This perfectly
22 | usable piece of code had been sitting on my hard drive for months untouched,
23 | which is totally unfair, so I figured it was a good idea to release it for
24 | other people to tinker with it.
25 |
26 | This Engine is a more or less accurate implementation of the algorithms on the
27 | [Sonic Physics Guide](http://info.sonicretro.org/Sonic_Physics_Guide),
28 | generalized to ℝ³. Some subtle adaptions had to be made, since the original
29 | Sonic engine used height maps for collisions, (I couldn't afford to do that
30 | here) used a strange fixed point encoding for numbers, (I couldn't bother to
31 | use something other than JS's `Number`) and had like, only two dimensions to
32 | worry about.
33 |
34 | My goal here was to make it "feel" almost exactly as the original Sonic games,
35 | if you only walked left and right and hit jump. I think I've accomplished that
36 | goal.
37 |
38 | **Beware:** The engine code is really messy, hacky and poorly documented.
39 | Sorry, I didn't have enough free time to refactor/clean it up. You might also
40 | find code doing something stupid as far as WebGL is concerned, since I wrote
41 | this engine as a learning exercise for WebGL.
42 |
43 | Controls
44 | --------
45 |
46 | [Q][W] - Rotate Camera
47 | [S] - Look Up
48 | [X] - Jump [^]
49 | [ Spacebar - Crouch Down ] [<][V][>] - Move
50 |
51 | Spindash = Crouch Dowm + Jump
52 |
53 | Technical Info
54 | --------------
55 |
56 | - The engine uses simple JSON wrappers for GLSL fragment and vector shaders.
57 | That seemed like a pretty good idea at the time, but is now one aspect of the
58 | engine I'm not completely happy about.
59 |
60 | - Textures are regular PNG or JPEG (or even SVG!) images loaded by the browser.
61 |
62 | - Meshes are stored on a custom JSON based format. (Yeah I know, using ASCII
63 | for binary data is kind of stupid, but it's easier to load.) Animations are
64 | vertex-based. (Yeah I know.) The source code of a simple converter
65 | from Quake's `md3` files to this custom format is included under `tools/`.
66 | You'll need to compile it with a C compiler to use it.
67 |
68 | - Sylvester is used for Matrix and Vector math. It's probably going to be
69 | slow by today's standards, specially if compared to something using
70 | `Float32Array`s, but it's only used on non-critical sections of the code.
71 |
72 | - Maps are tile-based! We have 128x128x128 tiles, as you would expect from a
73 | Sonic engine. :-) The JSON format used should be self-descriptive.
74 |
75 | - Objects can be indexed spatially using a grid, to allow for greater
76 | performance when having lots of objects.
77 |
78 | - The only form of collision checking available is ray-triangle intersection.
79 |
80 | - Check the Web Inspector / Web Console of your browser for (not-so)
81 | interesting debug messages.
82 |
83 | - The camera is always aligned to one of eight axes in relation to the player:
84 |
85 | \ | /
86 | \|/
87 | -----+-----
88 | /|\
89 | / | \
90 |
91 | This is very important, as it allows the player to move with great precision
92 | on a 3D environment using only the arrow keys.
93 |
94 | FAQ
95 | ---
96 |
97 | ### The control scheme sucks!
98 |
99 | *This is not really a question*. Anyway, I like it this way. Feel free to
100 | change it on the source.
101 |
102 | ### Can I play this with a Joystick?
103 |
104 | As of 2011, natively, no. You can use something like JoyToKey if you want it
105 | *that bad*. Expect that to change as progress is done by WHATWG and browser
106 | implementors with the HTML living standard's `` tag.
107 |
108 | Known Bugs/Issues
109 | -----------------
110 |
111 | - The matrix inversion algorithm used is numerically unstable. This is actually
112 | a Sylvester issue, and might result in wrong lighting on the models when
113 | they're rotated to specific angles.
114 |
115 | - Post-processing effects were *super slow*, and are commented out.
116 |
117 | - There's something very wrong with my shadow math. It currently depends on the
118 | camera position, and will break if you change the camera distance, FoV or
119 | orientation on any axis other than Y.
120 |
121 | Cool ideas if you have free time
122 | --------------------------------
123 |
124 | ### Easy
125 |
126 | - Edit the current test level!
127 |
128 | - Make a new level!
129 |
130 | - Change/add more textures!
131 |
132 | ### Medium
133 |
134 | - Implement new objects!
135 |
136 | - Add sound/music support!
137 |
138 | ### Hard
139 |
140 | - Add customizable control schemes!
141 |
142 | - Change the shader format to something more reasonable!
143 |
144 | - Add support for binary 3d model formats!
145 |
146 | - Refactor/clean up the code!
147 |
148 | - Fix the shadow code!
149 |
150 | - Implement bone-based animation!
151 |
152 | - Optimize/enhance post-processing code.
153 |
154 | - Make a level editor!
155 |
156 | - Implement online multiplayer using something like Socket.IO! (This one is
157 | pretty cool)
158 |
159 | ### Near-impossible
160 |
161 | - Make a finished game out of this ;D
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | WebSonic Engine
2 | Copyright (C) 2010, 2011 by Marco Aurélio "Mark the Echidna"
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
22 | -------------------------------------------------------------------------------
23 |
24 | The license above covers all the source code of the WebSonic engine:
25 |
26 | index.html
27 | js/*
28 | css/*
29 | tools/*
30 | level/*
31 | shader/*
32 |
33 | -------------------------------------------------------------------------------
34 |
35 | The 3d models and textures are covered by a Creative Commons BY-NC License:
36 |
37 | mesh/*
38 | texture/*
39 |
40 | -------------------------------------------------------------------------------
41 |
42 | This distribution also includes external libraries on which WebSonic depends.
43 | They are:
44 |
45 | lib/jquery.js
46 |
47 | /*!
48 | * jQuery JavaScript Library v1.4.2
49 | * http://jquery.com/
50 | *
51 | * Copyright 2010, John Resig
52 | * Dual licensed under the MIT or GPL Version 2 licenses.
53 | * http://jquery.org/license
54 | *
55 | * Includes Sizzle.js
56 | * http://sizzlejs.com/
57 | * Copyright 2010, The Dojo Foundation
58 | * Released under the MIT, BSD, and GPL Licenses.
59 | *
60 | * Date: Sat Feb 13 22:33:48 2010 -0500
61 | */
62 |
63 | lib/sylvester.js
64 |
65 | // === Sylvester ===
66 | // Vector and Matrix mathematics modules for JavaScript
67 | // Copyright (c) 2007 James Coglan
68 | //
69 | // Permission is hereby granted, free of charge, to any person obtaining
70 | // a copy of this software and associated documentation files (the "Software"),
71 | // to deal in the Software without restriction, including without limitation
72 | // the rights to use, copy, modify, merge, publish, distribute, sublicense,
73 | // and/or sell copies of the Software, and to permit persons to whom the
74 | // Software is furnished to do so, subject to the following conditions:
75 | //
76 | // The above copyright notice and this permission notice shall be included
77 | // in all copies or substantial portions of the Software.
78 | //
79 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
80 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
82 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
83 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
84 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
85 | // DEALINGS IN THE SOFTWARE.
86 |
87 | lib/sylvester.addons.js
88 |
89 | This is a piece of sample code extracted from a WebGL tutorial. I could no
90 | longer find the original source/author of the code, but a Google search for its
91 | first line: "// augment Sylvester some" revealed that it's in widespread use.
92 |
93 | I'm going to assume a MIT/BSD license here, since that's usual. If you're/know
94 | the original author, drop me a message and I'll attribute you/him. (Or, if you
95 | have problems with me using this code, drop me a message and I'll replace it
96 | with something else.)
97 |
98 | -------------------------------------------------------------------------------
99 |
100 | A Note About Sonic the Hedgehog Intelectual Property
101 | ----------------------------------------------------
102 |
103 | "Sonic the Hedgehog" is a registered trademark of SEGA Corporation. Some
104 | specific Sonic gameplay elements might be also patented by SEGA Corporation.
105 |
106 | All the code and assets included on this distribution are completely
107 | new/original material. This includes the textures, objects and the Sonic
108 | 3D model. NO CONTENT OR DATA "RIPPED" OR SOMEHOW "PIRATED" FROM ANY SONIC GAME
109 | IS INCLUDED ALONG WITH THIS CODE.
110 |
111 | The Sonic-related content on this distribution therefore violates NO COPYRIGHTS,
112 | but might violate trademark and patent rights, since it's used without express,
113 | written permission from SEGA.
114 |
115 | This is considered NOT TO be the case, due to:
116 |
117 | 1. The purely artistic/hobby nature of the content, comparable to
118 | fanfiction, fan-art or sculpures depicting Sonic the Hedgehog;
119 |
120 | 2. The strictly non-commercial license on which the Sonic related assets
121 | are distributed;
122 |
123 | 3. The existing good/strong bounds between the personal from SEGA and the
124 | Sonic fanbase;
125 |
126 | 4. Large amounts of similar, precedent material regarding which SEGA
127 | Corporation expressed no opposition or no concern (hundreds of existing Sonic
128 | fan-games)
129 |
130 | If you make use of the source on this distribution to create, specifically,
131 | a Sonic fan-game, you're STRONGLY ADVISED not to directly or indirectly profit
132 | from it. (e.g. selling licenses or advertising in game) Unless, of course,
133 | you're authorized to do so by SEGA Corporation (which is totally cool, then.)
134 |
135 | This is obviously NOT an obligation, since the code is MIT licensed, but not
136 | following this advice WILL likely get you into legal trouble, and may backfire
137 | at the Sonic fan-gaming community as a whole.
138 |
139 | If you make use of the source code on this distribution for anything else, do
140 | as you please. Just honor the MIT license.
--------------------------------------------------------------------------------
/tools/md3tojson3d.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | typedef unsigned char U8;
6 | typedef signed short int S16;
7 | typedef signed long int S32;
8 | typedef unsigned long int U32;
9 | typedef float F32;
10 | typedef struct { F32 x; F32 y; F32 z; } VEC3;
11 |
12 | #define MAX_QPATH 64
13 | #define MD3_XYZ_SCALE (1.0/64)
14 |
15 | typedef struct MD3 {
16 | S32 ident;
17 | S32 version;
18 | U8 name[MAX_QPATH];
19 | S32 flags;
20 | S32 numFrames;
21 | S32 numTags;
22 | S32 numSurfaces;
23 | S32 numSkins;
24 | S32 offsetFrames;
25 | S32 offsetT0ags;
26 | S32 offsetSurfaces;
27 | S32 offsetEOF;
28 | } MD3;
29 |
30 | typedef struct Frame {
31 | VEC3 minBounds;
32 | VEC3 maxBounds;
33 | VEC3 localOrigin;
34 | F32 radius;
35 | U8 name[16];
36 | } Frame;
37 |
38 | typedef struct Surface {
39 | U32 ident;
40 | U8 name[MAX_QPATH];
41 | S32 flags;
42 | S32 numFrames;
43 | S32 numShaders;
44 | S32 numVerts;
45 | S32 numTriangles;
46 | S32 offsetTriangles;
47 | S32 offsetShaders;
48 | S32 offsetSt;
49 | S32 offsetXYZNormal;
50 | S32 offsetEnd;
51 | } Surface;
52 |
53 | typedef struct Triangle {
54 | S32 v1;
55 | S32 v2;
56 | S32 v3;
57 | } Triangle;
58 |
59 | typedef struct TexCoord {
60 | F32 s;
61 | F32 t;
62 | } TexCoord;
63 |
64 | typedef struct Vertex {
65 | S16 x;
66 | S16 y;
67 | S16 z;
68 | S16 normal;
69 | } Vertex;
70 |
71 | int main (int argc, char **argv){
72 | if (argc != 2) {
73 | printf("usage: %s [FILENAME]\n", argv[0]);
74 | } else {
75 | FILE * file = fopen(argv[1], "rb");
76 | if (!file) {
77 | fprintf(stderr, "Error: Cannot find source file\n");
78 | exit(-1);
79 | }
80 | MD3 md3;
81 |
82 | if (!fread(&md3, sizeof(MD3), 1, file)) {
83 | fprintf(stderr, "Error: Cannot read source file (unexpected end of file)\n");
84 | exit(-1);
85 | }
86 |
87 | if (md3.ident != 0x33504449) {
88 | fprintf(stderr, "Error: File is not a valid MD3 mesh.\n");
89 | exit(-1);
90 | }
91 |
92 | printf("{\n");
93 | printf("\"format\": \"JSON3D 1.0\",\n");
94 | printf("\"surfaces\": [\n");
95 |
96 | int lastOffset = md3.offsetSurfaces;
97 | fseek(file, lastOffset, SEEK_SET);
98 | for (int i = 0; i < md3.numSurfaces; i++) {
99 | Surface surface;
100 | if (!fread(&surface, sizeof(Surface), 1, file)) {
101 | fprintf(stderr, "Error: Cannot read source file (unexpected end of file)\n");
102 | exit(-1);
103 | }
104 | printf("{\n");
105 | printf("\"name\": \"%s\",\n", surface.name);
106 |
107 | Vertex *vertices = malloc(sizeof(Vertex) * surface.numVerts * surface.numFrames);
108 | Triangle *tris = malloc(sizeof(Triangle) * surface.numTriangles);
109 | TexCoord *texCoords = malloc(sizeof(TexCoord) * surface.numVerts);
110 | fseek(file, lastOffset + surface.offsetXYZNormal, SEEK_SET);
111 | if (fread(vertices, sizeof(Vertex), surface.numVerts * surface.numFrames, file) < surface.numVerts * surface.numFrames) {
112 | fprintf(stderr, "Error: Cannot read source file (unexpected end of file)\n");
113 | exit(-1);
114 | }
115 | fseek(file, lastOffset + surface.offsetTriangles, SEEK_SET);
116 | if (fread(tris, sizeof(Triangle), surface.numTriangles, file) < surface.numTriangles) {
117 | fprintf(stderr, "Error: Cannot read source file (unexpected end of file)\n");
118 | exit(-1);
119 | }
120 | fseek(file, lastOffset + surface.offsetSt, SEEK_SET);
121 | if (fread(texCoords, sizeof(TexCoord), surface.numVerts, file) < surface.numVerts) {
122 | fprintf(stderr, "Error: Cannot read source file (unexpected end of file)\n");
123 | exit(-1);
124 | }
125 | printf("\"frames\": [\n");
126 | for (int f = 0; f < surface.numFrames; f++) {
127 | printf("{\n");
128 | printf("\"vertices\": [\n");
129 | for (int j = 0; j < surface.numTriangles; j++) {
130 | printf("%.1f, %.1f, %.1f,\n", vertices[surface.numVerts * f + tris[j].v1].x * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v1].z * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v1].y * MD3_XYZ_SCALE);
131 | printf("%.1f, %.1f, %.1f,\n", vertices[surface.numVerts * f + tris[j].v3].x * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v3].z * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v3].y * MD3_XYZ_SCALE);
132 | printf("%.1f, %.1f, %.1f,\n", vertices[surface.numVerts * f + tris[j].v2].x * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v2].z * MD3_XYZ_SCALE, vertices[surface.numVerts * f + tris[j].v2].y * MD3_XYZ_SCALE);
133 | }
134 | printf("], \n");
135 |
136 | printf("\"normals\": [\n");
137 | for (int j = 0; j < surface.numTriangles; j++) {
138 | float lat, lng, x, y, z;
139 | lat = ((vertices[surface.numVerts * f + tris[j].v1].normal >> 8) & 255) * (2 * 3.14159265) / 255.0;
140 | lng = (vertices[surface.numVerts * f + tris[j].v1].normal & 255) * (2 * 3.14159265) / 255.0;
141 | x = cos( lat ) * sin( lng );
142 | y = sin( lat ) * sin( lng );
143 | z = cos( lng );
144 |
145 | printf("%.2f, %.2f, %.2f,\n", x, z, y);
146 |
147 | lat = ((vertices[surface.numVerts * f + tris[j].v3].normal >> 8) & 255) * (2 * 3.14159265) / 255.0;
148 | lng = (vertices[surface.numVerts * f + tris[j].v3].normal & 255) * (2 * 3.14159265) / 255.0;
149 | x = cos( lat ) * sin( lng );
150 | y = sin( lat ) * sin( lng );
151 | z = cos( lng );
152 | printf("%.2f, %.2f, %.2f,\n", x, z, y);
153 |
154 | lat = ((vertices[surface.numVerts * f + tris[j].v2].normal >> 8) & 255) * (2 * 3.14159265) / 255.0;
155 | lng = (vertices[surface.numVerts * f + tris[j].v2].normal & 255) * (2 * 3.14159265) / 255.0;
156 | x = cos( lat ) * sin( lng );
157 | y = sin( lat ) * sin( lng );
158 | z = cos( lng );
159 |
160 | printf("%.2f, %.2f, %.2f,\n", x, z, y);
161 |
162 |
163 | }
164 | printf("] \n");
165 | printf("},\n");
166 | }
167 | printf("],\n");
168 | printf("\"textureCoordinates\": [\n");
169 | for (int j = 0; j < surface.numTriangles; j++) {
170 | printf("%f, %f,\n", texCoords[tris[j].v1].s, texCoords[tris[j].v1].t);
171 | printf("%f, %f,\n", texCoords[tris[j].v3].s, texCoords[tris[j].v3].t);
172 | printf("%f, %f,\n", texCoords[tris[j].v2].s, texCoords[tris[j].v2].t);
173 | }
174 | printf("]\n");
175 | free(tris);
176 | free(vertices);
177 |
178 | if (i == md3.numSurfaces - 1) {
179 | printf("}\n");
180 | } else {
181 | printf("},\n");
182 | }
183 |
184 | lastOffset += surface.offsetEnd;
185 | fseek(file, lastOffset, SEEK_SET);
186 | }
187 |
188 | printf("]\n");
189 | printf("}\n");
190 |
191 | fclose(file);
192 | }
193 | }
--------------------------------------------------------------------------------
/lib/sylvester.addons.js:
--------------------------------------------------------------------------------
1 | // augment Sylvester some
2 | Matrix.Translation = function (v)
3 | {
4 | if (v.elements.length == 2) {
5 | var r = Matrix.I(3);
6 | r.elements[2][0] = v.elements[0];
7 | r.elements[2][1] = v.elements[1];
8 | return r;
9 | }
10 |
11 | if (v.elements.length == 3) {
12 | var r = Matrix.I(4);
13 | r.elements[0][3] = v.elements[0];
14 | r.elements[1][3] = v.elements[1];
15 | r.elements[2][3] = v.elements[2];
16 | return r;
17 | }
18 |
19 | throw "Invalid length for Translation";
20 | }
21 |
22 | Matrix.prototype.flatten = function ()
23 | {
24 | // var result = [];
25 | if (this.elements.length == 0)
26 | return [];
27 |
28 | var stride = this.elements[0].length;
29 | var length = stride * this.elements.length;
30 | var result = new Float32Array(length);
31 |
32 | for (var j = 0; j < this.elements[0].length; j++)
33 | for (var i = 0; i < this.elements.length; i++)
34 | result[j * stride + i] = (this.elements[i][j]);
35 |
36 | return result;
37 | }
38 |
39 | Matrix.prototype.ensure4x4 = function()
40 | {
41 | if (this.elements.length == 4 &&
42 | this.elements[0].length == 4)
43 | return this;
44 |
45 | if (this.elements.length > 4 ||
46 | this.elements[0].length > 4)
47 | return null;
48 |
49 | for (var i = 0; i < this.elements.length; i++) {
50 | for (var j = this.elements[i].length; j < 4; j++) {
51 | if (i == j)
52 | this.elements[i].push(1);
53 | else
54 | this.elements[i].push(0);
55 | }
56 | }
57 |
58 | for (var i = this.elements.length; i < 4; i++) {
59 | if (i == 0)
60 | this.elements.push([1, 0, 0, 0]);
61 | else if (i == 1)
62 | this.elements.push([0, 1, 0, 0]);
63 | else if (i == 2)
64 | this.elements.push([0, 0, 1, 0]);
65 | else if (i == 3)
66 | this.elements.push([0, 0, 0, 1]);
67 | }
68 |
69 | return this;
70 | };
71 |
72 | Matrix.prototype.make3x3 = function()
73 | {
74 | if (this.elements.length != 4 ||
75 | this.elements[0].length != 4)
76 | return null;
77 |
78 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]],
79 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]],
80 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]);
81 | };
82 |
83 | Matrix.prototype.makeModeMatrix = function() {
84 | var used = [false, false, false, false];
85 | var newM = [];
86 | for (var i in this.elements) {
87 | var biggest = 0;
88 | var biggestJ = 0;
89 | for (var j in this.elements[i]) {
90 | if (Math.abs(this.elements[i][j]) > biggest) {
91 | if (!used[j]) {
92 | used[j] = true;
93 | biggest = Math.abs(this.elements[i][j]);
94 | biggestJ = j;
95 | }
96 | }
97 | }
98 | var newRow = [];
99 | for (var j in this.elements[i]) {
100 | if (j == biggestJ) {
101 | newRow.push((this.elements[i][j] > 0)? 1 : -1)
102 | } else {
103 | newRow.push(0);
104 | }
105 | }
106 | newM.push(newRow);
107 | }
108 |
109 | var result = $M(newM);
110 | console.log(result.inspect());
111 | return result;
112 | }
113 |
114 | Vector.prototype.to4D = function() {
115 | if (this.dimensions() == 4) {
116 | return this;
117 | } else if (this.dimensions() == 3) {
118 | return $V([this.elements[0], this.elements[1], this.elements[2], 1.0]);
119 | } else if (this.dimensions() == 2) {
120 | return $V([this.elements[0], this.elements[1], 0.0, 1.0]);
121 | }
122 | }
123 |
124 | Vector.prototype.xyz = function()
125 | {
126 | return $V([this.elements[0],this.elements[1],this.elements[2]])
127 | }
128 |
129 | Vector.prototype.xy = function()
130 | {
131 | return $V([this.elements[0],this.elements[1]])
132 | }
133 |
134 | Vector.prototype.xz = function()
135 | {
136 | return $V([this.elements[0],this.elements[2]])
137 | }
138 |
139 | Vector.prototype.yz = function()
140 | {
141 | return $V([this.elements[1],this.elements[2]])
142 | }
143 |
144 |
145 | Vector.prototype.flatten = function ()
146 | {
147 | return this.elements;
148 | };
149 |
150 | function mht(m) {
151 | var s = "";
152 | if (m.length == 16) {
153 | for (var i = 0; i < 4; i++) {
154 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
";
155 | }
156 | } else if (m.length == 9) {
157 | for (var i = 0; i < 3; i++) {
158 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
";
159 | }
160 | } else {
161 | return m.toString();
162 | }
163 | return s;
164 | }
165 |
166 | Matrix.LookAt = function(eye, center, up)
167 | {
168 | if (!up)
169 | up = $V([0, 1, 0]);
170 |
171 | var z = eye.subtract(center).toUnitVector();
172 | var x = up.cross(z).toUnitVector();
173 | var y = z.cross(x).toUnitVector();
174 |
175 | var m = $M([[x.e(1), x.e(2), x.e(3), 0],
176 | [y.e(1), y.e(2), y.e(3), 0],
177 | [z.e(1), z.e(2), z.e(3), 0],
178 | [ 0, 0, 0, 1]]);
179 |
180 | /* var t = $M([[1, 0, 0, -eye.elements[0]],
181 | [0, 1, 0, -eye.elements[1]],
182 | [0, 0, 1, -eye.elements[2]],
183 | [0, 0, 0, 1]]);*/
184 | return m;
185 | }
186 |
187 | Matrix.prototype.AlignYAxis = function(y, alpha) {
188 | // var x = $V([this.elements[0][0], this.elements[1][0], this.elements[2][0]]);
189 | var y = $V([y.elements[0] * alpha + this.elements[0][1] * (1 - alpha), y.elements[1] * alpha + this.elements[1][1] * (1 - alpha), y.elements[2] * alpha + this.elements[2][1] * (1 - alpha)]).toUnitVector();
190 | // console.log(y.inspect());
191 | var z = $V([this.elements[0][2], this.elements[1][2], this.elements[2][2]]);
192 | var x = z.cross(y).toUnitVector().x(-1);
193 | z = x.cross(y).toUnitVector();
194 | return $M([x.elements,y.elements,z.elements]).ensure4x4().transpose();
195 | }
196 |
197 | Matrix.LookAtY = function(targetY, back)
198 | {
199 | if (!back)
200 | back = $V([0, 0, 1]);
201 |
202 | var y = targetY.x(-1).toUnitVector();
203 | var x = back.cross(y).toUnitVector();
204 | var z = y.cross(x).toUnitVector();
205 |
206 | if (y.elements[1] < 0) {
207 | var m = $M([[x.e(1), x.e(2), x.e(3), 0],
208 | [-y.e(1), -y.e(2), -y.e(3), 0],
209 | [z.e(1), z.e(2), z.e(3), 0],
210 | [ 0, 0, 0, 1]]);
211 | } else {
212 | var m = $M([[-x.e(1), -x.e(2), -x.e(3), 0],
213 | [-y.e(1), -y.e(2), -y.e(3), 0],
214 | [-z.e(1), -z.e(2), -z.e(3), 0],
215 | [ 0, 0, 0, 1]]);
216 | }
217 |
218 | return m;
219 | }
220 |
221 |
222 | //
223 | // gluPerspective
224 | //
225 | Matrix.Perspective = function(fovy, aspect, znear, zfar)
226 | {
227 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
228 | var ymin = -ymax;
229 | var xmin = ymin * aspect;
230 | var xmax = ymax * aspect;
231 |
232 | return Matrix.Frustum(xmin, xmax, ymin, ymax, znear, zfar);
233 | }
234 |
235 | //
236 | // glFrustum
237 | //
238 | Matrix.Frustum = function(left, right,
239 | bottom, top,
240 | znear, zfar)
241 | {
242 | var X = 2*znear/(right-left);
243 | var Y = 2*znear/(top-bottom);
244 | var A = (right+left)/(right-left);
245 | var B = (top+bottom)/(top-bottom);
246 | var C = -(zfar+znear)/(zfar-znear);
247 | var D = -2*zfar*znear/(zfar-znear);
248 |
249 | return $M([[X, 0, A, 0],
250 | [0, Y, B, 0],
251 | [0, 0, C, D],
252 | [0, 0, -1, 0]]);
253 | }
254 |
255 | //
256 | // glOrtho
257 | //
258 | Matrix.Ortho = function(left, right, bottom, top, znear, zfar)
259 | {
260 | var tx = - (right + left) / (right - left);
261 | var ty = - (top + bottom) / (top - bottom);
262 | var tz = - (zfar + znear) / (zfar - znear);
263 |
264 | return $M([[2 / (right - left), 0, 0, tx],
265 | [0, 2 / (top - bottom), 0, ty],
266 | [0, 0, -2 / (zfar - znear), tz],
267 | [0, 0, 0, 1]]);
268 | }
269 |
--------------------------------------------------------------------------------
/level/lvl0.jsonlevel:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Test Zone",
3 | "mesh": "mesh/lvl0.jsonmesh",
4 | "data": [
5 | [
6 | [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
7 | [ 2, 0, 4, 4, 4, 1, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, null, null, 0, null ],
8 | [ 2, 0, 4, 4, 4, 1, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, 4, 3, 0, 0, null, null, null, 0 ],
9 | [ null, 0, 0, 0, 4, null, null, 0, 1, 0, null, null, null, null, null, null, null, null, null, 4, 0, 0, 0, null, null, 0, null ],
10 | [ null, null, null, null, 0, null, null, null, 1, 0, null, null, null, null, null, null, null, null, null, 4, 0, 0, 0, null, null, null, 0 ],
11 | [ null, null, null, null, 0, null, null, 4, 4, 4, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, null ],
12 | [ null, null, null, null, 0, 0, 0, 4, 4, 4, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
13 | [ null, null, null, null, 0, null, 0, 4, 4, 4, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, null ],
14 | [ null, null, null, null, null, null, 0, null, null, 4, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
15 | [ null, null, null, null, null, null, null, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0, null ],
16 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
17 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
18 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
19 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
20 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
21 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
22 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
23 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
24 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
25 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
26 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
27 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
28 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null ],
29 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
30 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
31 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ],
32 | [ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0 ]
33 | ],
34 | [
35 | [ null, null, null, null, 0, null, null, null, null ],
36 | [ 2, null, 1, 0, 0, null, null, null, null ],
37 | [ 2, null, 1, 0, 0, null, null, null, null ],
38 | [ null, null, null, null, null, null, null, 1, null ],
39 | [ null, null, null, null, null, null, null, 1, null ],
40 | [ null, 0, null, null, null, null, null, 4, 4 ],
41 | [ null, 0, null, null, null, null, null, null, null ],
42 | [ null, 0, null, null, null, null, null, 4, 4 ],
43 | [ null, 0, null, 0, null, null, null, null, null ],
44 | [ null, 0, null, 0, null, null, null, null, null ],
45 | [ null, 0, null, 0, null, null, null, null, null ],
46 | [ null, 0, 0, 0, null, null, null, null, null ]
47 | ],
48 | [
49 | [ null, null, null, null, null, 0, null, null, null ],
50 | [ 2, 1, null, null, null, 0, null, null, null ],
51 | [ 2, 1, null, null, null, 0, null, null, null ],
52 | [ null, null, null, null, null, 0, 0, null, null ],
53 | [ null, null, null, null, null, null, 0, null, null ],
54 | [ null, null, null, null, null, null, null, 4, 4 ],
55 | [ null, null, null, null, null, null, null, 4, 4 ],
56 | [ null, null, null, null, null, null, null, 4, 4 ],
57 | [ null, null, null, null, null, null, null, null, null ],
58 | [ null, null, null, null, null, null, null, null, null ],
59 | [ null, null, null, null, null, null, null, null, null ],
60 | [ null, null, null, null, null, null, null, null, null ]
61 | ],
62 | [
63 | [ 4, 4, 4, 4, 4, 4, 4, 4, 4 ],
64 | [ 4, null, 4, null, null, 4, 4, 4, 4 ],
65 | [ 4, null, 4, 4, null, 0, 5, 0, 4 ],
66 | [ 4, 4, 4, 4, null, 8, 4, 4, 4 ],
67 | [ 4, 4, 4, 4, null, 8, 4, 4, 4 ],
68 | [ 4, 4, null, null, null, 0, 4, 4, 4 ],
69 | [ 4, 4, 4, 4, 4, 4, 4, 4, 4 ],
70 | [ 4, 4, 4, 4, 4, 4, 4, 4, 4 ]
71 | ],
72 | [
73 | [ 4, 4, 4, 4, 4, 4, 4, null, null ],
74 | [ 4, null, null, 0, 0, 0, 4, null, null ],
75 | [ 4, null, null, 0, 0, 0, 4, null, null ],
76 | [ 4, 4, 4, 4, 0, 0, 4, null, null ],
77 | [ 4, 4, 4, 4, 0, 0, 4, 0, 4 ],
78 | [ 4, null, 1, 0, 0, 0, 5, null, 4 ],
79 | [ 4, 4, 4, 4, 4, 4, 4, null, 4 ],
80 | [ 4, 4, 4, 4, 4, 4, 4, null, null ]
81 | ],
82 | [
83 | [ null, null, null, null, 5, 5, null, null, 4 ],
84 | [ 4, 8, 4, 4, 4, 4, null, null, 4 ],
85 | [ 4, 8, 4, 4, 4, 4, null, null, 4 ],
86 | [ 4, 8, 4, 4, 4, 4, null, null, null ],
87 | [ 4, 8, 4, 4, 4, 4, null, 4, 4 ],
88 | [ 4, 0, null, 4, 4, 4, null, 4, 4 ],
89 | [ 4, 4, 4, 4, 4, 4, null, 4, 4 ],
90 | [ 4, 4, 4, 4, 4, 4, null, null, null ]
91 | ],
92 | [
93 | [ null, null, null, null, null, null, null, null, null ],
94 | [ null, null, null, null, 1, null, null, null, null ],
95 | [ null, null, null, null, null, null, 0, 0, null ],
96 | [ null, null, null, null, null, null, null, null, 0 ],
97 | [ null, null, null, null, null, null, null, null, null ],
98 | [ null, null, null, null, null, null, null, null, null ],
99 | [ null, null, null, null, null, null, null, null, null ],
100 | [ null, null, null, null, null, null, null, null, null ]
101 | ],
102 | [
103 | [ null, null, null, null, null, null, null, null, null ],
104 | [ 2, 1, 1, 1, null, null, null, null, null ],
105 | [ null, null, null, null, null, null, null, null, null ],
106 | [ null, null, null, null, null, null, null, null, null ],
107 | [ null, null, null, null, null, null, null, null, null ],
108 | [ null, null, null, null, null, null, null, null, null ],
109 | [ null, null, null, null, null, null, null, null, null ],
110 | [ null, null, null, null, null, null, null, null, null ]
111 | ],
112 | [
113 | [ null, null, null, null, null, null, null, null, null ],
114 | [ 2, null, null, null, null, null, null, null, null ],
115 | [ null, null, null, null, null, null, null, null, null ],
116 | [ null, null, null, null, null, null, null, null, null ],
117 | [ null, null, null, null, null, null, null, null, null ],
118 | [ null, null, null, null, null, null, null, null, null ],
119 | [ null, null, null, null, null, null, null, null, null ],
120 | [ null, null, null, null, null, null, null, null, null ]
121 | ],
122 | [
123 | [ null, null, null, null, null, null, null, null, null ],
124 | [ 2, null, 0, 0, 0, null, null, null, null ],
125 | [ null, null, 0, 0, 0, null, null, null, null ],
126 | [ null, 0, 0, 0, 0, 5, 5, 5, 5 ],
127 | [ null, null, null, null, null, null, null, null, null ],
128 | [ null, null, null, null, null, null, null, null, null ],
129 | [ null, null, null, null, null, null, null, null, null ],
130 | [ null, null, null, null, null, null, null, null, null ]
131 | ],
132 | [
133 | [ null, null, null, null, null, null, null, null, null ],
134 | [ 2, null, null, null, null, null, null, null, null ],
135 | [ null, null, null, null, null, null, null, null, null ],
136 | [ null, null, null, null, null, null, null, null, null ],
137 | [ null, null, null, null, null, null, null, null, null ],
138 | [ null, null, null, null, null, null, null, null, null ],
139 | [ null, null, null, null, null, null, null, null, null ],
140 | [ null, null, null, null, null, null, null, null, null ]
141 | ],
142 | ]
143 | }
--------------------------------------------------------------------------------
/lib/sylvester.js:
--------------------------------------------------------------------------------
1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))
--------------------------------------------------------------------------------
/js/WorldEngine.js:
--------------------------------------------------------------------------------
1 | var WorldEngine = function(engine) {
2 | var worldEngine = {}
3 | var gameTime = 0.0;
4 | var realTime = 0.0;
5 | var timeDelta;
6 | var TARGET_FPS = 60;
7 | var MIN_FPS = 2;
8 | var SUBSTEPS_PER_FRAME = 1;
9 | var BUCKET_WIDTH = 128.0;
10 |
11 | var stepCount = 0;
12 | var entities = [];
13 | var cameras = [];
14 | var buckets = {};
15 | var fps = 0.0;
16 | var removalFlag = false;
17 |
18 | var uniforms =
19 | { u_lightColor: $V([1.0,1.0,1.0,1.0]),
20 | u_lightDirection: $V([-0.05, 1, -0.1]).toUnitVector(),
21 | u_ambientLightColor: $V([0.2,0.2,0.25,1.0])};
22 |
23 | var calculateBucketId = function(position) {
24 | return [Math.floor(position.elements[0]/BUCKET_WIDTH), Math.floor(position.elements[1]/BUCKET_WIDTH), Math.floor(position.elements[2]/BUCKET_WIDTH)].toString();
25 | }
26 |
27 | worldEngine.uniforms = function(value) {
28 | if (value !== undefined) {
29 | uniforms = value;
30 | }
31 | return uniforms;
32 | }
33 |
34 | worldEngine.update = function() {
35 | var newRealTime = new Date().getTime() * 0.001;
36 | timeDelta = newRealTime - realTime;
37 | if (timeDelta > 1.0/MIN_FPS) {
38 | timeDelta = 1.0/MIN_FPS;
39 | }
40 |
41 | timeDelta *= 1.0;
42 |
43 | var substeps;
44 | if (timeDelta > 1.0/TARGET_FPS) {
45 | substeps = Math.ceil(timeDelta / (1.0/TARGET_FPS)) * SUBSTEPS_PER_FRAME;
46 | } else {
47 | substeps = SUBSTEPS_PER_FRAME;
48 | }
49 |
50 | fps = fps * 0.9 + (1/timeDelta) * 0.1;
51 |
52 | for (var i = 0; i < substeps; i++) {
53 | gameTime += timeDelta / substeps;
54 |
55 | uniforms.u_time = gameTime;
56 |
57 | removalFlag = false;
58 | for (var j = 0; j < entities.length; j++) {
59 | entities[j].update(timeDelta / substeps);
60 | if (removalFlag) {
61 | j--;
62 | removalFlag = false;
63 | }
64 | };
65 |
66 | cameras.forEach(function(camera) {
67 | var cameraCenter = camera.modelView().x($V([0,0,-4*BUCKET_WIDTH,1.0]));
68 | var xmin = Math.floor(cameraCenter.elements[0] / BUCKET_WIDTH) - 3;
69 | var ymin = Math.floor(cameraCenter.elements[1] / BUCKET_WIDTH) - 6;
70 | var zmin = Math.floor(cameraCenter.elements[2] / BUCKET_WIDTH) - 3;
71 | var xmax = xmin + 6;
72 | var ymax = ymin + 15;
73 | var zmax = zmin + 6;
74 | for (var x = xmin; x <= xmax; x++) {
75 | for (var y = ymin; y <= ymax; y++) {
76 | for (var z = zmin; z <= zmax; z++) {
77 | var bucket = buckets[[x,y,z]];
78 | if (bucket) {
79 | for (var j = 0; j < bucket.length; j++) {
80 | if (bucket[j].lastStep != stepCount) {
81 | bucket[j].lastStep = stepCount;
82 | bucket[j].update(timeDelta / substeps);
83 | }
84 | if (!removalFlag) {
85 | var entity = bucket[j];
86 | var newBucketId = calculateBucketId(entity.position());
87 | if (entity.bucketId != newBucketId) {
88 | // Entity is changing bucket
89 | worldEngine.remove(entity);
90 | worldEngine.add(entity);
91 | }
92 | }
93 | if (removalFlag) {
94 | j--;
95 | removalFlag = false;
96 | }
97 | }
98 | }
99 | }
100 | }
101 | }
102 | });
103 |
104 | engine.input.resetPressed();
105 | stepCount++;
106 | }
107 | realTime = newRealTime;
108 | }
109 |
110 | var shadowMapTarget = null;
111 | var shadowMapPosition = null;
112 | var renderShadows = function(camera) {
113 | var SHADOW_MAP_HEIGHT = 512;
114 | var SHADOW_MAP_WIDTH = 512;
115 | engine.gfx.clear();
116 | if (!shadowMapTarget) {
117 | shadowMapTarget = new engine.gfx.RenderTarget(SHADOW_MAP_WIDTH, SHADOW_MAP_HEIGHT);
118 | }
119 | shadowMapTarget.activate();
120 | shadowMapPosition = camera.modelView().x($V([0,0,-300,1.0])).xyz();
121 | var oldCameraPosition = camera.position();
122 | var oldCameraRotation = camera.rotation();
123 | camera.position(shadowMapPosition.add($V([0,550,0])));
124 | camera.rotation(Matrix.RotationX(-Math.PI/1.99).ensure4x4());
125 | var renderParams = {
126 | camera: camera,
127 | projection: camera.projection(shadowMapTarget.aspectRatio()),
128 | projectionFlat: camera.projection(shadowMapTarget.aspectRatio()).flatten(),
129 | cameraView: camera.modelView().inverse(),
130 | cameraViewFlat: camera.modelView().inverse().flatten(),
131 | uniforms: [uniforms],
132 | shader: engine.resources.get("shader/depth.jsonshader")
133 | }
134 | removalFlag = false;
135 | for (var i = 0; i < entities.length; i++) {
136 | if (entities[i].castsShadows) {
137 | entities[i].render(renderParams);//inversedCameraModelView);
138 | if (removalFlag) {
139 | i--;
140 | removalFlag = false;
141 | }
142 | }
143 | }
144 | var cameraCenter = camera.modelView().x($V([0,0,-4*BUCKET_WIDTH,1.0]));
145 | var xmin = Math.floor(cameraCenter.elements[0] / BUCKET_WIDTH) - 3;
146 | var ymin = Math.floor(cameraCenter.elements[1] / BUCKET_WIDTH) - 3;
147 | var zmin = Math.floor(cameraCenter.elements[2] / BUCKET_WIDTH) - 3;
148 | var xmax = xmin + 6;
149 | var ymax = ymin + 5;
150 | var zmax = zmin + 6;
151 | for (var x = xmin; x <= xmax; x++) {
152 | for (var y = ymin; y <= ymax; y++) {
153 | for (var z = zmin; z <= zmax; z++) {
154 | var bucket = buckets[[x,y,z]];
155 | if (bucket) {
156 | for (var i = 0; i < bucket.length; i++) {
157 | if (bucket[i].castsShadows) {
158 | bucket[i].render(renderParams);
159 | if (removalFlag) {
160 | i--;
161 | removalFlag = false;
162 | }
163 | }
164 | }
165 | }
166 | }
167 | }
168 | }
169 |
170 | camera.position(oldCameraPosition);
171 | camera.rotation(oldCameraRotation);
172 |
173 | shadowMapTarget.deactivate();
174 | }
175 |
176 | var colorTarget = null;
177 | worldEngine.render = function() {
178 | if (!colorTarget) {
179 | colorTarget = new engine.gfx.RenderTarget();
180 | }
181 |
182 | cameras.forEach(function(camera) {
183 | renderShadows(camera);
184 | // colorTarget.activate();
185 | // engine.gfx.gl.clearColor(40/256.0,124/256.0,235/256.0,1.0);
186 | engine.gfx.clear();
187 | engine.gfx.gl.clearColor(0.0, 0.0, 0.0, 0.0);
188 | uniforms.u_dynamicShadowMap = shadowMapTarget.texture();
189 | uniforms.u_dynamicShadowMapPosition = shadowMapPosition;
190 | var renderParams = {
191 | camera: camera,
192 | projection: camera.projection(colorTarget.aspectRatio()),
193 | projectionFlat: camera.projection(colorTarget.aspectRatio()).flatten(),
194 | cameraView: camera.modelView().inverse(),
195 | cameraViewFlat: camera.modelView().inverse().flatten(),
196 | uniforms: [uniforms],
197 | // shader: engine.resources.get("shader/depth.jsonshader")
198 | };
199 | removalFlag = false;
200 | var renderList = [];
201 |
202 | for (var i = 0; i < entities.length; i++) {
203 | renderList.push(entities[i]);
204 | //entities[i].render(renderParams);//inversedCameraModelView);
205 | if (removalFlag) {
206 | i--;
207 | removalFlag = false;
208 | }
209 | }
210 | var cameraCenter = camera.modelView().x($V([0,0,-4*BUCKET_WIDTH,1.0]));
211 | var xmin = Math.floor(cameraCenter.elements[0] / BUCKET_WIDTH) - 3;
212 | var ymin = Math.floor(cameraCenter.elements[1] / BUCKET_WIDTH) - 3;
213 | var zmin = Math.floor(cameraCenter.elements[2] / BUCKET_WIDTH) - 3;
214 | var xmax = xmin + 6;
215 | var ymax = ymin + 5;
216 | var zmax = zmin + 6;
217 | for (var x = xmin; x <= xmax; x++) {
218 | for (var y = ymin; y <= ymax; y++) {
219 | for (var z = zmin; z <= zmax; z++) {
220 | var bucket = buckets[[x,y,z]];
221 | if (bucket) {
222 | for (var i = 0; i < bucket.length; i++) {
223 | renderList.push(bucket[i]);
224 | //bucket[i].render(renderParams);
225 | if (removalFlag) {
226 | i--;
227 | removalFlag = false;
228 | }
229 | }
230 | }
231 | }
232 | }
233 | }
234 |
235 | renderList.sort(function(a,b){
236 | if (!a.layer)
237 | a.layer = 0;
238 | if (!b.layer)
239 | b.layer = 0;
240 | return a.layer - b.layer;
241 | })
242 |
243 | if (renderList.length > 0) {
244 | var lastLayer = renderList[0].layer;
245 | for (var i in renderList) {
246 | if (lastLayer != renderList[i].layer) {
247 | engine.gfx.clearDepth();
248 | lastLayer = renderList[i].layer;
249 | }
250 | renderList[i].render(renderParams);
251 | }
252 | }
253 |
254 | // colorTarget.deactivate();
255 | // engine.gfx.clear();
256 | // colorTarget.renderToScreen();
257 |
258 | engine.gfx.gl.finish();
259 | });
260 | }
261 |
262 | worldEngine.time = function() {
263 | return gameTime;
264 | }
265 |
266 | worldEngine.add = function(entity) {
267 | if (!entity.isStatic) {
268 | entities.push(entity);
269 | if (entity.isCamera) {
270 | cameras.push(entity);
271 | }
272 | } else {
273 | var position = entity.position();
274 | var bucketId = calculateBucketId(position);
275 | if (!buckets[bucketId]) {
276 | buckets[bucketId] = [];
277 | }
278 | buckets[bucketId].push(entity);
279 | entity.bucketId = bucketId;
280 | }
281 | }
282 |
283 | worldEngine.remove = function(entity) {
284 | var i;
285 | if (!entity.isStatic) {
286 | for (i in entities) {
287 | if (entities[i] === entity) {
288 | break;
289 | }
290 | }
291 | entities.splice(i, 1);
292 | } else {
293 | bucket = buckets[entity.bucketId];
294 | for (i in bucket) {
295 | if (bucket[i] === entity) {
296 | break;
297 | }
298 | }
299 | bucket.splice(i, 1);
300 | removalFlag = true;
301 | }
302 | }
303 |
304 | worldEngine.Entity = function() {
305 |
306 | var entity = {};
307 | var position = $V([0, 0, 0]);
308 | var rotation = Matrix.I(4);
309 | var scale = $V([1, 1, 1]);
310 | var modelView = null;
311 | var normalModelView = null;
312 |
313 | var computeModelView = function() {
314 | modelView = Matrix.Translation(position)
315 | .x(rotation)
316 | .x(scale.toDiagonalMatrix().ensure4x4());
317 | normalModelView = null;
318 | }
319 |
320 | var computeNormalModelView = function() {
321 | normalModelView = modelView.inverse().transpose();
322 | }
323 |
324 | entity.isEntity = true;
325 | entity.position = function(value) {
326 | if (value !== undefined) {
327 | position = value;
328 | modelView = null;
329 | }
330 | return position;
331 | }
332 |
333 | entity.rotation = function(value) {
334 | if (value !== undefined && value != null) {
335 | rotation = value;
336 | modelView = null;
337 | }
338 | return rotation;
339 | }
340 |
341 | entity.scale = function(value) {
342 | if (value !== undefined) {
343 | scale = value;
344 | modelView = null;
345 | }
346 | return scale;
347 | }
348 |
349 | entity.modelView = function() {
350 | if (modelView === null) {
351 | computeModelView();
352 | }
353 | return modelView;
354 | }
355 |
356 | entity.normalModelView = function() {
357 | if (modelView === null) {
358 | computeModelView();
359 | computeNormalModelView();
360 | return normalModelView;
361 | }
362 | if (normalModelView === null) {
363 | computeNormalModelView();
364 | }
365 | return entity.modelView().inverse().transpose();
366 | }
367 |
368 | entity.render = function(projection, inversedCameraModelView) {
369 | }
370 |
371 | entity.update = function(timeDelta) {
372 | }
373 |
374 | return entity;
375 | }
376 |
377 | worldEngine.Camera = function() {
378 |
379 | var camera = worldEngine.Entity();
380 |
381 | var fov = 45;
382 | var minZ = 50;
383 | var maxZ = 5000;
384 |
385 | camera.isCamera = true;
386 | camera.fov = function(value) {
387 | if (value !== undefined) {
388 | fov = value;
389 | projection = null;
390 | }
391 | return fov;
392 | }
393 |
394 | camera.minZ = function(value) {
395 | if (value !== undefined) {
396 | minZ = value;
397 | projection = null;
398 | }
399 | return minZ;
400 | }
401 |
402 | camera.maxZ = function(value) {
403 | if (value !== undefined) {
404 | maxZ = value;
405 | projection = null;
406 | }
407 | return maxZ;
408 | }
409 |
410 | camera.projection = function(aspectRatio) {
411 | if (!aspectRatio) {
412 | aspectRatio = engine.gfx.aspectRatio();
413 | }
414 | return Matrix.Perspective(fov, aspectRatio, minZ, maxZ);
415 | }
416 |
417 | return camera;
418 | }
419 |
420 | worldEngine.MeshEntity = function(mesh) {
421 | var meshEntity = worldEngine.Entity();
422 |
423 | meshEntity.isMeshEntity = true;
424 | meshEntity.castsShadows = true;
425 | meshEntity.frame = 0;
426 | meshEntity.render = function(renderParams) {
427 | renderParams.modelView = meshEntity.modelView();
428 | renderParams.normalModelView = meshEntity.normalModelView();
429 | mesh.render(renderParams, Math.floor(meshEntity.frame));
430 | }
431 |
432 | return meshEntity;
433 | }
434 |
435 | worldEngine.LevelEntity = function(level) {
436 | var levelEntity = worldEngine.Entity();
437 |
438 | levelEntity.render = function(renderParams) {
439 | var shadowMap = level.shadowMap();
440 | if (shadowMap) {
441 | uniforms.u_levelShadowMap = shadowMap;
442 | }
443 | uniforms.u_levelSize = level.levelSize();
444 | renderParams.modelView = levelEntity.modelView();
445 | renderParams.normalModelView = levelEntity.normalModelView();
446 | var cameraCenter = renderParams.camera.modelView().x($V([0,0,-730,1.0]));
447 | level.render(renderParams, cameraCenter);
448 | }
449 |
450 | levelEntity.rayIntersect = function(point, direction, maxDist, minDist) {
451 | return level.rayIntersect(point, direction, maxDist, minDist);
452 | }
453 |
454 | return levelEntity;
455 | }
456 |
457 | return worldEngine;
458 | }
--------------------------------------------------------------------------------
/mesh/sky.jsonmesh:
--------------------------------------------------------------------------------
1 | {
2 | "format": "JSON3D 1.0",
3 | "surfaces": [
4 | {
5 | "name": "Sphere01",
6 | "shader": "shader/sky.jsonshader",
7 | "samplers": { "u_cloudMap": "texture/sky.jpg" },
8 | "frames": [
9 | {
10 | "vertices": [0.0,37.6,21.7,0.0,43.4,0.0,-10.8,37.6,18.8,-10.8,37.6,18.8,0.0,43.4,0.0,-18.8,37.6,10.8,-18.8,37.6,10.8,0.0,43.4,0.0,-21.7,37.6,0.0,-21.7,37.6,0.0,0.0,43.4,0.0,-18.8,37.6,-10.8,-18.8,37.6,-10.8,0.0,43.4,0.0,-10.8,37.6,-18.8,-10.8,37.6,-18.8,0.0,43.4,0.0,0.0,37.6,-21.7,0.0,37.6,-21.7,0.0,43.4,0.0,10.8,37.6,-18.8,10.8,37.6,-18.8,0.0,43.4,0.0,18.8,37.6,-10.8,18.8,37.6,-10.8,0.0,43.4,0.0,21.7,37.6,0.0,21.7,37.6,0.0,0.0,43.4,0.0,18.8,37.6,10.8,18.8,37.6,10.8,0.0,43.4,0.0,10.8,37.6,18.8,10.8,37.6,18.8,0.0,43.4,0.0,0.0,37.6,21.7,0.0,21.7,37.6,0.0,37.6,21.7,-18.8,21.7,32.5,-18.8,21.7,32.5,0.0,37.6,21.7,-10.8,37.6,18.8,-18.8,21.7,32.5,-10.8,37.6,18.8,-32.5,21.7,18.8,-32.5,21.7,18.8,-10.8,37.6,18.8,-18.8,37.6,10.8,-32.5,21.7,18.8,-18.8,37.6,10.8,-37.6,21.7,0.0,-37.6,21.7,0.0,-18.8,37.6,10.8,-21.7,37.6,0.0,-37.6,21.7,0.0,-21.7,37.6,0.0,-32.5,21.7,-18.8,-32.5,21.7,-18.8,-21.7,37.6,0.0,-18.8,37.6,-10.8,-32.5,21.7,-18.8,-18.8,37.6,-10.8,-18.8,21.7,-32.5,-18.8,21.7,-32.5,-18.8,37.6,-10.8,-10.8,37.6,-18.8,-18.8,21.7,-32.5,-10.8,37.6,-18.8,0.0,21.7,-37.6,0.0,21.7,-37.6,-10.8,37.6,-18.8,0.0,37.6,-21.7,0.0,21.7,-37.6,0.0,37.6,-21.7,18.8,21.7,-32.5,18.8,21.7,-32.5,0.0,37.6,-21.7,10.8,37.6,-18.8,18.8,21.7,-32.5,10.8,37.6,-18.8,32.5,21.7,-18.8,32.5,21.7,-18.8,10.8,37.6,-18.8,18.8,37.6,-10.8,32.5,21.7,-18.8,18.8,37.6,-10.8,37.6,21.7,0.0,37.6,21.7,0.0,18.8,37.6,-10.8,21.7,37.6,0.0,37.6,21.7,0.0,21.7,37.6,0.0,32.5,21.7,18.8,32.5,21.7,18.8,21.7,37.6,0.0,18.8,37.6,10.8,32.5,21.7,18.8,18.8,37.6,10.8,18.8,21.7,32.5,18.8,21.7,32.5,18.8,37.6,10.8,10.8,37.6,18.8,18.8,21.7,32.5,10.8,37.6,18.8,0.0,21.7,37.6,0.0,21.7,37.6,10.8,37.6,18.8,0.0,37.6,21.7,0.0,0.0,43.4,0.0,21.7,37.6,-21.7,0.0,37.6,-21.7,0.0,37.6,0.0,21.7,37.6,-18.8,21.7,32.5,-21.7,0.0,37.6,-18.8,21.7,32.5,-37.6,0.0,21.7,-37.6,0.0,21.7,-18.8,21.7,32.5,-32.5,21.7,18.8,-37.6,0.0,21.7,-32.5,21.7,18.8,-43.4,0.0,0.0,-43.4,0.0,0.0,-32.5,21.7,18.8,-37.6,21.7,0.0,-43.4,0.0,0.0,-37.6,21.7,0.0,-37.6,0.0,-21.7,-37.6,0.0,-21.7,-37.6,21.7,0.0,-32.5,21.7,-18.8,-37.6,0.0,-21.7,-32.5,21.7,-18.8,-21.7,0.0,-37.6,-21.7,0.0,-37.6,-32.5,21.7,-18.8,-18.8,21.7,-32.5,-21.7,0.0,-37.6,-18.8,21.7,-32.5,0.0,0.0,-43.4,0.0,0.0,-43.4,-18.8,21.7,-32.5,0.0,21.7,-37.6,0.0,0.0,-43.4,0.0,21.7,-37.6,21.7,0.0,-37.6,21.7,0.0,-37.6,0.0,21.7,-37.6,18.8,21.7,-32.5,21.7,0.0,-37.6,18.8,21.7,-32.5,37.6,0.0,-21.7,37.6,0.0,-21.7,18.8,21.7,-32.5,32.5,21.7,-18.8,37.6,0.0,-21.7,32.5,21.7,-18.8,43.4,0.0,0.0,43.4,0.0,0.0,32.5,21.7,-18.8,37.6,21.7,0.0,43.4,0.0,0.0,37.6,21.7,0.0,37.6,0.0,21.7,37.6,0.0,21.7,37.6,21.7,0.0,32.5,21.7,18.8,37.6,0.0,21.7,32.5,21.7,18.8,21.7,0.0,37.6,21.7,0.0,37.6,32.5,21.7,18.8,18.8,21.7,32.5,21.7,0.0,37.6,18.8,21.7,32.5,0.0,0.0,43.4,0.0,0.0,43.4,18.8,21.7,32.5,0.0,21.7,37.6,0.0,-21.7,37.6,0.0,0.0,43.4,-18.8,-21.7,32.5,-18.8,-21.7,32.5,0.0,0.0,43.4,-21.7,0.0,37.6,-18.8,-21.7,32.5,-21.7,0.0,37.6,-32.5,-21.7,18.8,-32.5,-21.7,18.8,-21.7,0.0,37.6,-37.6,0.0,21.7,-32.5,-21.7,18.8,-37.6,0.0,21.7,-37.6,-21.7,0.0,-37.6,-21.7,0.0,-37.6,0.0,21.7,-43.4,0.0,0.0,-37.6,-21.7,0.0,-43.4,0.0,0.0,-32.5,-21.7,-18.8,-32.5,-21.7,-18.8,-43.4,0.0,0.0,-37.6,0.0,-21.7,-32.5,-21.7,-18.8,-37.6,0.0,-21.7,-18.8,-21.7,-32.5,-18.8,-21.7,-32.5,-37.6,0.0,-21.7,-21.7,0.0,-37.6,-18.8,-21.7,-32.5,-21.7,0.0,-37.6,0.0,-21.7,-37.6,0.0,-21.7,-37.6,-21.7,0.0,-37.6,0.0,0.0,-43.4,0.0,-21.7,-37.6,0.0,0.0,-43.4,18.8,-21.7,-32.5,18.8,-21.7,-32.5,0.0,0.0,-43.4,21.7,0.0,-37.6,18.8,-21.7,-32.5,21.7,0.0,-37.6,32.5,-21.7,-18.8,32.5,-21.7,-18.8,21.7,0.0,-37.6,37.6,0.0,-21.7,32.5,-21.7,-18.8,37.6,0.0,-21.7,37.6,-21.7,0.0,37.6,-21.7,0.0,37.6,0.0,-21.7,43.4,0.0,0.0,37.6,-21.7,0.0,43.4,0.0,0.0,32.5,-21.7,18.8,32.5,-21.7,18.8,43.4,0.0,0.0,37.6,0.0,21.7,32.5,-21.7,18.8,37.6,0.0,21.7,18.8,-21.7,32.5,18.8,-21.7,32.5,37.6,0.0,21.7,21.7,0.0,37.6,18.8,-21.7,32.5,21.7,0.0,37.6,0.0,-21.7,37.6,0.0,-21.7,37.6,21.7,0.0,37.6,0.0,0.0,43.4,0.0,-37.6,21.7,0.0,-21.7,37.6,-10.8,-37.6,18.8,-10.8,-37.6,18.8,0.0,-21.7,37.6,-18.8,-21.7,32.5,-10.8,-37.6,18.8,-18.8,-21.7,32.5,-18.8,-37.6,10.8,-18.8,-37.6,10.8,-18.8,-21.7,32.5,-32.5,-21.7,18.8,-18.8,-37.6,10.8,-32.5,-21.7,18.8,-21.7,-37.6,0.0,-21.7,-37.6,0.0,-32.5,-21.7,18.8,-37.6,-21.7,0.0,-21.7,-37.6,0.0,-37.6,-21.7,0.0,-18.8,-37.6,-10.8,-18.8,-37.6,-10.8,-37.6,-21.7,0.0,-32.5,-21.7,-18.8,-18.8,-37.6,-10.8,-32.5,-21.7,-18.8,-10.8,-37.6,-18.8,-10.8,-37.6,-18.8,-32.5,-21.7,-18.8,-18.8,-21.7,-32.5,-10.8,-37.6,-18.8,-18.8,-21.7,-32.5,0.0,-37.6,-21.7,0.0,-37.6,-21.7,-18.8,-21.7,-32.5,0.0,-21.7,-37.6,0.0,-37.6,-21.7,0.0,-21.7,-37.6,10.8,-37.6,-18.8,10.8,-37.6,-18.8,0.0,-21.7,-37.6,18.8,-21.7,-32.5,10.8,-37.6,-18.8,18.8,-21.7,-32.5,18.8,-37.6,-10.8,18.8,-37.6,-10.8,18.8,-21.7,-32.5,32.5,-21.7,-18.8,18.8,-37.6,-10.8,32.5,-21.7,-18.8,21.7,-37.6,0.0,21.7,-37.6,0.0,32.5,-21.7,-18.8,37.6,-21.7,0.0,21.7,-37.6,0.0,37.6,-21.7,0.0,18.8,-37.6,10.8,18.8,-37.6,10.8,37.6,-21.7,0.0,32.5,-21.7,18.8,18.8,-37.6,10.8,32.5,-21.7,18.8,10.8,-37.6,18.8,10.8,-37.6,18.8,32.5,-21.7,18.8,18.8,-21.7,32.5,10.8,-37.6,18.8,18.8,-21.7,32.5,0.0,-37.6,21.7,0.0,-37.6,21.7,18.8,-21.7,32.5,0.0,-21.7,37.6,-10.8,-37.6,18.8,0.0,-43.4,0.0,0.0,-37.6,21.7,-18.8,-37.6,10.8,0.0,-43.4,0.0,-10.8,-37.6,18.8,-21.7,-37.6,0.0,0.0,-43.4,0.0,-18.8,-37.6,10.8,-18.8,-37.6,-10.8,0.0,-43.4,0.0,-21.7,-37.6,0.0,-10.8,-37.6,-18.8,0.0,-43.4,0.0,-18.8,-37.6,-10.8,0.0,-37.6,-21.7,0.0,-43.4,0.0,-10.8,-37.6,-18.8,10.8,-37.6,-18.8,0.0,-43.4,0.0,0.0,-37.6,-21.7,18.8,-37.6,-10.8,0.0,-43.4,0.0,10.8,-37.6,-18.8,21.7,-37.6,0.0,0.0,-43.4,0.0,18.8,-37.6,-10.8,18.8,-37.6,10.8,0.0,-43.4,0.0,21.7,-37.6,0.0,10.8,-37.6,18.8,0.0,-43.4,0.0,18.8,-37.6,10.8,0.0,-37.6,21.7,0.0,-43.4,0.0,10.8,-37.6,18.8,],
11 | "normals": [0.08,-0.81,-0.58,0.01,-1.00,0.00,0.36,-0.81,-0.46,0.36,-0.81,-0.46,0.01,-1.00,0.00,0.54,-0.81,-0.23,0.54,-0.81,-0.23,0.01,-1.00,0.00,0.58,-0.81,0.06,0.58,-0.81,0.06,0.01,-1.00,0.00,0.48,-0.81,0.34,0.48,-0.81,0.34,0.01,-1.00,0.00,0.25,-0.81,0.53,0.25,-0.81,0.53,0.01,-1.00,0.00,-0.05,-0.81,0.59,-0.05,-0.81,0.59,0.01,-1.00,0.00,-0.34,-0.81,0.48,-0.34,-0.81,0.48,0.01,-1.00,0.00,-0.53,-0.81,0.25,-0.53,-0.81,0.25,0.01,-1.00,0.00,-0.58,-0.81,-0.08,-0.58,-0.81,-0.08,0.01,-1.00,0.00,-0.47,-0.81,-0.36,-0.47,-0.81,-0.36,0.01,-1.00,0.00,-0.22,-0.81,-0.55,-0.22,-0.81,-0.55,0.01,-1.00,0.00,0.08,-0.81,-0.58,0.06,-0.46,-0.89,0.08,-0.81,-0.58,0.51,-0.46,-0.73,0.51,-0.46,-0.73,0.08,-0.81,-0.58,0.36,-0.81,-0.46,0.51,-0.46,-0.73,0.36,-0.81,-0.46,0.80,-0.46,-0.38,0.80,-0.46,-0.38,0.36,-0.81,-0.46,0.54,-0.81,-0.23,0.80,-0.46,-0.38,0.54,-0.81,-0.23,0.89,-0.46,0.02,0.89,-0.46,0.02,0.54,-0.81,-0.23,0.58,-0.81,0.06,0.89,-0.46,0.02,0.58,-0.81,0.06,0.76,-0.46,0.46,0.76,-0.46,0.46,0.58,-0.81,0.06,0.48,-0.81,0.34,0.76,-0.46,0.46,0.48,-0.81,0.34,0.42,-0.46,0.79,0.42,-0.46,0.79,0.48,-0.81,0.34,0.25,-0.81,0.53,0.42,-0.46,0.79,0.25,-0.81,0.53,-0.03,-0.46,0.89,-0.03,-0.46,0.89,0.25,-0.81,0.53,-0.05,-0.81,0.59,-0.03,-0.46,0.89,-0.05,-0.81,0.59,-0.46,-0.46,0.76,-0.46,-0.46,0.76,-0.05,-0.81,0.59,-0.34,-0.81,0.48,-0.46,-0.46,0.76,-0.34,-0.81,0.48,-0.78,-0.46,0.43,-0.78,-0.46,0.43,-0.34,-0.81,0.48,-0.53,-0.81,0.25,-0.78,-0.46,0.43,-0.53,-0.81,0.25,-0.89,-0.46,-0.08,-0.89,-0.46,-0.08,-0.53,-0.81,0.25,-0.58,-0.81,-0.08,-0.89,-0.46,-0.08,-0.58,-0.81,-0.08,-0.73,-0.46,-0.51,-0.73,-0.46,-0.51,-0.58,-0.81,-0.08,-0.47,-0.81,-0.36,-0.73,-0.46,-0.51,-0.47,-0.81,-0.36,-0.39,-0.46,-0.80,-0.39,-0.46,-0.80,-0.47,-0.81,-0.36,-0.22,-0.81,-0.55,-0.39,-0.46,-0.80,-0.22,-0.81,-0.55,0.06,-0.46,-0.89,0.06,-0.46,-0.89,-0.22,-0.81,-0.55,0.08,-0.81,-0.58,0.04,0.02,-1.00,0.06,-0.46,-0.89,0.53,0.02,-0.85,0.53,0.02,-0.85,0.06,-0.46,-0.89,0.51,-0.46,-0.73,0.53,0.02,-0.85,0.51,-0.46,-0.73,0.88,0.02,-0.47,0.88,0.02,-0.47,0.51,-0.46,-0.73,0.80,-0.46,-0.38,0.88,0.02,-0.47,0.80,-0.46,-0.38,1.00,0.02,0.00,1.00,0.02,0.00,0.80,-0.46,-0.38,0.89,-0.46,0.02,1.00,0.02,0.00,0.89,-0.46,0.02,0.87,0.02,0.49,0.87,0.02,0.49,0.89,-0.46,0.02,0.76,-0.46,0.46,0.87,0.02,0.49,0.76,-0.46,0.46,0.51,0.02,0.86,0.51,0.02,0.86,0.76,-0.46,0.46,0.42,-0.46,0.79,0.51,0.02,0.86,0.42,-0.46,0.79,0.02,0.02,1.00,0.02,0.02,1.00,0.42,-0.46,0.79,-0.03,-0.46,0.89,0.02,0.02,1.00,-0.03,-0.46,0.89,-0.50,0.02,0.87,-0.50,0.02,0.87,-0.03,-0.46,0.89,-0.46,-0.46,0.76,-0.50,0.02,0.87,-0.46,-0.46,0.76,-0.86,0.02,0.51,-0.86,0.02,0.51,-0.46,-0.46,0.76,-0.78,-0.46,0.43,-0.86,0.02,0.51,-0.78,-0.46,0.43,-1.00,0.02,-0.04,-1.00,0.02,-0.04,-0.78,-0.46,0.43,-0.89,-0.46,-0.08,-1.00,0.02,-0.04,-0.89,-0.46,-0.08,-0.85,0.02,-0.53,-0.85,0.02,-0.53,-0.89,-0.46,-0.08,-0.73,-0.46,-0.51,-0.85,0.02,-0.53,-0.73,-0.46,-0.51,-0.46,0.02,-0.89,-0.46,0.02,-0.89,-0.73,-0.46,-0.51,-0.39,-0.46,-0.80,-0.46,0.02,-0.89,-0.39,-0.46,-0.80,0.04,0.02,-1.00,0.04,0.02,-1.00,-0.39,-0.46,-0.80,0.06,-0.46,-0.89,-0.01,0.49,-0.87,0.04,0.02,-1.00,0.43,0.49,-0.76,0.43,0.49,-0.76,0.04,0.02,-1.00,0.53,0.02,-0.85,0.43,0.49,-0.76,0.53,0.02,-0.85,0.76,0.49,-0.43,0.76,0.49,-0.43,0.53,0.02,-0.85,0.88,0.02,-0.47,0.76,0.49,-0.43,0.88,0.02,-0.47,0.87,0.49,0.00,0.87,0.49,0.00,0.88,0.02,-0.47,1.00,0.02,0.00,0.87,0.49,0.00,1.00,0.02,0.00,0.78,0.49,0.39,0.78,0.49,0.39,1.00,0.02,0.00,0.87,0.02,0.49,0.78,0.49,0.39,0.87,0.02,0.49,0.48,0.49,0.73,0.48,0.49,0.73,0.87,0.02,0.49,0.51,0.02,0.86,0.48,0.49,0.73,0.51,0.02,0.86,0.04,0.49,0.87,0.04,0.49,0.87,0.51,0.02,0.86,0.02,0.02,1.00,0.04,0.49,0.87,0.02,0.02,1.00,-0.40,0.49,0.78,-0.40,0.49,0.78,0.02,0.02,1.00,-0.50,0.02,0.87,-0.40,0.49,0.78,-0.50,0.02,0.87,-0.73,0.49,0.48,-0.73,0.49,0.48,-0.50,0.02,0.87,-0.86,0.02,0.51,-0.73,0.49,0.48,-0.86,0.02,0.51,-0.87,0.49,0.05,-0.87,0.49,0.05,-0.86,0.02,0.51,-1.00,0.02,-0.04,-0.87,0.49,0.05,-1.00,0.02,-0.04,-0.75,0.49,-0.44,-0.75,0.49,-0.44,-1.00,0.02,-0.04,-0.85,0.02,-0.53,-0.75,0.49,-0.44,-0.85,0.02,-0.53,-0.44,0.49,-0.76,-0.44,0.49,-0.76,-0.85,0.02,-0.53,-0.46,0.02,-0.89,-0.44,0.49,-0.76,-0.46,0.02,-0.89,-0.01,0.49,-0.87,-0.01,0.49,-0.87,-0.46,0.02,-0.89,0.04,0.02,-1.00,-0.03,0.83,-0.56,-0.01,0.49,-0.87,0.25,0.83,-0.50,0.25,0.83,-0.50,-0.01,0.49,-0.87,0.43,0.49,-0.76,0.25,0.83,-0.50,0.43,0.49,-0.76,0.46,0.83,-0.31,0.46,0.83,-0.31,0.43,0.49,-0.76,0.76,0.49,-0.43,0.46,0.83,-0.31,0.76,0.49,-0.43,0.56,0.83,-0.04,0.56,0.83,-0.04,0.76,0.49,-0.43,0.87,0.49,0.00,0.56,0.83,-0.04,0.87,0.49,0.00,0.51,0.83,0.23,0.51,0.83,0.23,0.87,0.49,0.00,0.78,0.49,0.39,0.51,0.83,0.23,0.78,0.49,0.39,0.33,0.83,0.45,0.33,0.83,0.45,0.78,0.49,0.39,0.48,0.49,0.73,0.33,0.83,0.45,0.48,0.49,0.73,0.07,0.83,0.55,0.07,0.83,0.55,0.48,0.49,0.73,0.04,0.49,0.87,0.07,0.83,0.55,0.04,0.49,0.87,-0.22,0.83,0.51,-0.22,0.83,0.51,0.04,0.49,0.87,-0.40,0.49,0.78,-0.22,0.83,0.51,-0.40,0.49,0.78,-0.45,0.83,0.33,-0.45,0.83,0.33,-0.40,0.49,0.78,-0.73,0.49,0.48,-0.45,0.83,0.33,-0.73,0.49,0.48,-0.55,0.83,0.06,-0.55,0.83,0.06,-0.73,0.49,0.48,-0.87,0.49,0.05,-0.55,0.83,0.06,-0.87,0.49,0.05,-0.50,0.83,-0.25,-0.50,0.83,-0.25,-0.87,0.49,0.05,-0.75,0.49,-0.44,-0.50,0.83,-0.25,-0.75,0.49,-0.44,-0.31,0.83,-0.46,-0.31,0.83,-0.46,-0.75,0.49,-0.44,-0.44,0.49,-0.76,-0.31,0.83,-0.46,-0.44,0.49,-0.76,-0.03,0.83,-0.56,-0.03,0.83,-0.56,-0.44,0.49,-0.76,-0.01,0.49,-0.87,0.25,0.83,-0.50,0.00,1.00,0.00,-0.03,0.83,-0.56,0.46,0.83,-0.31,0.00,1.00,0.00,0.25,0.83,-0.50,0.56,0.83,-0.04,0.00,1.00,0.00,0.46,0.83,-0.31,0.51,0.83,0.23,0.00,1.00,0.00,0.56,0.83,-0.04,0.33,0.83,0.45,0.00,1.00,0.00,0.51,0.83,0.23,0.07,0.83,0.55,0.00,1.00,0.00,0.33,0.83,0.45,-0.22,0.83,0.51,0.00,1.00,0.00,0.07,0.83,0.55,-0.45,0.83,0.33,0.00,1.00,0.00,-0.22,0.83,0.51,-0.55,0.83,0.06,0.00,1.00,0.00,-0.45,0.83,0.33,-0.50,0.83,-0.25,0.00,1.00,0.00,-0.55,0.83,0.06,-0.31,0.83,-0.46,0.00,1.00,0.00,-0.50,0.83,-0.25,-0.03,0.83,-0.56,0.00,1.00,0.00,-0.31,0.83,-0.46,]
12 | },
13 | ],
14 | "textureCoordinates": [0.000000,0.166667,0.000000,0.000000,0.083333,0.166667,0.083333,0.166667,0.083333,0.000000,0.166667,0.166667,0.166667,0.166667,0.166667,0.000000,0.250000,0.166667,0.250000,0.166667,0.250000,0.000000,0.333333,0.166667,0.333333,0.166667,0.333333,0.000000,0.416667,0.166667,0.416667,0.166667,0.416667,0.000000,0.500000,0.166667,0.500000,0.166667,0.500000,0.000000,0.583333,0.166667,0.583333,0.166667,0.583333,0.000000,0.666667,0.166667,0.666667,0.166667,0.666667,0.000000,0.750000,0.166667,0.750000,0.166667,0.750000,0.000000,0.833333,0.166667,0.833333,0.166667,0.833333,0.000000,0.916667,0.166667,0.916667,0.166667,0.916667,0.000000,1.000000,0.166667,0.000000,0.333333,0.000000,0.166667,0.083333,0.333333,0.083333,0.333333,0.000000,0.166667,0.083333,0.166667,0.083333,0.333333,0.083333,0.166667,0.166667,0.333333,0.166667,0.333333,0.083333,0.166667,0.166667,0.166667,0.166667,0.333333,0.166667,0.166667,0.250000,0.333333,0.250000,0.333333,0.166667,0.166667,0.250000,0.166667,0.250000,0.333333,0.250000,0.166667,0.333333,0.333333,0.333333,0.333333,0.250000,0.166667,0.333333,0.166667,0.333333,0.333333,0.333333,0.166667,0.416667,0.333333,0.416667,0.333333,0.333333,0.166667,0.416667,0.166667,0.416667,0.333333,0.416667,0.166667,0.500000,0.333333,0.500000,0.333333,0.416667,0.166667,0.500000,0.166667,0.500000,0.333333,0.500000,0.166667,0.583333,0.333333,0.583333,0.333333,0.500000,0.166667,0.583333,0.166667,0.583333,0.333333,0.583333,0.166667,0.666667,0.333333,0.666667,0.333333,0.583333,0.166667,0.666667,0.166667,0.666667,0.333333,0.666667,0.166667,0.750000,0.333333,0.750000,0.333333,0.666667,0.166667,0.750000,0.166667,0.750000,0.333333,0.750000,0.166667,0.833333,0.333333,0.833333,0.333333,0.750000,0.166667,0.833333,0.166667,0.833333,0.333333,0.833333,0.166667,0.916667,0.333333,0.916667,0.333333,0.833333,0.166667,0.916667,0.166667,0.916667,0.333333,0.916667,0.166667,1.000000,0.333333,1.000000,0.333333,0.916667,0.166667,1.000000,0.166667,0.000000,0.500000,0.000000,0.333333,0.083333,0.500000,0.083333,0.500000,0.000000,0.333333,0.083333,0.333333,0.083333,0.500000,0.083333,0.333333,0.166667,0.500000,0.166667,0.500000,0.083333,0.333333,0.166667,0.333333,0.166667,0.500000,0.166667,0.333333,0.250000,0.500000,0.250000,0.500000,0.166667,0.333333,0.250000,0.333333,0.250000,0.500000,0.250000,0.333333,0.333333,0.500000,0.333333,0.500000,0.250000,0.333333,0.333333,0.333333,0.333333,0.500000,0.333333,0.333333,0.416667,0.500000,0.416667,0.500000,0.333333,0.333333,0.416667,0.333333,0.416667,0.500000,0.416667,0.333333,0.500000,0.500000,0.500000,0.500000,0.416667,0.333333,0.500000,0.333333,0.500000,0.500000,0.500000,0.333333,0.583333,0.500000,0.583333,0.500000,0.500000,0.333333,0.583333,0.333333,0.583333,0.500000,0.583333,0.333333,0.666667,0.500000,0.666667,0.500000,0.583333,0.333333,0.666667,0.333333,0.666667,0.500000,0.666667,0.333333,0.750000,0.500000,0.750000,0.500000,0.666667,0.333333,0.750000,0.333333,0.750000,0.500000,0.750000,0.333333,0.833333,0.500000,0.833333,0.500000,0.750000,0.333333,0.833333,0.333333,0.833333,0.500000,0.833333,0.333333,0.916667,0.500000,0.916667,0.500000,0.833333,0.333333,0.916667,0.333333,0.916667,0.500000,0.916667,0.333333,1.000000,0.500000,1.000000,0.500000,0.916667,0.333333,1.000000,0.333333,0.000000,0.666667,0.000000,0.500000,0.083333,0.666667,0.083333,0.666667,0.000000,0.500000,0.083333,0.500000,0.083333,0.666667,0.083333,0.500000,0.166667,0.666667,0.166667,0.666667,0.083333,0.500000,0.166667,0.500000,0.166667,0.666667,0.166667,0.500000,0.250000,0.666667,0.250000,0.666667,0.166667,0.500000,0.250000,0.500000,0.250000,0.666667,0.250000,0.500000,0.333333,0.666667,0.333333,0.666667,0.250000,0.500000,0.333333,0.500000,0.333333,0.666667,0.333333,0.500000,0.416667,0.666667,0.416667,0.666667,0.333333,0.500000,0.416667,0.500000,0.416667,0.666667,0.416667,0.500000,0.500000,0.666667,0.500000,0.666667,0.416667,0.500000,0.500000,0.500000,0.500000,0.666667,0.500000,0.500000,0.583333,0.666667,0.583333,0.666667,0.500000,0.500000,0.583333,0.500000,0.583333,0.666667,0.583333,0.500000,0.666667,0.666667,0.666667,0.666667,0.583333,0.500000,0.666667,0.500000,0.666667,0.666667,0.666667,0.500000,0.750000,0.666667,0.750000,0.666667,0.666667,0.500000,0.750000,0.500000,0.750000,0.666667,0.750000,0.500000,0.833333,0.666667,0.833333,0.666667,0.750000,0.500000,0.833333,0.500000,0.833333,0.666667,0.833333,0.500000,0.916667,0.666667,0.916667,0.666667,0.833333,0.500000,0.916667,0.500000,0.916667,0.666667,0.916667,0.500000,1.000000,0.666667,1.000000,0.666667,0.916667,0.500000,1.000000,0.500000,0.000000,0.833333,0.000000,0.666667,0.083333,0.833333,0.083333,0.833333,0.000000,0.666667,0.083333,0.666667,0.083333,0.833333,0.083333,0.666667,0.166667,0.833333,0.166667,0.833333,0.083333,0.666667,0.166667,0.666667,0.166667,0.833333,0.166667,0.666667,0.250000,0.833333,0.250000,0.833333,0.166667,0.666667,0.250000,0.666667,0.250000,0.833333,0.250000,0.666667,0.333333,0.833333,0.333333,0.833333,0.250000,0.666667,0.333333,0.666667,0.333333,0.833333,0.333333,0.666667,0.416667,0.833333,0.416667,0.833333,0.333333,0.666667,0.416667,0.666667,0.416667,0.833333,0.416667,0.666667,0.500000,0.833333,0.500000,0.833333,0.416667,0.666667,0.500000,0.666667,0.500000,0.833333,0.500000,0.666667,0.583333,0.833333,0.583333,0.833333,0.500000,0.666667,0.583333,0.666667,0.583333,0.833333,0.583333,0.666667,0.666667,0.833333,0.666667,0.833333,0.583333,0.666667,0.666667,0.666667,0.666667,0.833333,0.666667,0.666667,0.750000,0.833333,0.750000,0.833333,0.666667,0.666667,0.750000,0.666667,0.750000,0.833333,0.750000,0.666667,0.833333,0.833333,0.833333,0.833333,0.750000,0.666667,0.833333,0.666667,0.833333,0.833333,0.833333,0.666667,0.916667,0.833333,0.916667,0.833333,0.833333,0.666667,0.916667,0.666667,0.916667,0.833333,0.916667,0.666667,1.000000,0.833333,1.000000,0.833333,0.916667,0.666667,1.000000,0.666667,0.083333,0.833333,0.000000,1.000000,0.000000,0.833333,0.166667,0.833333,0.083333,1.000000,0.083333,0.833333,0.250000,0.833333,0.166667,1.000000,0.166667,0.833333,0.333333,0.833333,0.250000,1.000000,0.250000,0.833333,0.416667,0.833333,0.333333,1.000000,0.333333,0.833333,0.500000,0.833333,0.416667,1.000000,0.416667,0.833333,0.583333,0.833333,0.500000,1.000000,0.500000,0.833333,0.666667,0.833333,0.583333,1.000000,0.583333,0.833333,0.750000,0.833333,0.666667,1.000000,0.666667,0.833333,0.833333,0.833333,0.750000,1.000000,0.750000,0.833333,0.916667,0.833333,0.833333,1.000000,0.833333,0.833333,1.000000,0.833333,0.916667,1.000000,0.916667,0.833333,]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/js/Player.js:
--------------------------------------------------------------------------------
1 | var Player = function(engine, camera, level){
2 | var acc = 0.046875 * 3600.0; // Acceleration
3 | var air = 0.09375 * 3600.0; // Air Acceleration
4 | var dec = 0.5 * 3600.0; // Deceleration
5 | var max = 6 * 60.0; // Max speed
6 | var frc = 0.046875 * 3600.0; // Friction
7 | var grv = 0.21875 * 3600.0; // Gravity
8 | var jmp = 6.5 * 60.0; // Jump Stength
9 | var ljp = 4.0 * 60.0; // Low Jump Strength (for variable jump)
10 | var slp = 0.125 * 3600.0; // Slope Acceleration
11 | var mgs = 2.5 * 60.0; // Minimum Ground Speed to Stick on Walls
12 | var mrs = 1.03125 * 60.0; // Mininum Rolling Speed
13 | var mrr = 0.5 * 60.0; // Mininum Rolling Speed After Already Rolling
14 | var sru = 0.078125 * 60.0 * 60.0;
15 | var srd = 0.3125 * 60.0 * 60.0;
16 |
17 | var mesh = engine.resources.get("mesh/sonic.jsonmesh");
18 | var spinball = engine.resources.get("mesh/spinball.jsonmesh");
19 | var player = new engine.world.MeshEntity(mesh);
20 | var speed = $V([0,0,0]);
21 | var targetCameraAngle = Math.PI/2;
22 | var cameraAngle = Math.PI/2;
23 | var cameraDistance = 256+64;
24 | var cameraHeight = 64;
25 | var targetCameraHeight = 100;
26 |
27 | var onGround = false;
28 | var onLedge = false;
29 | var isHoldingJump = false;
30 | var cameraBoxPosition = player.position();
31 | var cameraBoxWidth = 16;
32 | var cameraBoxHeight = 64;
33 | var cameraBoxYOffset = 32; // 128 - 96
34 | var cameraOffsetY = 16; // 128 - 112
35 |
36 | var animations = {
37 | stopped: {
38 | start: 0,
39 | end: 0,
40 | speed: 1
41 | },
42 | walking: {
43 | start: 1,
44 | end: 8,
45 | speed: 10
46 | },
47 | running: {
48 | start: 9,
49 | end: 12,
50 | speed: 20
51 | },
52 | spinning: {
53 | start: 13,
54 | end: 13,
55 | speed: 0
56 | },
57 | lookUp: {
58 | start: 14,
59 | end: 14,
60 | speed: 0
61 | },
62 | spring: {
63 | start: 15,
64 | end: 15,
65 | speed: 0
66 | },
67 | hit: {
68 | start: 16,
69 | end: 16,
70 | speed: 0
71 | },
72 | crouchDown: {
73 | start: 17,
74 | end: 17,
75 | speed: 0
76 | },
77 | hold: {
78 | start: 18,
79 | end: 18,
80 | speed: 0
81 | },
82 | waiting: {
83 | start: 19,
84 | end: 20,
85 | speed: 3
86 | },
87 | dying: {
88 | start: 21,
89 | end: 21,
90 | speed: 2
91 | },
92 | balancing: {
93 | start: 22,
94 | end: 23,
95 | speed: 4
96 | },
97 | pushing: {
98 | start: 24,
99 | end: 26,
100 | speed: 4
101 | },
102 | breathing: {
103 | start: 28,
104 | end: 28,
105 | speed: 0
106 | }
107 | };
108 | var currentAnimation = "stopped";
109 | var lastAnimation = "stopped";
110 | var animationTransform = Matrix.I(4);
111 |
112 | var SPEED_BASED_ANIMATION_GAP = 0.2;
113 |
114 | var timeWaiting = 0.0;
115 | var isPushing = false;
116 |
117 | var STATE_NORMAL = 1;
118 | var STATE_JUMPING = 2;
119 | var STATE_ROLLING = 3;
120 | var STATE_CROUCH_DOWN = 4;
121 | var STATE_SPINDASH = 5;
122 | var STATE_LOOK_UP = 6;
123 | var STATE_SPRING = 7;
124 | player.STATE_NORMAL = STATE_NORMAL;
125 | player.STATE_JUMPING = STATE_JUMPING;
126 | player.STATE_ROLLING = STATE_ROLLING;
127 | player.STATE_CROUCH_DOWN = STATE_CROUCH_DOWN;
128 | player.STATE_SPINDASH = STATE_SPINDASH;
129 | player.STATE_LOOK_UP = STATE_LOOK_UP;
130 | player.STATE_SPRING = STATE_SPRING;
131 |
132 | var state = STATE_NORMAL;
133 |
134 | player.state = function(newState) {
135 | if (newState !== undefined) {
136 | state = newState;
137 | }
138 | return state;
139 | }
140 |
141 | var spindashCharge = 0;
142 |
143 | var direction = $V([0,0,0]);
144 |
145 | var angle = 0.0;
146 | var angleOverride = false;
147 |
148 | camera.fov(35);
149 | // player.scale($V([0.20,0.41,0.20]));
150 | //player.scale($V([3,3,3]));
151 |
152 | var convertMotionToAir = function() {
153 | speed = player.rotation().make3x3().x(speed);
154 | onGround = false;
155 | }
156 |
157 | var convertMotionToGround = function() {
158 | speed = player.rotation().inverse().make3x3().x(speed);
159 | onGround = true;
160 | }
161 |
162 | var alignPlayerToNormal = function(normal, timeDelta) {
163 | if (speed.modulus() < mgs) {
164 | player.rotation(player.rotation().AlignYAxis(normal, 1.0 - Math.pow(0.0001, timeDelta)));
165 | } else {
166 | player.rotation(player.rotation().AlignYAxis(normal, 1.0));
167 | }
168 | }
169 |
170 | var updateCamera = function(timeDelta) {
171 |
172 | if (engine.input.pressed("Q".charCodeAt(0)))
173 | targetCameraAngle += Math.PI/4;
174 | if (engine.input.pressed("W".charCodeAt(0)))
175 | targetCameraAngle -= Math.PI/4;
176 |
177 | cameraAngle -= (cameraAngle - targetCameraAngle) * 4.0 * timeDelta;
178 | cameraHeight -= (cameraHeight - (targetCameraHeight - 0.0 * Math.min(0, speed.elements[1]))) * 1.0 * timeDelta;
179 |
180 | var transformedSpeed = player.rotation().make3x3().x(speed).x(timeDelta);
181 |
182 | // Horizontal movement
183 | if (player.position().elements[0] > (cameraBoxPosition.elements[0] + cameraBoxWidth / 2)) {
184 | cameraBoxPosition.elements[0] += Math.min(player.position().elements[0] - (cameraBoxPosition.elements[0] + cameraBoxWidth / 2), 16 * 60 * timeDelta);
185 | }
186 |
187 | if (player.position().elements[0] < (cameraBoxPosition.elements[0] - cameraBoxWidth / 2)) {
188 | cameraBoxPosition.elements[0] += Math.max(player.position().elements[0] - (cameraBoxPosition.elements[0] - cameraBoxWidth / 2), -16 * 60 * timeDelta);
189 | }
190 |
191 | if (player.position().elements[2] > (cameraBoxPosition.elements[2] + cameraBoxWidth / 2)) {
192 | cameraBoxPosition.elements[2] += Math.min(player.position().elements[2] - (cameraBoxPosition.elements[2] + cameraBoxWidth / 2), 16 * 60 * timeDelta);
193 | }
194 |
195 | if (player.position().elements[2] < (cameraBoxPosition.elements[2] - cameraBoxWidth / 2)) {
196 | cameraBoxPosition.elements[2] += Math.max(player.position().elements[2] - (cameraBoxPosition.elements[2] - cameraBoxWidth / 2), -16 * 60 * timeDelta);
197 | }
198 |
199 | // Vertical movement
200 | if (!onGround) {
201 | if (player.position().elements[1] > cameraBoxPosition.elements[1] + cameraBoxHeight ) {
202 | cameraBoxPosition.elements[1] += Math.min(player.position().elements[1] - (cameraBoxPosition.elements[1] + cameraBoxHeight), 16 * 60 * timeDelta);
203 | }
204 | if (player.position().elements[1] < cameraBoxPosition.elements[1]) {
205 | cameraBoxPosition.elements[1] += Math.max(player.position().elements[1] - (cameraBoxPosition.elements[1]), - 16 * 60 * timeDelta);
206 | }
207 | } else {
208 | if (player.position().elements[1] > cameraBoxPosition.elements[1] + cameraBoxYOffset ) {
209 | if (Math.abs(transformedSpeed.elements[1]) > 6 * timeDelta) {
210 | // Fast catch up
211 | cameraBoxPosition.elements[1] += Math.min(player.position().elements[1] - (cameraBoxPosition.elements[1] + cameraBoxYOffset), 16 * 60 * timeDelta);
212 | } else {
213 | // Slow catch up
214 | cameraBoxPosition.elements[1] += Math.min(player.position().elements[1] - (cameraBoxPosition.elements[1] + cameraBoxYOffset), 6 * 60 * timeDelta);
215 | }
216 | }
217 | if (player.position().elements[1] < cameraBoxPosition.elements[1] + cameraBoxYOffset ) {
218 | if (Math.abs(transformedSpeed.elements[1]) > 6 * timeDelta) {
219 | // Fast catch up
220 | cameraBoxPosition.elements[1] += Math.max(player.position().elements[1] - (cameraBoxPosition.elements[1] + cameraBoxYOffset), -16 * 60 * timeDelta);
221 | } else {
222 | // Slow catch up
223 | cameraBoxPosition.elements[1] += Math.max(player.position().elements[1] - (cameraBoxPosition.elements[1] + cameraBoxYOffset), -6 * 60 * timeDelta);
224 | }
225 | }
226 | }
227 |
228 | camera.position(cameraBoxPosition.add($V([Math.cos(cameraAngle) * cameraDistance, cameraHeight + cameraOffsetY, Math.sin(cameraAngle) * cameraDistance])));
229 | camera.rotation(Matrix.LookAt(camera.position(), cameraBoxPosition.add($V([0,cameraOffsetY,0]))).inverse());
230 | }
231 |
232 | var handleControls = function(timeDelta) {
233 |
234 | timeWaiting += timeDelta;
235 |
236 | // Controls aligned to camera
237 | var canMove = true;
238 | var moveX = camera.rotation().x($V([1.0,0.0,0.0,0.0])).xyz();
239 | var moveZ = camera.rotation().x($V([0.0,0.0,1.0,0.0])).xyz();
240 |
241 | moveX.elements[1] = 0.0;
242 | moveZ.elements[1] = 0.0;
243 |
244 | moveX = moveX.toUnitVector();
245 | moveZ = moveZ.toUnitVector();
246 |
247 | direction = $V([0,0,0]);
248 |
249 | if (engine.input.heldLeft())
250 | direction = direction.add(moveX.x(-1));
251 |
252 | if (engine.input.heldRight())
253 | direction = direction.add(moveX.x(1));
254 |
255 | if (engine.input.heldUp())
256 | direction = direction.add(moveZ.x(-1));
257 |
258 | if (engine.input.heldDown())
259 | direction = direction.add(moveZ.x(1));
260 |
261 | if (state == STATE_CROUCH_DOWN || state == STATE_SPINDASH || state == STATE_LOOK_UP) {
262 | canMove = false;
263 | }
264 |
265 | if (state != STATE_ROLLING) {
266 | if (direction.modulus() > 0 && canMove) {
267 |
268 | timeWaiting = 0;
269 |
270 | // The player is holding the arrow keys on some direction
271 | direction = direction.toUnitVector();
272 |
273 | if ($V([speed.elements[0], 0, speed.elements[2]]).dot(direction) >= 0) {
274 | // The direction pressed is similar to the direction Sonic's facing
275 |
276 | if (speed.xz().modulus() > 2 && !angleOverride) {
277 | angle = Math.atan2(speed.elements[0], speed.elements[2]);
278 | // console.log(angle);
279 | }
280 |
281 | // Store the old speed (for max speed check)
282 | var oldSpeedModulus = speed.xz().modulus();
283 |
284 | if (onGround) {
285 | // Ground acc
286 | speed = speed.add((direction) .x (acc * timeDelta));
287 | } else {
288 | // Air acc
289 | speed = speed.add((direction) .x (air * timeDelta));
290 | }
291 | // Store the new speed
292 | var newSpeedModulus = speed.xz().modulus();
293 |
294 | if (newSpeedModulus > max) {
295 | // We're faster than the max speed
296 | if (oldSpeedModulus < max) {
297 | // We got here by "natural means". Get back to the max speed, but allow handling
298 | speed.elements[0] = (speed.elements[0] / newSpeedModulus) * max;
299 | speed.elements[2] = (speed.elements[2] / newSpeedModulus) * max;
300 | } else {
301 | // We got here by "supernatural means" (e.g. a Spring).
302 | if (newSpeedModulus > oldSpeedModulus) {
303 | // We're faster than we were before: Get back to as fast as we already were, but allow handling
304 | speed.elements[0] = (speed.elements[0] / newSpeedModulus) * oldSpeedModulus;
305 | speed.elements[2] = (speed.elements[2] / newSpeedModulus) * oldSpeedModulus;
306 | }
307 | }
308 | }
309 |
310 | } else {
311 | // The direction pressed is opposite to the direction Sonic's facing
312 | if (onGround) {
313 | // Ground deceleration
314 | speed = speed.add((direction) .x (dec * timeDelta));
315 | } else {
316 | // Air deceleration ( = the same as acceleration)
317 | speed = speed.add((direction) .x (air * timeDelta));
318 | }
319 | }
320 | } else {
321 | // The player is not holding on any direction
322 | if (onGround) {
323 | // We're on the floor. Enters friction.
324 | direction = $V([-speed.elements[0], 0, -speed.elements[2]]).toUnitVector();
325 | speed = speed.add(direction.x(frc * timeDelta));
326 |
327 | // Stop when speed is lower than friction
328 | if (speed.modulus() < (frc * timeDelta)) {
329 | speed = $V([0,0,0]);
330 | }
331 | } else {
332 | // no friction on air (we calculate air drag later)
333 | }
334 | }
335 | } else {
336 | // Rolling physics
337 |
338 | // Reduced friction.
339 | var frictionDirection = $V([-speed.elements[0], 0, -speed.elements[2]]).toUnitVector();
340 | speed = speed.add(frictionDirection.x(frc / 2 * timeDelta));
341 |
342 | // Stop when speed is lower than friction
343 | if (speed.modulus() < (frc * timeDelta)) {
344 | speed = $V([0,0,0]);
345 | } else {
346 | // Deceleration
347 | if ($V([speed.elements[0], 0, speed.elements[2]]).dot(direction) < 0) {
348 | speed = speed.add((direction) .x (dec / 4 * timeDelta));
349 | }
350 | }
351 | }
352 |
353 | // Jump/Spindash/Spindash Rev
354 | if (onGround && engine.input.pressed("X".charCodeAt(0))) {
355 | if (state == STATE_NORMAL || state == STATE_ROLLING) {
356 | isHoldingJump = true;
357 | speed.elements[1] = jmp;
358 | onGround = false;
359 | timeWaiting = 0;
360 | state = STATE_JUMPING;
361 | } else if (state == STATE_CROUCH_DOWN) {
362 | state = STATE_SPINDASH;
363 | spindashCharge = 0;
364 | } else if (state == STATE_SPINDASH) {
365 | spindashCharge += 2;
366 | if (spindashCharge > 8) {
367 | spindashCharge = 8;
368 | }
369 | }
370 | }
371 |
372 | // Variable jump
373 | if (!engine.input.held("X".charCodeAt(0)) && isHoldingJump) {
374 | isHoldingJump = false;
375 | if (speed.elements[1] > ljp) {
376 | speed.elements[1] = ljp;
377 | }
378 | }
379 |
380 | // gratuitous speed
381 | if (engine.input.pressed("P".charCodeAt(0))) {
382 | if (speed.elements[0] != 0 || speed.elements[2] != 0) {
383 | var length = speed.xz().modulus();
384 | speed.elements[0] *= 12 * 60 / length;
385 | speed.elements[2] *= 12 * 60 / length;
386 | }
387 | }
388 |
389 | // Look Up
390 | if (engine.input.held("S".charCodeAt(0))) {
391 | timeWaiting = 0;
392 | if (onGround && state == STATE_NORMAL) {
393 | if (speed.xz().modulus() < mrs) {
394 | state = STATE_LOOK_UP;
395 | }
396 | }
397 | } else {
398 | if (state == STATE_LOOK_UP) {
399 | state = STATE_NORMAL;
400 | }
401 | }
402 |
403 | // Roll/Crouch
404 | if (engine.input.held(" ".charCodeAt(0))) {
405 | timeWaiting = 0;
406 | // Only roll or crouch if we're on ground, and on normal state
407 | if (onGround && state == STATE_NORMAL || state == STATE_CROUCH_DOWN) {
408 | // We're moving. Roll
409 | if (speed.xz().modulus() > mrs) {
410 | if (state != STATE_ROLLING) {
411 | state = STATE_ROLLING;
412 | }
413 | } else {
414 | // We're not moving. Crouch.
415 | if (state != STATE_SPINDASH) {
416 | state = STATE_CROUCH_DOWN;
417 | }
418 | }
419 | }
420 | } else {
421 | // We've released the crouch button
422 | if (state == STATE_CROUCH_DOWN) {
423 | // We're crouching. Get back to normal.
424 | state = STATE_NORMAL;
425 | }
426 | if (state == STATE_SPINDASH) {
427 | // We're spindashing. Roll at the right speed.
428 | state = STATE_ROLLING;
429 | speed.elements[0] = (8 + Math.floor(Math.floor(spindashCharge) / 2)) * 60 * Math.sin(angle);
430 | speed.elements[2] = (8 + Math.floor(Math.floor(spindashCharge) / 2)) * 60 * Math.cos(angle);
431 | }
432 | }
433 |
434 | spindashCharge *= Math.pow(0.148834266, timeDelta);
435 |
436 | if (engine.input.pressed("R".charCodeAt(0))) {
437 | ringLoss();
438 | }
439 | }
440 |
441 | var handleGround = function(timeDelta) {
442 | var normal = player.rotation().make3x3().x($V([0,1,0]));
443 |
444 | // Slope Acceleration
445 | if (state != STATE_ROLLING) {
446 | speed = speed.add($V([normal.elements[0] * slp * timeDelta, 0, normal.elements[2] * slp * timeDelta]))
447 | } else {
448 | if ($V([normal.elements[0], 0, normal.elements[2]]).dot($V([speed.elements[0], 0, speed.elements[2]])) >= 0) {
449 | // Rolling Downhill
450 | speed = speed.add($V([normal.elements[0] * srd * timeDelta, 0, normal.elements[2] * srd * timeDelta]))
451 | } else {
452 | // Rolling Uphill
453 | speed = speed.add($V([normal.elements[0] * sru * timeDelta, 0, normal.elements[2] * sru * timeDelta]))
454 | }
455 | }
456 |
457 | // Fall off from the walls if we're too slow
458 | if (normal.dot($V([0,1,0])) <= 0.0 && speed.xz().modulus() < mgs) {
459 | convertMotionToAir();
460 | player.rotation(Matrix.I(4));
461 | return;
462 | }
463 |
464 | // Stop rolling if we're too slow.
465 | if (speed.modulus() <= mrr && state == STATE_ROLLING) {
466 | state = STATE_NORMAL;
467 | }
468 | }
469 |
470 | var handleAir = function(timeDelta) {
471 | // Add gravity to the player's y speed
472 | speed.elements[1] -= grv * timeDelta;
473 |
474 | if (speed.elements[1] > 0 && speed.elements[1] < 4 * 60) {
475 | // We're going upwards, but no that much
476 | if (speed.xz().modulus() > 0.125 * 60.0) {
477 | // We're going fast. Air drag kicks in
478 | speed.elements[0] *= Math.pow(0.148834266, timeDelta);
479 | speed.elements[2] *= Math.pow(0.148834266, timeDelta);
480 | }
481 | }
482 |
483 |
484 | if (state == STATE_ROLLING) {
485 | state = STATE_JUMPING;
486 | } else if (state == STATE_SPRING) {
487 | if (speed.elements[1] < 0) {
488 | state = STATE_NORMAL;
489 | }
490 | }
491 | }
492 |
493 | var handleCollisions = function(timeDelta) {
494 |
495 | var didPush = false;
496 | for (var i = 0; i < 2*Math.PI; i+= 0.25*Math.PI) {
497 | var sensorDirection = $V([Math.sin(i), 0, Math.cos(i)]);
498 | var intersect = level.rayIntersect(player.position().add($V([0,0,-4])), player.rotation().make3x3().x(sensorDirection), 15, 0);
499 | var speedComponent = sensorDirection.xz().dot(speed.xz());
500 |
501 | if (isFinite(intersect.distance)) {
502 | if (speedComponent >= 0) {
503 | speed.elements[0] -= speedComponent * sensorDirection.elements[0];
504 | speed.elements[2] -= speedComponent * sensorDirection.elements[2];
505 | }
506 | if (direction.xz().dot(sensorDirection.xz()) > 0.8) {
507 | angle = i;
508 | didPush = true;
509 | }
510 | player.position(player.position().subtract(player.rotation().make3x3().x(sensorDirection.x(15-intersect.distance))));
511 | }
512 | }
513 | if (isPushing && !didPush) {
514 | angleOverride = false;
515 | }
516 | isPushing = didPush;
517 | if (isPushing) {
518 | angleOverride = true;
519 | }
520 |
521 |
522 | var modeMatrix = player.rotation().make3x3();//.makeModeMatrix();
523 | var modeVector = modeMatrix.x($V([0, -1, 0]));
524 | var intersectA1 = level.rayIntersect(player.position().add($V([-9,0,-9])), modeVector, 36, 0);
525 | var intersectA2 = level.rayIntersect(player.position().add($V([-9,0,9])), modeVector, 36, 0);
526 | var intersectB1 = level.rayIntersect(player.position().add($V([9,0,-9])), modeVector, 36, 0);
527 | var intersectB2 = level.rayIntersect(player.position().add($V([9,0,9])), modeVector, 36, 0);
528 |
529 | var minIntersectA = ((intersectA1.distance < intersectA2.distance)?intersectA1:intersectA2);
530 | var minIntersectB = ((intersectB1.distance < intersectB2.distance)?intersectB1:intersectB2);
531 | var minIntersect = ((minIntersectA.distance < minIntersectB.distance)?minIntersectA:minIntersectB)
532 | /* var minIntersect = {
533 | distance: 0.0,
534 | normal: $V([0,0,0])
535 | }*/
536 | minIntersect.normal = $V([0,0,0]);
537 | var count = 0;
538 | if (isFinite(intersectA1.distance)) {
539 | // minIntersect.distance += intersectA1.distance;
540 | minIntersect.normal = minIntersect.normal.add(intersectA1.normal);
541 | count++;
542 | }
543 | if (isFinite(intersectA2.distance)) {
544 | // minIntersect.distance += intersectA2.distance;
545 | minIntersect.normal = minIntersect.normal.add(intersectA2.normal);
546 | count++;
547 | }
548 | if (isFinite(intersectB1.distance)) {
549 | // minIntersect.distance += intersectB1.distance;
550 | minIntersect.normal = minIntersect.normal.add(intersectB1.normal);
551 | count++;
552 | }
553 | if (isFinite(intersectB2.distance)) {
554 | // minIntersect.distance += intersectB2.distance;
555 | minIntersect.normal = minIntersect.normal.add(intersectB2.normal);
556 | count++;
557 | }
558 | // minIntersect.distance /= count;
559 | minIntersect.normal = minIntersect.normal.x(1/count).toUnitVector();
560 |
561 | if (count != 4) {
562 | onLedge = true;
563 | } else {
564 | onLedge = false;
565 | }
566 |
567 | if (isFinite(minIntersect.distance)) {
568 | if ((minIntersect.distance <= 20 || onGround) && speed.elements[1] <= 0) {
569 |
570 | player.position(player.position().add(player.rotation().make3x3().x($V([0,20-minIntersect.distance,0]))));
571 | if (minIntersect.normal.dot(player.rotation().make3x3().x($V([0,1,0]))) > 0.0) {
572 | alignPlayerToNormal(minIntersect.normal, timeDelta);
573 | }
574 |
575 | if (!onGround) {
576 | convertMotionToGround();
577 | }
578 |
579 | if (state == STATE_JUMPING || state == STATE_SPRING) {
580 | state = STATE_NORMAL;
581 | }
582 |
583 | speed.elements[1] = 0.0;
584 | }
585 | } else {
586 | convertMotionToAir();
587 | player.rotation(Matrix.I(4));
588 | }
589 |
590 | var modeVector = modeMatrix.x($V([0, 1, 0]));
591 | var intersectA1 = level.rayIntersect(player.position().add($V([-9,0,-9])), modeVector, 36, 0);
592 | var intersectA2 = level.rayIntersect(player.position().add($V([-9,0,9])), modeVector, 36, 0);
593 | var intersectB1 = level.rayIntersect(player.position().add($V([9,0,-9])), modeVector, 36, 0);
594 | var intersectB2 = level.rayIntersect(player.position().add($V([9,0,9])), modeVector, 36, 0);
595 |
596 | var minIntersectA = ((intersectA1.distance < intersectA2.distance)?intersectA1:intersectA2);
597 | var minIntersectB = ((intersectB1.distance < intersectB2.distance)?intersectB1:intersectB2);
598 | var minIntersect = ((minIntersectA.distance < minIntersectB.distance)?minIntersectA:minIntersectB)
599 |
600 | if (isFinite(minIntersect.distance)) {
601 | if (minIntersect.distance <= 20 && speed.elements[1] >= 0) {
602 | player.position(player.position().subtract(player.rotation().make3x3().x($V([0,20-minIntersect.distance,0]))));
603 | speed.elements[1] = 0.0;
604 | }
605 | }
606 | }
607 |
608 | var repositionPlayer = function(timeDelta) {
609 | player.position(player.position().add(player.rotation().make3x3().x(speed).x(timeDelta)));
610 | }
611 |
612 | var updateAnimations = function(timeDelta) {
613 | if (currentAnimation != lastAnimation) {
614 | player.frame = animations[currentAnimation].start;
615 | lastAnimation = currentAnimation;
616 | }
617 |
618 | player.frame += animations[currentAnimation].speed * timeDelta;
619 |
620 | if (player.frame >= animations[currentAnimation].end + 1) {
621 | player.frame -= animations[currentAnimation].end - animations[currentAnimation].start + 1;
622 | }
623 | }
624 |
625 | var handleAnimations = function(timeDelta) {
626 | // if (speed.xz().modulus() > frc * timeDelta) {
627 | // angle = Math.atan2(speed.elements[0], speed.elements[2]);
628 | // }
629 | var speedModulus = speed.xz().modulus();
630 | if (onGround) {
631 | if (state == STATE_ROLLING) {
632 | currentAnimation = "spinning";
633 | } else if (state == STATE_CROUCH_DOWN) {
634 | currentAnimation = "crouchDown";
635 | } else if (state == STATE_LOOK_UP) {
636 | currentAnimation = "lookUp";
637 | } else if (state == STATE_SPINDASH) {
638 | currentAnimation = "spinning";
639 | } else {
640 | if (speedModulus <= SPEED_BASED_ANIMATION_GAP) {
641 | if (onLedge) {
642 | currentAnimation = "balancing";
643 | } else {
644 | if (isPushing) {
645 | currentAnimation = "pushing";
646 | } else {
647 | if (timeWaiting > 5) {
648 | currentAnimation = "waiting";
649 | } else {
650 | currentAnimation = "stopped";
651 | }
652 | }
653 | }
654 | } else if (speedModulus < max - SPEED_BASED_ANIMATION_GAP) {
655 | if (isPushing) {
656 | currentAnimation = "pushing";
657 | } else {
658 | currentAnimation = "walking";
659 | }
660 | } else {
661 | currentAnimation = "running";
662 | }
663 | }
664 | } else {
665 | if (state == STATE_JUMPING) {
666 | currentAnimation = "spinning";
667 | } else if (state == STATE_SPRING) {
668 | currentAnimation = "spring";
669 | } else {
670 | if (speedModulus <= SPEED_BASED_ANIMATION_GAP) {
671 | currentAnimation = "stopped";
672 | } else if (speedModulus < max - SPEED_BASED_ANIMATION_GAP) {
673 | currentAnimation = "walking";
674 | } else {
675 | currentAnimation = "running";
676 | }
677 | }
678 | }
679 | updateAnimations(timeDelta);
680 |
681 | if (currentAnimation == "spinning") {
682 | animationTransform = Matrix.RotationX(-engine.world.time()*40.0).ensure4x4();
683 | if (Math.floor(engine.world.time() * 40) % 2 == 0) {
684 | spinball.visible = true;
685 | } else {
686 | spinball.visible = false;
687 | }
688 | } else if (currentAnimation == "spring") {
689 | animationTransform = Matrix.RotationZ(-engine.world.time()*10.0).ensure4x4();
690 | spinball.visible = false;
691 | } else {
692 | spinball.visible = false;
693 | animationTransform = Matrix.I(4);
694 | }
695 | }
696 |
697 | var ringLoss = function() {
698 | var rotation = Matrix.RotationY(-cameraAngle+Math.PI/2);
699 | var speed = 4 * 60.0;
700 | var angle = 101.25 / 360.0 * 2 * Math.PI;
701 | var n = false;
702 | for (var t = 0; t<32; t++) {
703 | var ring = Ring(engine, player, level);
704 | ring.position(player.position());
705 | if (n) {
706 | ring.speed(rotation.x($V([Math.sin(angle)*speed, -Math.cos(angle)*speed, -4])));
707 | angle += 22.5 / 360 * 2 * Math.PI;
708 | } else {
709 | ring.speed(rotation.x($V([-Math.sin(angle)*speed, Math.cos(angle)*speed, +4])));
710 | }
711 | engine.world.add(ring);
712 | n = !n;
713 | if (t == 15) {
714 | speed = 2 * 60;
715 | angle = 101.25 / 360 * 2 * Math.PI;
716 | }
717 | }
718 | }
719 |
720 | var superUpdate = player.update;
721 |
722 | player.update = function(timeDelta) {
723 |
724 | superUpdate(timeDelta);
725 |
726 | handleControls(timeDelta);
727 |
728 | if (onGround) {
729 | handleGround(timeDelta);
730 | } else {
731 | handleAir(timeDelta);
732 | }
733 |
734 | repositionPlayer(timeDelta);
735 |
736 | handleCollisions(timeDelta);
737 |
738 | handleAnimations(timeDelta);
739 |
740 | if (player.position().elements[1] < -100) {
741 | // player.position(player.position().add($V([0,1000,0])));
742 | speed = $V([speed.elements[0],500,speed.elements[2]]);
743 | }
744 |
745 | updateCamera(timeDelta);
746 |
747 | }
748 |
749 | var superRender = player.render;
750 | player.render = function(renderParams) {
751 |
752 | var rotation = player.rotation();
753 |
754 | player.rotation(rotation.x(Matrix.RotationY(Math.PI + angle).ensure4x4()).x(animationTransform));
755 |
756 | renderParams.modelView = player.modelView();
757 | renderParams.normalModelView = player.normalModelView();
758 | if (spinball.visible) {
759 | spinball.render(renderParams, 0);
760 | } else {
761 | mesh.render(renderParams, Math.floor(player.frame));
762 | }
763 | player.rotation(rotation);
764 | }
765 |
766 | player.speed = function(newSpeed) {
767 | if (newSpeed !== undefined) {
768 | speed = newSpeed;
769 | }
770 | return speed;
771 | }
772 |
773 | //player.isStatic = true;
774 |
775 | return player;
776 | }
--------------------------------------------------------------------------------
/js/GraphicsEngine.js:
--------------------------------------------------------------------------------
1 | var GraphicsEngine = function(engine, canvas) {
2 | var graphicsEngine = {};
3 | var gl;
4 | var glParams = {}//{premultipliedAlpha: false, alpha: false};
5 | var activeShader = null;
6 |
7 | console.log("Initializing WebGl...");
8 |
9 | // Try to initialize WebGL
10 | if (!(gl = canvas.getContext("webgl", glParams))) {
11 | // Initialization failed, try experimental mode
12 | if (gl = canvas.getContext("experimental-webgl", glParams)) {
13 | // Tell the user WebGL is running in experimental mode
14 | console.info("WebGL is running in experimental mode. Performance and stability may suffer.")
15 | } else {
16 | // Experimental mode failed, WebGL not supported or disabled
17 | throw new Error("Could not initialize WebGL. Are you running a modern browser with WebGL enabled?");
18 | }
19 | }
20 |
21 | gl.enable(gl.DEPTH_TEST);
22 | // gl.enable(gl.CULL_FACE);
23 | // gl.cullFace(gl.FRONT);
24 | gl.depthFunc(gl.LESS);
25 | gl.clearColor(0.0, 0.0, 0.0, 1.0);
26 | gl.enable(gl.BLEND);
27 | gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
28 |
29 | // expose the WebGL context
30 | graphicsEngine.gl = gl;
31 |
32 | graphicsEngine.clear = function(){
33 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
34 | }
35 |
36 | graphicsEngine.clearColor = function(){
37 | gl.clear(gl.COLOR_BUFFER_BIT);
38 | }
39 |
40 | graphicsEngine.clearDepth = function(){
41 | gl.clear(gl.DEPTH_BUFFER_BIT);
42 | }
43 |
44 |
45 | graphicsEngine.width = function() {
46 | return canvas.width;
47 | }
48 |
49 | graphicsEngine.height = function() {
50 | return canvas.height;
51 | }
52 |
53 | graphicsEngine.aspectRatio = function() {
54 | return canvas.width / canvas.height;
55 | }
56 |
57 | graphicsEngine.Shader = function(shaderData, shaderName) {
58 | var shader = {}
59 |
60 | // Compile the vertex shader
61 | console.log("Compiling vertex shader...");
62 | var vertexShader = gl.createShader(gl.VERTEX_SHADER);
63 | gl.shaderSource(vertexShader, shaderData.vertexShader);
64 | gl.compileShader(vertexShader);
65 |
66 | if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
67 | throw new Error("Error compiling vertex shader: " + gl.getShaderInfoLog(vertexShader));
68 | }
69 |
70 | // Compile the fragment shader
71 | console.log("Compiling fragment shader...");
72 | var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
73 | gl.shaderSource(fragmentShader, shaderData.fragmentShader);
74 | gl.compileShader(fragmentShader);
75 |
76 | if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
77 | throw new Error("Error compiling fragment shader: " + gl.getShaderInfoLog(fragmentShader));
78 | }
79 |
80 | // Link the program
81 | console.log("Linking shader program...");
82 | var program = gl.createProgram();
83 | gl.attachShader(program, fragmentShader);
84 | gl.attachShader(program, vertexShader);
85 | gl.linkProgram(program);
86 | if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
87 | throw new Error("Error linking shader program: " + gl.getProgramInfoLog(program));
88 | }
89 |
90 | // Obtain uniform locations
91 | console.log("Extracting uniform locations...");
92 | var uniforms = {};
93 | shaderData.uniforms.forEach(function(uniform){
94 | uniforms[uniform] = gl.getUniformLocation(program, uniform);
95 | if (!uniforms[uniform]) {
96 | console.warn("Nonexistent or unused uniform in the description of shader " + shaderName + ": " + uniform);
97 | }
98 | });
99 |
100 | // Obtain attribute locations
101 | console.log("Extracting attribute locations...");
102 | var attributes = {};
103 | shaderData.attributes.forEach(function(attribute){
104 | attributes[attribute] = gl.getAttribLocation(program, attribute);
105 | if (attributes[attribute] == -1) {
106 | console.warn("Nonexistent or unused attribute in the description of shader " + shaderName + ": " + attribute);
107 | }
108 | });
109 |
110 | // Use the program
111 | shader.use = function() {
112 | if (activeShader != shader) {
113 | gl.useProgram(program);
114 | activeShader = shader;
115 | // console.log("ShaderSwap");
116 | }
117 | }
118 |
119 | // Get a uniform location
120 | shader.uniform = function(name) {
121 | if (!uniforms[name])
122 | throw new Error("Shader " + shaderName + " has no uniform named " + name);
123 | return uniforms[name];
124 | }
125 |
126 | // Get an attribute location
127 | shader.attribute = function(name) {
128 | if (attributes[name] === undefined)
129 | throw new Error("Shader " + shaderName + " has no attribute named " + name);
130 | return attributes[name];
131 | }
132 |
133 | shader.hasAttribute = function(name) {
134 | return attributes[name] != null;
135 | }
136 |
137 | shader.hasUniform = function(name) {
138 | return uniforms[name] != null;
139 | }
140 | return shader;
141 | }
142 |
143 | graphicsEngine.Mesh = function(meshData) {
144 | var mesh = {};
145 | var surfaces = [];
146 | var __uniformArray = [null];
147 |
148 | // bake the surfaces
149 | meshData.surfaces.forEach(function(surface){
150 | var bakedSurface = {};
151 | bakedSurface.name = surface.name;
152 | bakedSurface.frames = [];
153 | bakedSurface.shader = surface.shader;
154 | engine.resources.load(bakedSurface.shader);
155 | bakedSurface.samplers = surface.samplers;
156 | for (var name in bakedSurface.samplers) {
157 | engine.resources.load(bakedSurface.samplers[name]);
158 | }
159 |
160 | // No frames (single frame mode)
161 | if (!surface.frames) {
162 | // Create a single frame for baking
163 | surface.frames = [{normals: surface.normals, vertices: surface.vertices}];
164 | }
165 |
166 | // bake the frames
167 | console.log("Baking vertices and normals...");
168 | surface.frames.forEach(function(frame){
169 | var bakedFrame = {};
170 |
171 | // bake the vertices
172 | bakedFrame.vertices = new Float32Array(frame.vertices);
173 | bakedFrame.vertexBuffer = gl.createBuffer();
174 | gl.bindBuffer(gl.ARRAY_BUFFER, bakedFrame.vertexBuffer);
175 | gl.bufferData(gl.ARRAY_BUFFER, bakedFrame.vertices, gl.STATIC_DRAW);
176 |
177 | // bake the normals
178 | bakedFrame.normals = new Float32Array(frame.normals);
179 | bakedFrame.normalBuffer = gl.createBuffer();
180 | gl.bindBuffer(gl.ARRAY_BUFFER, bakedFrame.normalBuffer);
181 | gl.bufferData(gl.ARRAY_BUFFER, bakedFrame.normals, gl.STATIC_DRAW);
182 |
183 | // add the newly baked frame to the surface
184 | bakedSurface.frames.push(bakedFrame);
185 | });
186 |
187 | // bake the texture coordinates
188 | console.log("Baking texture coordinates...");
189 | bakedSurface.textureCoordinates = new Float32Array(surface.textureCoordinates)
190 | bakedSurface.textureCoordinateBuffer = gl.createBuffer();
191 | gl.bindBuffer(gl.ARRAY_BUFFER, bakedSurface.textureCoordinateBuffer);
192 | gl.bufferData(gl.ARRAY_BUFFER, bakedSurface.textureCoordinates, gl.STATIC_DRAW);
193 |
194 | // add the newly baked surface to the mesh's surface list
195 | surfaces.push(bakedSurface);
196 | surfaces[bakedSurface.name] = bakedSurface;
197 | });
198 |
199 | if (surfaces.length > 0) {
200 | mesh.render = function(renderParams, frame) {
201 | for (var i = 0; i < surfaces.length; i++) {
202 | mesh.renderSurface(renderParams, i, frame);
203 | }
204 | }
205 | } else {
206 | mesh.render = function(renderParams, frame) {
207 | mesh.renderSurface(renderParams, 0, frame);
208 | }
209 | }
210 |
211 | mesh.renderSurface = function(renderParams, surfaceIndex, frame) {
212 |
213 | var uniformsList = renderParams.uniforms;
214 | var surface = surfaces[surfaceIndex];
215 | var shader = renderParams.shader ? renderParams.shader : engine.resources.get(surface.shader);
216 |
217 | shader.use();
218 |
219 | if (!renderParams.cameraView.flat) {
220 | renderParams.cameraView.flat = renderParams.cameraView.flatten();
221 | }
222 | gl.uniformMatrix4fv(shader.uniform("u_cameraView"), false, renderParams.cameraView.flat);
223 | if (!renderParams.modelView.flat) {
224 | renderParams.modelView.flat = renderParams.modelView.flatten();
225 | }
226 | gl.uniformMatrix4fv(shader.uniform("u_modelView"), false, renderParams.modelView.flat);
227 | if (!renderParams.projection.flat) {
228 | renderParams.projection.flat = renderParams.projection.flatten();
229 | }
230 | if (shader.hasUniform("u_projection")) {
231 | gl.uniformMatrix4fv(shader.uniform("u_projection"), false, renderParams.projection.flat);
232 | }
233 |
234 | if (shader.hasUniform("u_normalModelView")) {
235 | /*try {
236 | var normalModelViewFlat =
237 | (renderParams.modelView)
238 | .inverse()
239 | .transpose()
240 | .flatten();
241 | gl.uniformMatrix4fv(
242 | shader.uniform("u_normalModelView"),
243 | false,
244 | normalModelViewFlat
245 | );
246 | } catch (e) {
247 | // We could not invert the matrix for some reason (singular?)*/
248 | if (!(renderParams.normalModelView.flat)) {
249 | renderParams.normalModelView.flat = renderParams.normalModelView.flatten();
250 | }
251 | // console.log(renderParams.normalModelView.inspect());
252 | gl.uniformMatrix4fv(
253 | shader.uniform("u_normalModelView"),
254 | false,
255 | renderParams.normalModelView.flatten()
256 | );
257 | // }
258 | }
259 |
260 | if (shader.hasUniform("u_normalCameraView")) {
261 | try {
262 | var normalModelViewFlat =
263 | (renderParams.cameraView)
264 | .inverse()
265 | .transpose()
266 | .flatten();
267 | gl.uniformMatrix4fv(
268 | shader.uniform("u_normalCameraView"),
269 | false,
270 | normalModelViewFlat
271 | );
272 | } catch (e) {
273 | // We could not invert the matrix for some reason (singular?)
274 | gl.uniformMatrix4fv(
275 | shader.uniform("u_normalCameraView"),
276 | false,
277 | ((renderParams.cameraView)).flatten()
278 | );
279 | }
280 | }
281 |
282 | //var textureNumber = 0;
283 | var unitsUsed = 0x0;
284 | for (var sampler in surface.samplers) {
285 | var texture = engine.resources.get(surface.samplers[sampler]);
286 | var textureUnit;
287 | if (unitsUsed & (1 << texture.lastUnit)) {
288 | textureUnit = 0;
289 | while(unitsUsed & (1 << textureUnit)) {
290 | textureUnit++;
291 | }
292 | } else {
293 | textureUnit = (texture.lastUnit << 0);
294 | }
295 | texture.lastUnit = textureUnit;
296 | unitsUsed |= (1 << textureUnit)
297 | // console.log(textureUnit);
298 |
299 | gl.activeTexture(gl.TEXTURE0 + textureUnit);
300 | gl.bindTexture(gl.TEXTURE_2D, texture);
301 | if (shader.hasUniform(sampler)) {
302 | gl.uniform1i(shader.uniform(sampler), textureUnit)
303 | }
304 | //textureNumber++;
305 | }
306 | /* for (var sampler in surface.samplers) {
307 | if (textureNumber < 2) {
308 | gl.activeTexture(gl.TEXTURE0 + textureNumber);
309 | gl.bindTexture(gl.TEXTURE_2D, engine.resources.get(surface.samplers[sampler]));
310 | if (shader.hasUniform(sampler)) {
311 | gl.uniform1i(shader.uniform(sampler), textureNumber)
312 | console.log(textureNumber);
313 | }
314 | lastTexture = engine.resources.get(surface.samplers[sampler]);
315 | textureNumber+=2;
316 | }
317 | }*/
318 | /*for (var sampler in surface.samplers) {
319 | gl.activeTexture(gl.TEXTURE0 + textureNumber);
320 | gl.bindTexture(gl.TEXTURE_2D, engine.resources.get(surface.samplers[sampler]));
321 | if (shader.hasUniform(sampler)) {
322 | gl.uniform1i(shader.uniform(sampler), textureNumber)
323 | }
324 | lastTexture = engine.resources.get(surface.samplers[sampler]);
325 | textureNumber++;
326 | }*/
327 |
328 | //gl.activeTexture(gl.TEXTURE0 + textureNumber);
329 | //gl.bindTexture(gl.TEXTURE_2D, lastTexture);
330 | //if (shader.hasUniform("u_diffuseMap")) {
331 | // gl.uniform1i(shader.uniform("u_diffuseMap"), textureNumber)
332 | //}
333 | //textureNumber++;
334 |
335 | /*
336 | gl.activeTexture(gl.TEXTURE0 + textureNumber);
337 | gl.bindTexture(gl.TEXTURE_2D, lastTexture);
338 | gl.uniform1i(shader.uniform("u_diffuseMap"), textureNumber)
339 | textureNumber++;*/
340 |
341 |
342 | //if (uniforms) {
343 | //if (!(uniforms instanceof Array)) {
344 | // __uniformArray[0] = uniforms;
345 | // uniforms = __uniformArray;
346 | //}
347 | for (var uniformsListIndex in uniformsList) {
348 | var uniforms = uniformsList[uniformsListIndex];
349 | for (var uniformName in uniforms) {
350 | var uniform = uniforms[uniformName];
351 | if (!shader.hasUniform(uniformName))
352 | continue;
353 | switch(true) {
354 | case uniform instanceof Matrix:
355 | //if (!uniform.isSquare()) {
356 | // throw new Error("Uniform matrix " + uniformName + " is not square.");
357 | //}
358 | //if (uniform.rows() > 4) {
359 | // throw new Error("Uniform matrix " + uniformName + " is too large.");
360 | //}
361 | if (!uniform.flat) {
362 | uniform.flat = uniform.flatten();
363 | }
364 | gl["uniformMatrix"+uniform.elements.length+"fv"](shader.uniform(uniformName), false, uniform.flat);
365 | break;
366 | case uniform instanceof Vector:
367 | //if (uniform.dimensions() > 4) {
368 | // throw new Error("Uniform vector " + uniformName + " is too large.");
369 | //}
370 | if (!uniform.flat) {
371 | uniform.flat = uniform.flatten();
372 | }
373 | gl["uniform"+uniform.elements.length+"fv"](shader.uniform(uniformName), uniform.flat);
374 | break;
375 | case (typeof uniform) == "number" || uniform instanceof Number:
376 | gl.uniform1f(shader.uniform(uniformName), uniform);
377 | break;
378 | default:
379 | if (!uniform)
380 | break;
381 | var textureUnit;
382 | if (unitsUsed & (1 << uniform.lastUnit)) {
383 | textureUnit = 0;
384 | while(unitsUsed & (1 << textureUnit)) {
385 | textureUnit++;
386 | }
387 | } else {
388 | textureUnit = (uniform.lastUnit << 0);
389 | }
390 | uniform.lastUnit = textureUnit;
391 | unitsUsed |= (1 << textureUnit)
392 |
393 | gl.activeTexture(gl.TEXTURE0 + textureUnit);
394 | gl.bindTexture(gl.TEXTURE_2D, uniform);
395 | gl.uniform1i(shader.uniform(uniformName), textureUnit)
396 | break;
397 | }
398 | }
399 | };
400 | // console.log(textureNumber);
401 | //}
402 |
403 | gl.bindBuffer(gl.ARRAY_BUFFER, surface.frames[frame].vertexBuffer);
404 | gl.enableVertexAttribArray(shader.attribute("a_position"));
405 | gl.vertexAttribPointer(shader.attribute("a_position"), 3, gl.FLOAT, false, 0, 0);
406 |
407 | if (shader.hasAttribute("a_normal")) {
408 | gl.bindBuffer(gl.ARRAY_BUFFER, surface.frames[frame].normalBuffer);
409 | gl.enableVertexAttribArray(shader.attribute("a_normal"));
410 | gl.vertexAttribPointer(shader.attribute("a_normal"), 3, gl.FLOAT, false, 0, 0);
411 | }
412 |
413 | if (shader.hasAttribute("a_texCoords")) {
414 | gl.bindBuffer(gl.ARRAY_BUFFER, surface.textureCoordinateBuffer);
415 | gl.vertexAttribPointer(shader.attribute("a_texCoords"), 2, gl.FLOAT, false, 0, 0);
416 | gl.enableVertexAttribArray(shader.attribute("a_texCoords"));
417 | }
418 |
419 | gl.drawArrays(gl.TRIANGLES, 0, surface.frames[frame].vertices.length / 3);
420 |
421 | /*for (var i = 0; i < textureNumber; i++) {
422 | gl.activeTexture(gl.TEXTURE0 + i);
423 | gl.bindTexture(gl.TEXTURE_2D, null);
424 | }*/
425 |
426 | // gl.flush();
427 | }
428 |
429 | mesh.rayIntersect = function(surfaceIndex, point, direction, maxDist, minDist) {
430 | var Ox = point.elements[0]; // Point
431 | var Oy = point.elements[1];
432 | var Oz = point.elements[2];
433 | var Dx = direction.elements[0]; // Direction
434 | var Dy = direction.elements[1];
435 | var Dz = direction.elements[2];
436 | var surface = surfaces[surfaceIndex];
437 | var vertices = surface.frames[0].vertices;
438 | var numVertices = vertices.length;
439 | var closestIntersect = Infinity;
440 | var closestNx = Infinity;
441 | var closestNy = Infinity;
442 | var closestNz = Infinity;
443 | for (var i = 0; i < numVertices; i+= 9) {
444 | var Ax = vertices[i]; // Vertex A
445 | var Ay = vertices[i+1];
446 | var Az = vertices[i+2];
447 | var Bx = vertices[i+3]; // Vertex B
448 | var By = vertices[i+4];
449 | var Bz = vertices[i+5];
450 | var Cx = vertices[i+6]; // Vertex C
451 | var Cy = vertices[i+7];
452 | var Cz = vertices[i+8];
453 | var ABx = Bx - Ax; // B - A
454 | var ABy = By - Ay;
455 | var ABz = Bz - Az;
456 | var ACx = Cx - Ax; // C - A
457 | var ACy = Cy - Ay;
458 | var ACz = Cz - Az;
459 | var Nx = -((ABy * ACz) - (ABz * ACy)); // Triangle Normal (Cross Product)
460 | var Ny = ((ABx * ACz) - (ABz * ACx));
461 | var Nz = -((ABx * ACy) - (ABy * ACx));
462 | var lowerDot = Dx * Nx + Dy * Ny + Dz * Nz;
463 | if (lowerDot >= 0) {
464 | continue;
465 | }
466 | var AOx = Ox - Ax; // O - A
467 | var AOy = Oy - Ay;
468 | var AOz = Oz - Az;
469 | var upperDot = AOx * Nx + AOy * Ny + AOz * Nz; // Point - Plane Distance
470 | var distance = -(upperDot/lowerDot);
471 | var Px, Py, Pz; // Point of intersection with the triangle plane
472 | var u, v; // Barycentric coordinates (w is implied)
473 |
474 | if (distance > maxDist) { // No need to find a collision this far
475 | continue;
476 | }
477 | if (distance < minDist) { // No need to find a collision this close
478 | continue;
479 | }
480 | if (distance > closestIntersect) { // No need to find a collision further
481 | continue;
482 | }
483 |
484 | // Figure out the dominant axis of the triangle normal
485 | var absNx = Nx > 0? Nx : -Nx;
486 | var absNy = Ny > 0? Ny : -Ny;
487 | var absNz = Nz > 0? Nz : -Nz;
488 | if (absNx > absNy) {
489 | if (absNx > absNz) {
490 | // x is the dominant normal axis
491 | Py = (Oy + distance * Dy) - Ay;
492 | Pz = (Oz + distance * Dz) - Az;
493 | u = (Pz*ACy - Py*ACz) / (ABz * ACy - ABy * ACz);
494 | if (u < 0) {
495 | continue;
496 | }
497 | v = (Pz*ABy - Py*ABz) / (ACz * ABy - ACy * ABz);
498 | } else {
499 | // z is the dominant normal axis
500 | Px = (Ox + distance * Dx) - Ax;
501 | Py = (Oy + distance * Dy) - Ay;
502 | u = (Py*ACx - Px*ACy) / (ABy * ACx - ABx * ACy);
503 | if (u < 0) {
504 | continue;
505 | }
506 | v = (Py*ABx - Px*ABy) / (ACy * ABx - ACx * ABy);
507 | }
508 | } else {
509 | if (absNy > absNz) {
510 | // y is the dominant axis
511 | Px = (Ox + distance * Dx) - Ax;
512 | Pz = (Oz + distance * Dz) - Az;
513 | u = (Pz*ACx - Px*ACz) / (ABz * ACx - ABx * ACz);
514 | if (u < 0) {
515 | continue;
516 | }
517 | v = (Pz*ABx - Px*ABz) / (ACz * ABx - ACx * ABz);
518 | } else {
519 | // z is the dominant axis
520 | Px = (Ox + distance * Dx) - Ax;
521 | Py = (Oy + distance * Dy) - Ay;
522 | u = (Py*ACx - Px*ACy) / (ABy * ACx - ABx * ACy);
523 | if (u < 0) {
524 | continue;
525 | }
526 | v = (Py*ABx - Px*ABy) / (ACy * ABx - ACx * ABy);
527 | }
528 | }
529 |
530 | if (v < 0) {
531 | continue;
532 | }
533 | if (u + v > 1) {
534 | continue;
535 | }
536 | // We are inside the triangle
537 | closestIntersect = distance;
538 | closestNx = Nx;
539 | closestNy = Ny;
540 | closestNz = Nz;
541 |
542 | // For some reason, this line of code is required for the function
543 | // to work on TraceMonkey (!)
544 | window.moreMagic = true;
545 | }
546 |
547 | return {distance: closestIntersect, normal: $V([closestNx, closestNy, closestNz])};
548 | }
549 |
550 | return mesh;
551 | }
552 |
553 | graphicsEngine.Level = function(levelData) {
554 | var scaleFactor = 128.0;
555 | var scaleMatrix = $V([scaleFactor, scaleFactor, scaleFactor, 1.0]).toDiagonalMatrix();
556 | var level = {}
557 | engine.resources.load(levelData.mesh);
558 | var shadowMap = null;
559 | var size = $V([levelData.data[0][0].length * scaleFactor,
560 | levelData.data.length * scaleFactor,
561 | levelData.data[0].length * scaleFactor]);
562 |
563 | var generateShadowMap = function() {
564 | var LIGHTMAP_WIDTH = 128;
565 | var LIGHTMAP_HEIGHT = 128;
566 | var canvas = document.createElement("canvas");
567 | canvas.width = LIGHTMAP_WIDTH;
568 | canvas.height = LIGHTMAP_HEIGHT;
569 | var height = size.elements[1];
570 | var depth = size.elements[2];
571 | var width = size.elements[0];
572 | var context = canvas.getContext("2d");
573 | context.fillStyle = "white";
574 | context.fillRect(0,0,LIGHTMAP_WIDTH,LIGHTMAP_HEIGHT);
575 | for (var x = 0; x < LIGHTMAP_WIDTH; x++) {
576 | for (var z = 0; z < LIGHTMAP_HEIGHT; z++) {
577 | var targetX = width * (x) / LIGHTMAP_WIDTH;
578 | var targetZ = depth * (z) / LIGHTMAP_HEIGHT;
579 | var intersect = level.rayIntersect($V([targetX,height,targetZ]), $V([0,-1,0]), height, 0);
580 | if (isFinite(intersect.distance)) {
581 | context.fillStyle = "rgba(0,0,0," + (intersect.distance / height) + ")"
582 | } else {
583 | context.fillStyle = "rgba(0,0,0,1.0)"
584 | }
585 | context.fillRect(x, z, 1, 1);
586 | }
587 | }
588 | // document.body.appendChild(canvas);
589 | // canvas.style.position = "absolute";
590 | // canvas.style.top = "0";
591 | // canvas.style.left = "0";
592 |
593 | shadowMap = gl.createTexture();
594 | gl.bindTexture(gl.TEXTURE_2D, shadowMap);
595 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
596 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
597 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
598 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
599 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
600 | }
601 |
602 | level.render = function(renderParams, cameraCenter) {
603 | //console.log(renderParams.modelView.eql(Matrix.I(4)));
604 | if (!shadowMap)
605 | generateShadowMap();
606 | // renderParams.uniforms.push({
607 | // u_lightMap: lightMap,
608 | // u_levelSize: size
609 | // });
610 | var mesh = engine.resources.get(levelData.mesh);
611 | var modelView = renderParams.modelView;
612 | var minX = Math.floor(cameraCenter.elements[0] / scaleFactor) - 6;
613 | var minY = Math.floor(cameraCenter.elements[1] / scaleFactor) - 2;
614 | var minZ = Math.floor(cameraCenter.elements[2] / scaleFactor) - 6;
615 | var maxX = minX + 12;
616 | var maxY = minY + 5;
617 | var maxZ = minZ + 12;
618 | for (var y = minY; y < maxY; y ++) {
619 | if (levelData.data[y] === undefined) continue;
620 | for (var z = minZ; z < maxZ; z ++) {
621 | if (levelData.data[y][z] === undefined) continue;
622 | for (var x = minX; x < maxX; x ++) {
623 | if (levelData.data[y][z][x] === undefined) continue;
624 | if (levelData.data[y][z][x] !== null) {
625 | renderParams.modelView = modelView.x(scaleMatrix).x(Matrix.Translation($V([x,y,z])));
626 | mesh.renderSurface(renderParams, levelData.data[y][z][x], 0);
627 | }
628 | }
629 | }
630 | }
631 | // renderParams.uniforms.pop();
632 | }
633 |
634 | level.levelSize = function() {
635 | return size;
636 | }
637 |
638 | level.shadowMap = function() {
639 | return shadowMap;
640 | }
641 |
642 | level.rayIntersect = function(point, direction, maxDist, minDist) {
643 | var mesh = engine.resources.get(levelData.mesh);
644 | var Px = Math.floor(point.elements[0] / scaleFactor);
645 | var Py = Math.floor(point.elements[1] / scaleFactor);
646 | var Pz = Math.floor(point.elements[2] / scaleFactor);
647 | var P2x = Math.floor((point.elements[0] + direction.elements[0] * maxDist) / scaleFactor);
648 | var P2y = Math.floor((point.elements[1] + direction.elements[1] * maxDist) / scaleFactor);
649 | var P2z = Math.floor((point.elements[2] + direction.elements[2] * maxDist) / scaleFactor);
650 | if (P2x < Px) {
651 | var tmp = P2x;
652 | P2x = Px;
653 | Px = tmp;
654 | }
655 | if (P2y < Py) {
656 | var tmp = P2y;
657 | P2y = Py;
658 | Py = tmp;
659 | }
660 | if (P2z < Pz) {
661 | var tmp = P2z;
662 | P2z = Pz;
663 | Pz = tmp;
664 | }
665 |
666 | var numNeighboors = Math.ceil(maxDist/scaleFactor);
667 | var closestIntersect = Infinity;
668 | var closestResult = {distance: Infinity, normal: $V([Infinity, Infinity, Infinity])};;
669 | for (var y = Py; y <= P2y; y++) {
670 | if (levelData.data[y]) {
671 | for (var z = Pz; z <= P2z; z++) {
672 | if (levelData.data[y][z]) {
673 | for (var x = Px; x <= P2x; x++) {
674 | var surfaceIndex = levelData.data[y][z][x];
675 | if (surfaceIndex != null) {
676 | var intersect = mesh.rayIntersect(surfaceIndex, $V([point.elements[0]/scaleFactor - x, point.elements[1]/scaleFactor - y, point.elements[2]/scaleFactor - z]), direction, maxDist/scaleFactor, minDist/scaleFactor)
677 | if (intersect.distance < closestIntersect) {
678 | closestResult = intersect;
679 | }
680 | }
681 | }
682 | }
683 | }
684 | }
685 | }
686 | closestResult.distance *= scaleFactor;
687 | return closestResult;
688 | }
689 |
690 | return level;
691 | }
692 |
693 | graphicsEngine.RenderTarget = function(width, height){
694 | var renderTarget = {}
695 | var framebuffer;
696 | var target;
697 | var depth;
698 | var autoSize;
699 |
700 | var createFrameBuffer = function(width, height) {
701 | framebuffer = gl.createFramebuffer();
702 | gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
703 |
704 | target = gl.createTexture();
705 | gl.bindTexture(gl.TEXTURE_2D, target);
706 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
707 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
708 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
709 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
710 | // gl.generateMipmap(gl.TEXTURE_2D);
711 | // var textureStorage = new Int8Array(width * height * 4);
712 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
713 |
714 | depth = gl.createRenderbuffer();
715 | gl.bindRenderbuffer(gl.RENDERBUFFER, depth);
716 | gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
717 |
718 | gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target, 0);
719 | gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depth);
720 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
721 | gl.bindTexture(gl.TEXTURE_2D, null);
722 | gl.bindRenderbuffer(gl.RENDERBUFFER, null);
723 | }
724 |
725 | if (width !== undefined) {
726 | createFrameBuffer(width, height);
727 | autoSize = false;
728 | } else {
729 | autoSize = true;
730 | }
731 |
732 | renderTarget.activate = function() {
733 | if (autoSize) {
734 | if (width != canvas.width || height != canvas.height) {
735 | createFrameBuffer(canvas.width, canvas.height);
736 | width = canvas.width;
737 | height = canvas.height;
738 | }
739 | }
740 | gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
741 | gl.viewport(0, 0, width, height);
742 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
743 | }
744 |
745 | renderTarget.deactivate = function() {
746 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
747 | gl.viewport(0, 0, canvas.width, canvas.height);
748 | }
749 |
750 | renderTarget.texture = function() {
751 | return target;
752 | }
753 |
754 | var vertices = null, texCoords, vertexBuffer, texCoordsBuffer, shader;
755 |
756 | renderTarget.renderToScreen = function() {
757 | if (!vertices) {
758 | vertices = new Float32Array(
759 | [-1.0, -1.0, 0.0,
760 | -1.0, 1.0, 0.0,
761 | 1.0, -1.0, 0.0,
762 |
763 | 1.0, 1.0, 0.0,
764 | -1.0, 1.0, 0.0,
765 | 1.0, -1.0, 0.0
766 | ]);
767 | texCoords = new Float32Array(
768 | [0.0, 0.0,
769 | 0.0, 1.0,
770 | 1.0, 0.0,
771 | 1.0, 1.0,
772 | 0.0, 1.0,
773 | 1.0, 0.0
774 | ]);
775 |
776 | vertexBuffer = gl.createBuffer();
777 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
778 | gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
779 |
780 | texCoordsBuffer = gl.createBuffer();
781 | gl.bindBuffer(gl.ARRAY_BUFFER, texCoordsBuffer);
782 | gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
783 |
784 | shader = engine.resources.get("shader/glow.jsonshader");
785 | }
786 |
787 | shader.use();
788 |
789 | gl.activeTexture(gl.TEXTURE0);
790 | gl.bindTexture(gl.TEXTURE_2D, target);
791 | gl.uniform1i(shader.uniform("u_image"), 0);
792 |
793 | gl.bindBuffer(gl.ARRAY_BUFFER, texCoordsBuffer);
794 | gl.vertexAttribPointer(shader.attribute("a_texCoords"), 2, gl.FLOAT, false, 0, 0);
795 | gl.enableVertexAttribArray(shader.attribute("a_texCoords"));
796 |
797 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
798 | gl.vertexAttribPointer(shader.attribute("a_position"), 3, gl.FLOAT, false, 0, 0);
799 | gl.enableVertexAttribArray(shader.attribute("a_position"));
800 |
801 | gl.drawArrays(gl.TRIANGLES, 0, 6);
802 | }
803 |
804 | renderTarget.aspectRatio = function() {
805 | return width / height;
806 | }
807 |
808 | return renderTarget;
809 | }
810 |
811 | return graphicsEngine;
812 | }
--------------------------------------------------------------------------------
/mesh/spinball.jsonmesh:
--------------------------------------------------------------------------------
1 | {
2 | "format": "JSON3D 1.0",
3 | "surfaces": [
4 | {
5 | "name": "Sphere01",
6 | "shader": "shader/sonic.jsonshader",
7 | "samplers": { "u_diffuseMap": "texture/sonic.png" },
8 | "frames": [
9 | {
10 | "vertices": [13.8,0.0,0.0,12.7,0.0,6.1,12.7,2.3,5.7,13.8,0.0,0.0,12.7,2.3,5.7,12.7,4.3,4.3,13.8,0.0,0.0,12.7,4.3,4.3,12.7,5.7,2.3,13.8,0.0,0.0,12.7,5.7,2.3,12.7,6.1,0.0,13.8,0.0,0.0,12.7,6.1,0.0,12.7,5.7,-2.3,13.8,0.0,0.0,12.7,5.7,-2.3,12.7,4.3,-4.3,13.8,0.0,0.0,12.7,4.3,-4.3,12.7,2.3,-5.7,13.8,0.0,0.0,12.7,2.3,-5.7,12.7,0.0,-6.1,13.8,0.0,0.0,12.7,0.0,-6.1,12.7,-2.3,-5.7,13.8,0.0,0.0,12.7,-2.3,-5.7,12.7,-4.3,-4.3,13.8,0.0,0.0,12.7,-4.3,-4.3,12.7,-5.7,-2.3,13.8,0.0,0.0,12.7,-5.7,-2.3,12.7,-6.1,0.0,13.8,0.0,0.0,12.7,-6.1,0.0,12.7,-5.7,2.3,13.8,0.0,0.0,12.7,-5.7,2.3,12.7,-4.3,4.3,13.8,0.0,0.0,12.7,-4.3,4.3,12.7,-2.3,5.7,13.8,0.0,0.0,12.7,-2.3,5.7,12.7,0.0,6.1,12.7,0.0,6.1,9.7,0.0,11.3,9.7,4.3,10.4,12.7,0.0,6.1,9.7,4.3,10.4,12.7,2.3,5.7,12.7,2.3,5.7,9.7,4.3,10.4,9.7,8.0,8.0,12.7,2.3,5.7,9.7,8.0,8.0,12.7,4.3,4.3,12.7,4.3,4.3,9.7,8.0,8.0,9.7,10.4,4.3,12.7,4.3,4.3,9.7,10.4,4.3,12.7,5.7,2.3,12.7,5.7,2.3,9.7,10.4,4.3,9.7,11.3,0.0,12.7,5.7,2.3,9.7,11.3,0.0,12.7,6.1,0.0,12.7,6.1,0.0,9.7,11.3,0.0,9.7,10.4,-4.3,12.7,6.1,0.0,9.7,10.4,-4.3,12.7,5.7,-2.3,12.7,5.7,-2.3,9.7,10.4,-4.3,9.7,8.0,-8.0,12.7,5.7,-2.3,9.7,8.0,-8.0,12.7,4.3,-4.3,12.7,4.3,-4.3,9.7,8.0,-8.0,9.7,4.3,-10.4,12.7,4.3,-4.3,9.7,4.3,-10.4,12.7,2.3,-5.7,12.7,2.3,-5.7,9.7,4.3,-10.4,9.7,0.0,-11.3,12.7,2.3,-5.7,9.7,0.0,-11.3,12.7,0.0,-6.1,12.7,0.0,-6.1,9.7,0.0,-11.3,9.7,-4.3,-10.4,12.7,0.0,-6.1,9.7,-4.3,-10.4,12.7,-2.3,-5.7,12.7,-2.3,-5.7,9.7,-4.3,-10.4,9.7,-8.0,-8.0,12.7,-2.3,-5.7,9.7,-8.0,-8.0,12.7,-4.3,-4.3,12.7,-4.3,-4.3,9.7,-8.0,-8.0,9.7,-10.4,-4.3,12.7,-4.3,-4.3,9.7,-10.4,-4.3,12.7,-5.7,-2.3,12.7,-5.7,-2.3,9.7,-10.4,-4.3,9.7,-11.3,0.0,12.7,-5.7,-2.3,9.7,-11.3,0.0,12.7,-6.1,0.0,12.7,-6.1,0.0,9.7,-11.3,0.0,9.7,-10.4,4.3,12.7,-6.1,0.0,9.7,-10.4,4.3,12.7,-5.7,2.3,12.7,-5.7,2.3,9.7,-10.4,4.3,9.7,-8.0,8.0,12.7,-5.7,2.3,9.7,-8.0,8.0,12.7,-4.3,4.3,12.7,-4.3,4.3,9.7,-8.0,8.0,9.7,-4.3,10.4,12.7,-4.3,4.3,9.7,-4.3,10.4,12.7,-2.3,5.7,12.7,-2.3,5.7,9.7,-4.3,10.4,9.7,0.0,11.3,12.7,-2.3,5.7,9.7,0.0,11.3,12.7,0.0,6.1,9.7,0.0,11.3,5.3,0.0,14.8,5.3,5.7,13.7,9.7,0.0,11.3,5.3,5.7,13.7,9.7,4.3,10.4,9.7,4.3,10.4,5.3,5.7,13.7,5.3,10.4,10.4,9.7,4.3,10.4,5.3,10.4,10.4,9.7,8.0,8.0,9.7,8.0,8.0,5.3,10.4,10.4,5.3,13.7,5.7,9.7,8.0,8.0,5.3,13.7,5.7,9.7,10.4,4.3,9.7,10.4,4.3,5.3,13.7,5.7,5.3,14.8,0.0,9.7,10.4,4.3,5.3,14.8,0.0,9.7,11.3,0.0,9.7,11.3,0.0,5.3,14.8,0.0,5.3,13.7,-5.7,9.7,11.3,0.0,5.3,13.7,-5.7,9.7,10.4,-4.3,9.7,10.4,-4.3,5.3,13.7,-5.7,5.3,10.4,-10.4,9.7,10.4,-4.3,5.3,10.4,-10.4,9.7,8.0,-8.0,9.7,8.0,-8.0,5.3,10.4,-10.4,5.3,5.7,-13.7,9.7,8.0,-8.0,5.3,5.7,-13.7,9.7,4.3,-10.4,9.7,4.3,-10.4,5.3,5.7,-13.7,5.3,0.0,-14.8,9.7,4.3,-10.4,5.3,0.0,-14.8,9.7,0.0,-11.3,9.7,0.0,-11.3,5.3,0.0,-14.8,5.3,-5.7,-13.7,9.7,0.0,-11.3,5.3,-5.7,-13.7,9.7,-4.3,-10.4,9.7,-4.3,-10.4,5.3,-5.7,-13.7,5.3,-10.4,-10.4,9.7,-4.3,-10.4,5.3,-10.4,-10.4,9.7,-8.0,-8.0,9.7,-8.0,-8.0,5.3,-10.4,-10.4,5.3,-13.7,-5.7,9.7,-8.0,-8.0,5.3,-13.7,-5.7,9.7,-10.4,-4.3,9.7,-10.4,-4.3,5.3,-13.7,-5.7,5.3,-14.8,0.0,9.7,-10.4,-4.3,5.3,-14.8,0.0,9.7,-11.3,0.0,9.7,-11.3,0.0,5.3,-14.8,0.0,5.3,-13.7,5.7,9.7,-11.3,0.0,5.3,-13.7,5.7,9.7,-10.4,4.3,9.7,-10.4,4.3,5.3,-13.7,5.7,5.3,-10.4,10.4,9.7,-10.4,4.3,5.3,-10.4,10.4,9.7,-8.0,8.0,9.7,-8.0,8.0,5.3,-10.4,10.4,5.3,-5.7,13.7,9.7,-8.0,8.0,5.3,-5.7,13.7,9.7,-4.3,10.4,9.7,-4.3,10.4,5.3,-5.7,13.7,5.3,0.0,14.8,9.7,-4.3,10.4,5.3,0.0,14.8,9.7,0.0,11.3,5.3,0.0,14.8,0.0,0.0,16.0,0.0,6.1,14.8,5.3,0.0,14.8,0.0,6.1,14.8,5.3,5.7,13.7,5.3,5.7,13.7,0.0,6.1,14.8,0.0,11.3,11.3,5.3,5.7,13.7,0.0,11.3,11.3,5.3,10.4,10.4,5.3,10.4,10.4,0.0,11.3,11.3,0.0,14.8,6.1,5.3,10.4,10.4,0.0,14.8,6.1,5.3,13.7,5.7,5.3,13.7,5.7,0.0,14.8,6.1,0.0,16.0,0.0,5.3,13.7,5.7,0.0,16.0,0.0,5.3,14.8,0.0,5.3,14.8,0.0,0.0,16.0,0.0,0.0,14.8,-6.1,5.3,14.8,0.0,0.0,14.8,-6.1,5.3,13.7,-5.7,5.3,13.7,-5.7,0.0,14.8,-6.1,0.0,11.3,-11.3,5.3,13.7,-5.7,0.0,11.3,-11.3,5.3,10.4,-10.4,5.3,10.4,-10.4,0.0,11.3,-11.3,0.0,6.1,-14.8,5.3,10.4,-10.4,0.0,6.1,-14.8,5.3,5.7,-13.7,5.3,5.7,-13.7,0.0,6.1,-14.8,0.0,0.0,-16.0,5.3,5.7,-13.7,0.0,0.0,-16.0,5.3,0.0,-14.8,5.3,0.0,-14.8,0.0,0.0,-16.0,0.0,-6.1,-14.8,5.3,0.0,-14.8,0.0,-6.1,-14.8,5.3,-5.7,-13.7,5.3,-5.7,-13.7,0.0,-6.1,-14.8,0.0,-11.3,-11.3,5.3,-5.7,-13.7,0.0,-11.3,-11.3,5.3,-10.4,-10.4,5.3,-10.4,-10.4,0.0,-11.3,-11.3,0.0,-14.8,-6.1,5.3,-10.4,-10.4,0.0,-14.8,-6.1,5.3,-13.7,-5.7,5.3,-13.7,-5.7,0.0,-14.8,-6.1,0.0,-16.0,0.0,5.3,-13.7,-5.7,0.0,-16.0,0.0,5.3,-14.8,0.0,5.3,-14.8,0.0,0.0,-16.0,0.0,0.0,-14.8,6.1,5.3,-14.8,0.0,0.0,-14.8,6.1,5.3,-13.7,5.7,5.3,-13.7,5.7,0.0,-14.8,6.1,0.0,-11.3,11.3,5.3,-13.7,5.7,0.0,-11.3,11.3,5.3,-10.4,10.4,5.3,-10.4,10.4,0.0,-11.3,11.3,0.0,-6.1,14.8,5.3,-10.4,10.4,0.0,-6.1,14.8,5.3,-5.7,13.7,5.3,-5.7,13.7,0.0,-6.1,14.8,0.0,0.0,16.0,5.3,-5.7,13.7,0.0,0.0,16.0,5.3,0.0,14.8,0.0,0.0,16.0,-5.3,0.0,14.8,-5.3,5.7,13.7,0.0,0.0,16.0,-5.3,5.7,13.7,0.0,6.1,14.8,0.0,6.1,14.8,-5.3,5.7,13.7,-5.3,10.4,10.4,0.0,6.1,14.8,-5.3,10.4,10.4,0.0,11.3,11.3,0.0,11.3,11.3,-5.3,10.4,10.4,-5.3,13.7,5.7,0.0,11.3,11.3,-5.3,13.7,5.7,0.0,14.8,6.1,0.0,14.8,6.1,-5.3,13.7,5.7,-5.3,14.8,0.0,0.0,14.8,6.1,-5.3,14.8,0.0,0.0,16.0,0.0,0.0,16.0,0.0,-5.3,14.8,0.0,-5.3,13.7,-5.7,0.0,16.0,0.0,-5.3,13.7,-5.7,0.0,14.8,-6.1,0.0,14.8,-6.1,-5.3,13.7,-5.7,-5.3,10.4,-10.4,0.0,14.8,-6.1,-5.3,10.4,-10.4,0.0,11.3,-11.3,0.0,11.3,-11.3,-5.3,10.4,-10.4,-5.3,5.7,-13.7,0.0,11.3,-11.3,-5.3,5.7,-13.7,0.0,6.1,-14.8,0.0,6.1,-14.8,-5.3,5.7,-13.7,-5.3,0.0,-14.8,0.0,6.1,-14.8,-5.3,0.0,-14.8,0.0,0.0,-16.0,0.0,0.0,-16.0,-5.3,0.0,-14.8,-5.3,-5.7,-13.7,0.0,0.0,-16.0,-5.3,-5.7,-13.7,0.0,-6.1,-14.8,0.0,-6.1,-14.8,-5.3,-5.7,-13.7,-5.3,-10.4,-10.4,0.0,-6.1,-14.8,-5.3,-10.4,-10.4,0.0,-11.3,-11.3,0.0,-11.3,-11.3,-5.3,-10.4,-10.4,-5.3,-13.7,-5.7,0.0,-11.3,-11.3,-5.3,-13.7,-5.7,0.0,-14.8,-6.1,0.0,-14.8,-6.1,-5.3,-13.7,-5.7,-5.3,-14.8,0.0,0.0,-14.8,-6.1,-5.3,-14.8,0.0,0.0,-16.0,0.0,0.0,-16.0,0.0,-5.3,-14.8,0.0,-5.3,-13.7,5.7,0.0,-16.0,0.0,-5.3,-13.7,5.7,0.0,-14.8,6.1,0.0,-14.8,6.1,-5.3,-13.7,5.7,-5.3,-10.4,10.4,0.0,-14.8,6.1,-5.3,-10.4,10.4,0.0,-11.3,11.3,0.0,-11.3,11.3,-5.3,-10.4,10.4,-5.3,-5.7,13.7,0.0,-11.3,11.3,-5.3,-5.7,13.7,0.0,-6.1,14.8,0.0,-6.1,14.8,-5.3,-5.7,13.7,-5.3,0.0,14.8,0.0,-6.1,14.8,-5.3,0.0,14.8,0.0,0.0,16.0,-5.3,0.0,14.8,-9.7,0.0,11.3,-9.7,4.3,10.4,-5.3,0.0,14.8,-9.7,4.3,10.4,-5.3,5.7,13.7,-5.3,5.7,13.7,-9.7,4.3,10.4,-9.7,8.0,8.0,-5.3,5.7,13.7,-9.7,8.0,8.0,-5.3,10.4,10.4,-5.3,10.4,10.4,-9.7,8.0,8.0,-9.7,10.4,4.3,-5.3,10.4,10.4,-9.7,10.4,4.3,-5.3,13.7,5.7,-5.3,13.7,5.7,-9.7,10.4,4.3,-9.7,11.3,0.0,-5.3,13.7,5.7,-9.7,11.3,0.0,-5.3,14.8,0.0,-5.3,14.8,0.0,-9.7,11.3,0.0,-9.7,10.4,-4.3,-5.3,14.8,0.0,-9.7,10.4,-4.3,-5.3,13.7,-5.7,-5.3,13.7,-5.7,-9.7,10.4,-4.3,-9.7,8.0,-8.0,-5.3,13.7,-5.7,-9.7,8.0,-8.0,-5.3,10.4,-10.4,-5.3,10.4,-10.4,-9.7,8.0,-8.0,-9.7,4.3,-10.4,-5.3,10.4,-10.4,-9.7,4.3,-10.4,-5.3,5.7,-13.7,-5.3,5.7,-13.7,-9.7,4.3,-10.4,-9.7,0.0,-11.3,-5.3,5.7,-13.7,-9.7,0.0,-11.3,-5.3,0.0,-14.8,-5.3,0.0,-14.8,-9.7,0.0,-11.3,-9.7,-4.3,-10.4,-5.3,0.0,-14.8,-9.7,-4.3,-10.4,-5.3,-5.7,-13.7,-5.3,-5.7,-13.7,-9.7,-4.3,-10.4,-9.7,-8.0,-8.0,-5.3,-5.7,-13.7,-9.7,-8.0,-8.0,-5.3,-10.4,-10.4,-5.3,-10.4,-10.4,-9.7,-8.0,-8.0,-9.7,-10.4,-4.3,-5.3,-10.4,-10.4,-9.7,-10.4,-4.3,-5.3,-13.7,-5.7,-5.3,-13.7,-5.7,-9.7,-10.4,-4.3,-9.7,-11.3,0.0,-5.3,-13.7,-5.7,-9.7,-11.3,0.0,-5.3,-14.8,0.0,-5.3,-14.8,0.0,-9.7,-11.3,0.0,-9.7,-10.4,4.3,-5.3,-14.8,0.0,-9.7,-10.4,4.3,-5.3,-13.7,5.7,-5.3,-13.7,5.7,-9.7,-10.4,4.3,-9.7,-8.0,8.0,-5.3,-13.7,5.7,-9.7,-8.0,8.0,-5.3,-10.4,10.4,-5.3,-10.4,10.4,-9.7,-8.0,8.0,-9.7,-4.3,10.4,-5.3,-10.4,10.4,-9.7,-4.3,10.4,-5.3,-5.7,13.7,-5.3,-5.7,13.7,-9.7,-4.3,10.4,-9.7,0.0,11.3,-5.3,-5.7,13.7,-9.7,0.0,11.3,-5.3,0.0,14.8,-9.7,0.0,11.3,-12.7,0.0,6.1,-12.7,2.3,5.7,-9.7,0.0,11.3,-12.7,2.3,5.7,-9.7,4.3,10.4,-9.7,4.3,10.4,-12.7,2.3,5.7,-12.7,4.3,4.3,-9.7,4.3,10.4,-12.7,4.3,4.3,-9.7,8.0,8.0,-9.7,8.0,8.0,-12.7,4.3,4.3,-12.7,5.7,2.3,-9.7,8.0,8.0,-12.7,5.7,2.3,-9.7,10.4,4.3,-9.7,10.4,4.3,-12.7,5.7,2.3,-12.7,6.1,0.0,-9.7,10.4,4.3,-12.7,6.1,0.0,-9.7,11.3,0.0,-9.7,11.3,0.0,-12.7,6.1,0.0,-12.7,5.7,-2.3,-9.7,11.3,0.0,-12.7,5.7,-2.3,-9.7,10.4,-4.3,-9.7,10.4,-4.3,-12.7,5.7,-2.3,-12.7,4.3,-4.3,-9.7,10.4,-4.3,-12.7,4.3,-4.3,-9.7,8.0,-8.0,-9.7,8.0,-8.0,-12.7,4.3,-4.3,-12.7,2.3,-5.7,-9.7,8.0,-8.0,-12.7,2.3,-5.7,-9.7,4.3,-10.4,-9.7,4.3,-10.4,-12.7,2.3,-5.7,-12.7,0.0,-6.1,-9.7,4.3,-10.4,-12.7,0.0,-6.1,-9.7,0.0,-11.3,-9.7,0.0,-11.3,-12.7,0.0,-6.1,-12.7,-2.3,-5.7,-9.7,0.0,-11.3,-12.7,-2.3,-5.7,-9.7,-4.3,-10.4,-9.7,-4.3,-10.4,-12.7,-2.3,-5.7,-12.7,-4.3,-4.3,-9.7,-4.3,-10.4,-12.7,-4.3,-4.3,-9.7,-8.0,-8.0,-9.7,-8.0,-8.0,-12.7,-4.3,-4.3,-12.7,-5.7,-2.3,-9.7,-8.0,-8.0,-12.7,-5.7,-2.3,-9.7,-10.4,-4.3,-9.7,-10.4,-4.3,-12.7,-5.7,-2.3,-12.7,-6.1,0.0,-9.7,-10.4,-4.3,-12.7,-6.1,0.0,-9.7,-11.3,0.0,-9.7,-11.3,0.0,-12.7,-6.1,0.0,-12.7,-5.7,2.3,-9.7,-11.3,0.0,-12.7,-5.7,2.3,-9.7,-10.4,4.3,-9.7,-10.4,4.3,-12.7,-5.7,2.3,-12.7,-4.3,4.3,-9.7,-10.4,4.3,-12.7,-4.3,4.3,-9.7,-8.0,8.0,-9.7,-8.0,8.0,-12.7,-4.3,4.3,-12.7,-2.3,5.7,-9.7,-8.0,8.0,-12.7,-2.3,5.7,-9.7,-4.3,10.4,-9.7,-4.3,10.4,-12.7,-2.3,5.7,-12.7,0.0,6.1,-9.7,-4.3,10.4,-12.7,0.0,6.1,-9.7,0.0,11.3,-13.8,0.0,0.0,-12.7,2.3,5.7,-12.7,0.0,6.1,-13.8,0.0,0.0,-12.7,4.3,4.3,-12.7,2.3,5.7,-13.8,0.0,0.0,-12.7,5.7,2.3,-12.7,4.3,4.3,-13.8,0.0,0.0,-12.7,6.1,0.0,-12.7,5.7,2.3,-13.8,0.0,0.0,-12.7,5.7,-2.3,-12.7,6.1,0.0,-13.8,0.0,0.0,-12.7,4.3,-4.3,-12.7,5.7,-2.3,-13.8,0.0,0.0,-12.7,2.3,-5.7,-12.7,4.3,-4.3,-13.8,0.0,0.0,-12.7,0.0,-6.1,-12.7,2.3,-5.7,-13.8,0.0,0.0,-12.7,-2.3,-5.7,-12.7,0.0,-6.1,-13.8,0.0,0.0,-12.7,-4.3,-4.3,-12.7,-2.3,-5.7,-13.8,0.0,0.0,-12.7,-5.7,-2.3,-12.7,-4.3,-4.3,-13.8,0.0,0.0,-12.7,-6.1,0.0,-12.7,-5.7,-2.3,-13.8,0.0,0.0,-12.7,-5.7,2.3,-12.7,-6.1,0.0,-13.8,0.0,0.0,-12.7,-4.3,4.3,-12.7,-5.7,2.3,-13.8,0.0,0.0,-12.7,-2.3,5.7,-12.7,-4.3,4.3,-13.8,0.0,0.0,-12.7,0.0,6.1,-12.7,-2.3,5.7,],
11 | "normals": [1.00,0.02,0.00,0.88,0.04,0.47,0.87,0.24,0.44,1.00,0.02,0.00,0.87,0.24,0.44,0.87,0.38,0.31,1.00,0.02,0.00,0.87,0.38,0.31,0.86,0.49,0.15,1.00,0.02,0.00,0.86,0.49,0.15,0.86,0.51,0.00,1.00,0.02,0.00,0.86,0.51,0.00,0.87,0.45,-0.20,1.00,0.02,0.00,0.87,0.45,-0.20,0.88,0.33,-0.34,1.00,0.02,0.00,0.88,0.33,-0.34,0.88,0.17,-0.45,1.00,0.02,0.00,0.88,0.17,-0.45,0.89,-0.03,-0.45,1.00,0.02,0.00,0.89,-0.03,-0.45,0.88,-0.23,-0.42,1.00,0.02,0.00,0.88,-0.23,-0.42,0.88,-0.37,-0.29,1.00,0.02,0.00,0.88,-0.37,-0.29,0.88,-0.46,-0.13,1.00,0.02,0.00,0.88,-0.46,-0.13,0.88,-0.48,0.02,1.00,0.02,0.00,0.88,-0.48,0.02,0.87,-0.43,0.22,1.00,0.02,0.00,0.87,-0.43,0.22,0.87,-0.32,0.36,1.00,0.02,0.00,0.87,-0.32,0.36,0.87,-0.13,0.47,1.00,0.02,0.00,0.87,-0.13,0.47,0.88,0.04,0.47,0.88,0.04,0.47,0.65,0.04,0.76,0.63,0.33,0.70,0.88,0.04,0.47,0.63,0.33,0.70,0.87,0.24,0.44,0.87,0.24,0.44,0.63,0.33,0.70,0.63,0.57,0.52,0.87,0.24,0.44,0.63,0.57,0.52,0.87,0.38,0.31,0.87,0.38,0.31,0.63,0.57,0.52,0.62,0.74,0.26,0.87,0.38,0.31,0.62,0.74,0.26,0.86,0.49,0.15,0.86,0.49,0.15,0.62,0.74,0.26,0.62,0.79,0.00,0.86,0.49,0.15,0.62,0.79,0.00,0.86,0.51,0.00,0.86,0.51,0.00,0.62,0.79,0.00,0.64,0.70,-0.30,0.86,0.51,0.00,0.64,0.70,-0.30,0.87,0.45,-0.20,0.87,0.45,-0.20,0.64,0.70,-0.30,0.65,0.53,-0.54,0.87,0.45,-0.20,0.65,0.53,-0.54,0.88,0.33,-0.34,0.88,0.33,-0.34,0.65,0.53,-0.54,0.66,0.29,-0.70,0.88,0.33,-0.34,0.66,0.29,-0.70,0.88,0.17,-0.45,0.88,0.17,-0.45,0.66,0.29,-0.70,0.67,-0.01,-0.74,0.88,0.17,-0.45,0.67,-0.01,-0.74,0.89,-0.03,-0.45,0.89,-0.03,-0.45,0.67,-0.01,-0.74,0.65,-0.32,-0.69,0.89,-0.03,-0.45,0.65,-0.32,-0.69,0.88,-0.23,-0.42,0.88,-0.23,-0.42,0.65,-0.32,-0.69,0.65,-0.56,-0.51,0.88,-0.23,-0.42,0.65,-0.56,-0.51,0.88,-0.37,-0.29,0.88,-0.37,-0.29,0.65,-0.56,-0.51,0.65,-0.71,-0.25,0.88,-0.37,-0.29,0.65,-0.71,-0.25,0.88,-0.46,-0.13,0.88,-0.46,-0.13,0.65,-0.71,-0.25,0.65,-0.76,0.02,0.88,-0.46,-0.13,0.65,-0.76,0.02,0.88,-0.48,0.02,0.88,-0.48,0.02,0.65,-0.76,0.02,0.64,-0.70,0.32,0.88,-0.48,0.02,0.64,-0.70,0.32,0.87,-0.43,0.22,0.87,-0.43,0.22,0.64,-0.70,0.32,0.64,-0.52,0.56,0.87,-0.43,0.22,0.64,-0.52,0.56,0.87,-0.32,0.36,0.87,-0.32,0.36,0.64,-0.52,0.56,0.65,-0.25,0.72,0.87,-0.32,0.36,0.65,-0.25,0.72,0.87,-0.13,0.47,0.87,-0.13,0.47,0.65,-0.25,0.72,0.65,0.04,0.76,0.87,-0.13,0.47,0.65,0.04,0.76,0.88,0.04,0.47,0.65,0.04,0.76,0.33,0.02,0.94,0.33,0.38,0.87,0.65,0.04,0.76,0.33,0.38,0.87,0.63,0.33,0.70,0.63,0.33,0.70,0.33,0.38,0.87,0.32,0.69,0.65,0.63,0.33,0.70,0.32,0.69,0.65,0.63,0.57,0.52,0.63,0.57,0.52,0.32,0.69,0.65,0.33,0.88,0.34,0.63,0.57,0.52,0.33,0.88,0.34,0.62,0.74,0.26,0.62,0.74,0.26,0.33,0.88,0.34,0.31,0.95,0.00,0.62,0.74,0.26,0.31,0.95,0.00,0.62,0.79,0.00,0.62,0.79,0.00,0.31,0.95,0.00,0.34,0.87,-0.36,0.62,0.79,0.00,0.34,0.87,-0.36,0.64,0.70,-0.30,0.64,0.70,-0.30,0.34,0.87,-0.36,0.35,0.67,-0.66,0.64,0.70,-0.30,0.35,0.67,-0.66,0.65,0.53,-0.54,0.65,0.53,-0.54,0.35,0.67,-0.66,0.35,0.36,-0.87,0.65,0.53,-0.54,0.35,0.36,-0.87,0.66,0.29,-0.70,0.66,0.29,-0.70,0.35,0.36,-0.87,0.36,-0.01,-0.93,0.66,0.29,-0.70,0.36,-0.01,-0.93,0.67,-0.01,-0.74,0.67,-0.01,-0.74,0.36,-0.01,-0.93,0.35,-0.37,-0.86,0.67,-0.01,-0.74,0.35,-0.37,-0.86,0.65,-0.32,-0.69,0.65,-0.32,-0.69,0.35,-0.37,-0.86,0.34,-0.68,-0.65,0.65,-0.32,-0.69,0.34,-0.68,-0.65,0.65,-0.56,-0.51,0.65,-0.56,-0.51,0.34,-0.68,-0.65,0.34,-0.88,-0.34,0.65,-0.56,-0.51,0.34,-0.88,-0.34,0.65,-0.71,-0.25,0.65,-0.71,-0.25,0.34,-0.88,-0.34,0.35,-0.94,0.01,0.65,-0.71,-0.25,0.35,-0.94,0.01,0.65,-0.76,0.02,0.65,-0.76,0.02,0.35,-0.94,0.01,0.34,-0.86,0.38,0.65,-0.76,0.02,0.34,-0.86,0.38,0.64,-0.70,0.32,0.64,-0.70,0.32,0.34,-0.86,0.38,0.34,-0.64,0.69,0.64,-0.70,0.32,0.34,-0.64,0.69,0.64,-0.52,0.56,0.64,-0.52,0.56,0.34,-0.64,0.69,0.33,-0.34,0.88,0.64,-0.52,0.56,0.33,-0.34,0.88,0.65,-0.25,0.72,0.65,-0.25,0.72,0.33,-0.34,0.88,0.33,0.02,0.94,0.65,-0.25,0.72,0.33,0.02,0.94,0.65,0.04,0.76,0.33,0.02,0.94,0.02,0.02,1.00,0.02,0.40,0.92,0.33,0.02,0.94,0.02,0.40,0.92,0.33,0.38,0.87,0.33,0.38,0.87,0.02,0.40,0.92,0.01,0.72,0.69,0.33,0.38,0.87,0.01,0.72,0.69,0.32,0.69,0.65,0.32,0.69,0.65,0.01,0.72,0.69,0.01,0.93,0.36,0.32,0.69,0.65,0.01,0.93,0.36,0.33,0.88,0.34,0.33,0.88,0.34,0.01,0.93,0.36,-0.00,1.00,-0.00,0.33,0.88,0.34,-0.00,1.00,-0.00,0.31,0.95,0.00,0.31,0.95,0.00,-0.00,1.00,-0.00,0.02,0.93,-0.36,0.31,0.95,0.00,0.02,0.93,-0.36,0.34,0.87,-0.36,0.34,0.87,-0.36,0.02,0.93,-0.36,0.03,0.72,-0.69,0.34,0.87,-0.36,0.03,0.72,-0.69,0.35,0.67,-0.66,0.35,0.67,-0.66,0.03,0.72,-0.69,0.04,0.40,-0.92,0.35,0.67,-0.66,0.04,0.40,-0.92,0.35,0.36,-0.87,0.35,0.36,-0.87,0.04,0.40,-0.92,0.04,0.02,-1.00,0.35,0.36,-0.87,0.04,0.02,-1.00,0.36,-0.01,-0.93,0.36,-0.01,-0.93,0.04,0.02,-1.00,0.04,-0.37,-0.93,0.36,-0.01,-0.93,0.04,-0.37,-0.93,0.35,-0.37,-0.86,0.35,-0.37,-0.86,0.04,-0.37,-0.93,0.03,-0.70,-0.72,0.35,-0.37,-0.86,0.03,-0.70,-0.72,0.34,-0.68,-0.65,0.34,-0.68,-0.65,0.03,-0.70,-0.72,0.02,-0.92,-0.40,0.34,-0.68,-0.65,0.02,-0.92,-0.40,0.34,-0.88,-0.34,0.34,-0.88,-0.34,0.02,-0.92,-0.40,-0.00,-1.00,0.01,0.34,-0.88,-0.34,-0.00,-1.00,0.01,0.35,-0.94,0.01,0.35,-0.94,0.01,-0.00,-1.00,0.01,0.01,-0.92,0.40,0.35,-0.94,0.01,0.01,-0.92,0.40,0.34,-0.86,0.38,0.34,-0.86,0.38,0.01,-0.92,0.40,0.01,-0.70,0.72,0.34,-0.86,0.38,0.01,-0.70,0.72,0.34,-0.64,0.69,0.34,-0.64,0.69,0.01,-0.70,0.72,0.02,-0.37,0.93,0.34,-0.64,0.69,0.02,-0.37,0.93,0.33,-0.34,0.88,0.33,-0.34,0.88,0.02,-0.37,0.93,0.02,0.02,1.00,0.33,-0.34,0.88,0.02,0.02,1.00,0.33,0.02,0.94,0.02,0.02,1.00,-0.32,-0.01,0.95,-0.32,0.36,0.88,0.02,0.02,1.00,-0.32,0.36,0.88,0.02,0.40,0.92,0.02,0.40,0.92,-0.32,0.36,0.88,-0.31,0.67,0.68,0.02,0.40,0.92,-0.31,0.67,0.68,0.01,0.72,0.69,0.01,0.72,0.69,-0.31,0.67,0.68,-0.32,0.87,0.38,0.01,0.72,0.69,-0.32,0.87,0.38,0.01,0.93,0.36,0.01,0.93,0.36,-0.32,0.87,0.38,-0.31,0.95,0.02,0.01,0.93,0.36,-0.31,0.95,0.02,-0.00,1.00,-0.00,-0.00,1.00,-0.00,-0.31,0.95,0.02,-0.31,0.88,-0.36,-0.00,1.00,-0.00,-0.31,0.88,-0.36,0.02,0.93,-0.36,0.02,0.93,-0.36,-0.31,0.88,-0.36,-0.30,0.69,-0.66,0.02,0.93,-0.36,-0.30,0.69,-0.66,0.03,0.72,-0.69,0.03,0.72,-0.69,-0.30,0.69,-0.66,-0.30,0.38,-0.88,0.03,0.72,-0.69,-0.30,0.38,-0.88,0.04,0.40,-0.92,0.04,0.40,-0.92,-0.30,0.38,-0.88,-0.30,0.02,-0.95,0.04,0.40,-0.92,-0.30,0.02,-0.95,0.04,0.02,-1.00,0.04,0.02,-1.00,-0.30,0.02,-0.95,-0.30,-0.34,-0.89,0.04,0.02,-1.00,-0.30,-0.34,-0.89,0.04,-0.37,-0.93,0.04,-0.37,-0.93,-0.30,-0.34,-0.89,-0.30,-0.64,-0.71,0.04,-0.37,-0.93,-0.30,-0.64,-0.71,0.03,-0.70,-0.72,0.03,-0.70,-0.72,-0.30,-0.64,-0.71,-0.31,-0.86,-0.40,0.03,-0.70,-0.72,-0.31,-0.86,-0.40,0.02,-0.92,-0.40,0.02,-0.92,-0.40,-0.31,-0.86,-0.40,-0.35,-0.94,-0.03,0.02,-0.92,-0.40,-0.35,-0.94,-0.03,-0.00,-1.00,0.01,-0.00,-1.00,0.01,-0.35,-0.94,-0.03,-0.33,-0.88,0.36,-0.00,-1.00,0.01,-0.33,-0.88,0.36,0.01,-0.92,0.40,0.01,-0.92,0.40,-0.33,-0.88,0.36,-0.32,-0.68,0.66,0.01,-0.92,0.40,-0.32,-0.68,0.66,0.01,-0.70,0.72,0.01,-0.70,0.72,-0.32,-0.68,0.66,-0.32,-0.37,0.87,0.01,-0.70,0.72,-0.32,-0.37,0.87,0.02,-0.37,0.93,0.02,-0.37,0.93,-0.32,-0.37,0.87,-0.32,-0.01,0.95,0.02,-0.37,0.93,-0.32,-0.01,0.95,0.02,0.02,1.00,-0.32,-0.01,0.95,-0.62,-0.01,0.78,-0.61,0.29,0.74,-0.32,-0.01,0.95,-0.61,0.29,0.74,-0.32,0.36,0.88,-0.32,0.36,0.88,-0.61,0.29,0.74,-0.62,0.53,0.58,-0.32,0.36,0.88,-0.62,0.53,0.58,-0.31,0.67,0.68,-0.31,0.67,0.68,-0.62,0.53,0.58,-0.63,0.70,0.33,-0.31,0.67,0.68,-0.63,0.70,0.33,-0.32,0.87,0.38,-0.32,0.87,0.38,-0.63,0.70,0.33,-0.62,0.79,0.04,-0.32,0.87,0.38,-0.62,0.79,0.04,-0.31,0.95,0.02,-0.31,0.95,0.02,-0.62,0.79,0.04,-0.61,0.74,-0.28,-0.31,0.95,0.02,-0.61,0.74,-0.28,-0.31,0.88,-0.36,-0.31,0.88,-0.36,-0.61,0.74,-0.28,-0.61,0.57,-0.54,-0.31,0.88,-0.36,-0.61,0.57,-0.54,-0.30,0.69,-0.66,-0.30,0.69,-0.66,-0.61,0.57,-0.54,-0.60,0.33,-0.72,-0.30,0.69,-0.66,-0.60,0.33,-0.72,-0.30,0.38,-0.88,-0.30,0.38,-0.88,-0.60,0.33,-0.72,-0.60,0.04,-0.80,-0.30,0.38,-0.88,-0.60,0.04,-0.80,-0.30,0.02,-0.95,-0.30,0.02,-0.95,-0.60,0.04,-0.80,-0.60,-0.25,-0.76,-0.30,0.02,-0.95,-0.60,-0.25,-0.76,-0.30,-0.34,-0.89,-0.30,-0.34,-0.89,-0.60,-0.25,-0.76,-0.61,-0.52,-0.60,-0.30,-0.34,-0.89,-0.61,-0.52,-0.60,-0.30,-0.64,-0.71,-0.30,-0.64,-0.71,-0.61,-0.52,-0.60,-0.63,-0.70,-0.35,-0.30,-0.64,-0.71,-0.63,-0.70,-0.35,-0.31,-0.86,-0.40,-0.31,-0.86,-0.40,-0.63,-0.70,-0.35,-0.64,-0.76,-0.06,-0.31,-0.86,-0.40,-0.64,-0.76,-0.06,-0.35,-0.94,-0.03,-0.35,-0.94,-0.03,-0.64,-0.76,-0.06,-0.64,-0.71,0.28,-0.35,-0.94,-0.03,-0.64,-0.71,0.28,-0.33,-0.88,0.36,-0.33,-0.88,0.36,-0.64,-0.71,0.28,-0.63,-0.56,0.53,-0.33,-0.88,0.36,-0.63,-0.56,0.53,-0.32,-0.68,0.66,-0.32,-0.68,0.66,-0.63,-0.56,0.53,-0.63,-0.32,0.71,-0.32,-0.68,0.66,-0.63,-0.32,0.71,-0.32,-0.37,0.87,-0.32,-0.37,0.87,-0.63,-0.32,0.71,-0.62,-0.01,0.78,-0.32,-0.37,0.87,-0.62,-0.01,0.78,-0.32,-0.01,0.95,-0.62,-0.01,0.78,-0.86,-0.03,0.51,-0.86,0.17,0.48,-0.62,-0.01,0.78,-0.86,0.17,0.48,-0.61,0.29,0.74,-0.61,0.29,0.74,-0.86,0.17,0.48,-0.86,0.33,0.39,-0.61,0.29,0.74,-0.86,0.33,0.39,-0.62,0.53,0.58,-0.62,0.53,0.58,-0.86,0.33,0.39,-0.87,0.45,0.23,-0.62,0.53,0.58,-0.87,0.45,0.23,-0.63,0.70,0.33,-0.63,0.70,0.33,-0.87,0.45,0.23,-0.86,0.51,0.05,-0.63,0.70,0.33,-0.86,0.51,0.05,-0.62,0.79,0.04,-0.62,0.79,0.04,-0.86,0.51,0.05,-0.85,0.49,-0.18,-0.62,0.79,0.04,-0.85,0.49,-0.18,-0.61,0.74,-0.28,-0.61,0.74,-0.28,-0.85,0.49,-0.18,-0.86,0.38,-0.34,-0.61,0.74,-0.28,-0.86,0.38,-0.34,-0.61,0.57,-0.54,-0.61,0.57,-0.54,-0.86,0.38,-0.34,-0.85,0.24,-0.47,-0.61,0.57,-0.54,-0.85,0.24,-0.47,-0.60,0.33,-0.72,-0.60,0.33,-0.72,-0.85,0.24,-0.47,-0.85,0.04,-0.53,-0.60,0.33,-0.72,-0.85,0.04,-0.53,-0.60,0.04,-0.80,-0.60,0.04,-0.80,-0.85,0.04,-0.53,-0.86,-0.13,-0.50,-0.60,0.04,-0.80,-0.86,-0.13,-0.50,-0.60,-0.25,-0.76,-0.60,-0.25,-0.76,-0.86,-0.13,-0.50,-0.85,-0.32,-0.42,-0.60,-0.25,-0.76,-0.85,-0.32,-0.42,-0.61,-0.52,-0.60,-0.61,-0.52,-0.60,-0.85,-0.32,-0.42,-0.86,-0.43,-0.25,-0.61,-0.52,-0.60,-0.86,-0.43,-0.25,-0.63,-0.70,-0.35,-0.63,-0.70,-0.35,-0.86,-0.43,-0.25,-0.87,-0.48,-0.08,-0.63,-0.70,-0.35,-0.87,-0.48,-0.08,-0.64,-0.76,-0.06,-0.64,-0.76,-0.06,-0.87,-0.48,-0.08,-0.87,-0.46,0.16,-0.64,-0.76,-0.06,-0.87,-0.46,0.16,-0.64,-0.71,0.28,-0.64,-0.71,0.28,-0.87,-0.46,0.16,-0.87,-0.37,0.33,-0.64,-0.71,0.28,-0.87,-0.37,0.33,-0.63,-0.56,0.53,-0.63,-0.56,0.53,-0.87,-0.37,0.33,-0.86,-0.23,0.45,-0.63,-0.56,0.53,-0.86,-0.23,0.45,-0.63,-0.32,0.71,-0.63,-0.32,0.71,-0.86,-0.23,0.45,-0.86,-0.03,0.51,-0.63,-0.32,0.71,-0.86,-0.03,0.51,-0.62,-0.01,0.78,-1.00,0.02,-0.04,-0.86,0.17,0.48,-0.86,-0.03,0.51,-1.00,0.02,-0.04,-0.86,0.33,0.39,-0.86,0.17,0.48,-1.00,0.02,-0.04,-0.87,0.45,0.23,-0.86,0.33,0.39,-1.00,0.02,-0.04,-0.86,0.51,0.05,-0.87,0.45,0.23,-1.00,0.02,-0.04,-0.85,0.49,-0.18,-0.86,0.51,0.05,-1.00,0.02,-0.04,-0.86,0.38,-0.34,-0.85,0.49,-0.18,-1.00,0.02,-0.04,-0.85,0.24,-0.47,-0.86,0.38,-0.34,-1.00,0.02,-0.04,-0.85,0.04,-0.53,-0.85,0.24,-0.47,-1.00,0.02,-0.04,-0.86,-0.13,-0.50,-0.85,0.04,-0.53,-1.00,0.02,-0.04,-0.85,-0.32,-0.42,-0.86,-0.13,-0.50,-1.00,0.02,-0.04,-0.86,-0.43,-0.25,-0.85,-0.32,-0.42,-1.00,0.02,-0.04,-0.87,-0.48,-0.08,-0.86,-0.43,-0.25,-1.00,0.02,-0.04,-0.87,-0.46,0.16,-0.87,-0.48,-0.08,-1.00,0.02,-0.04,-0.87,-0.37,0.33,-0.87,-0.46,0.16,-1.00,0.02,-0.04,-0.86,-0.23,0.45,-0.87,-0.37,0.33,-1.00,0.02,-0.04,-0.86,-0.03,0.51,-0.86,-0.23,0.45,]
12 | },
13 | ],
14 | "textureCoordinates": [0.000000,0.000000,0.000000,0.125000,0.062500,0.125000,0.062500,0.000000,0.062500,0.125000,0.125000,0.125000,0.125000,0.000000,0.125000,0.125000,0.187500,0.125000,0.187500,0.000000,0.187500,0.125000,0.250000,0.125000,0.250000,0.000000,0.250000,0.125000,0.312500,0.125000,0.312500,0.000000,0.312500,0.125000,0.375000,0.125000,0.375000,0.000000,0.375000,0.125000,0.437500,0.125000,0.437500,0.000000,0.437500,0.125000,0.500000,0.125000,0.500000,0.000000,0.500000,0.125000,0.562500,0.125000,0.562500,0.000000,0.562500,0.125000,0.625000,0.125000,0.625000,0.000000,0.625000,0.125000,0.687500,0.125000,0.687500,0.000000,0.687500,0.125000,0.750000,0.125000,0.750000,0.000000,0.750000,0.125000,0.812500,0.125000,0.812500,0.000000,0.812500,0.125000,0.875000,0.125000,0.875000,0.000000,0.875000,0.125000,0.937500,0.125000,0.937500,0.000000,0.937500,0.125000,1.000000,0.125000,0.000000,0.125000,0.000000,0.250000,0.062500,0.250000,0.000000,0.125000,0.062500,0.250000,0.062500,0.125000,0.062500,0.125000,0.062500,0.250000,0.125000,0.250000,0.062500,0.125000,0.125000,0.250000,0.125000,0.125000,0.125000,0.125000,0.125000,0.250000,0.187500,0.250000,0.125000,0.125000,0.187500,0.250000,0.187500,0.125000,0.187500,0.125000,0.187500,0.250000,0.250000,0.250000,0.187500,0.125000,0.250000,0.250000,0.250000,0.125000,0.250000,0.125000,0.250000,0.250000,0.312500,0.250000,0.250000,0.125000,0.312500,0.250000,0.312500,0.125000,0.312500,0.125000,0.312500,0.250000,0.375000,0.250000,0.312500,0.125000,0.375000,0.250000,0.375000,0.125000,0.375000,0.125000,0.375000,0.250000,0.437500,0.250000,0.375000,0.125000,0.437500,0.250000,0.437500,0.125000,0.437500,0.125000,0.437500,0.250000,0.500000,0.250000,0.437500,0.125000,0.500000,0.250000,0.500000,0.125000,0.500000,0.125000,0.500000,0.250000,0.562500,0.250000,0.500000,0.125000,0.562500,0.250000,0.562500,0.125000,0.562500,0.125000,0.562500,0.250000,0.625000,0.250000,0.562500,0.125000,0.625000,0.250000,0.625000,0.125000,0.625000,0.125000,0.625000,0.250000,0.687500,0.250000,0.625000,0.125000,0.687500,0.250000,0.687500,0.125000,0.687500,0.125000,0.687500,0.250000,0.750000,0.250000,0.687500,0.125000,0.750000,0.250000,0.750000,0.125000,0.750000,0.125000,0.750000,0.250000,0.812500,0.250000,0.750000,0.125000,0.812500,0.250000,0.812500,0.125000,0.812500,0.125000,0.812500,0.250000,0.875000,0.250000,0.812500,0.125000,0.875000,0.250000,0.875000,0.125000,0.875000,0.125000,0.875000,0.250000,0.937500,0.250000,0.875000,0.125000,0.937500,0.250000,0.937500,0.125000,0.937500,0.125000,0.937500,0.250000,1.000000,0.250000,0.937500,0.125000,1.000000,0.250000,1.000000,0.125000,0.000000,0.250000,0.000000,0.375000,0.062500,0.375000,0.000000,0.250000,0.062500,0.375000,0.062500,0.250000,0.062500,0.250000,0.062500,0.375000,0.125000,0.375000,0.062500,0.250000,0.125000,0.375000,0.125000,0.250000,0.125000,0.250000,0.125000,0.375000,0.187500,0.375000,0.125000,0.250000,0.187500,0.375000,0.187500,0.250000,0.187500,0.250000,0.187500,0.375000,0.250000,0.375000,0.187500,0.250000,0.250000,0.375000,0.250000,0.250000,0.250000,0.250000,0.250000,0.375000,0.312500,0.375000,0.250000,0.250000,0.312500,0.375000,0.312500,0.250000,0.312500,0.250000,0.312500,0.375000,0.375000,0.375000,0.312500,0.250000,0.375000,0.375000,0.375000,0.250000,0.375000,0.250000,0.375000,0.375000,0.437500,0.375000,0.375000,0.250000,0.437500,0.375000,0.437500,0.250000,0.437500,0.250000,0.437500,0.375000,0.500000,0.375000,0.437500,0.250000,0.500000,0.375000,0.500000,0.250000,0.500000,0.250000,0.500000,0.375000,0.562500,0.375000,0.500000,0.250000,0.562500,0.375000,0.562500,0.250000,0.562500,0.250000,0.562500,0.375000,0.625000,0.375000,0.562500,0.250000,0.625000,0.375000,0.625000,0.250000,0.625000,0.250000,0.625000,0.375000,0.687500,0.375000,0.625000,0.250000,0.687500,0.375000,0.687500,0.250000,0.687500,0.250000,0.687500,0.375000,0.750000,0.375000,0.687500,0.250000,0.750000,0.375000,0.750000,0.250000,0.750000,0.250000,0.750000,0.375000,0.812500,0.375000,0.750000,0.250000,0.812500,0.375000,0.812500,0.250000,0.812500,0.250000,0.812500,0.375000,0.875000,0.375000,0.812500,0.250000,0.875000,0.375000,0.875000,0.250000,0.875000,0.250000,0.875000,0.375000,0.937500,0.375000,0.875000,0.250000,0.937500,0.375000,0.937500,0.250000,0.937500,0.250000,0.937500,0.375000,1.000000,0.375000,0.937500,0.250000,1.000000,0.375000,1.000000,0.250000,0.000000,0.375000,0.000000,0.500000,0.062500,0.500000,0.000000,0.375000,0.062500,0.500000,0.062500,0.375000,0.062500,0.375000,0.062500,0.500000,0.125000,0.500000,0.062500,0.375000,0.125000,0.500000,0.125000,0.375000,0.125000,0.375000,0.125000,0.500000,0.187500,0.500000,0.125000,0.375000,0.187500,0.500000,0.187500,0.375000,0.187500,0.375000,0.187500,0.500000,0.250000,0.500000,0.187500,0.375000,0.250000,0.500000,0.250000,0.375000,0.250000,0.375000,0.250000,0.500000,0.312500,0.500000,0.250000,0.375000,0.312500,0.500000,0.312500,0.375000,0.312500,0.375000,0.312500,0.500000,0.375000,0.500000,0.312500,0.375000,0.375000,0.500000,0.375000,0.375000,0.375000,0.375000,0.375000,0.500000,0.437500,0.500000,0.375000,0.375000,0.437500,0.500000,0.437500,0.375000,0.437500,0.375000,0.437500,0.500000,0.500000,0.500000,0.437500,0.375000,0.500000,0.500000,0.500000,0.375000,0.500000,0.375000,0.500000,0.500000,0.562500,0.500000,0.500000,0.375000,0.562500,0.500000,0.562500,0.375000,0.562500,0.375000,0.562500,0.500000,0.625000,0.500000,0.562500,0.375000,0.625000,0.500000,0.625000,0.375000,0.625000,0.375000,0.625000,0.500000,0.687500,0.500000,0.625000,0.375000,0.687500,0.500000,0.687500,0.375000,0.687500,0.375000,0.687500,0.500000,0.750000,0.500000,0.687500,0.375000,0.750000,0.500000,0.750000,0.375000,0.750000,0.375000,0.750000,0.500000,0.812500,0.500000,0.750000,0.375000,0.812500,0.500000,0.812500,0.375000,0.812500,0.375000,0.812500,0.500000,0.875000,0.500000,0.812500,0.375000,0.875000,0.500000,0.875000,0.375000,0.875000,0.375000,0.875000,0.500000,0.937500,0.500000,0.875000,0.375000,0.937500,0.500000,0.937500,0.375000,0.937500,0.375000,0.937500,0.500000,1.000000,0.500000,0.937500,0.375000,1.000000,0.500000,1.000000,0.375000,0.000000,0.500000,0.000000,0.625000,0.062500,0.625000,0.000000,0.500000,0.062500,0.625000,0.062500,0.500000,0.062500,0.500000,0.062500,0.625000,0.125000,0.625000,0.062500,0.500000,0.125000,0.625000,0.125000,0.500000,0.125000,0.500000,0.125000,0.625000,0.187500,0.625000,0.125000,0.500000,0.187500,0.625000,0.187500,0.500000,0.187500,0.500000,0.187500,0.625000,0.250000,0.625000,0.187500,0.500000,0.250000,0.625000,0.250000,0.500000,0.250000,0.500000,0.250000,0.625000,0.312500,0.625000,0.250000,0.500000,0.312500,0.625000,0.312500,0.500000,0.312500,0.500000,0.312500,0.625000,0.375000,0.625000,0.312500,0.500000,0.375000,0.625000,0.375000,0.500000,0.375000,0.500000,0.375000,0.625000,0.437500,0.625000,0.375000,0.500000,0.437500,0.625000,0.437500,0.500000,0.437500,0.500000,0.437500,0.625000,0.500000,0.625000,0.437500,0.500000,0.500000,0.625000,0.500000,0.500000,0.500000,0.500000,0.500000,0.625000,0.562500,0.625000,0.500000,0.500000,0.562500,0.625000,0.562500,0.500000,0.562500,0.500000,0.562500,0.625000,0.625000,0.625000,0.562500,0.500000,0.625000,0.625000,0.625000,0.500000,0.625000,0.500000,0.625000,0.625000,0.687500,0.625000,0.625000,0.500000,0.687500,0.625000,0.687500,0.500000,0.687500,0.500000,0.687500,0.625000,0.750000,0.625000,0.687500,0.500000,0.750000,0.625000,0.750000,0.500000,0.750000,0.500000,0.750000,0.625000,0.812500,0.625000,0.750000,0.500000,0.812500,0.625000,0.812500,0.500000,0.812500,0.500000,0.812500,0.625000,0.875000,0.625000,0.812500,0.500000,0.875000,0.625000,0.875000,0.500000,0.875000,0.500000,0.875000,0.625000,0.937500,0.625000,0.875000,0.500000,0.937500,0.625000,0.937500,0.500000,0.937500,0.500000,0.937500,0.625000,1.000000,0.625000,0.937500,0.500000,1.000000,0.625000,1.000000,0.500000,0.000000,0.625000,0.000000,0.750000,0.062500,0.750000,0.000000,0.625000,0.062500,0.750000,0.062500,0.625000,0.062500,0.625000,0.062500,0.750000,0.125000,0.750000,0.062500,0.625000,0.125000,0.750000,0.125000,0.625000,0.125000,0.625000,0.125000,0.750000,0.187500,0.750000,0.125000,0.625000,0.187500,0.750000,0.187500,0.625000,0.187500,0.625000,0.187500,0.750000,0.250000,0.750000,0.187500,0.625000,0.250000,0.750000,0.250000,0.625000,0.250000,0.625000,0.250000,0.750000,0.312500,0.750000,0.250000,0.625000,0.312500,0.750000,0.312500,0.625000,0.312500,0.625000,0.312500,0.750000,0.375000,0.750000,0.312500,0.625000,0.375000,0.750000,0.375000,0.625000,0.375000,0.625000,0.375000,0.750000,0.437500,0.750000,0.375000,0.625000,0.437500,0.750000,0.437500,0.625000,0.437500,0.625000,0.437500,0.750000,0.500000,0.750000,0.437500,0.625000,0.500000,0.750000,0.500000,0.625000,0.500000,0.625000,0.500000,0.750000,0.562500,0.750000,0.500000,0.625000,0.562500,0.750000,0.562500,0.625000,0.562500,0.625000,0.562500,0.750000,0.625000,0.750000,0.562500,0.625000,0.625000,0.750000,0.625000,0.625000,0.625000,0.625000,0.625000,0.750000,0.687500,0.750000,0.625000,0.625000,0.687500,0.750000,0.687500,0.625000,0.687500,0.625000,0.687500,0.750000,0.750000,0.750000,0.687500,0.625000,0.750000,0.750000,0.750000,0.625000,0.750000,0.625000,0.750000,0.750000,0.812500,0.750000,0.750000,0.625000,0.812500,0.750000,0.812500,0.625000,0.812500,0.625000,0.812500,0.750000,0.875000,0.750000,0.812500,0.625000,0.875000,0.750000,0.875000,0.625000,0.875000,0.625000,0.875000,0.750000,0.937500,0.750000,0.875000,0.625000,0.937500,0.750000,0.937500,0.625000,0.937500,0.625000,0.937500,0.750000,1.000000,0.750000,0.937500,0.625000,1.000000,0.750000,1.000000,0.625000,0.000000,0.750000,0.000000,0.875000,0.062500,0.875000,0.000000,0.750000,0.062500,0.875000,0.062500,0.750000,0.062500,0.750000,0.062500,0.875000,0.125000,0.875000,0.062500,0.750000,0.125000,0.875000,0.125000,0.750000,0.125000,0.750000,0.125000,0.875000,0.187500,0.875000,0.125000,0.750000,0.187500,0.875000,0.187500,0.750000,0.187500,0.750000,0.187500,0.875000,0.250000,0.875000,0.187500,0.750000,0.250000,0.875000,0.250000,0.750000,0.250000,0.750000,0.250000,0.875000,0.312500,0.875000,0.250000,0.750000,0.312500,0.875000,0.312500,0.750000,0.312500,0.750000,0.312500,0.875000,0.375000,0.875000,0.312500,0.750000,0.375000,0.875000,0.375000,0.750000,0.375000,0.750000,0.375000,0.875000,0.437500,0.875000,0.375000,0.750000,0.437500,0.875000,0.437500,0.750000,0.437500,0.750000,0.437500,0.875000,0.500000,0.875000,0.437500,0.750000,0.500000,0.875000,0.500000,0.750000,0.500000,0.750000,0.500000,0.875000,0.562500,0.875000,0.500000,0.750000,0.562500,0.875000,0.562500,0.750000,0.562500,0.750000,0.562500,0.875000,0.625000,0.875000,0.562500,0.750000,0.625000,0.875000,0.625000,0.750000,0.625000,0.750000,0.625000,0.875000,0.687500,0.875000,0.625000,0.750000,0.687500,0.875000,0.687500,0.750000,0.687500,0.750000,0.687500,0.875000,0.750000,0.875000,0.687500,0.750000,0.750000,0.875000,0.750000,0.750000,0.750000,0.750000,0.750000,0.875000,0.812500,0.875000,0.750000,0.750000,0.812500,0.875000,0.812500,0.750000,0.812500,0.750000,0.812500,0.875000,0.875000,0.875000,0.812500,0.750000,0.875000,0.875000,0.875000,0.750000,0.875000,0.750000,0.875000,0.875000,0.937500,0.875000,0.875000,0.750000,0.937500,0.875000,0.937500,0.750000,0.937500,0.750000,0.937500,0.875000,1.000000,0.875000,0.937500,0.750000,1.000000,0.875000,1.000000,0.750000,0.000000,1.000000,0.062500,0.875000,0.000000,0.875000,0.062500,1.000000,0.125000,0.875000,0.062500,0.875000,0.125000,1.000000,0.187500,0.875000,0.125000,0.875000,0.187500,1.000000,0.250000,0.875000,0.187500,0.875000,0.250000,1.000000,0.312500,0.875000,0.250000,0.875000,0.312500,1.000000,0.375000,0.875000,0.312500,0.875000,0.375000,1.000000,0.437500,0.875000,0.375000,0.875000,0.437500,1.000000,0.500000,0.875000,0.437500,0.875000,0.500000,1.000000,0.562500,0.875000,0.500000,0.875000,0.562500,1.000000,0.625000,0.875000,0.562500,0.875000,0.625000,1.000000,0.687500,0.875000,0.625000,0.875000,0.687500,1.000000,0.750000,0.875000,0.687500,0.875000,0.750000,1.000000,0.812500,0.875000,0.750000,0.875000,0.812500,1.000000,0.875000,0.875000,0.812500,0.875000,0.875000,1.000000,0.937500,0.875000,0.875000,0.875000,0.937500,1.000000,1.000000,0.875000,0.937500,0.875000,]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------